Pārlūkot izejas kodu

添加动态指派功能

kagg886 2 mēneši atpakaļ
vecāks
revīzija
7a6d8a36c3

+ 6 - 3
src/components/gFlow/propertySetting/CommonProperty.vue

@@ -15,7 +15,9 @@
 						<el-option v-for="item in actionRuleOption" :key="item.value" :label="item.label" :value="item.value" />
 					</el-select>
 				</el-form-item>
-				<el-form-item label="指定指派表达式" v-show="formData.actionRule == FlowCheckDynamicJudge"> </el-form-item>
+				<el-form-item label="指定指派表达式" v-show="formData.actionRule == FlowCheckDynamicJudge">
+					<dynamic-judge-input v-model="formData.dynamicJudge" :readonly="readonly" />
+				</el-form-item>
 				<el-form-item
 					label="指定上级部门"
 					v-show="formData.actionRule === FlowCheckRuleFormCreatorDeptPrev || formData.actionRule === FlowCheckRuleFormCreatorDeptLeaderPrev"
@@ -91,8 +93,8 @@
 				</el-form-item>
 				<el-form-item label="允许退回" v-show="nodeType !== NodeTypeStart">
 					<el-radio-group v-model="formData.rollback" :disabled="readonly">
-						<el-radio label="1">是</el-radio>
-						<el-radio label="0">否</el-radio>
+						<el-radio :label="1">是</el-radio>
+						<el-radio :label="0">否</el-radio>
 					</el-radio-group>
 				</el-form-item>
 				<el-form-item label="分支条件" v-show="nodeType === NodeTypeCondition">
@@ -166,6 +168,7 @@ import {
 } from '/@/components/gFlow/consts'
 import systemApi from '/@/api/system'
 import WebhookParams from '/@/components/gFlow/propertySetting/webhookParams.vue'
+import DynamicJudgeInput from '/@/components/gFlow/propertySetting/DynamicJudgeInput.vue'
 
 interface PostInfo {
 	postId: number

+ 296 - 0
src/components/gFlow/propertySetting/DynamicJudgeInput.vue

@@ -0,0 +1,296 @@
+<template>
+	<div class="dynamic-judge-input">
+		<div class="input-container">
+			<el-input
+				ref="inputRef"
+				v-model="expression"
+				placeholder="请输入动态指派表达式,如:\{\{.userId\}\}"
+				:disabled="readonly"
+				type="textarea"
+				:autosize="{ minRows: 3, maxRows: 6 }"
+				@focus="onInputFocus"
+				@blur="onInputBlur"
+			/>
+			<el-popover placement="bottom" :width="600" trigger="click" @hide="handlePopoverHide">
+				<template #reference>
+					<el-button type="primary" size="small" :disabled="readonly" class="template-btn"> 插入字段 </el-button>
+				</template>
+				<div class="popover-content">
+					<div class="two-column-layout">
+						<!-- 第一列:表单类别 -->
+						<div class="left-column">
+							<div class="column-title">表单类别</div>
+							<div class="category-list">
+								<div
+									v-for="item in flowForms"
+									:key="item.value"
+									class="category-item"
+									:class="{ active: currentSelectCate === item }"
+									@click="selectCategory(item)"
+								>
+									{{ item.label }}
+								</div>
+							</div>
+						</div>
+
+						<!-- 第二列:字段列表 -->
+						<div class="right-column">
+							<div class="column-title">字段列表</div>
+							<div class="field-list">
+								<div v-for="field in currentListSelectCate" :key="field.key" class="field-item" @click="insertField(field.key)">
+									<div class="field-name">{{ field.key }}</div>
+									<div class="field-type">{{ field.type }}</div>
+									<div class="field-desc">{{ field.dc }}</div>
+								</div>
+							</div>
+						</div>
+					</div>
+				</div>
+			</el-popover>
+		</div>
+
+		<div class="help-text">
+			<el-text type="info" size="small"> 表达式的值应为用户id </el-text>
+		</div>
+	</div>
+</template>
+
+<script lang="ts" setup>
+import { computed, getCurrentInstance, Ref, ref, watch } from 'vue'
+import { asyncComputed, useAsyncState } from '@vueuse/core'
+import { getFlowFields, getFlowForm, listFlowForm } from '/@/api/flow/flowForm'
+
+const { proxy } = getCurrentInstance() as any
+const {
+	flow_model_cate,
+}: {
+	[key: string]: Ref<
+		Array<{
+			label: string
+			value: string
+			meta?: FlowFieldsInSql['infos']
+		}>
+	>
+} = proxy.useDict('flow_model_cate')
+
+// 定义组件的 Props
+interface Props {
+	modelValue: string
+	readonly?: boolean
+}
+
+type FlowFieldsInSql = {
+	infos: Array<{
+		key: string
+		type: string
+		dc: string
+	}>
+}
+
+const props = withDefaults(defineProps<Props>(), {
+	readonly: false,
+})
+
+const emit = defineEmits(['update:modelValue'])
+
+// 输入框引用
+const inputRef = ref()
+// 光标位置
+const cursorPosition = ref(0)
+
+const expression = computed<string>({
+	get() {
+		return props.modelValue ?? ''
+	},
+	set(value) {
+		emit('update:modelValue', value)
+	},
+})
+
+// 输入框获得焦点时记录光标位置
+const onInputFocus = () => {
+	setTimeout(() => {
+		if (inputRef.value?.textarea) {
+			cursorPosition.value = inputRef.value.textarea.selectionStart
+		}
+	}, 0)
+}
+
+// 输入框失去焦点时记录光标位置
+const onInputBlur = () => {
+	if (inputRef.value?.textarea) {
+		cursorPosition.value = inputRef.value.textarea.selectionStart
+	}
+}
+
+const currentSelectCate = ref<any | undefined>(undefined)
+
+// 选择表单类别
+const selectCategory = (categoryValue: any) => {
+	currentSelectCate.value = categoryValue
+}
+
+// 插入字段到表达式中
+const insertField = (fieldKey: string) => {
+	const fieldTemplate = `{{.${fieldKey}}}`
+	const currentValue = expression.value || ''
+
+	// 在光标位置插入字段模板
+	const beforeCursor = currentValue.substring(0, cursorPosition.value)
+	const afterCursor = currentValue.substring(cursorPosition.value)
+	const newValue = beforeCursor + fieldTemplate + afterCursor
+
+	expression.value = newValue
+
+	// 更新光标位置
+	cursorPosition.value += fieldTemplate.length
+
+	// 重新聚焦到输入框并设置光标位置
+	setTimeout(() => {
+		if (inputRef.value?.textarea) {
+			inputRef.value.textarea.focus()
+			inputRef.value.textarea.setSelectionRange(cursorPosition.value, cursorPosition.value)
+		}
+	}, 0)
+}
+
+const flowForms = asyncComputed<{ label: string; value: string; meta?: FlowFieldsInSql['infos'] }[]>(async () => {
+	const form = await Promise.all(
+		((await listFlowForm({ pageNum: 1, pageSize: 10 })) as unknown as { list: { name: string; id: number }[] }).list.map(async (detail) => {
+			const form_fields_resp = (await getFlowForm(detail.id)) as unknown as { fields: string[]; name: string }
+
+			const fields = form_fields_resp.fields.map((it) => JSON.parse(it)) as unknown as {
+				field: string
+				type: string
+				title: string
+			}[]
+			return {
+				label: form_fields_resp.name,
+				value: form_fields_resp.name,
+				meta: fields.map((it) => {
+					return {
+						key: it.field,
+						type: it.type,
+						dc: it.title,
+					}
+				}),
+			}
+		})
+	)
+
+	return [...flow_model_cate.value, ...form]
+})
+
+watch(currentSelectCate, (newListSelectCate: string) => {
+	if (newListSelectCate === undefined || newListSelectCate === '') return
+	selectCate(100, newListSelectCate)
+})
+
+const { state: currentListSelectCate, execute: selectCate } = useAsyncState(
+	async (data) => {
+		if (data.meta !== undefined) {
+			return data.meta
+		}
+		return await getFlowFields(data.value)
+			.then((res: any) => (res as FlowFieldsInSql).infos)
+			.then((res) => res.filter((it) => it.key !== ''))
+			.catch(() => [] as FlowFieldsInSql['infos'])
+	},
+	[] as FlowFieldsInSql['infos'],
+	{ immediate: false }
+)
+
+// 监听popover关闭,重置组件状态
+const handlePopoverHide = () => {
+	currentSelectCate.value = ''
+	currentListSelectCate.value = []
+}
+</script>
+
+<style scoped lang="scss">
+.dynamic-judge-input {
+	width: 100%;
+
+	.input-container {
+		position: relative;
+
+		.template-btn {
+			position: absolute;
+			top: 8px;
+			right: 8px;
+			z-index: 10;
+		}
+	}
+
+	.help-text {
+		margin-top: 8px;
+	}
+}
+
+.popover-content {
+	.two-column-layout {
+		display: flex;
+		gap: 16px;
+		height: 300px;
+
+		.left-column,
+		.right-column {
+			flex: 1;
+			display: flex;
+			flex-direction: column;
+			border: 1px solid #e4e7ed;
+			border-radius: 4px;
+			overflow: hidden;
+
+			.column-title {
+				padding: 8px 12px;
+				background-color: #f5f7fa;
+				border-bottom: 1px solid #e4e7ed;
+				font-weight: 500;
+				font-size: 14px;
+			}
+
+			.category-list,
+			.field-list {
+				flex: 1;
+				overflow-y: auto;
+				padding: 4px 0;
+
+				.category-item,
+				.field-item {
+					padding: 8px 12px;
+					cursor: pointer;
+					transition: background-color 0.2s;
+
+					&:hover {
+						background-color: #f5f7fa;
+					}
+
+					&.active {
+						background-color: #409eff;
+						color: white;
+					}
+				}
+
+				.field-item {
+					.field-name {
+						font-weight: 500;
+						margin-bottom: 2px;
+					}
+
+					.field-type {
+						font-size: 12px;
+						color: #909399;
+						margin-bottom: 2px;
+					}
+
+					.field-desc {
+						font-size: 12px;
+						color: #606266;
+					}
+				}
+			}
+		}
+	}
+}
+</style>

+ 189 - 182
src/components/gFlow/showDesign.vue

@@ -1,49 +1,55 @@
 <template>
-  <div class="FL-container getting-started">
-    <!-- 画布 -->
-    <div class="app-content" ref="logicFlowContainerRef"></div>
-    <!-- 属性面板 -->
-    <el-drawer title="设置节点属性" v-model="dialogVisible" direction="rtl" size="900px" :before-close="closeDialog">
-      <PropertyDialog v-if="dialogVisible" :nodeData="clickNode" :lf="lf as LogicFlow" @setPropertiesFinish="closeDialog" :readonly="true"></PropertyDialog>
-    </el-drawer>
-  </div>
+	<div class="FL-container getting-started">
+		<!-- 画布 -->
+		<div class="app-content" ref="logicFlowContainerRef"></div>
+		<!-- 属性面板 -->
+		<el-drawer title="设置节点属性" v-model="dialogVisible" direction="rtl" size="900px" :before-close="closeDialog">
+			<PropertyDialog
+				v-if="dialogVisible"
+				:nodeData="clickNode"
+				:lf="lf as LogicFlow"
+				@setPropertiesFinish="closeDialog"
+				:readonly="true"
+			></PropertyDialog>
+		</el-drawer>
+	</div>
 </template>
 
 <script setup lang="ts">
-import LogicFlow, {BaseEdgeModel, BaseNodeModel} from "@logicflow/core";
-import "@logicflow/core/lib/style/index.css";
-import '@logicflow/extension/lib/style/index.css';
-import {ref} from "vue";
-import {setTheme} from "/@/components/gFlow/config";
+import LogicFlow, { BaseEdgeModel, BaseNodeModel } from '@logicflow/core'
+import '@logicflow/core/lib/style/index.css'
+import '@logicflow/extension/lib/style/index.css'
+import { ref } from 'vue'
+import { setTheme } from '/@/components/gFlow/config'
 
 import {
-  registerEnd,
-  registerStart,
-  registerStartDone,
-  registerConcurrent,
-  registerPush,
-  registerCondition,
-  registerUserTask, registerEdgeDone, registerConditionDone, registerEndDone, registerConcurrentDone, registerPushDone,
-	registerWebHook, registerWebHookDone
-} from "/@/components/gFlow/registerNode";
-import PropertyDialog from "/@/components/gFlow/propertySetting/PropertyDialog.vue";
-import {getNodeData} from "/@/api/flow/flowModel";
-import {
-  FlowCheckRuleDept,
-  FlowCheckRuleDeptLeader, FlowCheckRulePost,
-  FlowCheckRuleRole,
-  FlowCheckRuleUser
-} from "/@/components/gFlow/consts";
-import registerUserTaskDone from "./registerNode/registerUserTaskDone";
-
+	registerConcurrent,
+	registerConcurrentDone,
+	registerCondition,
+	registerConditionDone,
+	registerEdgeDone,
+	registerEnd,
+	registerEndDone,
+	registerPush,
+	registerPushDone,
+	registerStart,
+	registerStartDone,
+	registerUserTask,
+	registerWebHook,
+	registerWebHookDone,
+} from '/@/components/gFlow/registerNode'
+import PropertyDialog from '/@/components/gFlow/propertySetting/PropertyDialog.vue'
+import { getNodeData } from '/@/api/flow/flowModel'
+import { FlowCheckRuleDept, FlowCheckRuleDeptLeader, FlowCheckRulePost, FlowCheckRuleRole, FlowCheckRuleUser } from '/@/components/gFlow/consts'
+import registerUserTaskDone from './registerNode/registerUserTaskDone'
 
 const modelId = ref(0)
 const nodeId = ref('')
 const logicFlowContainerRef = ref()
 const lf = ref<LogicFlow>({} as LogicFlow)
 const addPanelStyle = ref({
-  top: '0',
-  left: '0',
+	top: '0',
+	left: '0',
 })
 const showAddPanel = ref(false)
 const addClickNode = ref<any>()
@@ -51,178 +57,179 @@ const clickNode = ref({})
 const dialogVisible = ref(false)
 const moveData = ref({})
 
-const showDesign = (params:any)=>{
-  modelId.value = params.flowId
-  nodeId.value = params.processId
-  lf.value = new LogicFlow({
-    container: logicFlowContainerRef.value,
-    grid: false,
-  })
-  registerNode()
-  initLF()
+const showDesign = (params: any) => {
+	modelId.value = params.flowId
+	nodeId.value = params.processId
+	lf.value = new LogicFlow({
+		container: logicFlowContainerRef.value,
+		grid: false,
+	})
+	registerNode()
+	initLF()
 }
 //注册节点信息
-const registerNode = ()=>{
-  const logicFlow = lf.value as LogicFlow
-  registerStart(logicFlow)
-  registerStartDone(logicFlow)
-  registerEnd(logicFlow)
-  registerEndDone(logicFlow)
-  registerConcurrent(logicFlow)
-  registerConcurrentDone(logicFlow)
-  registerPush(logicFlow)
-  registerPushDone(logicFlow)
-  registerCondition(logicFlow)
-  registerConditionDone(logicFlow)
-  registerUserTask(logicFlow)
-  registerUserTaskDone(logicFlow)
-  registerEdgeDone(logicFlow)
+const registerNode = () => {
+	const logicFlow = lf.value as LogicFlow
+	registerStart(logicFlow)
+	registerStartDone(logicFlow)
+	registerEnd(logicFlow)
+	registerEndDone(logicFlow)
+	registerConcurrent(logicFlow)
+	registerConcurrentDone(logicFlow)
+	registerPush(logicFlow)
+	registerPushDone(logicFlow)
+	registerCondition(logicFlow)
+	registerConditionDone(logicFlow)
+	registerUserTask(logicFlow)
+	registerUserTaskDone(logicFlow)
+	registerEdgeDone(logicFlow)
 	registerWebHook(logicFlow)
 	registerWebHookDone(logicFlow)
 }
-const initLF= async ()=>{
-  const logicFlow = lf.value as LogicFlow;
-  setTheme(logicFlow)
-  await $_render()
-  $_LfEvent()
-  //nodeId.value = 'f4330b11-25ff-4ced-b011-9730bf1be122' //测试用
-  //设置已经处理过的节点状态
-  if(nodeId.value!='') {
-    /*lf.value.getNodeOutgoingEdge(nodeId.value).map((edge: BaseEdgeModel) => {
+const initLF = async () => {
+	const logicFlow = lf.value as LogicFlow
+	setTheme(logicFlow)
+	await $_render()
+	$_LfEvent()
+	//nodeId.value = 'f4330b11-25ff-4ced-b011-9730bf1be122' //测试用
+	//设置已经处理过的节点状态
+	if (nodeId.value != '') {
+		/*lf.value.getNodeOutgoingEdge(nodeId.value).map((edge: BaseEdgeModel) => {
       lf.value.changeEdgeType(edge.id, "edgeDone")
     })
     const data = lf.value.getNodeDataById(nodeId.value)
     lf.value.changeNodeType(nodeId.value,data?.type+"Done")*/
-    setDonePrevNode(nodeId.value)
-  }
+		setDonePrevNode(nodeId.value)
+	}
 }
-const setDonePrevNode = (nodeId:string)=>{
-  lf.value.getNodeIncomingNode(nodeId).map((node:BaseNodeModel)=>{
-    if(node.type.indexOf("Done")>=0){
-      return
-    }
-    lf.value.changeNodeType(node.id,node.type+"Done")
-    lf.value.getNodeOutgoingEdge(node.id).map((edge: BaseEdgeModel) => {
-      lf.value.changeEdgeType(edge.id, "edgeDone")
-    })
-    setDonePrevNode(node.id)
-  })
+const setDonePrevNode = (nodeId: string) => {
+	lf.value.getNodeIncomingNode(nodeId).map((node: BaseNodeModel) => {
+		if (node.type.indexOf('Done') >= 0) {
+			return
+		}
+		lf.value.changeNodeType(node.id, node.type + 'Done')
+		lf.value.getNodeOutgoingEdge(node.id).map((edge: BaseEdgeModel) => {
+			lf.value.changeEdgeType(edge.id, 'edgeDone')
+		})
+		setDonePrevNode(node.id)
+	})
 }
-const $_render = async ()=>{
-  //获取节点数据
-  return getNodeData(modelId.value).then((res:any)=>{
-    const nodes = (res.nodes??[]).map((item:any)=>{
-      const node = {
-        id: item.nodeId,
-        type: item.nodeType,
-        x: item.nodePosition.x,
-        y: item.nodePosition.y,
-        text: item.nodeText??{},
-        properties: {
-          text: item.nodeText?.value,
-          actionRule: item.nodeActionRule,
-          approveRule: item.nodeRule,
-          notice: item.notice ?? [],
-          rollback: item.rollback,
-          nodeExt: item.nodeExt??[],
-					deptProv: item.deptProv??1,
+const $_render = async () => {
+	//获取节点数据
+	return getNodeData(modelId.value).then((res: any) => {
+		const nodes = (res.nodes ?? []).map((item: any) => {
+			const node = {
+				id: item.nodeId,
+				type: item.nodeType,
+				x: item.nodePosition.x,
+				y: item.nodePosition.y,
+				text: item.nodeText ?? {},
+				properties: {
+					text: item.nodeText?.value,
+					actionRule: item.nodeActionRule,
+					approveRule: item.nodeRule,
+					notice: item.notice ?? [],
+					rollback: item.rollback,
+					nodeExt: item.nodeExt ?? [],
+					deptProv: item.deptProv ?? 1,
 					// WebHook 配置 - 从后端数据构建 webhook 对象
-					webhook: JSON.parse(item.ext ?? '{}')
-        }
-      }
-      setReceiver(node,item.nodeReceiver)
-      return node
-    })
-    const edges = (res.edges??[]).map((item:any)=>{
-      return {
-        id: item.id,
-        type: item.lineType,
-        sourceNodeId: item.sourceNodeId,
-        targetNodeId: item.targetNodeId,
-        startPoint:item.startPoint,
-        endPoint:item.endPoint,
-        properties: item.properties,
-        pointsList: item.pointsList,
-        text:item.text
-      }
-    })
-    lf.value.render({nodes,edges});
-    $_LfEvent();
-  })
+					webhook: JSON.parse(item.ext ?? '{}'),
+					dynamicJudge: JSON.parse(item.ext ?? '{}')?.userId,
+				},
+			}
+			setReceiver(node, item.nodeReceiver)
+			return node
+		})
+		const edges = (res.edges ?? []).map((item: any) => {
+			return {
+				id: item.id,
+				type: item.lineType,
+				sourceNodeId: item.sourceNodeId,
+				targetNodeId: item.targetNodeId,
+				startPoint: item.startPoint,
+				endPoint: item.endPoint,
+				properties: item.properties,
+				pointsList: item.pointsList,
+				text: item.text,
+			}
+		})
+		lf.value.render({ nodes, edges })
+		$_LfEvent()
+	})
 }
-const setReceiver = (node:any,receivers:Array<string>)=>{
-  switch(node.properties.actionRule){
-    case FlowCheckRuleRole://角色
-      node.properties.roleIds = receivers
-      break
-    case FlowCheckRuleDept://部门
-    case FlowCheckRuleDeptLeader://部门负责人
-      node.properties.deptIds = receivers
-      break
-    case FlowCheckRuleUser://指定人员
-      node.properties.userIds = receivers
-      break
-    case FlowCheckRulePost://岗位
-      node.properties.postIds = receivers
-  }
+const setReceiver = (node: any, receivers: Array<string>) => {
+	switch (node.properties.actionRule) {
+		case FlowCheckRuleRole: //角色
+			node.properties.roleIds = receivers
+			break
+		case FlowCheckRuleDept: //部门
+		case FlowCheckRuleDeptLeader: //部门负责人
+			node.properties.deptIds = receivers
+			break
+		case FlowCheckRuleUser: //指定人员
+			node.properties.userIds = receivers
+			break
+		case FlowCheckRulePost: //岗位
+			node.properties.postIds = receivers
+	}
 }
 
-const $_LfEvent=()=>{
-  const logicFlow = lf.value as LogicFlow;
-  logicFlow.on('node:click', (data) => {
-    console.log('node:click', data);
-    clickNode.value = data.data;
-    dialogVisible.value = true;
-  })
-  logicFlow.on('edge:click', ({ data }) => {
-    console.log('edge:click', data);
-    //this.$data.clickNode = data;
-    //this.$data.dialogVisible = true;
-  });
-  logicFlow.on('element:click', () => {
-    hideAddPanel();
-  });
-  logicFlow.on('edge:add', ({ data }) => {
-    console.log('edge:add', data);
-  });
-  logicFlow.on('node:mousemove', ({ data }) => {
-    console.log('node:mousemove');
-    moveData.value = data;
-  });
-  logicFlow.on('blank:click', () => {
-    hideAddPanel();
-  });
-  logicFlow.on('connection:not-allowed', (data) => {
-    console.log('connection:not-allowed',data)
-  });
-  logicFlow.on('node:mousemove', () => {
-    console.log('on mousemove');
-  });
+const $_LfEvent = () => {
+	const logicFlow = lf.value as LogicFlow
+	logicFlow.on('node:click', (data) => {
+		console.log('node:click', data)
+		clickNode.value = data.data
+		dialogVisible.value = true
+	})
+	logicFlow.on('edge:click', ({ data }) => {
+		console.log('edge:click', data)
+		//this.$data.clickNode = data;
+		//this.$data.dialogVisible = true;
+	})
+	logicFlow.on('element:click', () => {
+		hideAddPanel()
+	})
+	logicFlow.on('edge:add', ({ data }) => {
+		console.log('edge:add', data)
+	})
+	logicFlow.on('node:mousemove', ({ data }) => {
+		console.log('node:mousemove')
+		moveData.value = data
+	})
+	logicFlow.on('blank:click', () => {
+		hideAddPanel()
+	})
+	logicFlow.on('connection:not-allowed', (data) => {
+		console.log('connection:not-allowed', data)
+	})
+	logicFlow.on('node:mousemove', () => {
+		console.log('on mousemove')
+	})
 }
 const hideAddPanel = () => {
-  showAddPanel.value = false;
-  addPanelStyle.value.top = '0';
-  addPanelStyle.value.left = '0';
-  addClickNode.value = null;
+	showAddPanel.value = false
+	addPanelStyle.value.top = '0'
+	addPanelStyle.value.left = '0'
+	addClickNode.value = null
 }
 const closeDialog = () => {
-  dialogVisible.value = false;
+	dialogVisible.value = false
 }
-defineExpose({showDesign})
+defineExpose({ showDesign })
 </script>
 
 <style scoped lang="scss">
 .FL-container {
-  width: 100%;
-  overflow: hidden;
-  .app-content {
-    height: calc(100vh - 120px);
-  }
+	width: 100%;
+	overflow: hidden;
+	.app-content {
+		height: calc(100vh - 120px);
+	}
 }
-.demo-control{
-  position: absolute;
-  top: 20px;
-  right: 50px;
-  z-index: 2;
+.demo-control {
+	position: absolute;
+	top: 20px;
+	right: 50px;
+	z-index: 2;
 }
 </style>

+ 241 - 234
src/views/flow/flowModel/list/component/design.vue

@@ -1,52 +1,51 @@
 <template>
-  <div class="FL-container getting-started">
-    <!-- 辅助工具栏 -->
-    <Control class="demo-control" v-if="lf.container" :lf="lf as LogicFlow" @catData="$_catData" @saveModel="$_saveModel"></Control>
-    <!-- 画布 -->
-    <div class="app-content" ref="logicFlowContainerRef"></div>
-    <!-- 属性面板 -->
-    <el-drawer title="设置节点属性" v-model="dialogVisible" direction="rtl" size="900px" :before-close="closeDialog">
-      <PropertyDialog v-if="dialogVisible" :nodeData="clickNode" :lf="lf as LogicFlow" @setPropertiesFinish="closeDialog"></PropertyDialog>
-    </el-drawer>
-    <!-- 数据查看面板 -->
-    <el-dialog title="数据" v-model="dataVisible" width="50%">
-      <DataDialog :graphData="graphData"></DataDialog>
-    </el-dialog>
-  </div>
+	<div class="FL-container getting-started">
+		<!-- 辅助工具栏 -->
+		<Control class="demo-control" v-if="lf.container" :lf="lf as LogicFlow" @catData="$_catData" @saveModel="$_saveModel"></Control>
+		<!-- 画布 -->
+		<div class="app-content" ref="logicFlowContainerRef"></div>
+		<!-- 属性面板 -->
+		<el-drawer title="设置节点属性" v-model="dialogVisible" direction="rtl" size="900px" :before-close="closeDialog">
+			<PropertyDialog v-if="dialogVisible" :nodeData="clickNode" :lf="lf as LogicFlow" @setPropertiesFinish="closeDialog"></PropertyDialog>
+		</el-drawer>
+		<!-- 数据查看面板 -->
+		<el-dialog title="数据" v-model="dataVisible" width="50%">
+			<DataDialog :graphData="graphData"></DataDialog>
+		</el-dialog>
+	</div>
 </template>
 
 <script setup lang="ts">
-import LogicFlow from "@logicflow/core";
-import {DndPanel, Menu, MiniMap, SelectionSelect} from '@logicflow/extension';
-import "@logicflow/core/lib/style/index.css";
-import '@logicflow/extension/lib/style/index.css';
-import {onMounted, ref} from "vue";
-import Control from "/@/components/gFlow/Control.vue"
-import {setPatternItems, setTheme} from "/@/components/gFlow/config";
+import LogicFlow from '@logicflow/core'
+import { DndPanel, Menu, MiniMap, SelectionSelect, Snapshot } from '@logicflow/extension'
+import '@logicflow/core/lib/style/index.css'
+import '@logicflow/extension/lib/style/index.css'
+import { onMounted, ref } from 'vue'
+import Control from '/@/components/gFlow/Control.vue'
+import { setPatternItems, setTheme } from '/@/components/gFlow/config'
 
 import {
-  registerEnd,
-  registerStart,
-  registerConcurrent,
-  registerPush,
-  registerCondition,
-  registerUserTask,
+	registerConcurrent,
+	registerCondition,
+	registerEnd,
+	registerPush,
+	registerStart,
+	registerUserTask,
 	registerWebHook,
-} from "/@/components/gFlow/registerNode";
-
-import { Snapshot } from "@logicflow/extension";
-import PropertyDialog from "/@/components/gFlow/propertySetting/PropertyDialog.vue";
-import DataDialog from "/@/components/gFlow/DataDialog.vue";
-import {useRoute} from "vue-router";
-import {ElMessage} from "element-plus";
-import {getNodeData, saveModeNode} from "/@/api/flow/flowModel";
+} from '/@/components/gFlow/registerNode'
+import PropertyDialog from '/@/components/gFlow/propertySetting/PropertyDialog.vue'
+import DataDialog from '/@/components/gFlow/DataDialog.vue'
+import { useRoute } from 'vue-router'
+import { ElMessage } from 'element-plus'
+import { getNodeData, saveModeNode } from '/@/api/flow/flowModel'
 import {
-  FlowCheckRuleDept,
-  FlowCheckRuleDeptLeader, FlowCheckRulePost,
-  FlowCheckRuleRole,
-  FlowCheckRuleUser
-} from "/@/components/gFlow/consts";
-import GraphConfigData = LogicFlow.GraphConfigData;
+	FlowCheckRuleDept,
+	FlowCheckRuleDeptLeader,
+	FlowCheckRulePost,
+	FlowCheckRuleRole,
+	FlowCheckRuleUser
+} from '/@/components/gFlow/consts'
+import GraphConfigData = LogicFlow.GraphConfigData
 
 const route = useRoute()
 const modelId = ref(0)
@@ -55,229 +54,237 @@ const lf = ref<LogicFlow>({} as LogicFlow)
 const dataVisible = ref(false)
 const graphData = ref<GraphConfigData>()
 const addPanelStyle = ref({
-  top: '0',
-  left: '0',
+	top: '0',
+	left: '0',
 })
 const showAddPanel = ref(false)
 const addClickNode = ref<any>()
 const clickNode = ref({})
 const dialogVisible = ref(false)
 const moveData = ref({})
-onMounted(()=>{
-  if (route.query.id){
-    modelId.value = parseInt(route.query.id as string)
-  }else{
-    ElMessage.error('参数错误');
-    return
-  }
-  lf.value = new LogicFlow({
-    container: logicFlowContainerRef.value,
-    grid: true,
-    plugins: [DndPanel, SelectionSelect,Snapshot,Menu, MiniMap],
-    pluginsOptions: {
-      miniMap: {
-        isShowHeader: false,
-        isShowCloseIcon: true,
-        headerTitle: 'MiniMap'
-      }
-    }
-  })
-  registerNode()
-  initLF()
+onMounted(() => {
+	if (route.query.id) {
+		modelId.value = parseInt(route.query.id as string)
+	} else {
+		ElMessage.error('参数错误')
+		return
+	}
+	lf.value = new LogicFlow({
+		container: logicFlowContainerRef.value,
+		grid: true,
+		plugins: [DndPanel, SelectionSelect, Snapshot, Menu, MiniMap],
+		pluginsOptions: {
+			miniMap: {
+				isShowHeader: false,
+				isShowCloseIcon: true,
+				headerTitle: 'MiniMap',
+			},
+		},
+	})
+	registerNode()
+	initLF()
 })
 //注册节点信息
-const registerNode = ()=>{
-  const logicFlow = lf.value as LogicFlow
-  registerStart(logicFlow)
-  registerEnd(logicFlow)
-  registerConcurrent(logicFlow)
-  registerPush(logicFlow)
-  registerCondition(logicFlow)
-  registerUserTask(logicFlow)
+const registerNode = () => {
+	const logicFlow = lf.value as LogicFlow
+	registerStart(logicFlow)
+	registerEnd(logicFlow)
+	registerConcurrent(logicFlow)
+	registerPush(logicFlow)
+	registerCondition(logicFlow)
+	registerUserTask(logicFlow)
 	registerWebHook(logicFlow)
 }
 
-const initLF=()=>{
-  const logicFlow = lf.value as LogicFlow;
-  setPatternItems(logicFlow)
-  setTheme(logicFlow)
-  $_render()
-  $_LfEvent()
+const initLF = () => {
+	const logicFlow = lf.value as LogicFlow
+	setPatternItems(logicFlow)
+	setTheme(logicFlow)
+	$_render()
+	$_LfEvent()
 }
-const $_render = ()=>{
-  //获取节点数据
-  getNodeData(modelId.value).then((res:any)=>{
-    const nodes = (res.nodes??[]).map((item:any)=>{
-      const node = {
-        id: item.nodeId,
-        type: item.nodeType,
-        x: item.nodePosition.x,
-        y: item.nodePosition.y,
-        text: item.nodeText??{},
-        properties: {
-          text: item.nodeText?.value,
-          actionRule: item.nodeActionRule,
-          approveRule: item.nodeRule,
-          notice: item.notice ?? [],
-          rollback: item.rollback,
-          nodeExt: item.nodeExt??[],
-					deptProv: item.deptProv??1,
+const $_render = () => {
+	//获取节点数据
+	getNodeData(modelId.value).then((res: any) => {
+		const nodes = (res.nodes ?? []).map((item: any) => {
+			const node = {
+				id: item.nodeId,
+				type: item.nodeType,
+				x: item.nodePosition.x,
+				y: item.nodePosition.y,
+				text: item.nodeText ?? {},
+				properties: {
+					text: item.nodeText?.value,
+					actionRule: item.nodeActionRule,
+					approveRule: item.nodeRule,
+					notice: item.notice ?? [],
+					rollback: item.rollback,
+					nodeExt: item.nodeExt ?? [],
+					deptProv: item.deptProv ?? 1,
 					// WebHook 配置 - 从后端数据构建 webhook 对象
 					webhook: JSON.parse(item.ext ?? '{}'),
-        }
-      }
-      setReceiver(node,item.nodeReceiver)
-      return node
-    })
-    const edges = (res.edges??[]).map((item:any)=>{
-      return {
-        id: item.id,
-        type: item.lineType,
-        sourceNodeId: item.sourceNodeId,
-        targetNodeId: item.targetNodeId,
-        startPoint:item.startPoint,
-        endPoint:item.endPoint,
-        properties: item.properties,
-        pointsList: item.pointsList,
-        text:item.text
-      }
-    })
-    lf.value.render({nodes,edges});
-    $_LfEvent();
-  })
+
+					// 动态判断配置
+					dynamicJudge: JSON.parse(item.ext ?? '{}')?.userId,
+				},
+			}
+			setReceiver(node, item.nodeReceiver)
+			return node
+		})
+		const edges = (res.edges ?? []).map((item: any) => {
+			return {
+				id: item.id,
+				type: item.lineType,
+				sourceNodeId: item.sourceNodeId,
+				targetNodeId: item.targetNodeId,
+				startPoint: item.startPoint,
+				endPoint: item.endPoint,
+				properties: item.properties,
+				pointsList: item.pointsList,
+				text: item.text,
+			}
+		})
+		lf.value.render({ nodes, edges })
+		$_LfEvent()
+	})
 }
-const setReceiver = (node:any,receivers:Array<string>)=>{
-  switch(node.properties.actionRule){
-    case FlowCheckRuleRole://角色
-      node.properties.roleIds = receivers
-      break
-    case FlowCheckRuleDept://部门
-    case FlowCheckRuleDeptLeader://部门负责人
-      node.properties.deptIds = receivers
-      break
-    case FlowCheckRuleUser://指定人员
-      node.properties.userIds = receivers
-      break
-    case FlowCheckRulePost://岗位
-      node.properties.postIds = receivers
-  }
+const setReceiver = (node: any, receivers: Array<string>) => {
+	switch (node.properties.actionRule) {
+		case FlowCheckRuleRole: //角色
+			node.properties.roleIds = receivers
+			break
+		case FlowCheckRuleDept: //部门
+		case FlowCheckRuleDeptLeader: //部门负责人
+			node.properties.deptIds = receivers
+			break
+		case FlowCheckRuleUser: //指定人员
+			node.properties.userIds = receivers
+			break
+		case FlowCheckRulePost: //岗位
+			node.properties.postIds = receivers
+	}
 }
 const $_catData = () => {
-  graphData.value = lf.value.getGraphData() as GraphConfigData;
-  dataVisible.value = true;
+	graphData.value = lf.value.getGraphData() as GraphConfigData
+	dataVisible.value = true
 }
-const $_saveModel = ()=>{
-  const data = lf.value.getGraphData() as any
-  const nodes = data.nodes.map((item:any)=>{
-    return {
-      nodeId:item.id,
-      modelId:modelId.value,
-      nodeType:item.type,
-      nodePosition:{x:item.x,y:item.y},
-      nodeText:item.text,
-      nodeActionRule:item.properties?.actionRule,
-      nodeReceiver: getNodeReceiver(item.properties?.actionRule,item),
-      nodeRule:item.properties?.approveRule,
-      notice:item.properties?.notice,
-      rollback:item.properties?.rollback,
-      nodeExt:item.properties?.nodeExt,
-			deptProv:item.properties?.deptProv,
+const $_saveModel = () => {
+	const data = lf.value.getGraphData() as any
+	const nodes = data.nodes.map((item: any) => {
+		return {
+			nodeId: item.id,
+			modelId: modelId.value,
+			nodeType: item.type,
+			nodePosition: { x: item.x, y: item.y },
+			nodeText: item.text,
+			nodeActionRule: item.properties?.actionRule,
+			nodeReceiver: getNodeReceiver(item.properties?.actionRule, item),
+			nodeRule: item.properties?.approveRule,
+			notice: item.properties?.notice,
+			rollback: item.properties?.rollback,
+			nodeExt: item.properties?.nodeExt,
+			deptProv: item.properties?.deptProv,
 
-			// WebHook 相关配置 - 整合到 webhook 对象中
-			ext: item.properties?.webhook
-    }
-  })
-  const edges = data.edges.map((item:any)=>{
-    return {
-      modelId:modelId.value,
-      lineType:item.type,
-      sourceNodeId:item.sourceNodeId,
-      targetNodeId:item.targetNodeId,
-      startPoint:item.startPoint,
-      endPoint:item.endPoint,
-      properties:item.properties,
-      text:item.text,
-      pointsList:item.pointsList
-    }
-  })
-  const postData = {
-    modelId:modelId.value,
-    nodes:nodes,
-    edges:edges
-  }
-  saveModeNode(postData).then(()=>{
-		ElMessage.success('保存成功');
-  }).catch(()=> ElMessage.error('导出失败'))
+			ext: JSON.stringify({
+				// WebHook 相关配置 - 整合到 webhook 对象中
+				...item.properties?.webhook,
+				userId: item.properties?.dynamicJudge,
+			}),
+		}
+	})
+	const edges = data.edges.map((item: any) => {
+		return {
+			modelId: modelId.value,
+			lineType: item.type,
+			sourceNodeId: item.sourceNodeId,
+			targetNodeId: item.targetNodeId,
+			startPoint: item.startPoint,
+			endPoint: item.endPoint,
+			properties: item.properties,
+			text: item.text,
+			pointsList: item.pointsList,
+		}
+	})
+	const postData = {
+		modelId: modelId.value,
+		nodes: nodes,
+		edges: edges,
+	}
+	saveModeNode(postData)
+		.then(() => {
+			ElMessage.success('保存成功')
+		})
+		.catch(() => ElMessage.error('导出失败'))
 }
-const $_LfEvent=()=>{
-  const logicFlow = lf.value as LogicFlow;
-  logicFlow.on('node:click', (data) => {
-    console.log('node:click', data);
-    clickNode.value = data.data;
-    dialogVisible.value = true;
-  })
-  logicFlow.on('edge:click', ({ data }) => {
-    console.log('edge:click', data);
-    //this.$data.clickNode = data;
-    //this.$data.dialogVisible = true;
-  });
-  logicFlow.on('element:click', () => {
-    hideAddPanel();
-  });
-  logicFlow.on('edge:add', ({ data }) => {
-    console.log('edge:add', data);
-  });
-  logicFlow.on('node:mousemove', ({ data }) => {
-    console.log('node:mousemove');
-    moveData.value = data;
-  });
-  logicFlow.on('blank:click', () => {
-    hideAddPanel();
-  });
-  logicFlow.on('connection:not-allowed', (data) => {
-    console.log('connection:not-allowed',data)
-  });
-  logicFlow.on('node:mousemove', () => {
-    console.log('on mousemove');
-  });
+const $_LfEvent = () => {
+	const logicFlow = lf.value as LogicFlow
+	logicFlow.on('node:click', (data) => {
+		console.log('node:click', data)
+		clickNode.value = data.data
+		dialogVisible.value = true
+	})
+	logicFlow.on('edge:click', ({ data }) => {
+		console.log('edge:click', data)
+		//this.$data.clickNode = data;
+		//this.$data.dialogVisible = true;
+	})
+	logicFlow.on('element:click', () => {
+		hideAddPanel()
+	})
+	logicFlow.on('edge:add', ({ data }) => {
+		console.log('edge:add', data)
+	})
+	logicFlow.on('node:mousemove', ({ data }) => {
+		console.log('node:mousemove')
+		moveData.value = data
+	})
+	logicFlow.on('blank:click', () => {
+		hideAddPanel()
+	})
+	logicFlow.on('connection:not-allowed', (data) => {
+		console.log('connection:not-allowed', data)
+	})
+	logicFlow.on('node:mousemove', () => {
+		console.log('on mousemove')
+	})
 }
 const hideAddPanel = () => {
-  showAddPanel.value = false;
-  addPanelStyle.value.top = '0';
-  addPanelStyle.value.left = '0';
-  addClickNode.value = null;
+	showAddPanel.value = false
+	addPanelStyle.value.top = '0'
+	addPanelStyle.value.left = '0'
+	addClickNode.value = null
 }
 const closeDialog = () => {
-  dialogVisible.value = false;
+	dialogVisible.value = false
 }
-const getNodeReceiver = (rule:number,item:any)=>{
-  switch(rule){
-    case FlowCheckRuleRole://角色
-      return item.properties.roleIds
-    case FlowCheckRuleDept://部门
-    case FlowCheckRuleDeptLeader://部门负责人
-      return item.properties.deptIds
-    case FlowCheckRuleUser://指定人员
-      return item.properties.userIds
-    case FlowCheckRulePost://岗位
-      return item.properties.postIds
-  }
-  return []
+const getNodeReceiver = (rule: number, item: any) => {
+	switch (rule) {
+		case FlowCheckRuleRole: //角色
+			return item.properties.roleIds
+		case FlowCheckRuleDept: //部门
+		case FlowCheckRuleDeptLeader: //部门负责人
+			return item.properties.deptIds
+		case FlowCheckRuleUser: //指定人员
+			return item.properties.userIds
+		case FlowCheckRulePost: //岗位
+			return item.properties.postIds
+	}
+	return []
 }
 </script>
 
 <style scoped lang="scss">
 .FL-container {
-  width: 100%;
-  overflow: hidden;
-  .app-content {
-    height: calc(100vh - 120px);
-  }
+	width: 100%;
+	overflow: hidden;
+	.app-content {
+		height: calc(100vh - 120px);
+	}
 }
-.demo-control{
-  position: absolute;
-  top: 20px;
-  right: 50px;
-  z-index: 2;
+.demo-control {
+	position: absolute;
+	top: 20px;
+	right: 50px;
+	z-index: 2;
 }
 </style>