|
@@ -43,6 +43,9 @@ export function useFlowDesigner(lfContainer: Ref<HTMLDivElement | undefined>) {
|
|
|
timeoutAction: 'remind',
|
|
timeoutAction: 'remind',
|
|
|
approveTimeField: '',
|
|
approveTimeField: '',
|
|
|
ccUsers: '',
|
|
ccUsers: '',
|
|
|
|
|
+ subNodesEnabled: false,
|
|
|
|
|
+ subNodeMode: 'parallel',
|
|
|
|
|
+ subNodes: [] as any[],
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
// 条件节点出连线配置
|
|
// 条件节点出连线配置
|
|
@@ -118,6 +121,10 @@ export function useFlowDesigner(lfContainer: Ref<HTMLDivElement | undefined>) {
|
|
|
syncEdgeToLf(edge)
|
|
syncEdgeToLf(edge)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ function generateSubNodeId(): string {
|
|
|
|
|
+ return 'sub-' + Date.now() + '-' + Math.random().toString(36).slice(2, 8)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
function getDefaultProps(type: string) {
|
|
function getDefaultProps(type: string) {
|
|
|
if (type === 'approval-node')
|
|
if (type === 'approval-node')
|
|
|
return {
|
|
return {
|
|
@@ -127,6 +134,9 @@ export function useFlowDesigner(lfContainer: Ref<HTMLDivElement | undefined>) {
|
|
|
timeoutHours: undefined,
|
|
timeoutHours: undefined,
|
|
|
timeoutAction: 'remind',
|
|
timeoutAction: 'remind',
|
|
|
approveTimeField: '',
|
|
approveTimeField: '',
|
|
|
|
|
+ subNodesEnabled: false,
|
|
|
|
|
+ subNodeMode: 'parallel',
|
|
|
|
|
+ subNodes: [],
|
|
|
}
|
|
}
|
|
|
if (type === 'cc-node') return { ccUsers: '' }
|
|
if (type === 'cc-node') return { ccUsers: '' }
|
|
|
return {}
|
|
return {}
|
|
@@ -145,13 +155,40 @@ export function useFlowDesigner(lfContainer: Ref<HTMLDivElement | undefined>) {
|
|
|
props.timeoutHours = nodeProps.timeoutHours
|
|
props.timeoutHours = nodeProps.timeoutHours
|
|
|
props.timeoutAction = nodeProps.timeoutAction ?? 'remind'
|
|
props.timeoutAction = nodeProps.timeoutAction ?? 'remind'
|
|
|
props.approveTimeField = nodeProps.approveTimeField ?? ''
|
|
props.approveTimeField = nodeProps.approveTimeField ?? ''
|
|
|
|
|
+ props.subNodesEnabled = nodeProps.subNodesEnabled ?? false
|
|
|
|
|
+ props.subNodeMode = nodeProps.subNodeMode ?? 'parallel'
|
|
|
|
|
+ props.subNodes = Array.isArray(nodeProps.subNodes) ? nodeProps.subNodes : []
|
|
|
} else if (type === 'cc-node') {
|
|
} else if (type === 'cc-node') {
|
|
|
props.ccUsers = nodeProps.ccUsers ?? ''
|
|
props.ccUsers = nodeProps.ccUsers ?? ''
|
|
|
}
|
|
}
|
|
|
lf.setProperties(selectedNode.value.id, props)
|
|
lf.setProperties(selectedNode.value.id, props)
|
|
|
|
|
+ // 同步子节点数量角标到节点文本
|
|
|
|
|
+ if (type === 'approval-node') {
|
|
|
|
|
+ syncNodeTextWithSubNodeBadge(selectedNode.value.id, props.subNodesEnabled, props.subNodes)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ function getNodeRawText(nodeId: string): string {
|
|
|
|
|
+ if (!lf) return ''
|
|
|
|
|
+ try {
|
|
|
|
|
+ const node = lf.getNodeData(nodeId)
|
|
|
|
|
+ const text = node?.text?.value || node?.text || ''
|
|
|
|
|
+ return String(text).replace(/ \(\+\d+\)$/, '')
|
|
|
|
|
+ } catch {
|
|
|
|
|
+ return ''
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ function syncNodeTextWithSubNodeBadge(nodeId: string, enabled: boolean, subNodes: any[]) {
|
|
|
|
|
+ if (!lf) return
|
|
|
|
|
+ const rawText = getNodeRawText(nodeId)
|
|
|
|
|
+ if (!rawText) return
|
|
|
|
|
+ const count = enabled && Array.isArray(subNodes) ? subNodes.length : 0
|
|
|
|
|
+ const newText = count > 0 ? `${rawText} (+${count})` : rawText
|
|
|
|
|
+ lf.setNodeText(nodeId, newText)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
function loadNodeProps(data: any) {
|
|
function loadNodeProps(data: any) {
|
|
|
const props = data.properties || getDefaultProps(data.type)
|
|
const props = data.properties || getDefaultProps(data.type)
|
|
|
const cloned = JSON.parse(JSON.stringify(props))
|
|
const cloned = JSON.parse(JSON.stringify(props))
|
|
@@ -182,6 +219,18 @@ export function useFlowDesigner(lfContainer: Ref<HTMLDivElement | undefined>) {
|
|
|
nodeProps.timeoutHours = cloned.timeoutHours ?? undefined
|
|
nodeProps.timeoutHours = cloned.timeoutHours ?? undefined
|
|
|
nodeProps.timeoutAction = cloned.timeoutAction ?? 'remind'
|
|
nodeProps.timeoutAction = cloned.timeoutAction ?? 'remind'
|
|
|
nodeProps.approveTimeField = cloned.approveTimeField ?? ''
|
|
nodeProps.approveTimeField = cloned.approveTimeField ?? ''
|
|
|
|
|
+ nodeProps.subNodesEnabled = cloned.subNodesEnabled === true
|
|
|
|
|
+ nodeProps.subNodeMode = cloned.subNodeMode ?? 'parallel'
|
|
|
|
|
+ nodeProps.subNodes = Array.isArray(cloned.subNodes)
|
|
|
|
|
+ ? cloned.subNodes.map((s: any) => ({
|
|
|
|
|
+ id: s.id || generateSubNodeId(),
|
|
|
|
|
+ name: s.name || '',
|
|
|
|
|
+ assigneeValue: s.assigneeValue ?? '',
|
|
|
|
|
+ approveMode: s.approveMode ?? 'or',
|
|
|
|
|
+ timeoutHours: s.timeoutHours ?? undefined,
|
|
|
|
|
+ timeoutAction: s.timeoutAction ?? 'remind',
|
|
|
|
|
+ }))
|
|
|
|
|
+ : []
|
|
|
} else if (data.type === 'cc-node') {
|
|
} else if (data.type === 'cc-node') {
|
|
|
nodeProps.ccUsers = cloned.ccUsers ?? ''
|
|
nodeProps.ccUsers = cloned.ccUsers ?? ''
|
|
|
}
|
|
}
|
|
@@ -347,6 +396,7 @@ export function useFlowDesigner(lfContainer: Ref<HTMLDivElement | undefined>) {
|
|
|
const parsed = JSON.parse(def.flowJson)
|
|
const parsed = JSON.parse(def.flowJson)
|
|
|
const graphData = convertToFrontendFormat(parsed)
|
|
const graphData = convertToFrontendFormat(parsed)
|
|
|
lf?.render(graphData)
|
|
lf?.render(graphData)
|
|
|
|
|
+ nextTick(() => syncAllSubNodeBadges())
|
|
|
} catch {
|
|
} catch {
|
|
|
lf?.render({ nodes: defaultNodes(), edges: [] })
|
|
lf?.render({ nodes: defaultNodes(), edges: [] })
|
|
|
}
|
|
}
|
|
@@ -360,9 +410,18 @@ export function useFlowDesigner(lfContainer: Ref<HTMLDivElement | undefined>) {
|
|
|
} else {
|
|
} else {
|
|
|
lf.render({ nodes: defaultNodes(), edges: [] })
|
|
lf.render({ nodes: defaultNodes(), edges: [] })
|
|
|
}
|
|
}
|
|
|
|
|
+ nextTick(() => syncAllSubNodeBadges())
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 节点类型映射:LogicFlow <-> 后端
|
|
|
|
|
|
|
+ function syncAllSubNodeBadges() {
|
|
|
|
|
+ if (!lf) return
|
|
|
|
|
+ const graphData = lf.getGraphData()
|
|
|
|
|
+ for (const node of graphData.nodes || []) {
|
|
|
|
|
+ if (node.type !== 'approval-node') continue
|
|
|
|
|
+ const props = node.properties || {}
|
|
|
|
|
+ syncNodeTextWithSubNodeBadge(node.id, props.subNodesEnabled, props.subNodes)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
const typeToBackend: Record<string, string> = {
|
|
const typeToBackend: Record<string, string> = {
|
|
|
'start-node': 'start',
|
|
'start-node': 'start',
|
|
|
'approval-node': 'approval',
|
|
'approval-node': 'approval',
|
|
@@ -390,6 +449,8 @@ export function useFlowDesigner(lfContainer: Ref<HTMLDivElement | undefined>) {
|
|
|
// text -> name
|
|
// text -> name
|
|
|
if (n.text !== undefined) {
|
|
if (n.text !== undefined) {
|
|
|
n.name = typeof n.text === 'object' ? n.text.value : n.text
|
|
n.name = typeof n.text === 'object' ? n.text.value : n.text
|
|
|
|
|
+ // 去掉子节点数量角标,避免保存到后端
|
|
|
|
|
+ n.name = String(n.name).replace(/ \(\+\d+\)$/, '')
|
|
|
delete n.text
|
|
delete n.text
|
|
|
}
|
|
}
|
|
|
return n
|
|
return n
|
|
@@ -478,7 +539,7 @@ export function useFlowDesigner(lfContainer: Ref<HTMLDivElement | undefined>) {
|
|
|
}
|
|
}
|
|
|
// name -> text
|
|
// name -> text
|
|
|
if (n.name !== undefined) {
|
|
if (n.name !== undefined) {
|
|
|
- n.text = n.name
|
|
|
|
|
|
|
+ n.text = String(n.name).replace(/ \(\+\d+\)$/, '')
|
|
|
delete n.name
|
|
delete n.name
|
|
|
}
|
|
}
|
|
|
return n
|
|
return n
|
|
@@ -816,6 +877,7 @@ export function useFlowDesigner(lfContainer: Ref<HTMLDivElement | undefined>) {
|
|
|
saveCurrentNodeProps,
|
|
saveCurrentNodeProps,
|
|
|
loadNodeProps,
|
|
loadNodeProps,
|
|
|
updateNodeName,
|
|
updateNodeName,
|
|
|
|
|
+ generateSubNodeId,
|
|
|
// save dialog
|
|
// save dialog
|
|
|
saveDialogVisible,
|
|
saveDialogVisible,
|
|
|
saveForm,
|
|
saveForm,
|