commit:同步2.1版本

This commit is contained in:
Jerry
2021-12-16 21:49:09 +08:00
parent 81bb8ea64e
commit c76388f593
552 changed files with 5641 additions and 2583 deletions

View File

@@ -1,6 +1,17 @@
import * as staticDict from '@/staticDict'
export default class DictionaryController {
static dictSysRole (sender, params, axiosOption, httpOption) {
return new Promise((resolve, reject) => {
sender.doUrl('/admin/upms/sysRole/listDict', 'get', params, axiosOption, httpOption).then(res => {
let dictData = new staticDict.DictionaryBase('角色字典');
dictData.setList(res.data);
resolve(dictData);
}).catch(err => {
reject(err);
});
});
}
static dictSysUserStatus () {
return new Promise((resolve) => {
resolve(staticDict.SysUserStatus);
@@ -81,4 +92,15 @@ export default class DictionaryController {
});
});
}
static dictSysPost (sender, params, axiosOption, httpOption) {
return new Promise((resolve, reject) => {
sender.doUrl('/admin/upms/sysPost/listDict', 'get', params, axiosOption, httpOption).then(res => {
let dictData = new staticDict.DictionaryBase('岗位字典');
dictData.setList(res.data);
resolve(dictData);
}).catch(err => {
reject(err);
});
});
}
}

View File

@@ -95,4 +95,20 @@ export default class FlowOperationController {
static deleteProcessInstance (sender, params, axiosOption, httpOption) {
return sender.doUrl('/admin/flow/flowOperation/deleteProcessInstance', 'post', params, axiosOption, httpOption);
}
// 催办
static remindRuntimeTask (sender, params, axiosOption, httpOption) {
return sender.doUrl('/admin/flow/flowOperation/remindRuntimeTask', 'post', params, axiosOption, httpOption);
}
// 催办消息列表
static listRemindingTask (sender, params, axiosOption, httpOption) {
return sender.doUrl('/admin/flow/flowMessage/listRemindingTask', 'post', params, axiosOption, httpOption);
}
// 驳回
static rejectRuntimeTask (sender, params, axiosOption, httpOption) {
return sender.doUrl('/admin/flow/flowOperation/rejectRuntimeTask', 'post', params, axiosOption, httpOption);
}
// 撤销
static revokeHistoricTask (sender, params, axiosOption, httpOption) {
return sender.doUrl('/admin/flow/flowOperation/revokeHistoricTask', 'post', params, axiosOption, httpOption);
}
}

View File

@@ -2,7 +2,6 @@ import Vue from 'vue';
import { Loading, Message } from 'element-ui';
import request from './request';
import requestUrl from './requestUrl';
import merge from 'lodash/merge';
import { globalConfig } from '@/core/config';
/**
@@ -132,34 +131,41 @@ const ajaxThrottleSet = new Set();
* @param {Object} options 显示设置
*/
const doUrl = function (url, type, params, axiosOption, options) {
options = merge(globalConfig.httpOption, options);
axiosOption = merge(globalConfig.axiosOption, axiosOption);
let finalOption = {
...globalConfig.httpOption,
...options
};
let { showMask, showError, throttleFlag, throttleTimeout } = finalOption;
let finalAxiosOption = {
...globalConfig.axiosOption,
...axiosOption
}
if (type == null || type === '') type = 'post';
if (ajaxThrottleSet.has(url) && options.throttleFlag) {
if (ajaxThrottleSet.has(url) && throttleFlag) {
return Promise.resolve();
} else {
if (options.throttleFlag) {
if (throttleFlag) {
ajaxThrottleSet.add(url);
setTimeout(() => {
ajaxThrottleSet.delete(url);
}, options.throttleTimeout || 50);
}, throttleTimeout || 50);
}
return new Promise((resolve, reject) => {
if (options.showMask) loadingManager.showMask();
if (showMask) loadingManager.showMask();
let ajaxCall = null;
if (type.toLowerCase() === 'get') {
ajaxCall = fetchGet(url, params, axiosOption);
ajaxCall = fetchGet(url, params, finalAxiosOption);
} else if (type.toLowerCase() === 'post') {
ajaxCall = fetchPost(url, params, axiosOption);
ajaxCall = fetchPost(url, params, finalAxiosOption);
}
if (ajaxCall != null) {
ajaxCall.then(res => {
if (options.showMask) loadingManager.hideMask();
if (showMask) loadingManager.hideMask();
if (res.data && res.data.success) {
resolve(res.data);
} else {
if (options.showError) {
if (showError) {
Message.error({
showClose: true,
message: res.data.errorMessage ? res.data.errorMessage : '数据请求失败'
@@ -168,8 +174,8 @@ const doUrl = function (url, type, params, axiosOption, options) {
reject(res.data);
}
}).catch(e => {
if (options.showMask) loadingManager.hideMask();
if (options.showError) {
if (showMask) loadingManager.hideMask();
if (showError) {
Message.error({
showClose: true,
message: e.errorMessage ? e.errorMessage : '网络请求错误'
@@ -178,7 +184,7 @@ const doUrl = function (url, type, params, axiosOption, options) {
reject(e);
});
} else {
if (options.showMask) loadingManager.hideMask();
if (showMask) loadingManager.hideMask();
reject(new Error('错误的请求类型 - ' + type));
}
});

View File

@@ -44,6 +44,7 @@ const routers = [
{path: 'formOnlinePage', component: _import('onlineForm/formOnlinePage/index'), name: 'formOnlinePage', props: getProps, meta: {title: '在线表单管理'}},
{path: 'onlineForm', component: _import('onlineForm/index'), name: 'onlineForm', props: getProps, meta: {title: '在线表单'}},
// 工作流模块路由配置
{path: 'formMessage', component: _import('workflow/formMessage/index'), name: 'formMessage', meta: {title: '催办消息'}},
{path: 'formFlowCategory', component: _import('workflow/flowCategory/formFlowCategory'), name: 'formFlowCategory', props: getProps, meta: {title: '流程分类管理'}},
{path: 'formFlowEntry', component: _import('workflow/flowEntry/formFlowEntry'), name: 'formFlowEntry', props: getProps, meta: {title: '流程设计'}},
{path: 'formAllInstance', component: _import('workflow/taskManager/formAllInstance'), name: 'formAllInstance', props: getProps, meta: {title: '流程实例'}},

View File

@@ -62,6 +62,16 @@ const SysFlowTaskOperationType = new DictionaryBase('任务操作类型', [
name: '拒绝',
symbol: 'REFUSE'
},
{
id: 'reject',
name: '驳回',
symbol: 'REJECT'
},
{
id: 'revoke',
name: '撤销',
symbol: 'REVOKE'
},
{
id: 'transfer',
name: '转办',

View File

@@ -1 +1,47 @@
export default {}
import { FlowOperationController } from '@/api/flowController.js';
// 催办消息下拉个数
const MESSAGE_SHOW_COUNT = 10;
// 催办消息轮询间隔
const MESSAGE_TIMER_INTERVAL = 10000;
// 获得消息列表数据
function loadMessage (context, owner) {
let params = {
pageParam: {
pageSize: MESSAGE_SHOW_COUNT,
pageNum: 1
}
}
FlowOperationController.listRemindingTask(owner, params, null, {
showMask: false,
showError: false
}).then(res => {
context.commit('setMessageList', res.data);
}).catch(e => {
console.error(e);
});
}
export default {
startMessage: (context, owner) => {
if (context.state.messageTimer != null) {
clearInterval(context.state.messageTimer);
}
let timer = setInterval(() => {
loadMessage(context, owner);
}, MESSAGE_TIMER_INTERVAL);
context.commit('setMessageTimer', timer);
loadMessage(context, owner);
},
stopMessage: (context) => {
if (context.state.messageTimer != null) {
clearInterval(context.state.messageTimer);
}
context.commit('setMessageTimer', null);
},
reloadMessage: (context, owner) => {
loadMessage(context, owner);
}
}

View File

@@ -82,5 +82,8 @@ export default {
},
getCurrentColumnId: (state) => {
return state.currentColumnId;
},
getMessageList: (state) => {
return state.messageList;
}
}

View File

@@ -157,5 +157,11 @@ export default {
setCurrentColumnId: (state, columnId) => {
if (setObjectToSessionStorage('currentColumnId', columnId)) state.currentColumnId = columnId;
if (setObjectToSessionStorage('currentMenuId', null)) state.currentMenuId = null;
},
setMessageTimer: (state, timerHandler) => {
state.messageTimer = timerHandler;
},
setMessageList: (state, messageList) => {
state.messageList = messageList;
}
}

View File

@@ -25,5 +25,8 @@ export default {
// 当前菜单
currentMenuId: getObjectFromSessionStorage('currentMenuId', undefined),
// 当前栏目
currentColumnId: getObjectFromSessionStorage('currentColumnId', undefined)
currentColumnId: getObjectFromSessionStorage('currentColumnId', undefined),
// 消息列表
messageTimeer: null,
messageList: []
}

View File

@@ -12,6 +12,25 @@
</el-menu>
</div>
<div class="header-menu" style="flex-grow: 1;">
<el-popover class="message" style="margin-right: 20px;" width="300" placement="bottom-end" :offset="20" popper-class="message-popover">
<el-badge slot="reference" is-dot :hidden="(getMessageList || {}).dataList == null || (getMessageList || {}).dataList.length <= 0"
style="height: 180x; line-height: 18px; cursor: pointer;">
<i class="el-icon-bell" style="font-size: 18px;" />
</el-badge>
<el-table :data="(getMessageList || {}).dataList" size="mini" empty-text="暂无消息" :show-header="false">
<el-table-column label="流程名称" prop="processDefinitionName" />
<el-table-column width="80px">
<template slot-scope="scope">
<el-button size="mini" type="text" @click="onSubmit(scope.row)">办理</el-button>
</template>
</el-table-column>
</el-table>
<el-button v-if="getMessageList && (getMessageList.dataList || []).length < getMessageList.totalCount"
size="small" type="text" style="width: 100%;"
@click="onMoreMessageClick">
查看更多
</el-button>
</el-popover>
<el-dropdown class="user-dropdown" trigger="click" @command="handleCommand">
<span class="el-dropdown-link">{{(getUserInfo || {}).showName}}<i class="el-icon-arrow-down el-icon--right"></i>
</span>
@@ -40,11 +59,12 @@
<script>
import '@/staticDict/onlineStaticDict.js';
import SideBar from './components/sidebar/sidebar.vue';
import { mapGetters, mapMutations } from 'vuex';
import { mapGetters, mapMutations, mapActions } from 'vuex';
import Breadcrumb from './components/breadcrumb';
import TagPanel from './components/tags/tagPanel.vue';
import formModifyPassword from './components/formModifyPassword/index.vue';
import { SystemController } from '@/api';
import { FlowOperationController } from '@/api/flowController.js';
import { getToken, setToken } from '@/utils';
export default {
@@ -107,6 +127,47 @@ export default {
}, {}).catch(e => {});
}
},
// 办理催办任务
onSubmit (row) {
console.log(row);
let params = {
processInstanceId: row.processInstanceId,
processDefinitionId: row.processDefinitionId,
taskId: row.taskId
}
FlowOperationController.viewRuntimeTaskInfo(this, params).then(res => {
if (res.data) {
this.$router.push({
name: res.data.routerName || 'handlerFlowTask',
query: {
isRuntime: true,
taskId: row.taskId,
processDefinitionKey: row.processDefinitionKey,
processInstanceId: row.processInstanceId,
processDefinitionId: row.processDefinitionId,
formId: res.data.formId,
routerName: res.data.routerName,
readOnly: res.data.readOnly,
taskName: row.taskName,
flowEntryName: row.processDefinitionName,
processInstanceInitiator: row.processInstanceInitiator,
// 过滤掉加签和撤销操作,只有在已完成任务里可以操作
operationList: (res.data.operationList || []).filter(item => {
return item.type !== this.SysFlowTaskOperationType.CO_SIGN && item.type !== this.SysFlowTaskOperationType.REVOKE;
}),
variableList: res.data.variableList
}
});
}
}).catch(e => {});
},
// 更多催办消息
onMoreMessageClick () {
this.$router.push({
name: 'formMessage'
});
},
...mapMutations([
'setClientHeight',
'setClientWidth',
@@ -116,6 +177,10 @@ export default {
'setUserInfo',
'clearOnlineFormCache',
'setMenuList'
]),
...mapActions([
'startMessage',
'stopMessage'
])
},
computed: {
@@ -145,6 +210,7 @@ export default {
'getCurrentColumnId',
'getColumnList',
'getMenuItem',
'getMessageList',
'getMainContextHeight'
])
},
@@ -164,6 +230,9 @@ export default {
this.setUserInfo(data.data);
}).catch(e => {});
}
// 获取催办消息
this.startMessage(this);
},
watch: {
getMenuItem: {
@@ -204,9 +273,27 @@ export default {
},
immediate: true
}
},
beforeRouteLeave (to, form, next) {
this.stopMessage();
next();
},
destoryed () {
this.stopMessage();
}
}
</script>
<style lang="scss" scoped>
<style lang="scss">
.message-popover {
padding: 5px!important;
}
.message-popover .el-table::before {
height: 0px!important;
}
.message-popover .el-table td {
border: none;
}
</style>

View File

@@ -84,6 +84,7 @@
</template>
</el-table-column>
</template>
<el-table-column v-if="formType === SysOnlineFormType.WORK_ORDER" label="当前任务" prop="(runtimeTaskInfo || {}).taskName" />
<el-table-column v-if="formType === SysOnlineFormType.WORK_ORDER" label="流程创建时间" width="180px" prop="createTime" />
<el-table-column v-if="formType === SysOnlineFormType.WORK_ORDER" label="流程状态" width="100px" prop="flowStatus" />
<el-table-column
@@ -108,6 +109,11 @@
@click.stop="onHandlerWorkOrder(scope.row)">
办理
</el-button>
<el-button type="text" size="mini"
v-if="formType === SysOnlineFormType.WORK_ORDER"
@click.stop="onHandlerRemindClick(scope.row)">
催办
</el-button>
<el-button type="text" size="mini" class="table-btn error"
v-if="formType === SysOnlineFormType.WORK_ORDER"
@click.stop="onCancelWorkOrder(scope.row)">
@@ -191,6 +197,9 @@ export default {
onHandlerWorkOrder (row) {
this.$emit('handlerWOrkOrder', row, this.widgetConfig);
},
onHandlerRemindClick (row) {
this.$emit('handlerRemind', row, this.widgetConfig);
},
onCancelWorkOrder (row) {
this.$emit('cancelWOrkOrder', row, this.widgetConfig);
},
@@ -338,7 +347,7 @@ export default {
if (operatorType === this.SysCustomWidgetOperationType.ADD) this.tableWidget.dataList.push(row);
if (operatorType === this.SysCustomWidgetOperationType.EDIT) {
this.tableWidget.dataList = this.tableWidget.dataList.map(item => {
if (item[this.primaryColumnName] === row[this.primaryColumnName]) {
if (item.__cascade_add_id__ == null ? item[this.primaryColumnName] === row[this.primaryColumnName] : item.__cascade_add_id__ === row.__cascade_add_id__) {
return {
...row
}
@@ -375,18 +384,12 @@ export default {
getTableColumnFieldName (tableColumn) {
if (tableColumn.column == null) return null;
let fieldName = tableColumn.column.columnName || tableColumn.column.objectFieldName;
if (tableColumn.relation != null) {
fieldName = tableColumn.relation.variableName + '__' + fieldName;
}
// 工单列表
if (this.formType === this.SysOnlineFormType.WORK_ORDER) {
fieldName = 'masterTable__' + fieldName;
} else {
if (tableColumn.relation != null) {
fieldName = tableColumn.relation.variableName + '__' + fieldName;
}
/*
if (tableColumn.column.dictInfo && tableColumn.column.dictInfo.dictType === this.SysOnlineDictType.TABLE) {
fieldName = fieldName + '__DictMap';
}
*/
}
return fieldName;
},

View File

@@ -183,6 +183,8 @@ export default {
return this.pageType === this.SysOnlinePageType.FLOW;
} else if (item.id === this.SysOnlineFormType.QUERY) {
return this.pageType !== this.SysOnlinePageType.FLOW;
} else if (item.id === this.SysOnlineFormType.WORK_ORDER) {
return this.pageType === this.SysOnlinePageType.FLOW;
} else {
return true;
}
@@ -190,11 +192,18 @@ export default {
},
getValidTableList () {
return this.datasourceTableList.filter(item => {
// 主数据源和一对多关联的从表,才可以创建表单
return (
item.relationType == null || item.relationType === this.SysOnlineRelationType.ONE_TO_MANY ||
(this.formData.formType === this.SysOnlineFormType.FLOW && item.relationType === this.SysOnlineRelationType.ONE_TO_ONE)
);
switch (this.formData.formType) {
// 工单列表页面和工作流流程页面,只能选择主表
case this.SysOnlineFormType.FLOW:
case this.SysOnlineFormType.WORK_ORDER:
return item.relationType == null;
// 流程编辑页面只支持一对多从表,普通编辑页面只支持主表和一对多从表
case this.SysOnlineFormType.FORM:
return this.pageType === this.SysOnlinePageType.FLOW ? item.relationType === this.SysOnlineRelationType.ONE_TO_MANY : (item.relationType == null || item.relationType === this.SysOnlineRelationType.ONE_TO_MANY);
// 查询页面可以选择主表或者一对多从表
case this.SysOnlineFormType.QUERY:
return item.relationType == null || item.relationType === this.SysOnlineRelationType.ONE_TO_MANY;
}
});
}
},

View File

@@ -181,7 +181,10 @@ export default {
}).catch(e => {});
}
} else {
let masterData = {};
let masterData = {
// 级联添加数据唯一标识
__cascade_add_id__: this.formData.__cascade_add_id__ || new Date().getTime()
};
if (this.masterTable && Array.isArray(this.masterTable.columnList)) {
this.masterTable.columnList.forEach(column => {
let keyName = column.columnName;

View File

@@ -36,6 +36,7 @@
@viewWOrkOrder="onView"
@handlerWOrkOrder="onSubmit"
@cancelWOrkOrder="onCancelWorkOrder"
@handlerRemind="onRemindClick"
/>
</el-col>
</el-row>
@@ -253,6 +254,13 @@ export default {
}
}).catch(e => {});
},
onRemindClick (row) {
FlowOperationController.remindRuntimeTask(this, {
workOrderId: row.workOrderId
}).then(res => {
this.$message.success('催办成功');
}).catch(e => {});
},
onCancelWorkOrder (row) {
this.$confirm('是否撤销此工单?').then(res => {
let params = {

View File

@@ -82,6 +82,13 @@ export default {
params.sysDeptDtoFilter = {
deptName: this.formSysDept.formFilterCopy.deptName
};
// 按照显示顺序排序
params.orderParam = [
{
fieldName: 'showOrder',
asc: true
}
];
return new Promise((resolve, reject) => {
SysDeptController.list(this, params).then(res => {
resolve({

View File

@@ -18,7 +18,7 @@
<slot name="operations" />
</template>
<template v-else>
<el-button v-for="(operation, index) in operationList" :key="index"
<el-button v-for="(operation, index) in flowOperationList" :key="index"
size="small" :type="getButtonType(operation.type) || 'primary'" :plain="operation.plain || false"
@click="handlerOperation(operation)">
{{operation.label}}
@@ -144,6 +144,9 @@ export default {
case this.SysFlowTaskOperationType.PARALLEL_REFUSE:
case this.SysFlowTaskOperationType.MULTI_REFUSE:
return 'default';
case this.SysFlowTaskOperationType.REJECT:
case this.SysFlowTaskOperationType.REVOKE:
return 'danger';
default: return 'default';
}
},
@@ -158,7 +161,9 @@ export default {
case this.SysFlowTaskOperationType.MULTI_REFUSE:
return 'warning';
case this.SysFlowTaskOperationType.STOP:
return 'danger'
case this.SysFlowTaskOperationType.REJECT:
case this.SysFlowTaskOperationType.REVOKE:
return 'danger';
default:
return 'primary';
}
@@ -214,6 +219,28 @@ export default {
isReadOnly () {
return typeof this.readOnly === 'string' ? this.readOnly === 'true' : this.readOnly;
},
flowOperationList () {
if (Array.isArray(this.operationList)) {
return this.operationList.map(item => {
if (item.type === this.SysFlowTaskOperationType.MULTI_SIGN && item.multiSignAssignee != null) {
let multiSignAssignee = {
...item.multiSignAssignee
}
multiSignAssignee.assigneeList = item.multiSignAssignee.assigneeList ? multiSignAssignee.assigneeList.split(',') : undefined;
return {
...item,
multiSignAssignee
}
} else {
return {
...item
}
}
});
} else {
return [];
}
},
...mapGetters(['getMainContextHeight'])
},
mounted () {

View File

@@ -3,7 +3,8 @@
<el-form ref="formTaskCommit" :model="formData" class="full-width-input" :rules="rules" style="width: 100%;"
label-width="100px" size="mini" label-position="right" @submit.native.prevent>
<el-row :gutter="20">
<el-col :span="24" v-if="operation.type !== SysFlowTaskOperationType.CO_SIGN && operation.type !== SysFlowTaskOperationType.MULTI_SIGN">
<el-col :span="24"
v-if="operation.type !== SysFlowTaskOperationType.CO_SIGN && operation.type !== SysFlowTaskOperationType.MULTI_SIGN">
<el-form-item label="审批意见:" prop="message">
<el-input v-model="formData.message" clearable placeholder="请输入审批意见" />
</el-form-item>
@@ -89,12 +90,18 @@ export default {
},
computed: {
showAssignSelect () {
let showAssignSelect = false;
// 如果是会签操作,判断是否在流程内设置了会签人
if (this.operation.type === this.SysFlowTaskOperationType.MULTI_SIGN) {
showAssignSelect = !this.operation.multiSignAssignee ||
!Array.isArray(this.operation.multiSignAssignee.assigneeList) ||
this.operation.multiSignAssignee.assigneeList.length <= 0;
}
return [
this.SysFlowTaskOperationType.TRANSFER,
this.SysFlowTaskOperationType.CO_SIGN,
this.SysFlowTaskOperationType.MULTI_SIGN,
this.SysFlowTaskOperationType.SET_ASSIGNEE
].indexOf(this.operation.type) !== -1;
].indexOf(this.operation.type) !== -1 || showAssignSelect;
},
multiSelect () {
return this.operation.type === this.SysFlowTaskOperationType.CO_SIGN || this.operation.type === this.SysFlowTaskOperationType.MULTI_SIGN;

View File

@@ -1,26 +1,28 @@
<template>
<el-container class="advance-query-form">
<el-aside width="300px">
<el-container>
<el-main style="background-color: white;">
<el-card class="base-card" shadow="never" :body-style="{ padding: '0px' }" style="border: none;">
<div slot="header" class="base-card-header">
<span style="font-size: 16px; font-weight: 500; color: #282828;">所属部门</span>
</div>
<el-scrollbar :style="{height: '500px'}" class="custom-scroll">
<el-tree class="dept-tree" ref="deptTree" :data="getDeptTreeData" :props="{label: 'name'}"
node-key="id" :default-expand-all="true" :expand-on-click-node="false"
@node-click="onDeptNodeClick"
:highlight-current="true">
<div slot-scope="{ data }" style="height: 35px; line-height: 35px;">
{{data.name}}
</div>
</el-tree>
</el-scrollbar>
</el-card>
</el-aside>
<el-main style="margin-left: 15px; background-color: white;">
<el-card class="base-card" shadow="never" :body-style="{ padding: '0px' }" style="border: none;">
<div slot="header" class="base-card-header">
<span style="font-size: 16px; font-weight: 500; color: #282828;">岗位列表</span>
<el-row type="flex" align="middle">
<el-radio-group v-model="formData.deptType" size="mini" @change="formData.deptId = undefined">
<el-radio-button label="allDeptPost">全部</el-radio-button>
<el-radio-button label="selfDeptPost">本部门</el-radio-button>
<el-radio-button label="upDeptPost">上级部门</el-radio-button>
<el-radio-button label="deptPost">指定部门</el-radio-button>
</el-radio-group>
<el-cascader v-model="formData.deptId" :clearable="true"
size="mini" placeholder="选择部门" v-show="formData.deptType === 'deptPost'"
:props="{value: 'id', label: 'name', checkStrictly: true}"
:options="deptList">
</el-cascader>
<!--
<el-select v-model="formData.deptId" size="mini" placeholder="选择部门" v-show="formData.deptType === 'deptPost'" style="margin-left: 10px;">
<el-option v-for="item in deptList" :key="item.id"
:label="item.name" :value="item.id"
/>
</el-select>
-->
</el-row>
<div class="base-card-operation">
<el-button type="primary" size="mini"
:disabled="selectPost.length <= 0"
@@ -36,7 +38,11 @@
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="50px" :selectable="canSelect" />
<el-table-column label="岗位名称" prop="postShowName" />
<el-table-column label="岗位名称">
<template slot-scope="scope">
<span>{{scope.row.postShowName || scope.row.postName}}</span>
</template>
</el-table-column>
<el-table-column label="领导岗位">
<template slot-scope="scope">
<el-tag size="mini" :type="scope.row.leaderPost ? 'success' : 'danger'">
@@ -52,14 +58,15 @@
</template>
<script>
import { DictionaryController } from '@/api/index.js';
export default {
name: 'taskPostSelect',
props: {
deptList: {
type: Array
},
postList: {
type: Array
},
deptPostList: {
type: Array
},
@@ -70,6 +77,11 @@ export default {
data () {
return {
currentDept: undefined,
formData: {
deptType: 'allDeptPost',
deptId: undefined,
postId: undefined
},
// deptList: [],
selectPost: []
}
@@ -87,26 +99,18 @@ export default {
return true;
}
},
loadSysDeptData () {
DictionaryController.dictSysDept(this, {}).then(res => {
this.deptList = res.getList();
this.currentDept = this.deptList[0];
if (this.currentDept) {
this.$nextTick(() => {
this.$refs.deptTree.setCurrentKey(this.currentDept.id);
});
}
}).catch(e => {});
},
onDeptNodeClick (data) {
this.selectPost = [];
this.currentDept = data;
},
handleSelectionChange (values) {
this.selectPost = values;
},
onAddPostClick () {
this.onCancel(true, this.selectPost);
this.onCancel(true, this.selectPost.map(item => {
return {
id: `${this.formData.deptType}__${item.deptPostId || item.postId}`,
deptType: this.formData.deptType,
deptPostId: this.formData.deptType === 'deptPost' ? item.deptPostId : undefined,
postId: this.formData.deptType === 'deptPost' ? undefined : item.postId
}
}));
}
},
computed: {
@@ -114,29 +118,16 @@ export default {
return this.deptList;
},
getValidDeptPostList () {
if (Array.isArray(this.deptPostList)) {
if (this.currentDept == null) {
return this.deptPostList;
} else {
return this.deptPostList.filter(item => {
return item.deptId === this.currentDept.id;
});
}
if (this.formData.deptType !== 'deptPost') {
return this.postList || [];
} else {
return [];
return (this.deptPostList || []).filter(item => {
return item.deptId === (Array.isArray(this.formData.deptId) ? this.formData.deptId[this.formData.deptId.length - 1] : this.formData.deptId);
});
}
}
},
mounted () {
// this.loadSysDeptData();
if (Array.isArray(this.deptList)) {
this.currentDept = this.deptList[0];
if (this.currentDept) {
this.$nextTick(() => {
this.$refs.deptTree.setCurrentKey(this.currentDept.id);
});
}
}
}
}
</script>

View File

@@ -153,7 +153,7 @@ export default {
if (relation.relationType === this.SysOnlineRelationType.ONE_TO_ONE) {
temp.push({
label: relation.relationName,
value: relation.variableName,
value: relation.relationId,
tableId: relation.slaveTableId,
children: relation.columnList.map(column => {
return {

View File

@@ -240,7 +240,9 @@ export default {
readOnly: res.data.readOnly,
taskName: '启动流程',
flowEntryName: row.processDefinitionName,
operationList: (res.data.operationList || []).filter(item => item.type !== this.SysFlowTaskOperationType.CO_SIGN),
operationList: (res.data.operationList || []).filter(item => {
return item.type !== this.SysFlowTaskOperationType.CO_SIGN && item.type !== this.SysFlowTaskOperationType.REVOKE;
}),
variableList: res.data.variableList
}
});

View File

@@ -0,0 +1,128 @@
<template>
<div style="position: relative;">
<el-form label-width="100px" size="mini" label-position="right" @submit.native.prevent>
<filter-box :item-width="350">
<el-button slot="operator" type="primary" :plain="true" size="mini" @click="refreshFormMessage(true)">查询</el-button>
</filter-box>
</el-form>
<el-row>
<el-col :span="24">
<el-table ref="flowCategory" :data="messageListWidget.dataList" size="mini" @sort-change="messageListWidget.onSortChange"
header-cell-class-name="table-header-gray">
<el-table-column label="序号" header-align="center" align="center" type="index" width="55px" :index="messageListWidget.getTableIndex" />
<el-table-column label="流程名称" prop="processDefinitionName" />
<el-table-column label="任务名称" prop="taskName" />
<el-table-column label="催办人" prop="createUsername" />
<el-table-column label="任务创建时间" prop="taskStartTime" />
<el-table-column label="催办时间" prop="createTime" />
<el-table-column label="操作" width="100px">
<template slot-scope="scope">
<el-button type="text" size="mini" @click="onSubmit(scope.row)">办理</el-button>
</template>
</el-table-column>
</el-table>
<el-row type="flex" justify="end" style="margin-top: 10px;">
<el-pagination
:total="messageListWidget.totalCount"
:current-page="messageListWidget.currentPage"
:page-size="messageListWidget.pageSize"
:page-sizes="[10, 20, 50, 100]"
layout="total, prev, pager, next, sizes"
@current-change="messageListWidget.onCurrentPageChange"
@size-change="messageListWidget.onPageSizeChange">
</el-pagination>
</el-row>
</el-col>
</el-row>
</div>
</template>
<script>
import { uploadMixin, statsDateRangeMixin, cachePageMixin } from '@/core/mixins';
import { TableWidget } from '@/utils/widget.js';
/* eslint-disable-next-line */
import { FlowOperationController } from '@/api/flowController.js';
export default {
name: 'formMessage',
mixins: [uploadMixin, statsDateRangeMixin, cachePageMixin],
data () {
return {
messageListWidget: new TableWidget(this.loadMessageData, this.loadMessageVerify, true, false, 'createTime', 1)
}
},
methods: {
loadMessageData (params) {
if (params == null) params = {};
return new Promise((resolve, reject) => {
FlowOperationController.listRemindingTask(this, params).then(res => {
resolve({
dataList: res.data.dataList,
totalCount: res.data.totalCount
});
}).catch(e => {
reject(e);
});
});
},
loadMessageVerify () {
return true;
},
refreshFormMessage (reloadData = false) {
if (reloadData) {
this.messageListWidget.refreshTable(true, 1);
} else {
this.messageListWidget.refreshTable();
}
},
onSubmit (row) {
let params = {
processInstanceId: row.processInstanceId,
processDefinitionId: row.processDefinitionId,
taskId: row.taskId
}
FlowOperationController.viewRuntimeTaskInfo(this, params).then(res => {
if (res.data) {
this.$router.push({
name: res.data.routerName || 'handlerFlowTask',
query: {
isRuntime: true,
taskId: row.taskId,
processDefinitionKey: row.processDefinitionKey,
processInstanceId: row.processInstanceId,
processDefinitionId: row.processDefinitionId,
formId: res.data.formId,
routerName: res.data.routerName,
readOnly: res.data.readOnly,
taskName: row.taskName,
flowEntryName: row.processDefinitionName,
processInstanceInitiator: row.processInstanceInitiator,
// 过滤掉加签和撤销操作,加签只有在已完成任务里可以操作
operationList: (res.data.operationList || []).filter(item => {
return item.type !== this.SysFlowTaskOperationType.CO_SIGN && item.type !== this.SysFlowTaskOperationType.REVOKE;
}),
variableList: res.data.variableList
}
});
}
}).catch(e => {});
},
onResume () {
this.refreshFormMessage();
},
initFormData () {
},
formInit () {
this.refreshFormMessage();
}
},
mounted () {
// 初始化页面数据
this.formInit();
}
}
</script>
<style>
</style>

View File

@@ -29,7 +29,7 @@
</template>
<script>
import { mapGetters } from 'vuex';
import { mapGetters, mapActions } from 'vuex';
import flowMixins from '../mixins/flowMixins.js';
import { FlowOperationController } from '@/api/flowController.js';
import WorkflowForm from '@/views/onlineForm/index.vue';
@@ -136,11 +136,11 @@ export default {
if (this.isOnlineForm) {
this.$refs.workflowForm.getFormData().then(formData => {
formData.taskVariableData = this.$refs.workflowForm.getVariableData(this.variableList);
assignee = (assignee && assignee !== '') ? assignee.split(',') : undefined;
if (operationType === this.SysFlowTaskOperationType.MULTI_SIGN) {
// 会签操作设置多实例处理人集合
if (formData.taskVariableData == null) formData.taskVariableData = {};
formData.taskVariableData.assigneeList = assignee.split(',');
formData.taskVariableData.assigneeList = assignee;
} else if (operationType === this.SysFlowTaskOperationType.SET_ASSIGNEE) {
// 设置下一个任务节点处理人
if (formData.taskVariableData == null) formData.taskVariableData = {};
@@ -205,6 +205,30 @@ export default {
}).catch(e => {});
return;
}
// 驳回操作
if (operation.type === this.SysFlowTaskOperationType.REJECT) {
FlowOperationController.rejectRuntimeTask(this, {
processInstanceId: this.processInstanceId,
taskId: this.taskId,
comment: (res || {}).message
}).then(res => {
this.handlerClose();
}).catch(e => {});
return;
}
// 撤销操作
if (operation.type === this.SysFlowTaskOperationType.REVOKE) {
this.$confirm('是否撤销此任务?').then(res => {
FlowOperationController.revokeHistoricTask(this, {
processInstanceId: this.processInstanceId,
taskId: this.taskId,
comment: '任务处理人撤销任务'
}).then(res => {
this.handlerClose();
}).catch(e => {});
}).catch(e => {});
return;
}
this.getMasterData(operation.type, (res || {}).assignee).then(formData => {
let params = {
taskId: this.taskId,
@@ -221,6 +245,7 @@ export default {
FlowOperationController.submitUserTask(this, params).then(res => {
this.handlerClose();
this.reloadMessage(this);
this.$message.success('提交成功!');
}).catch(e => {});
});
@@ -267,7 +292,8 @@ export default {
let funInitFormData = this.getRouterCompomentFunction('initFormData');
funInitFormData ? funInitFormData() : this.$message.error('当前流程并未实现页面初始化功能,请联系管理员!');
}
}
},
...mapActions(['reloadMessage'])
},
computed: {
isReadOnly () {

View File

@@ -50,8 +50,12 @@ export default {
isStart ? resolve() : reject();
return;
}
// 会签、指定审批人或者审批操作
if (!isStart || operation.type === this.SysFlowTaskOperationType.MULTI_SIGN || operation.type === this.SysFlowTaskOperationType.SET_ASSIGNEE) {
// 撤销操作不弹出选择窗口
let showCommitDig = (!isStart && operation.type !== this.SysFlowTaskOperationType.REVOKE) || operation.type === this.SysFlowTaskOperationType.SET_ASSIGNEE;
if (operation.type === this.SysFlowTaskOperationType.MULTI_SIGN) {
showCommitDig = !operation.multiSignAssignee || !Array.isArray(operation.multiSignAssignee.assigneeList) || operation.multiSignAssignee.assigneeList.length <= 0;
}
if (showCommitDig) {
let title = isStart ? '提交' : (operation.type === this.SysFlowTaskOperationType.CO_SIGN ? '加签' : '审批');
this.$dialog.show(title, TaskCommit, {
area: '500px'

View File

@@ -1096,6 +1096,11 @@
"name": "showOrder",
"type": "String",
"isAttr": true
},
{
"name": "multiSignAssignee",
"type": "String",
"isAttr": true
}
]
},
@@ -1126,6 +1131,69 @@
}
]
},
{
"name": "DeptPostList",
"superClass": [ "Element" ],
"meta": {
"allowedIn": [
"bpmn:UserTask"
]
},
"properties": [
{
"name": "deptPostList",
"type": "DeptPost",
"isMany": true
}
]
},
{
"name": "DeptPost",
"superClass": [ "Element" ],
"properties": [
{
"name": "id",
"type": "String",
"isAttr": true
},
{
"name": "type",
"type": "String",
"isAttr": true
},
{
"name": "postId",
"type": "String",
"isAttr": true
},
{
"name": "deptPostId",
"type": "String",
"isAttr": true
}
]
},
{
"name": "UserCandidateGroups",
"superClass": [ "Element" ],
"meta": {
"allowedIn": [
"bpmn:UserTask"
]
},
"properties": [
{
"name": "type",
"type": "String",
"isAttr": true
},
{
"name": "value",
"type": "String",
"isAttr": true
}
]
},
{
"name": "CustomCondition",
"superClass": [ "Element" ],

View File

@@ -1092,6 +1092,11 @@
"name": "showOrder",
"type": "String",
"isAttr": true
},
{
"name": "multiSignAssignee",
"type": "String",
"isAttr": true
}
]
},
@@ -1122,6 +1127,69 @@
}
]
},
{
"name": "DeptPostList",
"superClass": [ "Element" ],
"meta": {
"allowedIn": [
"bpmn:UserTask"
]
},
"properties": [
{
"name": "deptPostList",
"type": "DeptPost",
"isMany": true
}
]
},
{
"name": "DeptPost",
"superClass": [ "Element" ],
"properties": [
{
"name": "id",
"type": "String",
"isAttr": true
},
{
"name": "type",
"type": "String",
"isAttr": true
},
{
"name": "postId",
"type": "String",
"isAttr": true
},
{
"name": "deptPostId",
"type": "String",
"isAttr": true
}
]
},
{
"name": "UserCandidateGroups",
"superClass": [ "Element" ],
"meta": {
"allowedIn": [
"bpmn:UserTask"
]
},
"properties": [
{
"name": "type",
"type": "String",
"isAttr": true
},
{
"name": "value",
"type": "String",
"isAttr": true
}
]
},
{
"name": "CustomCondition",
"superClass": [ "Element" ],

View File

@@ -88,7 +88,7 @@ export default {
formId: formObj.formId,
routerName: formObj.routerName,
editable: !formObj.readOnly,
groupType: formObj.groupType || 'DEPT'
groupType: formObj.groupType || 'ASSIGNEE'
}
}
let elExtensionElements = this.bpmnELement.businessObject.get("extensionElements") || window.bpmnInstances.moddle.create("bpmn:ExtensionElements", { values: [] });
@@ -109,7 +109,7 @@ export default {
formId: this.flowEntry().bindFormType === this.SysFlowEntryBindFormType.ONLINE_FORM ? this.formData.formId : undefined,
routerName: this.flowEntry().bindFormType === this.SysFlowEntryBindFormType.ONLINE_FORM ? undefined : this.formData.routerName,
readOnly: !this.formData.editable,
groupType: this.formData.groupType || 'DEPT'
groupType: this.formData.groupType || 'ROLE'
});
window.bpmnInstances.modeling.updateProperties(this.bpmnELement, { formKey: formKeyString });
});
@@ -126,7 +126,8 @@ export default {
id: item.id,
label: item.label,
type: item.type,
showOrder: item.showOrder
showOrder: item.showOrder,
multiSignAssignee: item.multiSignAssignee
});
});
// 更新到元素上
@@ -149,6 +150,7 @@ export default {
item.label = res.label;
item.type = res.type;
item.showOrder = res.showOrder;
item.multiSignAssignee = res.multiSignAssignee;
}
});
}

View File

@@ -18,6 +18,47 @@
:clearable="true" placeholder="按钮名称" />
</el-form-item>
</el-col>
<el-col :span="24" v-if="formData.type === SysFlowTaskOperationType.MULTI_SIGN">
<el-form-item label="会签用户类型">
<el-select v-model="multiSignAssignee.assigneeType" placeholder="" @change="multiSignAssignee.assigneeList = []">
<el-option label="用户" value="USER_GROUP" />
<el-option label="角色" value="ROLE_GROUP" />
<el-option label="部门" value="DEPT_GROUP" />
<el-option label="岗位" value="POST_GROUP" />
<el-option label="部门岗位" value="DEPT_POST_GROUP" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="24" v-if="formData.type === SysFlowTaskOperationType.MULTI_SIGN">
<el-form-item label="会签用户选择">
<el-select class="assignee-select"
v-if="
multiSignAssignee.assigneeType === 'USER_GROUP' ||
multiSignAssignee.assigneeType === 'ROLE_GROUP' ||
multiSignAssignee.assigneeType === 'POST_GROUP'
"
v-model="multiSignAssignee.assigneeList" placeholder="" :multiple="true">
<el-option v-for="item in multiSignGroupList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
<el-cascader v-if="multiSignAssignee.assigneeType === 'DEPT_GROUP'"
v-model="multiSignAssignee.assigneeList" :options="multiSignGroupList" key="dept_select"
:props="{
multiple: true,
checkStrictly: true,
value: 'id',
label: 'name'
}"
/>
<el-cascader v-if="multiSignAssignee.assigneeType === 'DEPT_POST_GROUP'"
v-model="multiSignAssignee.assigneeList" :options="multiSignGroupList" key="dept_post_select"
:props="{
multiple: true,
value: 'id',
label: 'name'
}"
/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="显示顺序">
<el-input-number class="input-item" v-model="formData.showOrder"
@@ -42,6 +83,9 @@
</template>
<script>
import { findTreeNodePath, treeDataTranslate } from '@/utils';
import { SystemController, DictionaryController, SysPostController } from '@/api';
export default {
props: {
rowData: {
@@ -56,6 +100,15 @@ export default {
label: undefined,
showOrder: 0
},
userList: undefined,
roleList: undefined,
deptList: undefined,
postList: undefined,
deptPostList: undefined,
multiSignAssignee: {
assigneeType: 'USER_GROUP',
value: []
},
rules: {
type: [{ required: true, message: '请选择按钮类型', trigger: 'blur' }],
label: [{ required: true, message: '请输入按钮名称', trigger: 'blur' }]
@@ -71,6 +124,24 @@ export default {
onSubmit () {
this.$refs.form.validate(valid => {
if (valid) {
if (this.formData.type === this.SysFlowTaskOperationType.MULTI_SIGN &&
Array.isArray(this.multiSignAssignee.assigneeList) && this.multiSignAssignee.assigneeList.length > 0) {
let tempValue;
if (this.multiSignAssignee.assigneeType === 'USER_GROUP' || this.multiSignAssignee.assigneeType === 'ROLE_GROUP' || this.multiSignAssignee.assigneeType === 'POST_GROUP') {
tempValue = this.multiSignAssignee.assigneeList.join(',');
} else if (this.multiSignAssignee.assigneeType === 'DEPT_GROUP' || this.multiSignAssignee.assigneeType === 'DEPT_POST_GROUP') {
tempValue = this.multiSignAssignee.assigneeList.map(item => {
return item[item.length - 1];
}).join(',');
}
this.formData.multiSignAssignee = JSON.stringify({
assigneeType: this.multiSignAssignee.assigneeType,
assigneeList: tempValue
});
} else {
this.formData.multiSignAssignee = undefined;
}
this.onCancel(true);
}
});
@@ -81,6 +152,99 @@ export default {
} else {
this.formData.label = this.SysFlowTaskOperationType.getValue(type);
}
},
loadGroupList (type) {
return new Promise((resolve, reject) => {
if (type === 'USER_GROUP') {
SystemController.getUserList(this, {}).then(res => {
this.userList = res.data.dataList.map(item => {
return {
id: item.loginName,
name: item.loginName
}
});
resolve();
}).catch(e => {
reject(e);
});
} else if (type === 'ROLE_GROUP') {
DictionaryController.dictSysRole(this, {}).then(res => {
this.roleList = res.getList();
resolve();
}).catch(e => {
reject(e);
});
} else if (type === 'DEPT_GROUP') {
DictionaryController.dictSysDept(this, {}).then(res => {
this.deptList = treeDataTranslate(res.getList());
resolve();
}).catch(e => {
reject(e);
});
} else if (type === 'POST_GROUP') {
SysPostController.list(this, {}).then(res => {
this.postList = res.data.dataList.map(item => {
return {
id: item.postId,
name: item.postName
}
});
resolve();
}).catch(e => {
reject(e);
});
} else if (type === 'DEPT_POST_GROUP') {
DictionaryController.dictDeptPost(this, {}).then(res => {
this.deptPostList = treeDataTranslate(res);
let deptMap = new Map();
res.forEach(item => {
let deptItem = deptMap.get(item.deptId);
if (deptItem == null) {
deptItem = {
id: item.deptId,
name: item.deptName,
children: []
}
deptMap.set(item.deptId, deptItem);
}
deptItem.children.push({
id: item.deptPostId,
name: item.postShowName
});
});
this.deptPostList = [];
deptMap.forEach((value) => {
this.deptPostList.push(value);
});
resolve();
}).catch(e => {
reject(e);
});
}
});
}
},
computed: {
multiSignGroupList () {
let tempList;
switch (this.multiSignAssignee.assigneeType) {
case 'USER_GROUP': return this.userList;
case 'ROLE_GROUP': return this.roleList;
case 'DEPT_GROUP': return this.deptList;
case 'POST_GROUP': return this.postList;
case 'DEPT_POST_GROUP': return this.deptPostList;
default:
return [];
}
}
},
watch: {
multiSignGroupList: {
handler (newValue) {
if (newValue == null) this.loadGroupList(this.multiSignAssignee.assigneeType).catch(e => {});
},
immediate: true
}
},
mounted () {
@@ -88,10 +252,29 @@ export default {
this.formData = {
...this.rowData
}
if (this.rowData.multiSignAssignee) {
this.multiSignAssignee = JSON.parse(this.rowData.multiSignAssignee);
let assigneeValue = this.multiSignAssignee.assigneeList;
this.multiSignAssignee.assigneeList = undefined;
this.loadGroupList(this.multiSignAssignee.assigneeType).then(res => {
if (this.multiSignAssignee.assigneeType === 'USER_GROUP' || this.multiSignAssignee.assigneeType === 'ROLE_GROUP' ||
this.multiSignAssignee.assigneeType === 'POST_GROUP') {
this.multiSignAssignee.assigneeList = assigneeValue.split(',');
} else if (this.multiSignAssignee.assigneeType === 'DEPT_GROUP' || this.multiSignAssignee.assigneeType === 'DEPT_POST_GROUP') {
this.multiSignAssignee.assigneeList = assigneeValue.split(',').map(item => {
let nodePath = findTreeNodePath(this.multiSignGroupList, item);
return nodePath;
});
}
}).catch(e => {});
}
}
}
}
</script>
<style>
<style scoped>
.assignee-select >>> .el-input__inner {
min-height: 28px!important;
}
</style>

View File

@@ -32,6 +32,7 @@ export function initListenerType(listener) {
if (listener.delegateExpression) listenerType = "delegateExpressionListener";
if (listener.script) listenerType = "scriptListener";
return {
id: (listener.$attrs || {}).id,
...JSON.parse(JSON.stringify(listener)),
...(listener.script ?? {}),
listenerType: listenerType
@@ -50,8 +51,8 @@ export const eventType = {
assignment: "指派",
complete: "完成",
delete: "删除",
update: "更新",
timeout: "超时"
// update: "更新",
// timeout: "超时"
};
export const fieldType = {

View File

@@ -1,23 +1,31 @@
<template>
<div style="margin-top: 16px">
<el-form-item label="处理用户">
<TagSelect v-model="userTaskForm.assignee">
<el-button slot="append" class="append-add" type="default" icon="el-icon-plus" @click="onSelectAssignee(false)" />
</TagSelect>
</el-form-item>
<el-form-item label="候选用户">
<TagSelect v-model="userTaskForm.candidateUsers">
<el-button slot="append" class="append-add" type="default" icon="el-icon-plus" @click="onSelectCandidateUsers(true)" />
</TagSelect>
</el-form-item>
<el-form-item label="分组类型">
<el-form-item label="候选类型">
<el-select v-model="formData.groupType" placeholder="请选择分组类型" @change="onGroupTypeChange">
<el-option label="处理用户" value="ASSIGNEE" />
<el-option label="候选用户组" value="USERS" />
<el-option label="角色" value="ROLE" />
<el-option label="部门" value="DEPT" />
<el-option label="岗位" value="POST" />
<el-option label="流程发起人部门领导" value="DEPT_POST_LEADER" />
<el-option label="流程发起人上级部门领导" value="UP_DEPT_POST_LEADER" />
</el-select>
</el-form-item>
<el-form-item label="处理用户" v-if="formData.groupType === 'ASSIGNEE'">
<TagSelect v-model="userTaskForm.assignee">
<el-button slot="append" class="append-add" type="default" icon="el-icon-plus" @click="onSelectAssignee(false)" />
</TagSelect>
</el-form-item>
<el-form-item label="候选用户" v-if="formData.groupType === 'USERS'">
<TagSelect v-model="userTaskForm.candidateUsers">
<el-button slot="append" class="append-add" type="default" icon="el-icon-plus" @click="onSelectCandidateUsers(true)" />
</TagSelect>
</el-form-item>
<el-form-item v-if="formData.groupType === 'ROLE'" label="候选角色">
<el-select v-model="candidateGroupIds" placeholder="" :multiple="true" @change="onSelectRoleChange">
<el-option v-for="role in roleList" :key="role.id" :label="role.name" :value="role.id" />
</el-select>
</el-form-item>
<el-form-item v-if="formData.groupType == 'DEPT' || formData.groupType == 'POST'"
:label="formData.groupType === 'DEPT' ? '候选部门' : '候选岗位'"
>
@@ -39,7 +47,7 @@
<script>
import { findItemFromList, treeDataTranslate } from '@/utils';
import { DictionaryController } from '@/api';
import { SysPostController, DictionaryController } from '@/api';
import TagSelect from '@/views/workflow/components/TagSelect.vue';
import TaskUserSelect from '@/views/workflow/components/TaskUserSelect.vue';
import TaskGroupSelect from '@/views/workflow/components/TaskGroupSelect.vue';
@@ -54,7 +62,7 @@ export default {
components: {
TagSelect
},
inject: ['flowEntry'],
inject: ['flowEntry', 'prefix'],
data() {
return {
candidateGroupIds: [],
@@ -67,11 +75,14 @@ export default {
priority: ""
},
formData: {
groupType: 'DEPT'
groupType: 'ASSIGNEE'
},
roleList: undefined,
groupList: undefined,
groupMap: new Map(),
postList: [],
deptPostList: [],
postMap: new Map(),
deptPostMap: new Map(),
userTaskForm: {
assignee: "",
@@ -129,6 +140,16 @@ export default {
this.userTaskForm.candidateUsers = usedUserIdList.join(',');
}).catch(e => {});
},
loadSysRoleList () {
return new Promise((resolve, reject) => {
DictionaryController.dictSysRole(this, {}).then(res => {
this.roleList = res.getList();
resolve();
}).catch(e => {
reject(e);
});
});
},
loadDeptWidgetDropdownList () {
return new Promise((resolve, reject) => {
DictionaryController.dictSysDept(this, {}).then(res => {
@@ -158,6 +179,20 @@ export default {
});
});
},
loadSysPostList () {
this.postMap = new Map();
return new Promise((resolve, reject) => {
SysPostController.list(this, {}).then(res => {
this.postList = res.data.dataList;
this.postList.forEach(item => {
this.postMap.set(item.postId, item);
});
resolve();
}).catch(e => {
reject(e);
});
});
},
handlerDeptChange (usedIdList) {
this.$dialog.show('选择部门', TaskGroupSelect, {
area: ['600px', '600px']
@@ -183,22 +218,50 @@ export default {
}, {
deptList: this.groupList,
deptPostList: this.deptPostList,
postList: this.postList,
usedIdList: usedIdList
}).then(res => {
this.userTaskForm.candidateGroups = '';
if (Array.isArray(res)) {
if (!Array.isArray(this.candidateGroupIds)) this.candidateGroupIds = [];
res.forEach(item => {
let temp = this.getDeptPostItem(item);
if (findItemFromList(this.candidateGroupIds, item.id, 'id') == null) {
this.candidateGroupIds.push({
id: item.deptPostId,
name: `${item.deptName} / ${item.postShowName}`
...item,
name: `${temp.deptName} / ${temp.postName}`
});
}
});
this.updateDeptPost();
}
this.userTaskForm.candidateGroups = Array.isArray(this.candidateGroupIds) ? this.candidateGroupIds.map(item => item.id).join(',') : '';
}).catch(e => {});
},
getDeptPostItem (item) {
let deptName;
switch (item.deptType) {
case 'allDeptPost':
deptName = '全部';
break;
case 'selfDeptPost':
deptName = '本部门';
break;
case 'upDeptPost':
deptName = '上级部门';
break;
case 'deptPost':
deptName = (this.deptPostMap.get(item.deptPostId) || {}).deptName || '未知岗位';
break;
}
let postName = item.deptType === 'deptPost' ? ((this.deptPostMap.get(item.deptPostId) || {}).postShowName || '未知岗位') :
((this.postMap.get(item.postId) || {}).postName || '未知岗位');
return {
deptName,
postName
}
},
onSelectCandidatGroups () {
let usedIdList = this.userTaskForm.candidateGroups ? this.userTaskForm.candidateGroups.split(',') : [];
if (this.formData.groupType === 'DEPT') {
@@ -207,6 +270,11 @@ export default {
this.handlerPostChange(usedIdList);
}
},
onSelectRoleChange (value) {
this.$nextTick(() => {
this.userTaskForm.candidateGroups = Array.isArray(value) ? value.join(',') : '';
});
},
resetTaskForm() {
this.userTaskForm = {
assignee: "",
@@ -224,11 +292,11 @@ export default {
formId: formObj.formId,
routerName: formObj.routerName,
editable: !formObj.readOnly,
groupType: formObj.groupType || 'DEPT'
groupType: formObj.groupType || 'ASSIGNEE'
}
} else {
this.formData = {
groupType: 'DEPT'
groupType: 'ASSIGNEE'
}
}
for (let key in this.defaultTaskForm) {
@@ -237,19 +305,9 @@ export default {
value = (window.bpmnInstances.bpmnElement || {}).businessObject[key] || this.defaultTaskForm[key];
if (key === "candidateGroups" && value) {
this.candidateGroupIds = value.split(',');
if (Array.isArray(this.candidateGroupIds)) {
if (Array.isArray(this.candidateGroupIds) && this.formData.groupType === 'DEPT') {
this.candidateGroupIds = this.candidateGroupIds.map(item => {
if (this.formData.groupType === 'DEPT') {
return this.groupMap.get(item);
} else {
let temp = this.deptPostMap.get(item);
if (temp) {
return {
id: temp.deptPostId,
name: `${temp.deptName} / ${temp.postShowName}`
}
}
}
return this.groupMap.get(item);
}).filter(item => item != null);
}
}
@@ -258,6 +316,26 @@ export default {
}
this.$set(this.userTaskForm, key, value);
}
// 岗位
if (this.formData.groupType === 'POST') {
let elExtensionElements = window.bpmnInstances.bpmnElement.businessObject.get("extensionElements") ||
window.bpmnInstances.moddle.create("bpmn:ExtensionElements", { values: [] });
this.deptPostListElement = elExtensionElements.values.filter(ex => ex.$type === `${this.prefix}:DeptPostList`)?.[0] ||
window.bpmnInstances.moddle.create(`${this.prefix}:DeptPostList`, { deptPostList: [] });
this.candidateGroupIds = this.deptPostListElement.deptPostList.map(item => {
item.deptType = item.type;
item.type = undefined;
let temp = this.getDeptPostItem({
...item
});
if (temp) {
return {
...item,
name: `${temp.deptName} / ${temp.postName}`
}
}
});
}
},
updateFormKey () {
if (this.formData == null) return;
@@ -265,40 +343,89 @@ export default {
formId: this.flowEntry().bindFormType === this.SysFlowEntryBindFormType.ONLINE_FORM ? this.formData.formId : undefined,
routerName: this.flowEntry().bindFormType === this.SysFlowEntryBindFormType.ONLINE_FORM ? undefined : this.formData.routerName,
readOnly: !this.formData.editable,
groupType: this.formData.groupType || 'DEPT'
groupType: this.formData.groupType || 'ASSIGNEE'
});
window.bpmnInstances.modeling.updateProperties(window.bpmnInstances.bpmnElement, { formKey: formKeyString });
},
onGroupTypeChange () {
this.userTaskForm.assignee = undefined;
this.userTaskForm.candidateUsers = undefined;
this.candidateGroupIds = [];
this.userTaskForm.candidateGroups = '';
this.updateFormKey();
},
updateDeptPost () {
// 岗位
if (this.formData.groupType === 'POST') {
let elExtensionElements = window.bpmnInstances.bpmnElement.businessObject.get("extensionElements") || window.bpmnInstances.moddle.create("bpmn:ExtensionElements", { values: [] });
let otherExtensions = elExtensionElements.values.filter(ex => ex.$type !== `${this.prefix}:DeptPostList`);
if (this.deptPostListElement == null) {
this.deptPostListElement = window.bpmnInstances.moddle.create(`${this.prefix}:DeptPostList`, { deptPostList: [] });
}
this.deptPostListElement.deptPostList = this.candidateGroupIds.map(item => {
return window.bpmnInstances.moddle.create(`${this.prefix}:DeptPost`, {
id: item.id,
type: item.deptType,
postId: item.postId,
deptPostId: item.deptPostId
});
});
const newElExtensionElements = window.bpmnInstances.moddle.create(`bpmn:ExtensionElements`, {
values: otherExtensions.concat(this.deptPostListElement)
});
// 更新到元素上
window.bpmnInstances.modeling.updateProperties(window.bpmnInstances.bpmnElement, {
extensionElements: newElExtensionElements
});
}
},
updateElementTask(key) {
let taskAttr = Object.create(null);
if (key === "candidateUsers" || key === "candidateGroups") {
taskAttr[key] = this.userTaskForm[key] || null;
let type = key === "candidateUsers" ? "USERS" : this.formData.groupType;
this.updateUserCandidateGroups(type, taskAttr[key]);
} else {
taskAttr[key] = this.userTaskForm[key] || null;
}
window.bpmnInstances.modeling.updateProperties(window.bpmnInstances.bpmnElement, taskAttr);
},
updateUserCandidateGroups (type, value) {
console.log(type, value);
let elExtensionElements = window.bpmnInstances.bpmnElement.businessObject.get("extensionElements") || window.bpmnInstances.moddle.create("bpmn:ExtensionElements", { values: [] });
let otherExtensions = elExtensionElements.values.filter(ex => ex.$type !== `${this.prefix}:UserCandidateGroups`);
let userCandidateGroupsElement = window.bpmnInstances.moddle.create(`${this.prefix}:UserCandidateGroups`, {
type: type,
value: value
});
if (type !== 'POST' && value != null && value !== '') otherExtensions.push(userCandidateGroupsElement)
const newElExtensionElements = window.bpmnInstances.moddle.create(`bpmn:ExtensionElements`, {
values: otherExtensions
});
// 更新到元素上
window.bpmnInstances.modeling.updateProperties(window.bpmnInstances.bpmnElement, {
extensionElements: newElExtensionElements
});
}
},
watch: {
id: {
immediate: true,
handler(newValue) {
if (this.groupList == null) {
let httpCall = [
this.loadDeptWidgetDropdownList(),
this.loadDeptPostList()
];
Promise.all(httpCall).then(res => {
if (this.roleList == null) {
this.loadSysRoleList().then(res => {
let httpCall = [
this.loadDeptWidgetDropdownList(),
this.loadSysPostList(),
this.loadDeptPostList()
];
return Promise.all(httpCall);
}).then(res => {
this.bpmnElement = window.bpmnInstances.bpmnElement;
this.$nextTick(() => {
this.resetTaskForm();
});
}).catch(e => {});
this.$nextTick(() => this.resetTaskForm());
}).catch(e => {
this.roleList = undefined;
});
} else {
this.bpmnElement = window.bpmnInstances.bpmnElement;
this.$nextTick(() => this.resetTaskForm());
@@ -317,7 +444,13 @@ export default {
},
'candidateGroupIds': {
handler () {
this.userTaskForm.candidateGroups = Array.isArray(this.candidateGroupIds) ? this.candidateGroupIds.map(item => item.id).join(',') : '';
if (this.formData.groupType === 'ROLE') {
this.userTaskForm.candidateGroups = Array.isArray(this.candidateGroupIds) ? this.candidateGroupIds.join(',') : '';
} else if (this.formData.groupType === 'POST') {
this.updateDeptPost();
} else {
this.userTaskForm.candidateGroups = Array.isArray(this.candidateGroupIds) ? this.candidateGroupIds.map(item => item.id).join(',') : '';
}
}
},
'userTaskForm.candidateGroups': {
@@ -329,6 +462,8 @@ export default {
beforeDestroy() {
this.bpmnElement = null;
this.groupMap = null;
this.postMap = null;
this.deptPostMap = null;
}
};
</script>

View File

@@ -28,6 +28,11 @@
<el-table-column label="流程名称" prop="processDefinitionName" />
<el-table-column label="流程标识" prop="processDefinitionKey" />
<el-table-column label="任务名称" prop="name" />
<el-table-column label="执行操作">
<template slot-scope="scope">
<span>{{SysFlowTaskOperationType.getValue(scope.row.approvalType)}}</span>
</template>
</el-table-column>
<el-table-column label="任务发起人" prop="startUser" />
<el-table-column label="任务发起时间" prop="startTime" />
<el-table-column label="操作" width="100px">
@@ -149,7 +154,10 @@ export default {
readOnly: true,
flowEntryName: row.processDefinitionName,
processInstanceInitiator: row.processInstanceInitiator,
operationList: res.data.operationList.filter(item => item.type === this.SysFlowTaskOperationType.CO_SIGN)
// 在已办理任务中仅显示加签和撤销操作
operationList: res.data.operationList.filter(item => {
return item.type === this.SysFlowTaskOperationType.CO_SIGN || item.type === this.SysFlowTaskOperationType.REVOKE;
})
}
});
}).then(res => {});

View File

@@ -3,6 +3,18 @@
<div style="position: relative;">
<el-form label-width="100px" size="mini" label-position="right" @submit.native.prevent>
<filter-box :item-width="350">
<el-form-item label="流程名称">
<el-input class="filter-item" v-model="formMyTask.formFilter.processDefinitionName"
:clearable="true" placeholder="流程名称" />
</el-form-item>
<el-form-item label="流程标识">
<el-input class="filter-item" v-model="formMyTask.formFilter.processDefinitionKey"
:clearable="true" placeholder="流程标识" />
</el-form-item>
<el-form-item label="任务名称">
<el-input class="filter-item" v-model="formMyTask.formFilter.taskName"
:clearable="true" placeholder="任务名称" />
</el-form-item>
<el-button slot="operator" type="primary" :plain="true" size="mini" @click="refreshMyTask(true)">查询</el-button>
</filter-box>
</el-form>
@@ -52,6 +64,16 @@ export default {
data () {
return {
formMyTask: {
formFilter: {
processDefinitionName: undefined,
processDefinitionKey: undefined,
taskName: undefined
},
formFilterCopy: {
processDefinitionName: undefined,
processDefinitionKey: undefined,
taskName: undefined
},
taskWidget: new TableWidget(this.loadTaskData, this.loadTaskDataVerify, true, false, 'entryId', 1),
isInit: false
}
@@ -61,6 +83,9 @@ export default {
loadTaskData (params) {
if (params == null) params = {};
params = {
processDefinitionName: this.formMyTask.formFilterCopy.processDefinitionName,
processDefinitionKey: this.formMyTask.formFilterCopy.processDefinitionKey,
taskName: this.formMyTask.formFilterCopy.taskName,
...params
}
return new Promise((resolve, reject) => {
@@ -75,6 +100,9 @@ export default {
});
},
loadTaskDataVerify () {
this.formMyTask.formFilterCopy.processDefinitionName = this.formMyTask.formFilter.processDefinitionName;
this.formMyTask.formFilterCopy.processDefinitionKey = this.formMyTask.formFilter.processDefinitionKey;
this.formMyTask.formFilterCopy.taskName = this.formMyTask.formFilter.taskName;
return true;
},
onSubmit (row) {
@@ -101,7 +129,9 @@ export default {
flowEntryName: row.processDefinitionName,
processInstanceInitiator: row.processInstanceInitiator,
// 过滤掉加签操作,加签只有在已完成任务里可以操作
operationList: (res.data.operationList || []).filter(item => item.type !== this.SysFlowTaskOperationType.CO_SIGN),
operationList: (res.data.operationList || []).filter(item => {
return item.type !== this.SysFlowTaskOperationType.CO_SIGN && item.type !== this.SysFlowTaskOperationType.REVOKE;
}),
variableList: res.data.variableList
}
});