🎉 1.0.7.RELEASE

main
ssc 5 years ago
parent 9d941dd805
commit 7411f1d692
  1. 26
      public/cdn/wf-design/index.umd.min.js
  2. 130
      src/views/plugin/workflow/design/index.vue
  3. 265
      src/views/plugin/workflow/mixins/ex-form.js
  4. 134
      src/views/plugin/workflow/process/components/button.vue
  5. 448
      src/views/plugin/workflow/process/components/detail.vue
  6. 85
      src/views/plugin/workflow/process/components/examForm.vue
  7. 40
      src/views/plugin/workflow/process/components/flow.vue
  8. 101
      src/views/plugin/workflow/process/components/form.vue
  9. 7
      src/views/plugin/workflow/process/components/user-select.vue
  10. 5
      src/views/plugin/workflow/process/copy.vue
  11. 5
      src/views/plugin/workflow/process/done.vue
  12. 230
      src/views/plugin/workflow/process/external/Leave/detail.vue
  13. 99
      src/views/plugin/workflow/process/external/Leave/start.vue
  14. 152
      src/views/plugin/workflow/process/external/template/detail.vue
  15. 58
      src/views/plugin/workflow/process/external/template/start.vue
  16. 5
      src/views/plugin/workflow/process/my-done.vue
  17. 5
      src/views/plugin/workflow/process/send.vue
  18. 11
      src/views/plugin/workflow/process/start.vue
  19. 5
      src/views/plugin/workflow/process/todo.vue

File diff suppressed because one or more lines are too long

@ -25,7 +25,7 @@
<avue-form ref="form1"
:option="step1.option"
v-model="step1.form">
<template slot="tip">
<template #tip>
<el-link type="primary"
:underline="false"
@click="$router.push('/plugin/workflow/design/form')">没有想要的表单点击去设计</el-link>
@ -73,6 +73,8 @@ import { submit, getDetail } from '@/api/plugin/workflow/model'
import { getList as buttonList } from '@/api/plugin/workflow/button'
import { userList } from '@/api/plugin/workflow/process'
import { fullscreenToggel } from "@/util/util";
import { mapGetters } from 'vuex'
export default {
@ -86,10 +88,25 @@ export default {
if (!val || val == 0) return
getDetail(val).then(res => {
this.process = res.data.data
const { formKey, xml } = this.process
this.$set(this.step1.form, 'formKey', formKey)
const { formKey, xml, exForm } = this.process
this.$set(this.step2.option, 'xml', xml)
this.$set(this.step2.option, 'process', this.process)
if (formKey.startsWith('wf_ex_')) { //
const column = []
exForm.forEach(ex => {
column.push({
label: ex.name,
prop: ex.id,
readable: true,
writable: true
})
})
this.$set(this.step1.form, 'column', column)
this.$set(this.step1.form, 'formType', 2)
this.$set(this.step1.form, 'exFormKey', formKey.substring(6))
} else {
this.$set(this.step1.form, 'formKey', formKey)
}
})
},
immediate: true
@ -109,6 +126,43 @@ export default {
icon: 'el-icon-warning-outline',
arrow: false,
column: [{
label: '表单类型',
prop: 'formType',
type: 'radio',
dicData: [{
label: '内置表单',
value: 1
}, {
label: '外置表单',
value: 2
}],
span: 24,
value: 1,
event: {
change: (val) => {
if (!val) return
if (val == 1) {
this.findObject(this.step1.option.group[0].column, 'exFormKey').display = false
this.findObject(this.step1.option.group[1].column, 'column').display = false
this.findObject(this.step1.option.group[0].column, 'formKey').display = true
this.findObject(this.step1.option.group[0].column, 'tip').display = true
this.findObject(this.step1.option.group[1].column, 'form').display = true
} else {
this.findObject(this.step1.option.group[0].column, 'exFormKey').display = true
this.findObject(this.step1.option.group[1].column, 'column').display = true
this.findObject(this.step1.option.group[0].column, 'formKey').display = false
this.findObject(this.step1.option.group[0].column, 'tip').display = false
this.findObject(this.step1.option.group[1].column, 'form').display = false
this.step1.option.group[1].display = true
}
}
}
}, {
label: '表单key',
prop: 'exFormKey',
display: false,
rules: [{ required: true, message: '请输入外置表单key' }]
}, {
label: '表单',
prop: 'formKey',
type: 'select',
@ -154,6 +208,38 @@ export default {
labelWidth: 0,
span: 24,
formslot: true
}, {
prop: 'column',
labelWidth: '0',
tip: '可用于控制外置表单字段的显隐配置,如果希望自己控制请忽略此字段',
tipPlacement: 'top',
span: 24,
type: 'dynamic',
children: {
align: 'center',
column: [{
label: '字段',
prop: 'label',
rules: [{ required: true, message: '请输入字段名' }]
}, {
label: '属性',
prop: 'prop',
rules: [{ required: true, message: '请输入属性名' }]
}, {
label: '默认可读',
prop: 'readable',
type: 'switch',
disabled: true,
value: true
}, {
label: '默认可写',
prop: 'writable',
type: 'switch',
disabled: true,
value: true
}]
},
display: false
}]
}]
},
@ -190,8 +276,16 @@ export default {
case 0:
this.$refs.form1.validate((valid, done) => {
if (valid) {
this.process.formKey = this.step1.form.formKey
this.$set(this.step2.option, 'form', this.step1.option1)
const { formType, formKey, exFormKey, column } = this.step1.form
if (formType == 1) { //
this.process.formKey = formKey
this.$set(this.step2.option, 'form', this.step1.option1)
} else { //
this.process.formKey = "wf_ex_" + exFormKey
this.$set(this.step2.option, 'exForm', {
exFormKey, column
})
}
this.step++
done()
}
@ -298,30 +392,8 @@ export default {
})
},
handleFullScreen() {
let element = document.querySelector("#bpmn2");
if (this.fullscreen) {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.webkitCancelFullScreen) {
document.webkitCancelFullScreen();
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
} else if (document.msExitFullscreen) {
document.msExitFullscreen();
}
} else {
if (element.requestFullscreen) {
element.requestFullscreen();
} else if (element.webkitRequestFullScreen) {
element.webkitRequestFullScreen();
} else if (element.mozRequestFullScreen) {
element.mozRequestFullScreen();
} else if (element.msRequestFullscreen) {
// IE11
element.msRequestFullscreen();
}
}
this.fullscreen = !this.fullscreen;
fullscreenToggel()
this.$store.commit('SET_COLLAPSE')
},
}
}

@ -0,0 +1,265 @@
import { getFormByProcessId, startProcess, detail, completeTask, transferTask, delegateTask, rollbackTask, terminateProcess } from '@/api/plugin/workflow/process'
import Layout from '@/page/index/'
import defaultValues from './default-values'
import Print from '../util/print'
import { mapGetters } from 'vuex'
export default {
mixins: [defaultValues],
computed: {
...mapGetters(['tag', 'userInfo']),
},
data() {
return {
process: {}, // 流程定义/流程实例信息
buttonList: [], // 配置按钮信息
flow: [], // 流转信息
userSelectType: '', // 人员选择类型 transfer转办 delegate委托 copy抄送 assignee审核人
checkType: 'radio', // 人员选择check类型 radio单选 checkbox多选
comment: '', // 评论
bpmnOption: {}, // 流程图配置信息
watermarkText: '', //水印文字
}
},
mounted() {
this.watermarkText = this.userInfo.user_name + " " + this.userInfo.real_name
},
methods: {
// 动态路由跳转
dynamicRoute(row, type) {
const { id, taskId, processInstanceId, formKey, formUrl } = row
let param = Buffer.from(JSON.stringify({
processId: id,
taskId,
processInsId: processInstanceId
})).toString('base64')
if (formKey && formKey.startsWith('wf_ex_')) {
if (formUrl) { // 配置了自定义路由
this.$router.push(formUrl + `?p=${param}`)
} else { // 动态添加路由
this.$router.addRoutes([{
path: `/workflow/process/external`,
component: Layout,
children: [{
path: `${formKey.substring(6)}/${type}`,
name: type == 'start' ? '发起流程' : '流程详情',
component: () =>
import( /* webpackChunkName: "views" */ `@/views/plugin/workflow/process/external/${formKey.substring(6)}/${type}.vue`),
}]
}])
this.$router.push(`/workflow/process/external/${formKey.substring(6)}/${type}?p=${param}`)
}
} else {
this.$router.push(`/workflow/process/${type}/${param}`)
}
},
// 根据可读可写,过滤avue column
filterAvueColumn(column, taskForm, props = { label: 'label', prop: 'prop' }) {
if (!column || column.length == 0) return { column }
const values = []
const vars = []
column.forEach(col => {
let c = taskForm.find(s => s.id == col[props.prop])
if (c && c.readable) {
if (c.writable) { // 可写,记录需要提交的字段、处理字段默认值
vars.push(col[props.prop])
if (col.value) col.value = this.getDefaultValues(col.value)
} else { // 不可写,清除校验与默认值
if (col.type == 'dynamic') {
col.children.addBtn = false
col.children.delBtn = false
} else {
col.readonly = true
col.disabled = true
}
delete col.rules
delete col.value
}
if (col.type == 'dynamic') { // 处理子表单
col.children.column = this.filterAvueColumn(col.children.column, taskForm).column
}
values.push(col)
}
})
return { column: values, vars }
},
/**
* 获取流程发起表单
* @param processId 流程定义id
* @returns Promise({"process": "流程定义信息", "startForm": "开始节点表单"})
*/
getStartForm(processId) {
return new Promise((resolve, reject) => {
getFormByProcessId({ processId }).then(res => {
const { process } = res.data.data
this.process = process
this.tag.label = '发起流程 - ' + process.name
resolve(res.data.data)
}).catch(() => {
reject()
})
})
},
/**
* 发起流程
* @param form {"processId": "流程定义id", ...表单自定义字段变量}
*/
handleStartProcess(form) {
return new Promise((resolve, reject) => {
startProcess(form).then(() => {
resolve()
}).catch(() => {
reject()
})
})
},
/**
* 获取流程任务详情
* @param taskId 任务id
* @param processInsId 流程实例id
* @returns Promise({"process": "流程实例信息", "form": "表单信息", "flow": "流转信息", "button": "配置按钮信息", "bpmnOption": "流程图配置"})
*/
getTaskDetail(taskId, processInsId) {
return new Promise((resolve, reject) => {
detail({ taskId, processInsId }).then(res => {
const { process, form, flow, button } = res.data.data
const { xml } = process
const flows = []
flow.forEach(f => {
const ff = {
id: f.historyActivityId
}
if (f.historyActivityType == 'sequenceFlow') ff.class = "lineWarn"
else ff.class = "nodeWarn"
flows.push(ff)
})
const bpmnOption = {
mode: 'view', xml, flows
}
this.process = process
this.flow = flow
this.buttonList = button
this.bpmnOption = bpmnOption
this.tag.label = '流程详情 - ' + process.processDefinitionName
resolve({ process, form, flow, button, bpmnOption })
}).catch(() => {
reject()
})
})
},
/**
* 任务审核
* @param pass 驳回/通过
*/
handleCompleteTask(pass, variables) {
return new Promise((resolve, reject) => {
const { comment, copyUser, assignee } = this.$refs.examineForm.examineForm
if (!pass && !comment) {
this.$message.error("请填写批复意见")
this.submitLoading = false
reject()
return
}
const { taskId, processInstanceId, processDefinitionName, processDefinitionId } = this.process
const param = {
taskId, processInstanceId, processDefinitionName, processDefinitionId, pass,
comment, copyUser, assignee, variables
}
completeTask(param).then(() => {
resolve()
}).catch(() => {
reject()
})
})
},
/**
* 驳回到指定节点
* @param nodeId 节点id
*/
handleRollbackTask(nodeId) {
const { taskId } = this.process
rollbackTask({ comment: this.comment, nodeId, taskId }).then(() => {
this.$message.success("回退成功")
this.handleCloseTag('/plugin/workflow/process/todo')
})
},
/**
* 终止流程
*/
handleTerminateProcess() {
const comment = this.comment
if (!comment) {
this.$message.error("请填写批复意见")
return
}
this.$confirm('确定要终止此流程吗?', '警告', {
type: 'warning'
}).then(() => {
const { taskId } = this.process
terminateProcess({ taskId, comment }).then(() => {
this.$message.success("操作成功")
this.handleCloseTag('/plugin/workflow/process/todo')
})
}).catch(() => {
})
},
// 人员选择弹窗
handleUserSelect({ type, checkType }) {
if (!this.comment && ['transfer', 'delegate'].includes(type)) {
this.$message.error("请填写批复意见")
return
}
this.$refs['user-select'].visible = true
this.userSelectType = type
this.checkType = checkType
},
// 选人回调
handleUserSelectConfirm(id, name) {
const { comment, copyUser } = this.$refs.examineForm.examineForm
const { taskId, processInstanceId, processDefinitionName, processDefinitionId } = this.process
const type = this.userSelectType
const param = {
taskId, processInstanceId, processDefinitionName, processDefinitionId,
assignee: id,
comment, copyUser
}
if (type == 'transfer') {
transferTask(param).then(() => { // 转办
this.$message.success("转办成功")
this.handleCloseTag('/plugin/workflow/process/todo')
})
} else if (type == 'delegate') { // 委托
delegateTask(param).then(() => {
this.$message.success("委托成功")
this.handleCloseTag('/plugin/workflow/process/todo')
})
} else if (type == 'copy') { // 抄送
this.$refs.examineForm.examineForm.copyUser = id
this.$refs.examineForm.examineForm.$copyUser = name
} else if (type == 'assignee') { // 指定下一步审批人
this.$refs.examineForm.examineForm.assignee = id
this.$refs.examineForm.examineForm.$assignee = name
}
this.$refs['user-select'].visible = false
},
handlePrint() { //打印
// this.watermark({ text: this.watermarkText })
Print(this.$refs.printBody)
},
// 关闭当前tag,并跳转
handleCloseTag(path) {
this.$store.commit('DEL_TAG', this.tag)
if (path) this.$router.push(path)
}
}
}

@ -0,0 +1,134 @@
<template>
<div>
<div style="height: 120px;"></div>
<el-row class="foot-item avue-affix"
:style="{width: isCollapse? 'calc(100% - 80px)': 'calc(100% - 260px)' }"
id="avue-view">
<el-button v-if="buttonList.find(b => b.key == 'wf_pass')"
type="success"
size="medium"
v-loading="loading"
@click="$emit('examine', true)">通过</el-button>
<el-button v-if="buttonList.find(b => b.key == 'wf_reject')"
type="danger"
size="medium"
v-loading="loading"
@click="$emit('examine', false)">驳回</el-button>
<el-button v-if="buttonList.find(b => b.key == 'wf_transfer')"
type="primary"
size="medium"
v-loading="loading"
@click="$emit('user-select', {type: 'transfer', checkType: 'radio'})">转办</el-button>
<el-button v-if="buttonList.find(b => b.key == 'wf_delegate')"
type="warning"
size="medium"
v-loading="loading"
@click="$emit('user-select', {type: 'delegate', checkType: 'radio'})">委托</el-button>
<el-button v-if="buttonList.find(b => b.key == 'wf_print')"
type="info"
size="medium"
v-loading="loading"
@click="$emit('print')">打印</el-button>
<el-button v-if="buttonList.find(b => b.key == 'wf_print')"
type="success"
size="medium"
v-loading="loading"
@click="handleRollback">指定回退</el-button>
<el-button v-if="buttonList.find(b => b.key == 'wf_terminate')"
type="danger"
size="medium"
v-loading="loading"
@click="$emit('terminate')">终止</el-button>
</el-row>
<el-dialog :visible.sync="nodeVisible"
append-to-body
title="选择回退节点">
<avue-form v-if="nodeVisible"
v-model="nodeForm"
:option="nodeOption"
@submit="handleNodeSubmit"></avue-form>
</el-dialog>
</div>
</template>
<script>
import { backNodes } from '@/api/plugin/workflow/process'
import { mapGetters } from 'vuex'
export default {
name: 'wf-button',
computed: {
...mapGetters(['isCollapse']),
},
props: {
loading: {
type: Boolean,
default: false
},
buttonList: {
type: Array,
default: () => {
return []
}
},
process: Object,
comment: String
},
data() {
return {
nodeVisible: false,
nodeForm: {},
nodeOption: {
column: [{
label: '节点',
prop: 'nodeId',
type: 'select',
props: {
label: 'nodeName',
value: 'nodeId'
},
span: 24,
rules: [{ required: true, message: '请选择回退节点', trigger: 'change' }]
}]
}
}
},
methods: {
handleRollback() { // 退
if (!this.comment) {
this.$message.error("请填写批复意见")
return
}
const { taskId } = this.process
backNodes({ taskId }).then(res => {
this.findObject(this.nodeOption.column, 'nodeId').dicData = res.data.data
this.nodeVisible = true
})
},
handleNodeSubmit() { // 退
const { nodeId } = this.nodeForm
this.$emit('rollback', nodeId)
},
}
}
</script>
<style lang="scss" scoped>
.foot-item {
position: fixed;
bottom: 0;
margin-left: -20px;
// right: 0;
z-index: 101;
height: 66px;
background-color: #fff;
display: flex;
justify-content: center;
align-items: center;
-webkit-transition: 0.3s;
transition: 0.3s;
-webkit-box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
</style>

@ -21,99 +21,49 @@
<el-card shadow="never"
style="margin-top: 20px"
v-if="process.status == 'todo'">
<avue-form v-model="examineForm"
ref="examineForm"
:option="examineOption">
</avue-form>
<wf-examine-form ref="examineForm"
:comment.sync="comment"
:process="process"
@user-select="handleUserSelect"></wf-examine-form>
</el-card>
</el-tab-pane>
<el-tab-pane label="流转信息"
name="second">
<el-card shadow="never"
style="margin-top: 5px;">
<el-row type="flex"
class="row-bg">
<el-timeline>
<template v-for="item in flow">
<el-timeline-item v-if="item.historyActivityType != 'sequenceFlow'"
:key="item.id"
:timestamp="item.endTime || item.createTime"
placement="top">
<el-card shadow="never">
<p>{{item.assigneeName}} [{{item.createTime}}] 开始处理 [{{item.historyActivityName}}] 环节</p>
<p v-if="item.historyActivityDurationTime">任务历时 [{{item.historyActivityDurationTime}}]</p>
<p v-if="item.commentObj && item.commentObj.type == 'transferComment'">转办意见: [{{item.comment}}]</p>
<p v-if="item.commentObj && item.commentObj.type == 'delegateComment'">委托意见: [{{item.comment}}]</p>
<p v-if="item.commentObj && item.commentObj.type == 'rollbackComment'">驳回意见: [{{item.comment}}]</p>
<p v-if="item.commentObj && item.commentObj.type == 'terminateComment'">终止意见: [{{item.comment}}]</p>
<p v-if="item.commentObj && item.commentObj.type == 'comment'">审批意见: [{{item.comment}}]</p>
<p v-if="item.endTime">结束时间: [{{item.endTime}}]</p>
</el-card>
</el-timeline-item>
</template>
</el-timeline>
</el-row>
<wf-flow :flow="flow"></wf-flow>
</el-card>
</el-tab-pane>
<el-tab-pane label="流程跟踪"
name="third">
<template v-if="activeName == 'third'">
<el-card shadow="never"
style="margin-top: 5px;">
<wf-design ref="bpmn"
style="height: 500px;"
:options="bpmnOption"></wf-design>
</el-card>
</template>
</el-tab-pane>
</el-tabs>
<template v-if="activeName == 'third'">
<el-card v-if="process && process.xml"
shadow="never"
style="margin-top: 5px;">
<wf-design ref="bpmn"
style="height: 500px;"
:options="bpmnOption"></wf-design>
</el-card>
</template>
<!-- 底部按钮 -->
<template v-if="process.status == 'todo'">
<div style="height: 120px;"></div>
<el-row class="foot-item avue-affix"
:style="{width: isCollapse? 'calc(100% - 80px)': 'calc(100% - 260px)' }"
id="avue-view">
<el-button v-if="buttonList.find(b => b.key == 'wf_pass')"
type="success"
size="medium"
v-loading="submitLoading"
@click="handleCompleteTask(true)">通过</el-button>
<el-button v-if="buttonList.find(b => b.key == 'wf_reject')"
type="danger"
size="medium"
v-loading="submitLoading"
@click="handleCompleteTask(false)">驳回</el-button>
<el-button v-if="buttonList.find(b => b.key == 'wf_transfer')"
type="primary"
size="medium"
v-loading="submitLoading"
@click="handleUserSelect('transfer')">转办</el-button>
<el-button v-if="buttonList.find(b => b.key == 'wf_delegate')"
type="warning"
size="medium"
v-loading="submitLoading"
@click="handleUserSelect('delegate')">委托</el-button>
<el-button v-if="buttonList.find(b => b.key == 'wf_print')"
type="info"
size="medium"
v-loading="submitLoading"
@click="handlePrint()">打印</el-button>
<el-button v-if="buttonList.find(b => b.key == 'wf_print')"
type="success"
size="medium"
v-loading="submitLoading"
@click="handleRollback()">指定回退</el-button>
<el-button v-if="buttonList.find(b => b.key == 'wf_terminate')"
type="danger"
size="medium"
v-loading="submitLoading"
@click="handleTerminate()">终止</el-button>
</el-row>
<wf-button :loading="submitLoading"
:button-list="buttonList"
:process="process"
:comment="comment"
@examine="handleExamine"
@user-select="handleUserSelect"
@print="handlePrint"
@rollback="handleRollbackTask"
@terminate="handleTerminateProcess"></wf-button>
</template>
<!-- 人员选择弹窗 -->
<user-select ref="user-select"
:select-type="selectType"
@onClose="handleClose"
@onConfirm="handleConfirm"></user-select>
:check-type="checkType"
@onConfirm="handleUserSelectConfirm"></user-select>
<!-- 选择回退节点弹窗 -->
<el-dialog :visible.sync="nodeVisible"
append-to-body
title="选择回退节点">
@ -125,20 +75,16 @@
</template>
<script>
import { detail, completeTask, transferTask, delegateTask, backNodes, rollbackTask, terminateProcess } from '@/api/plugin/workflow/process'
import WfExamineForm from './examForm.vue'
import WfButton from './button.vue'
import WfFlow from './flow.vue'
import userSelect from './user-select'
import { mapGetters } from 'vuex'
import Print from '../../util/print'
import defaultValues from '../../mixins/default-values'
import exForm from '../../mixins/ex-form'
export default {
mixins: [defaultValues],
components: { userSelect },
computed: {
...mapGetters(['tag', 'userInfo', 'isCollapse']),
},
mixins: [exForm],
components: { userSelect, WfExamineForm, WfButton, WfFlow },
watch: {
'$route.params.params': {
handler(val) {
@ -155,91 +101,25 @@ export default {
return {
activeName: 'first',
form: {},
option: {
menuBtn: false,
},
examineForm: {},
examineOption: {
menuBtn: false,
column: [{
label: '批复意见',
prop: 'comment',
type: 'textarea',
span: 24,
}, {
label: '抄送人',
prop: '$copyUser',
placeholder: '请选择 抄送人',
readonly: true,
append: '+',
span: 24,
event: {
click: () => {
this.$refs['user-select'].visible = true
this.selectType = 'checkbox'
this.userSelectType = 'copy'
}
}
}, {
label: '指定审批人',
prop: '$assignee',
placeholder: '请选择 下一级审批人,如不选择则使用默认处理人,驳回时无效',
readonly: true,
append: '+',
span: 24,
event: {
click: () => {
this.$refs['user-select'].visible = true
this.selectType = 'radio'
this.userSelectType = 'assignee'
}
}
}]
},
process: {},
flow: [],
bpmnOption: {
mode: 'view'
},
vars: [],
submitLoading: false,
buttonList: [],
watermarkText: '', //
userSelectType: '', // transfer delegate
selectType: 'radio',
nodeVisible: false,
nodeForm: {},
nodeOption: {
column: [{
label: '节点',
prop: 'nodeId',
type: 'select',
props: {
label: 'nodeName',
value: 'nodeId'
},
span: 24,
rules: [{ required: true, message: '请选择回退节点', trigger: 'change' }]
}]
}
option: {},
vars: [], //
submitLoading: false, // loading
}
},
created() {
this.watermarkText = this.userInfo.user_name + " " + this.userInfo.real_name
},
methods: {
//
getDetail(taskId, processInsId) {
detail({ taskId, processInsId }).then(res => {
const { process, form, flow, button } = res.data.data
const { variables, status, xml } = process
this.getTaskDetail(taskId, processInsId).then(res => {
const { process, form } = res
const { variables, status } = process
let { allForm, taskForm } = form
if (allForm) {
const option = eval('(' + allForm + ')')
option.menuBtn = false
if (status != 'todo') {
const { column, group } = option
if (status != 'todo') { //
option.detail = true
const { column, group } = option
if (column && column.length > 0) { // column
column.forEach(col => {
if (col.type == 'dynamic') col.children.column.forEach(cc => delete cc.value)
@ -257,93 +137,17 @@ export default {
}
})
}
}
else {
const columnArr = []
} else {
const columnFilter = this.filterAvueColumn(column, taskForm)
const columnArr = columnFilter.column
let vars = columnFilter.vars
const groupArr = []
const vars = []
const { column, group } = option
if (column && column.length > 0) { // column
column.forEach(col => {
const c = taskForm.find(s => s.id == col.prop)
if (c && c.readable) {
if (!c.writable) {
if (col.type == 'dynamic') {
col.children.addBtn = false
col.children.delBtn = false
} else {
col.readonly = true
col.disabled = true
}
delete col.rules
delete col.value
} else {
vars.push(col.prop)
if (col.value) col.value = this.getDefaultValues(col.value)
}
if (col.type == 'dynamic') { //
const childrenColumnArr = []
col.children.column.forEach(cc => {
let c2 = taskForm.find(s => s.id == cc.prop)
if (c2 && c2.readable) {
if (!c2.writable) {
cc.readonly = true
cc.disabled = true
delete cc.rules
delete cc.value
} else if (cc.value) cc.value = this.getDefaultValues(cc.value)
childrenColumnArr.push(cc)
}
})
col.children.column = childrenColumnArr
}
columnArr.push(col)
}
})
}
if (group && group.length > 0) { // group
group.forEach(gro => {
if (gro.column && gro.column.length > 0) {
const groupColumnArr = []
gro.column.forEach(col => {
const c = taskForm.find(s => s.id == col.prop)
if (c && c.readable) {
if (!c.writable) {
if (col.type == 'dynamic') {
col.children.addBtn = false
col.children.delBtn = false
}
else {
col.readonly = true
col.disabled = true
}
delete col.rules
delete col.value
} else {
vars.push(col.prop)
if (col.value) col.value = this.getDefaultValues(col.value)
}
if (col.type == 'dynamic') { //
const childrenColumnArr = []
col.children.column.forEach(cc => {
let c2 = taskForm.find(s => s.id == cc.prop)
if (c2 && c2.readable) {
if (!c2.writable) {
cc.readonly = true
cc.disabled = true
delete cc.rules
delete cc.value
} if (cc.value) cc.value = this.getDefaultValues(cc.value)
childrenColumnArr.push(cc)
}
})
col.children.column = childrenColumnArr
}
groupColumnArr.push(col)
}
})
gro.column = groupColumnArr
}
const groupFilter = this.filterAvueColumn(gro.column, taskForm)
gro.column = groupFilter.column
vars = vars.conact(groupFilter.vars)
if (gro.column.length > 0) groupArr.push(gro)
})
}
@ -366,152 +170,32 @@ export default {
this.option = option
this.form = variables
this.process = process
this.flow = flow
this.buttonList = button
this.tag.label = '流程详情 - ' + process.processDefinitionName
const flows = []
flow.forEach(f => {
const ff = {
id: f.historyActivityId
}
if (f.historyActivityType == 'sequenceFlow') ff.class = "lineWarn"
else ff.class = "nodeWarn"
flows.push(ff)
})
this.bpmnOption = {
mode: 'view',
xml,
flows
}
}
})
},
handleCompleteTask(pass) {
//
handleExamine(pass) {
this.submitLoading = true
const { comment, copyUser, assignee } = this.examineForm
if (!pass && !comment) {
this.$message.error("请填写批复意见")
this.submitLoading = false
return
}
this.$refs.form.validate((valid) => {
this.$refs.form.validate((valid, done) => {
if (valid) {
const variables = {}
this.vars.forEach(v => {
if (v != 'comment' && this.form[v]) variables[v] = this.form[v]
})
const { taskId, processInstanceId, processDefinitionName, processDefinitionId } = this.process
const params = {
taskId, processInstanceId, processDefinitionName, processDefinitionId, pass,
comment, copyUser, assignee, variables
}
completeTask(params).then(() => {
this.handleCompleteTask(pass, variables).then(() => {
this.$message.success("处理成功")
this.$store.commit('DEL_TAG', this.tag)
this.$router.push("/plugin/workflow/process/todo")
this.handleCloseTag('/plugin/workflow/process/todo')
}).catch(() => {
done()
this.submitLoading = false
})
} else {
done()
this.submitLoading = false
}
})
},
handlePrint() { //
// this.watermark({ text: this.watermarkText })
Print(this.$refs.printBody)
},
handleRollback() { // 退
const { comment } = this.examineForm
if (!comment) {
this.$message.error("请填写批复意见")
return
}
const { taskId } = this.process
backNodes({ taskId }).then(res => {
this.findObject(this.nodeOption.column, 'nodeId').dicData = res.data.data
this.nodeVisible = true
})
},
handleNodeSubmit() { // 退
const { comment } = this.examineForm
const { nodeId } = this.nodeForm
const { taskId } = this.process
rollbackTask({ comment, nodeId, taskId }).then(() => {
this.$message.success("回退成功")
this.closeTag()
})
},
handleTerminate() { //
const { comment } = this.examineForm
if (!comment) {
this.$message.error("请填写批复意见")
return
}
this.$confirm('确定要终止此流程吗?', '警告', {
type: 'warning'
}).then(() => {
const { taskId } = this.process
terminateProcess({ taskId, comment }).then(() => {
this.$message.success("操作成功")
this.closeTag()
})
}).catch(() => {
})
},
handleUserSelect(type) { //
const { comment } = this.examineForm
if (!comment) {
this.$message.error("请填写批复意见")
return
}
this.$refs['user-select'].visible = true
this.userSelectType = type
},
handleClose() { //
this.$refs['user-select'].visible = false
},
handleConfirm(id, name) { //
const { comment } = this.examineForm
const type = this.userSelectType
const param = {
taskId: this.process.taskId,
assignee: id,
comment
}
if (type == 'transfer') {
transferTask(param).then(() => { //
this.$message.success("转办成功")
this.closeTag()
})
} else if (type == 'delegate') { //
delegateTask(param).then(() => {
this.$message.success("委托成功")
this.closeTag()
})
} else if (type == 'copy') { //
this.examineForm.copyUser = id
this.examineForm.$copyUser = name
} else if (type == 'assignee') { //
this.examineForm.assignee = id
this.examineForm.$assignee = name
}
this.$refs['user-select'].visible = false
},
closeTag() {
this.$store.commit('DEL_TAG', this.tag)
this.$router.push("/plugin/workflow/process/todo")
}
}
}
</script>
@ -526,20 +210,4 @@ export default {
justify-content: space-between;
padding: 0 10px 10px 0;
}
.foot-item {
position: fixed;
bottom: 0;
margin-left: -20px;
// right: 0;
z-index: 101;
height: 66px;
background-color: #fff;
display: flex;
justify-content: center;
align-items: center;
-webkit-transition: 0.3s;
transition: 0.3s;
-webkit-box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
</style>

@ -0,0 +1,85 @@
<template>
<avue-form v-model="examineForm"
ref="examineForm"
:option="examineOption"></avue-form>
</template>
<script>
export default {
name: 'wf-exam-form',
props: {
process: {
type: Object,
default: () => {
return {}
}
}
},
watch: {
process: {
handler(val) {
if (!val) return
if (val.hideCopy) {
this.findObject(this.examineOption.column, '$copyUser').display = false
}
if (val.hideExamine) {
this.findObject(this.examineOption.column, '$assignee').display = false
}
},
deep: true,
immediate: true
}
},
data() {
return {
examineForm: {},
examineOption: {
menuBtn: false,
column: [{
label: '批复意见',
prop: 'comment',
type: 'textarea',
span: 24,
event: {
change: (val) => {
this.$emit('update:comment', val)
}
}
}, {
label: '抄送人',
prop: '$copyUser',
placeholder: '请选择 抄送人',
readonly: true,
append: '+',
span: 24,
event: {
click: () => {
this.$emit('user-select', { type: 'copy', checkType: 'checkbox' })
}
}
}, {
label: '指定审批人',
prop: '$assignee',
placeholder: '请选择 下一级审批人,如不选择则使用默认处理人,驳回时无效',
readonly: true,
append: '+',
span: 24,
event: {
click: () => {
this.$emit('user-select', { type: 'assignee', checkType: 'radio' })
}
}
}]
},
}
},
methods: {
getComment() {
return this.examineForm.comment
}
}
}
</script>
<style>
</style>

@ -0,0 +1,40 @@
<template>
<el-row type="flex">
<el-timeline>
<template v-for="item in flow">
<el-timeline-item v-if="item.historyActivityType != 'sequenceFlow'"
:key="item.id"
:timestamp="item.endTime || item.createTime"
placement="top">
<el-card shadow="never">
<p>{{item.assigneeName}} [{{item.createTime}}] 开始处理 [{{item.historyActivityName}}] 环节</p>
<p v-if="item.historyActivityDurationTime">任务历时 [{{item.historyActivityDurationTime}}]</p>
<p v-if="item.commentObj && item.commentObj.type == 'transferComment'">转办意见: [{{item.comment}}]</p>
<p v-if="item.commentObj && item.commentObj.type == 'delegateComment'">委托意见: [{{item.comment}}]</p>
<p v-if="item.commentObj && item.commentObj.type == 'rollbackComment'">驳回意见: [{{item.comment}}]</p>
<p v-if="item.commentObj && item.commentObj.type == 'terminateComment'">终止意见: [{{item.comment}}]</p>
<p v-if="item.commentObj && item.commentObj.type == 'comment'">审批意见: [{{item.comment}}]</p>
<p v-if="item.endTime">结束时间: [{{item.endTime}}]</p>
</el-card>
</el-timeline-item>
</template>
</el-timeline>
</el-row>
</template>
<script>
export default {
name: 'wf-flow',
props: {
flow: {
type: Array,
default: () => {
return []
}
}
}
}
</script>
<style>
</style>

@ -13,16 +13,10 @@
</template>
<script>
import { getFormByProcessId, startProcess } from '@/api/plugin/workflow/process'
import { mapGetters } from 'vuex'
import defaultValues from '../../mixins/default-values'
import exForm from '../../mixins/ex-form'
export default {
mixins: [defaultValues],
computed: {
...mapGetters(['tag']),
},
mixins: [exForm],
watch: {
'$route.params.params': {
handler(val) {
@ -44,113 +38,36 @@ export default {
},
methods: {
getForm(processId) {
getFormByProcessId({ processId }).then(res => {
let { process, form, startForm } = res.data.data
this.getStartForm(processId).then(res => {
let { process, form, startForm } = res
this.process = process
this.form.processId = process.id
if (form) {
const option = eval('(' + form + ')')
// option.menuBtn = false
const { column, group } = option
const columnArr = []
const groupArr = []
const { column, group } = option
if (column && column.length > 0) { // column
column.forEach(col => {
let c = startForm.find(s => s.id == col.prop)
if (c && c.readable) {
if (!c.writable) {
if (col.type == 'dynamic') {
col.children.addBtn = false
col.children.delBtn = false
} else {
col.readonly = true
col.disabled = true
}
delete col.rules
delete col.value
} else if (col.value) col.value = this.getDefaultValues(col.value)
if (col.type == 'dynamic') { //
const childrenColumnArr = []
col.children.column.forEach(cc => {
let c2 = startForm.find(s => s.id == cc.prop)
if (c2 && c2.readable) {
if (!c2.writable) {
cc.readonly = true
cc.disabled = true
delete cc.rules
delete cc.value
} else if (cc.value) cc.value = this.getDefaultValues(cc.value)
childrenColumnArr.push(cc)
}
})
col.children.column = childrenColumnArr
}
columnArr.push(col)
}
})
}
const columnArr = this.filterAvueColumn(column, startForm).column
if (group && group.length > 0) { // group
group.forEach(gro => {
if (gro.column && gro.column.length > 0) {
const groupColumnArr = []
gro.column.forEach(col => {
const c = startForm.find(s => s.id == col.prop)
if (c && c.readable) {
if (!c.writable) {
if (col.type == 'dynamic') {
col.children.addBtn = false
col.children.delBtn = false
} else {
col.readonly = true
col.disabled = true
}
delete col.rules
delete col.value
} else if (col.value) col.value = this.getDefaultValues(col.value)
if (col.type == 'dynamic') { //
const childrenColumnArr = []
col.children.column.forEach(cc => {
let c2 = startForm.find(s => s.id == cc.prop)
if (c2 && c2.readable) {
if (!c2.writable) {
cc.readonly = true
cc.disabled = true
delete cc.rules
delete cc.value
} else if (cc.value) cc.value = this.getDefaultValues(cc.value)
childrenColumnArr.push(cc)
}
})
col.children.column = childrenColumnArr
}
groupColumnArr.push(col)
}
})
gro.column = groupColumnArr
}
gro.column = this.filterAvueColumn(gro.column, startForm).column
if (gro.column.length > 0) groupArr.push(gro)
})
}
option.column = columnArr
option.group = groupArr
this.option = option
setTimeout(() => {
this.$refs.form.clearValidate()
})
this.tag.label = '发起流程 - ' + process.name
}
})
},
handleSubmit(form, done) {
startProcess(form).then(() => {
this.handleStartProcess(form).then(() => {
this.$message.success("发起成功")
done()
this.$store.commit('DEL_TAG', this.tag)
this.$router.push('/plugin/workflow/process/send')
this.handleCloseTag('/plugin/workflow/process/send')
})
},
}

@ -55,7 +55,7 @@
:data="userList"
@current-change="handleRadio"
@selection-change="handleCheckbox">
<template v-if="selectType == 'checkbox'">
<template v-if="checkType == 'checkbox'">
<el-table-column type="selection"
width="55"
align="center">
@ -127,7 +127,7 @@ import { userList as getList } from "@/api/plugin/workflow/process";
export default {
name: 'userSelect',
props: {
selectType: {
checkType: {
type: String,
default: () => {
return 'checkbox'
@ -172,10 +172,11 @@ export default {
handleClose() { //
this.$set(this, 'selectionList', [])
this.$set(this, 'tableRadio', '')
this.visible = false
this.$emit('onClose')
},
handleConfirm() { //
if (this.selectType == 'checkbox') {
if (this.checkType == 'checkbox') {
if (this.selectionList.length === 0) {
this.$message.warning("请选择至少一条数据");
return;

@ -18,7 +18,7 @@
<el-button type="text"
size="small"
icon="el-icon-info"
@click="handleDetail(row)">详情</el-button>
@click="dynamicRoute(row, 'detail')">详情</el-button>
<el-button type="text"
size="small"
icon="el-icon-search"
@ -41,7 +41,10 @@
import { copyList as getList, detail } from "@/api/plugin/workflow/process";
import { mapGetters } from "vuex";
import exForm from '../mixins/ex-form'
export default {
mixins: [exForm],
data() {
return {
form: {},

@ -19,7 +19,7 @@
type="text"
size="small"
icon="el-icon-info"
@click="handleDetail(row)">详情</el-button>
@click="dynamicRoute(row, 'detail')">详情</el-button>
<el-button v-if="permission.wf_process_done_follow"
type="text"
size="small"
@ -44,7 +44,10 @@
import { doneList as getList, detail } from "@/api/plugin/workflow/process";
import { mapGetters } from "vuex";
import exForm from '../mixins/ex-form'
export default {
mixins: [exForm],
data() {
return {
form: {},

@ -0,0 +1,230 @@
<template>
<basic-container>
<avue-affix id="avue-view"
:offset-top="116">
<div class="header">
<avue-title :value="process.processDefinitionName"></avue-title>
</div>
</avue-affix>
<el-tabs v-model="activeName">
<el-tab-pane label="申请信息"
name="first">
<el-card shadow="never">
<div ref="printBody">
<avue-form v-if="showForm"
v-model="form"
ref="form"
:option="option">
</avue-form>
</div>
</el-card>
<el-card shadow="never"
style="margin-top: 20px"
v-if="process.status == 'todo'">
<wf-examine-form ref="examineForm"
:comment.sync="comment"
@user-select="handleUserSelect"></wf-examine-form>
</el-card>
</el-tab-pane>
<el-tab-pane label="流转信息"
name="second">
<el-card shadow="never"
style="margin-top: 5px;">
<wf-flow :flow="flow"></wf-flow>
</el-card>
</el-tab-pane>
<el-tab-pane label="流程跟踪"
name="third">
<template v-if="activeName == 'third'">
<el-card shadow="never"
style="margin-top: 5px;">
<wf-design ref="bpmn"
style="height: 500px;"
:options="bpmnOption"></wf-design>
</el-card>
</template>
</el-tab-pane>
</el-tabs>
<!-- 底部按钮 -->
<template v-if="process.status == 'todo'">
<wf-button :loading="submitLoading"
:button-list="buttonList"
:process="process"
:comment="comment"
@examine="handleExamine"
@user-select="handleUserSelect"
@print="handlePrint"
@rollback="handleRollbackTask"
@terminate="handleTerminateProcess"></wf-button>
</template>
<!-- 人员选择弹窗 -->
<user-select ref="user-select"
:check-type="checkType"
@onConfirm="handleUserSelectConfirm"></user-select>
<!-- 选择回退节点弹窗 -->
<el-dialog :visible.sync="nodeVisible"
append-to-body
title="选择回退节点">
<avue-form v-model="nodeForm"
:option="nodeOption"
@submit="handleNodeSubmit"></avue-form>
</el-dialog>
</basic-container>
</template>
<script>
import WfExamineForm from '@/views/plugin/workflow/process/components/examForm.vue'
import WfButton from '@/views/plugin/workflow/process/components/button.vue'
import WfFlow from '@/views/plugin/workflow/process/components/flow.vue'
import userSelect from '@/views/plugin/workflow/process/components/user-select'
import exForm from '@/views/plugin/workflow/mixins/ex-form'
export default {
mixins: [exForm],
components: { userSelect, WfExamineForm, WfButton, WfFlow },
watch: {
'$route.query.p': {
handler(val) {
if (val) {
const param = JSON.parse(Buffer.from(val, 'base64').toString())
const { taskId, processInsId } = param
if (taskId && processInsId) this.getDetail(taskId, processInsId)
}
},
immediate: true
}
},
data() {
return {
activeName: 'first',
showForm: false,
form: {},
option: {
column: [{
label: '请假时间',
prop: 'datetime',
type: 'datetimerange',
format: 'yyyy-MM-dd HH:mm:ss',
valueFormat: 'yyyy-MM-dd HH:mm:ss',
rules: [{ required: true, message: '请选择请假时间' }]
}, {
label: '请假天数',
prop: 'days',
type: 'number',
rules: [{ required: true, message: '请输入请假天数' }]
}, {
label: '请假理由',
prop: 'reason',
type: 'textarea',
span: 24,
rules: [{ required: true, message: '请输入请假理由' }]
}]
},
vars: [], //
submitLoading: false, // loading
}
},
methods: {
//
getDetail(taskId, processInsId) {
this.getTaskDetail(taskId, processInsId).then(res => {
const { process, form } = res
const { variables, status } = process
let { taskForm } = form
const option = this.option
option.menuBtn = false
const { column, group } = option
if (status != 'todo') { //
option.detail = true
if (column && column.length > 0) { // column
column.forEach(col => {
if (col.type == 'dynamic') col.children.column.forEach(cc => delete cc.value)
else delete col.value
})
}
if (group && group.length > 0) { // group
group.forEach(gro => {
if (gro.column && gro.column.length > 0) {
gro.column.forEach(col => {
if (col.type == 'dynamic') col.children.column.forEach(cc => delete cc.value)
else delete col.value
})
}
})
}
} else {
const columnFilter = this.filterAvueColumn(column, taskForm)
const columnArr = columnFilter.column
let vars = columnFilter.vars
const groupArr = []
if (group && group.length > 0) { // group
group.forEach(gro => {
const groupFilter = this.filterAvueColumn(gro.column, taskForm)
gro.column = groupFilter.column
vars = vars.conact(groupFilter.vars)
if (gro.column.length > 0) groupArr.push(gro)
})
}
if (process.variables && process.variables.serialNumber) {
columnArr.unshift({
label: '流水号',
prop: 'serialNumber',
span: 24,
detail: true,
})
}
option.column = columnArr
option.group = groupArr
this.vars = vars
}
for (let key in variables) {
if (!variables[key]) delete variables[key]
}
this.option = option
this.form = variables
this.showForm = true
})
},
//
handleExamine(pass) {
this.submitLoading = true
this.$refs.form.validate((valid) => {
if (valid) {
const variables = {}
this.vars.forEach(v => {
if (v != 'comment' && this.form[v]) variables[v] = this.form[v]
})
this.handleCompleteTask(pass, variables).then(() => {
this.$message.success("处理成功")
this.handleCloseTag('/plugin/workflow/process/todo')
}).catch(() => {
this.submitLoading = false
})
} else {
this.submitLoading = false
}
})
},
}
}
</script>
<style lang="scss" scoped>
.header {
width: 100%;
height: 50px;
background: #fff;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 10px 10px 0;
}
</style>

@ -0,0 +1,99 @@
<template>
<basic-container>
<avue-title style="margin-bottom: 20px; "
:styles="{fontSize: '20px'}"
:value="process.name"></avue-title>
<!-- 自定义表单区域 -->
<avue-form v-if="option && ((option.column && option.column.length > 0) || (option.group && option.group.length > 0))"
v-model="form"
ref="form"
:option="option"
@submit="handleSubmit">
</avue-form>
<!-- 自定义表单区域 -->
</basic-container>
</template>
<script>
import exForm from '@/views/plugin/workflow/mixins/ex-form'
export default {
mixins: [exForm],
watch: {
'$route.query.p': {
handler(val) {
if (val) {
const param = JSON.parse(Buffer.from(val, 'base64').toString())
const { processId } = param
if (processId) this.getForm(processId)
}
},
immediate: true
}
},
data() {
return {
form: {},
option: {
column: [{
label: '请假时间',
prop: 'datetime',
type: 'datetimerange',
format: 'yyyy-MM-dd HH:mm:ss',
valueFormat: 'yyyy-MM-dd HH:mm:ss',
rules: [{ required: true, message: '请选择请假时间' }]
}, {
label: '请假天数',
prop: 'days',
type: 'number',
rules: [{ required: true, message: '请输入请假天数' }]
}, {
label: '请假理由',
prop: 'reason',
type: 'textarea',
span: 24,
rules: [{ required: true, message: '请输入请假理由' }]
}]
},
process: {}
}
},
methods: {
getForm(processId) {
this.getStartForm(processId).then(res => {
let { process, startForm } = res
this.process = process
this.form.processId = process.id
if (startForm && startForm.length > 0) {
const option = this.option
const { column, group } = option
const groupArr = []
const columnArr = this.filterAvueColumn(column, startForm).column
if (group && group.length > 0) { // group
group.forEach(gro => {
gro.column = this.filterAvueColumn(gro.column, startForm).column
if (gro.column.length > 0) groupArr.push(gro)
})
}
option.column = columnArr
option.group = groupArr
this.option = option
}
})
},
handleSubmit(form, done) {
this.handleStartProcess(form).then(() => {
this.$message.success("发起成功")
done()
this.handleCloseTag('/plugin/workflow/process/send')
})
},
}
}
</script>
<style>
</style>

@ -0,0 +1,152 @@
<template>
<basic-container>
<avue-affix id="avue-view"
:offset-top="116">
<div class="header">
<avue-title :value="process.processDefinitionName"></avue-title>
</div>
</avue-affix>
<el-tabs v-model="activeName">
<el-tab-pane label="申请信息"
name="first">
<el-card shadow="never">
<div ref="printBody">
<!-- 自定义表单区域 -->
<!-- 自定义表单区域 -->
</div>
</el-card>
<!-- 审批意见表单 -->
<el-card shadow="never"
style="margin-top: 20px"
v-if="process.status == 'todo'">
<wf-examine-form ref="examineForm"
:comment.sync="comment"
@user-select="handleUserSelect"></wf-examine-form>
</el-card>
</el-tab-pane>
<!-- 流转信息 -->
<el-tab-pane label="流转信息"
name="second">
<el-card shadow="never"
style="margin-top: 5px;">
<wf-flow :flow="flow"></wf-flow>
</el-card>
</el-tab-pane>
<!-- 流程图 -->
<el-tab-pane label="流程跟踪"
name="third">
<template v-if="activeName == 'third'">
<el-card shadow="never"
style="margin-top: 5px;">
<wf-design ref="bpmn"
style="height: 500px;"
:options="bpmnOption"></wf-design>
</el-card>
</template>
</el-tab-pane>
</el-tabs>
<!-- 底部按钮 -->
<template v-if="process.status == 'todo'">
<wf-button :loading="submitLoading"
:button-list="buttonList"
:process="process"
:comment="comment"
@examine="handleExamine"
@user-select="handleUserSelect"
@print="handlePrint"
@rollback="handleRollbackTask"
@terminate="handleTerminateProcess"></wf-button>
</template>
<!-- 人员选择弹窗 -->
<user-select ref="user-select"
:check-type="checkType"
@onConfirm="handleUserSelectConfirm"></user-select>
</basic-container>
</template>
<script>
import WfExamineForm from '@/views/plugin/workflow/process/components/examForm.vue'
import WfButton from '@/views/plugin/workflow/process/components/button.vue'
import WfFlow from '@/views/plugin/workflow/process/components/flow.vue'
import userSelect from '@/views/plugin/workflow/process/components/user-select'
import exForm from '@/views/plugin/workflow/mixins/ex-form'
export default {
mixins: [exForm],
components: { userSelect, WfExamineForm, WfButton, WfFlow },
watch: {
'$route.query.p': {
handler(val) {
if (val) {
const param = JSON.parse(Buffer.from(val, 'base64').toString())
const { taskId, processInsId } = param
if (taskId && processInsId) this.getDetail(taskId, processInsId)
}
},
immediate: true
}
},
data() {
return {
activeName: 'first',
form: {},
option: {}, //
vars: [], //
submitLoading: false, // loading
}
},
methods: {
//
getDetail(taskId, processInsId) {
this.getTaskDetail(taskId, processInsId).then(res => {
const { process, form } = res
const { variables, status } = process
let { taskForm } = form
console.log("process", process)
console.log("taskForm", taskForm)
console.log("variables", variables)
console.log("status", status) // todo done
//
})
},
//
handleExamine(pass) {
this.submitLoading = true
this.$refs.form.validate((valid) => {
if (valid) {
const variables = {}
this.vars.forEach(v => {
if (v != 'comment' && this.form[v]) variables[v] = this.form[v]
})
this.handleCompleteTask(pass, variables).then(() => {
this.$message.success("处理成功")
this.handleCloseTag('/plugin/workflow/process/todo')
}).catch(() => {
this.submitLoading = false
})
} else {
this.submitLoading = false
}
})
},
}
}
</script>
<style lang="scss" scoped>
.header {
width: 100%;
height: 50px;
background: #fff;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 10px 10px 0;
}
</style>

@ -0,0 +1,58 @@
<template>
<basic-container>
<avue-title style="margin-bottom: 20px; "
:styles="{fontSize: '20px'}"
:value="process.name"></avue-title>
<!-- 自定义表单区域 -->
<!-- 自定义表单区域 -->
</basic-container>
</template>
<script>
import exForm from '@/views/plugin/workflow/mixins/ex-form'
export default {
mixins: [exForm],
watch: {
'$route.query.p': {
handler(val) {
if (val) {
const param = JSON.parse(Buffer.from(val, 'base64').toString())
const { processId } = param
if (processId) this.getForm(processId)
}
},
immediate: true
}
},
data() {
return {
form: {},
option: {},
process: {}
}
},
methods: {
getForm(processId) {
this.getStartForm(processId).then(res => {
let { process, startForm } = res
console.log("process", process)
console.log("startForm", startForm)
//
})
},
handleSubmit(form, done) {
this.handleStartProcess(form).then(() => {
this.$message.success("发起成功")
done()
this.handleCloseTag('/plugin/workflow/process/send')
})
},
}
}
</script>
<style>
</style>

@ -17,7 +17,7 @@
<el-button type="text"
size="small"
icon="el-icon-info"
@click="handleDetail(row)">详情</el-button>
@click="dynamicRoute(row, 'detail')">详情</el-button>
<el-button type="text"
size="small"
icon="el-icon-search"
@ -40,7 +40,10 @@
<script>
import { myDoneList as getList, detail } from "@/api/plugin/workflow/process";
import exForm from '../mixins/ex-form'
export default {
mixins: [exForm],
data() {
return {
form: {},

@ -19,7 +19,7 @@
type="text"
size="small"
icon="el-icon-info"
@click="handleDetail(row)">详情</el-button>
@click="dynamicRoute(row, 'detail')">详情</el-button>
<el-button v-if="permission.wf_process_send_follow"
type="text"
size="small"
@ -43,7 +43,10 @@
import { sendList as getList, detail } from "@/api/plugin/workflow/process";
import { mapGetters } from "vuex";
import exForm from '../mixins/ex-form'
export default {
mixins: [exForm],
data() {
return {
form: {},

@ -18,7 +18,7 @@
type="text"
size="small"
icon="el-icon-video-play"
@click="handleStart(row)">发起</el-button>
@click="dynamicRoute(row, 'start')">发起</el-button>
</template>
</avue-crud>
</basic-container>
@ -28,7 +28,10 @@
import { processList as getList } from "@/api/plugin/workflow/process";
import { mapGetters } from "vuex";
import exForm from '../mixins/ex-form'
export default {
mixins: [exForm],
data() {
return {
form: {},
@ -119,12 +122,6 @@ export default {
}
},
methods: {
handleStart(row) {
const param = {
processId: row.id
}
this.$router.push('/workflow/process/start/' + Buffer.from(JSON.stringify(param)).toString('base64'))
},
searchReset() {
this.query = {};
this.onLoad(this.page);

@ -19,7 +19,7 @@
type="text"
size="small"
icon="el-icon-info"
@click="handleDetail(row)">详情</el-button>
@click="dynamicRoute(row, 'detail')">详情</el-button>
<el-button v-if="permission.wf_process_todo_follow"
type="text"
size="small"
@ -43,7 +43,10 @@
import { todoList as getList, detail } from "@/api/plugin/workflow/process";
import { mapGetters } from "vuex";
import exForm from '../mixins/ex-form'
export default {
mixins: [exForm],
data() {
return {
form: {},

Loading…
Cancel
Save