Selaa lähdekoodia

仿钉钉流程设计器- 删除第1版,新增连续多级部分负责人策略

jason 1 vuosi sitten
vanhempi
sitoutus
ab9ce936a3

+ 0 - 386
src/components/SimpleProcessDesigner/src/addNode.vue

@@ -1,386 +0,0 @@
-/* stylelint-disable order/properties-order */
-<template>
-  <div class="add-node-btn-box">
-    <div class="add-node-btn">
-      <el-popover placement="right-start" v-model="visible" width="auto">
-        <div class="add-node-popover-body">
-          <a class="add-node-popover-item approver" @click="addType(1)">
-            <div class="item-wrapper">
-              <span class="iconfont icon-approve"></span>
-            </div>
-            <p>审批人</p>
-          </a>
-          <!--  TODO 暂时去掉未完成
-          <a class="add-node-popover-item notifier" @click="addType(2)">
-            <div class="item-wrapper">
-              <span class="iconfont"></span>
-            </div>
-            <p>抄送人</p>
-          </a>
-          <a class="add-node-popover-item condition" @click="addType(4)">
-            <div class="item-wrapper">
-              <span class="iconfont"></span>
-            </div>
-            <p>条件分支</p>
-          </a>
-          -->
-          <a class="add-node-popover-item notifier" @click="addType(2)">
-            <div class="item-wrapper">
-              <span class="iconfont icon-copy"></span>
-            </div>
-            <p>抄送人</p>
-          </a>
-          <a class="add-node-popover-item condition" @click="addType(4)">
-            <div class="item-wrapper">
-              <span class="iconfont icon-exclusive"></span>
-            </div>
-            <p>条件分支</p>
-          </a>
-          <a class="add-node-popover-item condition" @click="addType(5)">
-            <div class="item-wrapper">
-              <span class="iconfont icon-parallel"></span>
-            </div>
-            <p>并行分支</p>
-          </a>
-          <a class="add-node-popover-item condition" @click="addType(7)">
-            <div class="item-wrapper">
-              <span class="iconfont icon-Inclusive"></span>
-            </div>
-            <p>包容分支</p>
-          </a>
-        </div>
-        <template #reference>
-          <button class="btn" type="button" v-if="showAddButton">
-            <span><Icon icon="ep:plus" class="addIcon" :size="14" /></span>
-          </button>
-        </template>
-      </el-popover>
-    </div>
-  </div>
-</template>
-<script lang="ts" setup>
-import { NodeType } from './consts'
-import { ref } from 'vue'
-import { generateUUID } from '@/utils'
-let props = defineProps({
-  childNodeP: {
-    type: Object,
-    default: () => ({})
-  },
-  showAddButton: {
-    type: Boolean,
-    default: true
-  }
-})
-let emits = defineEmits(['update:childNodeP'])
-let visible = ref(false)
-const defaultFieldsPermission = inject('defaultFieldsPermission')
-
-const addType = (type: number) => {
-  visible.value = false
-  // 审核节点
-  if (type === NodeType.APPROVE_USER_NODE) {
-    const data = {
-      name: '审核人',
-      error: true,
-      type: 1,
-      // 审批节点配置
-      attributes: {
-        approveMethod: undefined,
-        candidateStrategy: undefined,
-        candidateParam: undefined,
-        fieldsPermission: defaultFieldsPermission
-      },
-      childNode: props.childNodeP
-    }
-    emits('update:childNodeP', data)
-  }
-  // 抄送节点
-  if (type === NodeType.CC_USER_NODE) {
-    const data = {
-      name: '抄送人',
-      type: 2, // TODO @jason:这个要不要搞成枚举?NodeType 里貌似有枚举
-      error: true,
-      // 抄送节点配置
-      attributes: {
-        candidateStrategy: undefined,
-        candidateParam: undefined
-      },
-      childNode: props.childNodeP
-    }
-    emits('update:childNodeP', data)
-  }
-  // 条件分支
-  if (type === NodeType.EXCLUSIVE_NODE) {
-    const data = {
-      name: '条件分支',
-      type: 4,
-      id: 'GateWay_' + generateUUID(),
-      childNode: props.childNodeP,
-      conditionNodes: [
-        {
-          name: '分支1',
-          error: true,
-          type: 3,
-          priorityLevel: 1,
-          conditionList: [],
-          childNode: null
-        },
-        {
-          name: '其它情况',
-          type: 3,
-          priorityLevel: 2,
-          conditionList: [],
-          childNode: null
-        }
-      ]
-    }
-    emits('update:childNodeP', data)
-  }
-  // 并行分支 fork
-  if (type === NodeType.PARALLEL_NODE_FORK) {
-    const data = {
-      name: '并行分支_FORK',
-      type: 5,
-      id: 'GateWay_' + generateUUID(),
-      conditionNodes: [
-        {
-          name: '并行1',
-          error: true,
-          type: 3,
-          childNode: null
-        },
-        {
-          name: '并行2',
-          type: 3,
-          childNode: null
-        }
-      ],
-      childNode: {
-        id: 'GateWay_' + generateUUID(),
-        name: '并行分支_JOIN',
-        type: 6,
-        error: true,
-        childNode: props.childNodeP
-      }
-    }
-    emits('update:childNodeP', data)
-  }
-  // 包容分支 fork
-  if (type === NodeType.INCLUSIVE_NODE_FORK) {
-    const data = {
-      name: '包容分支_FORK',
-      type: 7,
-      id: 'GateWay_' + generateUUID(),
-      conditionNodes: [
-        {
-          name: '分支1',
-          error: true,
-          type: 3,
-          childNode: null
-        },
-        {
-          name: '其它情况',
-          type: 3,
-          childNode: null
-        }
-      ],
-      childNode: {
-        id: 'GateWay_' + generateUUID(),
-        name: '包容分支_JOIN',
-        type: 8,
-        error: true,
-        childNode: props.childNodeP
-      }
-    }
-    emits('update:childNodeP', data)
-  }
-  // if (type != 4) {
-  //   var data
-  //   if (type == 1) {
-  //     data = {
-  //       name: '审核人',
-  //       error: true,
-  //       type: 1,
-  //       // 审批节点配置
-  //       attributes : {
-  //         approveMethod : undefined,
-  //         candidateStrategy: undefined,
-  //         candidateParam: undefined
-  //       },
-  //       childNode: props.childNodeP
-  //     }
-  //   } else if (type == 2) {
-  //     data = {
-  //       name: '抄送人',
-  //       type: 2,
-  //       error: true,
-  //        // 抄送节点配置
-  //       attributes : {
-  //         candidateStrategy: undefined,
-  //         candidateParam: undefined
-  //       },
-  //       childNode: props.childNodeP
-  //     }
-  //   }
-  //   emits('update:childNodeP', data)
-  // } else {
-  //   emits('update:childNodeP', {
-  //     name: '路由',
-  //     type: 4,
-  //     id : 'GateWay_'+ generateUUID(),
-  //     childNode: props.childNodeP,
-  //     conditionNodes: [
-  //       {
-  //         name: '条件1',
-  //         error: true,
-  //         type: 3,
-  //         priorityLevel: 1,
-  //         conditionList: [],
-  //         childNode: null
-  //       },
-  //       {
-  //         name: '其它情况',
-  //         type: 3,
-  //         priorityLevel: 2,
-  //         conditionList: [],
-  //         childNode: null
-  //       }
-  //     ]
-  //   })
-  // }
-}
-</script>
-<style scoped lang="scss">
-.add-node-btn-box {
-  position: relative;
-  display: inline-flex;
-  width: 240px;
-  -ms-flex-negative: 0;
-  flex-shrink: 0;
-  -webkit-box-flex: 1;
-  -ms-flex-positive: 1;
-
-  &::before {
-    position: absolute;
-    inset: 0;
-    z-index: -1;
-    width: 2px;
-    height: 100%;
-    margin: auto;
-    background-color: #cacaca;
-    content: '';
-  }
-
-  .add-node-btn {
-    display: flex;
-    width: 240px;
-    padding: 20px 0 32px;
-    justify-content: center;
-    flex-shrink: 0;
-    -webkit-box-flex: 1;
-    -webkit-box-pack: center;
-    user-select: none;
-    flex-grow: 1;
-
-    .btn {
-      position: relative;
-      width: 30px;
-      height: 30px;
-      line-height: 30px;
-      background: #3296fa;
-      border: none;
-      border-radius: 50%;
-      outline: none;
-      box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.1);
-      -webkit-transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
-      transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
-
-      .addIcon {
-        line-height: 30px;
-        color: #fff;
-      }
-
-      &:hover {
-        transform: scale(1.3);
-        box-shadow: 0 13px 27px 0 rgba(0, 0, 0, 0.1);
-      }
-
-      &:active {
-        background: #1e83e9;
-        transform: none;
-        box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.1);
-      }
-    }
-  }
-}
-
-.add-node-popover-body {
-  display: flex;
-
-  .add-node-popover-item {
-    margin-right: 10px;
-    cursor: pointer;
-    text-align: center;
-    flex: 1;
-    color: #191f25 !important;
-
-    .item-wrapper {
-      display: inline-block;
-      width: 80px;
-      height: 80px;
-      margin-bottom: 5px;
-      background: #fff;
-      border: 1px solid #e2e2e2;
-      border-radius: 50%;
-      transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
-      user-select: none;
-
-      .iconfont {
-        font-size: 35px;
-        line-height: 80px;
-      }
-    }
-
-    &.approver {
-      .item-wrapper {
-        color: #ff943e;
-      }
-    }
-
-    &.notifier {
-      .item-wrapper {
-        color: #3296fa;
-      }
-    }
-
-    &.condition {
-      .item-wrapper {
-        color: #15bc83;
-      }
-    }
-
-    &:hover {
-      .item-wrapper {
-        background: #3296fa;
-        box-shadow: 0 10px 20px 0 rgba(50, 150, 250, 0.4);
-      }
-
-      .iconfont {
-        color: #fff;
-      }
-    }
-
-    &:active {
-      .item-wrapper {
-        background: #eaeaea;
-        box-shadow: none;
-      }
-
-      .iconfont {
-        color: inherit;
-      }
-    }
-  }
-}
-</style>

+ 0 - 63
src/components/SimpleProcessDesigner/src/consts.ts

@@ -1,63 +0,0 @@
-export enum NodeType {
-  //// -1 根节点流程开始节点 0 发起人 1审批 2抄送 3条件 4路由
-  ROOT_NODE = -1,
-  /**
-   * 发起人节点
-   */
-  START_USER_NODE = 0,
-  /**
-   * 审批人节点
-   */
-  APPROVE_USER_NODE = 1,
-  /**
-   * 抄送人节点
-   */
-  CC_USER_NODE = 2,
-  /**
-   * 条件节点
-   */
-  CONDITION_NODE = 3,
-  /**
-   * 条件分支节点
-   */
-  EXCLUSIVE_NODE = 4,
-  /**
-   * 并行分支分叉节点
-   */
-  PARALLEL_NODE_FORK = 5,
-  /**
-   * 并行分支聚合
-   */
-  PARALLEL_NODE_JOIN = 6,
-  /**
-   * 包容分支分叉节点
-   */
-  INCLUSIVE_NODE_FORK = 7,
-  /**
-   * 包容分支聚合节点
-   */
-  INCLUSIVE_NODE_JOIN = 8
-}
-
-export const NODE_BG_COLOR = new Map()
-NODE_BG_COLOR.set(NodeType.START_USER_NODE, '#87, 106, 149')
-NODE_BG_COLOR.set(NodeType.APPROVE_USER_NODE, '#255, 148, 62')
-NODE_BG_COLOR.set(NodeType.CC_USER_NODE, '#50, 150, 250')
-
-/**
- * 节点的标题
- */
-export const NODE_TITLE = new Map()
-NODE_TITLE.set(NodeType.START_USER_NODE, '发起人')
-NODE_TITLE.set(NodeType.APPROVE_USER_NODE, '审批人')
-NODE_TITLE.set(NodeType.CC_USER_NODE, '抄送人')
-
-export type WorkFlowNode = {
-  id: string,
-  type: NodeType,
-  name: string,
-  attributes: any,
-  // 操作人
-  childNode?: WorkFlowNode | undefined,
-  conditionNodes: WorkFlowNode[]
-}

+ 0 - 434
src/components/SimpleProcessDesigner/src/drawer/approverDrawer.vue

@@ -1,434 +0,0 @@
-<!-- eslint-disable vue/html-self-closing -->
-<template>
-  <el-drawer
-    :append-to-body="true"
-    v-model="visible"
-    :show-close="false"
-    :size="550"
-    :before-close="saveConfig"
-    class="justify-start"
-  >
-    <template #header>
-      <div class="w-full flex flex-col">
-        <span class="text-size-2xl">审批设置</span>
-        <el-divider />
-      </div>
-    </template>
-    <el-tabs type="border-card">
-      <el-tab-pane label="审批人">
-        <div>
-          <el-form label-position="top" label-width="100px">
-            <el-form-item label="审批方式" prop="approveMethod">
-              <el-select v-model="candidateConfig.approveMethod" style="width: 100%" clearable>
-                <el-option
-                  v-for="dict in approveMethods"
-                  :key="dict.value"
-                  :label="dict.label"
-                  :value="dict.value"
-                />
-              </el-select>
-            </el-form-item>
-
-            <el-form-item label="审批人规则类型" prop="candidateStrategy">
-              <el-select
-                v-model="candidateConfig.candidateStrategy"
-                style="width: 100%"
-                clearable
-                @change="changecandidateStrategy"
-              >
-                <el-option
-                  v-for="dict in getIntDictOptions(DICT_TYPE.BPM_TASK_CANDIDATE_STRATEGY)"
-                  :key="dict.value"
-                  :label="dict.label"
-                  :value="dict.value"
-                />
-              </el-select>
-            </el-form-item>
-
-            <el-form-item
-              v-if="candidateConfig.candidateStrategy == 10"
-              label="指定角色"
-              prop="candidateParam"
-            >
-              <el-select
-                v-model="candidateConfig.candidateParam"
-                clearable
-                multiple
-                style="width: 100%"
-              >
-                <el-option
-                  v-for="item in roleOptions"
-                  :key="item.id"
-                  :label="item.name"
-                  :value="item.id"
-                />
-              </el-select>
-            </el-form-item>
-            <el-form-item
-              v-if="
-                candidateConfig.candidateStrategy == 20 || candidateConfig.candidateStrategy == 21
-              "
-              label="指定部门"
-              prop="candidateParam"
-              span="24"
-            >
-              <el-tree-select
-                ref="treeRef"
-                v-model="candidateConfig.candidateParam"
-                :data="deptTreeOptions"
-                :props="defaultProps"
-                empty-text="加载中,请稍后"
-                multiple
-                node-key="id"
-                style="width: 100%"
-                show-checkbox
-              />
-            </el-form-item>
-            <el-form-item
-              v-if="candidateConfig.candidateStrategy == 22"
-              label="指定岗位"
-              prop="candidateParam"
-              span="24"
-            >
-              <el-select
-                v-model="candidateConfig.candidateParam"
-                clearable
-                multiple
-                style="width: 100%"
-              >
-                <el-option
-                  v-for="item in postOptions"
-                  :key="item.id"
-                  :label="item.name"
-                  :value="item.id"
-                />
-              </el-select>
-            </el-form-item>
-            <el-form-item
-              v-if="
-                candidateConfig.candidateStrategy == 30 ||
-                candidateConfig.candidateStrategy == 31 ||
-                candidateConfig.candidateStrategy == 32
-              "
-              label="指定用户"
-              prop="candidateParam"
-              span="24"
-            >
-              <el-select
-                v-model="candidateConfig.candidateParam"
-                clearable
-                multiple
-                style="width: 100%"
-              >
-                <el-option
-                  v-for="item in userOptions"
-                  :key="item.id"
-                  :label="item.nickname"
-                  :value="item.id"
-                />
-              </el-select>
-            </el-form-item>
-            <el-form-item
-              v-if="candidateConfig.candidateStrategy === 40"
-              label="指定用户组"
-              prop="candidateParam"
-            >
-              <el-select
-                v-model="candidateConfig.candidateParam"
-                clearable
-                multiple
-                style="width: 100%"
-              >
-                <el-option
-                  v-for="item in userGroupOptions"
-                  :key="item.id"
-                  :label="item.name"
-                  :value="item.id"
-                />
-              </el-select>
-            </el-form-item>
-            <el-form-item
-              v-if="candidateConfig.candidateStrategy === 60"
-              label="流程表达式"
-              prop="candidateParam"
-            >
-              <el-input
-                type="textarea"
-                v-model="candidateConfig.candidateParam[0]"
-                clearable
-                style="width: 100%"
-              />
-            </el-form-item>
-          </el-form>
-        </div>
-      </el-tab-pane>
-      <el-tab-pane label="设置字段权限" v-if="formType === 10">
-        <div class="field-setting-pane h-full w-full flex flex-col">
-          <div class="field-setting-content mr-2 overflow-auto py-4 pr-2">
-            <div class="field-container flex flex-col flex-items-start">
-              <div class="mb-2 ml-4 font-bold">字段权限</div>
-              <div class="field-body ml-4 mt-2">
-                <div class="field-permit-box text-size--13px">
-                  <div class="field-permit-title">
-                    <span class="setting-title-label">组件名称</span>
-                    <span class="setting-title-label">可编辑</span>
-                    <span class="setting-title-label">只读</span>
-                    <span class="setting-title-label">隐藏</span>
-                  </div>
-                  <!-- <div class="field-setting-item">
-                    <span class="field-setting-item-label">全选</span>
-                    <span class="all-checkbox-wrap">
-                      <el-checkbox
-                        label=""
-                        size="large"
-                      />
-                    </span>
-                    <span class="all-checkbox-wrap">
-                      <el-checkbox
-                        label=""
-                        size="large"
-                      />
-                    </span>
-                    <span class="all-checkbox-wrap">
-                      <el-checkbox
-                        label=""
-                        size="large"
-                      />
-                    </span>
-                  </div> -->
-                  <div class="field-setting-item-check">
-                    <div
-                      class="field-setting-item"
-                      v-for="(item, index) in candidateConfig.fieldsPermission"
-                      :key="index"
-                    >
-                      <span class="field-setting-item-label"> {{ item.title }}</span>
-                      <el-radio-group v-model="item.permission">
-                        <div class="item-radio-wrap">
-                          <el-radio value="1" size="large" label="1" />
-                        </div>
-                        <div class="item-radio-wrap">
-                          <el-radio value="2" size="large" label="2" />
-                        </div>
-                        <div class="item-radio-wrap">
-                          <el-radio value="3" size="large" label="3" />
-                        </div>
-                      </el-radio-group>
-                    </div>
-                  </div>
-                </div>
-              </div>
-            </div>
-          </div>
-        </div>
-      </el-tab-pane>
-    </el-tabs>
-
-    <template #footer>
-      <el-divider />
-      <div>
-        <el-button type="primary" @click="saveConfig">确 定</el-button>
-        <el-button @click="closeDrawer">取 消</el-button>
-      </div>
-    </template>
-  </el-drawer>
-</template>
-<script lang="ts" setup>
-import { ref, watch, computed, toRaw } from 'vue'
-import { approveMethods } from '../util'
-import { useWorkFlowStoreWithOut } from '@/store/modules/bpm/simpleWorkflow'
-import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
-import { defaultProps, handleTree } 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'
-
-const roleOptions = ref<RoleApi.RoleVO[]>([]) // 角色列表
-const postOptions = ref<PostApi.PostVO[]>([]) // 岗位列表
-const userOptions = ref<UserApi.UserVO[]>([]) // 用户列表
-const deptTreeOptions = ref() // 部门树
-const userGroupOptions = ref<UserGroupApi.UserGroupVO[]>([]) // 用户组列表
-const candidateConfig = ref({
-  candidateStrategy: undefined,
-  candidateParam: [],
-  approveMethod: undefined,
-  fieldsPermission: []
-})
-const store = useWorkFlowStoreWithOut()
-let { setApproverDrawer, setUserTaskConfig } = store
-// let approverConfig1 = computed(() => store.approverConfig1)
-let approverDrawer = computed(() => store.approverDrawer)
-const userTaskConfig = computed(() => store.userTaskConfig)
-const formType = inject('formType')
-let visible = computed({
-  get() {
-    return approverDrawer.value
-  },
-  set() {
-    closeDrawer()
-  }
-})
-watch(userTaskConfig, (val) => {
-  if (val.value.attributes) {
-    candidateConfig.value.approveMethod = val.value.attributes.approveMethod
-    candidateConfig.value.candidateStrategy = val.value.attributes.candidateStrategy
-    const candidateParamStr = val.value.attributes.candidateParam
-    if (val.value.attributes.candidateStrategy === 60) {
-      candidateConfig.value.candidateParam = [candidateParamStr]
-    } else {
-      if (candidateParamStr) {
-        candidateConfig.value.candidateParam = candidateParamStr.split(',').map((item) => +item)
-      }
-    }
-    console.log('val.value.attributes.fieldsPermission', val.value.attributes.fieldsPermission)
-    candidateConfig.value.fieldsPermission = val.value.attributes.fieldsPermission
-  }
-})
-// watch(approverConfig1, (val) => {
-//   approverConfig.value = val.value
-// })
-
-const saveConfig = () => {
-  const rawConfig = toRaw(userTaskConfig.value)
-  const { approveMethod, candidateStrategy, candidateParam, fieldsPermission } = toRaw(
-    candidateConfig.value
-  )
-  const candidateParamStr = candidateParam.join(',')
-  rawConfig.value.attributes = {
-    approveMethod,
-    candidateStrategy,
-    candidateParam: candidateParamStr,
-    fieldsPermission: fieldsPermission
-  }
-  rawConfig.flag = true
-  // TODO 进行校验
-  // setApproverConfig({
-  //     value: approverConfig.value,
-  //     flag: true,
-  //     id: approverConfig1.value.id
-  // })
-  setUserTaskConfig({
-    value: rawConfig.value,
-    flag: true,
-    id: userTaskConfig.value.id
-  })
-  closeDrawer()
-}
-
-const closeDrawer = () => {
-  setApproverDrawer(false)
-}
-const changecandidateStrategy = () => {
-  candidateConfig.value.candidateParam = []
-}
-const handleAllCheck = (event, type) => {
-  console.log('event', event)
-  console.log('type', type)
-  event.target.checked = true
-  let permission = '1'
-  if (type === 'edit' && editAllChecked.value) {
-    permission = '1' // TODO @jaosn:这个要不要用枚举里的哈
-  }
-  if (type === 'read' && readAllChecked.value) {
-    permission = '2'
-  }
-  if (type === 'hide' && hideAllChecked.value) {
-    permission = '3'
-  }
-  candidateConfig.value.fieldsPermission.forEach((item) => {
-    item.permission = permission
-  })
-}
-onMounted(async () => {
-  // 获得角色列表
-  roleOptions.value = await RoleApi.getSimpleRoleList()
-  // 获得岗位列表
-  postOptions.value = await PostApi.getSimplePostList()
-  // 获得用户列表
-  userOptions.value = await UserApi.getSimpleUserList()
-  // 获得部门列表
-  const deptOptions = await DeptApi.getSimpleDeptList()
-  deptTreeOptions.value = handleTree(deptOptions, 'id')
-  // 获得用户组列表
-  userGroupOptions.value = await UserGroupApi.getUserGroupSimpleList()
-})
-</script>
-<style lang="scss" scoped>
-// ::v-deep .el-drawer__header {
-//   margin-bottom: 2px;
-// }
-.field-permit-title {
-  height: 45px;
-  padding: 0 0 0 12px;
-  line-height: 32px;
-  background-color: rgba(248, 250, 252, 0.04);
-  border: 1px solid rgba(31, 56, 88, 0.1);
-
-  .setting-title-label:first-child {
-    text-align: left;
-  }
-
-  .setting-title-label {
-    display: inline-block;
-    width: 110px;
-    padding: 5px 0;
-    font-size: 13px;
-    font-weight: 700;
-    color: rgba(0, 0, 0, 0.6);
-    text-align: center;
-  }
-}
-
-.field-setting-item {
-  display: flex;
-  align-items: center;
-  height: 38px;
-  padding-bottom: 0;
-  padding-left: 12px;
-  line-height: 38px;
-  border-right: 1px solid rgba(31, 56, 88, 0.1);
-  border-bottom: 1px solid rgba(31, 56, 88, 0.1);
-  border-left: 1px solid rgba(31, 56, 88, 0.1);
-
-  .no-label {
-    font-size: 0;
-  }
-
-  .field-setting-item-label {
-    display: inline-block;
-    width: 110px;
-    min-height: 16px;
-    overflow: hidden;
-    text-overflow: ellipsis;
-    white-space: nowrap;
-    cursor: text;
-  }
-
-  .all-checkbox-wrap {
-    display: inline-block;
-    width: 110px;
-    text-align: center;
-  }
-
-  .item-radio-wrap {
-    display: inline-block;
-    width: 110px;
-    padding-left: 6px;
-    text-align: center;
-  }
-}
-
-::v-deep(.el-radio__label) {
-  opacity: 0; /* 隐藏标签文本 */
-}
-
-::v-deep(.el-divider--horizontal) {
-  display: block;
-  width: 100%;
-  height: 1px;
-  margin: 4px 0;
-  border-top: 1px var(--el-border-color) var(--el-border-style);
-}
-</style>

+ 0 - 250
src/components/SimpleProcessDesigner/src/drawer/copyerDrawer.vue

@@ -1,250 +0,0 @@
-<template>
-  <el-drawer
-    :append-to-body="true"
-    v-model="visible"
-    :show-close="false"
-    :size="550"
-    :before-close="saveConfig"
-  >
-    <template #header>
-      <div class="copy-task-header">抄送人设置</div>
-    </template>
-    <div>
-      <el-form label-position="top" label-width="100px">
-        <el-form-item label="选择抄送人" prop="candidateStrategy">
-          <el-select
-            v-model="candidateConfig.candidateStrategy"
-            style="width: 100%"
-            clearable
-            @change="changecandidateStrategy"
-          >
-            <el-option
-              v-for="dict in getIntDictOptions(DICT_TYPE.BPM_TASK_CANDIDATE_STRATEGY)"
-              :key="dict.value"
-              :label="dict.label"
-              :value="dict.value"
-            />
-          </el-select>
-        </el-form-item>
-
-        <el-form-item
-          v-if="candidateConfig.candidateStrategy == 10"
-          label="指定角色"
-          prop="candidateParam"
-        >
-          <el-select
-            v-model="candidateConfig.candidateParam"
-            clearable
-            multiple
-            style="width: 100%"
-          >
-            <el-option
-              v-for="item in roleOptions"
-              :key="item.id"
-              :label="item.name"
-              :value="item.id"
-            />
-          </el-select>
-        </el-form-item>
-        <el-form-item
-          v-if="candidateConfig.candidateStrategy == 20 || candidateConfig.candidateStrategy == 21"
-          label="指定部门"
-          prop="candidateParam"
-          span="24"
-        >
-          <el-tree-select
-            ref="treeRef"
-            v-model="candidateConfig.candidateParam"
-            :data="deptTreeOptions"
-            :props="defaultProps"
-            empty-text="加载中,请稍后"
-            multiple
-            node-key="id"
-            style="width: 100%"
-            show-checkbox
-          />
-        </el-form-item>
-        <el-form-item
-          v-if="candidateConfig.candidateStrategy == 22"
-          label="指定岗位"
-          prop="candidateParam"
-          span="24"
-        >
-          <el-select
-            v-model="candidateConfig.candidateParam"
-            clearable
-            multiple
-            style="width: 100%"
-          >
-            <el-option
-              v-for="item in postOptions"
-              :key="item.id"
-              :label="item.name"
-              :value="item.id"
-            />
-          </el-select>
-        </el-form-item>
-        <el-form-item
-          v-if="
-            candidateConfig.candidateStrategy == 30 ||
-            candidateConfig.candidateStrategy == 31 ||
-            candidateConfig.candidateStrategy == 32
-          "
-          label="指定用户"
-          prop="candidateParam"
-          span="24"
-        >
-          <el-select
-            v-model="candidateConfig.candidateParam"
-            clearable
-            multiple
-            style="width: 100%"
-          >
-            <el-option
-              v-for="item in userOptions"
-              :key="item.id"
-              :label="item.nickname"
-              :value="item.id"
-            />
-          </el-select>
-        </el-form-item>
-        <el-form-item
-          v-if="candidateConfig.candidateStrategy === 40"
-          label="指定用户组"
-          prop="candidateParam"
-        >
-          <el-select
-            v-model="candidateConfig.candidateParam"
-            clearable
-            multiple
-            style="width: 100%"
-          >
-            <el-option
-              v-for="item in userGroupOptions"
-              :key="item.id"
-              :label="item.name"
-              :value="item.id"
-            />
-          </el-select>
-        </el-form-item>
-        <el-form-item
-          v-if="candidateConfig.candidateStrategy === 60"
-          label="流程表达式"
-          prop="candidateParam"
-        >
-          <el-input
-            type="textarea"
-            v-model="candidateConfig.candidateParam[0]"
-            clearable
-            style="width: 100%"
-          />
-        </el-form-item>
-      </el-form>
-    </div>
-    <div class="demo-drawer__footer clear">
-      <el-button type="primary" @click="saveConfig">确 定</el-button>
-      <el-button @click="closeDrawer">取 消</el-button>
-    </div>
-  </el-drawer>
-</template>
-<script lang="ts" setup>
-import { ref, watch, computed, toRaw } from 'vue'
-import { useWorkFlowStoreWithOut } from '@/store/modules/bpm/simpleWorkflow'
-import { DICT_TYPE, getIntDictOptions, getDictLabel } from '@/utils/dict'
-import { defaultProps, handleTree } 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'
-
-const roleOptions = ref<RoleApi.RoleVO[]>([]) // 角色列表
-const postOptions = ref<PostApi.PostVO[]>([]) // 岗位列表
-const userOptions = ref<UserApi.UserVO[]>([]) // 用户列表
-const deptTreeOptions = ref() // 部门树
-const userGroupOptions = ref<UserGroupApi.UserGroupVO[]>([]) // 用户组列表
-const candidateConfig = ref({
-  candidateStrategy: undefined,
-  candidateParam: []
-})
-const store = useWorkFlowStoreWithOut()
-const { setCopyerDrawer, setCopyerConfig } = store
-
-const copyerDrawer = computed(() => store.copyerDrawer)
-const copyerConfig = computed(() => store.copyerConfig)
-
-const visible = computed({
-  get() {
-    return copyerDrawer.value
-  },
-  set() {
-    closeDrawer()
-  }
-})
-watch(copyerConfig, (val) => {
-  if (val.value.attributes) {
-    console.log('val.value.attributes', val.value.attributes)
-    candidateConfig.value.candidateStrategy = val.value.attributes.candidateStrategy
-    const candidateParamStr = val.value.attributes.candidateParam
-    if (val.value.attributes.candidateStrategy === 60) {
-      candidateConfig.value.candidateParam = [candidateParamStr]
-    } else {
-      if (candidateParamStr) {
-        candidateConfig.value.candidateParam = candidateParamStr.split(',').map((item) => +item)
-      }
-    }
-
-    // candidateConfig.value = val.value.attributes
-  }
-})
-
-const saveConfig = () => {
-  const rawConfig = toRaw(copyerConfig.value)
-  const { candidateStrategy, candidateParam } = toRaw(candidateConfig.value)
-  const candidateParamStr = candidateParam.join(',')
-  rawConfig.value.attributes = {
-    candidateStrategy,
-    candidateParam: candidateParamStr
-  }
-  rawConfig.flag = true
-  // TODO 进行校验
-  // setApproverConfig({
-  //     value: approverConfig.value,
-  //     flag: true,
-  //     id: approverConfig1.value.id
-  // })
-
-  setCopyerConfig({
-    value: rawConfig.value,
-    flag: true,
-    id: copyerConfig.value.id
-  })
-  console.log('after is copyerConfig', copyerConfig.value)
-  closeDrawer()
-}
-
-const closeDrawer = () => {
-  setCopyerDrawer(false)
-}
-const changecandidateStrategy = () => {
-  candidateConfig.value.candidateParam = []
-}
-onMounted(async () => {
-  // 获得角色列表
-  roleOptions.value = await RoleApi.getSimpleRoleList()
-  // 获得岗位列表
-  postOptions.value = await PostApi.getSimplePostList()
-  // 获得用户列表
-  userOptions.value = await UserApi.getSimpleUserList()
-  // 获得部门列表
-  const deptOptions = await DeptApi.getSimpleDeptList()
-  deptTreeOptions.value = handleTree(deptOptions, 'id')
-  // 获得用户组列表
-  userGroupOptions.value = await UserGroupApi.getUserGroupSimpleList()
-})
-</script>
-<style lang="scss" scoped>
-.copy-task-header {
-  font-size: 16px !important;
-}
-</style>

+ 0 - 504
src/components/SimpleProcessDesigner/src/nodeWrap.vue

@@ -1,504 +0,0 @@
-<!-- eslint-disable vue/no-mutating-props -->
-<!--
- * @Date: 2022-09-21 14:41:53
- * @LastEditors: StavinLi 495727881@qq.com
- * @LastEditTime: 2023-05-24 15:20:24
- * @FilePath: /Workflow-Vue3/src/components/nodeWrap.vue
--->
-<template>
-  <div class="node-wrap" v-if="nodeConfig.type < 3">
-    <div class="node-wrap-box" :class="isTried && nodeConfig.error ? 'active error' : ''">
-      <div class="title" :style="`background: rgb(${bgColors[nodeConfig.type]});`">
-        <span v-if="nodeConfig.type == 0">发起人</span>
-        <template v-else>
-          <span
-            class="iconfont"
-            :class="nodeConfig.type === NodeType.APPROVE_USER_NODE ? 'icon-approve' : 'icon-copy'"
-          >
-          </span>
-          <input
-            v-if="isInput"
-            type="text"
-            class="ant-input editable-title-input"
-            @blur="blurEvent(-1)"
-            @focus="$event.currentTarget?.select()"
-            v-mountedFocus
-            v-model="nodeConfig.name"
-            :placeholder="defaultText"
-          />
-          <span v-else class="editable-title" @click="clickEvent(-1)">{{ nodeConfig.name }}</span>
-          <i class="anticon anticon-close close" @click="delNode"></i>
-        </template>
-      </div>
-      <div class="content" @click="setPerson">
-        <div class="text">
-          <span class="placeholder" v-if="!showText">请选择{{ defaultText }}</span>
-          <span v-html="showText" class="ellipsis-text" v-else></span>
-        </div>
-        <!-- <div class="icon-box">
-          <i class="anticon anticon-edit" @click="editNode"></i>
-        </div> -->
-        <i class="anticon anticon-right arrow"></i>
-      </div>
-      <div class="error_tip" v-if="isTried && nodeConfig.error">
-        <i class="anticon anticon-exclamation-circle"></i>
-      </div>
-    </div>
-    <addNode v-model:childNodeP="nodeConfig.childNode" />
-  </div>
-  <div class="branch-wrap" v-if="nodeConfig.type == 4">
-    <div class="branch-box-wrap">
-      <div class="branch-box">
-        <button class="add-branch" @click="addTerm(nodeConfig.type)">添加条件</button>
-        <div class="col-box" v-for="(item, index) in nodeConfig.conditionNodes" :key="index">
-          <div class="condition-node">
-            <div class="condition-node-box">
-              <div class="title-wrapper" :style="`background: rgb(${bgColors[nodeConfig.type]});`">
-                <input
-                  v-if="isInputList[index]"
-                  type="text"
-                  class="ant-input editable-title-input"
-                  @blur="blurEvent(index)"
-                  @focus="$event.currentTarget?.select()"
-                  v-mountedFocus
-                  v-model="item.name"
-                />
-                <span v-else class="editable-title" @click="clickEvent(index)">{{
-                  item.name
-                }}</span>
-                <!-- <span class="priority-title" @click="setPerson(item.priorityLevel)"
-                      >优先级{{ index + 1 }}</span
-                    > -->
-                <i
-                  class="anticon anticon-close close"
-                  @click="delTerm(nodeConfig.type,index)"
-                  v-if="nodeConfig.conditionNodes && index != nodeConfig.conditionNodes?.length - 1"
-                ></i>
-              </div>
-              <div class="auto-judge" :class="isTried && item.error ? 'error active' : ''">
-                <!-- <div class="sort-left" v-if="index != 0" @click="arrTransfer(index, -1)">&lt;</div> -->
-
-                <!-- <div
-                  class="sort-right"
-                  v-if="index != nodeConfig.conditionNodes.length - 1"
-                  @click="arrTransfer(index)"
-                  >&gt;</div
-                > -->
-                <!-- <div class="content" @click="setPerson(item.priorityLevel)">{{
-                  conditionStr(nodeConfig, index)
-                }}</div> -->
-                <div class="content">{{ conditionStr(nodeConfig, index) }}</div>
-                <div class="error_tip" v-if="isTried && item.error">
-                  <i class="anticon anticon-exclamation-circle"></i>
-                </div>
-              </div>
-              <addNode v-model:childNodeP="item.childNode" />
-            </div>
-          </div>
-          <nodeWrap v-if="item.childNode" v-model:nodeConfig="item.childNode" />
-          <template v-if="index == 0">
-            <div class="top-left-cover-line"></div>
-            <div class="bottom-left-cover-line"></div>
-          </template>
-          <template v-if="index == nodeConfig.conditionNodes.length - 1">
-            <div class="top-right-cover-line"></div>
-            <div class="bottom-right-cover-line"></div>
-          </template>
-        </div>
-      </div>
-      <addNode v-model:childNodeP="nodeConfig.childNode" />
-    </div>
-  </div>
-  <div class="branch-wrap" v-if="nodeConfig.type == 5">
-    <div class="branch-box-wrap">
-      <div class="branch-box">
-        <button class="add-branch" @click="addTerm(nodeConfig.type)">添加分支</button>
-        <div class="col-box" v-for="(item, index) in nodeConfig.conditionNodes" :key="index">
-          <div class="condition-node">
-            <div class="condition-node-box">
-              <div class="title-wrapper" :style="`background: rgb(${bgColors[nodeConfig.type]});`">
-                <input
-                  v-if="isInputList[index]"
-                  type="text"
-                  class="ant-input editable-title-input"
-                  @blur="blurEvent(index)"
-                  @focus="$event.currentTarget?.select()"
-                  v-mountedFocus
-                  v-model="item.name"
-                />
-                <span v-else class="editable-title" @click="clickEvent(index)">{{
-                  item.name
-                }}</span>
-                <i class="anticon anticon-close close" @click="delTerm(nodeConfig.type, index)"></i>
-              </div>
-              <div class="auto-judge" :class="isTried && item.error ? 'error active' : ''">
-                <div class="content">并行执行</div>
-                <div class="error_tip" v-if="isTried && item.error">
-                  <i class="anticon anticon-exclamation-circle"></i>
-                </div>
-              </div>
-              <addNode v-model:childNodeP="item.childNode" />
-            </div>
-          </div>
-          <nodeWrap v-if="item.childNode" v-model:nodeConfig="item.childNode" />
-          <template v-if="index == 0">
-            <div class="top-left-cover-line"></div>
-            <div class="bottom-left-cover-line"></div>
-          </template>
-          <template v-if="index === nodeConfig.conditionNodes.length - 1">
-            <div class="top-right-cover-line"></div>
-            <div class="bottom-right-cover-line"></div>
-          </template>
-        </div>
-      </div>
-      <addNode v-model:childNodeP="nodeConfig.childNode" :show-add-button="false" />
-    </div>
-  </div>
-  <div class="branch-wrap" v-if="nodeConfig.type == 7">
-    <div class="branch-box-wrap">
-      <div class="branch-box">
-        <button class="add-branch" @click="addTerm(nodeConfig.type)">添加分支</button>
-        <div class="col-box" v-for="(item, index) in nodeConfig.conditionNodes" :key="index">
-          <div class="condition-node">
-            <div class="condition-node-box">
-              <div class="title-wrapper" :style="`background: rgb(${bgColors[nodeConfig.type]});`">
-                <input
-                  v-if="isInputList[index]"
-                  type="text"
-                  class="ant-input editable-title-input"
-                  @blur="blurEvent(index)"
-                  @focus="$event.currentTarget?.select()"
-                  v-mountedFocus
-                  v-model="item.name"
-                />
-                <span v-else class="editable-title" @click="clickEvent(index)">
-                  {{ item.name }}
-                </span>
-                 <i
-                  class="anticon anticon-close close"
-                  @click="delTerm(nodeConfig.type,index)"
-                  v-if="index != nodeConfig.conditionNodes?.length - 1"
-                  ></i>
-              </div>
-              <div class="auto-judge" :class="isTried && item.error ? 'error active' : ''">
-                <div class="content">{{ conditionStr(nodeConfig, index) }}</div>
-                <div class="error_tip" v-if="isTried && item.error">
-                  <i class="anticon anticon-exclamation-circle"></i>
-                </div>
-              </div>
-              <addNode v-model:childNodeP="item.childNode" />
-            </div>
-          </div>
-          <nodeWrap v-if="item.childNode" v-model:nodeConfig="item.childNode" />
-          <template v-if="index == 0">
-            <div class="top-left-cover-line"></div>
-            <div class="bottom-left-cover-line"></div>
-          </template>
-          <template v-if="index == nodeConfig.conditionNodes.length - 1">
-            <div class="top-right-cover-line"></div>
-            <div class="bottom-right-cover-line"></div>
-          </template>
-        </div>
-      </div>
-      <addNode v-model:childNodeP="nodeConfig.childNode" :show-add-button="false" />
-    </div>
-  </div>
-  <div class="node-wrap" v-if="nodeConfig.type === NodeType.PARALLEL_NODE_JOIN || nodeConfig.type === NodeType.INCLUSIVE_NODE_JOIN">
-    <div class="node-wrap-box">
-      <div class="content">
-        <div class="text">聚合</div>
-      </div>
-    </div>
-    <addNode v-model:childNodeP="nodeConfig.childNode"  />
-  </div>
-  <nodeWrap v-if="nodeConfig.childNode" v-model:nodeConfig="nodeConfig.childNode" />
-</template>
-<script lang="ts" setup>
-import addNode from './addNode.vue'
-import { onMounted, ref, watch, getCurrentInstance, computed } from 'vue'
-import {
-  conditionStr,
-  setApproverStr,
-  copyerStr,
-  bgColors,
-  placeholderList,
-  getApproverShowText
-} from './util'
-import { WorkFlowNode, NodeType } from './consts'
-import { useWorkFlowStoreWithOut } from '@/store/modules/bpm/simpleWorkflow'
-let _uid = getCurrentInstance().uid
-import { generateUUID } from '@/utils'
-let props = defineProps({
-  nodeConfig: {
-    type: Object as () => WorkFlowNode,
-    default: () => ({}) as WorkFlowNode
-  }
-})
-
-let defaultText = computed(() => {
-  return placeholderList[props.nodeConfig.type]
-})
-const isInputList = ref<boolean[]>([])
-const isInput = ref<boolean>(false)
-const resetConditionNodesErr = () => {
-  for (var i = 0; i < props.nodeConfig.conditionNodes.length; i++) {
-    // eslint-disable-next-line vue/no-mutating-props
-    props.nodeConfig.conditionNodes[i].error =
-      conditionStr(props.nodeConfig, i) == '请设置条件' &&
-      i != props.nodeConfig.conditionNodes.length - 1
-  }
-}
-onMounted(() => {
-  if (props.nodeConfig.type == 1) {
-    // eslint-disable-next-line vue/no-mutating-props
-    props.nodeConfig.error = !setApproverStr(props.nodeConfig)
-  } else if (props.nodeConfig.type == 2) {
-    // eslint-disable-next-line vue/no-mutating-props
-    props.nodeConfig.error = !copyerStr(props.nodeConfig)
-  } else if (props.nodeConfig.type == 4) {
-    resetConditionNodesErr()
-  }
-})
-let emits = defineEmits(['update:nodeConfig'])
-let store = useWorkFlowStoreWithOut()
-let {
-  setApproverDrawer,
-  setCopyerDrawer,
-  // setCondition,
-  setCopyerConfig,
-  // setConditionsConfig,
-  setUserTaskConfig
-} = store
-// ???
-const isTried = computed(() => store.isTried)
-// 审批节点的配置
-const userTaskConfig = computed(() => store.userTaskConfig)
-// 抄送节点的配置
-const copyerConfig = computed(() => store.copyerConfig)
-// let conditionsConfig1 = computed(() => store.conditionsConfig1)
-const showText = computed(() => {
-  if (props.nodeConfig.type == 0) return '发起人'
-  if (props.nodeConfig.type == 1) {
-    if (props.nodeConfig.attributes) {
-      return getApproverShowText(
-        props.nodeConfig.attributes.approveMethod,
-        props.nodeConfig.attributes.candidateStrategy
-      )
-    } else {
-      return ''
-    }
-  }
-  if (props.nodeConfig.type === 2) {
-    if (props.nodeConfig.attributes) {
-      return copyerStr(props.nodeConfig.attributes.candidateStrategy)
-    } else {
-      return ''
-    }
-  }
-  return ''
-})
-watch(userTaskConfig, (approver) => {
-  if (approver.flag && approver.id === _uid) {
-    emits('update:nodeConfig', approver.value)
-  }
-})
-watch(copyerConfig, (copyer) => {
-  console.log('copyer', copyer)
-  if (copyer.flag && copyer.id === _uid) {
-    console.log('copyer id is equal', copyer)
-    emits('update:nodeConfig', copyer.value)
-  }
-})
-
-// watch(conditionsConfig1, (condition) => {
-//   if (condition.flag && condition.id === _uid) {
-//     emits('update:nodeConfig', condition.value)
-//   }
-// })
-
-const clickEvent = (index) => {
-  if (index >= 0) {
-    isInputList.value[index] = true
-  } else {
-    isInput.value = true
-  }
-}
-
-const blurEvent = (index) => {
-  if (index >= 0) {
-    isInputList.value[index] = false
-    // eslint-disable-next-line vue/no-mutating-props
-    props.nodeConfig.conditionNodes[index].name =
-      props.nodeConfig.conditionNodes[index].name || '条件'
-  } else {
-    isInput.value = false
-    // eslint-disable-next-line vue/no-mutating-props
-    props.nodeConfig.name = props.nodeConfig.name || defaultText
-  }
-}
-const delNode = () => {
-  emits('update:nodeConfig', props.nodeConfig.childNode)
-}
-const addTerm = (type:number) => {
-  const len = props.nodeConfig.conditionNodes.length
-  let lastIndex = props.nodeConfig.conditionNodes.length - 1
-  let nodeName = '分支' + len
-  if(type === NodeType.PARALLEL_NODE_FORK) {
-    nodeName = '并行' + (len+1);
-    lastIndex = props.nodeConfig.conditionNodes.length;
-  }
-  const conditionData = {
-    id: 'SequenceFlow'+ generateUUID(),
-    name: nodeName,
-    type: NodeType.CONDITION_NODE,
-    childNode: undefined,
-    conditionNodes:[],
-    attributes : undefined
-  };
-  // eslint-disable-next-line vue/no-mutating-props
-  props.nodeConfig.conditionNodes.splice(lastIndex, 0, conditionData)
-  resetConditionNodesErr()
-  emits('update:nodeConfig', props.nodeConfig)
-}
-const delTerm = (nodeType: number, index: number) => {
-  if (props.nodeConfig.conditionNodes) {
-    // eslint-disable-next-line vue/no-mutating-props
-    props.nodeConfig.conditionNodes.splice(index, 1)
-    if (nodeType === NodeType.PARALLEL_NODE_FORK) {
-      props.nodeConfig.conditionNodes.map((item, index) => {
-          item.name = `并行${index + 1}`
-      })
-    } else {
-      props.nodeConfig.conditionNodes.map((item, index) => {
-      // item.priorityLevel = index + 1
-      if (index !== props.nodeConfig.conditionNodes.length - 1) {
-        item.name = `分支${index + 1}`
-      }
-    })
-    }
-   
-    resetConditionNodesErr()
-    emits('update:nodeConfig', props.nodeConfig)
-    if (props.nodeConfig.conditionNodes.length == 1) {
-      if (nodeType === NodeType.PARALLEL_NODE_FORK || nodeType === NodeType.INCLUSIVE_NODE_FORK) {
-        const joinNode = props.nodeConfig.childNode;
-        if (joinNode?.childNode) {
-          if (props.nodeConfig.conditionNodes[0].childNode) {
-            reData(props.nodeConfig.conditionNodes[0].childNode, joinNode?.childNode)
-          } else {
-            // eslint-disable-next-line vue/no-mutating-props
-            props.nodeConfig.conditionNodes[0].childNode = joinNode?.childNode
-          }
-        }
-        emits('update:nodeConfig', props.nodeConfig.conditionNodes[0].childNode)
-      } else {
-        if (props.nodeConfig.childNode) {
-          if (props.nodeConfig.conditionNodes[0].childNode) {
-            reData(props.nodeConfig.conditionNodes[0].childNode, props.nodeConfig.childNode)
-          } else {
-            // eslint-disable-next-line vue/no-mutating-props
-            props.nodeConfig.conditionNodes[0].childNode = props.nodeConfig.childNode
-          }
-        }
-        emits('update:nodeConfig', props.nodeConfig.conditionNodes[0].childNode)
-      }
-    }
-  }
-}
-const reData = (data, addData) => {
-  if (!data.childNode) {
-    data.childNode = addData
-  } else {
-    reData(data.childNode, addData)
-  }
-}
-const setPerson = (priorityLevel) => {
-  console.log('priorityLevel', priorityLevel)
-  const { type } = props.nodeConfig
-  console.log('type', type)
-  if (type == 0) {
-    // setPromoter(true)
-  } else if (type == 1) {
-    setApproverDrawer(true)
-    // if (_uid === userTaskConfig.value.id) {
-    //   showText = userTaskConfig.value.showText
-    // }
-    setUserTaskConfig({
-      value: {
-        ...JSON.parse(JSON.stringify(props.nodeConfig)),
-        id: 'Activity_' + _uid
-      },
-      flag: false,
-      id: _uid
-    })
-  } else if (type == 2) {
-    setCopyerDrawer(true)
-    setCopyerConfig({
-      value: {
-        ...JSON.parse(JSON.stringify(props.nodeConfig)),
-        id: 'Activity_' + _uid
-      },
-      flag: false,
-      id: _uid
-    })
-  } else {
-    // setCondition(true)
-    // setConditionsConfig({
-    //   value: {
-    //     ...JSON.parse(JSON.stringify(props.nodeConfig)),
-    //     id: 'Gateway_' + _uid
-    //   },
-    //   priorityLevel,
-    //   flag: false,
-    //   id: _uid
-    // })
-  }
-}
-// const arrTransfer = (index, type = 1) => {
-//   //向左-1,向右1
-//   // eslint-disable-next-line vue/no-mutating-props
-//   props.nodeConfig.conditionNodes[index] = props.nodeConfig.conditionNodes.splice(
-//     index + type,
-//     1,
-//     props.nodeConfig.conditionNodes[index]
-//   )[0]
-//   props.nodeConfig.conditionNodes.map((item, index) => {
-//     item.priorityLevel = index + 1
-//   })
-//   resetConditionNodesErr()
-//   emits('update:nodeConfig', props.nodeConfig)
-// }
-</script>
-<style lang="scss" scoped>
-.ellipsis-text {
-  overflow: hidden;
-  text-overflow: ellipsis;
-  white-space: nowrap;
-}
-
-.start-event-node {
-  color: #191f2566;
-  text-align: left;
-  border-radius: 50%;
-}
-
-.start-event-node-circle {
-  display: flex;
-  width: 40px;
-  height: 40px;
-  align-items: center;
-  justify-content: center;
-  // margin: auto;
-  // background: #dbdcdc;
-  font-size: 16px;
-  color: #f8f8fa;
-  background-image: linear-gradient(90deg, #ff6a00, #f78b3e), linear-gradient(#ff6a00, #ff6a00);
-  border-radius: 50%;
-}
-
-.start-event-node-text {
-  margin-top: 5px;
-  font-size: 14px;
-  text-align: center;
-}
-</style>

+ 0 - 218
src/components/SimpleProcessDesigner/src/util.ts

@@ -1,218 +0,0 @@
-// @ts-ignore
-import { DictDataVO } from '@/api/system/dict/types'
-import { DICT_TYPE,  getDictLabel } from '@/utils/dict'
-/**
- * todo
- */
-export const arrToStr = (arr?: [{ name: string }]) => {
-  if (arr) {
-    return arr
-      .map((item) => {
-        return item.name
-      })
-      .toString()
-  }
-}
-
-export const setApproverStr = (nodeConfig: any) => {
-  if (nodeConfig.settype == 1) {
-    if (nodeConfig.nodeUserList.length == 1) {
-      return nodeConfig.nodeUserList[0].name
-    } else if (nodeConfig.nodeUserList.length > 1) {
-      if (nodeConfig.examineMode == 1) {
-        return arrToStr(nodeConfig.nodeUserList)
-      } else if (nodeConfig.examineMode == 2) {
-        return nodeConfig.nodeUserList.length + '人会签'
-      }
-    }
-  } else if (nodeConfig.settype == 2) {
-    const level =
-      nodeConfig.directorLevel == 1 ? '直接主管' : '第' + nodeConfig.directorLevel + '级主管'
-    if (nodeConfig.examineMode == 1) {
-      return level
-    } else if (nodeConfig.examineMode == 2) {
-      return level + '会签'
-    }
-  } else if (nodeConfig.settype == 4) {
-    if (nodeConfig.selectRange == 1) {
-      return '发起人自选'
-    } else {
-      if (nodeConfig.nodeUserList.length > 0) {
-        if (nodeConfig.selectRange == 2) {
-          return '发起人自选'
-        } else {
-          return '发起人从' + nodeConfig.nodeUserList[0].name + '中自选'
-        }
-      } else {
-        return ''
-      }
-    }
-  } else if (nodeConfig.settype == 5) {
-    return '发起人自己'
-  } else if (nodeConfig.settype == 7) {
-    return '从直接主管到通讯录中级别最高的第' + nodeConfig.examineEndDirectorLevel + '个层级主管'
-  }
-}
-
-
-export const approveMethods: DictDataVO [] = [
-  { label: '单人审批', value: 1 }
-  // { label: '多人审批(所有人审批通过)', value: 2 }
-  // TODO 更多的类型
-];
-
-export const getApproverShowText = (approveMethod :number, candidateStrategy: number) => {
-  let appoveMethodText = '单人审批'
-  if(candidateStrategy) {
-    approveMethods.forEach((item) => {
-      if (item.value == approveMethod) {
-        appoveMethodText = item.label
-      }
-    })
-    const strategyText = getDictLabel(
-      DICT_TYPE.BPM_TASK_CANDIDATE_STRATEGY,
-      candidateStrategy
-    )
-    return `审批方式:${appoveMethodText} <br/>
-            审批人规则类型:按${strategyText}`
-  } else {
-      return ''
-  }
-}
-
-export const copyerStr = ( candidateStrategy: number) => {
-  // if (nodeConfig.nodeUserList.length != 0) {
-  //   return arrToStr(nodeConfig.nodeUserList)
-  // } else {
-  //   if (nodeConfig.ccSelfSelectFlag == 1) {
-  //     return '发起人自选'
-  //   }
-  // }
-  console.log('candidateStrategy', candidateStrategy);
-
-  if(candidateStrategy) {
-    const strategyText = getDictLabel(
-      DICT_TYPE.BPM_TASK_CANDIDATE_STRATEGY,
-      candidateStrategy
-    )
-    return `抄送人类型:按${strategyText}`
-  } else {
-      return ''
-  }
-}
-export const conditionStr = (nodeConfig, index) => {
-  // const { conditionList, nodeUserList } = nodeConfig.conditionNodes[index]
-  // if (conditionList.length == 0) {
-    // return index == nodeConfig.conditionNodes.length - 1 &&
-    //   nodeConfig.conditionNodes[0].conditionList.length != 0
-    //   ? '其他条件进入此流程'
-    //   : '请设置条件'
-    // return index == nodeConfig.conditionNodes.length - 1 &&
-    //   nodeConfig.conditionNodes[0].conditionList.length != 0
-    //   ? '其他条件进入此流程'
-    //   : '请设置条件'
-    // console.log('index===>', index);
-    // console.log('nodeConfig.conditionNodes.length===>', nodeConfig.conditionNodes.length);
-    if( index === nodeConfig.conditionNodes.length - 1) {
-      return '其它情况将进入该分支'
-    } else {
-      return '请设置条件'
-    }
-    
-  // } else {
-  //   let str = ''
-  //   for (let i = 0; i < conditionList.length; i++) {
-  //     const {
-  //       columnId,
-  //       columnType,
-  //       showType,
-  //       showName,
-  //       optType,
-  //       zdy1,
-  //       opt1,
-  //       zdy2,
-  //       opt2,
-  //       fixedDownBoxValue
-  //     } = conditionList[i]
-  //     if (columnId == 0) {
-  //       if (nodeUserList.length != 0) {
-  //         str += '发起人属于:'
-  //         str +=
-  //           nodeUserList
-  //             .map((item) => {
-  //               return item.name
-  //             })
-  //             .join('或') + ' 并且 '
-  //       }
-  //     }
-  //     if (columnType == 'String' && showType == '3') {
-  //       if (zdy1) {
-  //         str += showName + '属于:' + dealStr(zdy1, JSON.parse(fixedDownBoxValue)) + ' 并且 '
-  //       }
-  //     }
-  //     if (columnType == 'Double') {
-  //       if (optType != 6 && zdy1) {
-  //         const optTypeStr = ['', '<', '>', '≤', '=', '≥'][optType]
-  //         str += `${showName} ${optTypeStr} ${zdy1} 并且 `
-  //       } else if (optType == 6 && zdy1 && zdy2) {
-  //         str += `${zdy1} ${opt1} ${showName} ${opt2} ${zdy2} 并且 `
-  //       }
-  //     }
-  //   }
-  // str ? str.substring(0, str.length - 4) :
-  return '请设置条件'
-  // }
-}
-
-// export const dealStr = (str: string, obj) => {
-//   const arr = []
-//   const list = str.split(',')
-//   for (const elem in obj) {
-//     list.map((item) => {
-//       if (item == elem) {
-//         arr.push(obj[elem].value)
-//       }
-//     })
-//   }
-//   return arr.join('或')
-// }
-
-export const removeEle = (arr, elem, key = 'id') => {
-  let includesIndex
-  arr.map((item, index) => {
-    if (item[key] == elem[key]) {
-      includesIndex = index
-    }
-  })
-  arr.splice(includesIndex, 1)
-}
-
-export const bgColors = ['87, 106, 149', '255, 148, 62', '50, 150, 250','50, 150, 250','248, 107, 248','244, 118, 118','23, 148, 46','23, 148, 46']
-export const placeholderList = ['发起人', '审核人', '抄送人']
-export const setTypes = [
-  { value: 1, label: '指定成员' },
-  { value: 2, label: '主管' },
-  { value: 4, label: '发起人自选' },
-  { value: 5, label: '发起人自己' },
-  { value: 7, label: '连续多级主管' }
-]
-
-export const selectModes = [
-  { value: 1, label: '选一个人' },
-  { value: 2, label: '选多个人' }
-]
-
-export const selectRanges = [
-  { value: 1, label: '全公司' },
-  { value: 2, label: '指定成员' },
-  { value: 3, label: '指定角色' }
-]
-
-export const optTypes = [
-  { value: '1', label: '小于' },
-  { value: '2', label: '大于' },
-  { value: '3', label: '小于等于' },
-  { value: '4', label: '等于' },
-  { value: '5', label: '大于等于' },
-  { value: '6', label: '介于两个数之间' }
-]

BIN
src/components/SimpleProcessDesigner/theme/iconfont.ttf


BIN
src/components/SimpleProcessDesigner/theme/iconfont.woff


BIN
src/components/SimpleProcessDesigner/theme/iconfont.woff2


+ 0 - 1366
src/components/SimpleProcessDesigner/theme/workflow.css

@@ -1,1366 +0,0 @@
-
-.clearfix {
-    zoom: 1
-}
-
-.clearfix:after,
-.clearfix:before {
-    content: "";
-    display: table
-}
-
-.clearfix:after {
-    clear: both
-}
-
-@font-face {
-    font-family: anticon;
-    font-display: fallback;
-    src: url("https://at.alicdn.com/t/font_148784_v4ggb6wrjmkotj4i.eot");
-    src: url("https://at.alicdn.com/t/font_148784_v4ggb6wrjmkotj4i.woff") format("woff"), url("https://at.alicdn.com/t/font_148784_v4ggb6wrjmkotj4i.ttf") format("truetype"), url("https://at.alicdn.com/t/font_148784_v4ggb6wrjmkotj4i.svg#iconfont") format("svg")
-}
-
-.anticon {
-    display: inline-block;
-    font-style: normal;
-    vertical-align: baseline;
-    text-align: center;
-    text-transform: none;
-    line-height: 1;
-    text-rendering: optimizeLegibility;
-    -webkit-font-smoothing: antialiased;
-    -moz-osx-font-smoothing: grayscale
-}
-
-.anticon:before {
-    display: block;
-    font-family: anticon!important
-}
-.anticon-close:before {
-    content: "\E633"
-}
-.anticon-right:before {
-    content: "\E61F"
-}
-.anticon-exclamation-circle{
-    color: rgb(242, 86, 67)
-}
-.anticon-exclamation-circle:before {
-    content: "\E62C"
-}
-
-.anticon-left:before {
-    content: "\E620"
-}
-
-.anticon-close-circle:before {
-    content: "\E62E"
-}
-  
-.ant-btn {
-    line-height: 1.5;
-    display: inline-block;
-    font-weight: 400;
-    text-align: center;
-    touch-action: manipulation;
-    cursor: pointer;
-    background-image: none;
-    border: 1px solid transparent;
-    white-space: nowrap;
-    padding: 0 15px;
-    font-size: 14px;
-    border-radius: 4px;
-    height: 32px;
-    user-select: none;
-    transition: all .3s cubic-bezier(.645, .045, .355, 1);
-    position: relative;
-    color: rgba(0, 0, 0, .65);
-    background-color: #fff;
-    border-color: #d9d9d9
-}
-
-.ant-btn>.anticon {
-    line-height: 1
-}
-
-.ant-btn,
-.ant-btn:active,
-.ant-btn:focus {
-    outline: 0
-}
-
-.ant-btn>a:only-child {
-    color: currentColor
-}
-
-.ant-btn>a:only-child:after {
-    content: "";
-    position: absolute;
-    top: 0;
-    left: 0;
-    bottom: 0;
-    right: 0;
-    background: transparent
-}
-
-.ant-btn:focus,
-.ant-btn:hover {
-    color: #40a9ff;
-    background-color: #fff;
-    border-color: #40a9ff
-}
-
-.ant-btn:focus>a:only-child,
-.ant-btn:hover>a:only-child {
-    color: currentColor
-}
-
-.ant-btn:focus>a:only-child:after,
-.ant-btn:hover>a:only-child:after {
-    content: "";
-    position: absolute;
-    top: 0;
-    left: 0;
-    bottom: 0;
-    right: 0;
-    background: transparent
-}
-
-.ant-btn.active,
-.ant-btn:active {
-    color: #096dd9;
-    background-color: #fff;
-    border-color: #096dd9
-}
-
-.ant-btn.active>a:only-child,
-.ant-btn:active>a:only-child {
-    color: currentColor
-}
-
-.ant-btn.active>a:only-child:after,
-.ant-btn:active>a:only-child:after {
-    content: "";
-    position: absolute;
-    top: 0;
-    left: 0;
-    bottom: 0;
-    right: 0;
-    background: transparent
-}
-
-.ant-btn.active,
-.ant-btn:active,
-.ant-btn:focus,
-.ant-btn:hover {
-    background: #fff;
-    text-decoration: none
-}
-
-.ant-btn>i,
-.ant-btn>span {
-    pointer-events: none
-}
-
-.ant-btn:before {
-    position: absolute;
-    top: -1px;
-    left: -1px;
-    bottom: -1px;
-    right: -1px;
-    background: #fff;
-    opacity: .35;
-    content: "";
-    border-radius: inherit;
-    z-index: 1;
-    transition: opacity .2s;
-    pointer-events: none;
-    display: none
-}
-
-.ant-btn .anticon {
-    transition: margin-left .3s cubic-bezier(.645, .045, .355, 1)
-}
-
-.ant-btn:active>span,
-.ant-btn:focus>span {
-    position: relative
-}
-
-.ant-btn>.anticon+span,
-.ant-btn>span+.anticon {
-    margin-left: 8px
-}
-
-.ant-input {
-    font-family: Chinese Quote, -apple-system, BlinkMacSystemFont, Segoe UI, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Helvetica Neue, Helvetica, Arial, sans-serif;
-    font-variant: tabular-nums;
-    box-sizing: border-box;
-    margin: 0;
-    padding: 0;
-    list-style: none;
-    position: relative;
-    display: inline-block;
-    padding: 4px 11px;
-    width: 100%;
-    height: 32px;
-    font-size: 14px;
-    line-height: 1.5;
-    color: rgba(0, 0, 0, .65);
-    background-color: #fff;
-    background-image: none;
-    border: 1px solid #d9d9d9;
-    border-radius: 4px;
-    transition: all .3s
-}
-
-.ant-input::-moz-placeholder {
-    color: #bfbfbf;
-    opacity: 1
-}
-
-.ant-input:-ms-input-placeholder {
-    color: #bfbfbf
-}
-
-.ant-input::-webkit-input-placeholder {
-    color: #bfbfbf
-}
-
-.ant-input:focus,
-.ant-input:hover {
-    border-color: #40a9ff;
-    border-right-width: 1px!important
-}
-
-.ant-input:focus {
-    outline: 0;
-    box-shadow: 0 0 0 2px rgba(24, 144, 255, .2)
-}
-
-textarea.ant-input {
-    max-width: 100%;
-    height: auto;
-    vertical-align: bottom;
-    transition: all .3s, height 0s;
-    min-height: 32px
-}
-
-a,
-abbr,
-acronym,
-address,
-applet,
-article,
-aside,
-audio,
-b,
-big,
-blockquote,
-body,
-canvas,
-caption,
-center,
-cite,
-code,
-dd,
-del,
-details,
-dfn,
-div,
-dl,
-dt,
-em,
-fieldset,
-figcaption,
-figure,
-footer,
-form,
-h1,
-h2,
-h3,
-h4,
-h5,
-h6,
-header,
-hgroup,
-html,
-i,
-iframe,
-img,
-ins,
-kbd,
-label,
-legend,
-li,
-mark,
-menu,
-nav,
-object,
-ol,
-p,
-pre,
-q,
-s,
-samp,
-section,
-small,
-span,
-strike,
-strong,
-sub,
-summary,
-sup,
-table,
-tbody,
-td,
-tfoot,
-th,
-thead,
-time,
-tr,
-tt,
-u,
-ul,
-var,
-video {
-    margin: 0;
-    padding: 0;
-    border: 0;
-    outline: 0;
-    font-size: 100%;
-    font: inherit;
-    vertical-align: baseline
-}
-
-*,
-:after,
-:before {
-    -webkit-box-sizing: border-box;
-    -moz-box-sizing: border-box;
-    box-sizing: border-box
-}
-
-html {
-    font-family: sans-serif;
-    -ms-text-size-adjust: 100%;
-    -webkit-text-size-adjust: 100%
-}
-
-body,
-html {
-    font-size: 14px
-}
-
-body {
-    font-family: Microsoft Yahei, Lucida Grande, Lucida Sans Unicode, Helvetica, Arial, Verdana, sans-serif;
-    line-height: 1.6;
-    background-color: #fff;
-    position: static!important;
-    -webkit-tap-highlight-color: rgba(0, 0, 0, 0)
-}
-
-ol,
-ul {
-    list-style-type: none
-}
-
-b,
-strong {
-    font-weight: 700
-}
-
-img {
-    border: 0
-}
-
-button,
-input,
-select,
-textarea {
-    font-family: inherit;
-    font-size: 100%;
-    margin: 0
-}
-
-textarea {
-    overflow: auto;
-    vertical-align: top;
-    -webkit-appearance: none
-}
-
-button,
-input {
-    line-height: normal
-}
-
-button,
-select {
-    text-transform: none
-}
-
-button,
-html input[type=button],
-input[type=reset],
-input[type=submit] {
-    -webkit-appearance: button;
-    cursor: pointer
-}
-
-input[type=search] {
-    -webkit-appearance: textfield;
-    -moz-box-sizing: content-box;
-    -webkit-box-sizing: content-box;
-    box-sizing: content-box
-}
-
-input[type=search]::-webkit-search-cancel-button,
-input[type=search]::-webkit-search-decoration {
-    -webkit-appearance: none
-}
-
-button::-moz-focus-inner,
-input::-moz-focus-inner {
-    border: 0;
-    padding: 0
-}
-
-table {
-    width: 100%;
-    border-spacing: 0;
-    border-collapse: collapse
-}
-
-table,
-td,
-th {
-    border: 0
-}
-
-td,
-th {
-    padding: 0;
-    vertical-align: top
-}
-
-th {
-    font-weight: 700;
-    text-align: left
-}
-
-thead th {
-    white-space: nowrap
-}
-
-a {
-    text-decoration: none;
-    cursor: pointer;
-    color: #3296fa
-}
-
-a:active,
-a:hover {
-    outline: 0;
-    color: #3296fa
-}
-
-small {
-    font-size: 80%
-}
-
-body,
-html {
-    font-size: 12px!important;
-    color: #191f25!important;
-    background: #f6f6f6!important
-}
-
-.wrap {
-    display: -webkit-box;
-    display: -ms-flexbox;
-    display: flex;
-    -webkit-box-orient: vertical;
-    -webkit-box-direction: normal;
-    -ms-flex-direction: column;
-    flex-direction: column;
-    height: 100%
-}
-
-/* @font-face {
-    font-family: IconFont;
-    src: url("//at.alicdn.com/t/font_135284_ph2thxxbzgf.eot");
-    src: url("//at.alicdn.com/t/font_135284_ph2thxxbzgf.eot?#iefix") format("embedded-opentype"), url("//at.alicdn.com/t/font_135284_ph2thxxbzgf.woff") format("woff"), url("//at.alicdn.com/t/font_135284_ph2thxxbzgf.ttf") format("truetype"), url("//at.alicdn.com/t/font_135284_ph2thxxbzgf.svg#IconFont") format("svg")
-}
-
-.iconfont {
-    font-family: IconFont!important;
-    font-size: 16px;
-    font-style: normal;
-    -webkit-font-smoothing: antialiased;
-    -webkit-text-stroke-width: .2px;
-    -moz-osx-font-smoothing: grayscale
-} */
-
-@font-face {
-    font-family: "iconfont"; /* Project id 4495938 */
-    src: url('iconfont.woff2?t=1712392083512') format('woff2'),
-        url('iconfont.woff?t=1712392083512') format('woff'),
-        url('iconfont.ttf?t=1712392083512') format('truetype');
-}
-  
-.iconfont {
-    font-family: "iconfont" !important;
-    font-size: 16px;
-    font-style: normal;
-    -webkit-font-smoothing: antialiased;
-    -moz-osx-font-smoothing: grayscale;
-}
-  
-.icon-Inclusive:before {
-    content: "\e602";
-}
-  
-.icon-copy:before {
-    content: "\e7eb";
-}
-  
-.icon-handle:before {
-    content: "\e61c";
-}
-  
-.icon-exclusive:before {
-    content: "\e717";
-}
-  
-.icon-approve:before {
-    content: "\e715";
-}
-  
-.icon-parallel:before {
-    content: "\e688";
-}
-
-.fd-nav {
-    position: fixed;
-    top: 0;
-    left: 0;
-    right: 0;
-    z-index: 997;
-    width: 100%;
-    height: 60px;
-    font-size: 14px;
-    color: #fff;
-    background: #3296fa;
-    display: flex;
-    align-items: center
-}
-
-.fd-nav>* {
-    flex: 1;
-    width: 100%
-}
-
-.fd-nav .fd-nav-left {
-    display: -webkit-box;
-    display: flex;
-    align-items: center
-}
-
-.fd-nav .fd-nav-center {
-    flex: none;
-    width: 600px;
-    text-align: center
-}
-
-.fd-nav .fd-nav-right {
-    display: flex;
-    align-items: center;
-    justify-content: flex-end;
-    text-align: right
-}
-
-.fd-nav .fd-nav-back {
-    display: inline-block;
-    width: 60px;
-    height: 60px;
-    font-size: 22px;
-    border-right: 1px solid #1583f2;
-    text-align: center;
-    cursor: pointer
-}
-
-.fd-nav .fd-nav-back:hover {
-    background: #5af
-}
-
-.fd-nav .fd-nav-back:active {
-    background: #1583f2
-}
-
-.fd-nav .fd-nav-back .anticon {
-    line-height: 60px
-}
-
-.fd-nav .fd-nav-title {
-    width: 0;
-    flex: 1;
-    overflow: hidden;
-    white-space: nowrap;
-    text-overflow: ellipsis;
-    padding: 0 15px
-}
-
-.fd-nav a {
-    color: #fff;
-    margin-left: 12px
-}
-
-.fd-nav .button-publish {
-    min-width: 80px;
-    margin-left: 4px;
-    margin-right: 15px;
-    color: #3296fa;
-    border-color: #fff
-}
-
-.fd-nav .button-publish.ant-btn:focus,
-.fd-nav .button-publish.ant-btn:hover {
-    color: #3296fa;
-    border-color: #fff;
-    box-shadow: 0 10px 20px 0 rgba(0, 0, 0, .3)
-}
-
-.fd-nav .button-publish.ant-btn:active {
-    color: #3296fa;
-    background: #d6eaff;
-    box-shadow: none
-}
-
-.fd-nav .button-preview {
-    min-width: 80px;
-    margin-left: 16px;
-    margin-right: 4px;
-    color: #fff;
-    border-color: #fff;
-    background: transparent
-}
-
-.fd-nav .button-preview.ant-btn:focus,
-.fd-nav .button-preview.ant-btn:hover {
-    color: #fff;
-    border-color: #fff;
-    background: #59acfc
-}
-
-.fd-nav .button-preview.ant-btn:active {
-    color: #fff;
-    border-color: #fff;
-    background: #2186ef
-}
-
-.fd-nav-content {
-    position: fixed;
-    top: 60px;
-    left: 0;
-    right: 0;
-    bottom: 0;
-    z-index: 1;
-    overflow-x: hidden;
-    overflow-y: auto;
-    padding-bottom: 30px
-}
-
-.error-modal-desc {
-    font-size: 13px;
-    color: rgba(25, 31, 37, .56);
-    line-height: 22px;
-    margin-bottom: 14px
-}
-
-.error-modal-list {
-    height: 200px;
-    overflow-y: auto;
-    margin-right: -25px;
-    padding-right: 25px
-}
-
-.error-modal-item {
-    padding: 10px 20px;
-    line-height: 21px;
-    background: #f6f6f6;
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-    margin-bottom: 8px;
-    border-radius: 4px
-}
-
-.error-modal-item-label {
-    flex: none;
-    font-size: 15px;
-    color: rgba(25, 31, 37, .56);
-    padding-right: 10px
-}
-
-.error-modal-item-content {
-    text-align: right;
-    flex: 1;
-    font-size: 13px;
-    color: #191f25
-}
-
-#body.blur {
-    -webkit-filter: blur(3px);
-    filter: blur(3px)
-}
-
-.zoom {
-    display: flex;
-    position: fixed;
-    -webkit-box-align: center;
-    -ms-flex-align: center;
-    align-items: center;
-    -webkit-box-pack: justify;
-    -ms-flex-pack: justify;
-    justify-content: space-between;
-    height: 40px;
-    width: 125px;
-    right: 40px;
-    margin-top: 30px;
-    z-index: 10
-}
-
-.zoom .zoom-in,
-.zoom .zoom-out {
-    width: 30px;
-    height: 30px;
-    background: #fff;
-    color: #c1c1cd;
-    cursor: pointer;
-    background-size: 100%;
-    background-repeat: no-repeat
-}
-
-.zoom .zoom-out {
-    background-image: url(https://gw.alicdn.com/tfs/TB1s0qhBHGYBuNjy0FoXXciBFXa-90-90.png)
-}
-
-.zoom .zoom-out.disabled {
-    opacity: .5
-}
-
-.zoom .zoom-in {
-    background-image: url(https://gw.alicdn.com/tfs/TB1UIgJBTtYBeNjy1XdXXXXyVXa-90-90.png)
-}
-
-.zoom .zoom-in.disabled {
-    opacity: .5
-}
-
-.auto-judge:hover .editable-title,
-.node-wrap-box:hover .editable-title {
-    border-bottom: 1px dashed #fff
-}
-
-.auto-judge:hover .editable-title.editing,
-.node-wrap-box:hover .editable-title.editing {
-    text-decoration: none;
-    border: 1px solid #d9d9d9
-}
-
-.auto-judge:hover .editable-title {
-    border-color: #15bc83
-}
-
-.editable-title {
-    line-height: 15px;
-    overflow: hidden;
-    white-space: nowrap;
-    text-overflow: ellipsis;
-    border-bottom: 1px dashed transparent
-}
-
-.editable-title:before {
-    content: "";
-    position: absolute;
-    top: 0;
-    left: 0;
-    bottom: 0;
-    right: 40px
-}
-
-.editable-title:hover {
-    border-bottom: 1px dashed #fff
-}
-
-.editable-title-input {
-    flex: none;
-    height: 18px;
-    padding-left: 4px;
-    text-indent: 0;
-    font-size: 12px;
-    line-height: 18px;
-    z-index: 1
-}
-
-.editable-title-input:hover {
-    text-decoration: none
-}
-
-.ant-btn {
-    position: relative
-}
-
-.node-wrap-box {
-    display: -webkit-inline-box;
-    display: -ms-inline-flexbox;
-    display: inline-flex;
-    -webkit-box-orient: vertical;
-    -webkit-box-direction: normal;
-    -ms-flex-direction: column;
-    flex-direction: column;
-    position: relative;
-    width: 220px;
-    min-height: 72px;
-    -ms-flex-negative: 0;
-    flex-shrink: 0;
-    background: #fff;
-    border-radius: 4px;
-    cursor: pointer
-}
-
-.node-wrap-box:after {
-    pointer-events: none;
-    content: "";
-    position: absolute;
-    top: 0;
-    bottom: 0;
-    left: 0;
-    right: 0;
-    z-index: 2;
-    border-radius: 4px;
-    border: 1px solid transparent;
-    transition: all .1s cubic-bezier(.645, .045, .355, 1);
-    box-shadow: 0 2px 5px 0 rgba(0, 0, 0, .1)
-}
-
-.node-wrap-box.active:after,
-.node-wrap-box:active:after,
-.node-wrap-box:hover:after {
-    border: 1px solid #3296fa;
-    box-shadow: 0 0 6px 0 rgba(50, 150, 250, .3)
-}
-
-.node-wrap-box.active .close,
-.node-wrap-box:active .close,
-.node-wrap-box:hover .close {
-    display: block
-}
-
-.node-wrap-box.error:after {
-    border: 1px solid #f25643;
-    box-shadow: 0 2px 5px 0 rgba(0, 0, 0, .1)
-}
-
-.node-wrap-box .title {
-    position: relative;
-    display: flex;
-    align-items: center;
-    padding-left: 16px;
-    padding-right: 30px;
-    width: 100%;
-    height: 24px;
-    line-height: 24px;
-    font-size: 12px;
-    color: #fff;
-    text-align: left;
-    background: #576a95;
-    border-radius: 4px 4px 0 0
-}
-
-.node-wrap-box .title .iconfont {
-    font-size: 12px;
-    margin-right: 5px
-}
-
-.node-wrap-box .placeholder {
-    color: #bfbfbf
-}
-
-.node-wrap-box .close {
-    display: none;
-    position: absolute;
-    right: 10px;
-    top: 50%;
-    transform: translateY(-50%);
-    width: 20px;
-    height: 20px;
-    font-size: 14px;
-    color: #fff;
-    border-radius: 50%;
-    text-align: center;
-    line-height: 20px
-}
-
-.node-wrap-box .content {
-    position: relative;
-    font-size: 14px;
-    padding: 16px;
-    padding-right: 30px
-}
-
-.node-wrap-box .content .text {
-    overflow: hidden;
-    text-overflow: ellipsis;
-    display: -webkit-box;
-    -webkit-line-clamp: 3;
-    -webkit-box-orient: vertical
-}
-
-.node-wrap-box .content .arrow {
-    position: absolute;
-    right: 10px;
-    top: 50%;
-    transform: translateY(-50%);
-    width: 20px;
-    height: 14px;
-    font-size: 14px;
-    color: #979797
-}
-
-.start-node.node-wrap-box .content .text {
-    display: block;
-    white-space: nowrap
-}
-
-.node-wrap-box:before {
-    content: "";
-    position: absolute;
-    top: -12px;
-    left: 50%;
-    -webkit-transform: translateX(-50%);
-    transform: translateX(-50%);
-    width: 0;
-    height: 4px;
-    border-style: solid;
-    border-width: 8px 6px 4px;
-    border-color: #cacaca transparent transparent;
-    background: #f5f5f7
-}
-
-.node-wrap-box.start-node:before {
-    content: none
-}
-
-.top-left-cover-line {
-    left: -1px
-}
-
-.top-left-cover-line,
-.top-right-cover-line {
-    position: absolute;
-    height: 8px;
-    width: 50%;
-    background-color: #f5f5f7;
-    top: -4px
-}
-
-.top-right-cover-line {
-    right: -1px
-}
-
-.bottom-left-cover-line {
-    left: -1px
-}
-
-.bottom-left-cover-line,
-.bottom-right-cover-line {
-    position: absolute;
-    height: 8px;
-    width: 50%;
-    background-color: #f5f5f7;
-    bottom: -4px
-}
-
-.bottom-right-cover-line {
-    right: -1px
-}
-
-.dingflow-design {
-    width: 100%;
-    background-color: #f5f5f7;
-    overflow: auto;
-    position: absolute;
-    bottom: 0;
-    left: 0;
-    right: 0;
-    top: 0
-}
-
-.dingflow-design .box-scale {
-    transform: scale(1);
-    display: inline-block;
-    position: relative;
-    width: 100%;
-    padding: 54.5px 0;
-    -webkit-box-align: start;
-    -ms-flex-align: start;
-    align-items: flex-start;
-    -webkit-box-pack: center;
-    -ms-flex-pack: center;
-    justify-content: center;
-    -ms-flex-wrap: wrap;
-    flex-wrap: wrap;
-    min-width: -webkit-min-content;
-    min-width: -moz-min-content;
-    min-width: min-content;
-    background-color: #f5f5f7;
-    transform-origin: 50% 0px 0px;
-}
-
-.dingflow-design .node-wrap {
-    flex-direction: column;
-    -webkit-box-pack: start;
-    -ms-flex-pack: start;
-    justify-content: flex-start;
-    -webkit-box-align: center;
-    -ms-flex-align: center;
-    align-items: center;
-    -ms-flex-wrap: wrap;
-    flex-wrap: wrap;
-    -webkit-box-flex: 1;
-    -ms-flex-positive: 1;
-    padding: 0 50px;
-    position: relative
-}
-
-.dingflow-design .branch-wrap,
-.dingflow-design .node-wrap {
-    display: inline-flex;
-    width: 100%
-}
-
-.dingflow-design .branch-box-wrap {
-    display: flex;
-    -webkit-box-orient: vertical;
-    -webkit-box-direction: normal;
-    -ms-flex-direction: column;
-    flex-direction: column;
-    -ms-flex-wrap: wrap;
-    flex-wrap: wrap;
-    -webkit-box-align: center;
-    -ms-flex-align: center;
-    align-items: center;
-    min-height: 270px;
-    width: 100%;
-    -ms-flex-negative: 0;
-    flex-shrink: 0
-}
-
-.dingflow-design .branch-box {
-    display: flex;
-    overflow: visible;
-    min-height: 180px;
-    height: auto;
-    border-bottom: 2px solid #ccc;
-    border-top: 2px solid #ccc;
-    position: relative;
-    margin-top: 15px
-}
-
-.dingflow-design .branch-box .col-box {
-    background: #f5f5f7
-}
-
-.dingflow-design .branch-box .col-box:before {
-    content: "";
-    position: absolute;
-    top: 0;
-    left: 0;
-    right: 0;
-    bottom: 0;
-    z-index: 0;
-    margin: auto;
-    width: 2px;
-    height: 100%;
-    background-color: #cacaca
-}
-
-.dingflow-design .add-branch {
-    border: none;
-    outline: none;
-    user-select: none;
-    justify-content: center;
-    font-size: 12px;
-    padding: 0 10px;
-    height: 30px;
-    line-height: 30px;
-    border-radius: 15px;
-    color: #3296fa;
-    background: #fff;
-    box-shadow: 0 2px 4px 0 rgba(0, 0, 0, .1);
-    position: absolute;
-    top: -16px;
-    left: 50%;
-    transform: translateX(-50%);
-    transform-origin: center center;
-    cursor: pointer;
-    z-index: 1;
-    display: inline-flex;
-    align-items: center;
-    -webkit-transition: all .3s cubic-bezier(.645, .045, .355, 1);
-    transition: all .3s cubic-bezier(.645, .045, .355, 1)
-}
-
-.dingflow-design .add-branch:hover {
-    transform: translateX(-50%) scale(1.1);
-    box-shadow: 0 8px 16px 0 rgba(0, 0, 0, .1)
-}
-
-.dingflow-design .add-branch:active {
-    transform: translateX(-50%);
-    box-shadow: none
-}
-
-.dingflow-design .col-box {
-    display: inline-flex;
-    -webkit-box-orient: vertical;
-    -webkit-box-direction: normal;
-    flex-direction: column;
-    -webkit-box-align: center;
-    align-items: center;
-    position: relative
-}
-
-.dingflow-design .condition-node {
-    min-height: 220px
-}
-
-.dingflow-design .condition-node,
-.dingflow-design .condition-node-box {
-    display: inline-flex;
-    -webkit-box-orient: vertical;
-    -webkit-box-direction: normal;
-    flex-direction: column;
-    -webkit-box-flex: 1
-}
-
-.dingflow-design .condition-node-box {
-    padding-top: 30px;
-    padding-right: 50px;
-    padding-left: 50px;
-    -webkit-box-pack: center;
-    justify-content: center;
-    -webkit-box-align: center;
-    align-items: center;
-    flex-grow: 1;
-    position: relative
-}
-
-.dingflow-design .condition-node-box:before {
-    content: "";
-    position: absolute;
-    top: 0;
-    left: 0;
-    right: 0;
-    bottom: 0;
-    margin: auto;
-    width: 2px;
-    height: 100%;
-    background-color: #cacaca
-}
-
-.dingflow-design .auto-judge {
-    position: relative;
-    width: 220px;
-    min-height: 72px;
-    background: #fff;
-    border-radius: 4px;
-    padding: 14px 19px;
-    cursor: pointer
-}
-
-.dingflow-design .auto-judge:after {
-    pointer-events: none;
-    content: "";
-    position: absolute;
-    top: 0;
-    bottom: 0;
-    left: 0;
-    right: 0;
-    z-index: 2;
-    border-radius: 4px;
-    border: 1px solid transparent;
-    transition: all .1s cubic-bezier(.645, .045, .355, 1);
-    box-shadow: 0 2px 5px 0 rgba(0, 0, 0, .1)
-}
-
-.dingflow-design .auto-judge.active:after,
-.dingflow-design .auto-judge:active:after,
-.dingflow-design .auto-judge:hover:after {
-    border: 1px solid #3296fa;
-    box-shadow: 0 0 6px 0 rgba(50, 150, 250, .3)
-}
-
-
-
-.dingflow-design .auto-judge.error:after {
-    border: 1px solid #f25643;
-    box-shadow: 0 2px 5px 0 rgba(0, 0, 0, .1)
-}
-
-/* .dingflow-design .auto-judge .title-wrapper {
-    position: relative;
-    font-size: 12px;
-    color: #15bc83;
-    text-align: left;
-    height: 24px;
-    line-height: 24px;
-    width: 258px;
-} */
-
-.dingflow-design  .title-wrapper {
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-    position: relative;
-    font-size: 12px;
-    border-radius: 4px 4px 0 0;
-    text-align: left;
-    height: 24px;
-    line-height: 24px;
-    width: 220px;
-    color: #fff;
-    padding-right: 10px;
-    padding-left: 10px;
-}
-
-.dingflow-design  .title-wrapper .editable-title {
-    max-width: 120px;
-    overflow: hidden;
-    white-space: nowrap;
-    text-overflow: ellipsis
-}
-
-.dingflow-design .title-wrapper .close {
-    display: none;
-    position: absolute;
-    right: 10px;
-    top: 2px;
-    width: 20px;
-    height: 20px;
-    font-size: 14px;
-    color:#fff;
-    border-radius: 50%;
-    text-align: center;
-    line-height: 20px;
-    z-index: 2
-}
-
-.dingflow-design .title-wrapper:hover .close {
-    display: block
-}
-/* .dingflow-design  .title-wrapper .close {
-    padding-right: 2px;
-} */
-
-/* .dingflow-design  .title-wrapper .priority-title {
-    display: inline-block;
-    float: right;
-    margin-right: 10px;
-    color: rgba(25, 31, 37, .56)
-} */
-
-/* .dingflow-design .auto-judge .title-wrapper .editable-title {
-    display: inline-block;
-    max-width: 120px;
-    overflow: hidden;
-    white-space: nowrap;
-    text-overflow: ellipsis
-}
-
-.dingflow-design .auto-judge .title-wrapper .priority-title {
-    display: inline-block;
-    float: right;
-    margin-right: 10px;
-    color: rgba(25, 31, 37, .56)
-} */
-
-.dingflow-design .auto-judge .placeholder {
-    color: #bfbfbf
-}
-
-.dingflow-design .auto-judge .content {
-    font-size: 14px;
-    color: #191f25;
-    text-align: left;
-    margin-top: 6px;
-    overflow: hidden;
-    text-overflow: ellipsis;
-    display: -webkit-box;
-    -webkit-line-clamp: 3;
-    -webkit-box-orient: vertical
-}
-
-.dingflow-design .auto-judge .sort-left,
-.dingflow-design .auto-judge .sort-right {
-    position: absolute;
-    top: 0;
-    bottom: 0;
-    display: none;
-    z-index: 1
-}
-
-.dingflow-design .auto-judge .sort-left {
-    left: 0;
-    border-right: 1px solid #f6f6f6
-}
-
-.dingflow-design .auto-judge .sort-right {
-    right: 0;
-    border-left: 1px solid #f6f6f6
-}
-
-.dingflow-design .auto-judge:hover .sort-left,
-.dingflow-design .auto-judge:hover .sort-right {
-    display: flex;
-    align-items: center
-}
-
-.dingflow-design .auto-judge .sort-left:hover,
-.dingflow-design .auto-judge .sort-right:hover {
-    background: #efefef
-}
-
-.dingflow-design .end-node {
-    border-radius: 50%;
-    font-size: 14px;
-    color: rgba(25, 31, 37, .4);
-    text-align: left
-}
-
-.dingflow-design .end-node .end-node-circle {
-    width: 10px;
-    height: 10px;
-    margin: auto;
-    border-radius: 50%;
-    background: #dbdcdc
-}
-
-.dingflow-design .end-node .end-node-text {
-    margin-top: 5px;
-    text-align: center
-}
-
-.approval-setting {
-    border-radius: 2px;
-    margin: 20px 0;
-    position: relative;
-    background: #fff
-}
-
-.ant-btn {
-    position: relative
-}
-
-

+ 2 - 2
src/components/SimpleProcessDesignerV2/src/SimpleProcessDesigner.vue

@@ -146,9 +146,9 @@ onMounted(async () => {
     processNodeTree.value = {
       name: '开始',
       type: NodeType.START_EVENT_NODE,
-      id: 'StartEvent_1', // TODO @jason:这个我们要不要 StartEvent 哈?
+      id: 'StartEvent', 
       childNode: {
-        id: 'EndEvent_1',
+        id: 'EndEvent',
         name: '结束',
         type: NodeType.END_EVENT_NODE
       }

+ 47 - 1
src/components/SimpleProcessDesignerV2/src/consts.ts

@@ -1,5 +1,6 @@
 // @ts-ignore
 import { DictDataVO } from '@/api/system/dict/types'
+
 /**
  * 节点类型
  */
@@ -85,13 +86,17 @@ export enum CandidateStrategy {
    */
   ROLE = 10,
   /**
-   * 指定部门成员
+   * 部门成员
    */
   DEPT_MEMBER = 20,
   /**
    * 部门的负责人
    */
   DEPT_LEADER = 21,
+  /**
+   * 连续多级部门的负责人
+   */
+  MULTI_LEVEL_DEPT_LEADER = 23,
   /**
    * 指定岗位
    */
@@ -108,6 +113,14 @@ export enum CandidateStrategy {
    * 发起人自己
    */
   START_USER = 36,
+  /**
+   * 发起人部门负责人
+   */
+  START_USER_DEPT_LEADER = 37,
+  /**
+   * 发起人连续多级部门的负责人
+   */
+  START_USER_MULTI_LEVEL_DEPT_LEADER = 38,
   /**
    * 指定用户组
    */
@@ -280,6 +293,21 @@ NODE_DEFAULT_NAME.set(NodeType.USER_TASK_NODE, '审批人')
 NODE_DEFAULT_NAME.set(NodeType.COPY_TASK_NODE, '抄送人')
 NODE_DEFAULT_NAME.set(NodeType.CONDITION_NODE, '条件')
 
+// 候选人策略。暂时不从字典中取。 后续可能调整。控制显示顺序
+export const CANDIDATE_STRATEGY: DictDataVO[] = [
+  { label: '指定成员', value: CandidateStrategy.USER },
+  { label: '指定角色', value: CandidateStrategy.ROLE },
+  { label: '部门成员', value: CandidateStrategy.DEPT_MEMBER },
+  { label: '部门负责人', value: CandidateStrategy.DEPT_LEADER },
+  { label: '连续多级部门负责人', value: CandidateStrategy.MULTI_LEVEL_DEPT_LEADER },
+  { label: '发起人自选', value: CandidateStrategy.START_USER_SELECT },
+  { label: '发起人本人', value: CandidateStrategy.START_USER },
+  { label: '发起人部门负责人', value: CandidateStrategy.START_USER_DEPT_LEADER },
+  { label: '发起人连续部门负责人', value: CandidateStrategy.START_USER_MULTI_LEVEL_DEPT_LEADER },
+  { label: '用户组', value: CandidateStrategy.USER_GROUP },
+  { label: '流程表达式', value: CandidateStrategy.EXPRESSION }
+]
+
 export const APPROVE_METHODS: DictDataVO[] = [
   { label: '随机挑选一人审批', value: ApproveMethodType.RRANDOM_SELECT_ONE_APPROVE },
   { label: '多人会签(按通过比例%)', value: ApproveMethodType.APPROVE_BY_RATIO },
@@ -355,3 +383,21 @@ export const DEFAULT_BUTTON_SETTING: ButtonSetting[] = [
   { id: OpsButtonType.ADD_SIGN, displayName: '加签', enable: false },
   { id: OpsButtonType.RETURN, displayName: '回退', enable: false }
 ]
+
+export const MULTI_LEVEL_DEPT: DictDataVO = [
+  { label: '第1级部门', value: 1 },
+  { label: '第2级部门', value: 2 },
+  { label: '第3级部门', value: 3 },
+  { label: '第4级部门', value: 4 },
+  { label: '第5级部门', value: 5 },
+  { label: '第6级部门', value: 6 },
+  { label: '第7级部门', value: 7 },
+  { label: '第8级部门', value: 8 },
+  { label: '第9级部门', value: 9 },
+  { label: '第10级部门', value: 10 },
+  { label: '第11级部门', value: 11 },
+  { label: '第12级部门', value: 12 },
+  { label: '第13级部门', value: 13 },
+  { label: '第14级部门', value: 14 },
+  { label: '第15级部门', value: 15 }
+]

+ 139 - 20
src/components/SimpleProcessDesignerV2/src/node.ts

@@ -89,9 +89,16 @@ export function useFormFieldsPermission() {
 }
 
 export type UserTaskFormType = {
-  candidateParamArray: any[]
+  //candidateParamArray: any[]
   candidateStrategy: CandidateStrategy
   approveMethod: ApproveMethodType
+  roleIds?: number[] // 角色
+  deptIds?: number[] // 部门
+  deptLevel?: number // 部门层级
+  userIds?: number[] // 用户
+  userGroups?: number[] // 用户组
+  postIds?: number[] // 岗位
+  expression?: string // 流程表达式
   approveRatio?: number
   rejectHandlerType?: RejectHandlerType
   returnNodeId?: string
@@ -103,8 +110,15 @@ export type UserTaskFormType = {
 }
 
 export type CopyTaskFormType = {
-  candidateParamArray: any[]
+  // candidateParamArray: any[]
   candidateStrategy: CandidateStrategy
+  roleIds?: number[] // 角色
+  deptIds?: number[] // 部门
+  deptLevel?: number // 部门层级
+  userIds?: number[] // 用户
+  userGroups?: number[] // 用户组
+  postIds?: number[] // 岗位
+  expression?: string // 流程表达式
 }
 
 /**
@@ -120,7 +134,7 @@ export function useNodeForm(nodeType: NodeType) {
   const configForm = ref<UserTaskFormType | CopyTaskFormType>()
   if (nodeType === NodeType.USER_TASK_NODE) {
     configForm.value = {
-      candidateParamArray: [],
+      //candidateParamArray: [],
       candidateStrategy: CandidateStrategy.USER,
       approveMethod: ApproveMethodType.RRANDOM_SELECT_ONE_APPROVE,
       approveRatio: 100,
@@ -134,7 +148,7 @@ export function useNodeForm(nodeType: NodeType) {
     }
   } else {
     configForm.value = {
-      candidateParamArray: [],
+      //candidateParamArray: [],
       candidateStrategy: CandidateStrategy.USER
     }
   }
@@ -143,10 +157,10 @@ export function useNodeForm(nodeType: NodeType) {
     let showText = ''
     // 指定成员
     if (configForm.value?.candidateStrategy === CandidateStrategy.USER) {
-      if (configForm.value.candidateParamArray?.length > 0) {
+      if (configForm.value?.userIds!.length > 0) {
         const candidateNames: string[] = []
         userOptions?.value.forEach((item) => {
-          if (configForm.value?.candidateParamArray.includes(item.id)) {
+          if (configForm.value?.userIds!.includes(item.id)) {
             candidateNames.push(item.nickname)
           }
         })
@@ -155,10 +169,10 @@ export function useNodeForm(nodeType: NodeType) {
     }
     // 指定角色
     if (configForm.value?.candidateStrategy === CandidateStrategy.ROLE) {
-      if (configForm.value.candidateParamArray?.length > 0) {
+      if (configForm.value.roleIds!.length > 0) {
         const candidateNames: string[] = []
         roleOptions?.value.forEach((item) => {
-          if (configForm.value?.candidateParamArray.includes(item.id)) {
+          if (configForm.value?.roleIds!.includes(item.id)) {
             candidateNames.push(item.name)
           }
         })
@@ -168,29 +182,32 @@ export function useNodeForm(nodeType: NodeType) {
     // 指定部门
     if (
       configForm.value?.candidateStrategy === CandidateStrategy.DEPT_MEMBER ||
-      configForm.value?.candidateStrategy === CandidateStrategy.DEPT_LEADER
+      configForm.value?.candidateStrategy === CandidateStrategy.DEPT_LEADER ||
+      configForm.value?.candidateStrategy === CandidateStrategy.MULTI_LEVEL_DEPT_LEADER
     ) {
-      if (configForm.value?.candidateParamArray?.length > 0) {
+      if (configForm.value?.deptIds!.length > 0) {
         const candidateNames: string[] = []
         deptOptions?.value.forEach((item) => {
-          if (configForm.value?.candidateParamArray.includes(item.id)) {
+          if (configForm.value?.deptIds!.includes(item.id!)) {
             candidateNames.push(item.name)
           }
         })
         if (configForm.value.candidateStrategy === CandidateStrategy.DEPT_MEMBER) {
           showText = `部门成员:${candidateNames.join(',')}`
-        } else {
+        } else if (configForm.value.candidateStrategy === CandidateStrategy.DEPT_LEADER) {
           showText = `部门的负责人:${candidateNames.join(',')}`
+        } else {
+          showText = `多级部门的负责人:${candidateNames.join(',')}`
         }
       }
     }
 
     // 指定岗位
     if (configForm.value?.candidateStrategy === CandidateStrategy.POST) {
-      if (configForm.value.candidateParamArray?.length > 0) {
+      if (configForm.value.postIds!.length > 0) {
         const candidateNames: string[] = []
         postOptions?.value.forEach((item) => {
-          if (configForm.value?.candidateParamArray.includes(item.id)) {
+          if (configForm.value?.postIds!.includes(item.id!)) {
             candidateNames.push(item.name)
           }
         })
@@ -199,10 +216,10 @@ export function useNodeForm(nodeType: NodeType) {
     }
     // 指定用户组
     if (configForm.value?.candidateStrategy === CandidateStrategy.USER_GROUP) {
-      if (configForm.value?.candidateParamArray?.length > 0) {
+      if (configForm.value?.userGroups!.length > 0) {
         const candidateNames: string[] = []
         userGroupOptions?.value.forEach((item) => {
-          if (configForm.value?.candidateParamArray.includes(item.id)) {
+          if (configForm.value?.userGroups!.includes(item.id)) {
             candidateNames.push(item.name)
           }
         })
@@ -218,16 +235,116 @@ export function useNodeForm(nodeType: NodeType) {
     if (configForm.value?.candidateStrategy === CandidateStrategy.START_USER) {
       showText = `发起人自己`
     }
-
+    // 发起人的部门负责人
+    if (configForm.value?.candidateStrategy === CandidateStrategy.START_USER_DEPT_LEADER) {
+      showText = `发起人的部门负责人`
+    }
+    // 发起人的部门负责人
+    if (
+      configForm.value?.candidateStrategy === CandidateStrategy.START_USER_MULTI_LEVEL_DEPT_LEADER
+    ) {
+      showText = `发起人连续部门负责人`
+    }
     // 流程表达式
     if (configForm.value?.candidateStrategy === CandidateStrategy.EXPRESSION) {
-      if (configForm.value.candidateParamArray?.length > 0) {
-        showText = `流程表达式:${configForm.value.candidateParamArray[0]}`
-      }
+      showText = `流程表达式:${configForm.value.expression}`
     }
     return showText
   }
 
+  /**
+   *  处理候选人参数的赋值
+   */
+  const handleCandidateParam = () => {
+    let candidateParam: undefined | string = undefined
+    if (!configForm.value) {
+      return candidateParam
+    }
+    switch (configForm.value.candidateStrategy) {
+      case CandidateStrategy.USER:
+        candidateParam = configForm.value.userIds!.join(',')
+        break
+      case CandidateStrategy.ROLE:
+        candidateParam = configForm.value.roleIds!.join(',')
+        break
+      case CandidateStrategy.POST:
+        candidateParam = configForm.value.postIds!.join(',')
+        break
+      case CandidateStrategy.USER_GROUP:
+        candidateParam = configForm.value.userGroups!.join(',')
+        break
+      case CandidateStrategy.EXPRESSION:
+        candidateParam = configForm.value.expression!
+        break
+      case CandidateStrategy.DEPT_MEMBER:
+      case CandidateStrategy.DEPT_LEADER:
+        candidateParam = configForm.value.deptIds!.join(',')
+        break
+      // 发起人部门负责人
+      case CandidateStrategy.START_USER_DEPT_LEADER:
+      case CandidateStrategy.START_USER_MULTI_LEVEL_DEPT_LEADER:
+        candidateParam = configForm.value.deptLevel + ''
+        break
+      // 指定连续多级部门的负责人
+      case CandidateStrategy.MULTI_LEVEL_DEPT_LEADER: {
+        // TODO 是否允许选多个部门
+        const deptIds = configForm.value.deptIds!.join(',')
+        candidateParam = deptIds.concat(',' + configForm.value.deptLevel + '')
+        break
+      }
+      default:
+        break
+    }
+    return candidateParam
+  }
+  /**
+   *  解析候选人参数
+   */
+  const parseCandidateParam = (
+    candidateStrategy: CandidateStrategy,
+    candidateParam: string | undefined
+  ) => {
+    if (!configForm.value || !candidateParam) {
+      return
+    }
+    switch (candidateStrategy) {
+      case CandidateStrategy.USER: {
+        configForm.value.userIds = candidateParam.split(',').map((item) => +item)
+        break
+      }
+      case CandidateStrategy.ROLE:
+        configForm.value.roleIds = candidateParam.split(',').map((item) => +item)
+        break
+      case CandidateStrategy.POST:
+        configForm.value.postIds = candidateParam.split(',').map((item) => +item)
+        break
+      case CandidateStrategy.USER_GROUP:
+        configForm.value.userGroups = candidateParam.split(',').map((item) => +item)
+        break
+      case CandidateStrategy.EXPRESSION:
+        configForm.value.expression = candidateParam
+        break
+      case CandidateStrategy.DEPT_MEMBER:
+      case CandidateStrategy.DEPT_LEADER:
+        configForm.value.deptIds = candidateParam.split(',').map((item) => +item)
+        break
+      // 发起人部门负责人
+      case CandidateStrategy.START_USER_DEPT_LEADER:
+      case CandidateStrategy.START_USER_MULTI_LEVEL_DEPT_LEADER:
+        configForm.value.deptLevel = +candidateParam
+        break
+      // 指定连续多级部门的负责人
+      case CandidateStrategy.MULTI_LEVEL_DEPT_LEADER: {
+        // 暂时只能选一个部门
+        const paramArray = candidateParam.split(',')
+        configForm.value.deptIds = [+paramArray[0]]
+        configForm.value.deptLevel = +paramArray[1]
+        break
+      }
+      default:
+        break
+    }
+  }
   return {
     configForm,
     roleOptions,
@@ -235,6 +352,8 @@ export function useNodeForm(nodeType: NodeType) {
     userOptions,
     userGroupOptions,
     deptTreeOptions,
+    handleCandidateParam,
+    parseCandidateParam,
     getShowText
   }
 }

+ 31 - 46
src/components/SimpleProcessDesignerV2/src/nodes-config/CopyTaskNodeConfig.vue

@@ -46,14 +46,9 @@
             <el-form-item
               v-if="configForm.candidateStrategy == CandidateStrategy.ROLE"
               label="指定角色"
-              prop="candidateParamArray"
+              prop="roleIds"
             >
-              <el-select
-                v-model="configForm.candidateParamArray"
-                clearable
-                multiple
-                style="width: 100%"
-              >
+              <el-select v-model="configForm.roleIds" clearable multiple style="width: 100%">
                 <el-option
                   v-for="item in roleOptions"
                   :key="item.id"
@@ -68,12 +63,12 @@
                 configForm.candidateStrategy == CandidateStrategy.DEPT_LEADER
               "
               label="指定部门"
-              prop="candidateParamArray"
+              prop="deptIds"
               span="24"
             >
               <el-tree-select
                 ref="treeRef"
-                v-model="configForm.candidateParamArray"
+                v-model="configForm.deptIds"
                 :data="deptTreeOptions"
                 :props="defaultProps"
                 empty-text="加载中,请稍后"
@@ -86,15 +81,10 @@
             <el-form-item
               v-if="configForm.candidateStrategy == CandidateStrategy.POST"
               label="指定岗位"
-              prop="candidateParamArray"
+              prop="postIds"
               span="24"
             >
-              <el-select
-                v-model="configForm.candidateParamArray"
-                clearable
-                multiple
-                style="width: 100%"
-              >
+              <el-select v-model="configForm.postIds" clearable multiple style="width: 100%">
                 <el-option
                   v-for="item in postOptions"
                   :key="item.id"
@@ -106,15 +96,10 @@
             <el-form-item
               v-if="configForm.candidateStrategy == CandidateStrategy.USER"
               label="指定用户"
-              prop="candidateParamArray"
+              prop="userIds"
               span="24"
             >
-              <el-select
-                v-model="configForm.candidateParamArray"
-                clearable
-                multiple
-                style="width: 100%"
-              >
+              <el-select v-model="configForm.userIds" clearable multiple style="width: 100%">
                 <el-option
                   v-for="item in userOptions"
                   :key="item.id"
@@ -126,14 +111,9 @@
             <el-form-item
               v-if="configForm.candidateStrategy === CandidateStrategy.USER_GROUP"
               label="指定用户组"
-              prop="candidateParamArray"
+              prop="userGroups"
             >
-              <el-select
-                v-model="configForm.candidateParamArray"
-                clearable
-                multiple
-                style="width: 100%"
-              >
+              <el-select v-model="configForm.userGroups" clearable multiple style="width: 100%">
                 <el-option
                   v-for="item in userGroupOptions"
                   :key="item.id"
@@ -146,11 +126,11 @@
             <el-form-item
               v-if="configForm.candidateStrategy === CandidateStrategy.EXPRESSION"
               label="流程表达式"
-              prop="candidateParamArray"
+              prop="expression"
             >
               <el-input
                 type="textarea"
-                v-model="configForm.candidateParamArray[0]"
+                v-model="configForm.expression"
                 clearable
                 style="width: 100%"
               />
@@ -200,7 +180,7 @@
   </el-drawer>
 </template>
 <script setup lang="ts">
-import { SimpleFlowNode, CandidateStrategy, NodeType } from '../consts'
+import { SimpleFlowNode, CandidateStrategy, NodeType, CANDIDATE_STRATEGY } from '../consts'
 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
 import {
   useWatchNode,
@@ -235,7 +215,12 @@ const formRef = ref() // 表单 Ref
 // 表单校验规则
 const formRules = reactive({
   candidateStrategy: [{ required: true, message: '抄送人设置不能为空', trigger: 'change' }],
-  candidateParamArray: [{ required: true, message: '选项不能为空', trigger: 'blur' }]
+  userIds: [{ required: true, message: '用户不能为空', trigger: 'change' }],
+  roleIds: [{ required: true, message: '角色不能为空', trigger: 'change' }],
+  deptIds: [{ required: true, message: '部门不能为空', trigger: 'change' }],
+  userGroups: [{ required: true, message: '用户组不能为空', trigger: 'change' }],
+  postIds: [{ required: true, message: '岗位不能为空', trigger: 'change' }],
+  expression: [{ required: true, message: '流程表达式不能为空', trigger: 'blur' }]
 })
 
 const {
@@ -245,12 +230,14 @@ const {
   userOptions,
   userGroupOptions,
   deptTreeOptions,
-  getShowText
+  getShowText,
+  handleCandidateParam,
+  parseCandidateParam
 } = useNodeForm(NodeType.COPY_TASK_NODE)
 const configForm = tempConfigForm as Ref<CopyTaskFormType>
 // 抄送人策略, 去掉发起人自选 和 发起人自己
 const copyUserStrategies = computed(() => {
-  return getIntDictOptions(DICT_TYPE.BPM_TASK_CANDIDATE_STRATEGY).filter(
+  return CANDIDATE_STRATEGY.filter(
     (item) =>
       item.value !== CandidateStrategy.START_USER_SELECT &&
       item.value !== CandidateStrategy.START_USER
@@ -258,7 +245,12 @@ const copyUserStrategies = computed(() => {
 })
 // 改变抄送人设置策略
 const changeCandidateStrategy = () => {
-  configForm.value.candidateParamArray = []
+  configForm.value.userIds = []
+  configForm.value.deptIds = []
+  configForm.value.roleIds = []
+  configForm.value.postIds = []
+  configForm.value.userGroups = []
+  configForm.value.deptLevel = 1
 }
 // 保存配置
 const saveConfig = async () => {
@@ -269,7 +261,7 @@ const saveConfig = async () => {
   const showText = getShowText()
   if (!showText) return false
   currentNode.value.name = nodeName.value!
-  currentNode.value.candidateParam = configForm.value.candidateParamArray?.join(',')
+  handleCandidateParam()
   currentNode.value.candidateStrategy = configForm.value.candidateStrategy
   currentNode.value.showText = showText
   currentNode.value.fieldsPermission = fieldsPermissionConfig.value
@@ -281,14 +273,7 @@ const showCopyTaskNodeConfig = (node: SimpleFlowNode) => {
   nodeName.value = node.name
   // 抄送人设置
   configForm.value.candidateStrategy = node.candidateStrategy!
-  const strCandidateParam = node?.candidateParam
-  if (node.candidateStrategy === CandidateStrategy.EXPRESSION) {
-    configForm.value.candidateParamArray[0] = strCandidateParam
-  } else {
-    if (strCandidateParam) {
-      configForm.value.candidateParamArray = strCandidateParam.split(',').map((item) => +item)
-    }
-  }
+  parseCandidateParam(node.candidateStrategy!, node?.candidateParam)
   // 表单字段权限
   getNodeConfigFormFields(node.fieldsPermission)
 }

+ 68 - 48
src/components/SimpleProcessDesignerV2/src/nodes-config/UserTaskNodeConfig.vue

@@ -34,7 +34,7 @@
                 @change="changeCandidateStrategy"
               >
                 <el-radio
-                  v-for="(dict, index) in getIntDictOptions(DICT_TYPE.BPM_TASK_CANDIDATE_STRATEGY)"
+                  v-for="(dict, index) in CANDIDATE_STRATEGY"
                   :key="index"
                   :value="dict.value"
                   :label="dict.value"
@@ -47,14 +47,9 @@
             <el-form-item
               v-if="configForm.candidateStrategy == CandidateStrategy.ROLE"
               label="指定角色"
-              prop="candidateParamArray"
+              prop="roleIds"
             >
-              <el-select
-                v-model="configForm.candidateParamArray"
-                clearable
-                multiple
-                style="width: 100%"
-              >
+              <el-select v-model="configForm.roleIds" clearable multiple style="width: 100%">
                 <el-option
                   v-for="item in roleOptions"
                   :key="item.id"
@@ -66,15 +61,16 @@
             <el-form-item
               v-if="
                 configForm.candidateStrategy == CandidateStrategy.DEPT_MEMBER ||
-                configForm.candidateStrategy == CandidateStrategy.DEPT_LEADER
+                configForm.candidateStrategy == CandidateStrategy.DEPT_LEADER ||
+                configForm.candidateStrategy == CandidateStrategy.MULTI_LEVEL_DEPT_LEADER
               "
               label="指定部门"
-              prop="candidateParamArray"
+              prop="deptIds"
               span="24"
             >
               <el-tree-select
                 ref="treeRef"
-                v-model="configForm.candidateParamArray"
+                v-model="configForm.deptIds"
                 :data="deptTreeOptions"
                 :props="defaultProps"
                 empty-text="加载中,请稍后"
@@ -84,18 +80,32 @@
                 show-checkbox
               />
             </el-form-item>
+            <el-form-item
+              v-if="
+                configForm.candidateStrategy == CandidateStrategy.MULTI_LEVEL_DEPT_LEADER ||
+                configForm.candidateStrategy == CandidateStrategy.START_USER_DEPT_LEADER ||
+                configForm.candidateStrategy == CandidateStrategy.START_USER_MULTI_LEVEL_DEPT_LEADER
+              "
+              :label="deptLevelLabel!"
+              prop="deptLevel"
+              span="24"
+            >
+              <el-select v-model="configForm.deptLevel" clearable>
+                <el-option
+                  v-for="(item, index) in MULTI_LEVEL_DEPT"
+                  :key="index"
+                  :label="item.label"
+                  :value="item.value"
+                />
+              </el-select>
+            </el-form-item>
             <el-form-item
               v-if="configForm.candidateStrategy == CandidateStrategy.POST"
               label="指定岗位"
-              prop="candidateParamArray"
+              prop="postIds"
               span="24"
             >
-              <el-select
-                v-model="configForm.candidateParamArray"
-                clearable
-                multiple
-                style="width: 100%"
-              >
+              <el-select v-model="configForm.postIds" clearable multiple style="width: 100%">
                 <el-option
                   v-for="item in postOptions"
                   :key="item.id"
@@ -107,11 +117,11 @@
             <el-form-item
               v-if="configForm.candidateStrategy == CandidateStrategy.USER"
               label="指定用户"
-              prop="candidateParamArray"
+              prop="userIds"
               span="24"
             >
               <el-select
-                v-model="configForm.candidateParamArray"
+                v-model="configForm.userIds"
                 clearable
                 multiple
                 style="width: 100%"
@@ -128,14 +138,9 @@
             <el-form-item
               v-if="configForm.candidateStrategy === CandidateStrategy.USER_GROUP"
               label="指定用户组"
-              prop="candidateParamArray"
+              prop="userGroups"
             >
-              <el-select
-                v-model="configForm.candidateParamArray"
-                clearable
-                multiple
-                style="width: 100%"
-              >
+              <el-select v-model="configForm.userGroups" clearable multiple style="width: 100%">
                 <el-option
                   v-for="item in userGroupOptions"
                   :key="item.id"
@@ -147,11 +152,11 @@
             <el-form-item
               v-if="configForm.candidateStrategy === CandidateStrategy.EXPRESSION"
               label="流程表达式"
-              prop="candidateParamArray"
+              prop="expression"
             >
               <el-input
                 type="textarea"
-                v-model="configForm.candidateParamArray[0]"
+                v-model="configForm.expression"
                 clearable
                 style="width: 100%"
               />
@@ -364,9 +369,11 @@ import {
   REJECT_HANDLER_TYPES,
   DEFAULT_BUTTON_SETTING,
   OPERATION_BUTTON_NAME,
-  ButtonSetting
+  ButtonSetting,
+  MULTI_LEVEL_DEPT,
+  CANDIDATE_STRATEGY
 } from '../consts'
-import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
+
 import {
   useWatchNode,
   useNodeName,
@@ -390,6 +397,15 @@ const props = defineProps({
 const emits = defineEmits<{
   'find:returnTaskNodes': [nodeList: SimpleFlowNode[]]
 }>()
+const deptLevelLabel = computed(() => {
+  let label = '部门负责人来源'
+  if (configForm.value.candidateStrategy == CandidateStrategy.MULTI_LEVEL_DEPT_LEADER) {
+    label = label + '(指定部门向上)'
+  } else {
+    label = label + '(发起人部门向上)'
+  }
+  return label
+})
 // 监控节点的变化
 const currentNode = useWatchNode(props)
 // 抽屉配置
@@ -409,7 +425,12 @@ const formRef = ref() // 表单 Ref
 // 表单校验规则
 const formRules = reactive({
   candidateStrategy: [{ required: true, message: '审批人设置不能为空', trigger: 'change' }],
-  candidateParamArray: [{ required: true, message: '该选项不能为空', trigger: 'change' }],
+  userIds: [{ required: true, message: '用户不能为空', trigger: 'change' }],
+  roleIds: [{ required: true, message: '角色不能为空', trigger: 'change' }],
+  deptIds: [{ required: true, message: '部门不能为空', trigger: 'change' }],
+  userGroups: [{ required: true, message: '用户组不能为空', trigger: 'change' }],
+  postIds: [{ required: true, message: '岗位不能为空', trigger: 'change' }],
+  expression: [{ required: true, message: '流程表达式不能为空', trigger: 'blur' }],
   approveMethod: [{ required: true, message: '多人审批方式不能为空', trigger: 'change' }],
   approveRatio: [{ required: true, message: '通过比例不能为空', trigger: 'blur' }],
   returnNodeId: [{ required: true, message: '驳回节点不能为空', trigger: 'change' }],
@@ -426,6 +447,8 @@ const {
   userOptions,
   userGroupOptions,
   deptTreeOptions,
+  handleCandidateParam,
+  parseCandidateParam,
   getShowText
 } = useNodeForm(NodeType.USER_TASK_NODE)
 const configForm = tempConfigForm as Ref<UserTaskFormType>
@@ -433,7 +456,12 @@ const configForm = tempConfigForm as Ref<UserTaskFormType>
 const notAllowedMultiApprovers = ref(false)
 // 改变审批人设置策略
 const changeCandidateStrategy = () => {
-  configForm.value.candidateParamArray = []
+  configForm.value.userIds = []
+  configForm.value.deptIds = []
+  configForm.value.roleIds = []
+  configForm.value.postIds = []
+  configForm.value.userGroups = []
+  configForm.value.deptLevel = 1
   configForm.value.approveMethod = ApproveMethodType.RRANDOM_SELECT_ONE_APPROVE
   if (
     configForm.value.candidateStrategy === CandidateStrategy.START_USER ||
@@ -447,7 +475,8 @@ const changeCandidateStrategy = () => {
 // 改变审批候选人
 const changedCandidateUsers = () => {
   if (
-    configForm.value.candidateParamArray?.length <= 1 &&
+    configForm.value.userIds &&
+    configForm.value.userIds?.length <= 1 &&
     configForm.value.candidateStrategy === CandidateStrategy.USER
   ) {
     configForm.value.approveMethod = ApproveMethodType.RRANDOM_SELECT_ONE_APPROVE
@@ -488,7 +517,8 @@ const saveConfig = async () => {
   if (!showText) return false
   currentNode.value.name = nodeName.value!
   currentNode.value.candidateStrategy = configForm.value.candidateStrategy
-  currentNode.value.candidateParam = configForm.value.candidateParamArray?.join(',')
+  // 处理 candidateParam 参数
+  currentNode.value.candidateParam = handleCandidateParam()
   // 设置审批方式
   currentNode.value.approveMethod = configForm.value.approveMethod
   if (configForm.value.approveMethod === ApproveMethodType.APPROVE_BY_RATIO) {
@@ -521,19 +551,9 @@ const showUserTaskNodeConfig = (node: SimpleFlowNode) => {
   nodeName.value = node.name
   //1.1 审批人设置
   configForm.value.candidateStrategy = node.candidateStrategy!
-  const strCandidateParam = node?.candidateParam
-  if (node.candidateStrategy === CandidateStrategy.EXPRESSION) {
-    configForm.value.candidateParamArray[0] = strCandidateParam
-  } else {
-    if (strCandidateParam) {
-      configForm.value.candidateParamArray = strCandidateParam.split(',').map((item) => +item)
-    }
-  }
-  if (
-    (configForm.value.candidateParamArray?.length <= 1 &&
-      node.candidateStrategy === CandidateStrategy.USER) ||
-    node.candidateStrategy === CandidateStrategy.START_USER
-  ) {
+  // 解析候选人参数
+  parseCandidateParam(node.candidateStrategy!, node?.candidateParam)
+  if (configForm.value.deptIds && configForm.value.deptIds.length > 1) {
     notAllowedMultiApprovers.value = true
   } else {
     notAllowedMultiApprovers.value = false