🎉 1.2.0.RELEASE

saber
ssc 4 years ago
parent 0165c01d75
commit bffb44a725
  1. 19
      src/api/plugin/workflow/model-scope.js
  2. 22
      src/api/plugin/workflow/ops.js
  3. 11
      src/api/plugin/workflow/process.js
  4. 45
      src/views/plugin/workflow/design/model.vue
  5. 20
      src/views/plugin/workflow/mixins/ex-form.js
  6. 34
      src/views/plugin/workflow/ops/index.vue
  7. 5
      src/views/plugin/workflow/process/components/button.vue
  8. 1
      src/views/plugin/workflow/process/components/detail.vue
  9. 2
      src/views/plugin/workflow/process/components/flow.vue
  10. 3
      src/views/plugin/workflow/process/components/form.vue
  11. 272
      src/views/plugin/workflow/process/components/user-option.vue
  12. 109
      src/views/plugin/workflow/process/components/user-select.vue

@ -0,0 +1,19 @@
import request from '@/router/axios'
const prefix = '/api/blade-workflow/design/model/scope'
export const getList = (params) => {
return request({
url: `${prefix}/list`,
method: 'get',
params
})
}
export const submit = (row) => {
return request({
url: `${prefix}/submit`,
method: 'post',
data: row
})
}

@ -136,4 +136,26 @@ export const getList = (current, size, params) => {
method: 'post',
data
})
}
/**
* 加签
*/
export const addMultiInstance = (data) => {
return request({
url: `${prefix}/addMultiInstance`,
method: 'post',
data
})
}
/**
* 减签
*/
export const deleteMultiInstance = (data) => {
return request({
url: `${prefix}/deleteMultiInstance`,
method: 'post',
data
})
}

@ -217,6 +217,17 @@ export const terminateProcess = (data) => {
})
}
/**
* 加签
*/
export const addMultiInstance = (data) => {
return request({
url: `${prefix}/addMultiInstance`,
method: 'post',
data
})
}
/**
* 用户列表
*/

@ -39,6 +39,11 @@
size="mini"
icon="el-icon-time"
@click="handleHistory(row)">历史</el-button>
<el-button v-if="permission.wf_design_model_history"
type="text"
size="mini"
icon="el-icon-time"
@click="handleScope(row)">权限</el-button>
</template>
</avue-crud>
@ -49,14 +54,22 @@
:option="{column:[{type:'tree',label:'流程分类',span:24,props:{label:'name',value:'id'},prop:'category',dicUrl:'/api/blade-workflow/design/category/tree',required:true,rules:[{required:true,message:'请选择分类'}]}]}"
@submit="handleDeploySubmit"></avue-form>
</el-dialog>
<user-option ref="userOption"
:user-option="userOption"
@submit="handleScopeSubmit"></user-option>
</basic-container>
</template>
<script>
import { getList, remove, deploy } from "@/api/plugin/workflow/model";
import { getList as scopeList, submit as scopeSubmit } from '@/api/plugin/workflow/model-scope'
import { mapGetters } from "vuex";
import UserOption from '../process/components/user-option.vue'
export default {
components: { UserOption },
data() {
return {
form: {},
@ -82,6 +95,7 @@ export default {
dialogType: 'drawer',
align: 'center',
searchMenuSpan: 6,
menuWidth: 320,
column: [
{
label: "模型key",
@ -110,6 +124,12 @@ export default {
data: [],
row: '',
categoryVisible: false,
userOption: {
userUrl: '/api/blade-user/search/user',
roleUrl: '/api/blade-system/search/role',
deptUrl: '/api/blade-system/search/dept',
postUrl: '/api/blade-system/search/post',
}
};
},
computed: {
@ -131,6 +151,31 @@ export default {
}
},
methods: {
handleScopeSubmit(list) {
list.forEach(l => l.val = l.value)
const { id, modelKey } = this.row
const param = {
modelId: id, modelKey,
scopeList: list
}
scopeSubmit(param).then(() => {
this.$message.success('操作成功')
})
},
handleScope(row) {
scopeList({ modelId: row.id }).then(res => {
this.$set(this.userOption, 'data', res.data.data.map(d => {
return {
value: d.val,
text: d.text,
type: d.type
}
}))
this.row = row
this.$refs.userOption.visible = true
})
},
handleDeploySubmit(form, done) {
const { id, category } = form
deploy({ id, category }).then(() => {

@ -1,4 +1,4 @@
import { getFormByProcessId, startProcess, detail, completeTask, transferTask, delegateTask, rollbackTask, terminateProcess } from '@/api/plugin/workflow/process'
import { getFormByProcessId, startProcess, detail, completeTask, transferTask, delegateTask, rollbackTask, terminateProcess, addMultiInstance } from '@/api/plugin/workflow/process'
import Layout from '@/page/index/'
import defaultValues from './default-values'
@ -22,6 +22,7 @@ export default {
comment: '', // 评论
bpmnOption: {}, // 流程图配置信息
watermarkText: '', //水印文字
defaultChecked: '', // 人员选择默认选中
}
},
mounted() {
@ -141,7 +142,7 @@ export default {
const { xml } = process
const bpmnOption = {
mode: 'view', xml,
mode: 'view', xml,
flows: this.handleResolveFlows(flow)
}
this.process = process
@ -219,6 +220,9 @@ export default {
this.$message.error("请填写批复意见")
return
}
if (type == 'assignee') this.defaultChecked = this.$refs.examineForm.examineForm.assignee
else if (type == 'copy') this.defaultChecked = this.$refs.examineForm.examineForm.copyUser
this.$refs['user-select'].visible = true
this.userSelectType = type
this.checkType = checkType
@ -244,6 +248,10 @@ export default {
this.$message.success("委托成功")
this.handleCloseTag('/plugin/workflow/process/todo')
})
} else if (type == 'addInstance') { // 加签
addMultiInstance(param).then(() => {
this.$message.success("加签成功")
})
} else if (type == 'copy') { // 抄送
this.$refs.examineForm.examineForm.copyUser = id
this.$refs.examineForm.examineForm.$copyUser = name
@ -301,6 +309,14 @@ export default {
comment = '终止:' + fullMessage
ff.class = 'nodeError'
}
if (type == 'addMultiInstanceComment') {
comment = '加签:' + fullMessage
ff.class = 'nodeWarn'
}
if (type == 'deleteMultiInstanceComment') {
comment = '减签:' + fullMessage
ff.class = 'nodeError'
}
if (type == 'comment') {
comment = '审批:' + fullMessage
ff.class = 'nodeSuccess'

@ -102,6 +102,10 @@
@click.native="getProcessNodes(row.taskId, row.processInstanceId, 'rollback')">指定回退</el-dropdown-item>
<el-dropdown-item v-if="permission.wf_ops_terminate"
@click.native="handleTerminateProcess(row.taskId)">终止</el-dropdown-item>
<el-dropdown-item v-if="permission.wf_ops_add_multi_instance && row.isMultiInstance"
@click.native="handleUserSelect({type: 'addMultiInstance', checkType: 'checkbox'}, row)">加签</el-dropdown-item>
<el-dropdown-item v-if="permission.wf_ops_delete_multi_instance && row.isMultiInstance"
@click.native="handleDeleteMultiInstance(row)">减签</el-dropdown-item>
<el-dropdown-item v-if="permission.wf_ops_copy"
@click.native="handleUserSelect({type: 'copy', checkType: 'checkbox'}, row)">抄送</el-dropdown-item>
<el-dropdown-item v-if="permission.wf_ops_urge"
@ -153,7 +157,7 @@
<script>
import { detail } from '@/api/plugin/workflow/process'
import {
getList, completeTask, changeTaskStatus, changeTaskAssignee, transferTask, delegateTask, copyTask, urgeTask, terminateProcess, processNodes, rollbackTask, dispatchTask
getList, completeTask, changeTaskStatus, changeTaskAssignee, transferTask, delegateTask, copyTask, urgeTask, terminateProcess, processNodes, rollbackTask, dispatchTask, addMultiInstance, deleteMultiInstance
} from "@/api/plugin/workflow/ops";
import { userList } from "@/api/plugin/workflow/process";
import { mapGetters } from "vuex";
@ -307,6 +311,20 @@ export default {
}
},
methods: {
handleDeleteMultiInstance(row) {
const { taskId } = row
this.$confirm(`确定要将选中的任务减签吗?`, '警告', {
type: 'warning',
}).then(() => {
this.loading = true
deleteMultiInstance({ taskId }).then(() => {
this.$message.success('减签成功')
this.onLoad(this.page, this.query)
}).catch(() => {
this.loading = false
})
}).catch(() => { })
},
handleDetail(row) {
this.form = { ...row }
this.detailVisible = true
@ -486,6 +504,20 @@ export default {
})
}).catch(() => { })
break;
case 'addMultiInstance':
this.$confirm(`确定要将选中的人员加签吗?`, '提示', {
type: 'warning',
}).then(() => {
this.$refs['user-select'].visible = false
addMultiInstance({ taskId: this.ids, assignee: id }).then(() => {
this.$message.success('加签成功')
this.onLoad(this.page, this.query)
this.selectionList = []
}).catch(() => {
this.loading = false
})
}).catch(() => { })
break;
}
},
handleFlow(row) {

@ -39,6 +39,11 @@
size="medium"
v-loading="loading"
@click="$emit('terminate')">终止</el-button>
<el-button v-if="process.isMultiInstance && buttonList.find(b => b.key == 'wf_add_instance')"
type="primary"
size="medium"
v-loading="loading"
@click="$emit('user-select', {type: 'addInstance', checkType: 'checkbox'})">加签</el-button>
</el-row>
<el-dialog :visible.sync="nodeVisible"
append-to-body

@ -62,6 +62,7 @@
<!-- 人员选择弹窗 -->
<user-select ref="user-select"
:check-type="checkType"
:default-checked="defaultChecked"
@onConfirm="handleUserSelectConfirm"></user-select>
</basic-container>
</template>

@ -57,6 +57,8 @@ export default {
delegateComment: '委托',
rollbackComment: '驳回意见',
terminateComment: '终止意见',
addMultiInstanceComment: '加签',
deleteMultiInstanceComment: '减签',
comment: '审批意见'
}
}

@ -97,6 +97,9 @@ export default {
this.$message.success("发起成功")
done()
this.handleCloseTag('/plugin/workflow/process/send')
}).catch(() => {
this.loading = false
done()
})
},
}

@ -0,0 +1,272 @@
<template>
<el-dialog ref="wf-dialog"
custom-class="wf-dialog"
:visible.sync="visible"
title="人员配置"
width="60%"
:before-close="handleClose"
append-to-body>
<el-table v-if="visible"
class="avue-crud"
:data="data"
border
size="mini">
<el-table-column align="center"
header-align="center"
width="80">
<template #header>
<el-button circle
type="primary"
size="mini"
icon="el-icon-plus"
@click="data.push({})"></el-button>
</template>
<template #default="{$index}">
<el-button circle
type="danger"
size="mini"
icon="el-icon-delete"
@click="data.splice($index, 1)"></el-button>
</template>
</el-table-column>
<el-table-column label="人员类型"
prop="type"
align="center"
header-align="center">
<template #default="{row, $index}">
<el-select v-model="row.type"
size="mini"
placeholder="人员类型"
@change="handleTypeChange($index)">
<el-option v-for="item in typeList"
:key="item.value"
:label="item.label"
:value="item.value"
:disabled="data.find(d => d.type == item.value)"></el-option>
</el-select>
</template>
</el-table-column>
<el-table-column label="值"
prop="text"
align="center"
header-align="center">
<template #default="{row, $index}">
<template v-if="row.type == 'user'">
<el-input v-model="row.text"
size="mini"
placeholder="用户"
readonly
@click.native="handleSelect($index, 'user-select')">
<template #append>
<el-button icon="el-icon-plus"></el-button>
</template>
</el-input>
</template>
<template v-else-if="row.type == 'role'">
<avue-input-tree :ref="`role_${$index}`"
v-model="row.value"
size="mini"
dataType="string"
multiple
clearable
placeholder="角色"
:dic="roleList"
:props="roleProps || {label: 'roleName', value: 'id'}"
@change="handleChange($index, `role_${$index}`)">
</avue-input-tree>
</template>
<template v-else-if="row.type == 'dept'">
<avue-input-tree :ref="`dept_${$index}`"
v-model="row.value"
size="mini"
dataType="string"
multiple
clearable
placeholder="部门"
:dic="deptList"
:props="deptProps || {label: 'deptName', value: 'id'}"
@change="handleChange($index, `dept_${$index}`)">
</avue-input-tree>
</template>
<template v-else-if="row.type == 'post'">
<avue-input-tree :ref="`post_${$index}`"
v-model="row.value"
size="mini"
dataType="string"
multiple
clearable
placeholder="职位"
:dic="postList"
:props="postProps || {label: 'postName', value: 'id'}"
@change="handleChange($index, `post_${$index}`)">
</avue-input-tree>
</template>
</template>
</el-table-column>
</el-table>
<template #footer>
<el-button @click="handleClose"
size="mini">取消</el-button>
<el-button type="primary"
@click="handleSubmit"
size="mini">确定</el-button>
</template>
<user-select ref="user-select"
check-type="checkbox"
:user-url="userUrl"
:custom-option="customOption"
:default-checked="defaultChecked"
@onConfirm="handleSelectConfirm"></user-select>
</el-dialog>
</template>
<script>
import UserSelect from './user-select.vue'
export default {
props: {
userOption: Object
},
components: {
UserSelect,
},
computed: {
userUrl() {
return this.userOption.userUrl
},
roleUrl() {
return this.userOption.roleUrl
},
deptUrl() {
return this.userOption.deptUrl
},
postUrl() {
return this.userOption.postUrl
},
customUrl() {
return this.userOption.customUrl
},
customOption() {
return this.userOption.customOption
},
roleProps() {
return this.customOption ? this.customOption.roleProps : null
},
deptProps() {
return this.customOption ? this.customOption.deptProps : null
},
postProps() {
return this.customOption ? this.customOption.postProps : null
}
},
watch: {
visible(val) {
if (!this.init) {
this.getRoleList()
this.getDeptList()
this.getPostList()
this.init = true
}
if (val && this.userOption && this.userOption.data) this.$set(this, 'data', JSON.parse(JSON.stringify(this.userOption.data)))
},
},
data() {
return {
init: false,
visible: false,
data: [],
roleList: [],
deptList: [],
postList: [],
selectIndex: 0,
defaultChecked: '',
typeList: [{
label: '用户',
value: 'user'
}, {
label: '角色',
value: 'role'
}, {
label: '部门',
value: 'dept'
}, {
label: '职位',
value: 'post'
}],
typeDic: {
user: '用户',
role: '角色',
dept: '部门',
post: '职位',
},
}
},
methods: {
handleSelect(index, ref) {
this.selectIndex = index
this.defaultChecked = this.data[index].value
this.$refs[ref].visible = true
},
handleSelectConfirm(id, name) {
this.$set(this.data[this.selectIndex], 'value', id)
this.$set(this.data[this.selectIndex], 'text', name)
},
handleTypeChange(index) {
this.$set(this.data, index, {
type: this.data[index].type
})
},
handleChange(index, ref) {
this.$nextTick(() => {
const text = this.$refs[ref].labelShow.join(',')
if (text) this.$set(this.data[index], 'text', text)
})
},
getRoleList() {
this.$axios.get(this.roleUrl).then(res => {
this.roleList = res.data.data
})
},
getDeptList() {
this.$axios.get(this.deptUrl).then(res => {
this.deptList = res.data.data
})
},
getPostList() {
this.$axios.get(this.postUrl, { current: 1, size: 999 }).then(res => {
this.postList = res.data.data.records
})
},
handleSubmit() {
this.$emit('submit', this.data.filter(d => d.type && d.value))
this.visible = false
},
handleClose(done) {
this.visible = false
if (done && typeof done == 'function') done()
}
}
}
</script>
<style lang="scss">
.wf-dialog {
display: flex;
flex-direction: column;
margin: 0 !important;
position: absolute;
top: 40%;
left: 50%;
transform: translate(-50%, -40%);
max-height: calc(100% - 30px);
max-width: calc(100% - 30px);
.el-dialog__body {
flex: 1;
overflow: auto;
}
.el-select {
width: 100%;
}
}
</style>

@ -6,8 +6,8 @@
width="60%"
:before-close="handleClose"
append-to-body>
<avue-crud v-if="visible"
:option="crudOption"
<avue-crud v-if="isInit && visible"
:option="option"
:table-loading="loading"
:data="data"
:page.sync="page"
@ -37,10 +37,16 @@
</el-dialog>
</template>
<script>
import { userList as getList } from "@/api/plugin/workflow/process";
export default {
props: {
defaultChecked: String,
userUrl: {
type: String,
default: () => {
return '/api/blade-user/search/user'
}
},
customOption: Object,
checkType: {
type: String,
default: () => {
@ -49,14 +55,19 @@ export default {
}
},
watch: {
visible: {
handler(val) {
if (val) this.changeDefaultChecked()
}
},
checkType: {
handler(val) {
if (val == 'radio') {
this.$set(this.crudOption, 'selection', false)
this.findObject(this.crudOption.column, 'radio').hide = false
this.$set(this.option, 'selection', false)
this.findObject(this.option.column, 'radio').hide = false
} else {
this.$set(this.crudOption, 'selection', true)
this.findObject(this.crudOption.column, 'radio').hide = true
this.$set(this.option, 'selection', true)
this.findObject(this.option.column, 'radio').hide = true
}
},
immediate: true
@ -80,6 +91,7 @@ export default {
},
data() {
return {
isInit: false,
visible: false,
form: {},
query: {},
@ -91,7 +103,13 @@ export default {
},
selectionList: [],
data: [],
crudOption: {
props: {
id: 'id',
name: 'realName',
records: 'data.data.records',
total: 'data.data.total',
},
option: {
size: 'mini',
searchSize: 'mini',
align: 'center',
@ -135,19 +153,32 @@ export default {
}
}
},
mounted() {
this.init()
},
methods: {
init() {
if (!this.isInit) {
if (this.customOption) {
const { column, userProps } = this.customOption
if (column) this.$set(this.option, 'column', column)
if (userProps) this.$set(this, 'props', userProps)
}
this.isInit = true
}
},
handleConfirm() {
if (this.selectionList.length === 0) {
this.$message.warning("请选择至少一条数据")
return
}
this.$emit('onConfirm', this.ids, this.names)
this.handleClose()
},
handleClose() {
if (this.checkType == 'checkbox') this.$refs.crud.toggleSelection()
this.$set(this, 'selectionList', [])
this.$set(this, 'form', { radio: '' })
handleClose(done) {
// this.selectionClear()
this.visible = false
if (done && typeof done == 'function') done()
},
searchReset() {
this.query = {}
@ -161,7 +192,7 @@ export default {
},
selectionClear() {
this.selectionList = []
this.$refs.crud.toggleSelection()
if (this.$refs.crud) this.$refs.crud.toggleSelection()
},
rowClick(row) {
if (this.checkType == 'radio') {
@ -169,14 +200,56 @@ export default {
this.$set(this.form, 'radio', row.id)
} else this.$refs.crud.toggleSelection([row])
},
changeDefaultChecked() {
let defaultChecked = this.defaultChecked
if (!this.defaultChecked) defaultChecked = ''
if (this.checkType == 'checkbox') {
this.selectionClear()
const checks = defaultChecked.split(",")
if (checks.length > 0) {
checks.forEach(c => {
const row = this.data.find(d => d.id == c)
if (row && this.$refs.crud) this.$refs.crud.toggleRowSelection(row, true)
})
}
} else {
const row = this.data.find(d => d.id == defaultChecked)
if (row) {
this.selectionList = [row]
this.$set(this.form, 'radio', defaultChecked)
} else {
this.selectionList = []
this.$set(this.form, 'radio', '')
}
}
},
onLoad(page, params = {}) {
this.loading = true;
getList(page.currentPage, page.pageSize, Object.assign(params, this.query)).then(res => {
const data = res.data.data
this.page.total = data.total
this.data = data.records
const param = {
current: page.currentPage,
size: page.pageSize,
...Object.assign(params, this.query)
}
this.$axios.get(this.userUrl, { params: param }).then(res => {
this.page.total = this.getAsVal(res, this.props.total)
this.data = this.getAsVal(res, this.props.records) || []
this.loading = false
this.changeDefaultChecked()
})
},
getAsVal(obj, bind = '') {
let result = this.deepClone(obj)
if (this.validatenull(bind)) return result
bind.split('.').forEach(ele => {
if (!this.validatenull(result[ele])) {
result = result[ele]
} else {
result = ''
}
});
return result
}
}
}

Loading…
Cancel
Save