Ver código fonte

初始化脚本编辑初始页面/添加异常处理任务字段/修改保存节点信息请求数据

lph 1 ano atrás
pai
commit
e419434390

+ 1 - 0
ruoyi-ui/package.json

@@ -73,6 +73,7 @@
     "less": "^2.7.3",
     "less-loader": "^4.1.0",
     "lucide-vue": "^0.89.0",
+    "mockjs": "^1.1.0",
     "nprogress": "0.2.0",
     "quill": "1.3.7",
     "screenfull": "5.0.2",

+ 46 - 2
ruoyi-ui/src/api/bpmprocess/process.js

@@ -84,19 +84,63 @@ export function enableProcess(data) {
 // 新增流程配置
 export function addConfiguration(data) {
   return request({
-    url: '/system/configuration',
+    url: '/system/configuration/addProcessNodeConfiguration',
     method: 'post',
     data: data,
     baseURL: process.env.VUE_APP_BASE_API4,
+    // baseURL: 'http://192.168.110.59:8055',
   })
 }
 
 // 修改流程配置
 export function updateConfiguration(data) {
   return request({
-    url: '/system/configuration',
+    url: '/system/configuration/updateProcessNodeConfiguration',
     method: 'put',
     data: data,
     baseURL: process.env.VUE_APP_BASE_API4,
   })
 }
+
+// 查询流程节点脚本列表
+export function listScript(query) {
+  return request({
+    url: '/system/script/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询流程节点脚本详细
+export function getScript(id) {
+  return request({
+    url: '/system/script/' + id,
+    method: 'get'
+  })
+}
+
+// 新增流程节点脚本
+export function addScript(data) {
+  return request({
+    url: '/system/script',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改流程节点脚本
+export function updateScript(data) {
+  return request({
+    url: '/system/script',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除流程节点脚本
+export function delScript(id) {
+  return request({
+    url: '/system/script/' + id,
+    method: 'delete'
+  })
+}

+ 1 - 1
ruoyi-ui/src/main.js

@@ -71,7 +71,7 @@ import JsonExcel from 'vue-json-excel'
 
 // 自定义指令
 import Directives from '@/utils/directives'
-
+import './mock.js'
 
 // 全局方法挂载
 Vue.prototype.getDicts = getDicts

+ 5 - 0
ruoyi-ui/src/store/modules/user.js

@@ -6,6 +6,7 @@ const user = {
   state: {
     token: getToken(),
     name: '',
+    userId: '',
     avatar: '',
     roles: [],
     permissions: [],
@@ -20,6 +21,9 @@ const user = {
     SET_NAME: (state, name) => {
       state.name = name
     },
+    SET_USER_ID: (state, userId) => {
+      state.userId = userId
+    },
     SET_AVATAR: (state, avatar) => {
       state.avatar = avatar
     },
@@ -61,6 +65,7 @@ const user = {
       return new Promise((resolve, reject) => {
         getInfo().then(res => {
           const user = res.user
+          commit('SET_USER_ID', res.user.userId)
           const avatar = (user.avatar == "" || user.avatar == null) ? require("@/assets/images/profile.jpg") : process.env.VUE_APP_BASE_API + user.avatar;
           if (res.roles && res.roles.length > 0) { // 验证返回的roles是否是一个非空数组
             commit('SET_ROLES', res.roles)

+ 371 - 0
ruoyi-ui/src/views/bpmprocess/scriptManage.vue

@@ -0,0 +1,371 @@
+<template>
+  <div class="app-container">
+    <el-form
+      :model="queryParams"
+      ref="queryForm"
+      size="small"
+      :inline="true"
+      v-show="showSearch"
+      label-width="68px"
+    >
+      <el-form-item label="脚本编码" prop="scriptKey">
+        <el-input
+          v-model="queryParams.scriptKey"
+          placeholder="请输入脚本编码"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="脚本方法名称" prop="scriptFunctionName">
+        <el-input
+          v-model="queryParams.scriptFunctionName"
+          placeholder="请输入脚本方法名称"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="脚本名称" prop="scriptName">
+        <el-input
+          v-model="queryParams.scriptName"
+          placeholder="请输入脚本名称"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="脚本描述" prop="scriptDescription">
+        <el-input
+          v-model="queryParams.scriptDescription"
+          placeholder="请输入脚本描述"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button
+          type="primary"
+          icon="el-icon-search"
+          size="mini"
+          @click="handleQuery"
+          >搜索</el-button
+        >
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery"
+          >重置</el-button
+        >
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['system:script:add']"
+          >新增</el-button
+        >
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['system:script:edit']"
+          >修改</el-button
+        >
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['system:script:remove']"
+          >删除</el-button
+        >
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          @click="handleExport"
+          v-hasPermi="['system:script:export']"
+          >导出</el-button
+        >
+      </el-col>
+      <right-toolbar
+        :showSearch.sync="showSearch"
+        @queryTable="getList"
+      ></right-toolbar>
+    </el-row>
+
+    <el-table
+      v-loading="loading"
+      :data="scriptList"
+      @selection-change="handleSelectionChange"
+    >
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="编号" align="center" prop="id" />
+      <el-table-column label="脚本编码" align="center" prop="scriptKey" />
+      <el-table-column
+        label="脚本方法名称"
+        align="center"
+        prop="scriptFunctionName"
+      />
+      <el-table-column label="脚本名称" align="center" prop="scriptName" />
+      <el-table-column
+        label="脚本方法体"
+        align="center"
+        prop="scriptFunctionCode"
+      />
+      <el-table-column label="脚本类型" align="center" prop="scriptType" />
+      <el-table-column
+        label="脚本描述"
+        align="center"
+        prop="scriptDescription"
+      />
+      <el-table-column
+        label="操作"
+        align="center"
+        class-name="small-padding fixed-width"
+      >
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['system:script:edit']"
+            >修改</el-button
+          >
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['system:script:remove']"
+            >删除</el-button
+          >
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total > 0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改流程节点脚本对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="脚本编码" prop="scriptKey">
+          <el-input v-model="form.scriptKey" placeholder="请输入脚本编码" />
+        </el-form-item>
+        <el-form-item label="脚本方法名称" prop="scriptFunctionName">
+          <el-input
+            v-model="form.scriptFunctionName"
+            placeholder="请输入脚本方法名称"
+          />
+        </el-form-item>
+        <el-form-item label="脚本名称" prop="scriptName">
+          <el-input v-model="form.scriptName" placeholder="请输入脚本名称" />
+        </el-form-item>
+        <el-form-item label="脚本方法体" prop="scriptFunctionCode">
+          <el-input
+            v-model="form.scriptFunctionCode"
+            type="textarea"
+            placeholder="请输入内容"
+          />
+        </el-form-item>
+        <el-form-item label="脚本描述" prop="scriptDescription">
+          <el-input
+            v-model="form.scriptDescription"
+            placeholder="请输入脚本描述"
+          />
+        </el-form-item>
+        <el-form-item label="删除标志" prop="delFlag">
+          <el-input v-model="form.delFlag" placeholder="请输入删除标志" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import {
+  listScript,
+  getScript,
+  delScript,
+  addScript,
+  updateScript,
+} from "@/api/bpmprocess/process";
+
+export default {
+  name: "Script",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 流程节点脚本表格数据
+      scriptList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        scriptKey: null,
+        scriptFunctionName: null,
+        scriptName: null,
+        scriptFunctionCode: null,
+        scriptType: null,
+        scriptDescription: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {},
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询流程节点脚本列表 */
+    getList() {
+      this.loading = true;
+      listScript(this.queryParams).then((response) => {
+        this.scriptList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        scriptKey: null,
+        scriptFunctionName: null,
+        scriptName: null,
+        scriptFunctionCode: null,
+        scriptType: null,
+        scriptDescription: null,
+        delFlag: null,
+        createBy: null,
+        createTime: null,
+        updateBy: null,
+        updateTime: null,
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map((item) => item.id);
+      this.single = selection.length !== 1;
+      this.multiple = !selection.length;
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加流程节点脚本";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids;
+      getScript(id).then((response) => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改流程节点脚本";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate((valid) => {
+        if (valid) {
+          if (this.form.id != null) {
+            updateScript(this.form).then((response) => {
+              this.$modal.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addScript(this.form).then((response) => {
+              this.$modal.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$modal
+        .confirm('是否确认删除流程节点脚本编号为"' + ids + '"的数据项?')
+        .then(function () {
+          return delScript(ids);
+        })
+        .then(() => {
+          this.getList();
+          this.$modal.msgSuccess("删除成功");
+        })
+        .catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      this.download(
+        "system/script/export",
+        {
+          ...this.queryParams,
+        },
+        `script_${new Date().getTime()}.xlsx`
+      );
+    },
+  },
+};
+</script>

+ 2 - 2
ruoyi-ui/src/views/system/bpmnPro/components/Panel/components/ElementExecuteUser.vue

@@ -163,7 +163,7 @@ export default {
           }
           res.rows.forEach((item) => {
             this.exeUserValueList.push({
-              value: item.userName,
+              value: item.userId,
               label: item.nickName,
             });
           });
@@ -217,7 +217,7 @@ export default {
   display: flex;
   padding-right: 25px;
 }
-::v-deep .edit-item_label{
+::v-deep .edit-item_label {
   width: 90px !important;
 }
 </style>

+ 193 - 0
ruoyi-ui/src/views/system/bpmnPro/components/Panel/components/ElementUnusualTasks.vue

@@ -0,0 +1,193 @@
+<template>
+  <el-collapse-item name="element-unusual-tasks">
+    <template #title>
+      <collapse-title title="异常任务">
+        <lucide-icon name="FileX2" />
+      </collapse-title>
+      <number-tag :value="listeners.length" margin-left="12px" />
+    </template>
+    <div class="element-unusual-tasks">
+      <el-table border :data="listeners" style="width: 100%" height="200px">
+        <el-table-column label="序号" type="index" width="50" />
+        <el-table-column
+          label="执行脚本"
+          prop="scriptKey"
+          show-overflow-tooltip
+        />
+        <el-table-column
+          label="触发方式"
+          prop="scriptTriggerType"
+          show-overflow-tooltip
+        />
+        <el-table-column label="操作" width="140">
+          <template slot-scope="{ row, $index }">
+            <el-button type="text" @click="openScriptModel($index, row)"
+              >编辑</el-button
+            >
+            <el-button type="text" @click="removeScript($index)"
+              >移除</el-button
+            >
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <el-button
+        type="primary"
+        class="inline-large-button"
+        icon="el-icon-plus"
+        @click="openScriptModel(-1)"
+      >
+        添加执行监听
+      </el-button>
+    </div>
+
+    <el-dialog
+      :visible.sync="modelVisible"
+      title="添加可触发的异常任务"
+      width="640px"
+      append-to-body
+      destroy-on-close
+    >
+      <el-form
+        ref="formRef"
+        :model="newUnusualTask"
+        :rules="formRules"
+        class="need-filled"
+        aria-modal="true"
+      >
+        <el-form-item path="scriptKey" label="任务脚本">
+          <el-select v-model="newUnusualTask.scriptKey">
+            <el-option
+              v-for="{ label, value } in scriptKeyList"
+              :label="label"
+              :value="value"
+              :key="value"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item path="scriptTriggerType" label="事件触发类型">
+          <el-select v-model="newUnusualTask.scriptTriggerType">
+            <el-option
+              v-for="{ label, value } in scriptTriggerTypeList"
+              :label="label"
+              :value="value"
+              :key="value"
+            />
+          </el-select>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="modelVisible = false">取 消</el-button>
+        <el-button type="primary" @click="saveUnusualTask">确 认</el-button>
+      </template>
+    </el-dialog>
+  </el-collapse-item>
+</template>
+
+<script>
+import {
+  addUnusualTask,
+  getUnusualTasks,
+  getUnusualTasksType,
+  removeUnusualTask,
+  updateUnusualTask,
+  getUnusualTaskTableData,
+} from "@packages/bo-utils/myFieldUtil";
+import { getScriptType } from "@packages/bo-utils/scriptUtil";
+import EventEmitter from "@utils/EventEmitter";
+import { getActive } from "@packages/bpmn-utils/BpmnDesignerUtils";
+
+export default {
+  name: "ElementUnusualTasks",
+  data() {
+    return {
+      modelVisible: false,
+      listeners: [],
+      newUnusualTask: {},
+      formRules: {
+        scriptKey: {
+          required: true,
+          trigger: ["blur", "change"],
+          message: "异常任务不能为空",
+        },
+        scriptTriggerType: {
+          required: true,
+          trigger: ["blur", "change"],
+          message: "任务触发方式不能为空",
+        },
+      },
+      scriptKeyList: [
+        {
+          value: 1,
+          label: "缺货异常",
+        },
+        {
+          value: 2,
+          label: "人员异常",
+        },
+      ],
+      scriptTriggerTypeList: [
+        {
+          value: 0,
+          label: "手动",
+        },
+        {
+          value: 1,
+          label: "自动",
+        },
+      ],
+    };
+  },
+
+  mounted() {
+    this.reloadExtensionListeners();
+    EventEmitter.on("element-update", this.reloadExtensionListeners);
+  },
+  methods: {
+    reloadExtensionListeners() {
+      this.modelVisible = false;
+      this.newUnusualTask = {
+        scriptKey: "",
+        scriptTriggerType: 0,
+        // event: getDefaultEvent(getActive()),
+        // type: "class",
+      };
+      this._listenersRaw = getUnusualTasks(getActive());
+
+      this.listeners = getUnusualTaskTableData(this._listenersRaw);
+      console.log(this.listeners);
+    },
+
+    updateScriptType(value) {
+      this.newUnusualTask.script = {
+        scriptFormat: this.newUnusualTask.script?.scriptFormat,
+        scriptType: value,
+      };
+    },
+    removeScript(index) {
+      const listener = this._listenersRaw[index];
+      removeUnusualTask(getActive(), listener);
+      this.reloadExtensionListeners();
+    },
+    async saveUnusualTask(index) {
+      await this.$refs.formRef.validate();
+      this.activeIndex === -1
+        ? addUnusualTask(getActive(), this.newUnusualTask)
+        : updateUnusualTask(
+            getActive(),
+            this.newUnusualTask,
+            this._listenersRaw[this.activeIndex]
+          );
+      this.reloadExtensionListeners();
+    },
+
+    async openScriptModel(index, TaskData) {
+      this.activeIndex = index;
+      TaskData && (this.newUnusualTask = JSON.parse(JSON.stringify(TaskData)));
+      this.modelVisible = true;
+      await this.$nextTick();
+      this.$refs.formRef && this.$refs.formRef.clearValidate();
+    },
+  },
+};
+</script>

+ 5 - 2
ruoyi-ui/src/views/system/bpmnPro/components/Panel/index.vue

@@ -44,6 +44,7 @@ import ElementExecuteForm from "@packages/Panel/components/ElementExecuteForm";
 import ElementExecuteUser from "@packages/Panel/components/ElementExecuteUser";
 import ElementBeforeNode from "@packages/Panel/components/ElementBeforeNode";
 import ElementAfterNode from "@packages/Panel/components/ElementAfterNode";
+import ElementUnusualTasks from "@packages/Panel/components/ElementUnusualTasks";
 
 export default {
   name: "BpmnPanel",
@@ -62,6 +63,7 @@ export default {
     ElementExecuteUser,
     ElementBeforeNode,
     ElementAfterNode,
+    ElementUnusualTasks,
   },
   data() {
     return {
@@ -158,9 +160,10 @@ export default {
       // 添加执行表单
       isTaskOrUserTask(element) &&
         this.renderComponents.push(ElementExecuteForm);
+      !isProcess(element) && this.renderComponents.push(ElementUnusualTasks); //可处理异常
       isUserTask(element) && this.renderComponents.push(ElementExecuteUser);
-      // !isProcess(element) && this.renderComponents.push(ElementBeforeNode);
-      // !isProcess(element) && this.renderComponents.push(ElementAfterNode);
+      !isProcess(element) && this.renderComponents.push(ElementBeforeNode);
+      !isProcess(element) && this.renderComponents.push(ElementAfterNode);
     },
   },
 };

+ 12 - 5
ruoyi-ui/src/views/system/bpmnPro/components/Toolbar/tools/Save.vue

@@ -16,6 +16,8 @@ import { getProcessEngine } from "@packages/bpmn-utils/BpmnDesignerUtils";
 import EventEmitter from "@utils/EventEmitter";
 import { formDataValidate } from "@utils/formDataValidate";
 import { getNodeMsg } from "@packages/bo-utils/getNodeMsg";
+
+import moment from "moment";
 export default {
   name: "BpmnSave",
   computed: {
@@ -66,7 +68,6 @@ export default {
     },
     getProcessAsSvg() {
       let process = this.getProcess("svg");
-      console.log(process);
     },
     xmlStr2XmlObj(xmlStr) {
       var xmlObj = {};
@@ -122,6 +123,9 @@ export default {
       // 获取xml标签内容标签内容
       let xmlPro = await this.getProcess("xml");
       var xmlObj = this.xmlStr2XmlObj(xmlPro);
+
+      // this.saveNodeMsg(xmlObj);
+      // return;
       formData.startEventType =
         xmlObj
           .getElementsByTagName("bpmn:process")[0]
@@ -163,10 +167,11 @@ export default {
     },
     async saveNodeMsg(obj) {
       let data = getNodeMsg(obj);
-      if (!data.length) return;
-      data.forEach((item) => {
+      if (!data.bpmProcessConfigurationList.length) return;
+      data.bpmProcessConfigurationList.forEach((item) => {
         item.createBy = this.$store.state.user.name;
         item.nodeProcessKey = obj.id;
+        item.createTime = moment().format("YYYY-MM-DD HH:mm:ss");
       });
       try {
         let res = await addConfiguration(data);
@@ -176,9 +181,11 @@ export default {
     },
     async updateNodeMsg(obj) {
       let data = getNodeMsg(obj.warnings);
-      data.forEach((item) => {
-        item.createBy = this.$store.state.user.name;
+      if (!data.bpmProcessConfigurationList.length) return;
+      data.bpmProcessConfigurationList.forEach((item) => {
+        item.updateBy = this.$store.state.user.name;
         item.nodeProcessKey = obj.id || "";
+        item.updateTime = moment().format("YYYY-MM-DD HH:mm:ss");
       });
       try {
         let res = await updateConfiguration(data);

+ 74 - 10
ruoyi-ui/src/views/system/bpmnPro/components/bo-utils/getNodeMsg.js

@@ -1,4 +1,6 @@
 import { getProcessEngine } from "@packages/bpmn-utils/BpmnDesignerUtils";
+import { getModeler } from "@packages/bpmn-utils/BpmnDesignerUtils";
+import { v4 as uuidv4 } from "uuid";
 
 function getSecondStr(str) {
   return str.split(':')[1];
@@ -30,26 +32,32 @@ function getSecondStr(str) {
 // }
 
 export function getNodeMsg(xmlObj) {
+  // let moddle = getModeler.getModdle();
+  // console.log(moddle);
+  // return;
   let prefix = getProcessEngine();
   let { attributes, childNodes } = xmlObj
     .getElementsByTagName("bpmn:process")[0];
-  let res = [], attributeArray = ['nodeKey', 'nodeFormKey', 'nodeProcessKey', 'nodeType', 'nodeBefore', 'nodeAfter', 'nodeRolePremission', 'spare1', 'spare2', 'spare3', 'createBy', 'updateBy', 'remark'];
+  let bpmProcessConfigurationList = [], bpmNodeHandleUserList = [], bpmNodeScriptRelevanceList = [], attributeArray = ['nodeKey', 'nodeFormKey', 'nodeProcessKey', 'nodeType', 'nodeBefore', 'nodeAfter', 'nodeRolePremission', 'spare1', 'spare2', 'spare3', 'createBy', 'updateBy', 'remark'];
   childNodes.forEach((node) => {
-    console.dir(node);
+    let uuid = uuidv4();
+    bpmNodeScriptRelevanceList = [...bpmNodeScriptRelevanceList, ...getNodeException(node)];//获取节点脚本数据
+    bpmNodeHandleUserList = [...bpmNodeHandleUserList, ...getBpmNodeHandleUser(node, uuid)]
     let nodeObj = {
       nodeKey: '',
-      nodeFormKey: '',
-      nodeProcessKey: '',
-      nodeType: '',
+      nodeName: '',
+      nodeFormKey: '', //节点表单别名
+      nodeProcessKey: '', //流程别名
+      nodeType: '',   //节点类型(判断节点,正常节点..)根据字典维护
       nodeBefore: '',
       nodeAfter: '',
-      nodeRolePremission: '',
+      nodeRolePremission: uuid, //节点对应的角色权限字符
       spare1: '',
       spare2: '',
       spare3: '',
-      createBy: '',
-      updateBy: '',
-      remark: '',
+      createBy: '',  //创建者
+      updateBy: '',  //修改者
+      remark: '',    //节点描述
     }
     attributeArray.forEach(attr => {
       let tempAttr = prefix + ':' + attr
@@ -58,7 +66,63 @@ export function getNodeMsg(xmlObj) {
     nodeObj.nodeKey = node.id;
     nodeObj.nodeType = node.localName;
     if (nodeObj.nodeType == "sequenceFlow") return;
-    res.push(nodeObj)
+    bpmProcessConfigurationList.push(nodeObj)
   })
+  return {
+    bpmProcessConfigurationList,
+    bpmNodeHandleUserList,
+    bpmNodeScriptRelevanceList
+  };
+}
+
+function getNodeException(node) {
+  // console.dir(node);
+  let prefix = getProcessEngine();
+  let res = []
+  let { children } = node;
+  if (!children.length) return [];
+  children = Array.from(children);//数组化
+  let extensionElements = children.find((item) => item.nodeName == `bpmn:extensionElements`
+  )
+
+  if (!extensionElements) return [];
+  extensionElements.childNodes.forEach(item => {
+    if (item.nodeName == `${prefix}:unusualTask`) {
+      res.push({
+        scriptKey: item.attributes.scriptKey?.nodeValue,
+        scriptTriggerType: item.attributes?.scriptTriggerType?.nodeValue || 0
+      })
+    }
+  })
+  res.forEach((item) => {
+    item.nodeKey = node.id;
+  })
+  // console.log(res);
   return res;
+}
+
+
+function getBpmNodeHandleUser(node, uuid) {
+  if (node.localName !== 'userTask') return []
+  if (!node.attributes.length) return []
+  let res = {}, prefix = getProcessEngine();
+  res.virtuallyRole = uuid;
+  console.dir(node);
+  console.log(node.getAttribute('camunda:executeUserType'), 'aaaa');
+  let type = node.getAttribute('camunda:executeUserType');
+  switch (type) {
+    case '1':
+      res.executeUserNo = node.getAttribute('camunda:executeUser') + ','
+      break;
+    case '2':
+      res.executeUserNo = node.getAttribute('camunda:executeUser') + ','
+      break;
+    case '3':
+      res.realRole = node.getAttribute('camunda:executeUser') + ','
+      break;
+    default:
+      break;
+  }
+
+  return [res]
 }

+ 74 - 1
ruoyi-ui/src/views/system/bpmnPro/components/bo-utils/myFieldUtil.js

@@ -1,5 +1,10 @@
 import { catchError } from "@utils/printCatch";
 import { getModeler, getProcessEngine } from "@packages/bpmn-utils/BpmnDesignerUtils";
+import {
+  getExtensionElementsList,
+  addExtensionElements,
+  removeExtensionElements
+} from "@packages/bpmn-utils/BpmnExtensionElements";
 import { getBusinessObject, is, isAny } from "bpmn-js/lib/util/ModelUtil";
 import { add as collectionAdd } from "diagram-js/lib/util/Collections";
 
@@ -162,7 +167,7 @@ export function getBeforeNdoe(element) {
   return businessObject.get(`${prefix}:nodeBefore`);
 }
 
-// 节点后
+/* 节点后 */
 export function setAfterNdoe(element, value) {
   const prefix = getProcessEngine();
   const modeling = getModeler.getModeling();
@@ -180,3 +185,71 @@ export function getAfterNdoe(element) {
 }
 
 
+/* 异常任务 */
+
+export function getUnusualTasksContainer(element) {
+  const businessObject = getBusinessObject(element);
+  return businessObject?.get("processRef") || businessObject;
+}
+
+
+export function addUnusualTask(element, props) {
+  const prefix = getProcessEngine();
+  const moddle = getModeler.getModdle();
+  const businessObject = getUnusualTasksContainer(element);
+  const listener = moddle.create(`${prefix}:UnusualTask`, {});
+  updateTaskProperty(element, listener, props);
+  addExtensionElements(element, businessObject, listener);
+}
+
+// 获取异常任务表数据
+export function getUnusualTaskTableData(moddleList = []) {
+  const prefix = getProcessEngine();
+  let res = moddleList.map(item => {
+    return {
+      scriptKey: item?.$attrs[prefix + ':scriptKey'] || '',
+      scriptTriggerType: item?.$attrs[prefix + ':scriptTriggerType'] || 0
+    }
+  })
+  return res
+}
+
+function updateTaskProperty(element, listener, props) {
+  const modeling = getModeler.getModeling();
+  const prefix = getProcessEngine();
+  const { scriptKey, scriptTriggerType } = props;
+
+  const updateProperty = (key, value) =>
+    modeling.updateModdleProperties(element, listener, { [`${prefix}:${key}`]: value });
+
+  scriptKey && updateProperty("scriptKey", scriptKey);
+  scriptTriggerType && updateProperty("scriptTriggerType", scriptTriggerType);
+}
+// 修改任务
+export function updateUnusualTask(element, props, listener) {
+  removeExtensionElements(element, getUnusualTasksContainer(element), listener);
+  addUnusualTask(element, props);
+}
+
+// 移除一个异常任务脚本
+export function removeUnusualTask(element, listener) {
+  removeExtensionElements(element, getUnusualTasksContainer(element), listener);
+}
+
+// 获取异常任务列表
+export function getUnusualTasks(element) {
+  const prefix = getProcessEngine();
+  const businessObject = getUnusualTasksContainer(element);
+  return getExtensionElementsList(businessObject, `${prefix}:UnusualTask`);
+}
+
+// 获取异常任务类型
+export function getUnusualTasksType(listener) {
+  const prefix = getProcessEngine();
+  if (isAny(listener, [`${prefix}:UnusualTask`])) {
+    if (listener.get(`${prefix}:scriptKey`)) return "scriptKey";
+    if (listener.get(`${prefix}:scriptTriggerType`)) return "scriptTriggerType";
+  }
+  return "";
+}
+

+ 67 - 0
ruoyi-ui/src/views/system/bpmnPro/components/moddle-extensions/activiti.json

@@ -1010,6 +1010,73 @@
           "type": "String"
         }
       ]
+    },
+    {
+      "name": "UnusualTask",
+      "superClass": ["Element"],
+      "meta": {
+        "allowedIn": [
+          "bpmn:Task",
+          "bpmn:ServiceTask",
+          "bpmn:UserTask",
+          "bpmn:BusinessRuleTask",
+          "bpmn:ScriptTask",
+          "bpmn:ReceiveTask",
+          "bpmn:ManualTask",
+          "bpmn:ExclusiveGateway",
+          "bpmn:SequenceFlow",
+          "bpmn:ParallelGateway",
+          "bpmn:InclusiveGateway",
+          "bpmn:StartEvent",
+          "bpmn:IntermediateCatchEvent",
+          "bpmn:IntermediateThrowEvent",
+          "bpmn:EndEvent",
+          "bpmn:BoundaryEvent",
+          "bpmn:CallActivity",
+          "bpmn:SubProcess"
+        ]
+      },
+      "properties": [
+        {
+          "name": "scriptKey",
+          "isAttr": true,
+          "type": "String"
+        },
+        {
+          "name": "scriptTriggerType",
+          "isAttr": true,
+          "type": "String"
+        },
+        {
+          "name": "expression",
+          "isAttr": true,
+          "type": "String"
+        },
+        {
+          "name": "class",
+          "isAttr": true,
+          "type": "String"
+        },
+        {
+          "name": "delegateExpression",
+          "isAttr": true,
+          "type": "String"
+        },
+        {
+          "name": "event",
+          "isAttr": true,
+          "type": "String"
+        },
+        {
+          "name": "script",
+          "type": "Script"
+        },
+        {
+          "name": "fields",
+          "type": "Field",
+          "isMany": true
+        }
+      ]
     }
   ],
   "enumerations": []

+ 65 - 2
ruoyi-ui/src/views/system/bpmnPro/components/moddle-extensions/camunda.json

@@ -692,7 +692,8 @@
         "allowedIn": [
           "camunda:ServiceTaskLike",
           "camunda:ExecutionListener",
-          "camunda:TaskListener"
+          "camunda:TaskListener",
+          "camunda:UnusualTask"
         ]
       },
       "properties": [
@@ -746,7 +747,10 @@
       "name": "FailedJobRetryTimeCycle",
       "superClass": ["Element"],
       "meta": {
-        "allowedIn": ["camunda:AsyncCapable", "bpmn:MultiInstanceLoopCharacteristics"]
+        "allowedIn": [
+          "camunda:AsyncCapable",
+          "bpmn:MultiInstanceLoopCharacteristics"
+        ]
       },
       "properties": [
         {
@@ -815,6 +819,65 @@
         }
       ]
     },
+    {
+      "name": "UnusualTask",
+      "superClass": ["Element"],
+      "meta": {
+        "allowedIn": [
+          "bpmn:Task",
+          "bpmn:ServiceTask",
+          "bpmn:UserTask",
+          "bpmn:BusinessRuleTask",
+          "bpmn:ScriptTask",
+          "bpmn:ReceiveTask",
+          "bpmn:ManualTask",
+          "bpmn:ExclusiveGateway",
+          "bpmn:SequenceFlow",
+          "bpmn:ParallelGateway",
+          "bpmn:InclusiveGateway",
+          "bpmn:EventBasedGateway",
+          "bpmn:StartEvent",
+          "bpmn:IntermediateCatchEvent",
+          "bpmn:IntermediateThrowEvent",
+          "bpmn:EndEvent",
+          "bpmn:BoundaryEvent",
+          "bpmn:CallActivity",
+          "bpmn:SubProcess",
+          "bpmn:Process"
+        ]
+      },
+      "properties": [
+        {
+          "name": "expression",
+          "isAttr": true,
+          "type": "String"
+        },
+        {
+          "name": "class",
+          "isAttr": true,
+          "type": "String"
+        },
+        {
+          "name": "delegateExpression",
+          "isAttr": true,
+          "type": "String"
+        },
+        {
+          "name": "event",
+          "isAttr": true,
+          "type": "String"
+        },
+        {
+          "name": "script",
+          "type": "Script"
+        },
+        {
+          "name": "fields",
+          "type": "Field",
+          "isMany": true
+        }
+      ]
+    },
     {
       "name": "TaskListener",
       "superClass": ["Element"],

+ 64 - 1
ruoyi-ui/src/views/system/bpmnPro/components/moddle-extensions/flowable.json

@@ -760,6 +760,7 @@
         "allowedIn": [
           "flowable:ServiceTaskLike",
           "flowable:ExecutionListener",
+          "flowable:UnusualTask",
           "flowable:TaskListener",
           "bpmn:ServiceTask"
         ]
@@ -880,7 +881,10 @@
       "name": "FailedJobRetryTimeCycle",
       "superClass": ["Element"],
       "meta": {
-        "allowedIn": ["flowable:AsyncCapable", "bpmn:MultiInstanceLoopCharacteristics"]
+        "allowedIn": [
+          "flowable:AsyncCapable",
+          "bpmn:MultiInstanceLoopCharacteristics"
+        ]
       },
       "properties": [
         {
@@ -949,6 +953,65 @@
         }
       ]
     },
+    {
+      "name": "UnusualTask",
+      "superClass": ["Element"],
+      "meta": {
+        "allowedIn": [
+          "bpmn:Task",
+          "bpmn:ServiceTask",
+          "bpmn:UserTask",
+          "bpmn:BusinessRuleTask",
+          "bpmn:ScriptTask",
+          "bpmn:ReceiveTask",
+          "bpmn:ManualTask",
+          "bpmn:ExclusiveGateway",
+          "bpmn:SequenceFlow",
+          "bpmn:ParallelGateway",
+          "bpmn:InclusiveGateway",
+          "bpmn:EventBasedGateway",
+          "bpmn:StartEvent",
+          "bpmn:IntermediateCatchEvent",
+          "bpmn:IntermediateThrowEvent",
+          "bpmn:EndEvent",
+          "bpmn:BoundaryEvent",
+          "bpmn:CallActivity",
+          "bpmn:SubProcess",
+          "bpmn:Process"
+        ]
+      },
+      "properties": [
+        {
+          "name": "expression",
+          "isAttr": true,
+          "type": "String"
+        },
+        {
+          "name": "class",
+          "isAttr": true,
+          "type": "String"
+        },
+        {
+          "name": "delegateExpression",
+          "isAttr": true,
+          "type": "String"
+        },
+        {
+          "name": "event",
+          "isAttr": true,
+          "type": "String"
+        },
+        {
+          "name": "script",
+          "type": "Script"
+        },
+        {
+          "name": "fields",
+          "type": "Field",
+          "isMany": true
+        }
+      ]
+    },
     {
       "name": "TaskListener",
       "superClass": ["Element"],

+ 66 - 54
ruoyi-ui/src/views/tablelist/commonTable/queryfrom.vue

@@ -1,18 +1,29 @@
 <template>
   <div>
     <div class="cardBox">
-      <el-card 
-        shadow="hover" 
-        :body-style="{ padding: '20px'}" 
+      <el-card
+        shadow="hover"
+        :body-style="{ padding: '20px' }"
         class="card"
-        v-for="item in cardcountArr"
+        v-for="(item, index) in cardcountArr"
+        :key="index"
+      >
+        <el-tooltip
+          class="item"
+          effect="dark"
+          :content="item.title"
+          placement="top-start"
         >
-        <el-tooltip class="item" effect="dark" :content="item.title" placement="top-start">
           <div class="title">{{ item.title }}</div>
         </el-tooltip>
-          
-        <el-tooltip class="item" effect="dark" :content="item.description" placement="top-start">
-          <div class="description">{{ item.description}}</div>
+
+        <el-tooltip
+          class="item"
+          effect="dark"
+          :content="item.description"
+          placement="top-start"
+        >
+          <div class="description">{{ item.description }}</div>
         </el-tooltip>
 
         <div class="type">
@@ -21,7 +32,7 @@
         </div>
       </el-card>
     </div>
-    
+
     <el-form
       :model="queryParams.queryMap"
       ref="queryForm"
@@ -197,60 +208,61 @@ export default {
       // card
       cardcountArr: [
         {
-          title: '标题1454654564548978784654456454545456489748787',
-          description: '描述11111154544564456486474787475465454564545454545454545',
-          type: '数量1',
-          count: 10
+          title: "标题1454654564548978784654456454545456489748787",
+          description:
+            "描述11111154544564456486474787475465454564545454545454545",
+          type: "数量1",
+          count: 10,
         },
         {
-          title: '标题2',
-          description: '描述256+56++46545646',
-          type: '已完成',
-          count: 20
+          title: "标题2",
+          description: "描述256+56++46545646",
+          type: "已完成",
+          count: 20,
         },
         {
-          title: '标题2',
-          description: '描述256+56++46545646',
-          type: '已完成',
-          count: 20
+          title: "标题2",
+          description: "描述256+56++46545646",
+          type: "已完成",
+          count: 20,
         },
         {
-          title: '标题2',
-          description: '描述256+56++46545646',
-          type: '已完成',
-          count: 20
+          title: "标题2",
+          description: "描述256+56++46545646",
+          type: "已完成",
+          count: 20,
         },
         {
-          title: '标题2',
-          description: '描述256+56++46545646',
-          type: '已完成',
-          count: 20
+          title: "标题2",
+          description: "描述256+56++46545646",
+          type: "已完成",
+          count: 20,
         },
         {
-          title: '标题2',
-          description: '描述256+56++46545646',
-          type: '已完成',
-          count: 20
+          title: "标题2",
+          description: "描述256+56++46545646",
+          type: "已完成",
+          count: 20,
         },
         {
-          title: '标题2',
-          description: '描述256+56++46545646',
-          type: '已完成',
-          count: 20
+          title: "标题2",
+          description: "描述256+56++46545646",
+          type: "已完成",
+          count: 20,
         },
         {
-          title: '标题2',
-          description: '描述256+56++46545646',
-          type: '已完成',
-          count: 20
+          title: "标题2",
+          description: "描述256+56++46545646",
+          type: "已完成",
+          count: 20,
         },
         {
-          title: '标题2',
-          description: '描述256+56++46545646',
-          type: '已完成',
-          count: 20
-        }
-      ]
+          title: "标题2",
+          description: "描述256+56++46545646",
+          type: "已完成",
+          count: 20,
+        },
+      ],
     };
   },
   watch: {
@@ -318,26 +330,26 @@ export default {
 </script>
 
 <style scoped lang="scss">
-.cardBox{
+.cardBox {
   display: flex;
   align-content: space-between;
   flex-wrap: wrap;
   align-content: flex-start;
 }
-.card{
+.card {
   /* width:15%; */
   flex-basis: 15%;
   margin-bottom: 10px;
   margin-right: 15px;
-  .title{
+  .title {
     /* width:20%; */
     font-size: 18px;
     margin-bottom: 5px;
     white-space: nowrap;
-    overflow: hidden; 
+    overflow: hidden;
     text-overflow: ellipsis;
   }
-  .description{
+  .description {
     width: 70%;
     font-size: 13px;
     color: #9699a2;
@@ -349,11 +361,11 @@ export default {
     word-break: break-all;
     float: left;
   }
-  .type{
+  .type {
     float: right;
     margin-top: 10px;
   }
-  .count{
+  .count {
     font-size: 30px;
   }
 }