ruoyi-nbcio-plus基于vue3的flowable用户任务的升级修改

news2024/11/20 4:37:46

更多ruoyi-nbcio功能请看演示系统

gitee源代码地址

前后端代码: https://gitee.com/nbacheng/ruoyi-nbcio

演示地址:RuoYi-Nbcio后台管理系统 http://122.227.135.243:9666/

更多nbcio-boot功能请看演示系统 

gitee源代码地址

后端代码: https://gitee.com/nbacheng/nbcio-boot

前端代码:https://gitee.com/nbacheng/nbcio-vue.git

在线演示(包括H5) : http://122.227.135.243:9888

1、因为增加了一个dataType,所以要在flowableDescriptor.json下面增加dataType类型属性

"name": "Assignable",
      "extends": [ "bpmn:UserTask" ],
      "properties": [
        {
          "name": "dataType",
          "isAttr": true,
          "type": "String"
        },

2、同时增加了一个text,所以要在要在flowableDescriptor.json下面增加text类型属性

{
      "name": "Assignable",
      "extends": ["bpmn:UserTask"],
      "properties": [
        {
          "name": "dataType",
          "isAttr": true,
          "type": "String"
        },
        {
          "name": "assignee",
          "isAttr": true,
          "type": "String"
        },
        {
          "name": "candidateUsers",
          "isAttr": true,
          "type": "String"
        },
        {
          "name": "candidateGroups",
          "isAttr": true,
          "type": "String"
        },
	{
          "name": "text",
          "isAttr": true,
          "type": "String"
        },
        {
          "name": "dueDate",
          "isAttr": true,
          "type": "String"
        },
        {
          "name": "followUpDate",
          "isAttr": true,
          "type": "String"
        },
        {
          "name": "priority",
          "isAttr": true,
          "type": "String"
        }
      ]
    },

3、原先vue2代码如下:

<template>
  <div>
    <el-row>
      <h4><b>审批人设置</b></h4>
      <el-radio-group v-model="dataType" @change="changeDataType">
        <el-radio label="USERS">指定用户</el-radio>
        <el-radio label="ROLES">角色</el-radio>
        <el-radio label="DEPTS">部门</el-radio>
        <el-radio label="INITIATOR">发起人</el-radio>
        <el-radio label="MANAGER">部门经理</el-radio>
      </el-radio-group>
    </el-row>
    <el-row>
      <div v-if="dataType === 'USERS'">
        <el-tag v-for="userText in selectedUser.text" :key="userText" effect="plain">
          {{userText}}
        </el-tag>
        <div class="element-drawer__button">
          <el-button size="mini" type="primary" icon="el-icon-plus" @click="onSelectUsers()">添加用户</el-button>
        </div>
      </div>
      <div v-if="dataType === 'ROLES'">
        <el-select v-model="roleIds" multiple size="mini" placeholder="请选择 角色" @change="changeSelectRoles">
          <el-option
            v-for="item in roleOptions"
            :key="item.roleId"
            :label="item.roleName"
            :value="`ROLE${item.roleId}`"
            :disabled="item.status === 1">
          </el-option>
        </el-select>
      </div>
      <div v-if="dataType === 'DEPTS'">
        <tree-select
          :width="320"
          :height="400"
          size="mini"
          :data="deptTreeData"
          :defaultProps="deptProps"
          multiple
          clearable
          checkStrictly
          nodeKey="id"
          :checkedKeys="deptIds"
          @change="checkedDeptChange">
        </tree-select>
      </div>
    </el-row>
    <el-row>
      <div v-show="showMultiFlog">
        <el-divider />
        <h4><b>多实例审批方式</b></h4>
        <el-row>
          <el-radio-group v-model="multiLoopType" @change="changeMultiLoopType()">
            <el-row><el-radio label="Null">无</el-radio></el-row>
            <el-row><el-radio label="SequentialMultiInstance">会签(需所有审批人同意)</el-radio></el-row>
            <el-row><el-radio label="ParallelMultiInstance">或签(一名审批人同意即可)</el-radio></el-row>
            <el-row><el-radio label="CustomMultiInstance">自定义会签条件</el-radio></el-row>
          </el-radio-group>
        </el-row>
        <el-row v-if="multiLoopType === 'CustomMultiInstance'">
          <el-input v-model="CustomCompletionCondition" clearable @change="updateLoopCondition" />
        </el-row>
        <el-row v-if="multiLoopType !== 'Null'">
          <el-tooltip content="开启后,实例需按顺序轮流审批" placement="top-start" @click.stop.prevent>
            <i class="header-icon el-icon-info"></i>
          </el-tooltip>
          <span class="custom-label">顺序审批:</span>
          <el-switch v-model="isSequential" @change="changeMultiLoopType()" />
        </el-row>
      </div>
    </el-row>

    <!-- 候选用户弹窗 -->
    <el-dialog title="候选用户" :visible.sync="userOpen" width="60%" append-to-body>
      <el-row type="flex" :gutter="20">
        <!--部门数据-->
        <el-col :span="7">
          <el-card shadow="never" style="height: 100%">
            <div slot="header">
              <span>部门列表</span>
            </div>
            <div class="head-container">
              <el-input
                v-model="deptName"
                placeholder="请输入部门名称"
                clearable
                size="small"
                prefix-icon="el-icon-search"
                style="margin-bottom: 20px"
              />
              <el-tree
                :data="deptOptions"
                :props="deptProps"
                :expand-on-click-node="false"
                :filter-node-method="filterNode"
                ref="tree"
                default-expand-all
                @node-click="handleNodeClick"
              />
            </div>
          </el-card>
        </el-col>
        <el-col :span="17">
          <el-table ref="multipleTable" height="600" :data="userTableList" border @selection-change="handleSelectionChange">
            <el-table-column type="selection" width="50" align="center" />
            <el-table-column label="用户名" align="center" prop="nickName" />
            <el-table-column label="部门" align="center" prop="dept.deptName" />
          </el-table>
          <pagination
            :total="userTotal"
            :page.sync="queryParams.pageNum"
            :limit.sync="queryParams.pageSize"
            @pagination="getUserList"
          />
        </el-col>
      </el-row>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="handleTaskUserComplete">确 定</el-button>
        <el-button @click="userOpen = false">取 消</el-button>
      </div>
    </el-dialog>
  </div>

</template>

<script>
import { listUser, deptTreeSelect } from "@/api/system/user";
import { listRole } from "@/api/system/role";
import TreeSelect from "@/components/TreeSelect";

const userTaskForm = {
  dataType: '',
  assignee: '',
  candidateUsers: '',
  candidateGroups: '',
  text: '',
  // dueDate: '',
  // followUpDate: '',
  // priority: ''
}

export default {
  name: "UserTask",
  props: {
    id: String,
    type: String
  },
  components: { TreeSelect },
  data() {
    return {
      loading: false,
      dataType: 'USERS',
      selectedUser: {
        ids: [],
        text: []
      },
      userOpen: false,
      deptName: undefined,
      deptOptions: [],
      deptProps: {
        children: "children",
        label: "label"
      },
      deptTempOptions: [],
      userTableList: [],
      userTotal: 0,
      selectedUserDate: [],
      roleOptions: [],
      roleIds: [],
      deptTreeData: [],
      deptIds: [],
      // 查询参数
      queryParams: {
        deptId: undefined
      },
      showMultiFlog: false,
      isSequential: false,
      multiLoopType: 'Null',
      CustomCompletionCondition: '${nrOfCompletedInstances/nrOfInstances>=1}',
    };
  },
  watch: {
    id: {
      immediate: true,
      handler() {
        this.bpmnElement = window.bpmnInstances.bpmnElement;
        this.$nextTick(() => this.resetTaskForm());
      }
    },
    // 根据名称筛选部门树
    deptName(val) {
      this.$refs.tree.filter(val);
    }
  },
  methods: {
    resetTaskForm() {
      const bpmnElementObj = this.bpmnElement?.businessObject;
      console.log("resetTaskForm bpmnElementObj",bpmnElementObj)
      if (!bpmnElementObj) {
        return;
      }
      this.clearOptionsData()
      this.dataType = bpmnElementObj['dataType'];
      console.log("resetTaskForm this.dataType",this.dataType)
      if (this.dataType === 'USERS') {
        let userIdData = bpmnElementObj['candidateUsers'] || bpmnElementObj['assignee'];
        let userText = bpmnElementObj['text'] || [];
        if (userIdData && userIdData.toString().length > 0 && userText && userText.length > 0) {
          this.selectedUser.ids = userIdData?.toString().split(',');
          this.selectedUser.text = userText?.split(',');
        }
        if (this.selectedUser.ids.length > 1) {
          this.showMultiFlog = true;
        }
      } else if (this.dataType === 'ROLES') {
        this.getRoleOptions();
        let roleIdData = bpmnElementObj['candidateGroups'] || [];
        if (roleIdData && roleIdData.length > 0) {
          this.roleIds = roleIdData.split(',')
        }
        this.showMultiFlog = true;
      } else if (this.dataType === 'DEPTS') {
        this.getDeptTreeData();
        let deptIdData = bpmnElementObj['candidateGroups'] || [];
        if (deptIdData && deptIdData.length > 0) {
          this.deptIds = deptIdData.split(',');
        }
        this.showMultiFlog = true;
      }
      this.getElementLoop(bpmnElementObj);
    },
    /**
     * 清空选项数据
     */
    clearOptionsData() {
      this.selectedUser.ids = [];
      this.selectedUser.text = [];
      this.roleIds = [];
      this.deptIds = [];
    },
    // 完成条件
    updateLoopCondition(condition) {
    },
    /**
     * 更新节点数据
     */
    updateElementTask() {
      const taskAttr = Object.create(null);
      for (let key in userTaskForm) {
          taskAttr[key] = userTaskForm[key];
      }
      console.log("updateElementTask taskAttr",taskAttr)
      window.bpmnInstances.modeling.updateProperties(this.bpmnElement, taskAttr);
    },
    /**
     * 查询部门下拉树结构
     */
    getDeptOptions() {
      return new Promise((resolve, reject) => {
        if (!this.deptOptions || this.deptOptions.length <= 0) {
          deptTreeSelect().then(response => {
            this.deptTempOptions = response.data;
            this.deptOptions = response.data;
            resolve()
          })
        } else {
          reject()
        }
      });
    },
    /**
     * 查询部门下拉树结构(含部门前缀)
     */
    getDeptTreeData() {
      function refactorTree(data) {
        return data.map(node => {
          let treeData = { id: `DEPT${node.id}`, label: node.label, parentId: node.parentId, weight: node.weight };
          if (node.children && node.children.length > 0) {
            treeData.children = refactorTree(node.children);
          }
          return treeData;
        });
      }
      return new Promise((resolve, reject) => {
        if (!this.deptTreeData || this.deptTreeData.length <= 0) {
          this.getDeptOptions().then(() => {
            this.deptTreeData = refactorTree(this.deptOptions);
            resolve()
          }).catch(() => {
            reject()
          })
        } else {
          resolve()
        }
      })
    },
    /**
     * 查询部门下拉树结构
     */
    getRoleOptions() {
      if (!this.roleOptions || this.roleOptions.length <= 0) {
        listRole().then(response => this.roleOptions = response.rows);
      }
    },
    /** 查询用户列表 */
    getUserList() {
      listUser(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
        this.userTableList = response.rows;
        this.userTotal = response.total;
      });
    },
    // 筛选节点
    filterNode(value, data) {
      if (!value) return true;
      return data.label.indexOf(value) !== -1;
    },
    // 节点单击事件
    handleNodeClick(data) {
      this.queryParams.deptId = data.id;
      this.getUserList();
    },
    // 关闭标签
    handleClose(tag) {
      this.selectedUserDate.splice(this.selectedUserDate.indexOf(tag), 1);
      this.$refs.multipleTable.toggleRowSelection(tag);
    },
    // 多选框选中数据
    handleSelectionChange(selection) {
      this.selectedUserDate = selection;
    },
    onSelectUsers() {
      this.selectedUserDate = []
      this.$refs.multipleTable?.clearSelection();
      this.getDeptOptions();
      this.userOpen = true;
    },
    handleTaskUserComplete() {
      if (!this.selectedUserDate || this.selectedUserDate.length <= 0) {
        this.$modal.msgError('请选择用户');
        return;
      }
      userTaskForm.dataType = 'USERS';
      this.selectedUser.text = this.selectedUserDate.map(k => k.nickName) || [];
      if (this.selectedUserDate.length === 1) {
        let data = this.selectedUserDate[0];
        userTaskForm.assignee = data.userName;
        userTaskForm.text = data.nickName;
        userTaskForm.candidateUsers = null;
        this.showMultiFlog = false;
        this.multiLoopType = 'Null';
        this.changeMultiLoopType();
      } else {
        userTaskForm.candidateUsers = this.selectedUserDate.map(k => k.userName).join() || null;
        userTaskForm.text = this.selectedUserDate.map(k => k.nickName).join() || null;
        userTaskForm.assignee = null;
        this.showMultiFlog = true;
      }
      this.updateElementTask()
      this.userOpen = false;
    },
    changeSelectRoles(val) {
      let groups = null;
      let text = null;
      if (val && val.length > 0) {
        userTaskForm.dataType = 'ROLES';
        groups = val.join() || null;
        let textArr = this.roleOptions.filter(k => val.indexOf(`ROLE${k.roleId}`) >= 0);
        text = textArr?.map(k => k.roleName).join() || null;
      } else {
        userTaskForm.dataType = null;
        this.multiLoopType = 'Null';
      }
      userTaskForm.candidateGroups = groups;
      userTaskForm.text = text;
      this.updateElementTask();
      this.changeMultiLoopType();
    },
    checkedDeptChange(checkedIds) {
      let groups = null;
      let text = null;
      this.deptIds = checkedIds;
      if (checkedIds && checkedIds.length > 0) {
        userTaskForm.dataType = 'DEPTS';
        groups = checkedIds.join() || null;
        let textArr = []
        let treeStarkData = JSON.parse(JSON.stringify(this.deptTreeData));
        checkedIds.forEach(id => {
          let stark = []
          stark = stark.concat(treeStarkData);
          while(stark.length) {
            let temp = stark.shift();
            if(temp.children) {
              stark = temp.children.concat(stark);
            }
            if(id === temp.id) {
              textArr.push(temp);
            }
          }
        })
        text = textArr?.map(k => k.label).join() || null;
      } else {
        userTaskForm.dataType = null;
        this.multiLoopType = 'Null';
      }
      userTaskForm.candidateGroups = groups;
      userTaskForm.text = text;
      this.updateElementTask();
      this.changeMultiLoopType();
    },
    changeDataType(val) {
      if (val === 'ROLES' || val === 'DEPTS' || (val === 'USERS' && this.selectedUser.ids.length > 1)) {
        this.showMultiFlog = true;
      } else {
        this.showMultiFlog = false;
      }
      this.multiLoopType = 'Null';
      this.changeMultiLoopType();
      // 清空 userTaskForm 所有属性值
      Object.keys(userTaskForm).forEach(key => userTaskForm[key] = null);
      userTaskForm.dataType = val;
      console.log("changeDataType this.selectedUser",this.selectedUser);
      console.log("changeDataType val",val);
      if (val === 'USERS') {
        if (this.selectedUser && this.selectedUser.ids && this.selectedUser.ids.length > 0) {
          if (this.selectedUser.ids.length === 1) {
            userTaskForm.assignee = this.selectedUser.ids[0];
          } else {
            userTaskForm.candidateUsers = this.selectedUser.ids.join()
          }
          userTaskForm.text = this.selectedUser.text?.join() || null
        }
      } else if (val === 'ROLES') {
        this.getRoleOptions();
        if (this.roleIds && this.roleIds.length > 0) {
          userTaskForm.candidateGroups = this.roleIds.join() || null;
          let textArr = this.roleOptions.filter(k => this.roleIds.indexOf(`ROLE${k.roleId}`) >= 0);
          userTaskForm.text = textArr?.map(k => k.roleName).join() || null;
        }
      } else if (val === 'DEPTS') {
        this.getDeptTreeData();
        if (this.deptIds && this.deptIds.length > 0) {
          userTaskForm.candidateGroups = this.deptIds.join() || null;
          let textArr = []
          let treeStarkData = JSON.parse(JSON.stringify(this.deptTreeData));
          this.deptIds.forEach(id => {
            let stark = []
            stark = stark.concat(treeStarkData);
            while(stark.length) {
              let temp = stark.shift();
              if(temp.children) {
                stark = temp.children.concat(stark);
              }
              if(id === temp.id) {
                textArr.push(temp);
              }
            }
          })
          userTaskForm.text = textArr?.map(k => k.label).join() || null;
        }
      } else if (val === 'MANAGER') {
        userTaskForm.assignee = "${DepManagerHandler.getUser(execution)}";
        userTaskForm.text = "部门经理";

      } else if (val === 'INITIATOR') {
        userTaskForm.assignee = "${initiator}";
        userTaskForm.text = "流程发起人";
      }
      this.updateElementTask();
    },
    getElementLoop(businessObject) {
      if (!businessObject.loopCharacteristics) {
        this.multiLoopType = "Null";
        return;
      }
      this.isSequential = businessObject.loopCharacteristics.isSequential;
      if (businessObject.loopCharacteristics.completionCondition) {
        if (businessObject.loopCharacteristics.completionCondition.body === "${nrOfCompletedInstances >= nrOfInstances}") {
          this.multiLoopType = "SequentialMultiInstance";
        } else if (businessObject.loopCharacteristics.completionCondition.body === "${nrOfCompletedInstances > 0}") {
          this.multiLoopType = "ParallelMultiInstance";
        } else {
          this.multiLoopType = "CustomMultiInstance";
        }
      }
    },
    changeMultiLoopType() {
      // 取消多实例配置
      if (this.multiLoopType === "Null") {
        window.bpmnInstances.modeling.updateProperties(this.bpmnElement, { loopCharacteristics: null, assignee: null });
        return;
      }
      this.multiLoopInstance = window.bpmnInstances.moddle.create("bpmn:MultiInstanceLoopCharacteristics", { isSequential: this.isSequential });
      // 更新多实例配置
      window.bpmnInstances.modeling.updateProperties(this.bpmnElement, {
        loopCharacteristics: this.multiLoopInstance,
        assignee: '${assignee}'
      });
      // 完成条件
      let completionCondition = null;
      // 会签
      if (this.multiLoopType === "SequentialMultiInstance") {
        completionCondition = window.bpmnInstances.moddle.create("bpmn:FormalExpression", { body: "${nrOfCompletedInstances >= nrOfInstances}" });
      }
      // 或签
      if (this.multiLoopType === "ParallelMultiInstance") {
        completionCondition = window.bpmnInstances.moddle.create("bpmn:FormalExpression", { body: "${nrOfCompletedInstances > 0}" });
      }
      // 自定义会签
      if (this.multiLoopType === "CustomMultiInstance") {
        completionCondition = window.bpmnInstances.moddle.create("bpmn:FormalExpression", { body: this.CustomCompletionCondition });
      }
      // 更新模块属性信息
      window.bpmnInstances.modeling.updateModdleProperties(this.bpmnElement, this.multiLoopInstance, {
        collection: '${multiInstanceHandler.getUserNames(execution)}',
        elementVariable: 'assignee',
        completionCondition
      });
    },
  },
  beforeUnmount() {
    this.bpmnElement = null;
  }
};
</script>

<style scoped lang="scss">
.el-row .el-radio-group {
  margin-bottom: 15px;
  .el-radio {
    line-height: 28px;
  }
}
.el-tag {
  margin-bottom: 10px;
  + .el-tag {
    margin-left: 10px;
  }
}

.custom-label {
  padding-left: 5px;
  font-weight: 500;
  font-size: 14px;
  color: #606266;
}

</style>

3、修改成vue3代码如下:

<template>
  <div>
    <el-row>
      <h4><b>审批人设置</b></h4>
      <el-radio-group v-model="dataType" @change="changeDataType">
        <el-radio label="USERS">指定用户</el-radio>
        <el-radio label="ROLES">角色</el-radio>
        <el-radio label="DEPTS">部门</el-radio>
        <el-radio label="INITIATOR">发起人</el-radio>
        <el-radio label="MANAGER">部门经理</el-radio>
      </el-radio-group>
    </el-row>
    <el-row>
      <div v-if="dataType === 'USERS'">
        <el-tag v-for="userText in selectedUser.text" :key="userText" effect="plain">
          {{userText}}
        </el-tag>
        <div class="element-drawer__button">
          <el-button size="small" type="primary" icon="el-icon-plus" @click="onSelectUsers()">添加用户</el-button>
        </div>
      </div>
      <div v-if="dataType === 'ROLES'">
        <el-select v-model="roleIds" multiple size="small" placeholder="请选择 角色" @change="changeSelectRoles">
          <el-option
            v-for="item in roleOptions"
            :key="item.roleId"
            :label="item.roleName"
            :value="`ROLE${item.roleId}`"
            :disabled="item.status === 1">
          </el-option>
        </el-select>
      </div>
      <div v-if="dataType === 'DEPTS'">
        <tree-select
          :width="320"
          :height="400"
          size="small"
          :data="deptTreeData"
          :props="deptProps"
          multiple
          clearable
          checkStrictly
          nodeKey="id"
          :checkedKeys="deptIds"
          @change="checkedDeptChange">
        </tree-select>
      </div>
    </el-row>
    <el-row>
      <div v-show="showMultiFlog">
        <el-divider />
        <h4><b>多实例审批方式</b></h4>
        <el-row>
          <el-radio-group v-model="multiLoopType" @change="changeMultiLoopType()">
            <el-row><el-radio label="Null">无</el-radio></el-row>
            <el-row><el-radio label="SequentialMultiInstance">会签(需所有审批人同意)</el-radio></el-row>
            <el-row><el-radio label="ParallelMultiInstance">或签(一名审批人同意即可)</el-radio></el-row>
            <el-row><el-radio label="CustomMultiInstance">自定义会签条件</el-radio></el-row>
          </el-radio-group>
        </el-row>
        <el-row v-if="multiLoopType === 'CustomMultiInstance'">
          <el-input v-model="CustomCompletionCondition" clearable @change="updateLoopCondition" />
        </el-row>
        <el-row v-if="multiLoopType !== 'Null'">
          <el-tooltip content="开启后,实例需按顺序轮流审批" placement="top-start" @click.stop.prevent>
            <i class="header-icon el-icon-info"></i>
          </el-tooltip>
          <span class="custom-label">顺序审批:</span>
          <el-switch v-model="isSequential" @change="changeMultiLoopType()" />
        </el-row>
      </div>
    </el-row>

    <!-- 候选用户弹窗 -->
    <el-dialog title="候选用户" v-model="userOpen" width="60%" append-to-body>
      <el-row type="flex" :gutter="20">
        <!--部门数据-->
        <el-col :span="7">
          <el-card shadow="never" style="height: 100%">
            <template #header>
              <span>部门列表</span>
            </template>
            <div class="head-container">
              <el-input
                v-model="deptName"
                placeholder="请输入部门名称"
                clearable
                size="small"
                prefix-icon="el-icon-search"
                style="margin-bottom: 20px"
              />
              <el-tree
                :data="deptOptions"
                :props="deptProps"
                :expand-on-click-node="false"
                :filter-node-method="filterNode"
                ref="tree"
                default-expand-all
                @node-click="handleNodeClick"
              />
            </div>
          </el-card>
        </el-col>
        <el-col :span="17">
          <el-table ref="multipleTable" height="600" :data="userTableList" border @selection-change="handleSelectionChange">
            <el-table-column type="selection" width="50" align="center" />
            <el-table-column label="用户名" align="center" prop="nickName" />
            <el-table-column label="部门" align="center" prop="dept.deptName" />
          </el-table>
          <pagination
            :total="userTotal"
            :page.sync="queryParams.pageNum"
            :limit.sync="queryParams.pageSize"
            @pagination="getUserList"
          />
        </el-col>
      </el-row>
      <template #footer class="dialog-footer">
        <el-button type="primary" @click="handleTaskUserComplete">确 定</el-button>
        <el-button @click="userOpen = false">取 消</el-button>
      </template>
    </el-dialog>
  </div>

</template>

<script lang="ts" setup>
  import { listUser, deptTreeSelect } from "@/api/system/user";
  import { listRole } from "@/api/system/role";

  defineOptions({ name: 'UserTask' })
  const props = defineProps({
    id: String,
    type: String
  })

  const userTaskForm = ref({
    dataType: '',
    assignee: '',
    candidateUsers: '',
    candidateGroups: '',
    text: '',
    // dueDate: '',
    // followUpDate: '',
    // priority: ''
  })

  const { proxy } = getCurrentInstance() as ComponentInternalInstance
  const bpmnElement = ref()
  const bpmnInstances = () => (window as any)?.bpmnInstances

  const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
  const loading = ref(false)
  const dataType = ref('USERS')
  const selectedUser = ref({
    ids: [],
    text: []
  })
  const userOpen = ref(false)
  const deptName = ref(undefined)
  const deptOptions = ref<any[]>([])
  const deptProps = ref({
    label: "label",
    children: "children"
  })
  const deptTempOptions = ref<any[]>([])
  const userTableList = ref<any[]>([])
  const userTotal = ref(0)
  const selectedUserDate = ref<any[]>([])
  const roleOptions = ref<any[]>([])
  const roleIds = ref<any[]>([])
  const deptTreeData = ref<any[]>([])
  const deptIds = ref<any[]>([])
  // 查询参数
  const queryParams = ref({
    pageNum: 1,
    pageSize: 10,
    deptId: ''
  })
  const showMultiFlog = ref(false)
  const isSequential = ref(false)
  const multiLoopType = ref('Null')
  const CustomCompletionCondition = ref('${nrOfCompletedInstances/nrOfInstances>=1}')

  const multipleTable = ref(null)
  const tree = ref(null)

  const resetTaskForm = () => {
    bpmnElement.value = bpmnInstances().bpmnElement
    const bpmnElementObj = toRaw(bpmnElement.value?.businessObject);
    console.log("resetTaskForm bpmnElementObj",bpmnElementObj)
    if (!bpmnElementObj) {
      return;
    }
    clearOptionsData()
    dataType.value = bpmnElementObj['dataType'];
    console.log("resetTaskForm dataType",dataType)
    console.log("resetTaskForm bpmnElementObj",bpmnElementObj)
    if (dataType.value === 'USERS') {
      let userIdData = bpmnElementObj['candidateUsers'] || bpmnElementObj['assignee'];
      console.log("resetTaskForm userIdData",userIdData)
      let userText = bpmnElementObj['text'] || [];
      console.log("resetTaskForm userText",userText)
      if (userIdData && userIdData.toString().length > 0 && userText && userText.length > 0) {
        selectedUser.value.ids = userIdData?.toString().split(',');
        selectedUser.value.text = userText?.split(',');
      }
      if (selectedUser.value.ids.length > 1) {
        showMultiFlog.value = true;
      }
    } else if (dataType.value === 'ROLES') {
      getRoleOptions();
      let roleIdData = bpmnElementObj['candidateGroups'] || [];
      if (roleIdData && roleIdData.length > 0) {
        roleIds.value = roleIdData.split(',')
      }
      showMultiFlog.value = true;
    } else if (dataType.value === 'DEPTS') {
      getDeptTreeData();
      let deptIdData = bpmnElementObj['candidateGroups'] || [];
      if (deptIdData && deptIdData.length > 0) {
        deptIds.value = deptIdData.split(',');
      }
      showMultiFlog.value = true;
    }
    getElementLoop(bpmnElementObj);
  }
  /**
    * 清空选项数据
    */
  const clearOptionsData = () => {
    selectedUser.value.ids = [];
    selectedUser.value.text = [];
    roleIds.value = [];
    deptIds.value = [];
  }
  // 完成条件
  const updateLoopCondition = (condition) => {

  }
  /**
    * 更新节点数据
    */
  const updateElementTask = () => {
    const taskAttr = Object.create(null);
    for (let key in userTaskForm.value) {
        taskAttr[key] = userTaskForm.value[key] || null;
    }
    console.log("updateElementTask taskAttr",taskAttr)
    bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), taskAttr)
  }
  /**
    * 查询部门下拉树结构
    */
  const getDeptOptions = () => {
    return new Promise((resolve, reject) => {
      if (!deptOptions.value || deptOptions.value.length <= 0) {
        deptTreeSelect().then(response => {
          deptTempOptions.value = response.data;
          deptOptions.value = response.data;
          resolve()
        })
      } else {
        reject()
      }
    });
  }

  /**
    * 查询部门下拉树结构(含部门前缀)
    */
  const getDeptTreeData = () => {
    return new Promise((resolve, reject) => {
      if (!deptTreeData.value || deptTreeData.value.length <= 0) {
        getDeptOptions().then(() => {
          deptTreeData.value = refactorTree(deptOptions.value);
          console.log("getDeptTreeData deptTreeData.value",deptTreeData.value)
          resolve()
        }).catch(() => {
          reject()
        })
      } else {
        resolve()
      }
    })
  }

  const  refactorTree = (data) => {
    return data.map(node => {
      let treeData = { id: `DEPT${node.id}`, label: node.label, parentId: node.parentId, weight: node.weight };
      if (node.children && node.children.length > 0) {
        treeData.children = refactorTree(node.children);
      }
      return treeData;
    });
  }

  /**
    * 查询部门下拉树结构
    */
  const  getRoleOptions = () => {
    if (!roleOptions.value || roleOptions.value.length <= 0) {
      listRole().then(response => roleOptions.value = response.rows);
    }
  }
  /** 查询用户列表 */
  const  getUserList = () => {
      listUser(proxy?.addDateRange(queryParams.value, dateRange.value)).then(response => {
        userTableList.value = response.rows;
        userTotal.value = response.total;
      });
  }
  // 筛选节点
  const  filterNode = (value, data) => {
      if (!value) return true;
      return data.label.indexOf(value) !== -1;
  }
  // 节点单击事件
  const  handleNodeClick = (data) => {
      queryParams.value.deptId = data.id;
      getUserList();
  }
  // 关闭标签
  const  handleClose = (tag) => {
      selectedUserDate.value.splice(selectedUserDate.value?.indexOf(tag), 1);
      multipleTable.value?.toggleRowSelection(tag);
  }
  // 多选框选中数据
  const  handleSelectionChange = (selection) => {
      selectedUserDate.value = selection;
  }
  const  onSelectUsers = () => {
      selectedUserDate.value = []
      multipleTable.value?.clearSelection();
      getDeptOptions();
      console.log("onSelectUsers deptOptions",deptOptions.value)
      console.log("onSelectUsers deptProps",deptProps.value)
      userOpen.value = true;
  }
  const  handleTaskUserComplete = () => {
    if (!selectedUserDate.value || selectedUserDate.value.length <= 0) {
      proxy?.$modal.msgError('请选择用户');
      return;
    }
    userTaskForm.value.dataType = 'USERS';
    selectedUser.value.text = selectedUserDate.value.map(k => k.nickName) || [];
    if (selectedUserDate.value.length === 1) {
      let data = selectedUserDate.value[0];
      userTaskForm.value.assignee = data.userName;
      userTaskForm.value.text = data.nickName;
      userTaskForm.value.candidateUsers = '';
      showMultiFlog.value = false;
      multiLoopType.value = 'Null';
      changeMultiLoopType();
    } else {
      userTaskForm.value.candidateUsers = selectedUserDate.value.map(k => k.userName).join() || '';
      userTaskForm.value.text = selectedUserDate.value.map(k => k.nickName).join() || '';
      userTaskForm.value.assignee = '';
      showMultiFlog.value = true;
    }
    updateElementTask()
    userOpen.value = false;
  }
  const  changeSelectRoles = (val) => {
    let groups = null;
    let text = null;
    if (val && val.length > 0) {
      userTaskForm.value.dataType = 'ROLES';
      groups = val.join() || null;
      let textArr = roleOptions.value.filter(k => val.indexOf(`ROLE${k.roleId}`) >= 0);
      text = textArr?.map(k => k.roleName).join() || null;
    } else {
      userTaskForm.value.dataType = '';
      multiLoopType.value = 'Null';
    }
    userTaskForm.value.candidateGroups = groups;
    userTaskForm.value.text = text;
    updateElementTask();
    changeMultiLoopType();
  }
  const  checkedDeptChange = (checkedIds) => {
    let groups = null;
    let text = null;
    deptIds.value = checkedIds;
    if (checkedIds && checkedIds.length > 0) {
      userTaskForm.value.dataType = 'DEPTS';
      groups = checkedIds.join() || null;
      let textArr = []
      let treeStarkData = JSON.parse(JSON.stringify(deptTreeData.value));
      checkedIds.forEach(id => {
        let stark = []
        stark = stark.concat(treeStarkData);
        while(stark.length) {
          let temp = stark.shift();
          if(temp.children) {
            stark = temp.children.concat(stark);
          }
          if(id === temp.id) {
            textArr.push(temp);
          }
        }
      })
      text = textArr?.map(k => k.label).join() || '';
    } else {
      userTaskForm.value.dataType = '';
      multiLoopType.value = 'Null';
    }
    userTaskForm.value.candidateGroups = groups;
    userTaskForm.value.text = text || '';
    updateElementTask();
    changeMultiLoopType();
  }
  const  changeDataType = (val) => {
    if (val === 'ROLES' || val === 'DEPTS' || (val === 'USERS' && selectedUser.value.ids.length > 1)) {
      showMultiFlog.value = true;
    } else {
      showMultiFlog.value = false;
    }
    multiLoopType.value = 'Null';
    changeMultiLoopType();
    // 清空 userTaskForm 所有属性值
    Object.keys(userTaskForm.value).forEach(key => userTaskForm.value[key] = null);
    userTaskForm.value.dataType = val;
    console.log("changeDataType selectedUser.value",selectedUser.value);
    console.log("changeDataType val",val);
    if (val === 'USERS') {
      if (selectedUser.value && selectedUser.value.ids && selectedUser.value.ids.length > 0) {
        if (selectedUser.value.ids.length === 1) {
          userTaskForm.value.assignee = selectedUser.value.ids[0];
        } else {
          userTaskForm.value.candidateUsers = selectedUser.value.ids.join()
        }
        userTaskForm.value.text = selectedUser.value.text?.join() || ''
      }
    } else if (val === 'ROLES') {
      getRoleOptions();
      if (roleIds.value&& roleIds.value.length > 0) {
        userTaskForm.value.candidateGroups = roleIds.value.join() || '';
        let textArr = roleOptions.value.filter(k => roleIds.value.indexOf(`ROLE${k.roleId}`) >= 0);
        userTaskForm.value.text = textArr?.map(k => k.roleName).join() || '';
      }
    } else if (val === 'DEPTS') {
      getDeptTreeData();
      if (deptIds.value && deptIds.value.length > 0) {
        userTaskForm.value.candidateGroups = deptIds.value.join() || '';
        let textArr = []
        let treeStarkData = JSON.parse(JSON.stringify(deptTreeData.value));
        deptIds.value.forEach(id => {
          let stark = []
          stark = stark.concat(treeStarkData);
          while(stark.length) {
            let temp = stark.shift();
            if(temp.children) {
              stark = temp.children.concat(stark);
            }
            if(id === temp.id) {
              textArr.push(temp);
            }
          }
        })
        userTaskForm.value.text = textArr?.map(k => k.label).join() || '';
      }
    } else if (val === 'MANAGER') {
      userTaskForm.value.assignee = "${DepManagerHandler.getUser(execution)}";
      userTaskForm.value.text = "部门经理";

    } else if (val === 'INITIATOR') {
      userTaskForm.value.assignee = "${initiator}";
      userTaskForm.value.text = "流程发起人";
    }
    updateElementTask();
  }
  const  getElementLoop = (businessObject) => {
    if (!businessObject.loopCharacteristics) {
      multiLoopType.value = "Null";
      return;
    }
    isSequential.value = businessObject.loopCharacteristics.isSequential;
    if (businessObject.loopCharacteristics.completionCondition) {
      if (businessObject.loopCharacteristics.completionCondition.body === "${nrOfCompletedInstances >= nrOfInstances}") {
        multiLoopType.value = "SequentialMultiInstance";
      } else if (businessObject.loopCharacteristics.completionCondition.body === "${nrOfCompletedInstances > 0}") {
        multiLoopType.value = "ParallelMultiInstance";
      } else {
        multiLoopType.value = "CustomMultiInstance";
      }
    }
  }
  const  changeMultiLoopType = () => {
    // 取消多实例配置
    if (multiLoopType.value === "Null") {
      bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), { loopCharacteristics: null, assignee: null });
      return;
    }
    const multiLoopInstance = bpmnInstances().moddle.create("bpmn:MultiInstanceLoopCharacteristics", { isSequential: isSequential.value });
    // 更新多实例配置
    bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
      loopCharacteristics: multiLoopInstance,
      assignee: '${assignee}'
    });
    // 完成条件
    let completionCondition = null;
    // 会签
    if (multiLoopType.value === "SequentialMultiInstance") {
      completionCondition = bpmnInstances().moddle.create("bpmn:FormalExpression", { body: "${nrOfCompletedInstances >= nrOfInstances}" });
    }
    // 或签
    if (multiLoopType.value === "ParallelMultiInstance") {
      completionCondition = bpmnInstances().moddle.create("bpmn:FormalExpression", { body: "${nrOfCompletedInstances > 0}" });
    }
    // 自定义会签
    if (multiLoopType.value === "CustomMultiInstance") {
      completionCondition = bpmnInstances().moddle.create("bpmn:FormalExpression", { body: CustomCompletionCondition.value });
    }
    // 更新模块属性信息
    bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), multiLoopInstance, {
      collection: '${multiInstanceHandler.getUserNames(execution)}',
      elementVariable: 'assignee',
      completionCondition
    });
  }

  watch(
    () => props.id,
    () => {
      bpmnElement.value = bpmnInstances().bpmnElement
      nextTick(() => {
        resetTaskForm()
      })
    },
    { immediate: true }
  )
  watch(
    // 根据名称筛选部门树
    () => deptName.value,
    (val) => {
      console.log("watch deptName",deptName)
      console.log("watch tree",tree)
      tree.value.filter(val);
    }
  )

  onBeforeUnmount(() => {
    bpmnElement.value = null;
  })
</script>

<style scoped lang="scss">
.el-row .el-radio-group {
  margin-bottom: 15px;
  .el-radio {
    line-height: 28px;
  }
}
.el-tag {
  margin-bottom: 10px;
  + .el-tag {
    margin-left: 10px;
  }
}

.custom-label {
  padding-left: 5px;
  font-weight: 500;
  font-size: 14px;
  color: #606266;
}

</style>

4、效果图

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1539852.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Xpath解析

目录 Xpath的简介&#xff1a; 简介&#xff1a; 相关概念&#xff1a; Xpath的使用&#xff1a; 安装&#xff1a; 用法&#xff1a; 第一步&#xff1a;准备html 第二步&#xff1a;将html构造出etree对象 第三步&#xff1a;使用etree对象的xpath()方法配合xpath表达…

Linux--Ubuntu安装【保姆级教程】

Linux操作系统时程序员必须要学的操作系统。接下来我们就来看一下Linux操作系统是如何安装的 我们在 Vmware 虚拟机中安装 linux 系统&#xff0c;所以需要先安装 vmware 软件&#xff0c;然后再 安装 Linux 系统。 一.所需安装文件&#xff1a; Vmware 下载地址(现在最新版的…

GraalVM详细安装及打包springboot、java、javafx使用教程(打包springboot3篇)

前言 在当前多元化开发环境下&#xff0c;Java作为一种广泛应用的编程语言&#xff0c;其应用部署效率与灵活性的重要性日益凸显。Spring Boot框架以其简洁的配置和强大的功能深受开发者喜爱&#xff0c;而JavaFX则为开发者提供了构建丰富桌面客户端应用的能力。然而&#xff…

01.重新认识文件(Linux基本概念)

知识引入&#xff1a; 我们经常使用word或者wps写的论文、作业等都是文件&#xff0c;而我们这样对文件的认识也比较片面。我们是否思考过&#xff0c;如果文件里面没有写东西&#xff0c;那么计算机会不会保存呢&#xff1f;答案是&#xff0c;肯定会的。因为我们每次建的空文…

SpringBoot如何替换启动图标

SpringBoot项目在启动时会出现一个默认的启动图案 . ____ _ __ _ _/\\ / ____ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | _ | _| | _ \/ _ | \ \ \ \\\/ ___)| |_)| | | | | || (_| | ) ) ) ) |____| .__|_| |_|_| |_\__, | / / / /|_||___//_/_/_/::…

Matlab|基于条件风险价值CVaR的微网动态定价与调度策略

目录 1 主要内容 模型示意图 电能交易流程 模型亮点 2 部分代码 3 程序结果 4 下载链接 1 主要内容 程序复现文章《A cooperative Stackelberg game based energy management considering price discrimination and risk assessment》&#xff0c;建立基于主从博弈的考虑…

2024年计算机三级|数据库习题整理(自用④)

所有题目均来自【三级数据库技术基础题库】&#xff0c;此博客仅为知识点的补充&#xff0c;用于自主的回顾学习&#xff0c;仅供参考。 选择题 知识点&#xff1a;数据库文件 透明性分级&#xff1a; ①分片透明性 > ②位置透明性 > ③局部数据模型透明性 数据仓库数据…

正版J-Link仿真器无输出电压问题

目录 一、Jink安装包获取二、正版J-Link无法输出3.3V问题引脚定义图 解决方案&#xff1a;J-Link Commander J-Link是支持仿真ARM内核芯片的JTAG仿真器 一、Jink安装包获取 官网&#xff1a; https://www.segger.com/downloads/jlink/ 二、正版J-Link无法输出3.3V问题 今天…

PostgreSQL中控制文件的解析与恢复

最近遇到有人问起PG中控制文件的一些使用问题,总结了一下。 1、PG控制文件简介 1.1、存储的位置 它的路径位于: 相关信息,可以用命令pg_controldata得到: [10:41:27-postgres@centos2:/var/lib/pgsql/14/data/global]$ pg_controldata -D $PGDATA pg_control version …

蓝桥杯-02-2023蓝桥杯c/c++省赛B组题目

参考 2023 年第十四届蓝桥杯 C/C B组省赛题解 2023蓝桥杯c/c省赛B组题目(最全版)&#xff1a; A&#xff1a;日期统计 这题方法应该很多&#xff0c;没有和别人讨论想法。我的解法思路是&#xff1a;先 load 函数生成所有这一年的合法日期&#xff0c;然后枚举所有可以从数据…

为什么独享ip会更高效?

随着互联网的蓬勃发展&#xff0c;代理IP因其特性&#xff0c;也备受关注&#xff0c;代理IP又有分共享代理IP和独享代理IP&#xff0c;但&#xff0c;无论是在数据采集方面&#xff0c;还是在其他业务场景上&#xff0c;独享代理IP似乎会更受用户欢迎一点&#xff0c;这到底是…

SpringCloud之网关组件Gateway学习

SpringCloud之网关组件Gateway学习 GateWay简介 Spring Cloud Gateway是Spring Cloud的⼀个全新项目&#xff0c;目标是取代Netflix Zuul&#xff0c;它基于Spring5.0SpringBoot2.0WebFlux&#xff08;基于高性能的Reactor模式响应式通信框架Netty&#xff0c;异步⾮阻塞模型…

每日一题 --- 977. 有序数组的平方[力扣][Go]

今天这一题和昨天的知识点是一样的&#xff0c;就是双指针法。 题目&#xff1a; 给你一个按 非递减顺序 排序的整数数组 nums&#xff0c;返回 每个数字的平方 组成的新数组&#xff0c;要求也按 非递减顺序 排序。 示例 1&#xff1a; 输入&#xff1a;nums [-4,-1,0,3,1…

Zero-Change Object Transmission for Distributed Big Data Analytics——论文泛读

ATC 2022 Paper 问题 分布式大数据分析在很大程度上依赖于Java和Scala等高级语言的可靠性和多功能性。然而&#xff0c;这些高级语言也为数据传输制造了障碍。要在Java虚拟机&#xff08;JVM&#xff09;之间传输数据&#xff0c;发送方应将对象转换为字节数组&#xff08;序…

ArmSoM-Sige RK3588开发板产品简介

让我们在 5 分钟内了解 Sige7。 简介​ ArmSoM-Sige7采用Rockchip RK3588新一代旗舰级八核64位处理器&#xff0c;主频高达2.4GHz&#xff0c;6 TOPS算力NPU&#xff0c;最大可配32GB大内存。支持8K视频编解码&#xff0c;拥有丰富的接口&#xff0c;支持双2.5G网口、WiFi6 &…

虚拟机开机启动失败,进入(initramfs)解决办法

虚拟机开机启动失败&#xff0c;进入&#xff08;initramfs&#xff09;解决办法 打开虚拟机中Ubuntu时进入(initramfs)&#xff0c;导致无法进入桌面。问题如下图显示&#xff1a; 命令行输入 fsck -y /dev/sda5输入 exit进入 选择root 后回车 输入虚拟机的密码 进入 root …

项目成功秘诀:高效管理策略确保按时交付v2

一、项目成功的重要性 在当今竞争激烈的商业环境中&#xff0c;项目的成功对于企业的生存和发展具有至关重要的意义。项目的成功不仅意味着企业能够达成既定的业务目标&#xff0c;还能提升企业的市场地位、增强品牌影响力&#xff0c;并为企业的可持续发展奠定坚实基础。我们…

C++ Primmer 12.3文本查询程序(自己原来写的,跟课本中比较)

题目要求如下 1.自己版本 #pragma once #include <fstream> #include <string> #include <vector> #include <set> #include <map> #include <iostream> #include <sstream>using namespace std;int main() {ifstream t_if (&quo…

乱码问题,字符流原理

首先科普一下知识&#xff0c;我们知道ASCII码中有128的数字&#xff0c;符号&#xff0c;或大小写字母&#xff0c;这对于英文来说已经够用了&#xff0c;一个字母占用一个字节&#xff08;一个字节8bit&#xff09;&#xff0c; 存储的过程是这样的&#xff0c;一个字母w&…

二进制王国(蓝桥杯备赛)【sort/cmp的灵活应用】

二进制王国 题目链接 https://www.lanqiao.cn/problems/17035/learning/?contest_id177 题目描述 思路 这里就要灵活理解字典序排列&#xff0c;虽然string内置可以直接比较字符串字典序&#xff0c;但是在拼接时比较特殊&#xff0c;比如 11的字典序小于110&#xff0c;但…