🎉 1.3.4.RELEASE

saber
ssc 4 years ago
parent bf875f26ee
commit 36f43dd8c8
  1. 15
      src/api/plugin/workflow/ops.js
  2. 260
      src/views/plugin/workflow/components/wf-user-select/index.vue
  3. 2
      src/views/plugin/workflow/mixins/custom-fields.js
  4. 6
      src/views/plugin/workflow/mixins/ex-form.js
  5. 6
      src/views/plugin/workflow/ops/detail.vue
  6. 275
      src/views/plugin/workflow/ops/list.vue
  7. 3
      src/views/plugin/workflow/process/components/flow.vue
  8. 50
      src/views/plugin/workflow/process/components/user-select.vue

@ -17,6 +17,21 @@ export const getList = (current, size, params) => {
})
}
/**
* 所有流程列表
*/
export const processList = (current, size, params) => {
return request({
url: `${prefix}/processList`,
method: 'get',
params: {
...params,
current,
size,
}
})
}
/**
* 所有办结流程
*/

@ -3,51 +3,26 @@
<el-input v-model="name"
:size="size"
suffix-icon="el-icon-user"
placeholder="人员选择(示例),谨慎使用"
:placeholder="placeholder || '人员选择'"
readonly
:disabled="disabled"
@click.native="handleSelect"></el-input>
<el-dialog ref="wf-dialog"
custom-class="wf-dialog"
:visible.sync="visible"
title="人员选择"
width="60%"
:before-close="handleClose"
append-to-body>
<avue-crud :option="option"
:table-loading="loading"
:data="data"
:page.sync="page"
v-model="form"
ref="crud"
@search-change="searchChange"
@search-reset="searchReset"
@selection-change="selectionList=$event"
@current-change="page.currentPage=$event"
@size-change="page.pageSize=$event"
@row-click="rowClick"
@on-load="onLoad">
<template v-if="checkType == 'radio'"
#radio="{row}">
<el-radio v-model="form.radio"
:label="row.id"><i></i></el-radio>
</template>
</avue-crud>
<span slot="footer"
class="dialog-footer">
<el-button @click="handleClose"
size="mini"> </el-button>
<el-button type="primary"
@click="handleConfirm"
size="mini"> </el-button>
</span>
</el-dialog>
<!-- 人员选择弹窗 -->
<wf-user-select ref="user-select"
:check-type="checkType"
:default-checked="value"
@onConfirm="handleUserSelectConfirm"></wf-user-select>
</div>
</template>
<script>
import { getUser } from "@/api/system/user"
import WfUserSelect from '../../process/components/user-select.vue'
export default {
name: 'user-select',
components: { WfUserSelect },
props: {
value: [String, Number],
checkType: { // radio checkbox
@ -69,217 +44,52 @@ export default {
disabled: {
type: Boolean,
default: false
},
placeholder: String,
userUrl: {
type: String,
default: () => {
return '/api/blade-user/search/user'
}
}
},
watch: {
value: {
handler(val) {
if (val) this.changeDefaultChecked()
},
immediate: true
},
checkType: {
handler(val) {
if (val == 'radio') {
this.$set(this.option, 'selection', false)
this.findObject(this.option.column, 'radio').hide = false
} else {
this.$set(this.option, 'selection', true)
this.findObject(this.option.column, 'radio').hide = true
if (val) {
const name = []
const checks = (val + '').split(',')
const asyncList = []
checks.forEach(c => {
asyncList.push(getUser(c))
})
Promise.all(asyncList).then(res => {
res.forEach(r => {
const data = r.data.data
if (data) name.push(data.realName)
})
this.$set(this, 'name', name.join(','))
})
}
},
immediate: true
}
},
computed: {
ids() {
let ids = [];
this.selectionList.forEach(ele => {
ids.push(ele.id);
});
return ids.join(",");
},
names() {
let names = [];
this.selectionList.forEach(ele => {
names.push(ele.realName);
});
return names.join(",");
}
},
data() {
return {
visible: false,
name: '',
form: {},
query: {},
loading: false,
page: {
pageSize: 10,
currentPage: 1,
total: 0
},
selectionList: [],
data: [],
option: {
size: 'mini',
searchSize: 'mini',
align: 'center',
menu: false,
addBtn: false,
header: false,
border: true,
tip: false,
reserveSelection: true,
highlightCurrentRow: true,
gutter: 5,
searchMenuSpan: 6,
selection: true,
column: [{
label: '',
prop: 'radio',
type: 'radio',
width: 55,
hide: true
}, {
label: '头像',
prop: 'avatar',
type: 'upload',
width: 90
}, {
label: '姓名',
prop: 'name',
overHidden: true,
search: true
}, {
label: '部门',
prop: 'deptName',
overHidden: true,
search: true
}, {
label: '职位',
prop: 'postName',
overHidden: true,
search: true
}]
}
}
},
mounted() {
this.onLoad(this.page).then(() => {
this.changeDefaultChecked()
})
},
methods: {
handleSelect() {
if (this.readonly || this.disabled) return
else this.visible = true
else this.$refs['user-select'].visible = true
},
handleConfirm() {
if (this.selectionList.length === 0) {
this.$message.warning("请选择至少一条数据")
return
}
this.$set(this, 'name', this.names)
this.$emit('input', this.ids)
this.handleClose()
},
handleClose(done) {
// this.selectionClear()
this.visible = false
if (done && typeof done == 'function') done()
},
searchReset() {
this.query = {}
this.onLoad(this.page)
},
searchChange(params, done) {
this.query = params
this.page.currentPage = 1
this.onLoad(this.page, params)
done()
},
selectionClear() {
this.selectionList = []
if (this.$refs.crud) this.$refs.crud.toggleSelection()
},
rowClick(row) {
if (this.checkType == 'radio') {
this.selectionList = [row]
this.$set(this.form, 'radio', row.id)
} else this.$refs.crud.toggleSelection([row])
},
changeDefaultChecked() {
if (!this.value) return
let defaultChecked = this.value + ''
const name = []
if (this.checkType == 'checkbox') {
// this.selectionClear()
const checks = defaultChecked.split(",")
if (checks.length > 0) {
setTimeout(() => {
checks.forEach(c => {
const row = this.data.find(d => d.id == c)
if (row) name.push(row.realName)
// TODO
// else {
//
// }
if (row && this.$refs.crud) {
this.$refs.crud.toggleRowSelection(row, true)
}
})
}, 500);
}
} else {
const row = this.data.find(d => d.id == defaultChecked)
if (row) {
this.selectionList = [row]
this.$set(this.form, 'radio', defaultChecked)
name.push(row.realName)
} else {
this.selectionList = []
this.$set(this.form, 'radio', '')
}
}
setTimeout(() => {
this.$set(this, 'name', name.join(','))
}, 1000);
},
onLoad(page, params = {}) {
return new Promise((resolve) => {
this.loading = true;
const param = {
current: page.currentPage,
size: page.pageSize,
...Object.assign(params, this.query)
}
this.$axios.get('/api/blade-user/search/user', { params: param }).then(res => {
this.page.total = res.data.data.total
this.data = res.data.data.records
this.loading = false
resolve()
})
})
handleUserSelectConfirm(id) {
this.$emit('input', id)
},
}
}
</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;
}
}
</style>

@ -4,7 +4,7 @@ export default {
customFields: [{
title: '业务字段',
list: [{
label: '人员选择(示例)',
label: '人员选择',
component: 'wf-user-select',
span: 24,
params: {

@ -72,7 +72,11 @@ export default {
const vars = []
column.forEach(col => {
let c = taskForm.find(s => s.id == col[props.prop])
if (c && c.readable) {
if (c && c.readable || !c) {
if (!c) { // 未重新点击节点设计表单字段可读可写。
if ((this.process.isOwner && this.process.status == 'todo') || !this.process.hasOwnProperty('isOwner')) c = { readable: true, writable: true }
else c = { readable: true, writable: false }
}
let event = ['change', 'blur', 'click', 'focus']
if (c.writable) { // 可写,记录需要提交的字段、处理字段默认值
vars.push(col[props.prop])

@ -3,7 +3,8 @@
<el-tab-pane label="申请信息"
name="first">
<el-card shadow="never">
<div ref="printBody">
<div ref="printBody"
class="wf-theme-default">
<avue-form v-if="option && ((option.column && option.column.length > 0) || (option.group && option.group.length > 0))"
v-model="form"
ref="form"
@ -37,9 +38,10 @@
import WfFlow from '../process/components/flow.vue'
import exForm from '../mixins/ex-form'
import theme from '../mixins/theme'
export default {
mixins: [exForm],
mixins: [exForm, theme],
components: { WfFlow },
props: {
processInstanceId: String,

@ -0,0 +1,275 @@
<template>
<basic-container>
<avue-crud ref="crud"
:option="option"
:table-loading="loading"
:data="data"
:page.sync="page"
v-model="form"
@search-change="searchChange"
@search-reset="searchReset"
@selection-change="selectionChange"
@current-change="currentChange"
@size-change="sizeChange"
@refresh-change="onLoad(page, query)"
@on-load="onLoad">
<template #processDefinitionName="{row}">
<el-link v-if="permission.wf_ops_detail"
style="font-size: 12px;"
type="primary"
@click="handleDetail(row)">{{row.processDefinitionName}}</el-link>
<span v-else>{{row.processDefinitionName}}</span>
</template>
<template #menu="{row}">
<el-button v-if="permission.wf_ops_follow"
type="text"
size="small"
icon="el-icon-search"
@click="handleFlow(row)">流程图</el-button>
</template>
</avue-crud>
<el-dialog :visible.sync="bpmnVisible"
append-to-body
destroy-on-close
title="流程图">
<wf-design ref="bpmn"
style="height: 500px;"
:options="bpmnOption"></wf-design>
</el-dialog>
<el-drawer :visible.sync="detailVisible"
:title="form.processDefinitionName"
custom-class="wf-drawer"
size="60%"
append-to-body>
<task-detail v-if="detailVisible"
:taskId="form.taskId"
:processInstanceId="form.processInstanceId"></task-detail>
</el-drawer>
</basic-container>
</template>
<script>
import { detail } from '@/api/plugin/workflow/process'
import { processList as getList } from "@/api/plugin/workflow/ops";
import { mapGetters } from "vuex";
import TaskDetail from './detail.vue'
import exForm from '../mixins/ex-form'
export default {
mixins: [exForm],
components: {
TaskDetail
},
data() {
return {
form: {},
query: {},
loading: true,
page: {
pageSize: 10,
currentPage: 1,
total: 0
},
selectionList: [],
option: {
size: 'mini',
height: 'auto',
calcHeight: 30,
tip: false,
border: true,
selection: true,
dialogType: 'drawer',
addBtn: false,
editBtn: false,
delBtn: false,
align: 'center',
searchSize: 'mini',
searchIndex: 3,
searchIcon: true,
column: [
{
label: '流程名称',
prop: 'processDefinitionName',
search: true,
overHidden: true
},
{
label: '流程标识',
prop: 'processDefinitionKey',
search: true,
overHidden: true
},
{
label: '流水号',
prop: 'serialNumber',
bind: 'variables.serialNumber',
search: true,
overHidden: true
},
{
label: "流程分类",
row: true,
type: 'tree',
dicUrl: '/api/blade-workflow/design/category/tree',
props: {
label: 'name',
value: 'id'
},
prop: "category",
search: true,
},
{
label: '申请人',
prop: 'startUsername',
search: true
},
{
label: '开始时间',
prop: 'createTime',
type: 'datetime',
format: 'yyyy-MM-dd HH:mm',
width: 165,
},
{
label: '结束时间',
prop: 'endTime',
type: 'datetime',
format: 'yyyy-MM-dd HH:mm',
width: 165,
},
{
label: '开始时间',
prop: 'startTimeRange',
type: 'datetime',
dataType: 'string',
format: 'yyyy-MM-dd HH:mm:ss',
valueFormat: 'yyyy-MM-dd HH:mm:ss',
hide: true,
search: true,
searchRange: true,
},
{
label: '结束时间',
prop: 'endTimeRange',
type: 'datetime',
dataType: 'string',
format: 'yyyy-MM-dd HH:mm:ss',
valueFormat: 'yyyy-MM-dd HH:mm:ss',
hide: true,
search: true,
searchRange: true,
},
{
label: '流程状态',
prop: 'processIsFinished',
dicData: [{
label: '进行中',
value: 'unfinished'
}, {
label: '已完成',
value: 'finished'
}, {
label: '已终结',
value: 'terminate'
}, {
label: '已撤销',
value: 'withdraw'
}, {
label: '已撤回',
value: 'recall'
}, {
label: '被驳回',
value: 'reject'
}],
type: 'select',
search: true
},
{
label: '流转详情',
prop: 'flow',
overHidden: true
}
]
},
data: [],
bpmnVisible: false,
bpmnOption: {},
detailVisible: false
};
},
computed: {
...mapGetters(["permission"]),
ids() {
let ids = [];
this.selectionList.forEach(ele => {
ids.push(ele.taskId);
});
return ids.join(",");
}
},
methods: {
handleDetail(row) {
this.dynamicRoute(row, 'detail', true).then(() => {
this.form = { ...row }
this.detailVisible = true
})
},
handleFlow(row) {
const { taskId, processInstanceId } = row
detail({ taskId, processInsId: processInstanceId }).then(res => {
const { process, flow } = res.data.data
this.bpmnOption = {
mode: 'view',
xml: process.xml,
flows: this.handleResolveFlows(flow)
}
this.bpmnVisible = true
})
},
searchReset() {
this.query = {};
this.onLoad(this.page);
},
searchChange(params, done) {
this.query = params;
this.page.currentPage = 1;
this.onLoad(this.page, params);
done();
},
selectionChange(list) {
this.selectionList = list;
},
currentChange(currentPage) {
this.page.currentPage = currentPage;
},
sizeChange(pageSize) {
this.page.pageSize = pageSize;
},
async 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
this.loading = false
}).catch(() => {
this.loading = false
})
}
}
};
</script>
<style lang="scss">
.wf-drawer {
.el-drawer__body {
padding: 0 20px;
overflow: auto;
}
}
</style>

@ -69,7 +69,8 @@ export default {
terminateComment: '终止意见',
addMultiInstanceComment: '加签',
deleteMultiInstanceComment: '减签',
withdrawComment: '撤回',
withdrawComment: '撤销',
recallComment: '撤回',
comment: '审批意见'
}
}

@ -1,5 +1,6 @@
<template>
<el-dialog ref="wf-dialog"
v-dialogdrag
custom-class="wf-dialog"
:visible.sync="visible"
title="人员选择"
@ -37,6 +38,8 @@
</el-dialog>
</template>
<script>
import { getUser } from "@/api/system/user"
export default {
props: {
defaultChecked: String,
@ -55,11 +58,6 @@ export default {
}
},
watch: {
visible: {
handler(val) {
if (val) this.changeDefaultChecked()
}
},
checkType: {
handler(val) {
if (val == 'radio') {
@ -75,18 +73,18 @@ export default {
},
computed: {
ids() {
let ids = [];
let ids = new Set()
this.selectionList.forEach(ele => {
ids.push(ele.id);
});
return ids.join(",");
ids.add(ele.id)
})
return Array.from(ids).join(",")
},
names() {
let names = [];
let names = new Set()
this.selectionList.forEach(ele => {
names.push(ele.realName);
});
return names.join(",");
names.add(ele.realName)
})
return Array.from(names).join(",")
}
},
data() {
@ -200,23 +198,35 @@ export default {
this.$set(this.form, 'radio', row.id)
} else this.$refs.crud.toggleSelection([row])
},
changeDefaultChecked() {
async changeDefaultChecked() {
if (!this.defaultChecked) return
let defaultChecked = this.defaultChecked
if (!this.defaultChecked) defaultChecked = ''
if (this.checkType == 'checkbox') {
this.selectionClear()
// this.selectionClear()
const checks = defaultChecked.split(",")
if (checks.length > 0) {
setTimeout(() => {
checks.forEach(c => {
const row = this.data.find(d => d.id == c)
checks.forEach(async (c) => {
let row = this.data.find(d => d.id == c) //
if (!row) {
row = this.selectionList.find(d => d.id == c) //
if (!row) {
let res = await getUser(c) //
if (res.data.data) row = res.data.data
}
}
if (row && this.$refs.crud) this.$refs.crud.toggleRowSelection(row, true)
})
}, 500);
}
} else {
const row = this.data.find(d => d.id == defaultChecked)
let row = this.data.find(d => d.id == defaultChecked)
if (!row) {
let res = await getUser(defaultChecked)
if (res.data.data) row = res.data.data
}
if (row) {
this.selectionList = [row]
this.$set(this.form, 'radio', defaultChecked)
@ -238,7 +248,7 @@ export default {
this.data = this.getAsVal(res, this.props.records) || []
this.loading = false
// this.changeDefaultChecked()
this.changeDefaultChecked()
})
},
getAsVal(obj, bind = '') {

Loading…
Cancel
Save