|
|
@@ -39,6 +39,7 @@ export function useFlowDesigner(lfContainer: Ref<HTMLDivElement | undefined>) {
|
|
|
const nodeProps = reactive<Record<string, any>>({
|
|
|
assigneeType: 'ROLE',
|
|
|
assigneeValue: '',
|
|
|
+ nodeKey: '',
|
|
|
approveMode: 'or',
|
|
|
timeoutHours: undefined as number | undefined,
|
|
|
timeoutAction: 'remind',
|
|
|
@@ -131,6 +132,7 @@ export function useFlowDesigner(lfContainer: Ref<HTMLDivElement | undefined>) {
|
|
|
return {
|
|
|
assigneeType: 'ROLE',
|
|
|
assigneeValue: '',
|
|
|
+ nodeKey: '',
|
|
|
approveMode: 'or',
|
|
|
timeoutHours: undefined,
|
|
|
timeoutAction: 'remind',
|
|
|
@@ -152,6 +154,7 @@ export function useFlowDesigner(lfContainer: Ref<HTMLDivElement | undefined>) {
|
|
|
if (type === 'approval-node') {
|
|
|
props.assigneeType = nodeProps.assigneeType ?? 'ROLE'
|
|
|
props.assigneeValue = nodeProps.assigneeValue ?? ''
|
|
|
+ props.nodeKey = nodeProps.nodeKey ?? ''
|
|
|
props.approveMode = nodeProps.approveMode ?? 'or'
|
|
|
props.timeoutHours = nodeProps.timeoutHours
|
|
|
props.timeoutAction = nodeProps.timeoutAction ?? 'remind'
|
|
|
@@ -198,7 +201,7 @@ export function useFlowDesigner(lfContainer: Ref<HTMLDivElement | undefined>) {
|
|
|
Object.assign(nodeProps, getDefaultProps(data.type))
|
|
|
// 兼容旧格式:approver + approveType -> 新格式
|
|
|
if (data.type === 'approval-node') {
|
|
|
- const supportedTypes = ['ROLE', 'SELF']
|
|
|
+ const supportedTypes = ['ROLE', 'SELF', 'EXTERNAL']
|
|
|
let assigneeType = cloned.assigneeType ?? 'ROLE'
|
|
|
let assigneeValue = cloned.assigneeValue ?? ''
|
|
|
const approveMode = cloned.approveMode ?? cloned.approveType ?? 'or'
|
|
|
@@ -206,17 +209,18 @@ export function useFlowDesigner(lfContainer: Ref<HTMLDivElement | undefined>) {
|
|
|
assigneeType = 'ROLE'
|
|
|
assigneeValue = cloned.approver
|
|
|
}
|
|
|
- // 当前设计器只支持 ROLE / SELF,其它旧类型降级为 ROLE 并清空值
|
|
|
+ // 当前设计器支持 ROLE / SELF / EXTERNAL,其它旧类型降级为 ROLE 并清空值
|
|
|
if (!supportedTypes.includes(assigneeType)) {
|
|
|
assigneeType = 'ROLE'
|
|
|
assigneeValue = ''
|
|
|
}
|
|
|
- // SELF 不需要审批角色值
|
|
|
- if (assigneeType === 'SELF') {
|
|
|
+ // SELF / EXTERNAL 不需要审批角色值
|
|
|
+ if (assigneeType === 'SELF' || assigneeType === 'EXTERNAL') {
|
|
|
assigneeValue = ''
|
|
|
}
|
|
|
nodeProps.assigneeType = assigneeType
|
|
|
nodeProps.assigneeValue = assigneeValue
|
|
|
+ nodeProps.nodeKey = cloned.nodeKey ?? ''
|
|
|
nodeProps.approveMode = approveMode
|
|
|
nodeProps.timeoutHours = cloned.timeoutHours ?? undefined
|
|
|
nodeProps.timeoutAction = cloned.timeoutAction ?? 'remind'
|
|
|
@@ -655,6 +659,13 @@ export function useFlowDesigner(lfContainer: Ref<HTMLDivElement | undefined>) {
|
|
|
optionDialogVisible.value = false
|
|
|
}
|
|
|
|
|
|
+ function getNodeDisplayName(node: any): string {
|
|
|
+ // LogicFlow 的 node.text 可能是 { value: '节点名' },直接拼接会变成 [object Object]
|
|
|
+ const text = node?.text
|
|
|
+ const value = text && typeof text === 'object' ? text.value : text
|
|
|
+ return String(value || node?.name || '未命名节点')
|
|
|
+ }
|
|
|
+
|
|
|
function validateFlow(graphData: any): string | null {
|
|
|
const nodes = graphData.nodes || []
|
|
|
const edges = graphData.edges || []
|
|
|
@@ -665,25 +676,39 @@ export function useFlowDesigner(lfContainer: Ref<HTMLDivElement | undefined>) {
|
|
|
if (endNodes.length === 0) return '流程图缺少结束节点'
|
|
|
if (startNodes.length > 1) return '流程图只能有一个开始节点'
|
|
|
// 检查审批节点是否配置了审批对象
|
|
|
+ const externalNodeKeys = new Set<string>()
|
|
|
for (const node of nodes) {
|
|
|
if (node.type === 'approval-node' || node.type === 'approval') {
|
|
|
const props = node.properties || {}
|
|
|
const assigneeType = props.assigneeType ?? 'ROLE'
|
|
|
const assigneeValue = props.assigneeValue || props.approver
|
|
|
if (assigneeType === 'ROLE' && !assigneeValue && props.subNodesEnabled !== true) {
|
|
|
- return `审批节点 "${node.text || node.name}" 未选择审批角色`
|
|
|
+ return `审批节点 ${getNodeDisplayName(node)} 未选择审批角色`
|
|
|
+ }
|
|
|
+ if (assigneeType === 'EXTERNAL') {
|
|
|
+ if (props.subNodesEnabled === true) {
|
|
|
+ return `审批节点 ${getNodeDisplayName(node)} 使用外部指定审批人时不支持子节点`
|
|
|
+ }
|
|
|
+ const nodeKey = String(props.nodeKey || '').trim()
|
|
|
+ if (!nodeKey) {
|
|
|
+ return `审批节点 ${getNodeDisplayName(node)} 未填写节点编码(nodeKey)`
|
|
|
+ }
|
|
|
+ if (externalNodeKeys.has(nodeKey)) {
|
|
|
+ return `节点编码 "${nodeKey}" 重复,请保证每个外部指定节点编码唯一`
|
|
|
+ }
|
|
|
+ externalNodeKeys.add(nodeKey)
|
|
|
}
|
|
|
if (props.subNodesEnabled === true) {
|
|
|
const subNodes = props.subNodes || []
|
|
|
if (subNodes.length === 0) {
|
|
|
- return `审批节点 "${node.text || node.name}" 已启用子节点,请至少配置一个子节点`
|
|
|
+ return `审批节点 ${getNodeDisplayName(node)} 已启用子节点,请至少配置一个子节点`
|
|
|
}
|
|
|
for (let i = 0; i < subNodes.length; i++) {
|
|
|
const sub = subNodes[i]
|
|
|
const subAssigneeType = sub.assigneeType ?? 'ROLE'
|
|
|
const subAssigneeValue = sub.assigneeValue
|
|
|
if (subAssigneeType === 'ROLE' && !subAssigneeValue) {
|
|
|
- return `审批节点 "${node.text || node.name}" 的子节点 ${i + 1} 未选择审批角色`
|
|
|
+ return `审批节点 ${getNodeDisplayName(node)} 的子节点 ${i + 1} 未选择审批角色`
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -703,7 +728,7 @@ export function useFlowDesigner(lfContainer: Ref<HTMLDivElement | undefined>) {
|
|
|
node.type !== 'end-node' &&
|
|
|
node.type !== 'end'
|
|
|
) {
|
|
|
- return `节点 "${node.text || node.name}" 是孤立节点,请删除或连接`
|
|
|
+ return `节点 ${getNodeDisplayName(node)} 是孤立节点,请删除或连接`
|
|
|
}
|
|
|
}
|
|
|
// 检查条件分支:有且只能有一个默认分支,非默认分支必须填写条件
|
|
|
@@ -721,17 +746,17 @@ export function useFlowDesigner(lfContainer: Ref<HTMLDivElement | undefined>) {
|
|
|
return props.isDefault || (!props.condition && !e.condition)
|
|
|
})
|
|
|
if (defaultEdges.length === 0) {
|
|
|
- return `条件节点 "${node.text || node.name}" 需要至少一条默认分支`
|
|
|
+ return `条件节点 ${getNodeDisplayName(node)} 需要至少一条默认分支`
|
|
|
}
|
|
|
if (defaultEdges.length > 1) {
|
|
|
- return `条件节点 "${node.text || node.name}" 只能有一条默认分支`
|
|
|
+ return `条件节点 ${getNodeDisplayName(node)} 只能有一条默认分支`
|
|
|
}
|
|
|
const invalid = outEdges.some((e: any) => {
|
|
|
const props = e.properties || {}
|
|
|
return !props.isDefault && !props.condition && !e.condition
|
|
|
})
|
|
|
if (invalid) {
|
|
|
- return `条件节点 "${node.text || node.name}" 的非默认分支必须填写条件表达式`
|
|
|
+ return `条件节点 ${getNodeDisplayName(node)} 的非默认分支必须填写条件表达式`
|
|
|
}
|
|
|
}
|
|
|
}
|