Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
fengxiaotx committed Dec 17, 2023
2 parents 09766d1 + a57b9fb commit d9e30dc
Show file tree
Hide file tree
Showing 21 changed files with 217 additions and 60 deletions.
65 changes: 39 additions & 26 deletions examples/approval-process-designer-react/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,62 +1,75 @@
import React from 'react';
import './App.css';
import {
ApprovalProcessDesigner,
ApprovalProcessDesigner, GlobalStore,
IProcessNode,
ProcessWidget, StudioPanel
} from "@trionesdev/approval-process-designer-react";
import {ApprovalActivity, ConditionActivity, RouteActivity, StartActivity,CcActivity} from "./activities";
import {ApprovalActivity, ConditionActivity, RouteActivity, StartActivity, CcActivity} from "./activities";
import {Watermark} from "antd";
import * as Icons from "./activities/Icons"

function App() {

const handleOnChange = (value: any) => {
console.log("[processNode]", value)
}
const processNode: IProcessNode = {
type: 'START',
componentName: 'StartActivity',
title: '开始',
nextNode:{
title: '发起人',
nextNode: {
type: 'APPROVAL',
componentName: 'ApprovalActivity',
title: '审批',
nextNode:{
type:'ROUTE',
componentName:'RouteActivity',
title:'路由',
nextNode:{
nextNode: {
type: 'ROUTE',
componentName: 'RouteActivity',
title: '路由',
nextNode: {
type: 'CC',
componentName: 'CcActivity',
title: '抄送人',
},
children:[
children: [
{
type:'CONDITION',
componentName:'ConditionActivity',
title:'条件1',
nextNode:{
type: 'CONDITION',
componentName: 'ConditionActivity',
title: '条件1',
nextNode: {
type: 'APPROVAL',
componentName: 'ApprovalActivity',
title: '审批人',
}
},
{
type:'CONDITION',
componentName:'ConditionActivity',
props:{
defaultCondition:true,
type: 'CONDITION',
componentName: 'ConditionActivity',
props: {
defaultCondition: true,
}
}
]
}
}
}

GlobalStore.registerIcons(Icons);
return (
<>
<ApprovalProcessDesigner value={processNode}>
<StudioPanel>
<ProcessWidget activities={{StartActivity, ApprovalActivity,RouteActivity,ConditionActivity,CcActivity}}/>
</StudioPanel>
</ApprovalProcessDesigner>
</>
<div>
<Watermark style={{height: '100%'}} content={['书阙', '北斗开源']}>
<ApprovalProcessDesigner value={processNode} onChange={handleOnChange}>
<StudioPanel>
<ProcessWidget activities={{
StartActivity,
ApprovalActivity,
RouteActivity,
ConditionActivity,
CcActivity
}}/>
</StudioPanel>
</ApprovalProcessDesigner>
</Watermark>
</div>
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import createResource = DesignerCore.createResource;
export const ApprovalActivity : ActivityFC<any> = TdApprovalActivity

ApprovalActivity.Resource = createResource({
icon:'ApprovalActivityIcon',
type: 'APPROVAL',
componentName:'ApprovalActivity',
title:'审批人',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export const CcActivity: ActivityFC<any> = TdCcActivity

CcActivity.Resource = createResource({
type: 'CC',
icon: '',
icon: 'CcActivityIcon',
componentName: 'CcActivity',
title: '抄送人',
addable: true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,5 @@ import createResource = DesignerCore.createResource;
export const ConditionActivity: ActivityFC<any> = TdConditionActivity
ConditionActivity.Resource = createResource({
type: 'CONDITION',
icon: '',
componentName: 'ConditionActivity',
title:'条件'
componentName: 'ConditionActivity'
})
43 changes: 43 additions & 0 deletions examples/approval-process-designer-react/src/activities/Icons.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
export const ApprovalActivityIcon = (
<svg width="40px" height="40px" viewBox="0 0 40 40" version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlnsXlink="http://www.w3.org/1999/xlink">
<title>审批人</title>
<g id="页面-1" stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
<g id="审批人">
<circle id="椭圆形" fill="#FAA349" cx="20" cy="20" r="20"></circle>
<path
d="M27.3874286,27.7245714 C27.7268571,27.7245714 28.0045714,28.0022857 28.0045714,28.3417143 C28.0045714,28.6811429 27.732,28.9588571 27.3874286,28.9588571 L12.6171429,29 C12.2777143,29 12,28.7222857 12,28.3828571 C12,28.0434286 12.2725714,27.7657143 12.6171429,27.7657143 L27.3874286,27.7245714 Z M20.0588571,11 C22.5274286,11 24.5331429,13.0057143 24.5331429,15.4742857 L24.5331429,15.5514286 C24.5331429,16.1171429 24.4251429,16.6674286 24.2142857,17.192 L24.1885714,17.2485714 L24.1525714,17.3 C23.6899303,18.0005708 22.596881,19.8524859 22.2932013,21.1578335 L25.8394286,21.1571429 C27.0582857,21.1571429 28.0457143,22.1445714 28.0457143,23.3634286 L28.0457143,25.6982857 C28.0457143,26.156 27.6754286,26.5211429 27.2228571,26.5211429 L12.8228571,26.5211429 C12.3702857,26.5211429 12,26.1508571 12,25.6982857 L12,23.3634286 C12,22.1445714 12.9874286,21.1571429 14.2062857,21.1571429 L17.8270905,21.1581802 C17.52774,19.8394456 16.4341022,18.0045273 15.9702857,17.3154286 L15.9342857,17.264 L15.9085714,17.2022857 C15.6925714,16.6725714 15.5845714,16.112 15.5845714,15.536 L15.5845714,15.4742857 C15.5845714,13.0057143 17.5902857,11 20.0588571,11 Z M20.064,12.2342857 C18.2794286,12.2342857 16.824,13.6897143 16.824,15.4742857 L16.824,15.536 C16.824,15.932 16.896,16.3125714 17.0348571,16.6828571 C17.3794286,17.2022857 19.1382857,19.9537143 19.1382857,21.7588571 C19.1382857,22.0498472 18.9341788,22.2954801 18.6620603,22.3596608 C18.5997594,22.3799975 18.5334355,22.3914286 18.4645714,22.3914286 L14.2062857,22.3914286 C13.6714286,22.3914286 13.2342857,22.8285714 13.2342857,23.3634286 L13.2342857,25.2868571 L26.8114286,25.2868571 L26.8114286,23.3634286 C26.8114286,22.8285714 26.3742857,22.3914286 25.8394286,22.3914286 L21.7765714,22.3914286 C21.7286897,22.3914286 21.682036,22.3859022 21.6372167,22.3754557 L21.6068571,22.376 C21.2674286,22.376 20.9897143,22.0982857 20.9897143,21.7588571 C20.9897143,19.9897143 22.7537143,17.1971429 23.0982857,16.6725714 C23.2371429,16.3125714 23.304,15.9371429 23.304,15.5514286 L23.304,15.4742857 C23.304,13.6897143 21.8485714,12.2342857 20.064,12.2342857 Z"
id="形状结合" stroke="#FFFFFF" strokeWidth="0.4" fill="#FFFFFF" fillRule="nonzero"></path>
</g>
</g>
</svg>
)
export const RouteActivityIcon = (
<svg width="40px" height="40px" viewBox="0 0 40 40" version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlnsXlink="http://www.w3.org/1999/xlink">
<title>条件分支</title>
<g id="页面-1" stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
<g id="条件分支">
<circle id="椭圆形" fill="#43CE9C" cx="20" cy="20" r="20"></circle>
<path
d="M20,12 C21.6568542,12 23,13.3431458 23,15 C23,16.6568542 21.6568542,18 20,18 C18.3431458,18 17,16.6568542 17,15 C17,13.3431458 18.3431458,12 20,12 Z M20,13.4 C19.1163444,13.4 18.4,14.1163444 18.4,15 C18.4,15.8836556 19.1163444,16.6 20,16.6 C20.8836556,16.6 21.6,15.8836556 21.6,15 C21.6,14.1163444 20.8836556,13.4 20,13.4 Z M24.5,19.3 C25.9911688,19.3 27.2,20.5088312 27.2,22 L27.2006472,24.0995116 C28.2403234,24.4024577 29,25.3625129 29,26.5 C29,27.8807119 27.8807119,29 26.5,29 C25.1192881,29 24,27.8807119 24,26.5 C24,25.3621471 24.7601652,24.4018403 25.8003558,24.0992196 L25.8,22 C25.8,21.2820298 25.2179702,20.7 24.5,20.7 L15.5,20.7 C14.7820298,20.7 14.2,21.2820298 14.2,22 L14.2006472,24.0995116 C15.2403234,24.4024577 16,25.3625129 16,26.5 C16,27.8807119 14.8807119,29 13.5,29 C12.1192881,29 11,27.8807119 11,26.5 C11,25.3621471 11.7601652,24.4018403 12.8003558,24.0992196 L12.8,22 C12.8,20.5088312 14.0088312,19.3 15.5,19.3 L24.5,19.3 Z M20,24 C21.3807119,24 22.5,25.1192881 22.5,26.5 C22.5,27.8807119 21.3807119,29 20,29 C18.6192881,29 17.5,27.8807119 17.5,26.5 C17.5,25.1192881 18.6192881,24 20,24 Z M13.5,25.4 C12.8924868,25.4 12.4,25.8924868 12.4,26.5 C12.4,27.1075132 12.8924868,27.6 13.5,27.6 C14.1075132,27.6 14.6,27.1075132 14.6,26.5 C14.6,25.8924868 14.1075132,25.4 13.5,25.4 Z M20,25.4 C19.3924868,25.4 18.9,25.8924868 18.9,26.5 C18.9,27.1075132 19.3924868,27.6 20,27.6 C20.6075132,27.6 21.1,27.1075132 21.1,26.5 C21.1,25.8924868 20.6075132,25.4 20,25.4 Z M26.5,25.4 C25.8924868,25.4 25.4,25.8924868 25.4,26.5 C25.4,27.1075132 25.8924868,27.6 26.5,27.6 C27.1075132,27.6 27.6,27.1075132 27.6,26.5 C27.6,25.8924868 27.1075132,25.4 26.5,25.4 Z"
id="形状结合" fill="#FFFFFF" fillRule="nonzero"></path>
</g>
</g>
</svg>
)

export const CcActivityIcon = (
<svg width="40px" height="40px" viewBox="0 0 40 40" version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlnsXlink="http://www.w3.org/1999/xlink">
<title>抄送人</title>
<g id="页面-1" stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
<g id="抄送人">
<circle id="椭圆形" fill="#469EFD" cx="20" cy="20" r="20"></circle>
<path
d="M26.3938464,12.0604408 L26.5280992,12.0618637 C27.189373,12.1059487 27.6897035,12.6777549 27.6456186,13.3390287 L26.7548243,26.7009429 C26.7413219,26.9034796 26.6766627,27.0992814 26.5668963,27.2700292 C26.2085137,27.8275132 25.4660571,27.9889168 24.908573,27.6305342 L19.2562318,23.9968863 C18.9310328,23.7878298 18.8368807,23.3547301 19.0459372,23.0295311 C19.2549937,22.704332 19.6880934,22.6101799 20.0132924,22.8192364 L25.38,26.269 L26.1460431,14.7542058 L17.7,22.312 L17.7,26.003 L18.4533918,25.0627135 C18.6729434,24.7882741 19.056956,24.7228746 19.3517715,24.8946995 L19.4372865,24.9533918 C19.7391699,25.1948985 19.7881149,25.6354032 19.5466082,25.9372865 L18.4370426,27.3242435 C18.0230311,27.8417578 17.2678803,27.9256635 16.7503659,27.511652 C16.4657077,27.2839254 16.3,26.9391499 16.3,26.5746095 L16.3,22.2235552 C16.3,21.8821523 16.4454186,21.5569113 16.6998462,21.3292656 L24.6980431,14.1722058 L13.52,18.645 L15.5992798,19.9816569 C15.8949153,20.1717083 15.9996029,20.5469193 15.8591265,20.8578957 L15.8095744,20.9490121 C15.6005179,21.2742112 15.1674182,21.3683633 14.8422192,21.1593068 L12.4374532,19.6133857 C12.2275151,19.4784256 12.0648805,19.281366 11.9721902,19.0496404 C11.7260542,18.4343002 12.0253532,17.7359356 12.6406935,17.4897995 L26.0026076,12.1450339 C26.0859747,12.1116871 26.1725525,12.0879082 26.260686,12.0739592 L26.3938464,12.0604408 Z"
id="形状结合" fill="#FFFFFF" fillRule="nonzero"></path>
</g>
</g>
</svg>
)
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import createResource = DesignerCore.createResource;
export const RouteActivity: ActivityFC<any> = TdRouteActivity

RouteActivity.Resource = createResource({
icon: 'RouteActivityIcon',
type: 'ROUTE',
componentName: 'RouteActivity',
title: '条件分支',
Expand Down
38 changes: 26 additions & 12 deletions packages/approval-process-designer-react/src/activity/Activity.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {ProcessNode} from "../model";
import {CloseIcon, RightIcon} from "../Icons";
import {AddActivityBox} from "./AddActivityBox";
import {IconWidget} from "../widget/IconWidget";
import {observer} from "@formily/react";

const ActivityStyled = styled('div')({
boxSizing: 'border-box',
Expand Down Expand Up @@ -109,22 +110,34 @@ export type ActivityProps = {
closeable?: boolean
onClick?: () => void
}
export const Activity: FC<ActivityProps> = ({
children,
processNode,
titleStyle,
titleEditable,
onChange,
closeable,
onClick,
}) => {
export const Activity: FC<ActivityProps> = observer(({
children,
processNode,
titleStyle,
titleEditable,
onChange,
closeable,
onClick,
}) => {
const inputRef = createRef<any>()
const [editing, setEditing] = useState(false)

const handleSave = (value: any) => {
processNode.title = value
setEditing(false)
}

const handleInputBlur = (e: any) => {
if (onChange) {
onChange(e.target.value)
}
setEditing(false)
handleSave(e.target.value)
}

const handleKeyDown = (e: any) => {
if (e.keyCode == 13) {
handleSave(e.target.value)
}
}

const handleRemove = () => {
Expand All @@ -143,7 +156,8 @@ export const Activity: FC<ActivityProps> = ({
<div>
<div style={titleStyle} className={classNames('header', {'editable-title': titleEditable})}>
<div>
{editing ? <input ref={inputRef} defaultValue={processNode.title} onBlur={handleInputBlur}/> :
{editing ? <input ref={inputRef} defaultValue={processNode.title} onBlur={handleInputBlur}
onKeyDown={handleKeyDown}/> :
<span className={classNames({'editable-title': titleEditable})}
onClick={(e) => {
e.stopPropagation();
Expand All @@ -162,4 +176,4 @@ export const Activity: FC<ActivityProps> = ({
</div>
<AddActivityBox processNode={processNode}/>
</ActivityStyled>
}
})
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ export const ConditionActivity: FC<ConditionActivityProps> = ({
defaultValue={processNode?.title || `条件${(index || 0) + 1}`}
onBlur={handleInputBlur}/> : <>
<span className={classNames('editable-title')}
onClick={() => setEditing(true)}>{processNode?.title}</span>
onClick={() => setEditing(true)}>{processNode?.title || `条件${(index || 0) + 1}`}</span>
<span className={classNames('priority-title')}>优先级{(index || 0) + 1}</span>
<IconWidget className={`close`} icon={React.cloneElement(CloseIcon)}
onClick={handleRemove}/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export const RouteActivity: FC<RouteActivityProps> = ({children, processNode, ne
}

return <>
<RouteBranches>
<RouteBranches processNode={processNode}>
<RouteActivityStyled className={`route-activity`}>
<button className={`add-branch`} onClick={handleAddBranch}>添加条件</button>
{children}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,25 @@ type ApprovalProcessDesignerProps = {
children?: React.ReactNode;
engine?: ApprovalProcessEngine
value?: any
onChange?: (value: any) => void
}

export const ApprovalProcessDesigner: FC<ApprovalProcessDesignerProps> = ({
children,
engine,
value
value,
onChange
}) => {
let scopeEngine = engine;
if (!scopeEngine) {
scopeEngine = new ApprovalProcessEngine();
}

scopeEngine?.setOnchange(onChange)

useEffect(() => {
if (value) {
scopeEngine.processNode.from(value)
scopeEngine.process.from(value)
}
}, [value])

Expand Down
5 changes: 4 additions & 1 deletion packages/approval-process-designer-react/src/context.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import {createContext} from "react";
import {ApprovalProcessEngine} from "./model/ApprovalProcessEngine";
import {IActivities} from "./types";
import {ProcessNode} from "./model";

export const ApprovalProcessContext = createContext<ApprovalProcessEngine>(null)

export const ActivitiesContext = createContext<IActivities>(null)
export const ActivitiesContext = createContext<IActivities>(null)

export const ProcessNodeContext = createContext<ProcessNode>(null)
4 changes: 3 additions & 1 deletion packages/approval-process-designer-react/src/hooks/index.tsx
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
export * from "./useProcessEngine"
export * from "./useActivities"
export * from "./useActivities"
export * from "./useProcess"
export * from "./useProcessNode"
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import {useProcessEngine} from "./useProcessEngine";

export const useProcess = () => {
return useProcessEngine().process
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {useProcessEngine} from "./useProcessEngine";
import {useContext} from "react";
import {ProcessNodeContext} from "../context";

export const useProcessNode = () => {
return useProcessEngine().processNode
return useContext(ProcessNodeContext)
}
3 changes: 2 additions & 1 deletion packages/approval-process-designer-react/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ export * from "./activity"
export * from "./widget"
export * from "./panel"
export * from "./types"
export * from "./util"
export * from "./util"
export * from "./store"
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import {ProcessNode} from "./ProcessNode";
import {action, define, observable} from "@formily/reactive";
import {define, observable} from "@formily/reactive";
import {GlobalStore} from "../store";
import {DesignerCore} from "../util";
import _ from "lodash";

interface IApprovalProcessEngine {

}

export class ApprovalProcessEngine {
processNode: ProcessNode;
process: ProcessNode;
onChange?: (value: any) => void

constructor(engine?: IApprovalProcessEngine) {
this.processNode = new ProcessNode({
this.process = new ProcessNode({
engine: this,
type: 'START',
componentName: 'StartActivity',
title: '开始'
Expand All @@ -20,11 +24,19 @@ export class ApprovalProcessEngine {

makeObservable() {
define(this, {
processNode: observable,
process: observable,
addableActivityResources: observable.computed
})
}

handleChange = _.debounce((msg: any)=>{
this.onChange?.(DesignerCore.transformToSchema(this.process))
},100)

setOnchange(fn: (value: any) => void) {
this.onChange = fn
}

get addableActivityResources() {
return GlobalStore.getAddableActivityResources()
}
Expand Down
Loading

0 comments on commit d9e30dc

Please sign in to comment.