feat: [BPM 工作流] Simple 模型 - 触发器节点
							parent
							
								
									55fda075e2
								
							
						
					
					
						commit
						9587a8cdcd
					
				|  | @ -0,0 +1,174 @@ | |||
| <script setup lang="ts"> | ||||
| import { toRefs, watch } from 'vue'; | ||||
| 
 | ||||
| import { Plus, Trash2 } from '@vben/icons'; | ||||
| 
 | ||||
| import { | ||||
|   Alert, | ||||
|   Button, | ||||
|   Col, | ||||
|   FormItem, | ||||
|   Input, | ||||
|   Row, | ||||
|   Select, | ||||
|   SelectOption, | ||||
| } from 'ant-design-vue'; | ||||
| 
 | ||||
| import { useFormFields } from '../../../helpers'; | ||||
| import HttpRequestParamSetting from './http-request-param-setting.vue'; | ||||
| 
 | ||||
| defineOptions({ name: 'HttpRequestSetting' }); | ||||
| 
 | ||||
| const props = defineProps({ | ||||
|   setting: { | ||||
|     type: Object, | ||||
|     required: true, | ||||
|   }, | ||||
|   responseEnable: { | ||||
|     type: Boolean, | ||||
|     required: true, | ||||
|   }, | ||||
|   formItemPrefix: { | ||||
|     type: String, | ||||
|     required: true, | ||||
|   }, | ||||
| }); | ||||
| const emits = defineEmits(['update:setting']); | ||||
| const { setting } = toRefs(props); | ||||
| watch( | ||||
|   () => setting, | ||||
|   (val) => { | ||||
|     emits('update:setting', val); | ||||
|   }, | ||||
| ); | ||||
| 
 | ||||
| /** 流程表单字段 */ | ||||
| const formFields = useFormFields(); | ||||
| 
 | ||||
| /** 添加 HTTP 请求返回值设置项 */ | ||||
| const addHttpResponseSetting = (responseSetting: Record<string, string>[]) => { | ||||
|   responseSetting.push({ | ||||
|     key: '', | ||||
|     value: '', | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| /** 删除 HTTP 请求返回值设置项 */ | ||||
| const deleteHttpResponseSetting = ( | ||||
|   responseSetting: Record<string, string>[], | ||||
|   index: number, | ||||
| ) => { | ||||
|   responseSetting.splice(index, 1); | ||||
| }; | ||||
| </script> | ||||
| <template> | ||||
|   <FormItem> | ||||
|     <Alert | ||||
|       message="仅支持 POST 请求,以请求体方式接收参数" | ||||
|       type="warning" | ||||
|       show-icon | ||||
|       :closable="false" | ||||
|     /> | ||||
|   </FormItem> | ||||
|   <!-- 请求地址--> | ||||
|   <FormItem | ||||
|     label="请求地址" | ||||
|     :label-col="{ span: 24 }" | ||||
|     :wrapper-col="{ span: 24 }" | ||||
|     :name="[formItemPrefix, 'url']" | ||||
|     :rules="{ | ||||
|       required: true, | ||||
|       message: '请求地址不能为空', | ||||
|       trigger: ['blur', 'change'], | ||||
|     }" | ||||
|   > | ||||
|     <Input v-model:value="setting.url" placeholder="请输入请求地址" /> | ||||
|   </FormItem> | ||||
|   <!-- 请求头,请求体设置--> | ||||
|   <HttpRequestParamSetting | ||||
|     :header="setting.header" | ||||
|     :body="setting.body" | ||||
|     :bind="formItemPrefix" | ||||
|   /> | ||||
|   <!-- 返回值设置--> | ||||
|   <div v-if="responseEnable"> | ||||
|     <FormItem | ||||
|       label="返回值" | ||||
|       :label-col="{ span: 24 }" | ||||
|       :wrapper-col="{ span: 24 }" | ||||
|     > | ||||
|       <Alert | ||||
|         message="通过请求返回值, 可以修改流程表单的值" | ||||
|         type="warning" | ||||
|         show-icon | ||||
|         :closable="false" | ||||
|       /> | ||||
|     </FormItem> | ||||
|     <FormItem :wrapper-col="{ span: 24 }"> | ||||
|       <Row | ||||
|         :gutter="8" | ||||
|         v-for="(item, index) in setting.response" | ||||
|         :key="index" | ||||
|         class="mb-2" | ||||
|       > | ||||
|         <Col :span="10"> | ||||
|           <FormItem | ||||
|             :name="[formItemPrefix, 'response', index, 'key']" | ||||
|             :rules="{ | ||||
|               required: true, | ||||
|               message: '表单字段不能为空', | ||||
|               trigger: ['blur', 'change'], | ||||
|             }" | ||||
|           > | ||||
|             <Select | ||||
|               v-model:value="item.key" | ||||
|               placeholder="请选择表单字段" | ||||
|               allow-clear | ||||
|             > | ||||
|               <SelectOption | ||||
|                 v-for="(field, fIdx) in formFields" | ||||
|                 :key="fIdx" | ||||
|                 :label="field.title" | ||||
|                 :value="field.field" | ||||
|                 :disabled="!field.required" | ||||
|               > | ||||
|                 {{ field.title }} | ||||
|               </SelectOption> | ||||
|             </Select> | ||||
|           </FormItem> | ||||
|         </Col> | ||||
|         <Col :span="12"> | ||||
|           <FormItem | ||||
|             :name="[formItemPrefix, 'response', index, 'value']" | ||||
|             :rules="{ | ||||
|               required: true, | ||||
|               message: '请求返回字段不能为空', | ||||
|               trigger: ['blur', 'change'], | ||||
|             }" | ||||
|           > | ||||
|             <Input v-model:value="item.value" placeholder="请求返回字段" /> | ||||
|           </FormItem> | ||||
|         </Col> | ||||
|         <Col :span="2"> | ||||
|           <div class="flex h-[32px] items-center"> | ||||
|             <Trash2 | ||||
|               class="size-4 cursor-pointer text-red-500" | ||||
|               @click="deleteHttpResponseSetting(setting.response!, index)" | ||||
|             /> | ||||
|           </div> | ||||
|         </Col> | ||||
|       </Row> | ||||
|       <Button | ||||
|         type="link" | ||||
|         @click="addHttpResponseSetting(setting.response!)" | ||||
|         class="flex items-center" | ||||
|       > | ||||
|         <template #icon> | ||||
|           <Plus class="size-[18px]" /> | ||||
|         </template> | ||||
|         添加一行 | ||||
|       </Button> | ||||
|     </FormItem> | ||||
|   </div> | ||||
| </template> | ||||
| <style lang="scss" scoped></style> | ||||
|  | @ -0,0 +1,695 @@ | |||
| <script setup lang="ts"> | ||||
| import type { Rule } from 'ant-design-vue/es/form'; | ||||
| import type { SelectValue } from 'ant-design-vue/es/select'; | ||||
| 
 | ||||
| import type { | ||||
|   FormTriggerSetting, | ||||
|   SimpleFlowNode, | ||||
|   TriggerSetting, | ||||
| } from '../../consts'; | ||||
| 
 | ||||
| import { computed, getCurrentInstance, onMounted, reactive, ref } from 'vue'; | ||||
| 
 | ||||
| import { useVbenDrawer } from '@vben/common-ui'; | ||||
| import { IconifyIcon, Trash2 } from '@vben/icons'; | ||||
| import { cloneDeep } from '@vben/utils'; | ||||
| 
 | ||||
| import { | ||||
|   Button, | ||||
|   Card, | ||||
|   Col, | ||||
|   Divider, | ||||
|   Form, | ||||
|   FormItem, | ||||
|   Input, | ||||
|   message, | ||||
|   Row, | ||||
|   Select, | ||||
|   SelectOption, | ||||
|   Tag, | ||||
| } from 'ant-design-vue'; | ||||
| 
 | ||||
| import { | ||||
|   DEFAULT_CONDITION_GROUP_VALUE, | ||||
|   NodeType, | ||||
|   TRIGGER_TYPES, | ||||
|   TriggerTypeEnum, | ||||
| } from '../../consts'; | ||||
| import { | ||||
|   getConditionShowText, | ||||
|   useFormFields, | ||||
|   useNodeName, | ||||
|   useWatchNode, | ||||
| } from '../../helpers'; | ||||
| // TODO import ConditionDialog from './modules/condition-dialog.vue'; | ||||
| import HttpRequestSetting from './modules/http-request-setting.vue'; | ||||
| 
 | ||||
| defineOptions({ | ||||
|   name: 'TriggerNodeConfig', | ||||
| }); | ||||
| 
 | ||||
| const props = defineProps({ | ||||
|   flowNode: { | ||||
|     type: Object as () => SimpleFlowNode, | ||||
|     required: true, | ||||
|   }, | ||||
| }); | ||||
| 
 | ||||
| const { proxy } = getCurrentInstance() as any; | ||||
| 
 | ||||
| // 抽屉配置 | ||||
| const [Drawer, drawerApi] = useVbenDrawer({ | ||||
|   header: true, | ||||
|   closable: true, | ||||
|   title: '', | ||||
|   onCancel() { | ||||
|     drawerApi.close(); | ||||
|   }, | ||||
|   onConfirm() { | ||||
|     saveConfig(); | ||||
|   }, | ||||
| }); | ||||
| 
 | ||||
| // 当前节点 | ||||
| const currentNode = useWatchNode(props); | ||||
| // 节点名称 | ||||
| const { nodeName, showInput, clickIcon, blurEvent } = useNodeName( | ||||
|   NodeType.TRIGGER_NODE, | ||||
| ); | ||||
| // 触发器表单配置 | ||||
| const formRef = ref(); // 表单 Ref | ||||
| // 表单校验规则 | ||||
| const formRules: Record<string, Rule[]> = reactive({ | ||||
|   type: [{ required: true, message: '触发器类型不能为空', trigger: 'change' }], | ||||
|   'httpRequestSetting.url': [ | ||||
|     { required: true, message: '请求地址不能为空', trigger: 'blur' }, | ||||
|   ], | ||||
| }); | ||||
| // 触发器配置表单数据 | ||||
| const configForm = ref<TriggerSetting>({ | ||||
|   type: TriggerTypeEnum.HTTP_REQUEST, | ||||
|   httpRequestSetting: { | ||||
|     url: '', | ||||
|     header: [], | ||||
|     body: [], | ||||
|     response: [], | ||||
|   }, | ||||
|   formSettings: [ | ||||
|     { | ||||
|       conditionGroups: cloneDeep(DEFAULT_CONDITION_GROUP_VALUE), | ||||
|       updateFormFields: {}, | ||||
|       deleteFields: [], | ||||
|     }, | ||||
|   ], | ||||
| }); | ||||
| // 流程表单字段 | ||||
| const formFields = useFormFields(); | ||||
| 
 | ||||
| // 可选的修改的表单字段 | ||||
| const optionalUpdateFormFields = computed(() => { | ||||
|   return formFields.map((field) => ({ | ||||
|     title: field.title, | ||||
|     field: field.field, | ||||
|     disabled: false, | ||||
|   })); | ||||
| }); | ||||
| 
 | ||||
| let originalSetting: TriggerSetting | undefined; | ||||
| 
 | ||||
| /** 触发器类型改变了 */ | ||||
| const changeTriggerType = () => { | ||||
|   if (configForm.value.type === TriggerTypeEnum.HTTP_REQUEST) { | ||||
|     configForm.value.httpRequestSetting = | ||||
|       originalSetting?.type === TriggerTypeEnum.HTTP_REQUEST && | ||||
|       originalSetting.httpRequestSetting | ||||
|         ? originalSetting.httpRequestSetting | ||||
|         : { | ||||
|             url: '', | ||||
|             header: [], | ||||
|             body: [], | ||||
|             response: [], | ||||
|           }; | ||||
|     configForm.value.formSettings = undefined; | ||||
|     return; | ||||
|   } | ||||
| 
 | ||||
|   if (configForm.value.type === TriggerTypeEnum.HTTP_CALLBACK) { | ||||
|     configForm.value.httpRequestSetting = | ||||
|       originalSetting?.type === TriggerTypeEnum.HTTP_CALLBACK && | ||||
|       originalSetting.httpRequestSetting | ||||
|         ? originalSetting.httpRequestSetting | ||||
|         : { | ||||
|             url: '', | ||||
|             header: [], | ||||
|             body: [], | ||||
|             response: [], | ||||
|           }; | ||||
|     configForm.value.formSettings = undefined; | ||||
|     return; | ||||
|   } | ||||
| 
 | ||||
|   if (configForm.value.type === TriggerTypeEnum.FORM_UPDATE) { | ||||
|     configForm.value.formSettings = | ||||
|       originalSetting?.type === TriggerTypeEnum.FORM_UPDATE && | ||||
|       originalSetting.formSettings | ||||
|         ? originalSetting.formSettings | ||||
|         : [ | ||||
|             { | ||||
|               conditionGroups: cloneDeep(DEFAULT_CONDITION_GROUP_VALUE), | ||||
|               updateFormFields: {}, | ||||
|               deleteFields: [], | ||||
|             }, | ||||
|           ]; | ||||
|     configForm.value.httpRequestSetting = undefined; | ||||
|     return; | ||||
|   } | ||||
| 
 | ||||
|   if (configForm.value.type === TriggerTypeEnum.FORM_DELETE) { | ||||
|     configForm.value.formSettings = | ||||
|       originalSetting?.type === TriggerTypeEnum.FORM_DELETE && | ||||
|       originalSetting.formSettings | ||||
|         ? originalSetting.formSettings | ||||
|         : [ | ||||
|             { | ||||
|               conditionGroups: cloneDeep(DEFAULT_CONDITION_GROUP_VALUE), | ||||
|               updateFormFields: undefined, | ||||
|               deleteFields: [], | ||||
|             }, | ||||
|           ]; | ||||
|     configForm.value.httpRequestSetting = undefined; | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| /** 添加新的修改表单设置 */ | ||||
| const addFormSetting = () => { | ||||
|   configForm.value.formSettings!.push({ | ||||
|     conditionGroups: cloneDeep(DEFAULT_CONDITION_GROUP_VALUE), | ||||
|     updateFormFields: {}, | ||||
|     deleteFields: [], | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| /** 删除修改表单设置 */ | ||||
| const deleteFormSetting = (index: number) => { | ||||
|   configForm.value.formSettings!.splice(index, 1); | ||||
| }; | ||||
| 
 | ||||
| /** 添加条件配置 */ | ||||
| const addFormSettingCondition = ( | ||||
|   index: number, | ||||
|   formSetting: FormTriggerSetting, | ||||
| ) => { | ||||
|   const conditionDialog = proxy.$refs[`condition-${index}`][0]; | ||||
|   conditionDialog.open(formSetting); | ||||
| }; | ||||
| /** 删除条件配置 */ | ||||
| const deleteFormSettingCondition = (formSetting: FormTriggerSetting) => { | ||||
|   formSetting.conditionType = undefined; | ||||
| }; | ||||
| /** 打开条件配置弹窗 */ | ||||
| const openFormSettingCondition = ( | ||||
|   index: number, | ||||
|   formSetting: FormTriggerSetting, | ||||
| ) => { | ||||
|   const conditionDialog = proxy.$refs[`condition-${index}`][0]; | ||||
|   conditionDialog.open(formSetting); | ||||
| }; | ||||
| /** 处理条件配置保存 */ | ||||
| /* 暂时注释掉未使用的函数 | ||||
| const _handleConditionUpdate = (index: number, condition: any) => { | ||||
|   if (configForm.value.formSettings![index]) { | ||||
|     configForm.value.formSettings![index].conditionType = | ||||
|       condition.conditionType; | ||||
|     configForm.value.formSettings![index].conditionExpression = | ||||
|       condition.conditionExpression; | ||||
|     configForm.value.formSettings![index].conditionGroups = | ||||
|       condition.conditionGroups; | ||||
|   } | ||||
| }; | ||||
| */ | ||||
| /** 条件配置展示 */ | ||||
| const showConditionText = (formSetting: FormTriggerSetting) => { | ||||
|   return getConditionShowText( | ||||
|     formSetting.conditionType, | ||||
|     formSetting.conditionExpression, | ||||
|     formSetting.conditionGroups, | ||||
|     formFields, | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| /** 添加修改字段设置项 */ | ||||
| const addFormFieldSetting = (formSetting: FormTriggerSetting) => { | ||||
|   if (!formSetting) return; | ||||
|   if (!formSetting.updateFormFields) { | ||||
|     formSetting.updateFormFields = {}; | ||||
|   } | ||||
|   formSetting.updateFormFields[''] = undefined; | ||||
| }; | ||||
| /** 更新字段 KEY */ | ||||
| const updateFormFieldKey = ( | ||||
|   formSetting: FormTriggerSetting, | ||||
|   oldKey: string, | ||||
|   newKey: SelectValue, | ||||
| ) => { | ||||
|   if (!formSetting?.updateFormFields || !newKey) return; | ||||
|   const value = formSetting.updateFormFields[oldKey]; | ||||
|   delete formSetting.updateFormFields[oldKey]; | ||||
|   formSetting.updateFormFields[String(newKey)] = value; | ||||
| }; | ||||
| 
 | ||||
| /** 删除修改字段设置项 */ | ||||
| const deleteFormFieldSetting = ( | ||||
|   formSetting: FormTriggerSetting, | ||||
|   key: string, | ||||
| ) => { | ||||
|   if (!formSetting?.updateFormFields) return; | ||||
|   delete formSetting.updateFormFields[key]; | ||||
| }; | ||||
| 
 | ||||
| /** 保存配置 */ | ||||
| const saveConfig = async () => { | ||||
|   if (!formRef.value) return false; | ||||
|   const valid = await formRef.value.validate(); | ||||
|   if (!valid) return false; | ||||
|   const showText = getShowText(); | ||||
|   if (!showText) return false; | ||||
|   currentNode.value.name = nodeName.value!; | ||||
|   currentNode.value.showText = showText; | ||||
|   switch (configForm.value.type) { | ||||
|     case TriggerTypeEnum.FORM_DELETE: { | ||||
|       configForm.value.httpRequestSetting = undefined; | ||||
|       // 清理修改字段相关的数据 | ||||
|       configForm.value.formSettings?.forEach((setting) => { | ||||
|         setting.updateFormFields = undefined; | ||||
|       }); | ||||
| 
 | ||||
|       break; | ||||
|     } | ||||
|     case TriggerTypeEnum.FORM_UPDATE: { | ||||
|       configForm.value.httpRequestSetting = undefined; | ||||
|       // 清理删除字段相关的数据 | ||||
|       configForm.value.formSettings?.forEach((setting) => { | ||||
|         setting.deleteFields = undefined; | ||||
|       }); | ||||
| 
 | ||||
|       break; | ||||
|     } | ||||
|     case TriggerTypeEnum.HTTP_REQUEST: { | ||||
|       configForm.value.formSettings = undefined; | ||||
| 
 | ||||
|       break; | ||||
|     } | ||||
|     // No default | ||||
|   } | ||||
|   currentNode.value.triggerSetting = configForm.value; | ||||
|   drawerApi.close(); | ||||
|   return true; | ||||
| }; | ||||
| 
 | ||||
| /** 获取节点展示内容 */ | ||||
| const getShowText = (): string => { | ||||
|   let showText = ''; | ||||
|   switch (configForm.value.type) { | ||||
|     case TriggerTypeEnum.FORM_DELETE: { | ||||
|       for (const [index, setting] of configForm.value.formSettings!.entries()) { | ||||
|         if (!setting.deleteFields || setting.deleteFields.length === 0) { | ||||
|           message.warning(`请选择表单设置${index + 1}要删除的字段`); | ||||
|           return ''; | ||||
|         } | ||||
|       } | ||||
|       showText = '删除表单数据'; | ||||
| 
 | ||||
|       break; | ||||
|     } | ||||
|     case TriggerTypeEnum.FORM_UPDATE: { | ||||
|       for (const [index, setting] of configForm.value.formSettings!.entries()) { | ||||
|         if ( | ||||
|           !setting.updateFormFields || | ||||
|           Object.keys(setting.updateFormFields).length === 0 | ||||
|         ) { | ||||
|           message.warning(`请添加表单设置${index + 1}的修改字段`); | ||||
|           return ''; | ||||
|         } | ||||
|       } | ||||
|       showText = '修改表单数据'; | ||||
| 
 | ||||
|       break; | ||||
|     } | ||||
|     case TriggerTypeEnum.HTTP_CALLBACK: | ||||
|     case TriggerTypeEnum.HTTP_REQUEST: { | ||||
|       showText = `${configForm.value.httpRequestSetting?.url}`; | ||||
| 
 | ||||
|       break; | ||||
|     } | ||||
|     // No default | ||||
|   } | ||||
|   return showText; | ||||
| }; | ||||
| 
 | ||||
| /** 显示触发器节点配置, 由父组件传过来 */ | ||||
| const showTriggerNodeConfig = (node: SimpleFlowNode) => { | ||||
|   nodeName.value = node.name; | ||||
|   originalSetting = node.triggerSetting | ||||
|     ? cloneDeep(node.triggerSetting) | ||||
|     : undefined; | ||||
|   if (node.triggerSetting) { | ||||
|     configForm.value = { | ||||
|       type: node.triggerSetting.type, | ||||
|       httpRequestSetting: node.triggerSetting.httpRequestSetting || { | ||||
|         url: '', | ||||
|         header: [], | ||||
|         body: [], | ||||
|         response: [], | ||||
|       }, | ||||
|       formSettings: node.triggerSetting.formSettings || [ | ||||
|         { | ||||
|           conditionGroups: cloneDeep(DEFAULT_CONDITION_GROUP_VALUE), | ||||
|           updateFormFields: {}, | ||||
|           deleteFields: [], | ||||
|         }, | ||||
|       ], | ||||
|     }; | ||||
|   } | ||||
|   drawerApi.open(); | ||||
| }; | ||||
| 
 | ||||
| // 暴露方法给父组件 | ||||
| defineExpose({ showTriggerNodeConfig }); | ||||
| 
 | ||||
| onMounted(() => { | ||||
|   // 初始化可能需要的操作 | ||||
| }); | ||||
| </script> | ||||
| <template> | ||||
|   <Drawer class="w-[580px]"> | ||||
|     <template #title> | ||||
|       <div class="config-header"> | ||||
|         <Input | ||||
|           v-if="showInput" | ||||
|           type="text" | ||||
|           class="config-editable-input" | ||||
|           @blur="blurEvent()" | ||||
|           v-model:value="nodeName" | ||||
|           :placeholder="nodeName" | ||||
|         /> | ||||
|         <div v-else class="node-name"> | ||||
|           {{ nodeName }} | ||||
|           <IconifyIcon class="ml-1" icon="ep:edit-pen" @click="clickIcon()" /> | ||||
|         </div> | ||||
|       </div> | ||||
|     </template> | ||||
|     <div> | ||||
|       <Form | ||||
|         ref="formRef" | ||||
|         :model="configForm" | ||||
|         :label-col="{ span: 24 }" | ||||
|         :wrapper-col="{ span: 24 }" | ||||
|         :rules="formRules" | ||||
|       > | ||||
|         <FormItem label="触发器类型" name="type"> | ||||
|           <Select v-model:value="configForm.type" @change="changeTriggerType"> | ||||
|             <SelectOption | ||||
|               v-for="(item, index) in TRIGGER_TYPES" | ||||
|               :key="index" | ||||
|               :value="item.value" | ||||
|               :label="item.label" | ||||
|             > | ||||
|               {{ item.label }} | ||||
|             </SelectOption> | ||||
|           </Select> | ||||
|         </FormItem> | ||||
|         <!-- HTTP 请求触发器 --> | ||||
|         <div | ||||
|           v-if=" | ||||
|             [ | ||||
|               TriggerTypeEnum.HTTP_REQUEST, | ||||
|               TriggerTypeEnum.HTTP_CALLBACK, | ||||
|             ].includes(configForm.type) && configForm.httpRequestSetting | ||||
|           " | ||||
|         > | ||||
|           <HttpRequestSetting | ||||
|             v-model:setting="configForm.httpRequestSetting" | ||||
|             :response-enable="configForm.type === TriggerTypeEnum.HTTP_REQUEST" | ||||
|             form-item-prefix="httpRequestSetting" | ||||
|           /> | ||||
|         </div> | ||||
| 
 | ||||
|         <!-- 表单数据修改触发器 --> | ||||
|         <div v-if="configForm.type === TriggerTypeEnum.FORM_UPDATE"> | ||||
|           <div | ||||
|             v-for="(formSetting, index) in configForm.formSettings" | ||||
|             :key="index" | ||||
|           > | ||||
|             <Card class="mt-4"> | ||||
|               <template #title> | ||||
|                 <div class="flex w-full items-center justify-between"> | ||||
|                   <span>修改表单设置 {{ index + 1 }}</span> | ||||
|                   <Button | ||||
|                     v-if="configForm.formSettings!.length > 1" | ||||
|                     shape="circle" | ||||
|                     class="flex items-center justify-center" | ||||
|                     @click="deleteFormSetting(index)" | ||||
|                   > | ||||
|                     <template #icon> | ||||
|                       <IconifyIcon icon="ep:close" /> | ||||
|                     </template> | ||||
|                   </Button> | ||||
|                 </div> | ||||
|               </template> | ||||
| 
 | ||||
|               <!-- TODO 条件设置 --> | ||||
|               <!-- <ConditionDialog | ||||
|                 :ref="`condition-${index}`" | ||||
|                 @update-condition="(val) => handleConditionUpdate(index, val)" | ||||
|               /> --> | ||||
|               <Row> | ||||
|                 <Col :span="24"> | ||||
|                   <div class="cursor-pointer" v-if="formSetting.conditionType"> | ||||
|                     <Tag | ||||
|                       color="success" | ||||
|                       closable | ||||
|                       @close="deleteFormSettingCondition(formSetting)" | ||||
|                       @click="openFormSettingCondition(index, formSetting)" | ||||
|                     > | ||||
|                       {{ showConditionText(formSetting) }} | ||||
|                     </Tag> | ||||
|                   </div> | ||||
|                   <Button | ||||
|                     v-else | ||||
|                     type="link" | ||||
|                     class="flex items-center p-0" | ||||
|                     @click="addFormSettingCondition(index, formSetting)" | ||||
|                   > | ||||
|                     <template #icon> | ||||
|                       <IconifyIcon icon="ep:link" /> | ||||
|                     </template> | ||||
|                     添加条件 | ||||
|                   </Button> | ||||
|                 </Col> | ||||
|               </Row> | ||||
|               <Divider>修改表单字段设置</Divider> | ||||
|               <!-- 表单字段修改设置 --> | ||||
|               <Row | ||||
|                 :gutter="8" | ||||
|                 v-for="key in Object.keys(formSetting.updateFormFields || {})" | ||||
|                 :key="key" | ||||
|               > | ||||
|                 <Col :span="8"> | ||||
|                   <FormItem> | ||||
|                     <Select | ||||
|                       :value="key || undefined" | ||||
|                       @change=" | ||||
|                         (newKey) => updateFormFieldKey(formSetting, key, newKey) | ||||
|                       " | ||||
|                       placeholder="请选择表单字段" | ||||
|                       :disabled="key !== ''" | ||||
|                       allow-clear | ||||
|                     > | ||||
|                       <SelectOption | ||||
|                         v-for="(field, fIdx) in optionalUpdateFormFields" | ||||
|                         :key="fIdx" | ||||
|                         :label="field.title" | ||||
|                         :value="field.field" | ||||
|                         :disabled="field.disabled" | ||||
|                       > | ||||
|                         {{ field.title }} | ||||
|                       </SelectOption> | ||||
|                     </Select> | ||||
|                   </FormItem> | ||||
|                 </Col> | ||||
|                 <Col :span="4"> | ||||
|                   <FormItem>的值设置为</FormItem> | ||||
|                 </Col> | ||||
|                 <Col :span="10"> | ||||
|                   <FormItem | ||||
|                     :name="['formSettings', index, 'updateFormFields', key]" | ||||
|                     :rules="{ | ||||
|                       required: true, | ||||
|                       message: '值不能为空', | ||||
|                       trigger: 'blur', | ||||
|                     }" | ||||
|                   > | ||||
|                     <Input | ||||
|                       v-model:value="formSetting.updateFormFields![key]" | ||||
|                       placeholder="请输入值" | ||||
|                       allow-clear | ||||
|                       :disabled="!key" | ||||
|                     /> | ||||
|                   </FormItem> | ||||
|                 </Col> | ||||
|                 <Col :span="2"> | ||||
|                   <div class="flex h-[32px] items-center"> | ||||
|                     <Trash2 | ||||
|                       class="size-4 cursor-pointer text-red-500" | ||||
|                       @click="deleteFormFieldSetting(formSetting, key)" | ||||
|                     /> | ||||
|                   </div> | ||||
|                 </Col> | ||||
|               </Row> | ||||
| 
 | ||||
|               <!-- 添加表单字段按钮 --> | ||||
|               <Row> | ||||
|                 <Col :span="24"> | ||||
|                   <Button | ||||
|                     type="link" | ||||
|                     class="flex items-center p-0" | ||||
|                     @click="addFormFieldSetting(formSetting)" | ||||
|                   > | ||||
|                     <template #icon> | ||||
|                       <IconifyIcon icon="ep:memo" /> | ||||
|                     </template> | ||||
|                     添加修改字段 | ||||
|                   </Button> | ||||
|                 </Col> | ||||
|               </Row> | ||||
|             </Card> | ||||
|           </div> | ||||
| 
 | ||||
|           <!-- 添加新的设置 --> | ||||
|           <Row class="mt-6"> | ||||
|             <Col :span="24"> | ||||
|               <Button | ||||
|                 class="flex items-center p-0" | ||||
|                 type="link" | ||||
|                 @click="addFormSetting" | ||||
|               > | ||||
|                 <template #icon> | ||||
|                   <IconifyIcon icon="ep:setting" /> | ||||
|                 </template> | ||||
|                 添加设置 | ||||
|               </Button> | ||||
|             </Col> | ||||
|           </Row> | ||||
|         </div> | ||||
| 
 | ||||
|         <!-- 表单数据删除触发器 --> | ||||
|         <div v-if="configForm.type === TriggerTypeEnum.FORM_DELETE"> | ||||
|           <div | ||||
|             v-for="(formSetting, index) in configForm.formSettings" | ||||
|             :key="index" | ||||
|           > | ||||
|             <Card class="mt-4"> | ||||
|               <template #title> | ||||
|                 <div class="flex w-full items-center justify-between"> | ||||
|                   <span>删除表单设置 {{ index + 1 }}</span> | ||||
|                   <Button | ||||
|                     v-if="configForm.formSettings!.length > 1" | ||||
|                     shape="circle" | ||||
|                     class="flex items-center justify-center" | ||||
|                     @click="deleteFormSetting(index)" | ||||
|                   > | ||||
|                     <template #icon> | ||||
|                       <IconifyIcon icon="ep:close" /> | ||||
|                     </template> | ||||
|                   </Button> | ||||
|                 </div> | ||||
|               </template> | ||||
| 
 | ||||
|               <!-- TODO 条件设置 --> | ||||
|               <!-- <ConditionDialog | ||||
|                 :ref="`condition-${index}`" | ||||
|                 @update-condition="(val) => handleConditionUpdate(index, val)" | ||||
|               /> --> | ||||
|               <Row> | ||||
|                 <Col :span="24"> | ||||
|                   <div class="cursor-pointer" v-if="formSetting.conditionType"> | ||||
|                     <Tag | ||||
|                       color="warning" | ||||
|                       closable | ||||
|                       @close="deleteFormSettingCondition(formSetting)" | ||||
|                       @click="openFormSettingCondition(index, formSetting)" | ||||
|                     > | ||||
|                       {{ showConditionText(formSetting) }} | ||||
|                     </Tag> | ||||
|                   </div> | ||||
|                   <Button | ||||
|                     v-else | ||||
|                     type="link" | ||||
|                     class="flex items-center p-0" | ||||
|                     @click="addFormSettingCondition(index, formSetting)" | ||||
|                   > | ||||
|                     <template #icon> | ||||
|                       <IconifyIcon icon="ep:link" /> | ||||
|                     </template> | ||||
|                     添加条件 | ||||
|                   </Button> | ||||
|                 </Col> | ||||
|               </Row> | ||||
| 
 | ||||
|               <Divider>删除表单字段设置</Divider> | ||||
|               <!-- 表单字段删除设置 --> | ||||
|               <div class="flex flex-wrap gap-2"> | ||||
|                 <Select | ||||
|                   v-model:value="formSetting.deleteFields" | ||||
|                   mode="multiple" | ||||
|                   placeholder="请选择要删除的字段" | ||||
|                   class="w-full" | ||||
|                 > | ||||
|                   <SelectOption | ||||
|                     v-for="field in formFields" | ||||
|                     :key="field.field" | ||||
|                     :label="field.title" | ||||
|                     :value="field.field" | ||||
|                   > | ||||
|                     {{ field.title }} | ||||
|                   </SelectOption> | ||||
|                 </Select> | ||||
|               </div> | ||||
|             </Card> | ||||
|           </div> | ||||
| 
 | ||||
|           <!-- 添加新的设置 --> | ||||
|           <Row class="mt-6"> | ||||
|             <Col :span="24"> | ||||
|               <Button | ||||
|                 class="flex items-center p-0" | ||||
|                 type="link" | ||||
|                 @click="addFormSetting" | ||||
|               > | ||||
|                 <template #icon> | ||||
|                   <IconifyIcon icon="ep:setting" /> | ||||
|                 </template> | ||||
|                 添加设置 | ||||
|               </Button> | ||||
|             </Col> | ||||
|           </Row> | ||||
|         </div> | ||||
|       </Form> | ||||
|     </div> | ||||
|     <template #footer> | ||||
|       <div class="flex justify-end"> | ||||
|         <Button type="primary" @click="saveConfig">确 定</Button> | ||||
|         <Button class="ml-2" @click="drawerApi.close()">取 消</Button> | ||||
|       </div> | ||||
|     </template> | ||||
|   </Drawer> | ||||
| </template> | ||||
| <style lang="scss" scoped> | ||||
| .config-editable-input { | ||||
|   &:focus { | ||||
|     outline: 0; | ||||
|     border-color: #40a9ff; | ||||
|     box-shadow: 0 0 0 2px rgb(24 144 255 / 20%); | ||||
|   } | ||||
| } | ||||
| </style> | ||||
|  | @ -0,0 +1,118 @@ | |||
| <script setup lang="ts"> | ||||
| import type { SimpleFlowNode } from '../../consts'; | ||||
| 
 | ||||
| import { inject, ref } from 'vue'; | ||||
| 
 | ||||
| import { IconifyIcon } from '@vben/icons'; | ||||
| 
 | ||||
| import { Input } from 'ant-design-vue'; | ||||
| 
 | ||||
| import { NODE_DEFAULT_TEXT, NodeType } from '../../consts'; | ||||
| import { useNodeName2, useTaskStatusClass, useWatchNode } from '../../helpers'; | ||||
| import TriggerNodeConfig from '../nodes-config/trigger-node-config.vue'; | ||||
| import NodeHandler from './node-handler.vue'; | ||||
| 
 | ||||
| defineOptions({ | ||||
|   name: 'TriggerNode', | ||||
| }); | ||||
| 
 | ||||
| const props = defineProps({ | ||||
|   flowNode: { | ||||
|     type: Object as () => SimpleFlowNode, | ||||
|     required: true, | ||||
|   }, | ||||
| }); | ||||
| // 定义事件,更新父组件 | ||||
| const emits = defineEmits<{ | ||||
|   'update:flowNode': [node: SimpleFlowNode | undefined]; | ||||
| }>(); | ||||
| // 是否只读 | ||||
| const readonly = inject<Boolean>('readonly'); | ||||
| // 监控节点的变化 | ||||
| const currentNode = useWatchNode(props); | ||||
| // 节点名称编辑 | ||||
| const { showInput, blurEvent, clickTitle } = useNodeName2( | ||||
|   currentNode, | ||||
|   NodeType.TRIGGER_NODE, | ||||
| ); | ||||
| 
 | ||||
| const nodeSetting = ref(); | ||||
| // 打开节点配置 | ||||
| const openNodeConfig = () => { | ||||
|   if (readonly) { | ||||
|     return; | ||||
|   } | ||||
|   nodeSetting.value.showTriggerNodeConfig(currentNode.value); | ||||
| }; | ||||
| 
 | ||||
| // 删除节点。更新当前节点为孩子节点 | ||||
| const deleteNode = () => { | ||||
|   emits('update:flowNode', currentNode.value.childNode); | ||||
| }; | ||||
| </script> | ||||
| <template> | ||||
|   <div class="node-wrapper"> | ||||
|     <div class="node-container"> | ||||
|       <div | ||||
|         class="node-box" | ||||
|         :class="[ | ||||
|           { 'node-config-error': !currentNode.showText }, | ||||
|           `${useTaskStatusClass(currentNode?.activityStatus)}`, | ||||
|         ]" | ||||
|       > | ||||
|         <div class="node-title-container"> | ||||
|           <div class="node-title-icon trigger-node"> | ||||
|             <span class="iconfont icon-trigger"></span> | ||||
|           </div> | ||||
|           <Input | ||||
|             v-if="!readonly && showInput" | ||||
|             type="text" | ||||
|             class="editable-title-input" | ||||
|             @blur="blurEvent()" | ||||
|             v-model="currentNode.name" | ||||
|             :placeholder="currentNode.name" | ||||
|           /> | ||||
|           <div v-else class="node-title" @click="clickTitle"> | ||||
|             {{ currentNode.name }} | ||||
|           </div> | ||||
|         </div> | ||||
|         <div class="node-content" @click="openNodeConfig"> | ||||
|           <div | ||||
|             class="node-text" | ||||
|             :title="currentNode.showText" | ||||
|             v-if="currentNode.showText" | ||||
|           > | ||||
|             {{ currentNode.showText }} | ||||
|           </div> | ||||
|           <div class="node-text" v-else> | ||||
|             {{ NODE_DEFAULT_TEXT.get(NodeType.TRIGGER_NODE) }} | ||||
|           </div> | ||||
|           <IconifyIcon v-if="!readonly" icon="ep:arrow-right-bold" /> | ||||
|         </div> | ||||
|         <div v-if="!readonly" class="node-toolbar"> | ||||
|           <div class="toolbar-icon"> | ||||
|             <IconifyIcon | ||||
|               color="#0089ff" | ||||
|               icon="ep:circle-close-filled" | ||||
|               :size="18" | ||||
|               @click="deleteNode" | ||||
|             /> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
| 
 | ||||
|       <!-- 传递子节点给添加节点组件。会在子节点前面添加节点 --> | ||||
|       <NodeHandler | ||||
|         v-if="currentNode" | ||||
|         v-model:child-node="currentNode.childNode" | ||||
|         :current-node="currentNode" | ||||
|       /> | ||||
|     </div> | ||||
|     <TriggerNodeConfig | ||||
|       v-if="!readonly && currentNode" | ||||
|       ref="nodeSetting" | ||||
|       :flow-node="currentNode" | ||||
|     /> | ||||
|   </div> | ||||
| </template> | ||||
| <style lang="scss" scoped></style> | ||||
|  | @ -6,6 +6,7 @@ import { useWatchNode } from '../helpers'; | |||
| import CopyTaskNode from './nodes/copy-task-node.vue'; | ||||
| import EndEventNode from './nodes/end-event-node.vue'; | ||||
| import StartUserNode from './nodes/start-user-node.vue'; | ||||
| import TriggerNode from './nodes/trigger-node.vue'; | ||||
| import UserTaskNode from './nodes/user-task-node.vue'; | ||||
| 
 | ||||
| defineOptions({ name: 'ProcessNodeTree' }); | ||||
|  | @ -117,11 +118,11 @@ const recursiveFindParentNode = ( | |||
|     @update:flow-node="handleModelValueUpdate" | ||||
|   /> --> | ||||
|   <!-- 触发器节点 --> | ||||
|   <!-- <TriggerNode | ||||
|   <TriggerNode | ||||
|     v-if="currentNode && currentNode.type === NodeType.TRIGGER_NODE" | ||||
|     :flow-node="currentNode" | ||||
|     @update:flow-node="handleModelValueUpdate" | ||||
|   /> --> | ||||
|   /> | ||||
|   <!-- 子流程节点 --> | ||||
|   <!-- <ChildProcessNode | ||||
|     v-if="currentNode && currentNode.type === NodeType.CHILD_PROCESS_NODE" | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 jason
						jason