| | |
| | | NODE_ENV = production |
| | | # 开发环境配置 |
| | | ENV = 'development' |
| | | |
| | | # 页面标题 |
| | | VUE_APP_TITLE = 工业互联网微服务平台 |
| | | |
| | | # 测试环境配置 |
| | | ENV = 'staging' |
| | | # 工业互联网微服务平台/开发环境 |
| | | #VUE_APP_BASE_API = '/proxy-api' |
| | | VUE_APP_BASE_API = 'http://172.16.8.100:48080' |
| | | |
| | | # 工业互联网微服务平台/测试环境 |
| | | VUE_APP_BASE_API = 'http://api-dashboard.iailab.iocoder.cn' |
| | | # 监控地址 |
| | | VITE_APP_MONITOR_ADMIN = 'http://172.16.8.100:9111' |
| | | |
| | | # 静态资源地址 |
| | | PUBLIC_PATH = 'http://static.iailab.iocoder.cn/' |
| | | # xxl-job 控制台地址 |
| | | VITE_APP_XXLJOB_ADMIN = 'http://172.16.8.100:9090' |
| | | |
| | | # druid 控制台地址 |
| | | VITE_APP_DRUID_ADMIN = 'http://172.16.8.100:48082' |
| | | |
| | | # 路由懒加载 |
| | | VUE_CLI_BABEL_TRANSPILE_MODULES = true |
| | | |
| | | # 多租户的开关 |
| | | VUE_APP_TENANT_ENABLE = true |
| | | |
| | | # 验证码的开关 |
| | | VUE_APP_CAPTCHA_ENABLE = true |
| | | VUE_APP_CAPTCHA_ENABLE = false |
| | | |
| | | # 文档的开关 |
| | | VUE_APP_DOC_ENABLE = false |
| | | VUE_APP_DOC_ENABLE = true |
| | | |
| | | # 百度统计 |
| | | VUE_APP_BAIDU_CODE = fadc1bd5db1a1d6f581df60a1807f8ab |
| | |
| | | }, |
| | | "dependencies": { |
| | | "@babel/parser": "7.18.4", |
| | | "@riophae/vue-treeselect": "0.4.0", |
| | | "@element-plus/icons-vue": "^2.1.0", |
| | | "@form-create/designer": "^3.1.3", |
| | | "@form-create/element-ui": "^3.1.24", |
| | | "@riophae/vue-treeselect": "^0.4.0", |
| | | "axios": "0.27.2", |
| | | "benz-amr-recorder": "^1.1.5", |
| | | "bpmn-js-token-simulation": "0.10.0", |
| | |
| | | "core-js": "^3.26.0", |
| | | "crypto-js": "^4.0.0", |
| | | "echarts": "5.4.0", |
| | | "element-plus": "^2.7.8", |
| | | "element-ui": "2.15.12", |
| | | "file-saver": "2.0.5", |
| | | "fuse.js": "6.6.2", |
| | | "highlight.js": "9.18.5", |
| | | "js-beautify": "1.13.0", |
| | | "js-cookie": "^2.2.1", |
| | | "jsencrypt": "3.3.1", |
| | | "min-dash": "3.5.2", |
| | | "nprogress": "0.2.0", |
| | | "qrcode.vue": "^1.7.0", |
| | | "quill": "1.3.7", |
| | | "relation-graph": "^2.1.42", |
| | | "screenfull": "5.0.2", |
| | | "sortablejs": "1.10.2", |
| | | "throttle-debounce": "2.1.0", |
| | | "vue": "2.7.14", |
| | | "vue-count-to": "1.0.13", |
| | | "vue-cron": "^1.0.9", |
| | | "vue-cropper": "0.5.8", |
| | | "vue-i18n": "^8.18.2", |
| | | "vue-meta": "^2.4.0", |
| | | "vue-quill-editor": "^3.0.6", |
| | | "vue-router": "3.4.9", |
| | | "vue-video-player": "^5.0.2", |
| | | "vuedraggable": "2.24.3", |
| | | "vuex": "3.6.2", |
| | | "xml-js": "1.6.11", |
| | | "js-cookie": "^2.2.1", |
| | | "relation-graph": "^2.1.42", |
| | | "vue-cron": "^1.0.9", |
| | | "vue-i18n": "^8.18.2", |
| | | "xlsx": "^0.18.5", |
| | | "xlsx-style": "^0.8.13" |
| | | "xlsx-style": "^0.8.13", |
| | | "xml-js": "1.6.11" |
| | | }, |
| | | "devDependencies": { |
| | | "@vue/cli-plugin-babel": "4.5.18", |
对比新文件 |
| | |
| | | import request from '@/utils/request' |
| | | |
| | | export function getProcessExpressionPage(query) { |
| | | return request({ |
| | | url: '/bpm/process-expression/page', |
| | | method: 'get', |
| | | params: query |
| | | }) |
| | | } |
| | | |
| | | export function getProcessExpression(id) { |
| | | return request({ |
| | | url: '/bpm/process-expression/get?id=' + id, |
| | | method: 'get', |
| | | }) |
| | | } |
| | | |
| | | export function createProcessExpression(data) { |
| | | return request({ |
| | | url: '/bpm/process-expression/create', |
| | | method: 'POST', |
| | | data: data |
| | | }) |
| | | } |
| | | |
| | | export function updateProcessExpression(data) { |
| | | return request({ |
| | | url: '/bpm/process-expression/update', |
| | | method: 'POST', |
| | | data: data |
| | | }) |
| | | } |
| | | |
| | | export function deleteProcessExpression(id) { |
| | | return request({ |
| | | url: '/bpm/process-expression/delete?id=', |
| | | method: 'DELETE', |
| | | data: { |
| | | id |
| | | } |
| | | }) |
| | | } |
| | |
| | | |
| | | export function cancelProcessInstance(id, reason) { |
| | | return request({ |
| | | url: '/bpm/process-instance/cancel', |
| | | url: '/bpm/process-instance/cancel-by-start-user', |
| | | method: 'DELETE', |
| | | data: { |
| | | id, |
| | |
| | | |
| | | export function updateTaskAssignee(data) { |
| | | return request({ |
| | | url: '/bpm/task/update-assignee', |
| | | url: '/bpm/task/transfer', |
| | | method: 'PUT', |
| | | data: data |
| | | }) |
| | |
| | | |
| | | export function getReturnList(taskId) { |
| | | return request({ |
| | | url: '/bpm/task/return-list?taskId='+ taskId, |
| | | url: '/bpm/task/list-by-return?id='+ taskId, |
| | | method: 'get', |
| | | }) |
| | | } |
| | |
| | | // 获取用户组精简信息列表 |
| | | export function listSimpleUserGroups() { |
| | | return request({ |
| | | url: '/bpm/user-group/list-all-simple', |
| | | url: '/bpm/user-group/simple-list', |
| | | method: 'get' |
| | | }) |
| | | } |
| | |
| | | // container-logo |
| | | $logoWidth: 500px; |
| | | $logoHeight: 64px; |
| | | //$logoImage: '../assets/logo/login-logo.png'; |
| | | // container-content |
| | | $contentWidth: round($W / $H * 100) * 1vw; |
| | | $contentHeight: round($picH / $W * 100) / 100 * $contentWidth; |
对比新文件 |
| | |
| | | <template> |
| | | <!-- 单选的时候,value绑定id,多选的时候绑定展示名称字符串数组 --> |
| | | <el-select |
| | | :title="multiple? optionData.label : ''" |
| | | ref="select" |
| | | :value="multiple ? optionData.label : value" |
| | | placeholder="请选择" |
| | | :size="size" |
| | | clearable |
| | | :filterable="filterable" |
| | | :filter-method="filterMethod" |
| | | :disabled="disabled" |
| | | :multiple="multiple" |
| | | :collapse-tags="collapseTags" |
| | | @remove-tag="removeTag" |
| | | @clear="clear" |
| | | @visible-change="visibleChange" |
| | | @focus="focus" |
| | | > |
| | | <!-- 单选的时候,label绑定展示名称,多选的时候绑定空字符串 --> |
| | | <el-option |
| | | ref="option" |
| | | class="tree-select__option" |
| | | :value="optionData.id" |
| | | :label="multiple ? '' : optionData.label" |
| | | > |
| | | <el-tree |
| | | ref="tree" |
| | | class="tree-select__tree" |
| | | :class="`tree-select__tree--${multiple ? 'checked' : 'radio'}`" |
| | | :node-key="nodeKey" |
| | | :data="data" |
| | | :props="props" |
| | | v-bind="treeAttr" |
| | | :highlight-current="!multiple" |
| | | :show-checkbox="multiple" |
| | | :check-strictly="checkStrictly" |
| | | :expand-on-click-node="multiple" |
| | | :filter-node-method="filterNode" |
| | | @node-click="handleNodeClick" |
| | | @current-change="handleCurrentChange" |
| | | @check-change="handleCheckChange" |
| | | ></el-tree> |
| | | </el-option> |
| | | </el-select> |
| | | </template> |
| | | |
| | | <script> |
| | | |
| | | export default { |
| | | name: 'SelectTree', |
| | | props: { |
| | | size: { |
| | | type: String, |
| | | default: 'small' |
| | | }, |
| | | // v-model绑定 |
| | | value: { |
| | | type: [String, Number, Array], |
| | | default: '' |
| | | }, |
| | | // 树形的数据 |
| | | data: { |
| | | type: Array, |
| | | default: function() { |
| | | return [] |
| | | } |
| | | }, |
| | | // 每个树节点用来作为唯一标识的属性 |
| | | nodeKey: { |
| | | type: [String, Number], |
| | | default: 'id' |
| | | }, |
| | | filterable: { |
| | | type: Boolean, |
| | | default: false |
| | | }, |
| | | disabled: { |
| | | type: Boolean, |
| | | default: false |
| | | }, |
| | | multiple: { |
| | | type: Boolean, |
| | | default: false |
| | | }, |
| | | collapseTags: { |
| | | type: Boolean, |
| | | default: false |
| | | }, |
| | | checkStrictly: { |
| | | type: Boolean, |
| | | default: false |
| | | }, |
| | | // tree的props配置 |
| | | props: { |
| | | type: Object, |
| | | default: function() { |
| | | return { |
| | | label: 'label', |
| | | children: 'children' |
| | | } |
| | | } |
| | | } |
| | | }, |
| | | data() { |
| | | return { |
| | | optionData: { |
| | | id: '', |
| | | name: '' |
| | | }, |
| | | filterFlag: false, |
| | | checkedArray: [] |
| | | } |
| | | }, |
| | | computed: { |
| | | treeAttr() { |
| | | if (this.value) { |
| | | return { |
| | | defaultExpandedKeys: [this.value] |
| | | } |
| | | } else { |
| | | // 考虑 value 可能为 null |
| | | return {} |
| | | } |
| | | } |
| | | }, |
| | | watch: { |
| | | value: { |
| | | handler(val) { |
| | | if (!this.isEmpty(this.data)) { |
| | | this.init(val) |
| | | } |
| | | }, |
| | | immediate: true |
| | | }, |
| | | data: function(val) { |
| | | if (!this.isEmpty(val)) { |
| | | this.init(this.value) |
| | | } |
| | | } |
| | | }, |
| | | methods: { |
| | | // 是否为空 |
| | | isEmpty(val) { |
| | | return this._.isEmpty(val) |
| | | }, |
| | | handleNodeClick(data) { |
| | | if (this.multiple) { |
| | | return |
| | | } |
| | | if (data.disabled) { |
| | | // 若节点 disabled === true,则取消选中 |
| | | this.$refs.tree.setCurrentKey(null) |
| | | return |
| | | } |
| | | this.$emit('input', data[this.nodeKey]) |
| | | this.$emit('setLayer', data['layer']) |
| | | this.$emit('selectNode', data[this.nodeKey]) |
| | | this.$refs.select.visible = false |
| | | }, |
| | | handleCurrentChange(data) { |
| | | if (this.multiple) { |
| | | return |
| | | } |
| | | this.$emit('change', false) |
| | | }, |
| | | handleCheckChange(data, checked, childrenChecked) { |
| | | if (checked) { |
| | | this.checkedArray.push(data) |
| | | } else { |
| | | let checkIndex = this._.findIndex(this.checkedArray, data) |
| | | this.checkedArray.splice(checkIndex, 1) |
| | | } |
| | | // 多选绑定的值是数组 |
| | | this.optionData.id = this.checkedArray |
| | | .map(item => item[this.nodeKey]) |
| | | // 多选展示的 label 是字符串数组 |
| | | const label = this.props.label || 'name' |
| | | this.optionData[label] = this.checkedArray |
| | | .map(item => item[label]) |
| | | this.$emit('input', this.optionData.id) |
| | | this.$emit('selectNode', this.optionData.id) |
| | | }, |
| | | init(val) { |
| | | // 多选 |
| | | if (this.multiple) { |
| | | if (val) { |
| | | const arr = val.toString().split(',') |
| | | this.$nextTick(() => { |
| | | this.$refs.tree.setCheckedKeys(arr) |
| | | const nodes = this.$refs.tree.getCheckedNodes() |
| | | this.optionData.id = val |
| | | |
| | | // 多选展示的 label 是字符串数组 |
| | | const label = this.props.label || 'name' |
| | | this.optionData[label] = nodes |
| | | .map(item => item[label]) |
| | | |
| | | }) |
| | | } else { |
| | | this.$refs.tree.setCheckedKeys([]) |
| | | } |
| | | } else { |
| | | // 单选 |
| | | val = val === '' ? null : val |
| | | this.$nextTick(() => { |
| | | this.$refs.tree.setCurrentKey(val) |
| | | if (!val) { |
| | | return |
| | | } |
| | | const label = this.props.label || 'name' |
| | | const node = this.$refs.tree.getNode(val) |
| | | this.optionData.id = val |
| | | this.optionData[label] = node.label |
| | | }) |
| | | } |
| | | }, |
| | | removeTag(tag) { |
| | | // this.handleCheckChange({ id: tag }, false) |
| | | }, |
| | | visibleChange(e) { |
| | | if (e) { |
| | | const tree = this.$refs.tree |
| | | this.filterFlag && tree.filter('') |
| | | this.filterFlag = false |
| | | let selectDom = null |
| | | if (this.multiple) { |
| | | selectDom = tree.$el.querySelector('.el-tree-node.is-checked') |
| | | } else { |
| | | selectDom = tree.$el.querySelector('.is-current') |
| | | } |
| | | setTimeout(() => { |
| | | this.$refs.select.scrollToOption({ $el: selectDom }) |
| | | }, 0) |
| | | } |
| | | }, |
| | | focus(e) { |
| | | this.$emit('focus') |
| | | }, |
| | | clear() { |
| | | this.$emit('input', null) |
| | | }, |
| | | filterMethod(val) { |
| | | this.filterFlag = true |
| | | this.$refs.tree.filter(val) |
| | | }, |
| | | filterNode(value, data) { |
| | | if (!value) return true |
| | | const label = this.props.label || 'name' |
| | | return data[label].indexOf(value) !== -1 |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | | .tree-select__option { |
| | | height: auto; |
| | | line-height: 1; |
| | | padding: 0; |
| | | background-color: #fff; |
| | | |
| | | &.el-select-dropdown__item { |
| | | height: auto; |
| | | line-height: 1; |
| | | padding: 0; |
| | | background-color: #fff; |
| | | } |
| | | |
| | | } |
| | | |
| | | .tree-select__tree { |
| | | padding: 4px 20px; |
| | | font-weight: 400; |
| | | |
| | | &.tree-select__tree--radio { |
| | | ::v-deep .el-tree-node.is-current > .el-tree-node__content { |
| | | color: #409eff; |
| | | font-weight: 700; |
| | | } |
| | | } |
| | | |
| | | /*::v-deep .el-tree-node.is-current > .el-tree-node__content { |
| | | color: #409eff; |
| | | font-weight: 700; |
| | | }*/ |
| | | |
| | | ::v-deep .el-tree-node:focus > .el-tree-node__content { |
| | | background-color: #ffffff; |
| | | } |
| | | |
| | | } |
| | | |
| | | /* 禁止通过 tag 取消选中 */ |
| | | ::v-deep .el-tag.el-tag--info .el-tag__close { |
| | | display: none; |
| | | } |
| | | |
| | | </style> |
| | |
| | | <template> |
| | | <div class="my-process-designer"> |
| | | <div class="my-process-designer__container"> |
| | | <div class="my-process-designer__canvas" ref="bpmn-canvas"></div> |
| | | <div class="my-process-designer__canvas" style="height: 760px" ref="bpmn-canvas"></div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | |
| | | <script> |
| | | import BpmnViewer from "bpmn-js/lib/Viewer"; |
| | | import DefaultEmptyXML from "./plugins/defaultEmpty"; |
| | | import { getDictDatas } from '@/utils/dict' |
| | | |
| | | export default { |
| | | name: "MyProcessViewer", |
| | |
| | | // 初始化 |
| | | this.initBpmnModeler(); |
| | | this.createNewDiagram(this.xml); |
| | | this.$once("hook:beforeDestroy", () => { |
| | | if (this.bpmnModeler) this.bpmnModeler.destroy(); |
| | | this.$emit("destroy", this.bpmnModeler); |
| | | this.bpmnModeler = null; |
| | | }); |
| | | // this.$once("hook:beforeDestroy", () => { |
| | | // if (this.bpmnModeler) this.bpmnModeler.destroy(); |
| | | // this.$emit("destroy", this.bpmnModeler); |
| | | // this.bpmnModeler = null; |
| | | // }); |
| | | // 初始模型的监听器 |
| | | this.initModelListeners(); |
| | | }, |
| | | beforeMount() { |
| | | if (this.bpmnModeler) this.bpmnModeler.destroy() |
| | | this.$emit("destroy", this.bpmnModeler); |
| | | this.bpmnModeler = null; |
| | | }, |
| | | watch: { |
| | | value: function (newValue) { // 在 xmlString 发生变化时,重新创建,从而绘制流程图 |
| | |
| | | }, |
| | | taskData: function (newTaskListData) { |
| | | this.taskList = newTaskListData; |
| | | console.log(this.taskList) |
| | | this.createNewDiagram(this.xml); |
| | | } |
| | | }, |
| | |
| | | let canvas = this.bpmnModeler.get('canvas'); |
| | | let todoActivity = activityList.find(m => !m.endTime) // 找到待办的任务 |
| | | let endActivity = activityList[activityList.length - 1] // 获得最后一个任务 |
| | | let findProcessTask = false //是否已经高亮了进行中的任务 |
| | | //进行中高亮之后的任务 key 集合,用于过滤掉 taskList 进行中后面的任务,避免进行中后面的数据 Hover 还有数据 |
| | | let removeTaskDefinitionKeyList = [] |
| | | // debugger |
| | | // console.log(this.bpmnModeler.getDefinitions().rootElements[0].flowElements); |
| | | this.bpmnModeler.getDefinitions().rootElements[0].flowElements?.forEach(n => { |
| | | let activity = activityList.find(m => m.key === n.id) // 找到对应的活动 |
| | | if (!activity) { |
| | |
| | | if (!task) { |
| | | return; |
| | | } |
| | | // 进行中的任务已经高亮过了,则不高亮后面的任务了 |
| | | if (findProcessTask) { |
| | | removeTaskDefinitionKeyList.push(n.id) |
| | | return |
| | | } |
| | | // 高亮任务 |
| | | canvas.addMarker(n.id, this.getResultCss(task.result)); |
| | | canvas.addMarker(n.id, this.getResultCss(task.status)); |
| | | |
| | | //标记是否高亮了进行中任务 |
| | | if (task.status === 1) { |
| | | findProcessTask = true |
| | | } |
| | | |
| | | // 如果非通过,就不走后面的线条了 |
| | | if (task.result !== 2) { |
| | | if (task.status !== 2) { |
| | | return; |
| | | } |
| | | // 处理 outgoing 出线 |
| | |
| | | // 如果目标活动存在,则根据该活动是否结束,进行【bpmn:SequenceFlow】连线的高亮设置 |
| | | if (targetActivity) { |
| | | canvas.addMarker(nn.id, targetActivity.endTime ? 'highlight' : 'highlight-todo'); |
| | | } else if (nn.targetRef.$type === 'bpmn:ExclusiveGateway') { // TODO iailab:这个流程,暂时没走到过 |
| | | } else if (nn.targetRef.$type === 'bpmn:ExclusiveGateway') { |
| | | // TODO iailab:这个流程,暂时没走到过 |
| | | canvas.addMarker(nn.id, activity.endTime ? 'highlight' : 'highlight-todo'); |
| | | canvas.addMarker(nn.targetRef.id, activity.endTime ? 'highlight' : 'highlight-todo'); |
| | | } else if (nn.targetRef.$type === 'bpmn:EndEvent') { // TODO iailab:这个流程,暂时没走到过 |
| | | } else if (nn.targetRef.$type === 'bpmn:EndEvent') { |
| | | // TODO iailab:这个流程,暂时没走到过 |
| | | if (!todoActivity && endActivity.key === n.id) { |
| | | canvas.addMarker(nn.id, 'highlight'); |
| | | canvas.addMarker(nn.targetRef.id, 'highlight'); |
| | |
| | | canvas.addMarker(nn.targetRef.id, this.getActivityHighlightCss(targetActivity)); |
| | | } |
| | | }) |
| | | } else if (n.$type === 'bpmn:StartEvent') { // 开始节点 |
| | | } else if (n.$type === 'bpmn:StartEvent') { |
| | | // 开始节点 |
| | | canvas.addMarker(n.id, 'highlight') |
| | | n.outgoing?.forEach(nn => { // outgoing 例如说【bpmn:SequenceFlow】连线 |
| | | // 获得连线是否有指向目标。如果有,则进行高亮 |
| | | let targetActivity = activityList.find(m => m.key === nn.targetRef.id); |
| | |
| | | } |
| | | }); |
| | | } else if (n.$type === 'bpmn:EndEvent') { // 结束节点 |
| | | if (!this.processInstance || this.processInstance.result === 1) { |
| | | if (!this.processInstance || this.processInstance.status === 1) { |
| | | return; |
| | | } |
| | | canvas.addMarker(n.id, this.getResultCss(this.processInstance.result)); |
| | | canvas.addMarker(n.id, this.getResultCss(this.processInstance.status)); |
| | | } else if (n.$type === 'bpmn:ServiceTask'){ //服务任务 |
| | | if(activity.startTime>0 && activity.endTime===0){//进入执行,标识进行色 |
| | | canvas.addMarker(n.id, this.getResultCss(1)); |
| | | } |
| | | if(activity.endTime>0){// 执行完成,节点标识完成色, 所有outgoing标识完成色。 |
| | | if(activity.endTime > 0){// 执行完成,节点标识完成色, 所有outgoing标识完成色。 |
| | | canvas.addMarker(n.id, this.getResultCss(2)); |
| | | const outgoing = this.getActivityOutgoing(activity) |
| | | outgoing?.forEach(out=>{ |
| | | canvas.addMarker(out.id,this.getResultCss(2)) |
| | | }) |
| | | } |
| | | } else if (n.$type === 'bpmn:SequenceFlow') { |
| | | let targetActivity = activityList.find(m => m.key === n.targetRef.id) |
| | | if (targetActivity) { |
| | | canvas.addMarker(n.id, this.getActivityHighlightCss(targetActivity)) |
| | | } |
| | | } |
| | | }) |
| | | if (removeTaskDefinitionKeyList) { |
| | | this.taskList = this.taskList.filter( |
| | | (item) => !removeTaskDefinitionKeyList.includes(item.taskDefinitionKey) |
| | | ) |
| | | } |
| | | }, |
| | | getActivityHighlightCss(activity) { |
| | | return activity.endTime ? 'highlight' : 'highlight-todo'; |
| | | }, |
| | | getResultCss(result) { |
| | | if (result === 1) { // 审批中 |
| | | return 'highlight-todo'; |
| | | } else if (result === 2) { // 已通过 |
| | | return 'highlight'; |
| | | } else if (result === 3) { // 不通过 |
| | | return 'highlight-reject'; |
| | | } else if (result === 4) { // 已取消 |
| | | return 'highlight-cancel'; |
| | | } else if (result === 5) { // 已退回 |
| | | return 'highlight-back'; |
| | | } else if (result === 6) { // 已委派 |
| | | return 'highlight-todo'; |
| | | getResultCss(status) { |
| | | if (status === 1) { |
| | | // 审批中 |
| | | return 'highlight-todo' |
| | | } else if (status === 2) { |
| | | // 已通过 |
| | | return 'highlight' |
| | | } else if (status === 3) { |
| | | // 不通过 |
| | | return 'highlight-reject' |
| | | } else if (status === 4) { |
| | | // 已取消 |
| | | return 'highlight-cancel' |
| | | } else if (status === 5) { |
| | | // 退回 |
| | | return 'highlight-return' |
| | | } else if (status === 6) { |
| | | // 委派 |
| | | return 'highlight-todo' |
| | | } else if (status === 7) { |
| | | // 审批通过中 |
| | | return 'highlight-todo' |
| | | } else if (status === 0) { |
| | | // 待审批 |
| | | return 'highlight-todo' |
| | | } |
| | | return ''; |
| | | return '' |
| | | }, |
| | | getActivityOutgoing(activity) { |
| | | // 如果有 outgoing,则直接使用它 |
| | |
| | | if (element.type === 'bpmn:StartEvent' && this.processInstance) { |
| | | html = `<p>发起人:${this.processInstance.startUser.nickname}</p> |
| | | <p>部门:${this.processInstance.startUser.deptName}</p> |
| | | <p>创建时间:${this.parseTime(this.processInstance.createTime)}`; |
| | | <p>创建时间:${this.parseTime(this.processInstance.startTime)}`; |
| | | } else if (element.type === 'bpmn:UserTask') { |
| | | // debugger |
| | | let task = this.taskList.find(m => m.id === activity.taskId); // 找到活动对应的 taskId |
| | | if (!task) { |
| | | return; |
| | | } |
| | | let optionData = getDictDatas(this.DICT_TYPE.BPM_TASK_STATUS) |
| | | let dataResult = '' |
| | | optionData.forEach((element) => { |
| | | if (element.value == task.status) { |
| | | dataResult = element.label |
| | | } |
| | | }) |
| | | html = `<p>审批人:${task.assigneeUser.nickname}</p> |
| | | <p>部门:${task.assigneeUser.deptName}</p> |
| | | <p>结果:${this.getDictDataLabel(this.DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT, task.result)}</p> |
| | | <p>结果:${dataResult}</p> |
| | | <p>创建时间:${this.parseTime(task.createTime)}</p>`; |
| | | if (task.endTime) { |
| | | html += `<p>结束时间:${this.parseTime(task.endTime)}</p>` |
| | |
| | | html += `<p>审批建议:${task.reason}</p>` |
| | | } |
| | | } else if (element.type === 'bpmn:ServiceTask' && this.processInstance) { |
| | | if(activity.startTime>0){ |
| | | if(activity.startTime > 0){ |
| | | html = `<p>创建时间:${this.parseTime(activity.startTime)}</p>`; |
| | | } |
| | | if(activity.endTime>0){ |
| | |
| | | } |
| | | console.log(html) |
| | | } else if (element.type === 'bpmn:EndEvent' && this.processInstance) { |
| | | html = `<p>结果:${this.getDictDataLabel(this.DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT, this.processInstance.result)}</p>`; |
| | | let optionData = getDictDatas(this.DICT_TYPE.BPM_TASK_STATUS) |
| | | let dataResult = '' |
| | | optionData.forEach((element) => { |
| | | if (element.value == this.processInstance.status) { |
| | | dataResult = element.label |
| | | } |
| | | }) |
| | | html = `<p>结果:${dataResult}</p>`; |
| | | if (this.processInstance.endTime) { |
| | | html += `<p>结束时间:${this.parseTime(this.processInstance.endTime)}</p>` |
| | | } |
| | |
| | | </el-collapse-item> |
| | | <el-collapse-item name="condition" v-if="formVisible" key="form"> |
| | | <div slot="title" class="panel-tab__title"><i class="el-icon-s-order"></i>表单</div> |
| | | <!-- <element-form :id="elementId" :type="elementType" />--> |
| | | 友情提示:使用 <router-link target="_blank" :to="{path:'/bpm/manager/form'}"><el-link type="danger">流程表单</el-link> </router-link> |
| | | 替代,提供更好的表单设计功能 |
| | | <element-form :id="elementId" :type="elementType" /> |
| | | <!-- 友情提示:使用 <router-link target="_blank" :to="{path:'/bpm/manager/form'}"><el-link type="danger">流程表单</el-link> </router-link>--> |
| | | <!-- 替代,提供更好的表单设计功能--> |
| | | </el-collapse-item> |
| | | <el-collapse-item name="task" v-if="elementType.indexOf('Task') !== -1" key="task"> |
| | | <div slot="title" class="panel-tab__title"><i class="el-icon-s-claim"></i>任务</div> |
| | |
| | | window.bpmnInstances.elementRegistry.find(el => el.type === "bpmn:Collaboration"); |
| | | } |
| | | if (!activatedElement) return; |
| | | console.log(` |
| | | ---------- |
| | | select element changed: |
| | | id: ${activatedElement.id} |
| | | type: ${activatedElement.businessObject.$type} |
| | | ---------- |
| | | `); |
| | | console.log("businessObject: ", activatedElement.businessObject); |
| | | // console.log(` |
| | | // ---------- |
| | | // select element changed: |
| | | // id: ${activatedElement.id} |
| | | // type: ${activatedElement.businessObject.$type} |
| | | // ---------- |
| | | // `); |
| | | // console.log("businessObject: ", activatedElement.businessObject); |
| | | window.bpmnInstances.bpmnElement = activatedElement; |
| | | this.bpmnElement = activatedElement; |
| | | this.elementId = activatedElement.id; |
| | |
| | | @submit.native.prevent |
| | | > |
| | | <div v-if="elementBaseInfo.$type === 'bpmn:Process'"> |
| | | <!-- 如果是 Process 信息的时候,使用自定义表单 --> |
| | | <el-link |
| | | href="https://doc.iocoder.cn/bpm/#_3-%E6%B5%81%E7%A8%8B%E5%9B%BE%E7%A4%BA%E4%BE%8B" |
| | | type="danger" |
| | | target="_blank" |
| | | >如何实现实现会签、或签?</el-link |
| | | > |
| | | <el-form-item label="流程标识" prop="key"> |
| | | <el-input |
| | | v-model="model.key" |
| | |
| | | <template> |
| | | <div class="panel-tab__content"> |
| | | <el-form size="mini" label-width="80px" @submit.native.prevent> |
| | | <el-form-item label="表单标识"> |
| | | <el-input v-model="formKey" clearable @change="updateElementFormKey" /> |
| | | </el-form-item> |
| | | <el-form-item label="业务标识"> |
| | | <el-select v-model="businessKey" @change="updateElementBusinessKey"> |
| | | <el-option v-for="i in fieldList" :key="i.id" :value="i.id" :label="i.label" /> |
| | | <el-option label="无" value="" /> |
| | | <el-form label-width="80px"> |
| | | <el-form-item label="流程表单"> |
| | | <el-select v-model="formKey" clearable @change="updateElementFormKey"> |
| | | <el-option v-for="form in formList" :key="form.id" :label="form.name" :value="form.id" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-form> |
| | | |
| | | <!--字段列表--> |
| | | <div class="element-property list-property"> |
| | | <el-divider><i class="el-icon-coin"></i> 表单字段</el-divider> |
| | | <el-table :data="fieldList" size="mini" max-height="240" border fit> |
| | | <el-table-column label="序号" type="index" width="50px" /> |
| | | <el-table-column label="字段名称" prop="label" min-width="80px" show-overflow-tooltip /> |
| | | <el-table-column label="字段类型" prop="type" min-width="80px" :formatter="row => fieldType[row.type] || row.type" show-overflow-tooltip /> |
| | | <el-table-column label="默认值" prop="defaultValue" min-width="80px" show-overflow-tooltip /> |
| | | <el-table-column label="操作" width="90px"> |
| | | <template v-slot="{ row, $index }"> |
| | | <el-button size="mini" type="text" @click="openFieldForm(row, $index)">编辑</el-button> |
| | | <el-divider direction="vertical" /> |
| | | <el-button size="mini" type="text" style="color: #ff4d4f" @click="removeField(row, $index)">移除</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | <div class="element-drawer__button"> |
| | | <el-button size="mini" type="primary" icon="el-icon-plus" @click="openFieldForm(null, -1)">添加字段</el-button> |
| | | </div> |
| | | |
| | | <!--字段配置侧边栏--> |
| | | <el-drawer :visible.sync="fieldModelVisible" title="字段配置" :size="`${width}px`" append-to-body destroy-on-close> |
| | | <el-form :model="formFieldForm" label-width="90px" size="mini" @submit.native.prevent> |
| | | <el-form-item label="字段ID"> |
| | | <el-input v-model="formFieldForm.id" clearable /> |
| | | </el-form-item> |
| | | <el-form-item label="类型"> |
| | | <el-select v-model="formFieldForm.typeType" placeholder="请选择字段类型" clearable @change="changeFieldTypeType"> |
| | | <el-option v-for="(value, key) of fieldType" :label="value" :value="key" :key="key" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="类型名称" v-if="formFieldForm.typeType === 'custom'"> |
| | | <el-input v-model="formFieldForm.type" clearable /> |
| | | </el-form-item> |
| | | <el-form-item label="名称"> |
| | | <el-input v-model="formFieldForm.label" clearable /> |
| | | </el-form-item> |
| | | <el-form-item label="时间格式" v-if="formFieldForm.typeType === 'date'"> |
| | | <el-input v-model="formFieldForm.datePattern" clearable /> |
| | | </el-form-item> |
| | | <el-form-item label="默认值"> |
| | | <el-input v-model="formFieldForm.defaultValue" clearable /> |
| | | </el-form-item> |
| | | </el-form> |
| | | |
| | | <!-- 枚举值设置 --> |
| | | <template v-if="formFieldForm.type === 'enum'"> |
| | | <el-divider key="enum-divider" /> |
| | | <p class="listener-filed__title" key="enum-title"> |
| | | <span><i class="el-icon-menu"></i>枚举值列表:</span> |
| | | <el-button size="mini" type="primary" @click="openFieldOptionForm(null, -1, 'enum')">添加枚举值</el-button> |
| | | </p> |
| | | <el-table :data="fieldEnumList" size="mini" key="enum-table" max-height="240" border fit> |
| | | <el-table-column label="序号" width="50px" type="index" /> |
| | | <el-table-column label="枚举值编号" prop="id" min-width="100px" show-overflow-tooltip /> |
| | | <el-table-column label="枚举值名称" prop="name" min-width="100px" show-overflow-tooltip /> |
| | | <el-table-column label="操作" width="90px"> |
| | | <template v-slot="{ row, $index }"> |
| | | <el-button size="mini" type="text" @click="openFieldOptionForm(row, $index, 'enum')">编辑</el-button> |
| | | <el-divider direction="vertical" /> |
| | | <el-button size="mini" type="text" style="color: #ff4d4f" @click="removeFieldOptionItem(row, $index, 'enum')">移除</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </template> |
| | | |
| | | <!-- 校验规则 --> |
| | | <el-divider key="validation-divider" /> |
| | | <p class="listener-filed__title" key="validation-title"> |
| | | <span><i class="el-icon-menu"></i>约束条件列表:</span> |
| | | <el-button size="mini" type="primary" @click="openFieldOptionForm(null, -1, 'constraint')">添加约束</el-button> |
| | | </p> |
| | | <el-table :data="fieldConstraintsList" size="mini" key="validation-table" max-height="240" border fit> |
| | | <el-table-column label="序号" width="50px" type="index" /> |
| | | <el-table-column label="约束名称" prop="name" min-width="100px" show-overflow-tooltip /> |
| | | <el-table-column label="约束配置" prop="config" min-width="100px" show-overflow-tooltip /> |
| | | <el-table-column label="操作" width="90px"> |
| | | <template v-slot="{ row, $index }"> |
| | | <el-button size="mini" type="text" @click="openFieldOptionForm(row, $index, 'constraint')">编辑</el-button> |
| | | <el-divider direction="vertical" /> |
| | | <el-button size="mini" type="text" style="color: #ff4d4f" @click="removeFieldOptionItem(row, $index, 'constraint')">移除</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <!-- 表单属性 --> |
| | | <el-divider key="property-divider" /> |
| | | <p class="listener-filed__title" key="property-title"> |
| | | <span><i class="el-icon-menu"></i>字段属性列表:</span> |
| | | <el-button size="mini" type="primary" @click="openFieldOptionForm(null, -1, 'property')">添加属性</el-button> |
| | | </p> |
| | | <el-table :data="fieldPropertiesList" size="mini" key="property-table" max-height="240" border fit> |
| | | <el-table-column label="序号" width="50px" type="index" /> |
| | | <el-table-column label="属性编号" prop="id" min-width="100px" show-overflow-tooltip /> |
| | | <el-table-column label="属性值" prop="value" min-width="100px" show-overflow-tooltip /> |
| | | <el-table-column label="操作" width="90px"> |
| | | <template v-slot="{ row, $index }"> |
| | | <el-button size="mini" type="text" @click="openFieldOptionForm(row, $index, 'property')">编辑</el-button> |
| | | <el-divider direction="vertical" /> |
| | | <el-button size="mini" type="text" style="color: #ff4d4f" @click="removeFieldOptionItem(row, $index, 'property')">移除</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <!-- 底部按钮 --> |
| | | <div class="element-drawer__button"> |
| | | <el-button size="mini">取 消</el-button> |
| | | <el-button size="mini" type="primary" @click="saveField">保 存</el-button> |
| | | </div> |
| | | </el-drawer> |
| | | |
| | | <el-dialog :visible.sync="fieldOptionModelVisible" :title="optionModelTitle" width="600px" append-to-body destroy-on-close> |
| | | <el-form :model="fieldOptionForm" size="mini" label-width="96px" @submit.native.prevent> |
| | | <el-form-item label="编号/ID" v-if="fieldOptionType !== 'constraint'" key="option-id"> |
| | | <el-input v-model="fieldOptionForm.id" clearable /> |
| | | </el-form-item> |
| | | <el-form-item label="名称" v-if="fieldOptionType !== 'property'" key="option-name"> |
| | | <el-input v-model="fieldOptionForm.name" clearable /> |
| | | </el-form-item> |
| | | <el-form-item label="配置" v-if="fieldOptionType === 'constraint'" key="option-config"> |
| | | <el-input v-model="fieldOptionForm.config" clearable /> |
| | | </el-form-item> |
| | | <el-form-item label="值" v-if="fieldOptionType === 'property'" key="option-value"> |
| | | <el-input v-model="fieldOptionForm.value" clearable /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template slot="footer"> |
| | | <el-button size="mini" @click="fieldOptionModelVisible = false">取 消</el-button> |
| | | <el-button size="mini" type="primary" @click="saveFieldOption">确 定</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import { getSimpleForms } from '@/api/bpm/form' |
| | | |
| | | export default { |
| | | name: "ElementForm", |
| | | props: { |
| | | id: String, |
| | | type: String |
| | | }, |
| | | inject: { |
| | | prefix: "prefix", |
| | | width: "width" |
| | | }, |
| | | data() { |
| | | return { |
| | | formKey: "", |
| | | businessKey: "", |
| | | optionModelTitle: "", |
| | | fieldList: [], |
| | | formFieldForm: {}, |
| | | fieldType: { |
| | | long: "长整型", |
| | | string: "字符串", |
| | | boolean: "布尔类", |
| | | date: "日期类", |
| | | enum: "枚举类", |
| | | custom: "自定义类型" |
| | | }, |
| | | formFieldIndex: -1, // 编辑中的字段, -1 为新增 |
| | | formFieldOptionIndex: -1, // 编辑中的字段配置项, -1 为新增 |
| | | fieldModelVisible: false, |
| | | fieldOptionModelVisible: false, |
| | | fieldOptionForm: {}, // 当前激活的字段配置项数据 |
| | | fieldOptionType: "", // 当前激活的字段配置项弹窗 类型 |
| | | fieldEnumList: [], // 枚举值列表 |
| | | fieldConstraintsList: [], // 约束条件列表 |
| | | fieldPropertiesList: [] // 绑定属性列表 |
| | | formList: [], |
| | | formData: [], |
| | | bpmnELement: Object, |
| | | }; |
| | | }, |
| | | watch: { |
| | | id: { |
| | | immediate: true, |
| | | handler(val) { |
| | | val && val.length && this.$nextTick(() => this.resetFormList()); |
| | | } |
| | | } |
| | | created() { |
| | | this.resetFormList() |
| | | }, |
| | | methods: { |
| | | getSimpleForms() { |
| | | getSimpleForms().then(response => { |
| | | this.formList = response.data |
| | | }) |
| | | }, |
| | | resetFormList() { |
| | | this.getSimpleForms() |
| | | this.bpmnELement = window.bpmnInstances.bpmnElement; |
| | | this.formKey = this.bpmnELement.businessObject.formKey; |
| | | // 获取元素扩展属性 或者 创建扩展属性 |
| | | this.elExtensionElements = |
| | | this.bpmnELement.businessObject.get("extensionElements") || window.bpmnInstances.moddle.create("bpmn:ExtensionElements", { values: [] }); |
| | | // 获取元素表单配置 或者 创建新的表单配置 |
| | | this.formData = |
| | | this.elExtensionElements.values.filter(ex => ex.$type === `${this.prefix}:FormData`)?.[0] || |
| | | window.bpmnInstances.moddle.create(`${this.prefix}:FormData`, { fields: [] }); |
| | | |
| | | // 业务标识 businessKey, 绑定在 formData 中 |
| | | this.businessKey = this.formData.businessKey; |
| | | |
| | | // 保留剩余扩展元素,便于后面更新该元素对应属性 |
| | | this.otherExtensions = this.elExtensionElements.values.filter(ex => ex.$type !== `${this.prefix}:FormData`); |
| | | |
| | | // 复制原始值,填充表格 |
| | | this.fieldList = JSON.parse(JSON.stringify(this.formData.fields || [])); |
| | | |
| | | // 更新元素扩展属性,避免后续报错 |
| | | this.updateElementExtensions(); |
| | | this.formKey = parseInt(this.bpmnELement.businessObject.formKey); |
| | | }, |
| | | updateElementFormKey() { |
| | | window.bpmnInstances.modeling.updateProperties(this.bpmnELement, { formKey: this.formKey }); |
| | | }, |
| | | updateElementBusinessKey() { |
| | | window.bpmnInstances.modeling.updateModdleProperties(this.bpmnELement, this.formData, { businessKey: this.businessKey }); |
| | | }, |
| | | // 根据类型调整字段type |
| | | changeFieldTypeType(type) { |
| | | this.$set(this.formFieldForm, "type", type === "custom" ? "" : type); |
| | | }, |
| | | |
| | | // 打开字段详情侧边栏 |
| | | openFieldForm(field, index) { |
| | | this.formFieldIndex = index; |
| | | if (index !== -1) { |
| | | const FieldObject = this.formData.fields[index]; |
| | | this.formFieldForm = JSON.parse(JSON.stringify(field)); |
| | | // 设置自定义类型 |
| | | this.$set(this.formFieldForm, "typeType", !this.fieldType[field.type] ? "custom" : field.type); |
| | | // 初始化枚举值列表 |
| | | field.type === "enum" && (this.fieldEnumList = JSON.parse(JSON.stringify(FieldObject?.values || []))); |
| | | // 初始化约束条件列表 |
| | | this.fieldConstraintsList = JSON.parse(JSON.stringify(FieldObject?.validation?.constraints || [])); |
| | | // 初始化自定义属性列表 |
| | | this.fieldPropertiesList = JSON.parse(JSON.stringify(FieldObject?.properties?.values || [])); |
| | | } else { |
| | | this.formFieldForm = {}; |
| | | // 初始化枚举值列表 |
| | | this.fieldEnumList = []; |
| | | // 初始化约束条件列表 |
| | | this.fieldConstraintsList = []; |
| | | // 初始化自定义属性列表 |
| | | this.fieldPropertiesList = []; |
| | | } |
| | | this.fieldModelVisible = true; |
| | | }, |
| | | // 打开字段 某个 配置项 弹窗 |
| | | openFieldOptionForm(option, index, type) { |
| | | this.fieldOptionModelVisible = true; |
| | | this.fieldOptionType = type; |
| | | this.formFieldOptionIndex = index; |
| | | if (type === "property") { |
| | | this.fieldOptionForm = option ? JSON.parse(JSON.stringify(option)) : {}; |
| | | return (this.optionModelTitle = "属性配置"); |
| | | } |
| | | if (type === "enum") { |
| | | this.fieldOptionForm = option ? JSON.parse(JSON.stringify(option)) : {}; |
| | | return (this.optionModelTitle = "枚举值配置"); |
| | | } |
| | | this.fieldOptionForm = option ? JSON.parse(JSON.stringify(option)) : {}; |
| | | return (this.optionModelTitle = "约束条件配置"); |
| | | }, |
| | | |
| | | // 保存字段 某个 配置项 |
| | | saveFieldOption() { |
| | | if (this.formFieldOptionIndex === -1) { |
| | | if (this.fieldOptionType === "property") { |
| | | this.fieldPropertiesList.push(this.fieldOptionForm); |
| | | } |
| | | if (this.fieldOptionType === "constraint") { |
| | | this.fieldConstraintsList.push(this.fieldOptionForm); |
| | | } |
| | | if (this.fieldOptionType === "enum") { |
| | | this.fieldEnumList.push(this.fieldOptionForm); |
| | | } |
| | | } else { |
| | | this.fieldOptionType === "property" && this.fieldPropertiesList.splice(this.formFieldOptionIndex, 1, this.fieldOptionForm); |
| | | this.fieldOptionType === "constraint" && this.fieldConstraintsList.splice(this.formFieldOptionIndex, 1, this.fieldOptionForm); |
| | | this.fieldOptionType === "enum" && this.fieldEnumList.splice(this.formFieldOptionIndex, 1, this.fieldOptionForm); |
| | | } |
| | | this.fieldOptionModelVisible = false; |
| | | this.fieldOptionForm = {}; |
| | | }, |
| | | // 保存字段配置 |
| | | saveField() { |
| | | const { id, type, label, defaultValue, datePattern } = this.formFieldForm; |
| | | const Field = window.bpmnInstances.moddle.create(`${this.prefix}:FormField`, { id, type, label }); |
| | | defaultValue && (Field.defaultValue = defaultValue); |
| | | datePattern && (Field.datePattern = datePattern); |
| | | // 构建属性 |
| | | if (this.fieldPropertiesList && this.fieldPropertiesList.length) { |
| | | const fieldPropertyList = this.fieldPropertiesList.map(fp => { |
| | | return window.bpmnInstances.moddle.create(`${this.prefix}:Property`, { id: fp.id, value: fp.value }); |
| | | }); |
| | | Field.properties = window.bpmnInstances.moddle.create(`${this.prefix}:Properties`, { values: fieldPropertyList }); |
| | | } |
| | | // 构建校验规则 |
| | | if (this.fieldConstraintsList && this.fieldConstraintsList.length) { |
| | | const fieldConstraintList = this.fieldConstraintsList.map(fc => { |
| | | return window.bpmnInstances.moddle.create(`${this.prefix}:Constraint`, { name: fc.name, config: fc.config }); |
| | | }); |
| | | Field.validation = window.bpmnInstances.moddle.create(`${this.prefix}:Validation`, { constraints: fieldConstraintList }); |
| | | } |
| | | // 构建枚举值 |
| | | if (this.fieldEnumList && this.fieldEnumList.length) { |
| | | Field.values = this.fieldEnumList.map(fe => { |
| | | return window.bpmnInstances.moddle.create(`${this.prefix}:Value`, { name: fe.name, id: fe.id }); |
| | | }); |
| | | } |
| | | // 更新数组 与 表单配置实例 |
| | | if (this.formFieldIndex === -1) { |
| | | this.fieldList.push(this.formFieldForm); |
| | | this.formData.fields.push(Field); |
| | | } else { |
| | | this.fieldList.splice(this.formFieldIndex, 1, this.formFieldForm); |
| | | this.formData.fields.splice(this.formFieldIndex, 1, Field); |
| | | } |
| | | this.updateElementExtensions(); |
| | | this.fieldModelVisible = false; |
| | | }, |
| | | |
| | | // 移除某个 字段的 配置项 |
| | | removeFieldOptionItem(option, index, type) { |
| | | if (type === "property") { |
| | | this.fieldPropertiesList.splice(index, 1); |
| | | return; |
| | | } |
| | | if (type === "enum") { |
| | | this.fieldEnumList.splice(index, 1); |
| | | return; |
| | | } |
| | | this.fieldConstraintsList.splice(index, 1); |
| | | }, |
| | | // 移除 字段 |
| | | removeField(field, index) { |
| | | this.fieldList.splice(index, 1); |
| | | this.formData.fields.splice(index, 1); |
| | | this.updateElementExtensions(); |
| | | }, |
| | | |
| | | updateElementExtensions() { |
| | | // 更新回扩展元素 |
| | | const newElExtensionElements = window.bpmnInstances.moddle.create(`bpmn:ExtensionElements`, { |
| | | values: this.otherExtensions.concat(this.formData) |
| | | }); |
| | | // 更新到元素上 |
| | | window.bpmnInstances.modeling.updateProperties(this.bpmnELement, { |
| | | extensionElements: newElExtensionElements |
| | | }); |
| | | } |
| | | } |
| | | }; |
| | | </script> |
对比新文件 |
| | |
| | | <template> |
| | | <div class="panel-tab__content"> |
| | | <el-form size="mini" label-width="80px" @submit.native.prevent> |
| | | <el-form-item label="表单标识"> |
| | | <el-input v-model="formKey" clearable @change="updateElementFormKey" /> |
| | | </el-form-item> |
| | | <el-form-item label="业务标识"> |
| | | <el-select v-model="businessKey" @change="updateElementBusinessKey"> |
| | | <el-option v-for="i in fieldList" :key="i.id" :value="i.id" :label="i.label" /> |
| | | <el-option label="无" value="" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-form> |
| | | |
| | | <!--字段列表--> |
| | | <div class="element-property list-property"> |
| | | <el-divider><i class="el-icon-coin"></i> 表单字段</el-divider> |
| | | <el-table :data="fieldList" size="mini" max-height="240" border fit> |
| | | <el-table-column label="序号" type="index" width="50px" /> |
| | | <el-table-column label="字段名称" prop="label" min-width="80px" show-overflow-tooltip /> |
| | | <el-table-column label="字段类型" prop="type" min-width="80px" :formatter="row => fieldType[row.type] || row.type" show-overflow-tooltip /> |
| | | <el-table-column label="默认值" prop="defaultValue" min-width="80px" show-overflow-tooltip /> |
| | | <el-table-column label="操作" width="90px"> |
| | | <template v-slot="{ row, $index }"> |
| | | <el-button size="mini" type="text" @click="openFieldForm(row, $index)">编辑</el-button> |
| | | <el-divider direction="vertical" /> |
| | | <el-button size="mini" type="text" style="color: #ff4d4f" @click="removeField(row, $index)">移除</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | <div class="element-drawer__button"> |
| | | <el-button size="mini" type="primary" icon="el-icon-plus" @click="openFieldForm(null, -1)">添加字段</el-button> |
| | | </div> |
| | | |
| | | <!--字段配置侧边栏--> |
| | | <el-drawer :visible.sync="fieldModelVisible" title="字段配置" :size="`${width}px`" append-to-body destroy-on-close> |
| | | <el-form :model="formFieldForm" label-width="90px" size="mini" @submit.native.prevent> |
| | | <el-form-item label="字段ID"> |
| | | <el-input v-model="formFieldForm.id" clearable /> |
| | | </el-form-item> |
| | | <el-form-item label="类型"> |
| | | <el-select v-model="formFieldForm.typeType" placeholder="请选择字段类型" clearable @change="changeFieldTypeType"> |
| | | <el-option v-for="(value, key) of fieldType" :label="value" :value="key" :key="key" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="类型名称" v-if="formFieldForm.typeType === 'custom'"> |
| | | <el-input v-model="formFieldForm.type" clearable /> |
| | | </el-form-item> |
| | | <el-form-item label="名称"> |
| | | <el-input v-model="formFieldForm.label" clearable /> |
| | | </el-form-item> |
| | | <el-form-item label="时间格式" v-if="formFieldForm.typeType === 'date'"> |
| | | <el-input v-model="formFieldForm.datePattern" clearable /> |
| | | </el-form-item> |
| | | <el-form-item label="默认值"> |
| | | <el-input v-model="formFieldForm.defaultValue" clearable /> |
| | | </el-form-item> |
| | | </el-form> |
| | | |
| | | <!-- 枚举值设置 --> |
| | | <template v-if="formFieldForm.type === 'enum'"> |
| | | <el-divider key="enum-divider" /> |
| | | <p class="listener-filed__title" key="enum-title"> |
| | | <span><i class="el-icon-menu"></i>枚举值列表:</span> |
| | | <el-button size="mini" type="primary" @click="openFieldOptionForm(null, -1, 'enum')">添加枚举值</el-button> |
| | | </p> |
| | | <el-table :data="fieldEnumList" size="mini" key="enum-table" max-height="240" border fit> |
| | | <el-table-column label="序号" width="50px" type="index" /> |
| | | <el-table-column label="枚举值编号" prop="id" min-width="100px" show-overflow-tooltip /> |
| | | <el-table-column label="枚举值名称" prop="name" min-width="100px" show-overflow-tooltip /> |
| | | <el-table-column label="操作" width="90px"> |
| | | <template v-slot="{ row, $index }"> |
| | | <el-button size="mini" type="text" @click="openFieldOptionForm(row, $index, 'enum')">编辑</el-button> |
| | | <el-divider direction="vertical" /> |
| | | <el-button size="mini" type="text" style="color: #ff4d4f" @click="removeFieldOptionItem(row, $index, 'enum')">移除</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </template> |
| | | |
| | | <!-- 校验规则 --> |
| | | <el-divider key="validation-divider" /> |
| | | <p class="listener-filed__title" key="validation-title"> |
| | | <span><i class="el-icon-menu"></i>约束条件列表:</span> |
| | | <el-button size="mini" type="primary" @click="openFieldOptionForm(null, -1, 'constraint')">添加约束</el-button> |
| | | </p> |
| | | <el-table :data="fieldConstraintsList" size="mini" key="validation-table" max-height="240" border fit> |
| | | <el-table-column label="序号" width="50px" type="index" /> |
| | | <el-table-column label="约束名称" prop="name" min-width="100px" show-overflow-tooltip /> |
| | | <el-table-column label="约束配置" prop="config" min-width="100px" show-overflow-tooltip /> |
| | | <el-table-column label="操作" width="90px"> |
| | | <template v-slot="{ row, $index }"> |
| | | <el-button size="mini" type="text" @click="openFieldOptionForm(row, $index, 'constraint')">编辑</el-button> |
| | | <el-divider direction="vertical" /> |
| | | <el-button size="mini" type="text" style="color: #ff4d4f" @click="removeFieldOptionItem(row, $index, 'constraint')">移除</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <!-- 表单属性 --> |
| | | <el-divider key="property-divider" /> |
| | | <p class="listener-filed__title" key="property-title"> |
| | | <span><i class="el-icon-menu"></i>字段属性列表:</span> |
| | | <el-button size="mini" type="primary" @click="openFieldOptionForm(null, -1, 'property')">添加属性</el-button> |
| | | </p> |
| | | <el-table :data="fieldPropertiesList" size="mini" key="property-table" max-height="240" border fit> |
| | | <el-table-column label="序号" width="50px" type="index" /> |
| | | <el-table-column label="属性编号" prop="id" min-width="100px" show-overflow-tooltip /> |
| | | <el-table-column label="属性值" prop="value" min-width="100px" show-overflow-tooltip /> |
| | | <el-table-column label="操作" width="90px"> |
| | | <template v-slot="{ row, $index }"> |
| | | <el-button size="mini" type="text" @click="openFieldOptionForm(row, $index, 'property')">编辑</el-button> |
| | | <el-divider direction="vertical" /> |
| | | <el-button size="mini" type="text" style="color: #ff4d4f" @click="removeFieldOptionItem(row, $index, 'property')">移除</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <!-- 底部按钮 --> |
| | | <div class="element-drawer__button"> |
| | | <el-button size="mini">取 消</el-button> |
| | | <el-button size="mini" type="primary" @click="saveField">保 存</el-button> |
| | | </div> |
| | | </el-drawer> |
| | | |
| | | <el-dialog :visible.sync="fieldOptionModelVisible" :title="optionModelTitle" width="600px" append-to-body destroy-on-close> |
| | | <el-form :model="fieldOptionForm" size="mini" label-width="96px" @submit.native.prevent> |
| | | <el-form-item label="编号/ID" v-if="fieldOptionType !== 'constraint'" key="option-id"> |
| | | <el-input v-model="fieldOptionForm.id" clearable /> |
| | | </el-form-item> |
| | | <el-form-item label="名称" v-if="fieldOptionType !== 'property'" key="option-name"> |
| | | <el-input v-model="fieldOptionForm.name" clearable /> |
| | | </el-form-item> |
| | | <el-form-item label="配置" v-if="fieldOptionType === 'constraint'" key="option-config"> |
| | | <el-input v-model="fieldOptionForm.config" clearable /> |
| | | </el-form-item> |
| | | <el-form-item label="值" v-if="fieldOptionType === 'property'" key="option-value"> |
| | | <el-input v-model="fieldOptionForm.value" clearable /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template slot="footer"> |
| | | <el-button size="mini" @click="fieldOptionModelVisible = false">取 消</el-button> |
| | | <el-button size="mini" type="primary" @click="saveFieldOption">确 定</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | export default { |
| | | name: "ElementForm", |
| | | props: { |
| | | id: String, |
| | | type: String |
| | | }, |
| | | inject: { |
| | | prefix: "prefix", |
| | | width: "width" |
| | | }, |
| | | data() { |
| | | return { |
| | | formKey: "", |
| | | businessKey: "", |
| | | optionModelTitle: "", |
| | | fieldList: [], |
| | | formFieldForm: {}, |
| | | fieldType: { |
| | | long: "长整型", |
| | | string: "字符串", |
| | | boolean: "布尔类", |
| | | date: "日期类", |
| | | enum: "枚举类", |
| | | custom: "自定义类型" |
| | | }, |
| | | formFieldIndex: -1, // 编辑中的字段, -1 为新增 |
| | | formFieldOptionIndex: -1, // 编辑中的字段配置项, -1 为新增 |
| | | fieldModelVisible: false, |
| | | fieldOptionModelVisible: false, |
| | | fieldOptionForm: {}, // 当前激活的字段配置项数据 |
| | | fieldOptionType: "", // 当前激活的字段配置项弹窗 类型 |
| | | fieldEnumList: [], // 枚举值列表 |
| | | fieldConstraintsList: [], // 约束条件列表 |
| | | fieldPropertiesList: [] // 绑定属性列表 |
| | | }; |
| | | }, |
| | | watch: { |
| | | id: { |
| | | immediate: true, |
| | | handler(val) { |
| | | val && val.length && this.$nextTick(() => this.resetFormList()); |
| | | } |
| | | } |
| | | }, |
| | | methods: { |
| | | resetFormList() { |
| | | this.bpmnELement = window.bpmnInstances.bpmnElement; |
| | | this.formKey = this.bpmnELement.businessObject.formKey; |
| | | // 获取元素扩展属性 或者 创建扩展属性 |
| | | this.elExtensionElements = |
| | | this.bpmnELement.businessObject.get("extensionElements") || window.bpmnInstances.moddle.create("bpmn:ExtensionElements", { values: [] }); |
| | | // 获取元素表单配置 或者 创建新的表单配置 |
| | | this.formData = |
| | | this.elExtensionElements.values.filter(ex => ex.$type === `${this.prefix}:FormData`)?.[0] || |
| | | window.bpmnInstances.moddle.create(`${this.prefix}:FormData`, { fields: [] }); |
| | | |
| | | // 业务标识 businessKey, 绑定在 formData 中 |
| | | this.businessKey = this.formData.businessKey; |
| | | |
| | | // 保留剩余扩展元素,便于后面更新该元素对应属性 |
| | | this.otherExtensions = this.elExtensionElements.values.filter(ex => ex.$type !== `${this.prefix}:FormData`); |
| | | |
| | | // 复制原始值,填充表格 |
| | | this.fieldList = JSON.parse(JSON.stringify(this.formData.fields || [])); |
| | | |
| | | // 更新元素扩展属性,避免后续报错 |
| | | this.updateElementExtensions(); |
| | | }, |
| | | updateElementFormKey() { |
| | | window.bpmnInstances.modeling.updateProperties(this.bpmnELement, { formKey: this.formKey }); |
| | | }, |
| | | updateElementBusinessKey() { |
| | | window.bpmnInstances.modeling.updateModdleProperties(this.bpmnELement, this.formData, { businessKey: this.businessKey }); |
| | | }, |
| | | // 根据类型调整字段type |
| | | changeFieldTypeType(type) { |
| | | this.$set(this.formFieldForm, "type", type === "custom" ? "" : type); |
| | | }, |
| | | |
| | | // 打开字段详情侧边栏 |
| | | openFieldForm(field, index) { |
| | | this.formFieldIndex = index; |
| | | if (index !== -1) { |
| | | const FieldObject = this.formData.fields[index]; |
| | | this.formFieldForm = JSON.parse(JSON.stringify(field)); |
| | | // 设置自定义类型 |
| | | this.$set(this.formFieldForm, "typeType", !this.fieldType[field.type] ? "custom" : field.type); |
| | | // 初始化枚举值列表 |
| | | field.type === "enum" && (this.fieldEnumList = JSON.parse(JSON.stringify(FieldObject?.values || []))); |
| | | // 初始化约束条件列表 |
| | | this.fieldConstraintsList = JSON.parse(JSON.stringify(FieldObject?.validation?.constraints || [])); |
| | | // 初始化自定义属性列表 |
| | | this.fieldPropertiesList = JSON.parse(JSON.stringify(FieldObject?.properties?.values || [])); |
| | | } else { |
| | | this.formFieldForm = {}; |
| | | // 初始化枚举值列表 |
| | | this.fieldEnumList = []; |
| | | // 初始化约束条件列表 |
| | | this.fieldConstraintsList = []; |
| | | // 初始化自定义属性列表 |
| | | this.fieldPropertiesList = []; |
| | | } |
| | | this.fieldModelVisible = true; |
| | | }, |
| | | // 打开字段 某个 配置项 弹窗 |
| | | openFieldOptionForm(option, index, type) { |
| | | this.fieldOptionModelVisible = true; |
| | | this.fieldOptionType = type; |
| | | this.formFieldOptionIndex = index; |
| | | if (type === "property") { |
| | | this.fieldOptionForm = option ? JSON.parse(JSON.stringify(option)) : {}; |
| | | return (this.optionModelTitle = "属性配置"); |
| | | } |
| | | if (type === "enum") { |
| | | this.fieldOptionForm = option ? JSON.parse(JSON.stringify(option)) : {}; |
| | | return (this.optionModelTitle = "枚举值配置"); |
| | | } |
| | | this.fieldOptionForm = option ? JSON.parse(JSON.stringify(option)) : {}; |
| | | return (this.optionModelTitle = "约束条件配置"); |
| | | }, |
| | | |
| | | // 保存字段 某个 配置项 |
| | | saveFieldOption() { |
| | | if (this.formFieldOptionIndex === -1) { |
| | | if (this.fieldOptionType === "property") { |
| | | this.fieldPropertiesList.push(this.fieldOptionForm); |
| | | } |
| | | if (this.fieldOptionType === "constraint") { |
| | | this.fieldConstraintsList.push(this.fieldOptionForm); |
| | | } |
| | | if (this.fieldOptionType === "enum") { |
| | | this.fieldEnumList.push(this.fieldOptionForm); |
| | | } |
| | | } else { |
| | | this.fieldOptionType === "property" && this.fieldPropertiesList.splice(this.formFieldOptionIndex, 1, this.fieldOptionForm); |
| | | this.fieldOptionType === "constraint" && this.fieldConstraintsList.splice(this.formFieldOptionIndex, 1, this.fieldOptionForm); |
| | | this.fieldOptionType === "enum" && this.fieldEnumList.splice(this.formFieldOptionIndex, 1, this.fieldOptionForm); |
| | | } |
| | | this.fieldOptionModelVisible = false; |
| | | this.fieldOptionForm = {}; |
| | | }, |
| | | // 保存字段配置 |
| | | saveField() { |
| | | const { id, type, label, defaultValue, datePattern } = this.formFieldForm; |
| | | const Field = window.bpmnInstances.moddle.create(`${this.prefix}:FormField`, { id, type, label }); |
| | | defaultValue && (Field.defaultValue = defaultValue); |
| | | datePattern && (Field.datePattern = datePattern); |
| | | // 构建属性 |
| | | if (this.fieldPropertiesList && this.fieldPropertiesList.length) { |
| | | const fieldPropertyList = this.fieldPropertiesList.map(fp => { |
| | | return window.bpmnInstances.moddle.create(`${this.prefix}:Property`, { id: fp.id, value: fp.value }); |
| | | }); |
| | | Field.properties = window.bpmnInstances.moddle.create(`${this.prefix}:Properties`, { values: fieldPropertyList }); |
| | | } |
| | | // 构建校验规则 |
| | | if (this.fieldConstraintsList && this.fieldConstraintsList.length) { |
| | | const fieldConstraintList = this.fieldConstraintsList.map(fc => { |
| | | return window.bpmnInstances.moddle.create(`${this.prefix}:Constraint`, { name: fc.name, config: fc.config }); |
| | | }); |
| | | Field.validation = window.bpmnInstances.moddle.create(`${this.prefix}:Validation`, { constraints: fieldConstraintList }); |
| | | } |
| | | // 构建枚举值 |
| | | if (this.fieldEnumList && this.fieldEnumList.length) { |
| | | Field.values = this.fieldEnumList.map(fe => { |
| | | return window.bpmnInstances.moddle.create(`${this.prefix}:Value`, { name: fe.name, id: fe.id }); |
| | | }); |
| | | } |
| | | // 更新数组 与 表单配置实例 |
| | | if (this.formFieldIndex === -1) { |
| | | this.fieldList.push(this.formFieldForm); |
| | | this.formData.fields.push(Field); |
| | | } else { |
| | | this.fieldList.splice(this.formFieldIndex, 1, this.formFieldForm); |
| | | this.formData.fields.splice(this.formFieldIndex, 1, Field); |
| | | } |
| | | this.updateElementExtensions(); |
| | | this.fieldModelVisible = false; |
| | | }, |
| | | |
| | | // 移除某个 字段的 配置项 |
| | | removeFieldOptionItem(option, index, type) { |
| | | if (type === "property") { |
| | | this.fieldPropertiesList.splice(index, 1); |
| | | return; |
| | | } |
| | | if (type === "enum") { |
| | | this.fieldEnumList.splice(index, 1); |
| | | return; |
| | | } |
| | | this.fieldConstraintsList.splice(index, 1); |
| | | }, |
| | | // 移除 字段 |
| | | removeField(field, index) { |
| | | this.fieldList.splice(index, 1); |
| | | this.formData.fields.splice(index, 1); |
| | | this.updateElementExtensions(); |
| | | }, |
| | | |
| | | updateElementExtensions() { |
| | | // 更新回扩展元素 |
| | | const newElExtensionElements = window.bpmnInstances.moddle.create(`bpmn:ExtensionElements`, { |
| | | values: this.otherExtensions.concat(this.formData) |
| | | }); |
| | | // 更新到元素上 |
| | | window.bpmnInstances.modeling.updateProperties(this.bpmnELement, { |
| | | extensionElements: newElExtensionElements |
| | | }); |
| | | } |
| | | } |
| | | }; |
| | | </script> |
| | |
| | | <template> |
| | | <div class="panel-tab__content"> |
| | | <el-form size="mini" label-width="90px" @submit.native.prevent> |
| | | <el-form-item label="异步延续"> |
| | | <el-checkbox v-model="taskConfigForm.asyncBefore" label="异步前" @change="changeTaskAsync" /> |
| | | <el-checkbox v-model="taskConfigForm.asyncAfter" label="异步后" @change="changeTaskAsync" /> |
| | | <el-checkbox v-model="taskConfigForm.exclusive" v-if="taskConfigForm.asyncAfter || taskConfigForm.asyncBefore" label="排除" @change="changeTaskAsync" /> |
| | | </el-form-item> |
| | | <!-- <el-form-item label="异步延续">--> |
| | | <!-- <el-checkbox v-model="taskConfigForm.asyncBefore" label="异步前" @change="changeTaskAsync" />--> |
| | | <!-- <el-checkbox v-model="taskConfigForm.asyncAfter" label="异步后" @change="changeTaskAsync" />--> |
| | | <!-- <el-checkbox v-model="taskConfigForm.exclusive" v-if="taskConfigForm.asyncAfter || taskConfigForm.asyncBefore" label="排除" @change="changeTaskAsync" />--> |
| | | <!-- </el-form-item>--> |
| | | <component :is="witchTaskComponent" v-bind="$props" /> |
| | | </el-form> |
| | | </div> |
对比新文件 |
| | |
| | | <!-- 表达式选择 --> |
| | | <template> |
| | | <Dialog title="请选择表达式" v-model="dialogVisible" width="1024px"> |
| | | <ContentWrap> |
| | | <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> |
| | | <el-table-column label="名字" align="center" prop="name" /> |
| | | <el-table-column label="表达式" align="center" prop="expression" /> |
| | | <el-table-column label="操作" align="center"> |
| | | <template #default="scope"> |
| | | <el-button link type="primary" @click="select(scope.row)"> 选择 </el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <!-- 分页 --> |
| | | <Pagination |
| | | :total="total" |
| | | v-model:page="queryParams.pageNo" |
| | | v-model:limit="queryParams.pageSize" |
| | | @pagination="getList" |
| | | /> |
| | | </ContentWrap> |
| | | </Dialog> |
| | | </template> |
| | | <script> |
| | | |
| | | import { getProcessExpressionPage } from '@/api/bpm/processExpression' |
| | | import { CommonStatusEnum } from '@/utils/constants' |
| | | |
| | | export default { |
| | | name: "ProcessExpressionDialog", |
| | | data() { |
| | | return { |
| | | dialogVisible: false, |
| | | loading: true, |
| | | list: [], |
| | | total: 0, |
| | | queryParams: { |
| | | pageNo: 1, |
| | | pageSize: 10, |
| | | type: '', |
| | | status: CommonStatusEnum.ENABLE |
| | | } |
| | | } |
| | | }, |
| | | methods: { |
| | | /** 打开弹窗 */ |
| | | open() { |
| | | this.queryParams.pageNo = 1 |
| | | this.queryParams.type = type |
| | | this.getList() |
| | | this.dialogVisible = true |
| | | }, |
| | | /** 查询列表 */ |
| | | getList() { |
| | | getProcessExpressionPage(this.queryParams).then(response => { |
| | | this.list = response.data.list; |
| | | this.total = response.data.total; |
| | | this.loading = false; |
| | | }) |
| | | }, |
| | | /** 提交表单 */ |
| | | select(row) { |
| | | this.dialogVisible = false |
| | | const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 |
| | | emit('select', row) |
| | | } |
| | | }, |
| | | } |
| | | |
| | | </script> |
| | |
| | | <template> |
| | | <div style="margin-top: 16px"> |
| | | <!-- <el-form-item label="处理用户">--> |
| | | <!-- <el-select v-model="userTaskForm.assignee" @change="updateElementTask('assignee')">--> |
| | | <!-- <el-option v-for="ak in mockData" :key="'ass-' + ak" :label="`用户${ak}`" :value="`user${ak}`" />--> |
| | | <!-- </el-select>--> |
| | | <!-- </el-form-item>--> |
| | | <!-- <el-form-item label="候选用户">--> |
| | | <!-- <el-select v-model="userTaskForm.candidateUsers" multiple collapse-tags @change="updateElementTask('candidateUsers')">--> |
| | | <!-- <el-option v-for="uk in mockData" :key="'user-' + uk" :label="`用户${uk}`" :value="`user${uk}`" />--> |
| | | <!-- </el-select>--> |
| | | <!-- </el-form-item>--> |
| | | <!-- <el-form-item label="候选分组">--> |
| | | <!-- <el-select v-model="userTaskForm.candidateGroups" multiple collapse-tags @change="updateElementTask('candidateGroups')">--> |
| | | <!-- <el-option v-for="gk in mockData" :key="'ass-' + gk" :label="`分组${gk}`" :value="`group${gk}`" />--> |
| | | <!-- </el-select>--> |
| | | <!-- </el-form-item>--> |
| | | <el-form-item label="到期时间"> |
| | | <el-input v-model="userTaskForm.dueDate" clearable @change="updateElementTask('dueDate')" /> |
| | | <el-form label-width="100px"> |
| | | <el-form-item label="规则类型" prop="candidateStrategy"> |
| | | <el-select |
| | | v-model="userTaskForm.candidateStrategy" |
| | | clearable |
| | | style="width: 100%" |
| | | @change="changeCandidateStrategy" |
| | | > |
| | | <el-option |
| | | v-for="dict in ruleOptions" |
| | | :key="dict.value" |
| | | :label="dict.label" |
| | | :value="dict.value" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="跟踪时间"> |
| | | <el-input v-model="userTaskForm.followUpDate" clearable @change="updateElementTask('followUpDate')" /> |
| | | <el-form-item |
| | | v-if="userTaskForm.candidateStrategy == 10" |
| | | label="指定角色" |
| | | prop="candidateParam" |
| | | > |
| | | <el-select |
| | | v-model="userTaskForm.candidateParam" |
| | | clearable |
| | | multiple |
| | | style="width: 100%" |
| | | @change="updateElementTask" |
| | | > |
| | | <el-option v-for="item in roleOptions" :key="item.id" :label="item.name" :value="item.id" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="优先级"> |
| | | <el-input v-model="userTaskForm.priority" clearable @change="updateElementTask('priority')" /> |
| | | <el-form-item |
| | | v-if="userTaskForm.candidateStrategy == 20 || userTaskForm.candidateStrategy == 21" |
| | | label="指定部门" |
| | | prop="candidateParam" |
| | | span="24" |
| | | > |
| | | <!-- 多选 --> |
| | | <el-select ref="selectForm" v-model="userTaskForm.candidateParam" placeholder="请选择"> |
| | | <el-option :value="treeDataValue" style="height: auto"> |
| | | <el-tree |
| | | ref="treeForm" |
| | | :data="deptTreeOptions" |
| | | node-key="id" |
| | | :props="defaultProps" |
| | | highlight-current |
| | | @node-click="selectDept" |
| | | /> |
| | | </el-option> |
| | | </el-select> |
| | | |
| | | <!-- <el-select ref="selectForm" v-model="userTaskForm.candidateParam" placeholder="请选择" clearable multiple>--> |
| | | <!-- <el-option hidden :key="1"></el-option>--> |
| | | <!-- <el-tree--> |
| | | <!-- ref="treeForm"--> |
| | | <!-- :data="deptTreeOptions"--> |
| | | <!-- :props="defaultProps"--> |
| | | <!-- empty-text="加载中,请稍后"--> |
| | | <!-- multiple--> |
| | | <!-- node-key="id"--> |
| | | <!-- show-checkbox--> |
| | | <!-- highlight-current--> |
| | | <!-- @check-change="selectDept"--> |
| | | <!-- />--> |
| | | <!-- </el-select>--> |
| | | </el-form-item> |
| | | 友情提示:任务的分配规则,使用 |
| | | <router-link target="_blank" :to="{path:'/bpm/manager/model'}"><el-link type="danger">流程模型</el-link> </router-link> |
| | | 下的【分配规则】替代,提供指定角色、部门负责人、部门成员、岗位、工作组、自定义脚本等 7 种维护的任务分配维度,更加灵活! |
| | | </div> |
| | | <el-form-item |
| | | v-if="userTaskForm.candidateStrategy == 22" |
| | | label="指定岗位" |
| | | prop="candidateParam" |
| | | span="24" |
| | | > |
| | | <el-select |
| | | v-model="userTaskForm.candidateParam" |
| | | clearable |
| | | multiple |
| | | style="width: 100%" |
| | | @change="updateElementTask" |
| | | > |
| | | <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="userTaskForm.candidateStrategy == 30" |
| | | label="指定用户" |
| | | prop="candidateParam" |
| | | span="24" |
| | | > |
| | | <el-select |
| | | v-model="userTaskForm.candidateParam" |
| | | clearable |
| | | multiple |
| | | style="width: 100%" |
| | | @change="updateElementTask" |
| | | > |
| | | <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="userTaskForm.candidateStrategy === 40" |
| | | label="指定用户组" |
| | | prop="candidateParam" |
| | | > |
| | | <el-select |
| | | v-model="userTaskForm.candidateParam" |
| | | clearable |
| | | multiple |
| | | style="width: 100%" |
| | | @change="updateElementTask" |
| | | > |
| | | <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="userTaskForm.candidateStrategy === 60" |
| | | label="流程表达式" |
| | | prop="candidateParam" |
| | | > |
| | | <el-input |
| | | type="textarea" |
| | | v-model="userTaskForm.candidateParam[0]" |
| | | clearable |
| | | style="width: 72%" |
| | | @change="updateElementTask" |
| | | /> |
| | | <el-button class="ml-5px" size="small" type="success" @click="openProcessExpressionDialog" |
| | | >选择表达式</el-button |
| | | > |
| | | <!-- 选择弹窗 --> |
| | | <ProcessExpressionDialog ref="processExpressionDialogRef" @select="selectProcessExpression" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | </template> |
| | | |
| | | <script> |
| | | import { DICT_TYPE, getDictDatas } from '@/utils/dict' |
| | | import { getRole, listSimpleRoles } from '@/api/system/role' |
| | | import { listSimpleDepts } from '@/api/system/dept' |
| | | import { listSimplePosts } from '@/api/system/post' |
| | | import { listSimpleUsers } from '@/api/system/user' |
| | | import { listSimpleUserGroups } from '@/api/bpm/userGroup' |
| | | import ProcessExpressionDialog from './ProcessExpressionDialog.vue' |
| | | import SelectTree from '@/components/SelectTree/index.vue' |
| | | |
| | | export default { |
| | | name: "UserTask", |
| | | components: { SelectTree, ProcessExpressionDialog }, |
| | | computed: { |
| | | DICT_TYPE() { |
| | | return DICT_TYPE |
| | | }, |
| | | }, |
| | | props: { |
| | | id: String, |
| | | type: String |
| | |
| | | followUpDate: "", |
| | | priority: "" |
| | | }, |
| | | userTaskForm: {}, |
| | | mockData: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] |
| | | defaultProps: { |
| | | children: 'children', |
| | | label: 'name', |
| | | value: 'id', |
| | | isLeaf: 'leaf', |
| | | emitPath: false // 用于 cascader 组件:在选中节点改变时,是否返回由该节点所在的各级菜单的值所组成的数组,若设置 false,则只返回该节点的值 |
| | | }, |
| | | userTaskForm: { |
| | | candidateStrategy: undefined, // 分配规则 |
| | | candidateParam: [] // 分配选项 |
| | | }, |
| | | bpmnElement: Object, |
| | | ruleOptions: [], |
| | | roleOptions: [], |
| | | deptTreeOptions: [], |
| | | postOptions: [], |
| | | userOptions: [], |
| | | userGroupOptions: [], |
| | | treeDataValue: '', |
| | | form: { |
| | | // treeData: "", // 单选 |
| | | treeData: [], // 多选 |
| | | }, |
| | | }; |
| | | }, |
| | | watch: { |
| | |
| | | } |
| | | } |
| | | }, |
| | | created() { |
| | | this.getDictDatas(); |
| | | this.getRoles(); |
| | | this.getDepts(); |
| | | this.getPosts(); |
| | | this.getUsers(); |
| | | this.getUserGroups(); |
| | | }, |
| | | methods: { |
| | | resetTaskForm() { |
| | | for (let key in this.defaultTaskForm) { |
| | | let value; |
| | | if (key === "candidateUsers" || key === "candidateGroups") { |
| | | value = this.bpmnElement?.businessObject[key] ? this.bpmnElement.businessObject[key].split(",") : []; |
| | | } else { |
| | | value = this.bpmnElement?.businessObject[key] || this.defaultTaskForm[key]; |
| | | } |
| | | this.$set(this.userTaskForm, key, value); |
| | | } |
| | | getDictDatas() { |
| | | this.ruleOptions = getDictDatas(DICT_TYPE.BPM_TASK_CANDIDATE_STRATEGY) |
| | | }, |
| | | updateElementTask(key) { |
| | | const taskAttr = Object.create(null); |
| | | if (key === "candidateUsers" || key === "candidateGroups") { |
| | | taskAttr[key] = this.userTaskForm[key] && this.userTaskForm[key].length ? this.userTaskForm[key].join() : null; |
| | | } else { |
| | | taskAttr[key] = this.userTaskForm[key] || null; |
| | | // 获得角色列表 |
| | | getRoles() { |
| | | listSimpleRoles().then(response => { |
| | | // 处理 roleOptions 参数 |
| | | this.roleOptions = []; |
| | | this.roleOptions = response.data; |
| | | }) |
| | | }, |
| | | getDepts() { |
| | | // 获得部门列表 |
| | | listSimpleDepts().then(response => { |
| | | // 处理 deptOptions 参数 |
| | | this.deptTreeOptions.push(...this.handleTree(response.data, "id")); |
| | | // console.log(this.deptTreeOptions) |
| | | }); |
| | | }, |
| | | getPosts() { |
| | | listSimplePosts().then(response => { |
| | | // 处理 postOptions 参数 |
| | | this.postOptions = []; |
| | | this.postOptions = response.data; |
| | | }); |
| | | }, |
| | | getUsers() { |
| | | listSimpleUsers().then(response => { |
| | | this.userOptions = response.data; |
| | | }); |
| | | }, |
| | | getUserGroups() { |
| | | listSimpleUserGroups().then(response => { |
| | | this.userGroupOptions = response.data; |
| | | }); |
| | | }, |
| | | changeCandidateStrategy() { |
| | | this.userTaskForm.candidateParam = [] |
| | | this.updateElementTask() |
| | | }, |
| | | resetTaskForm() { |
| | | const businessObject = this.bpmnElement.businessObject |
| | | if (!businessObject) { |
| | | return |
| | | } |
| | | window.bpmnInstances.modeling.updateProperties(this.bpmnElement, taskAttr); |
| | | } |
| | | console.log(businessObject) |
| | | console.log(businessObject.$attrs['flowable:candidateParam']) |
| | | if (businessObject.$attrs.candidateStrategy != undefined) { |
| | | this.userTaskForm.candidateStrategy = businessObject.$attrs['flowable:candidateStrategy'] |
| | | } else { |
| | | this.userTaskForm.candidateStrategy = undefined |
| | | } |
| | | if (businessObject.$attrs['flowable:candidateParam'] && businessObject.$attrs['flowable:candidateParam'].length > 0) { |
| | | this.userTaskForm.candidateStrategy = businessObject.$attrs['flowable:candidateStrategy'] |
| | | if (this.userTaskForm.candidateStrategy === 60) { |
| | | // 特殊:流程表达式,只有一个 input 输入框 |
| | | this.userTaskForm.candidateParam = [businessObject.$attrs['flowable:candidateParam']] |
| | | } else { |
| | | this.userTaskForm.candidateParam = businessObject.$attrs['flowable:candidateParam'] |
| | | .split(',') |
| | | .map((item) => +item) |
| | | } |
| | | } else { |
| | | this.userTaskForm.candidateParam = [] |
| | | } |
| | | console.log(this.userTaskForm) |
| | | }, |
| | | selectDept(data, checked, indeterminate) { |
| | | console.log(this.userTaskForm.candidateParam) |
| | | console.log(data) |
| | | console.log(checked) |
| | | console.log(indeterminate) |
| | | this.treeDataValue = data |
| | | this.userTaskForm.candidateParam.push(data.name) |
| | | this.form.treeData.push(data.name) |
| | | this.updateElementTask() |
| | | }, |
| | | updateElementTask() { |
| | | console.log(this.userTaskForm) |
| | | console.log(this.bpmnElement) |
| | | window.bpmnInstances.modeling.updateProperties(this.bpmnElement, { |
| | | candidateStrategy: this.userTaskForm.candidateStrategy, |
| | | candidateParam: this.userTaskForm.candidateParam.join(',') |
| | | }); |
| | | }, |
| | | openProcessExpressionDialog() { |
| | | this.$refs('processExpressionDialogRef').open() |
| | | }, |
| | | selectProcessExpression(expression) { |
| | | this.userTaskForm.candidateParam = [expression.expression] |
| | | this.updateElementTask() |
| | | }, |
| | | }, |
| | | beforeDestroy() { |
| | | this.bpmnElement = null; |
| | |
| | | Vue.use(VueMeta) |
| | | // Vue.use(hljs.vuePlugin); |
| | | |
| | | import _ from 'lodash' |
| | | Vue.prototype._ = _ |
| | | |
| | | // bpmnProcessDesigner 需要引入 |
| | | import MyPD from "@/components/bpmnProcessDesigner/package/index.js"; |
| | | Vue.use(MyPD); |
| | |
| | | i18n: (key, value) => i18n.t(key, value) |
| | | }); |
| | | |
| | | // import ElementPlus from 'element-plus' |
| | | // import 'element-plus/dist/index.css' |
| | | // |
| | | // Vue.use(ElementPlus) |
| | | |
| | | Vue.config.productionTip = false |
| | | |
| | | new Vue({ |
| | |
| | | SYSTEM_ROLE_TYPE: 'system_role_type', |
| | | SYSTEM_DATA_SCOPE: 'system_data_scope', |
| | | SYSTEM_NOTICE_TYPE: 'system_notice_type', |
| | | SYSTEM_OPERATE_TYPE: 'system_operate_type', |
| | | SYSTEM_LOGIN_TYPE: 'system_login_type', |
| | | SYSTEM_LOGIN_RESULT: 'system_login_result', |
| | | SYSTEM_SMS_CHANNEL_CODE: 'system_sms_channel_code', |
| | |
| | | INFRA_CODEGEN_FRONT_TYPE: 'infra_codegen_front_type', |
| | | INFRA_CODEGEN_SCENE: 'infra_codegen_scene', |
| | | INFRA_FILE_STORAGE: 'infra_file_storage', |
| | | INFRA_OPERATE_TYPE: 'infra_operate_type', |
| | | |
| | | // ========== BPM 模块 ========== |
| | | BPM_MODEL_CATEGORY: 'bpm_model_category', |
| | | BPM_MODEL_FORM_TYPE: 'bpm_model_form_type', |
| | | BPM_TASK_CANDIDATE_STRATEGY: 'bpm_task_candidate_strategy', |
| | | BPM_TASK_ASSIGN_RULE_TYPE: 'bpm_task_assign_rule_type', |
| | | BPM_PROCESS_INSTANCE_STATUS: 'bpm_process_instance_status', |
| | | BPM_TASK_STATUS: 'bpm_task_status', |
| | | BPM_PROCESS_INSTANCE_RESULT: 'bpm_process_instance_result', |
| | | BPM_TASK_ASSIGN_SCRIPT: 'bpm_task_assign_script', |
| | | BPM_OA_LEAVE_TYPE: 'bpm_oa_leave_type', |
| | |
| | | |
| | | return drawingList |
| | | } |
| | | // // 解码表单 Fields |
| | | // export function decodeFields2(fields) { |
| | | // const rule = [] |
| | | // fields.forEach((item) => { |
| | | // rule.push(JSON.parse(item)) |
| | | // }) |
| | | // return rule |
| | | // } |
| | | // // 设置表单的 Conf 和 Fields,适用 form-create 场景 |
| | | // export function setConfAndFields2 (detailPreview, conf, fields, value) { |
| | | // detailPreview = detailPreview.value |
| | | // detailPreview.option = JSON.parse(conf) |
| | | // detailPreview.rule = decodeFields2(fields) |
| | | // if (value) { |
| | | // detailPreview.value = value |
| | | // } |
| | | // } |
| | |
| | | <!-- 列表 --> |
| | | <el-table v-loading="loading" :data="list"> |
| | | <el-table-column label="定义编号" align="center" prop="id" width="400" /> |
| | | <el-table-column label="定义名称" align="center" prop="name" width="100"> |
| | | <el-table-column label="流程名称" align="center" prop="name"> |
| | | <template v-slot="scope"> |
| | | <el-button type="text" @click="handleBpmnDetail(scope.row)"> |
| | | <span>{{ scope.row.name }}</span> |
| | |
| | | <span>{{ parseTime(scope.row.deploymentTime) }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="定义描述" align="center" prop="description" width="300" show-overflow-tooltip /> |
| | | <el-table-column label="操作" align="center" width="150" fixed="right"> |
| | | <template v-slot="scope"> |
| | | <el-button size="mini" type="text" icon="el-icon-s-custom" @click="handleAssignRule(scope.row)" |
| | | v-hasPermi="['bpm:task-assign-rule:update']">分配规则</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="定义描述" align="center" prop="description" width="200" show-overflow-tooltip /> |
| | | <!-- <el-table-column label="操作" align="center" width="150" fixed="right">--> |
| | | <!-- <template v-slot="scope">--> |
| | | <!-- <el-button size="mini" type="text" icon="el-icon-s-custom" @click="handleAssignRule(scope.row)"--> |
| | | <!-- v-hasPermi="['bpm:task-assign-rule:update']">分配规则</el-button>--> |
| | | <!-- </template>--> |
| | | <!-- </el-table-column>--> |
| | | </el-table> |
| | | |
| | | <!-- 流程表单配置详情 --> |
| | |
| | | v-hasPermi="['bpm:model:update']">修改流程</el-button> |
| | | <el-button size="mini" type="text" icon="el-icon-setting" @click="handleDesign(scope.row)" |
| | | v-hasPermi="['bpm:model:update']">设计流程</el-button> |
| | | <el-button size="mini" type="text" icon="el-icon-s-custom" @click="handleAssignRule(scope.row)" |
| | | v-hasPermi="['bpm:task-assign-rule:query']">分配规则</el-button> |
| | | <!-- <el-button size="mini" type="text" icon="el-icon-s-custom" @click="handleAssignRule(scope.row)"--> |
| | | <!-- v-hasPermi="['bpm:task-assign-rule:query']">分配规则</el-button>--> |
| | | <el-button size="mini" type="text" icon="el-icon-thumb" @click="handleDeploy(scope.row)" |
| | | v-hasPermi="['bpm:model:deploy']">发布流程</el-button> |
| | | <el-button size="mini" type="text" icon="el-icon-ice-cream-round" @click="handleDefinitionList(scope.row)" |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <!-- 第一步,通过流程定义的列表,选择对应的流程 --> |
| | | <div v-if="!selectProcessInstance"> |
| | | <div v-if="!selectProcessDefinition"> |
| | | <el-table v-loading="loading" :data="list"> |
| | | <el-table-column label="流程名称" align="center" prop="name" width="200"> |
| | | <template v-slot="scope"> |
| | |
| | | <div v-else> |
| | | <el-card class="box-card" > |
| | | <div slot="header" class="clearfix"> |
| | | <span class="el-icon-document">申请信息【{{ selectProcessInstance.name }}】</span> |
| | | <el-button style="float: right;" type="primary" @click="selectProcessInstance = undefined">选择其它流程</el-button> |
| | | <span class="el-icon-document">申请信息【{{ selectProcessDefinition.name }}】</span> |
| | | <el-button style="float: right;" type="primary" @click="selectProcessDefinition = undefined">选择其它流程</el-button> |
| | | </div> |
| | | <el-col :span="16" :offset="6"> |
| | | <div> |
| | |
| | | <script> |
| | | import {getProcessDefinitionBpmnXML, getProcessDefinitionList} from "@/api/bpm/definition"; |
| | | import {DICT_TYPE, getDictDatas} from "@/utils/dict"; |
| | | import {decodeFields} from "@/utils/formGenerator"; |
| | | import { decodeFields, setConfAndFields2 } from '@/utils/formGenerator' |
| | | import Parser from '@/components/parser/Parser' |
| | | import {createProcessInstance} from "@/api/bpm/processInstance"; |
| | | import { createProcessInstance, getProcessInstance } from '@/api/bpm/processInstance' |
| | | import { listSimpleUsers } from '@/api/system/user' |
| | | |
| | | // 流程实例的发起 |
| | | export default { |
| | |
| | | loading: true, |
| | | // 表格数据 |
| | | list: [], |
| | | |
| | | processInstanceId: this.$route.query.processInstanceId, |
| | | // 流程表单详情 |
| | | detailForm: { |
| | | fields: [] |
| | | fields: [], |
| | | rule: [], |
| | | option: {}, |
| | | value: {} |
| | | }, |
| | | |
| | | // BPMN 数据 |
| | |
| | | |
| | | // 流程表单 |
| | | selectProcessInstance: undefined, // 选择的流程实例 |
| | | startUserSelectTasks: [], |
| | | startUserSelectAssignees: {}, |
| | | startUserSelectAssigneesFormRules: {}, |
| | | selectProcessDefinition: undefined, |
| | | userList: [], |
| | | |
| | | // 数据字典 |
| | | categoryDictDatas: getDictDatas(DICT_TYPE.BPM_MODEL_CATEGORY), |
| | |
| | | this.loading = false |
| | | } |
| | | ); |
| | | // 如果 processInstanceId 非空,说明是重新发起 |
| | | if (this.processInstanceId?.length > 0) { |
| | | let processInstance |
| | | getProcessInstance(this.processInstanceId).then(response => { |
| | | processInstance = response.data |
| | | this.selectProcessInstance = response.data |
| | | if (!processInstance) { |
| | | this.$modal.msgError('重新发起流程失败,原因:流程实例不存在') |
| | | return |
| | | } |
| | | const processDefinition = this.list.find(item => item.key == processInstance.processDefinition?.key |
| | | ) |
| | | if (!processDefinition) { |
| | | this.$modal.msgError('重新发起流程失败,原因:流程定义不存在') |
| | | return |
| | | } |
| | | this.handleSelect(processDefinition, processInstance.formVariables) |
| | | }) |
| | | } |
| | | }, |
| | | /** 处理选择流程的按钮操作 **/ |
| | | handleSelect(row) { |
| | | handleSelect(row, formVariables) { |
| | | console.log(row) |
| | | // 设置选择的流程 |
| | | this.selectProcessInstance = row; |
| | | |
| | | // 流程表单 |
| | | if (row.formId) { |
| | | this.selectProcessDefinition = row |
| | | // 重置指定审批人 |
| | | this.startUserSelectTasks = [] |
| | | this.startUserSelectAssignees = {} |
| | | this.startUserSelectAssigneesFormRules = {} |
| | | // 情况一:流程表单 |
| | | if (row.formType == 10) { |
| | | // 设置表单 |
| | | // 设置对应的表单 |
| | | this.detailForm = { |
| | | ...JSON.parse(row.formConf), |
| | | fields: decodeFields(row.formFields) |
| | | fields: decodeFields(row.formFields, formVariables) |
| | | } |
| | | |
| | | // 加载流程图 |
| | | getProcessDefinitionBpmnXML(row.id).then(response => { |
| | | this.bpmnXML = response.data.bpmnXml |
| | | const processDefinitionDetail = response.data |
| | | if (processDefinitionDetail) { |
| | | this.bpmnXML = processDefinitionDetail.bpmnXml |
| | | this.startUserSelectTasks = processDefinitionDetail.startUserSelectTasks |
| | | |
| | | // 设置指定审批人 |
| | | if (this.startUserSelectTasks?.length > 0) { |
| | | this.detailForm.rule.push({ |
| | | type: 'startUserSelect', |
| | | props: { |
| | | title: '指定审批人' |
| | | } |
| | | }) |
| | | // 设置校验规则 |
| | | for(const userTask of this.startUserSelectTasks) { |
| | | this.startUserSelectAssignees[userTask.id] = [] |
| | | this.startUserSelectAssigneesFormRules[userTask.id] = [ |
| | | { required: true, message: '请选择审批人', trigger: 'blur' } |
| | | ] |
| | | } |
| | | // 加载用户列表 |
| | | listSimpleUsers().then(response => { |
| | | this.userList = response.data |
| | | }) |
| | | } |
| | | } |
| | | }) |
| | | // 情况二:业务表单 |
| | | } else if (row.formCustomCreatePath) { |
| | | this.$router.push({ path: row.formCustomCreatePath}); |
| | | this.$router.push({ path: row.formCustomCreatePath}); |
| | | // 这里暂时无需加载流程图,因为跳出到另外个 Tab; |
| | | } |
| | | // 流程表单 |
| | | // if (row.formId) { |
| | | // // 设置对应的表单 |
| | | // this.detailForm = { |
| | | // ...JSON.parse(row.formConf), |
| | | // fields: decodeFields(row.formFields) |
| | | // } |
| | | // |
| | | // // 加载流程图 |
| | | // getProcessDefinitionBpmnXML(row.id).then(response => { |
| | | // this.bpmnXML = response.data.bpmnXml |
| | | // }) |
| | | // } else if (row.formCustomCreatePath) { |
| | | // this.$router.push({ path: row.formCustomCreatePath}); |
| | | // // 这里暂时无需加载流程图,因为跳出到另外个 Tab; |
| | | // } |
| | | }, |
| | | /** 提交按钮 */ |
| | | submitForm(params) { |
| | |
| | | // 提交表单,创建流程 |
| | | const variables = params.values; |
| | | createProcessInstance({ |
| | | processDefinitionId: this.selectProcessInstance.id, |
| | | processDefinitionId: this.selectProcessDefinition.id, |
| | | variables: variables |
| | | }).then(response => { |
| | | this.$modal.msgSuccess("发起流程成功"); |
| | |
| | | <el-col :span="16" :offset="4"> |
| | | <div class="block"> |
| | | <el-timeline> |
| | | <el-timeline-item v-for="(item, index) in tasks" :key="index" |
| | | :icon="getTimelineItemIcon(item)" :type="getTimelineItemType(item)"> |
| | | <p style="font-weight: 700">任务:{{ item.name }}</p> |
| | | <el-timeline-item |
| | | v-if="processInstance.endTime" |
| | | :type="getProcessInstanceTimelineItemType(processInstance)" |
| | | > |
| | | <p style="font-weight: 700"> |
| | | 结束流程:在 {{ parseTime(processInstance?.endTime) }} 结束 |
| | | <dict-tag |
| | | :type="DICT_TYPE.BPM_PROCESS_INSTANCE_STATUS" |
| | | :value="processInstance.status" |
| | | /> |
| | | </p> |
| | | </el-timeline-item> |
| | | <el-timeline-item v-for="(item, index) in tasks" :key="index" :type="getTaskTimelineItemType(item)"> |
| | | <p style="font-weight: 700"> |
| | | 审批任务:{{ item.name }} |
| | | <dict-tag :type="DICT_TYPE.BPM_TASK_STATUS" :value="item.status" /> |
| | | </p> |
| | | <!-- <el-button--> |
| | | <!-- class="ml-10px"--> |
| | | <!-- v-if="item.children"--> |
| | | <!-- @click="openChildrenTask(item)"--> |
| | | <!-- size="small"--> |
| | | <!-- >--> |
| | | <!-- <Icon icon="ep:memo" /> 子任务--> |
| | | <!-- </el-button>--> |
| | | <el-card :body-style="{ padding: '10px' }"> |
| | | <label v-if="item.assigneeUser" style="font-weight: normal; margin-right: 30px;"> |
| | | 审批人:{{ item.assigneeUser.nickname }} |
| | |
| | | <label v-if="item.durationInMillis" style="color:#8a909c;font-weight: normal"> |
| | | {{ getDateStar(item.durationInMillis) }} </label> |
| | | <p v-if="item.reason"> |
| | | <el-tag :type="getTimelineItemType(item)">{{ item.reason }}</el-tag> |
| | | <el-tag :type="getTaskTimelineItemType(item)">审批建议:{{ item.reason }}</el-tag> |
| | | </p> |
| | | </el-card> |
| | | </el-timeline-item> |
| | | <el-timeline-item type="success"> |
| | | <p style="font-weight: 700"> |
| | | 发起流程:【{{ processInstance.startUser?.nickname }}】在 |
| | | {{ parseTime(processInstance?.startTime) }} 发起【 {{ processInstance.name }} 】流程 |
| | | </p> |
| | | </el-timeline-item> |
| | | </el-timeline> |
| | | </div> |
| | |
| | | <div slot="header" class="clearfix"> |
| | | <span class="el-icon-picture-outline">流程图</span> |
| | | </div> |
| | | <my-process-viewer key="designer" v-model="bpmnXML" v-bind="bpmnControlForm" :activityData="activityList" |
| | | <my-process-viewer key="designer" v-model="bpmnXML" v-bind="bpmnControlForm" :prefix="bpmnControlForm.prefix" :activityData="activityList" |
| | | :processInstanceData="processInstance" :taskData="tasks"/> |
| | | </el-card> |
| | | |
| | |
| | | <el-option v-for="item in userOptions" :key="parseInt(item.id)" :label="item.nickname" |
| | | :value="parseInt(item.id)"/> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="转派理由" prop="reason"> |
| | | <el-input v-model="updateAssignee.form.reason" clearable placeholder="请输入转派理由" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <div slot="footer" class="dialog-footer"> |
| | |
| | | <!--退回流程--> |
| | | <el-dialog title="退回流程" :visible.sync="returnOpen" width="40%" append-to-body> |
| | | <el-form ref="formRef" v-loading="formLoading" :model="formData" :rules="formRules" label-width="110px"> |
| | | <el-form-item label="退回节点" prop="targetDefinitionKey"> |
| | | <el-select v-model="formData.targetDefinitionKey" clearable style="width: 100%"> |
| | | <el-form-item label="退回节点" prop="targetTaskDefinitionKey"> |
| | | <el-select v-model="formData.targetTaskDefinitionKey" clearable style="width: 100%"> |
| | | <el-option |
| | | v-for="item in returnList" |
| | | :key="item.definitionKey" |
| | | :key="item.taskDefinitionKey" |
| | | :label="item.name" |
| | | :value="item.definitionKey" |
| | | :value="item.taskDefinitionKey" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | |
| | | data() { |
| | | return { |
| | | // 遮罩层 |
| | | processInstanceLoading: true, |
| | | processInstanceLoading: false, |
| | | // 流程实例 |
| | | id: undefined, // 流程实例的编号 |
| | | processInstance: {}, |
| | |
| | | returnList: [], |
| | | formData: { |
| | | id: '', |
| | | targetDefinitionKey: undefined, |
| | | targetTaskDefinitionKey: undefined, |
| | | reason: '' |
| | | }, |
| | | formRules: { |
| | | targetDefinitionKey: [{required: true, message: '必须选择回退节点', trigger: 'change'}], |
| | | targetTaskDefinitionKey: [{required: true, message: '必须选择回退节点', trigger: 'change'}], |
| | | reason: [{required: true, message: '回退理由不能为空', trigger: 'blur'}] |
| | | }, |
| | | returnOpen: false, |
| | |
| | | // 设置流程信息 |
| | | this.processInstance = response.data; |
| | | |
| | | //将业务表单,注册为动态组件 |
| | | const path = this.processInstance.processDefinition.formCustomViewPath; |
| | | Vue.component("async-biz-form-component", function (resolve) { |
| | | require([`@/views${path}`], resolve); |
| | | }); |
| | | |
| | | // 设置表单信息 |
| | | if (this.processInstance.processDefinition.formType === 10) { |
| | | this.detailForm = { |
| | |
| | | item.__config__.defaultValue = val |
| | | } |
| | | }); |
| | | } else { |
| | | //将业务表单,注册为动态组件 |
| | | const path = this.processInstance.processDefinition.formCustomViewPath; |
| | | Vue.component("async-biz-form-component", function (resolve) { |
| | | require([`@/views${path}`], resolve); |
| | | }); |
| | | } |
| | | |
| | | // 加载流程图 |
| | | getProcessDefinitionBpmnXML(this.processInstance.processDefinition.id).then(response => { |
| | | this.bpmnXML = response.data |
| | | this.bpmnXML = response.data.bpmnXml |
| | | }); |
| | | // 加载活动列表 |
| | | getActivityList({ |
| | |
| | | }).then(response => { |
| | | this.activityList = response.data; |
| | | }); |
| | | |
| | | }).finally(() => { |
| | | // 取消加载中 |
| | | this.processInstanceLoading = false; |
| | | }); |
| | | }) |
| | | |
| | | // 获得流程任务列表(审批记录) |
| | | this.tasksLoad = true; |
| | |
| | | // 需要审核的记录 |
| | | const userId = store.getters.userId; |
| | | this.tasks.forEach(task => { |
| | | if (task.result !== 1 && task.result !== 6) { // 只有待处理才需要 |
| | | if (task.status !== 1 && task.status !== 6) { // 只有待处理才需要 |
| | | return; |
| | | } |
| | | if (!task.assigneeUser || task.assigneeUser.id !== userId) { // 自己不是处理人 |
| | |
| | | this.tasksLoad = false; |
| | | }); |
| | | }, |
| | | |
| | | /** 获得流程实例对应的颜色 */ |
| | | getProcessInstanceTimelineItemType(item) { |
| | | if (item.status === 2) { |
| | | return 'success' |
| | | } |
| | | if (item.status === 3) { |
| | | return 'danger' |
| | | } |
| | | if (item.status === 4) { |
| | | return 'warning' |
| | | } |
| | | return '' |
| | | }, |
| | | |
| | | /** 获得任务对应的颜色 */ |
| | | getTaskTimelineItemType(item) { |
| | | if ([0, 1, 6, 7].includes(item.status)) { |
| | | return 'primary' |
| | | } |
| | | if (item.status === 2) { |
| | | return 'success' |
| | | } |
| | | if (item.status === 3) { |
| | | return 'danger' |
| | | } |
| | | if (item.status === 4) { |
| | | return 'info' |
| | | } |
| | | if (item.status === 5) { |
| | | return 'warning' |
| | | } |
| | | return '' |
| | | }, |
| | | |
| | | getDateStar(ms) { |
| | | return getDate(ms); |
| | | }, |
| | | getTimelineItemIcon(item) { |
| | | if (item.result === 1) { |
| | | return 'el-icon-time'; |
| | | } |
| | | if (item.result === 2) { |
| | | return 'el-icon-check'; |
| | | } |
| | | if (item.result === 3) { |
| | | return 'el-icon-close'; |
| | | } |
| | | if (item.result === 4) { |
| | | return 'el-icon-remove-outline'; |
| | | } |
| | | if (item.result === 5) { |
| | | return 'el-icon-back' |
| | | } |
| | | return ''; |
| | | }, |
| | | getTimelineItemType(item) { |
| | | if (item.result === 1) { |
| | | return 'primary'; |
| | | } |
| | | if (item.result === 2) { |
| | | return 'success'; |
| | | } |
| | | if (item.result === 3) { |
| | | return 'danger'; |
| | | } |
| | | if (item.result === 4) { |
| | | return 'info'; |
| | | } |
| | | if (item.result === 5) { |
| | | return 'warning'; |
| | | } |
| | | if (item.result === 6) { |
| | | return 'default' |
| | | } |
| | | return ''; |
| | | }, |
| | | /** 处理审批通过和不通过的操作 */ |
| | | handleAudit(task, pass) { |
| | |
| | | }, |
| | | /** 提交退回任务 */ |
| | | submitReturn() { |
| | | if (!this.formData.targetDefinitionKey) { |
| | | if (!this.formData.targetTaskDefinitionKey) { |
| | | this.$modal.msgError("请选择退回节点!"); |
| | | } |
| | | this.$refs['formRef'].validate(valid => { |
| | |
| | | </el-form-item> |
| | | <el-form-item label="状态" prop="status"> |
| | | <el-select v-model="queryParams.status" placeholder="请选择状态" clearable> |
| | | <el-option v-for="dict in this.getDictDatas(DICT_TYPE.BPM_PROCESS_INSTANCE_STATUS)" |
| | | :key="dict.value" :label="dict.label" :value="dict.value"/> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="结果" prop="result"> |
| | | <el-select v-model="queryParams.result" placeholder="请选择流结果" clearable> |
| | | <el-option v-for="dict in this.getDictDatas(DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT)" |
| | | <el-option v-for="dict in this.getDictDatas(DICT_TYPE.BPM_TASK_STATUS)" |
| | | :key="dict.value" :label="dict.label" :value="dict.value"/> |
| | | </el-select> |
| | | </el-form-item> |
| | |
| | | <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="['bpm:process-instance:query']">发起流程</el-button> |
| | | v-hasPermi="['bpm:process-instance:add']">发起流程</el-button> |
| | | </el-col> |
| | | <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> |
| | | </el-row> |
| | | |
| | | <!-- 列表 --> |
| | | <el-table v-loading="loading" :data="list"> |
| | | <el-table-column label="编号" align="center" prop="id" width="320" /> |
| | | <el-table-column label="流程名" align="center" prop="name" /> |
| | | <el-table-column label="流程名称" align="center" prop="name" /> |
| | | <el-table-column label="流程分类" align="center" prop="category"> |
| | | <template v-slot="scope"> |
| | | <dict-tag :type="DICT_TYPE.BPM_MODEL_CATEGORY" :value="scope.row.category" /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="当前审批任务" align="center" prop="tasks"> |
| | | <el-table-column label="当前任务" align="center" prop="tasks"> |
| | | <template v-slot="scope"> |
| | | <el-button v-for="task in scope.row.tasks" :key="task.id" type="text""> |
| | | <span>{{ task.name }}</span> |
| | | <el-button v-for="task in scope.row.tasks" :key="task.id" type="text"> |
| | | <span>{{ task.name }} </span> |
| | | </el-button> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="状态" align="center" prop="status"> |
| | | <el-table-column label="流程状态" align="center" prop="status"> |
| | | <template v-slot="scope"> |
| | | <dict-tag :type="DICT_TYPE.BPM_PROCESS_INSTANCE_STATUS" :value="scope.row.status" /> |
| | | <dict-tag :type="DICT_TYPE.BPM_TASK_STATUS" :value="scope.row.status" /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="结果" align="center" prop="result"> |
| | | <el-table-column label="提交时间" align="center" prop="startTime" width="180"> |
| | | <template v-slot="scope"> |
| | | <dict-tag :type="DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT" :value="scope.row.result"/> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="提交时间" align="center" prop="createTime" width="180"> |
| | | <template v-slot="scope"> |
| | | <span>{{ parseTime(scope.row.createTime) }}</span> |
| | | <span>{{ parseTime(scope.row.startTime) }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="结束时间" align="center" prop="createTime" width="180"> |
| | |
| | | <span>{{ parseTime(scope.row.endTime) }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="耗时" align="center" prop="durationInMillis" width="180"> |
| | | <template v-slot="scope"> |
| | | <span>{{ getDateStar(scope.row.durationInMillis) }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="流程编号" align="center" prop="id" width="120" :show-overflow-tooltip="true" /> |
| | | <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> |
| | | <template v-slot="scope"> |
| | | <el-button type="text" size="small" icon="el-icon-delete" v-if="scope.row.result === 1" |
| | | v-hasPermi="['bpm:process-instance:cancel']" @click="handleCancel(scope.row)">取消</el-button> |
| | | <el-button size="mini" type="text" icon="el-icon-edit" @click="handleDetail(scope.row)" |
| | | v-hasPermi="['bpm:process-instance:query']">详情</el-button> |
| | | <el-button type="text" size="small" icon="el-icon-delete" v-if="scope.row.status === 1" |
| | | v-hasPermi="['bpm:process-instance:cancel']" @click="handleCancel(scope.row)">取消</el-button> |
| | | <el-button size="mini" type="text" icon="el-icon-plus" v-else @click="handleAdd(scope.row)" |
| | | v-hasPermi="['bpm:process-instance:create']">重新发起</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | |
| | | </template> |
| | | |
| | | <script> |
| | | import { getMyProcessInstancePage, cancelProcessInstance } from "@/api/bpm/processInstance"; |
| | | import { getMyProcessInstancePage, cancelProcessInstance, getProcessInstance } from '@/api/bpm/processInstance' |
| | | import { DICT_TYPE } from '@/utils/dict' |
| | | import { getDate } from '@/utils/dateUtils' |
| | | |
| | | export default { |
| | | name: "BpmProcessInstance", |
| | | computed: { |
| | | DICT_TYPE() { |
| | | return DICT_TYPE |
| | | } |
| | | }, |
| | | components: { |
| | | }, |
| | | data() { |
| | |
| | | this.handleQuery(); |
| | | }, |
| | | /** 新增按钮操作 **/ |
| | | handleAdd() { |
| | | this.$router.push({ name: "BpmProcessInstanceCreate"}) |
| | | handleAdd(row) { // 如果是【业务表单】,不支持重新发起 |
| | | if (row?.id) { |
| | | getProcessInstance(row.id).then(response => { |
| | | let processDefinitionDetail = response.data.processDefinition |
| | | if (processDefinitionDetail.formType === 20) { |
| | | this.$modal.msgError("重新发起流程失败,原因:该流程使用业务表单,不支持重新发起"); |
| | | return |
| | | } |
| | | }) |
| | | } |
| | | this.$router.push({ name: "BpmProcessInstanceCreate", query: {processInstanceId: row?.id}}) |
| | | }, |
| | | /** 取消按钮操作 */ |
| | | handleCancel(row) { |
| | |
| | | this.$modal.msgSuccess("取消成功"); |
| | | }) |
| | | }, |
| | | |
| | | getDateStar(ms) { |
| | | return getDate(ms); |
| | | }, |
| | | |
| | | /** 处理详情按钮 */ |
| | | handleDetail(row) { |
| | | this.$router.push({ name: "BpmProcessInstanceDetail", query: { id: row.id}}); |
| | |
| | | |
| | | <!-- 列表 --> |
| | | <el-table v-loading="loading" :data="list"> |
| | | <el-table-column label="任务编号" align="center" prop="id" width="320" fixed /> |
| | | <el-table-column label="任务名称" align="center" prop="name" width="200" /> |
| | | <el-table-column label="所属流程" align="center" prop="processInstance.name" width="200" /> |
| | | <el-table-column label="流程发起人" align="center" prop="processInstance.startUserNickname" width="120" /> |
| | | <el-table-column label="结果" align="center" prop="result"> |
| | | <template v-slot="scope"> |
| | | <dict-tag :type="DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT" :value="scope.row.result"/> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="审批意见" align="center" prop="reason" width="200" /> |
| | | <el-table-column label="创建时间" align="center" prop="createTime" width="180"> |
| | | <el-table-column label="发起人" align="center" prop="processInstance.startUser.nickname" width="120" /> |
| | | <el-table-column label="发起时间" align="center" prop="createTime" width="180"> |
| | | <template v-slot="scope"> |
| | | <span>{{ parseTime(scope.row.createTime) }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="当前任务" align="center" prop="name" width="200" /> |
| | | <el-table-column label="审批状态" align="center" prop="status"> |
| | | <template v-slot="scope"> |
| | | <dict-tag :type="DICT_TYPE.BPM_TASK_STATUS" :value="scope.row.status"/> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="审批建议" align="center" prop="reason" width="200" /> |
| | | <el-table-column label="审批时间" align="center" prop="endTime" width="180"> |
| | | <template v-slot="scope"> |
| | | <span>{{ parseTime(scope.row.endTime) }}</span> |
| | |
| | | <span>{{ getDateStar(scope.row.durationInMillis) }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="流程编号" align="center" prop="id" width="120" :show-overflow-tooltip="true" /> |
| | | <el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width"> |
| | | <template v-slot="scope"> |
| | | <el-button size="mini" type="text" icon="el-icon-edit" @click="handleAudit(scope.row)" |
| | |
| | | <script> |
| | | import {getDoneTaskPage} from '@/api/bpm/task' |
| | | import {getDate} from "@/utils/dateUtils"; |
| | | import { DICT_TYPE } from '@/utils/dict' |
| | | |
| | | export default { |
| | | name: "BpmDoneTask", |
| | | computed: { |
| | | DICT_TYPE() { |
| | | return DICT_TYPE |
| | | } |
| | | }, |
| | | components: { |
| | | }, |
| | | data() { |
| | |
| | | |
| | | <!-- 列表 --> |
| | | <el-table v-loading="loading" :data="list"> |
| | | <el-table-column label="任务编号" align="center" prop="id" width="320" /> |
| | | <el-table-column label="任务名称" align="center" prop="name" /> |
| | | <el-table-column label="所属流程" align="center" prop="processInstance.name" /> |
| | | <el-table-column label="流程发起人" align="center" prop="processInstance.startUserNickname" /> |
| | | <el-table-column label="创建时间" align="center" prop="createTime" width="180"> |
| | | <el-table-column label="发起人" align="center" prop="processInstance.startUser.nickname" /> |
| | | <el-table-column label="当前任务" align="center" prop="name" /> |
| | | <el-table-column label="发起时间" align="center" prop="createTime" width="180"> |
| | | <template v-slot="scope"> |
| | | <span>{{ parseTime(scope.row.createTime) }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="状态" align="center" prop="version" width="80"> |
| | | <!-- <el-table-column label="状态" align="center" prop="version" width="80">--> |
| | | <!-- <template v-slot="scope">--> |
| | | <!-- <el-tag type="success" v-if="scope.row.suspensionState === 1">激活</el-tag>--> |
| | | <!-- <el-tag type="warning" v-if="scope.row.suspensionState === 2">挂起</el-tag>--> |
| | | <!-- </template>--> |
| | | <!-- </el-table-column>--> |
| | | <el-table-column label="任务时间" align="center" prop="createTime" width="180"> |
| | | <template v-slot="scope"> |
| | | <el-tag type="success" v-if="scope.row.suspensionState === 1">激活</el-tag> |
| | | <el-tag type="warning" v-if="scope.row.suspensionState === 2">挂起</el-tag> |
| | | <span>{{ parseTime(scope.row.createTime) }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="流程编号" align="center" prop="id" width="120" :show-overflow-tooltip="true"/> |
| | | <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> |
| | | <template v-slot="scope"> |
| | | <el-button size="mini" type="text" icon="el-icon-edit" @click="handleAudit(scope.row)" |
| | | v-hasPermi="['bpm:task:update']">审批</el-button> |
| | | v-hasPermi="['bpm:task:update']">办理</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | |
| | | <span>{{ scope.row.resultCode === 0 ? '成功' : '失败(' + scope.row.resultMsg + ')' }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="操作模块" align="center" prop="operateModule" width="180" /> |
| | | <el-table-column label="操作名" align="center" prop="operateName" width="180" /> |
| | | <el-table-column label="操作类型" align="center" prop="operateType"> |
| | | <template #default="scope"> |
| | | <dict-tag :type="DICT_TYPE.INFRA_OPERATE_TYPE" :value="scope.row.operateType" /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> |
| | | <template v-slot="scope"> |
| | | <el-button size="mini" type="text" icon="el-icon-view" @click="handleView(scope.row,scope.index)" |
| | |
| | | <el-form-item label="操作结果:"> |
| | | <div v-if="form.resultCode === 0">正常</div> |
| | | <div v-else-if="form.resultCode > 0">失败 | {{ form.resultCode }} || {{ form.resultMsg}}</div> |
| | | </el-form-item> |
| | | <el-form-item label="操作模块:">{{ form.operateModule }}</el-form-item> |
| | | <el-form-item label="操作名:">{{ form.operateName }}</el-form-item> |
| | | <el-form-item label="操作类型:"> |
| | | <dict-tag :type="DICT_TYPE.INFRA_OPERATE_TYPE" :value="form.operateType"/> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | |
| | | }).then(response => { |
| | | this.$download.excel(response, 'API 访问日志.xls'); |
| | | this.exportLoading = false; |
| | | }).catch(() => {}); |
| | | }).finally(() => { |
| | | this.exportLoading = false; |
| | | }); |
| | | } |
| | | } |
| | | }; |
| | |
| | | }).then(response => { |
| | | this.$download.excel(response, 'API 错误日志.xls'); |
| | | this.exportLoading = false; |
| | | }).catch(() => {}); |
| | | }).finally(() => { |
| | | this.exportLoading = false; |
| | | }); |
| | | } |
| | | } |
| | | }; |
| | |
| | | }).then(response => { |
| | | this.$download.excel(response, '参数配置.xls'); |
| | | this.exportLoading = false; |
| | | }).catch(() => {}); |
| | | }).finally(() => { |
| | | this.exportLoading = false; |
| | | }); |
| | | }, |
| | | } |
| | | }; |
| | |
| | | handleExport() { |
| | | const queryParams = this.queryParams; |
| | | this.$modal.confirm("是否确认导出所有定时任务数据项?").then(() => { |
| | | this.exportLoading = true; |
| | | return exportJob(queryParams); |
| | | }).then(response => { |
| | | this.$download.excel(response, '定时任务.xls'); |
| | | this.exportLoading = false; |
| | | }).catch(() => {}); |
| | | this.exportLoading = true; |
| | | return exportJob(queryParams); |
| | | }).then(response => { |
| | | this.$download.excel(response, '定时任务.xls'); |
| | | }).finally(() => { |
| | | this.exportLoading = false; |
| | | }); |
| | | } |
| | | } |
| | | }; |
| | |
| | | handleExport() { |
| | | const queryParams = this.queryParams; |
| | | this.$modal.confirm('是否确认导出所有数据项?').then(() => { |
| | | this.exportLoading = true; |
| | | return exportData(queryParams); |
| | | }).then(response => { |
| | | this.$download.excel(response, '字典数据.xls'); |
| | | this.exportLoading = false; |
| | | }).catch(() => {}); |
| | | this.exportLoading = true; |
| | | return exportData(queryParams); |
| | | }).then(response => { |
| | | this.$download.excel(response, '字典数据.xls'); |
| | | }).finally(() => { |
| | | this.exportLoading = false; |
| | | }); |
| | | } |
| | | } |
| | | }; |
| | |
| | | }).then(response => { |
| | | this.$download.excel(response, '字典类型.xls'); |
| | | this.exportLoading = false; |
| | | }).catch(() => {}); |
| | | }).finally(() => { |
| | | this.exportLoading = false; |
| | | }); |
| | | } |
| | | } |
| | | }; |
| | |
| | | /** 导出按钮操作 */ |
| | | handleExport() { |
| | | this.$modal.confirm('是否确认导出所有操作日志数据项?').then(() => { |
| | | // 处理查询参数 |
| | | let params = {...this.queryParams}; |
| | | params.pageNo = undefined; |
| | | params.pageSize = undefined; |
| | | this.exportLoading = true; |
| | | return exportLoginLog(params); |
| | | }).then(response => { |
| | | this.$download.excel(response, '登录日志.xls'); |
| | | this.exportLoading = false; |
| | | }).catch(() => {}); |
| | | // 处理查询参数 |
| | | let params = {...this.queryParams}; |
| | | params.pageNo = undefined; |
| | | params.pageSize = undefined; |
| | | this.exportLoading = true; |
| | | return exportLoginLog(params); |
| | | }).then(response => { |
| | | this.$download.excel(response, '登录日志.xls'); |
| | | }).finally(() => { |
| | | this.exportLoading = false; |
| | | }); |
| | | } |
| | | } |
| | | }; |
| | |
| | | return { |
| | | // 遮罩层 |
| | | loading: true, |
| | | // 导出遮罩层 |
| | | exportLoading: false, |
| | | // 显示搜索条件 |
| | | showSearch: true, |
| | | // 总条数 |
| | |
| | | <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="module"> |
| | | <el-input v-model="queryParams.module" placeholder="请输入系统模块" clearable style="width: 240px;" |
| | | @keyup.enter.native="handleQuery"/> |
| | | </el-form-item> |
| | | <el-form-item label="操作人员" prop="userNickname"> |
| | | <el-input v-model="queryParams.userNickname" placeholder="请输入操作人员" clearable style="width: 240px;" |
| | | @keyup.enter.native="handleQuery"/> |
| | | </el-form-item> |
| | | <el-form-item label="类型" prop="type"> |
| | | <el-select v-model="queryParams.type" placeholder="操作类型" clearable style="width: 240px"> |
| | | <el-option v-for="dict in this.getDictDatas(DICT_TYPE.SYSTEM_OPERATE_TYPE)" :key="parseInt(dict.value)" |
| | | :label="dict.label" :value="parseInt(dict.value)"/> |
| | | <el-form-item label="操作人" prop="userId"> |
| | | <el-select v-model="queryParams.userId" placeholder="请输入操作人员" clearable style="width: 240px"> |
| | | <el-option v-for="user in this.userList" :key="user.id" :label="user.nickname" :value="user.id"/> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="状态" prop="status"> |
| | | <el-select v-model="queryParams.success" placeholder="操作状态" clearable style="width: 240px"> |
| | | <el-option :key="true" label="成功" :value="true"/> |
| | | <el-option :key="false" label="失败" :value="false"/> |
| | | </el-select> |
| | | <el-form-item label="操作模块" prop="type"> |
| | | <el-input v-model="queryParams.type" placeholder="请输入操作模块" clearable style="width: 240px;" |
| | | @keyup.enter.native="handleQuery"/> |
| | | </el-form-item> |
| | | <el-form-item label="操作时间" prop="startTime"> |
| | | <el-date-picker v-model="queryParams.startTime" style="width: 240px" value-format="yyyy-MM-dd HH:mm:ss" type="daterange" |
| | | <el-form-item label="操作名" prop="subType"> |
| | | <el-input v-model="queryParams.subType" placeholder="请输入操作名" clearable style="width: 240px;" |
| | | @keyup.enter.native="handleQuery"/> |
| | | </el-form-item> |
| | | <el-form-item label="操作内容" prop="action"> |
| | | <el-input v-model="queryParams.action" placeholder="请输入操作内容" clearable style="width: 240px;" |
| | | @keyup.enter.native="handleQuery"/> |
| | | </el-form-item> |
| | | <el-form-item label="操作时间" prop="createTime"> |
| | | <el-date-picker v-model="queryParams.createTime" style="width: 240px" value-format="yyyy-MM-dd HH:mm:ss" type="daterange" |
| | | range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" :default-time="['00:00:00', '23:59:59']" /> |
| | | </el-form-item> |
| | | <el-form-item label="业务编号" prop="action"> |
| | | <el-input v-model="queryParams.bizId" placeholder="请输入业务编号" clearable style="width: 240px;" |
| | | @keyup.enter.native="handleQuery"/> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button> |
| | |
| | | </el-row> |
| | | |
| | | <el-table v-loading="loading" :data="list"> |
| | | <el-table-column label="日志编号" align="center" prop="id" /> |
| | | <el-table-column label="操作模块" align="center" prop="module" /> |
| | | <el-table-column label="操作名" align="center" prop="name" width="180" /> |
| | | <el-table-column label="操作类型" align="center" prop="type"> |
| | | <el-table-column label="日志编号" align="center" prop="id" width="100" /> |
| | | <el-table-column label="操作人" align="center" prop="userName" width="120" /> |
| | | <el-table-column label="操作模块" align="center" prop="type" width="120" /> |
| | | <el-table-column label="操作名" align="center" prop="subType" width="160" /> |
| | | <el-table-column label="操作内容" align="center" prop="action" /> |
| | | <el-table-column label="操作日期" align="center" prop="createTime" width="180"> |
| | | <template v-slot="scope"> |
| | | <dict-tag :type="DICT_TYPE.SYSTEM_OPERATE_TYPE" :value="scope.row.type"/> |
| | | <span>{{ parseTime(scope.row.createTime) }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="操作人" align="center" prop="userNickname" /> |
| | | <el-table-column label="操作结果" align="center" prop="status"> |
| | | <template v-slot="scope"> |
| | | <span>{{ scope.row.resultCode === 0 ? '成功' : '失败' }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="操作日期" align="center" prop="startTime" width="180"> |
| | | <template v-slot="scope"> |
| | | <span>{{ parseTime(scope.row.startTime) }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="执行时长" align="center" prop="startTime"> |
| | | <template v-slot="scope"> |
| | | <span>{{ scope.row.duration }} ms</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> |
| | | <el-table-column label="业务编号" align="center" prop="bizId" width="120" /> |
| | | <el-table-column label="操作 IP" align="center" prop="userIp" width="120" /> |
| | | <el-table-column label="操作" align="center" width="60" class-name="small-padding fixed-width"> |
| | | <template v-slot="scope"> |
| | | <el-button size="mini" type="text" icon="el-icon-view" @click="handleView(scope.row,scope.index)" |
| | | v-hasPermi="['system:operate-log:query']">详细</el-button> |
| | |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize" |
| | | <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize" |
| | | @pagination="getList" /> |
| | | |
| | | <!-- 操作日志详细 --> |
| | |
| | | <el-form-item label="链路追踪:">{{ form.traceId }}</el-form-item> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <el-form-item label="用户信息:">{{ form.userId }} | {{ form.userNickname }} | {{ form.userIp }} | {{ form.userAgent}} </el-form-item> |
| | | <el-form-item label="操作人编号:">{{ form.userId }} </el-form-item> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <el-form-item label="操作信息:"> |
| | | {{ form.module }} | {{ form.name }} |
| | | <dict-tag :type="DICT_TYPE.SYSTEM_OPERATE_TYPE" :value="form.type"/> |
| | | <br /> {{ form.content }} |
| | | <br /> {{ form.exts }} |
| | | </el-form-item> |
| | | <el-form-item label="操作人名字:">{{ form.userName }} </el-form-item> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <el-form-item label="请求信息:">{{ form.requestMethod }} | {{ form.requestUrl }} </el-form-item> |
| | | <el-form-item label="操作人 IP:">{{ form.userIp }} </el-form-item> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <el-form-item label="方法名:">{{ form.javaMethod }}</el-form-item> |
| | | <el-form-item label="操作人 UA:">{{ form.userAgent }} </el-form-item> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <el-form-item label="方法参数:">{{ form.javaMethodArgs }}</el-form-item> |
| | | <el-form-item label="操作模块:">{{ form.type }}</el-form-item> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <el-form-item label="开始时间:"> |
| | | {{ parseTime(form.startTime) }} | {{ form.duration }} ms |
| | | </el-form-item> |
| | | <el-form-item label="操作名:">{{ form.subType }}</el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="操作结果:"> |
| | | <div v-if="form.resultCode === 0">正常 | {{ form.resultData}} </div> |
| | | <div v-else-if="form.resultCode > 0">失败 | {{ form.resultCode }} || {{ form.resultMsg}}</div> |
| | | </el-form-item> |
| | | <el-col :span="24"> |
| | | <el-form-item label="操作内容:">{{ form.action }}</el-form-item> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <el-form-item label="拓展参数:">{{ form.extra }}</el-form-item> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <el-form-item label="请求 URL:">{{ form.requestMethod }} | {{ form.requestUrl }} </el-form-item> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <el-form-item label="操作时间:">{{ parseTime(form.createTime) }}</el-form-item> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <el-form-item label="业务编号:">{{ form.bizId }}</el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | |
| | | |
| | | <script> |
| | | import { listOperateLog, exportOperateLog } from "@/api/system/operatelog"; |
| | | import { listSimpleUsers } from "@/api/system/user"; |
| | | |
| | | export default { |
| | | name: "SystemOperateLog", |
| | |
| | | queryParams: { |
| | | pageNo: 1, |
| | | pageSize: 10, |
| | | module: undefined, |
| | | userNickname: undefined, |
| | | businessType: undefined, |
| | | status: undefined, |
| | | startTime: [] |
| | | userId: undefined, |
| | | type: undefined, |
| | | subType: undefined, |
| | | action: undefined, |
| | | createTime: [], |
| | | bizId: undefined |
| | | }, |
| | | userList: [], // 用户列表 |
| | | }; |
| | | }, |
| | | created() { |
| | | this.getList(); |
| | | // 获取用户精简信息列表 |
| | | listSimpleUsers().then(res => { |
| | | this.userList = res.data; |
| | | }); |
| | | }, |
| | | methods: { |
| | | /** 查询登录日志 */ |
| | |
| | | /** 导出按钮操作 */ |
| | | handleExport() { |
| | | this.$modal.confirm('是否确认导出所有操作日志数据项?').then(() => { |
| | | // 处理查询参数 |
| | | let params = {...this.queryParams}; |
| | | params.pageNo = undefined; |
| | | params.pageSize = undefined; |
| | | this.exportLoading = true; |
| | | return exportOperateLog(params); |
| | | }).then(response => { |
| | | this.$download.excel(response, '操作日志.xls'); |
| | | this.exportLoading = false; |
| | | }).catch(() => {}); |
| | | // 处理查询参数 |
| | | let params = {...this.queryParams}; |
| | | params.pageNo = undefined; |
| | | params.pageSize = undefined; |
| | | this.exportLoading = true; |
| | | return exportOperateLog(params); |
| | | }).then(response => { |
| | | this.$download.excel(response, '操作日志.xls'); |
| | | }).finally(() => { |
| | | this.exportLoading = false; |
| | | }); |
| | | } |
| | | } |
| | | }; |
| | |
| | | handleExport() { |
| | | const queryParams = this.queryParams; |
| | | this.$modal.confirm('是否确认导出所有岗位数据项?').then(() => { |
| | | this.exportLoading = true; |
| | | return exportPost(queryParams); |
| | | }).then(response => { |
| | | this.$download.excel(response, '岗位数据.xls'); |
| | | this.exportLoading = false; |
| | | }).catch(() => {}); |
| | | this.exportLoading = true; |
| | | return exportPost(queryParams); |
| | | }).then(response => { |
| | | this.$download.excel(response, '岗位数据.xls'); |
| | | }).finally(() => { |
| | | this.exportLoading = false; |
| | | }); |
| | | } |
| | | } |
| | | }; |
| | |
| | | /** 导出按钮操作 */ |
| | | handleExport() { |
| | | const queryParams = this.queryParams; |
| | | this.$modal.confirm('是否确认导出所有角色数据项?').then(function() { |
| | | this.exportLoading = true; |
| | | return exportRole(queryParams); |
| | | }).then(response => { |
| | | this.$download.excel(response, '角色数据.xls'); |
| | | this.exportLoading = false; |
| | | }).catch(() => {}); |
| | | this.$modal.confirm('是否确认导出所有角色数据项?').then(() => { |
| | | this.exportLoading = true; |
| | | return exportRole(queryParams); |
| | | }).then(response => { |
| | | this.$download.excel(response, '角色数据.xls'); |
| | | }).finally(() => { |
| | | this.exportLoading = false; |
| | | }); |
| | | } |
| | | } |
| | | }; |
| | |
| | | }).then(response => { |
| | | this.$download.excel(response, '短信日志.xls'); |
| | | this.exportLoading = false; |
| | | }).catch(() => {}); |
| | | }).finally(() => { |
| | | this.exportLoading = false; |
| | | }); |
| | | }, |
| | | /** 详细按钮操作 */ |
| | | handleView(row) { |
| | |
| | | }).then(response => { |
| | | this.$download.excel(response, '短信模板.xls'); |
| | | this.exportLoading = false; |
| | | }).catch(() => {}); |
| | | }).finally(() => { |
| | | this.exportLoading = false; |
| | | }); |
| | | }, |
| | | /** 发送短息按钮 */ |
| | | handleSendSms(row) { |
| | |
| | | params.pageSize = undefined; |
| | | // 执行导出 |
| | | this.$modal.confirm('是否确认导出所有租户数据项?').then(() => { |
| | | this.exportLoading = true; |
| | | return exportTenantExcel(params); |
| | | }).then(response => { |
| | | this.$download.excel(response, '租户.xls'); |
| | | this.exportLoading = false; |
| | | }).catch(() => {}); |
| | | this.exportLoading = true; |
| | | return exportTenantExcel(params); |
| | | }).then(response => { |
| | | this.$download.excel(response, '租户.xls'); |
| | | }).catch(() => { |
| | | this.exportLoading = false; |
| | | }); |
| | | }, |
| | | /** 套餐名格式化 */ |
| | | getPackageName(packageId) { |
| | |
| | | return { |
| | | // 遮罩层 |
| | | loading: true, |
| | | // 导出遮罩层 |
| | | exportLoading: false, |
| | | // 显示搜索条件 |
| | | showSearch: true, |
| | | // 总条数 |
| | |
| | | return exportUser(params); |
| | | }).then(response => { |
| | | this.$download.excel(response, '用户数据.xls'); |
| | | this.exportLoading = false; |
| | | }).catch(() => {}); |
| | | }).finally(() => { |
| | | this.exportLoading = false; |
| | | }) |
| | | }, |
| | | /** 导入按钮操作 */ |
| | | handleImport() { |