Browse Source

仿钉钉流程设计器- 代码优化

jason 1 year ago
parent
commit
3a5c93fa84

+ 2 - 8
src/components/SimpleProcessDesignerV2/src/ProcessNodeTree.vue

@@ -50,6 +50,7 @@ import CopyTaskNode from './nodes/CopyTaskNode.vue'
 import ExclusiveNode from './nodes/ExclusiveNode.vue'
 import ParallelNode from './nodes/ParallelNode.vue'
 import { SimpleFlowNode, NodeType } from './consts'
+import { useWatchNode } from './node'
 defineOptions({
   name: 'ProcessNodeTree'
 })
@@ -72,15 +73,8 @@ const emits = defineEmits<{
   ]
 }>()
 
-const currentNode = ref<SimpleFlowNode>(props.flowNode)
+const currentNode = useWatchNode(props)
 
-// 重要:监控节点变化. 重新绘制节点
-watch(
-  () => props.flowNode,
-  (newValue) => {
-    currentNode.value = newValue
-  }
-)
 // 用于删除节点
 const handleModelValueUpdate = (updateValue) => {
   emits('update:flowNode', updateValue)

+ 1 - 0
src/components/SimpleProcessDesignerV2/src/SimpleProcessDesigner.vue

@@ -138,6 +138,7 @@ const zoomIn = () => {
 
 onMounted(async () => {
   const result = await getBpmSimpleModel(props.modelId)
+  console.log('the result is :', result)
   if (result) {
     processNodeTree.value = result
   } else {

+ 133 - 113
src/components/SimpleProcessDesignerV2/src/consts.ts

@@ -1,6 +1,8 @@
 // @ts-ignore
 import { DictDataVO } from '@/api/system/dict/types'
-
+/**
+ * 节点类型
+ */
 export enum NodeType {
   /**
    * 发起人节点
@@ -46,68 +48,37 @@ export enum NodeType {
    */
   INCLUSIVE_NODE_JOIN = 8
 }
-// 时间单位枚举
-export enum TimeUnitType {
-  /**
-   * 分钟
-   */
-  MINUTE = 1,
-  /**
-   * 小时
-   */
-  HOUR = 2,
-  /**
-   * 天
-   */
-  DAY = 3
-}
-
-export enum RejectHandlerType {
-  /**
-   * 结束流程
-   */
-  FINISH_PROCESS = 1,
-  /**
-   * 驳回到指定节点
-   */
-  RETURN_USER_TASK = 2
-}
-
-// 条件配置类型 ( 用于条件节点配置 )
-export enum ConditionConfigType {
-  /**
-   * 条件表达式
-   */
-  EXPRESSION = 1,
-
-  /**
-   * 条件规则
-   */
-  RULE = 2
-}
-// 多人审批方式类型 ( 用于审批节点 )
-export enum ApproveMethodType {
-  /**
-   * 随机挑选一人审批
-   */
-  RRANDOM_SELECT_ONE_APPROVE = 1,
-
-  /**
-   * 多人会签(按通过比例)
-   */
-  APPROVE_BY_RATIO = 2,
-
-  /**
-   * 多人或签(通过只需一人,拒绝只需一人)
-   */
-  ANY_APPROVE = 3,
-  /**
-   * 多人依次审批
-   */
-  SEQUENTIAL_APPROVE = 4
+/**
+ *  节点结构定义
+ */
+export interface SimpleFlowNode {
+  id: string
+  type: NodeType
+  name: string
+  showText?: string
+  attributes?: any
+  // 孩子节点
+  childNode?: SimpleFlowNode
+  // 条件节点
+  conditionNodes?: SimpleFlowNode[]
+  // 候选人策略
+  candidateStrategy?: number
+  // 候选人参数
+  candidateParam?: string
+  // 多人审批方式
+  approveMethod?: ApproveMethodType
+  //通过比例
+  approveRatio?: number
+  // 审批按钮设置
+  buttonsSetting?: any[]
+  // 表单权限
+  fieldsPermission?: Array<Record<string, string>>
+  // 审批任务超时处理
+  timeoutHandler?: TimeoutHandler
+  // 审批任务拒绝处理
+  rejectHandler?: RejectHandler
 }
-
-// 候选人策略 ( 用于审批节点。抄送节点 )
+// 候选人策略枚举 ( 用于审批节点。抄送节点 )
 export enum CandidateStrategy {
   /**
    * 指定角色
@@ -147,12 +118,41 @@ export enum CandidateStrategy {
   EXPRESSION = 60
 }
 
+// 多人审批方式类型枚举 ( 用于审批节点 )
+export enum ApproveMethodType {
+  /**
+   * 随机挑选一人审批
+   */
+  RRANDOM_SELECT_ONE_APPROVE = 1,
+
+  /**
+   * 多人会签(按通过比例)
+   */
+  APPROVE_BY_RATIO = 2,
+
+  /**
+   * 多人或签(通过只需一人,拒绝只需一人)
+   */
+  ANY_APPROVE = 3,
+  /**
+   * 多人依次审批
+   */
+  SEQUENTIAL_APPROVE = 4
+}
+
+/**
+ * 审批拒绝结构定义
+ */
 export type RejectHandler = {
+  // 审批拒绝类型
   type: RejectHandlerType
-
+  // 回退节点 Id
   returnNodeId?: string
 }
 
+/**
+ * 审批超时结构定义
+ */
 export type TimeoutHandler = {
   //是否开启超时处理
   enable: boolean
@@ -163,60 +163,57 @@ export type TimeoutHandler = {
   // 执行动作是自动提醒, 最大提醒次数
   maxRemindCount?: number
 }
-
-export type SimpleFlowNode = {
-  id: string
-  type: NodeType
-  name: string
-  showText?: string
-  attributes?: any
-  // 孩子节点
-  childNode?: SimpleFlowNode
-  // 条件节点
-  conditionNodes?: SimpleFlowNode[]
-  // 候选人策略
-  candidateStrategy?: number
-  // 候选人参数
-  candidateParam?: string
-  // 多人审批方式
-  approveMethod?: ApproveMethodType
-  //通过比例
-  approveRatio?: number
-  // 审批按钮设置
-  buttonsSetting?: any[]
-  // 表单权限
-  fieldsPermission?: any[]
-  // 审批任务超时处理
-  timeoutHandler?: TimeoutHandler
-  // 审批任务拒绝处理
-  rejectHandler?: RejectHandler
+// 审批拒绝类型枚举
+export enum RejectHandlerType {
+  /**
+   * 结束流程
+   */
+  FINISH_PROCESS = 1,
+  /**
+   * 驳回到指定节点
+   */
+  RETURN_USER_TASK = 2
 }
 
-// 条件组
-export type ConditionGroup = {
-  // 条件组的逻辑关系是否为且
-  and: boolean
-  // 条件数组
-  conditions: Condition[]
+// 时间单位枚举
+export enum TimeUnitType {
+  /**
+   * 分钟
+   */
+  MINUTE = 1,
+  /**
+   * 小时
+   */
+  HOUR = 2,
+  /**
+   * 天
+   */
+  DAY = 3
 }
 
-// 条件
-export type Condition = {
-  // 条件规则的逻辑关系是否为且
-  and: boolean
-  rules: ConditionRule[]
+// 条件配置类型 ( 用于条件节点配置 )
+export enum ConditionConfigType {
+  /**
+   * 条件表达式
+   */
+  EXPRESSION = 1,
+
+  /**
+   * 条件规则
+   */
+  RULE = 2
 }
 
-// 条件规则
-export type ConditionRule = {
-  type: number
-  opName: string
-  opCode: string
-  leftSide: string
-  rightSide: string
+/**
+ * 操作按钮权限结构定义
+ */
+export type ButtonSetting = {
+  id: OpsButtonType
+  displayName: string
+  enable: boolean
 }
 
-// 审批操作按钮类型
+// 操作按钮类型枚举 (用于审批节点)
 export enum OpsButtonType {
   /**
    * 通过
@@ -243,11 +240,34 @@ export enum OpsButtonType {
    */
   RETURN = 6
 }
+/**
+ * 条件规则结构定义
+ */
+export type ConditionRule = {
+  type: number
+  opName: string
+  opCode: string
+  leftSide: string
+  rightSide: string
+}
 
-export type ButtonSetting = {
-  id: OpsButtonType
-  displayName: string
-  enable: boolean
+/**
+ * 条件组结构定义
+ */
+export type ConditionGroup = {
+  // 条件组的逻辑关系是否为且
+  and: boolean
+  // 条件数组
+  conditions: Condition[]
+}
+
+/**
+ * 条件结构定义
+ */
+export type Condition = {
+  // 条件规则的逻辑关系是否为且
+  and: boolean
+  rules: ConditionRule[]
 }
 
 export const NODE_DEFAULT_TEXT = new Map<number, string>()

+ 260 - 0
src/components/SimpleProcessDesignerV2/src/node.ts

@@ -0,0 +1,260 @@
+import { cloneDeep } from 'lodash-es'
+import * as RoleApi from '@/api/system/role'
+import * as DeptApi from '@/api/system/dept'
+import * as PostApi from '@/api/system/post'
+import * as UserApi from '@/api/system/user'
+import * as UserGroupApi from '@/api/bpm/userGroup'
+import {
+  SimpleFlowNode,
+  CandidateStrategy,
+  NodeType,
+  ApproveMethodType,
+  RejectHandlerType,
+  NODE_DEFAULT_NAME
+} from './consts'
+export function useWatchNode(props: { flowNode: SimpleFlowNode }): Ref<SimpleFlowNode> {
+  const node = ref<SimpleFlowNode>(props.flowNode)
+  watch(
+    () => props.flowNode,
+    (newValue) => {
+      node.value = newValue
+    }
+  )
+  return node
+}
+
+/**
+ * @description 表单数据权限配置,用于审批节点、抄送节点
+ */
+export function useFormFieldsPermission() {
+  // 字段权限配置. 需要有 field, title,  permissioin 属性
+  const fieldsPermissionConfig = ref<Array<Record<string, string>>>([])
+
+  const formType = inject<Ref<number>>('formType') // 表单类型
+
+  const formFields = inject<Ref<string[]>>('formFields') // 流程表单字段
+
+  const getNodeConfigFormFields = (nodeFormFields?: Array<Record<string, string>>) => {
+    nodeFormFields = toRaw(nodeFormFields)
+    fieldsPermissionConfig.value =
+      cloneDeep(nodeFormFields) || getDefaultFieldsPermission(unref(formFields))
+  }
+  // 获取默认的表单权限。 所有字段只读
+  const getDefaultFieldsPermission = (formFields?: string[]) => {
+    const defaultFieldsPermission: Array<Record<string, string>> = []
+    if (formFields) {
+      formFields.forEach((fieldStr: string) => {
+        const { field, title } = JSON.parse(fieldStr)
+        defaultFieldsPermission.push({
+          field,
+          title,
+          permission: '1' // 只读
+        })
+      })
+    }
+    return defaultFieldsPermission
+  }
+
+  return {
+    formType,
+    fieldsPermissionConfig,
+    getNodeConfigFormFields
+  }
+}
+
+export type UserTaskFormType = {
+  candidateParamArray: any[]
+  candidateStrategy: CandidateStrategy
+  approveMethod: ApproveMethodType
+  approveRatio?: number
+  rejectHandlerType?: RejectHandlerType
+  returnNodeId?: string
+  timeoutHandlerEnable?: boolean
+  timeoutHandlerAction?: number
+  timeDuration?: number
+  maxRemindCount?: number
+  buttonsSetting: any[]
+}
+
+export type CopyTaskFormType = {
+  candidateParamArray: any[]
+  candidateStrategy: CandidateStrategy
+}
+
+/**
+ * @description 节点表单数据。 用于审批节点、抄送节点
+ */
+export function useNodeForm(nodeType: NodeType) {
+  const roleOptions = inject<Ref<RoleApi.RoleVO[]>>('roleList') // 角色列表
+  const postOptions = inject<Ref<PostApi.PostVO[]>>('postList') // 岗位列表
+  const userOptions = inject<Ref<UserApi.UserVO[]>>('userList') // 用户列表
+  const deptOptions = inject<Ref<DeptApi.DeptVO[]>>('deptList') // 部门列表
+  const userGroupOptions = inject<Ref<UserGroupApi.UserGroupVO[]>>('userGroupList') // 用户组列表
+  const deptTreeOptions = inject('deptTree') // 部门树
+  const configForm = ref<UserTaskFormType | CopyTaskFormType>()
+  if (nodeType === NodeType.USER_TASK_NODE) {
+    configForm.value = {
+      candidateParamArray: [],
+      candidateStrategy: CandidateStrategy.USER,
+      approveMethod: ApproveMethodType.RRANDOM_SELECT_ONE_APPROVE,
+      approveRatio: 100,
+      rejectHandlerType: RejectHandlerType.FINISH_PROCESS,
+      returnNodeId: '',
+      timeoutHandlerEnable: false,
+      timeoutHandlerAction: 1,
+      timeDuration: 6, // 默认 6小时
+      maxRemindCount: 1, // 默认 提醒 1次
+      buttonsSetting: []
+    }
+  } else {
+    configForm.value = {
+      candidateParamArray: [],
+      candidateStrategy: CandidateStrategy.USER
+    }
+  }
+
+  const getShowText = (): string => {
+    let showText = ''
+    // 指定成员
+    if (configForm.value?.candidateStrategy === CandidateStrategy.USER) {
+      if (configForm.value.candidateParamArray?.length > 0) {
+        const candidateNames: string[] = []
+        userOptions?.value.forEach((item) => {
+          if (configForm.value?.candidateParamArray.includes(item.id)) {
+            candidateNames.push(item.nickname)
+          }
+        })
+        showText = `指定成员:${candidateNames.join(',')}`
+      }
+    }
+    // 指定角色
+    if (configForm.value?.candidateStrategy === CandidateStrategy.ROLE) {
+      if (configForm.value.candidateParamArray?.length > 0) {
+        const candidateNames: string[] = []
+        roleOptions?.value.forEach((item) => {
+          if (configForm.value?.candidateParamArray.includes(item.id)) {
+            candidateNames.push(item.name)
+          }
+        })
+        showText = `指定角色:${candidateNames.join(',')}`
+      }
+    }
+    // 指定部门
+    if (
+      configForm.value?.candidateStrategy === CandidateStrategy.DEPT_MEMBER ||
+      configForm.value?.candidateStrategy === CandidateStrategy.DEPT_LEADER
+    ) {
+      if (configForm.value?.candidateParamArray?.length > 0) {
+        const candidateNames: string[] = []
+        deptOptions?.value.forEach((item) => {
+          if (configForm.value?.candidateParamArray.includes(item.id)) {
+            candidateNames.push(item.name)
+          }
+        })
+        if (configForm.value.candidateStrategy === CandidateStrategy.DEPT_MEMBER) {
+          showText = `部门成员:${candidateNames.join(',')}`
+        } else {
+          showText = `部门的负责人:${candidateNames.join(',')}`
+        }
+      }
+    }
+
+    // 指定岗位
+    if (configForm.value?.candidateStrategy === CandidateStrategy.POST) {
+      if (configForm.value.candidateParamArray?.length > 0) {
+        const candidateNames: string[] = []
+        postOptions?.value.forEach((item) => {
+          if (configForm.value?.candidateParamArray.includes(item.id)) {
+            candidateNames.push(item.name)
+          }
+        })
+        showText = `指定岗位: ${candidateNames.join(',')}`
+      }
+    }
+    // 指定用户组
+    if (configForm.value?.candidateStrategy === CandidateStrategy.USER_GROUP) {
+      if (configForm.value?.candidateParamArray?.length > 0) {
+        const candidateNames: string[] = []
+        userGroupOptions?.value.forEach((item) => {
+          if (configForm.value?.candidateParamArray.includes(item.id)) {
+            candidateNames.push(item.name)
+          }
+        })
+        showText = `指定用户组: ${candidateNames.join(',')}`
+      }
+    }
+
+    // 发起人自选
+    if (configForm.value?.candidateStrategy === CandidateStrategy.START_USER_SELECT) {
+      showText = `发起人自选`
+    }
+    // 发起人自己
+    if (configForm.value?.candidateStrategy === CandidateStrategy.START_USER) {
+      showText = `发起人自己`
+    }
+
+    // 流程表达式
+    if (configForm.value?.candidateStrategy === CandidateStrategy.EXPRESSION) {
+      if (configForm.value.candidateParamArray?.length > 0) {
+        showText = `流程表达式:${configForm.value.candidateParamArray[0]}`
+      }
+    }
+    return showText
+  }
+
+  return {
+    configForm,
+    roleOptions,
+    postOptions,
+    userOptions,
+    userGroupOptions,
+    deptTreeOptions,
+    getShowText
+  }
+}
+
+/**
+ * @description 抽屉配置
+ */
+export function useDrawer() {
+  // 抽屉配置是否可见
+  const settingVisible = ref(false)
+  // 关闭配置抽屉
+  const closeDrawer = () => {
+    settingVisible.value = false
+  }
+  // 打开配置抽屉
+  const openDrawer = () => {
+    settingVisible.value = true
+  }
+  return {
+    settingVisible,
+    closeDrawer,
+    openDrawer
+  }
+}
+
+/**
+ * @description 节点名称配置
+ */
+export function useNodeName(nodeType: NodeType) {
+  // 节点名称
+  const nodeName = ref<string>()
+  // 节点名称输入框
+  const showInput = ref(false)
+  // 点击节点名称编辑图标
+  const clickIcon = () => {
+    showInput.value = true
+  }
+  // 节点名称输入框失去焦点
+  const blurEvent = () => {
+    showInput.value = false
+    nodeName.value = nodeName.value || (NODE_DEFAULT_NAME.get(nodeType) as string)
+  }
+  return {
+    nodeName,
+    showInput,
+    clickIcon,
+    blurEvent
+  }
+}

+ 52 - 159
src/components/SimpleProcessDesignerV2/src/nodes-config/CopyTaskNodeConfig.vue

@@ -14,14 +14,12 @@
           class="config-editable-input"
           @blur="blurEvent()"
           v-mountedFocus
-          v-model="configForm.name"
-          :placeholder="configForm.name"
+          v-model="nodeName"
+          :placeholder="nodeName"
         />
-        <div v-else class="node-name"
-          >{{ configForm.name }}
-          <Icon class="ml-1" icon="ep:edit-pen" :size="16" @click="clickIcon()"
-        /></div>
-
+        <div v-else class="node-name">
+          {{ nodeName }} <Icon class="ml-1" icon="ep:edit-pen" :size="16" @click="clickIcon()" />
+        </div>
         <div class="divide-line"></div>
       </div>
     </template>
@@ -173,7 +171,7 @@
           </div>
           <div
             class="field-setting-item"
-            v-for="(item, index) in configForm.fieldsPermission"
+            v-for="(item, index) in fieldsPermissionConfig"
             :key="index"
           >
             <div class="field-setting-item-label"> {{ item.title }} </div>
@@ -202,16 +200,17 @@
   </el-drawer>
 </template>
 <script setup lang="ts">
-import { SimpleFlowNode, CandidateStrategy, NodeType, NODE_DEFAULT_NAME } from '../consts'
-import { getDefaultFieldsPermission } from '../utils'
+import { SimpleFlowNode, CandidateStrategy, NodeType } from '../consts'
 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
-import * as RoleApi from '@/api/system/role'
-import * as DeptApi from '@/api/system/dept'
-import * as PostApi from '@/api/system/post'
-import * as UserApi from '@/api/system/user'
-import * as UserGroupApi from '@/api/bpm/userGroup'
+import {
+  useWatchNode,
+  useDrawer,
+  useNodeName,
+  useFormFieldsPermission,
+  useNodeForm,
+  CopyTaskFormType
+} from '../node'
 import { defaultProps } from '@/utils/tree'
-import { cloneDeep } from 'lodash-es'
 defineOptions({
   name: 'CopyTaskNodeConfig'
 })
@@ -221,53 +220,45 @@ const props = defineProps({
     required: true
   }
 })
-// 是否可见
-const settingVisible = ref(false)
+// 抽屉配置
+const { settingVisible, closeDrawer, openDrawer } = useDrawer()
 // 当前节点
-const currentNode = ref<SimpleFlowNode>(props.flowNode)
-// 监控节点变化
-watch(
-  () => props.flowNode,
-  (newValue) => {
-    currentNode.value = newValue
-  }
-)
-const roleOptions = inject<Ref<RoleApi.RoleVO[]>>('roleList') // 角色列表
-const postOptions = inject<Ref<PostApi.PostVO[]>>('postList') // 岗位列表
-const userOptions = inject<Ref<UserApi.UserVO[]>>('userList') // 用户列表
-const deptOptions = inject<Ref<DeptApi.DeptVO[]>>('deptList') // 部门列表
-const userGroupOptions = inject<Ref<UserGroupApi.UserGroupVO[]>>('userGroupList') // 用户组列表
-const deptTreeOptions = inject('deptTree') // 部门树
-const formType = inject('formType') // 表单类型
-const formFields = inject<Ref<string[]>>('formFields')
-
-// 抄送人策略, 去掉发起人自选 和 发起人自己
-const copyUserStrategies = computed(() => {
-  return getIntDictOptions(DICT_TYPE.BPM_TASK_CANDIDATE_STRATEGY).filter(
-    (item) =>
-      item.value !== CandidateStrategy.START_USER_SELECT &&
-      item.value !== CandidateStrategy.START_USER
-  )
-})
+const currentNode = useWatchNode(props)
+// 节点名称
+const { nodeName, showInput, clickIcon, blurEvent } = useNodeName(NodeType.COPY_TASK_NODE)
 // 激活的 Tab 标签页
 const activeTabName = ref('user')
+// 表单字段权限配置
+const { formType, fieldsPermissionConfig, getNodeConfigFormFields } = useFormFieldsPermission()
+// 抄送人表单配置
 const formRef = ref() // 表单 Ref
-
-const configForm = ref<any>({
-  name: NODE_DEFAULT_NAME.get(NodeType.COPY_TASK_NODE),
-  candidateParamArray: [],
-  candidateStrategy: CandidateStrategy.USER,
-  fieldsPermission: []
-})
 // 表单校验规则
 const formRules = reactive({
   candidateStrategy: [{ required: true, message: '抄送人设置不能为空', trigger: 'change' }],
   candidateParamArray: [{ required: true, message: '选项不能为空', trigger: 'blur' }]
 })
 
-// 关闭
-const closeDrawer = () => {
-  settingVisible.value = false
+const {
+  configForm: tempConfigForm,
+  roleOptions,
+  postOptions,
+  userOptions,
+  userGroupOptions,
+  deptTreeOptions,
+  getShowText
+} = useNodeForm(NodeType.COPY_TASK_NODE)
+const configForm = tempConfigForm as Ref<CopyTaskFormType>
+// 抄送人策略, 去掉发起人自选 和 发起人自己
+const copyUserStrategies = computed(() => {
+  return getIntDictOptions(DICT_TYPE.BPM_TASK_CANDIDATE_STRATEGY).filter(
+    (item) =>
+      item.value !== CandidateStrategy.START_USER_SELECT &&
+      item.value !== CandidateStrategy.START_USER
+  )
+})
+// 改变抄送人设置策略
+const changeCandidateStrategy = () => {
+  configForm.value.candidateParamArray = []
 }
 // 保存配置
 const saveConfig = async () => {
@@ -277,23 +268,19 @@ const saveConfig = async () => {
   if (!valid) return false
   const showText = getShowText()
   if (!showText) return false
-  currentNode.value.name = configForm.value.name
+  currentNode.value.name = nodeName.value!
   currentNode.value.candidateParam = configForm.value.candidateParamArray?.join(',')
   currentNode.value.candidateStrategy = configForm.value.candidateStrategy
   currentNode.value.showText = showText
-  currentNode.value.fieldsPermission = configForm.value.fieldsPermission
+  currentNode.value.fieldsPermission = fieldsPermissionConfig.value
   settingVisible.value = false
   return true
 }
-
-const open = () => {
-  settingVisible.value = true
-}
-// 设置抄送节点
-const setCurrentNode = (node: SimpleFlowNode) => {
-  configForm.value.name = node.name
+// 显示抄送节点配置, 由父组件传过来
+const showCopyTaskNodeConfig = (node: SimpleFlowNode) => {
+  nodeName.value = node.name
   // 抄送人设置
-  configForm.value.candidateStrategy = node.candidateStrategy
+  configForm.value.candidateStrategy = node.candidateStrategy!
   const strCandidateParam = node?.candidateParam
   if (node.candidateStrategy === CandidateStrategy.EXPRESSION) {
     configForm.value.candidateParamArray[0] = strCandidateParam
@@ -303,104 +290,10 @@ const setCurrentNode = (node: SimpleFlowNode) => {
     }
   }
   // 表单字段权限
-  configForm.value.fieldsPermission =
-    cloneDeep(node.fieldsPermission) || getDefaultFieldsPermission(formFields?.value)
+  getNodeConfigFormFields(node.fieldsPermission)
 }
 
-defineExpose({ open, setCurrentNode }) // 暴露方法给父组件
-const changeCandidateStrategy = () => {
-  configForm.value.candidateParamArray = []
-}
-// TODO 貌似可以和 UserTaskNodeConfig 重复了, 如何共用??
-const getShowText = (): string => {
-  let showText = ''
-  // 指定成员
-  if (configForm.value.candidateStrategy === CandidateStrategy.USER) {
-    if (configForm.value.candidateParamArray?.length > 0) {
-      const candidateNames: string[] = []
-      userOptions?.value.forEach((item) => {
-        if (configForm.value.candidateParamArray.includes(item.id)) {
-          candidateNames.push(item.nickname)
-        }
-      })
-      showText = `指定成员:${candidateNames.join(',')}`
-    }
-  }
-  // 指定角色
-  if (configForm.value.candidateStrategy === CandidateStrategy.ROLE) {
-    if (configForm.value.candidateParamArray?.length > 0) {
-      const candidateNames: string[] = []
-      roleOptions?.value.forEach((item) => {
-        if (configForm.value.candidateParamArray.includes(item.id)) {
-          candidateNames.push(item.name)
-        }
-      })
-      showText = `指定角色:${candidateNames.join(',')}`
-    }
-  }
-  // 指定部门
-  if (
-    configForm.value.candidateStrategy === CandidateStrategy.DEPT_MEMBER ||
-    configForm.value.candidateStrategy === CandidateStrategy.DEPT_LEADER
-  ) {
-    if (configForm.value.candidateParamArray?.length > 0) {
-      const candidateNames: string[] = []
-      deptOptions?.value.forEach((item) => {
-        if (configForm.value.candidateParamArray.includes(item.id)) {
-          candidateNames.push(item.name)
-        }
-      })
-      if (currentNode.value.candidateStrategy === CandidateStrategy.DEPT_MEMBER) {
-        showText = `部门成员:${candidateNames.join(',')}`
-      } else {
-        showText = `部门的负责人:${candidateNames.join(',')}`
-      }
-    }
-  }
-  // 指定岗位
-  if (configForm.value.candidateStrategy === CandidateStrategy.POST) {
-    if (configForm.value.candidateParamArray?.length > 0) {
-      const candidateNames: string[] = []
-      postOptions?.value.forEach((item) => {
-        if (configForm.value.candidateParamArray.includes(item.id)) {
-          candidateNames.push(item.name)
-        }
-      })
-      showText = `指定岗位: ${candidateNames.join(',')}`
-    }
-  }
-  // 指定用户组
-  if (configForm.value.candidateStrategy === CandidateStrategy.USER_GROUP) {
-    if (configForm.value.candidateParamArray?.length > 0) {
-      const candidateNames: string[] = []
-      userGroupOptions?.value.forEach((item) => {
-        if (configForm.value.candidateParamArray.includes(item.id)) {
-          candidateNames.push(item.name)
-        }
-      })
-      showText = `指定用户组: ${candidateNames.join(',')}`
-    }
-  }
-  // 流程表达式
-  if (configForm.value.candidateStrategy === CandidateStrategy.EXPRESSION) {
-    if (configForm.value.candidateParamArray?.length > 0) {
-      showText = `流程表达式:${configForm.value.candidateParamArray[0]}`
-    }
-  }
-  return showText
-}
-// 显示名称输入框
-const showInput = ref(false)
-
-const clickIcon = () => {
-  showInput.value = true
-}
-// 输入框失去焦点
-const blurEvent = () => {
-  showInput.value = false
-  configForm.value.name =
-    configForm.value.name || (NODE_DEFAULT_NAME.get(NodeType.COPY_TASK_NODE) as string)
-}
+defineExpose({ openDrawer, showCopyTaskNodeConfig }) // 暴露方法给父组件
 </script>
 
 <style lang="scss" scoped></style>

+ 208 - 298
src/components/SimpleProcessDesignerV2/src/nodes-config/UserTaskNodeConfig.vue

@@ -15,14 +15,12 @@
           class="config-editable-input"
           @blur="blurEvent()"
           v-mountedFocus
-          v-model="configForm.name"
-          :placeholder="configForm.name"
+          v-model="nodeName"
+          :placeholder="nodeName"
         />
-        <div v-else class="node-name"
-          >{{ configForm.name }}
-          <Icon class="ml-1" icon="ep:edit-pen" :size="16" @click="clickIcon()"
-        /></div>
-
+        <div v-else class="node-name">
+          {{ nodeName }} <Icon class="ml-1" icon="ep:edit-pen" :size="16" @click="clickIcon()" />
+        </div>
         <div class="divide-line"></div>
       </div>
     </template>
@@ -280,7 +278,7 @@
           </el-form>
         </div>
       </el-tab-pane>
-      <el-tab-pane label="操作按钮设置" name="buttons" v-if="formType === 10">
+      <el-tab-pane label="操作按钮设置" name="buttons">
         <div class="button-setting-pane">
           <div class="button-setting-desc">操作按钮</div>
           <div class="button-setting-title">
@@ -288,11 +286,7 @@
             <div class="pl-4 button-title-label">显示名称</div>
             <div class="button-title-label">启用</div>
           </div>
-          <div
-            class="button-setting-item"
-            v-for="(item, index) in configForm.buttonsSetting"
-            :key="index"
-          >
+          <div class="button-setting-item" v-for="(item, index) in buttonsSetting" :key="index">
             <div class="button-setting-item-label"> {{ OPERATION_BUTTON_NAME.get(item.id) }} </div>
             <div class="button-setting-item-label">
               <input
@@ -327,7 +321,7 @@
           </div>
           <div
             class="field-setting-item"
-            v-for="(item, index) in configForm.fieldsPermission"
+            v-for="(item, index) in fieldsPermissionConfig"
             :key="index"
           >
             <div class="field-setting-item-label"> {{ item.title }} </div>
@@ -368,19 +362,22 @@ import {
   TIMEOUT_HANDLER_ACTION_TYPES,
   TIME_UNIT_TYPES,
   REJECT_HANDLER_TYPES,
-  NODE_DEFAULT_NAME,
   DEFAULT_BUTTON_SETTING,
-  OPERATION_BUTTON_NAME
+  OPERATION_BUTTON_NAME,
+  ButtonSetting
 } from '../consts'
 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
-import { getDefaultFieldsPermission } from '../utils'
+import {
+  useWatchNode,
+  useNodeName,
+  useFormFieldsPermission,
+  useNodeForm,
+  UserTaskFormType,
+  useDrawer
+} from '../node'
 import { defaultProps } from '@/utils/tree'
-import * as RoleApi from '@/api/system/role'
-import * as DeptApi from '@/api/system/dept'
-import * as PostApi from '@/api/system/post'
-import * as UserApi from '@/api/system/user'
-import * as UserGroupApi from '@/api/bpm/userGroup'
 import { cloneDeep } from 'lodash-es'
+import { convertTimeUnit } from '../utils'
 defineOptions({
   name: 'UserTaskNodeConfig'
 })
@@ -393,44 +390,22 @@ const props = defineProps({
 const emits = defineEmits<{
   'find:returnTaskNodes': [nodeList: SimpleFlowNode[]]
 }>()
-
-const currentNode = ref<SimpleFlowNode>(props.flowNode)
-// 监控节点变化
-watch(
-  () => props.flowNode,
-  (newValue) => {
-    currentNode.value = newValue
-  }
-)
-const notAllowedMultiApprovers = ref(false)
-const settingVisible = ref(false)
-const roleOptions = inject<Ref<RoleApi.RoleVO[]>>('roleList') // 角色列表
-const postOptions = inject<Ref<PostApi.PostVO[]>>('postList') // 岗位列表
-const userOptions = inject<Ref<UserApi.UserVO[]>>('userList') // 用户列表
-const deptOptions = inject<Ref<DeptApi.DeptVO[]>>('deptList') // 部门列表
-const userGroupOptions = inject<Ref<UserGroupApi.UserGroupVO[]>>('userGroupList') // 用户组列表
-const deptTreeOptions = inject('deptTree') // 部门树
-const formType = inject('formType') // 表单类型
-const formFields = inject<Ref<string[]>>('formFields')
-const returnTaskList = ref<SimpleFlowNode[]>([])
-
+// 监控节点的变化
+const currentNode = useWatchNode(props)
+// 抽屉配置
+const { settingVisible, closeDrawer, openDrawer } = useDrawer()
+// 节点名称配置
+const { nodeName, showInput, clickIcon, blurEvent } = useNodeName(NodeType.USER_TASK_NODE)
+// 激活的 Tab 标签页
+const activeTabName = ref('user')
+// 表单字段权限设置
+const { formType, fieldsPermissionConfig, getNodeConfigFormFields } = useFormFieldsPermission()
+// 操作按钮设置
+const { buttonsSetting, btnDisplayNameEdit, changeBtnDisplayName, btnDisplayNameBlurEvent } =
+  useButtonsSetting()
+
+// 审批人表单设置
 const formRef = ref() // 表单 Ref
-const activeTabName = ref('user') // 激活的 Tab 标签页
-const configForm = ref<any>({
-  name: NODE_DEFAULT_NAME.get(NodeType.USER_TASK_NODE),
-  candidateParamArray: [],
-  candidateStrategy: CandidateStrategy.USER,
-  approveMethod: ApproveMethodType.RRANDOM_SELECT_ONE_APPROVE,
-  approveRatio: 100,
-  rejectHandlerType: RejectHandlerType.FINISH_PROCESS,
-  returnNodeId: '',
-  timeoutHandlerEnable: false,
-  timeoutHandlerAction: 1,
-  timeDuration: 6, // 默认 6小时
-  maxRemindCount: 1, // 默认 提醒 1次
-  fieldsPermission: [],
-  buttonsSetting: []
-})
 // 表单校验规则
 const formRules = reactive({
   candidateStrategy: [{ required: true, message: '审批人设置不能为空', trigger: 'change' }],
@@ -443,10 +418,66 @@ const formRules = reactive({
   timeDuration: [{ required: true, message: '超时时间不能为空', trigger: 'blur' }],
   maxRemindCount: [{ required: true, message: '提醒次数不能为空', trigger: 'blur' }]
 })
-// 关闭
-const closeDrawer = () => {
-  settingVisible.value = false
+
+const {
+  configForm: tempConfigForm,
+  roleOptions,
+  postOptions,
+  userOptions,
+  userGroupOptions,
+  deptTreeOptions,
+  getShowText
+} = useNodeForm(NodeType.USER_TASK_NODE)
+const configForm = tempConfigForm as Ref<UserTaskFormType>
+// 不允许多人审批
+const notAllowedMultiApprovers = ref(false)
+// 改变审批人设置策略
+const changeCandidateStrategy = () => {
+  configForm.value.candidateParamArray = []
+  configForm.value.approveMethod = ApproveMethodType.RRANDOM_SELECT_ONE_APPROVE
+  if (
+    configForm.value.candidateStrategy === CandidateStrategy.START_USER ||
+    configForm.value.candidateStrategy === CandidateStrategy.USER
+  ) {
+    notAllowedMultiApprovers.value = true
+  } else {
+    notAllowedMultiApprovers.value = false
+  }
+}
+// 改变审批候选人
+const changedCandidateUsers = () => {
+  if (
+    configForm.value.candidateParamArray?.length <= 1 &&
+    configForm.value.candidateStrategy === CandidateStrategy.USER
+  ) {
+    configForm.value.approveMethod = ApproveMethodType.RRANDOM_SELECT_ONE_APPROVE
+    configForm.value.rejectHandlerType = RejectHandlerType.FINISH_PROCESS
+    notAllowedMultiApprovers.value = true
+  } else {
+    notAllowedMultiApprovers.value = false
+  }
 }
+// 审批方式改变
+const approveMethodChanged = () => {
+  configForm.value.rejectHandlerType = RejectHandlerType.FINISH_PROCESS
+  if (configForm.value.approveMethod === ApproveMethodType.APPROVE_BY_RATIO) {
+    configForm.value.approveRatio = 100
+  }
+  formRef.value.clearValidate('approveRatio')
+}
+// 审批拒绝 可回退的节点
+const returnTaskList = ref<SimpleFlowNode[]>([])
+// 审批人超时未处理设置
+const {
+  timeoutHandlerChange,
+  cTimeoutAction,
+  timeoutActionChanged,
+  timeUnit,
+  timeUnitChange,
+  isoTimeDuration,
+  cTimeoutMaxRemindCount
+} = useTimeoutHandler()
+
 // 保存配置
 const saveConfig = async () => {
   activeTabName.value = 'user'
@@ -455,7 +486,7 @@ const saveConfig = async () => {
   if (!valid) return false
   const showText = getShowText()
   if (!showText) return false
-  currentNode.value.name = configForm.value.name
+  currentNode.value.name = nodeName.value!
   currentNode.value.candidateStrategy = configForm.value.candidateStrategy
   currentNode.value.candidateParam = configForm.value.candidateParamArray?.join(',')
   // 设置审批方式
@@ -465,121 +496,31 @@ const saveConfig = async () => {
   }
   // 设置拒绝处理
   currentNode.value.rejectHandler = {
-    type: configForm.value.rejectHandlerType,
+    type: configForm.value.rejectHandlerType!,
     returnNodeId: configForm.value.returnNodeId
   }
   // 设置超时处理
   currentNode.value.timeoutHandler = {
-    enable: configForm.value.timeoutHandlerEnable,
+    enable: configForm.value.timeoutHandlerEnable!,
     action: cTimeoutAction.value,
     timeDuration: isoTimeDuration.value,
     maxRemindCount: cTimeoutMaxRemindCount.value
   }
   // 设置表单权限
-  currentNode.value.fieldsPermission = configForm.value.fieldsPermission
+  currentNode.value.fieldsPermission = fieldsPermissionConfig.value
   // 设置按钮权限
-  currentNode.value.buttonsSetting = configForm.value.buttonsSetting
+  currentNode.value.buttonsSetting = buttonsSetting.value
 
-  currentNode.value.showText = getShowText()
+  currentNode.value.showText = showText
   settingVisible.value = false
   return true
 }
-const getShowText = (): string => {
-  let showText = ''
-  // 指定成员
-  if (configForm.value.candidateStrategy === CandidateStrategy.USER) {
-    if (configForm.value.candidateParamArray?.length > 0) {
-      const candidateNames: string[] = []
-      userOptions?.value.forEach((item) => {
-        if (configForm.value.candidateParamArray.includes(item.id)) {
-          candidateNames.push(item.nickname)
-        }
-      })
-      showText = `指定成员:${candidateNames.join(',')}`
-    }
-  }
-  // 指定角色
-  if (configForm.value.candidateStrategy === CandidateStrategy.ROLE) {
-    if (configForm.value.candidateParamArray?.length > 0) {
-      const candidateNames: string[] = []
-      roleOptions?.value.forEach((item) => {
-        if (configForm.value.candidateParamArray.includes(item.id)) {
-          candidateNames.push(item.name)
-        }
-      })
-      showText = `指定角色:${candidateNames.join(',')}`
-    }
-  }
-  // 指定部门
-  if (
-    configForm.value.candidateStrategy === CandidateStrategy.DEPT_MEMBER ||
-    configForm.value.candidateStrategy === CandidateStrategy.DEPT_LEADER
-  ) {
-    if (configForm.value.candidateParamArray?.length > 0) {
-      const candidateNames: string[] = []
-      deptOptions?.value.forEach((item) => {
-        if (configForm.value.candidateParamArray.includes(item.id)) {
-          candidateNames.push(item.name)
-        }
-      })
-      if (configForm.value.candidateStrategy === CandidateStrategy.DEPT_MEMBER) {
-        showText = `部门成员:${candidateNames.join(',')}`
-      } else {
-        showText = `部门的负责人:${candidateNames.join(',')}`
-      }
-    }
-  }
 
-  // 指定岗位
-  if (configForm.value.candidateStrategy === CandidateStrategy.POST) {
-    if (configForm.value.candidateParamArray?.length > 0) {
-      const candidateNames: string[] = []
-      postOptions?.value.forEach((item) => {
-        if (configForm.value.candidateParamArray.includes(item.id)) {
-          candidateNames.push(item.name)
-        }
-      })
-      showText = `指定岗位: ${candidateNames.join(',')}`
-    }
-  }
-  // 指定用户组
-  if (configForm.value.candidateStrategy === CandidateStrategy.USER_GROUP) {
-    if (configForm.value.candidateParamArray?.length > 0) {
-      const candidateNames: string[] = []
-      userGroupOptions?.value.forEach((item) => {
-        if (configForm.value.candidateParamArray.includes(item.id)) {
-          candidateNames.push(item.name)
-        }
-      })
-      showText = `指定用户组: ${candidateNames.join(',')}`
-    }
-  }
-
-  // 发起人自选
-  if (configForm.value.candidateStrategy === CandidateStrategy.START_USER_SELECT) {
-    showText = `发起人自选`
-  }
-  // 发起人自己
-  if (configForm.value.candidateStrategy === CandidateStrategy.START_USER) {
-    showText = `发起人自己`
-  }
-
-  // 流程表达式
-  if (configForm.value.candidateStrategy === CandidateStrategy.EXPRESSION) {
-    if (configForm.value.candidateParamArray?.length > 0) {
-      showText = `流程表达式:${configForm.value.candidateParamArray[0]}`
-    }
-  }
-  return showText
-}
-const open = () => {
-  settingVisible.value = true
-}
-// 配置审批节点, 由父组件传过来
-const setCurrentNode = (node: SimpleFlowNode) => {
-  configForm.value.name = node.name
+// 显示审批节点配置, 由父组件传过来
+const showUserTaskNodeConfig = (node: SimpleFlowNode) => {
+  nodeName.value = node.name
   //1.1 审批人设置
-  configForm.value.candidateStrategy = node.candidateStrategy
+  configForm.value.candidateStrategy = node.candidateStrategy!
   const strCandidateParam = node?.candidateParam
   if (node.candidateStrategy === CandidateStrategy.EXPRESSION) {
     configForm.value.candidateParamArray[0] = strCandidateParam
@@ -598,18 +539,18 @@ const setCurrentNode = (node: SimpleFlowNode) => {
     notAllowedMultiApprovers.value = false
   }
   //1.2 设置审批方式
-  configForm.value.approveMethod = node.approveMethod
+  configForm.value.approveMethod = node.approveMethod!
   if (node.approveMethod == ApproveMethodType.APPROVE_BY_RATIO) {
-    configForm.value.approveRatio = node.approveRatio
+    configForm.value.approveRatio = node.approveRatio!
   }
   // 1.3 设置审批拒绝处理
-  configForm.value.rejectHandlerType = node.rejectHandler?.type
+  configForm.value.rejectHandlerType = node.rejectHandler!.type
   configForm.value.returnNodeId = node.rejectHandler?.returnNodeId
   const matchNodeList = []
   emits('find:returnTaskNodes', matchNodeList)
   returnTaskList.value = matchNodeList
   // 1.4 设置审批超时处理
-  configForm.value.timeoutHandlerEnable = node.timeoutHandler?.enable
+  configForm.value.timeoutHandlerEnable = node.timeoutHandler!.enable
   if (node.timeoutHandler?.enable && node.timeoutHandler?.timeDuration) {
     const strTimeDuration = node.timeoutHandler.timeDuration
     let parseTime = strTimeDuration.slice(2, strTimeDuration.length - 1)
@@ -620,151 +561,120 @@ const setCurrentNode = (node: SimpleFlowNode) => {
   configForm.value.timeoutHandlerAction = node.timeoutHandler?.action
   configForm.value.maxRemindCount = node.timeoutHandler?.maxRemindCount
   // 2. 操作按钮设置
-  configForm.value.buttonsSetting = cloneDeep(node.buttonsSetting) || DEFAULT_BUTTON_SETTING
+  buttonsSetting.value = cloneDeep(node.buttonsSetting) || DEFAULT_BUTTON_SETTING
   // 3. 表单字段权限配置
-  configForm.value.fieldsPermission =
-    cloneDeep(node.fieldsPermission) || getDefaultFieldsPermission(formFields?.value)
+  getNodeConfigFormFields(node.fieldsPermission)
 }
 
-defineExpose({ open, setCurrentNode }) // 暴露方法给父组件
-
-const changeCandidateStrategy = () => {
-  configForm.value.candidateParamArray = []
-  configForm.value.approveMethod = ApproveMethodType.RRANDOM_SELECT_ONE_APPROVE
-  if (
-    configForm.value.candidateStrategy === CandidateStrategy.START_USER ||
-    configForm.value.candidateStrategy === CandidateStrategy.USER
-  ) {
-    notAllowedMultiApprovers.value = true
-  } else {
-    notAllowedMultiApprovers.value = false
-  }
-}
-
-const changedCandidateUsers = () => {
-  if (
-    configForm.value.candidateParamArray?.length <= 1 &&
-    configForm.value.candidateStrategy === CandidateStrategy.USER
-  ) {
-    configForm.value.approveMethod = ApproveMethodType.RRANDOM_SELECT_ONE_APPROVE
-    configForm.value.rejectHandlerType = RejectHandlerType.FINISH_PROCESS
-    notAllowedMultiApprovers.value = true
-  } else {
-    notAllowedMultiApprovers.value = false
-  }
-}
-// 显示名称输入框
-const showInput = ref(false)
-
-const clickIcon = () => {
-  showInput.value = true
-}
-// 节点名称输入框失去焦点
-const blurEvent = () => {
-  showInput.value = false
-  configForm.value.name =
-    configForm.value.name || (NODE_DEFAULT_NAME.get(NodeType.USER_TASK_NODE) as string)
-}
-
-const approveMethodChanged = () => {
-  configForm.value.rejectHandlerType = RejectHandlerType.FINISH_PROCESS
-  if (configForm.value.approveMethod === ApproveMethodType.APPROVE_BY_RATIO) {
-    configForm.value.approveRatio = 100
+defineExpose({ openDrawer, showUserTaskNodeConfig }) // 暴露方法给父组件
+
+/**
+ * @description 操作按钮设置
+ */
+function useButtonsSetting() {
+  const buttonsSetting = ref<ButtonSetting[]>()
+  // 操作按钮显示名称可编辑
+  const btnDisplayNameEdit = ref<boolean[]>([])
+  const changeBtnDisplayName = (index: number) => {
+    btnDisplayNameEdit.value[index] = true
+  }
+  const btnDisplayNameBlurEvent = (index: number) => {
+    btnDisplayNameEdit.value[index] = false
+    const buttonItem = buttonsSetting.value![index]
+    buttonItem.displayName = buttonItem.displayName || OPERATION_BUTTON_NAME.get(buttonItem.id)!
+  }
+  return {
+    buttonsSetting,
+    btnDisplayNameEdit,
+    changeBtnDisplayName,
+    btnDisplayNameBlurEvent
   }
-  formRef.value.clearValidate('approveRatio')
 }
 
-const timeUnit = ref(TimeUnitType.HOUR)
-
-// 超时时间的 ISO 表示
-const isoTimeDuration = computed(() => {
-  if (!configForm.value.timeoutHandlerEnable) {
-    return undefined
-  }
-  let strTimeDuration = 'PT'
-  if (timeUnit.value === TimeUnitType.MINUTE) {
-    strTimeDuration += configForm.value.timeDuration + 'M'
-  }
-  if (timeUnit.value === TimeUnitType.HOUR) {
-    strTimeDuration += configForm.value.timeDuration + 'H'
-  }
-  if (timeUnit.value === TimeUnitType.DAY) {
-    strTimeDuration += configForm.value.timeDuration + 'D'
-  }
-  return strTimeDuration
-})
-// 超时执行的动作
-const cTimeoutAction = computed(() => {
-  if (!configForm.value.timeoutHandlerEnable) {
-    return undefined
-  }
-  return configForm.value.timeoutHandlerAction
-})
-// 超时最大提醒次数
-const cTimeoutMaxRemindCount = computed(() => {
-  if (!configForm.value.timeoutHandlerEnable) {
-    return undefined
-  }
-  if (configForm.value.timeoutHandlerAction !== 1) {
-    return undefined
+/**
+ * @description 审批人超时未处理配置
+ */
+function useTimeoutHandler() {
+  // 时间单位
+  const timeUnit = ref(TimeUnitType.HOUR)
+
+  // 超时开关改变
+  const timeoutHandlerChange = () => {
+    if (configForm.value.timeoutHandlerEnable) {
+      timeUnit.value = 2
+      configForm.value.timeDuration = 6
+      configForm.value.timeoutHandlerAction = 1
+      configForm.value.maxRemindCount = 1
+    }
   }
-  return configForm.value.maxRemindCount
-})
+  // 超时执行的动作
+  const cTimeoutAction = computed(() => {
+    if (!configForm.value.timeoutHandlerEnable) {
+      return undefined
+    }
+    return configForm.value.timeoutHandlerAction
+  })
 
-// 超时开关改变
-const timeoutHandlerChange = () => {
-  if (configForm.value.timeoutHandlerEnable) {
-    timeUnit.value = 2
-    configForm.value.timeDuration = 6
-    configForm.value.timeoutHandlerAction = 1
-    configForm.value.maxRemindCount = 1
-  }
-}
-// 超时处理动作改变
-const timeoutActionChanged = () => {
-  if (configForm.value.timeoutHandlerAction === 1) {
-    configForm.value.maxRemindCount = 1 // 超时提醒次数,默认为1
+  // 超时处理动作改变
+  const timeoutActionChanged = () => {
+    if (configForm.value.timeoutHandlerAction === 1) {
+      configForm.value.maxRemindCount = 1 // 超时提醒次数,默认为1
+    }
   }
-}
 
-// 时间单位改变
-const timeUnitChange = () => {
-  // 分钟,默认是 60 分钟
-  if (timeUnit.value === TimeUnitType.MINUTE) {
-    configForm.value.timeDuration = 60
-  }
-  // 小时,默认是 6 个小时
-  if (timeUnit.value === TimeUnitType.HOUR) {
-    configForm.value.timeDuration = 6
-  }
-  // 天, 默认 1天
-  if (timeUnit.value === TimeUnitType.DAY) {
-    configForm.value.timeDuration = 1
+  // 时间单位改变
+  const timeUnitChange = () => {
+    // 分钟,默认是 60 分钟
+    if (timeUnit.value === TimeUnitType.MINUTE) {
+      configForm.value.timeDuration = 60
+    }
+    // 小时,默认是 6 个小时
+    if (timeUnit.value === TimeUnitType.HOUR) {
+      configForm.value.timeDuration = 6
+    }
+    // 天, 默认 1天
+    if (timeUnit.value === TimeUnitType.DAY) {
+      configForm.value.timeDuration = 1
+    }
   }
-}
+  // 超时时间的 ISO 表示
+  const isoTimeDuration = computed(() => {
+    if (!configForm.value.timeoutHandlerEnable) {
+      return undefined
+    }
+    let strTimeDuration = 'PT'
+    if (timeUnit.value === TimeUnitType.MINUTE) {
+      strTimeDuration += configForm.value.timeDuration + 'M'
+    }
+    if (timeUnit.value === TimeUnitType.HOUR) {
+      strTimeDuration += configForm.value.timeDuration + 'H'
+    }
+    if (timeUnit.value === TimeUnitType.DAY) {
+      strTimeDuration += configForm.value.timeDuration + 'D'
+    }
+    return strTimeDuration
+  })
 
-const convertTimeUnit = (strTimeUnit: string) => {
-  if (strTimeUnit === 'M') {
-    return TimeUnitType.MINUTE
-  }
-  if (strTimeUnit === 'H') {
-    return TimeUnitType.HOUR
-  }
-  if (strTimeUnit === 'D') {
-    return TimeUnitType.DAY
+  // 超时最大提醒次数
+  const cTimeoutMaxRemindCount = computed(() => {
+    if (!configForm.value.timeoutHandlerEnable) {
+      return undefined
+    }
+    if (configForm.value.timeoutHandlerAction !== 1) {
+      return undefined
+    }
+    return configForm.value.maxRemindCount
+  })
+
+  return {
+    timeoutHandlerChange,
+    cTimeoutAction,
+    timeoutActionChanged,
+    timeUnit,
+    timeUnitChange,
+    isoTimeDuration,
+    cTimeoutMaxRemindCount
   }
-  return TimeUnitType.HOUR
-}
-
-// 操作按钮显示名称可编辑
-const btnDisplayNameEdit = ref<boolean[]>([])
-const changeBtnDisplayName = (index: number) => {
-  btnDisplayNameEdit.value[index] = true
-}
-const btnDisplayNameBlurEvent = (index: number) => {
-  btnDisplayNameEdit.value[index] = false
-  const buttonItem = configForm.value.buttonPermission[index]
-  buttonItem.displayName = buttonItem.displayName || OPERATION_BUTTON_NAME.get(buttonItem.id)
 }
 </script>
 

+ 2 - 3
src/components/SimpleProcessDesignerV2/src/nodes/CopyTaskNode.vue

@@ -43,7 +43,6 @@
 import { SimpleFlowNode, NodeType, NODE_DEFAULT_TEXT, NODE_DEFAULT_NAME } from '../consts'
 import NodeHandler from '../NodeHandler.vue'
 import CopyTaskNodeConfig from '../nodes-config/CopyTaskNodeConfig.vue'
-import { generateUUID } from '@/utils'
 defineOptions({
   name: 'CopyTaskNode'
 })
@@ -81,8 +80,8 @@ const clickEvent = () => {
 const nodeSetting = ref()
 // 打开节点配置
 const openNodeConfig = () => {
-  nodeSetting.value.setCurrentNode(currentNode.value)
-  nodeSetting.value.open()
+  nodeSetting.value.showCopyTaskNodeConfig(currentNode.value)
+  nodeSetting.value.openDrawer()
 }
 
 // 删除节点。更新当前节点为孩子节点

+ 6 - 10
src/components/SimpleProcessDesignerV2/src/nodes/UserTaskNode.vue

@@ -45,6 +45,7 @@
 </template>
 <script setup lang="ts">
 import { SimpleFlowNode, NodeType, NODE_DEFAULT_TEXT, NODE_DEFAULT_NAME } from '../consts'
+import { useWatchNode } from '../node'
 import NodeHandler from '../NodeHandler.vue'
 import UserTaskNodeConfig from '../nodes-config/UserTaskNodeConfig.vue'
 defineOptions({
@@ -61,21 +62,16 @@ const emits = defineEmits<{
   'find:parentNode': [nodeList: SimpleFlowNode[], nodeType: NodeType]
 }>()
 
-const currentNode = ref<SimpleFlowNode>(props.flowNode)
+const currentNode = useWatchNode(props)
+
 const nodeSetting = ref()
 // 打开节点配置
 const openNodeConfig = () => {
   // 把当前节点传递给配置组件
-  nodeSetting.value.setCurrentNode(currentNode.value)
-  nodeSetting.value.open()
+  nodeSetting.value.showUserTaskNodeConfig(currentNode.value)
+  nodeSetting.value.openDrawer()
 }
-// 监控节点变化
-watch(
-  () => props.flowNode,
-  (newValue) => {
-    currentNode.value = newValue
-  }
-)
+
 // 显示节点名称输入框
 const showInput = ref(false)
 // 节点名称输入框失去焦点

+ 12 - 13
src/components/SimpleProcessDesignerV2/src/utils.ts

@@ -1,3 +1,5 @@
+import { TimeUnitType } from './consts'
+
 // 获取条件节点默认的名称
 export const getDefaultConditionNodeName = (index: number, defaultFlow: boolean): string => {
   if (defaultFlow) {
@@ -6,18 +8,15 @@ export const getDefaultConditionNodeName = (index: number, defaultFlow: boolean)
   return '条件' + (index + 1)
 }
 
-// 获得默认的表单字段权限.
-export const getDefaultFieldsPermission = (formFields: string[] | undefined) => {
-  const defaultFieldsPermission: any[] = []
-  if (formFields) {
-    formFields.forEach((fieldStr: string) => {
-      const { field, title } = JSON.parse(fieldStr)
-      defaultFieldsPermission.push({
-        field,
-        title,
-        permission: '1' // 只读
-      })
-    })
+export const convertTimeUnit = (strTimeUnit: string) => {
+  if (strTimeUnit === 'M') {
+    return TimeUnitType.MINUTE
+  }
+  if (strTimeUnit === 'H') {
+    return TimeUnitType.HOUR
+  }
+  if (strTimeUnit === 'D') {
+    return TimeUnitType.DAY
   }
-  return defaultFieldsPermission
+  return TimeUnitType.HOUR
 }