<template> <div class="app-container"> <!-- 申请信息 --> <el-card class="box-card mt-10" v-loading="processInstanceLoading"> <div slot="header" class="clearfix"> <span class="el-icon-document" >{{ $t("申请信息") }}【{{ processInstance.name }}】</span > </div> <el-col v-if=" this.processInstance.processDefinition && this.processInstance.processDefinition.formType === 10 " :span="16" :offset="6" > <div> <parser :key="new Date().getTime()" :form-conf="detailForm" @submit="submitForm" /> </div> </el-col> <div v-if=" this.processInstance.processDefinition && this.processInstance.processDefinition.formType === 20 " > <component v-if="businessKeyToComponent" :is="businessKeyToComponent.component" v-bind="businessKeyToComponent" /> <div v-else> <router-link :to=" this.processInstance.processDefinition.formCustomViewPath + '?id=' + this.processInstance.businessKey " > <el-button type="primary">{{ $t("点击查看") }}</el-button> </router-link> </div> </div> </el-card> <!-- 审批信息 --> <el-card class="box-card" v-loading="processInstanceLoading" v-for="(item, index) in runningTasks" :key="index" > <div slot="header" class="clearfix"> <span class="el-icon-picture-outline" >{{ $t("审批任务") }}【{{ item.name }}】</span > </div> <el-col :span="16" :offset="6"> <el-form :ref="'form' + index" :model="auditForms[index]" :rules="auditRule2" label-width="100px" > <el-form-item :label="$t('流程名')" v-if="processInstance && processInstance.name" > {{ processInstance.name }} </el-form-item> <el-form-item :label="$t('流程发起人')" v-if="processInstance && processInstance.startUser" > {{ processInstance.startUser.nickname }} <el-tag type="info" size="mini">{{ processInstance.startUser.deptName }}</el-tag> </el-form-item> <el-form-item :label="$t('抄送人')" prop="copyUserIds"> <el-select v-model="auditForms[index].copyUserIds" clearable multiple filterable style="width: 100%" > <el-option v-for="item in userOptions" :key="parseInt(item.id)" :label="item.nickname" :value="parseInt(item.id)" /> </el-select> </el-form-item> <el-form-item :label="$t('审批建议')" prop="comment"> <el-input type="textarea" v-model="auditForms[index].comment" :placeholder="$t('请输入审批建议')" /> </el-form-item> </el-form> <div style="margin-left: 10%; margin-bottom: 20px; font-size: 14px"> <el-button :loading="loading" icon="el-icon-edit-outline" type="success" size="mini" @click="handleAudit(item, true)" >{{ $t("通过") }} </el-button> <el-button :loading="loading" icon="el-icon-circle-close" type="danger" size="mini" @click="handleAudit(item, false)" >{{ $t("不通过") }} </el-button> <el-button :loading="loading" icon="el-icon-edit-outline" type="primary" size="mini" @click="handleUpdateAssignee(item)" >{{ $t("转办") }} </el-button> <!--<el-button icon="el-icon-edit-outline" type="primary" size="mini" @click="handleDelegate(item)">{{ $t('委派') }}</el-button>--> <!--<el-button icon="el-icon-refresh-left" type="warning" size="mini" @click="handleBack(item)">{{ $t('退回') }}</el-button>--> </div> </el-col> </el-card> <el-card class="box-card mt-10" v-loading="tasksLoad"> <div slot="header" class="clearfix"> <span class="el-icon-picture-outline">{{ $t("审批记录") }}</span> </div> <el-col :span="16" :offset="4"> <div class="block"> <el-timeline> <el-timeline-item v-for="(item, index) in tasks" :key="index" :icon="getTimelineItemIcon(item)" :type="getTimelineItemType(item)" > <p style="font-weight: 700">{{ $t("任务") }}:{{ item.name }}</p> <el-card :body-style="{ padding: '10px' }"> <label v-if="item.assigneeUser" style="font-weight: normal; margin-right: 30px" > {{ $t("审批人") }}:{{ item.assigneeUser.nickname }} <el-tag type="info" size="mini">{{ item.assigneeUser.deptName }}</el-tag> </label> <label style="font-weight: normal" >{{ $t("创建时间") }}:</label > <label style="color: #8a909c; font-weight: normal">{{ parseTime(item.createTime) }}</label> <label v-if="item.endTime" style="margin-left: 30px; font-weight: normal" >{{ $t("审批时间") }}:</label > <label v-if="item.endTime" style="color: #8a909c; font-weight: normal" > {{ parseTime(item.endTime) }}</label > <label v-if="item.durationInMillis" style="margin-left: 30px; font-weight: normal" >{{ $t("耗时") }}:</label > <label v-if="item.durationInMillis" style="color: #8a909c; font-weight: normal" > {{ getDateStar(item.durationInMillis) }} </label> <p v-if="item.comment"> <el-tag :type="getTimelineItemType(item)">{{ item.comment }}</el-tag> </p> </el-card> </el-timeline-item> </el-timeline> </div> </el-col> </el-card> <!-- 高亮流程图 --> <el-card class="box-card mt-10" v-loading="processInstanceLoading"> <div slot="header" class="clearfix"> <span class="el-icon-picture-outline">{{ $t("流程图") }}</span> </div> <my-process-viewer key="designer" v-model="bpmnXML" v-bind="bpmnControlForm" :activityData="activityList" :processInstanceData="processInstance" :taskData="tasks" /> </el-card> <!-- 对话框(转派审批人) --> <el-dialog :title="$t('转派审批人')" :visible.sync="updateAssignee.open" width="500px" append-to-body > <el-form ref="updateAssigneeForm" :model="updateAssignee.form" :rules="updateAssignee.rules" label-width="110px" > <el-form-item :label="$t('新审批人')" prop="assigneeUserId"> <el-select v-model="updateAssignee.form.assigneeUserId" clearable style="width: 100%" > <el-option v-for="item in userOptions" :key="parseInt(item.id)" :label="item.nickname" :value="parseInt(item.id)" /> </el-select> </el-form-item> </el-form> <div slot="footer" class="dialog-footer"> <el-button type="primary" @click="submitUpdateAssigneeForm">{{ $t("确定") }}</el-button> <el-button @click="cancelUpdateAssigneeForm">{{ $t("取消") }}</el-button> </div> </el-dialog> </div> </template> <script> import { getProcessDefinitionBpmnXML } from "@/api/bpm/definition"; import { DICT_TYPE, getDictDatas } from "@/utils/dict"; import store from "@/store"; import { decodeFields } from "@/utils/formGenerator"; import Parser from "@/components/parser/Parser"; import { createProcessInstance, getProcessInstance, } from "@/api/bpm/processInstance"; import { approveTask, getTaskListByProcessInstanceId, rejectTask, updateTaskAssignee, } from "@/api/bpm/task"; import { getDate } from "@/utils/dateUtils"; import { listSimpleUsers } from "@/api/system/user"; import { getActivityList } from "@/api/bpm/activity"; import OfferSpecialDetail from "@/views/ecw/offer/components/SpecialDetail"; import warehouseDetails from "@/views/ecw/order/components/warehouseDetails"; import shippingDetail from "@/views/ecw/box/shippingDetail"; import SplitDetail from "@/views/ecw/order/components/SplitDetail"; import MergeDetail from "@/views/ecw/order/components/MergeDetail"; import CargoControlDetail from "@/views/ecw/order/components/CargoControlDetail"; import BoxSplitDetail from "@/views/ecw/order/components/BoxSplitDetail"; // 流程实例的详情页,可用于审批 export default { name: "ProcessInstanceDetail", components: { Parser, OfferSpecialDetail, warehouseDetails, shippingDetail, SplitDetail, MergeDetail, CargoControlDetail, BoxSplitDetail, }, computed: { auditRule2() { if (this.isMust == true) { var obj = { comment: [ { required: true, message: this.$t("审批建议不能为空"), trigger: "blur", }, ], }; return obj; } else { return {}; } }, matterNum() { return this.$store.state.user.matterNum; }, businessKeyToComponent() { if ( !this.processInstance.processDefinition || !this.processInstance.processDefinition.formCustomViewPath ) { return false; } const map = { shippingDetail: { component: "shippingDetail", processId: this.processInstance.businessKey, }, // 报价单特价审核,原来配置的组件名 "special-discount": { component: "OfferSpecialDetail", id: this.processInstance.businessKey, type: 1, }, // 报价单特价审核,符合命名规则的组件名 offer_special: { component: "OfferSpecialDetail", id: this.processInstance.businessKey, type: 1, }, offer_commission: { component: "OfferSpecialDetail", id: this.processInstance.businessKey, type: 2, }, // 原来的费用申请 free_apply: { component: "warehouseDetails", processId: this.processInstance.businessKey, type: 2, }, // 2.0空运加的批量申请 batch_free_apply: { component: () => import("@/views/ecw/order/components/BatchFeeApplication"), businessId: this.processInstance.businessKey, processInstanceId: this.$route.query.id, }, retired_warehouse: { component: "warehouseDetails", processId: this.processInstance.businessKey, type: 3, }, warehouse_transfer: { component: "warehouseDetails", processId: this.processInstance.businessKey, type: 1, }, warehouse_update: { component: "warehouseDetails", processId: this.processInstance.businessKey, type: 4, }, container_modify: { component: "shippingDetail", processId: this.processInstance.businessKey, }, trailer_modify: { component: "shippingDetail", processId: this.processInstance.businessKey, }, ship_modify: { component: "shippingDetail", processId: this.processInstance.businessKey, }, customs_declare_modify: { component: "shippingDetail", processId: this.processInstance.businessKey, }, arrival_modify: { component: "shippingDetail", processId: this.processInstance.businessKey, }, customs_clearance_modify: { component: "shippingDetail", processId: this.processInstance.businessKey, }, customs_exit_part: { component: "shippingDetail", processId: this.processInstance.businessKey, }, customs_exit_all: { component: "shippingDetail", processId: this.processInstance.businessKey, }, start_port_modify: { component: "shippingDetail", processId: this.processInstance.businessKey, }, book_space_modify: { component: "shippingDetail", processId: this.processInstance.businessKey, }, sorting_apply_no: { component: "shippingDetail", processId: this.processInstance.businessKey, }, sorting_apply: { component: "shippingDetail", processId: this.processInstance.businessKey, }, unload_container_no: { component: "shippingDetail", processId: this.processInstance.businessKey, }, unload_container: { component: "shippingDetail", processId: this.processInstance.businessKey, type: "unload_container", }, close_container: { component: "shippingDetail", processId: this.processInstance.businessKey, type: "close_container", }, shipment_preassemble: { component: "shippingDetail", processId: this.processInstance.businessKey, }, close_container_no: { component: "shippingDetail", processId: this.processInstance.businessKey, }, // 拆单审核 split_detail: { component: "SplitDetail", id: this.processInstance.businessKey, }, // 出货拆单审核 shipment_split_detail: { component: "BoxSplitDetail", id: this.processInstance.businessKey, }, // 退场拆单,跟出货装柜拆单一样 exit_split: { component: "BoxSplitDetail", id: this.processInstance.businessKey, }, merge_detail: { component: "MergeDetail", id: this.processInstance.businessKey, }, // 放货修改 order_update_release: { component: "CargoControlDetail", id: this.processInstance.businessKey, applyType: 7, }, // 反复核 order_fallback: { component: "CargoControlDetail", id: this.processInstance.businessKey, applyType: 8, }, // 调货审核 order_transfer: { component: "CargoControlDetail", id: this.processInstance.businessKey, applyType: 9, }, // 取消放货审核 order_cancel_release: { component: "CargoControlDetail", id: this.processInstance.businessKey, applyType: 10, }, // 提单审核 order_landing_bill: { component: () => import("@/views/ecw/order/components/LandingBillDetail"), id: this.processInstance.businessKey, path: this.processInstance.processDefinition?.formCustomViewPath, }, // 订单审核详情 order_approval: { component: () => import("@/views/ecw/order/components/ApprovalDetail"), id: this.processInstance.businessKey, path: this.processInstance.processDefinition?.formCustomViewPath, }, // 订单修改审批 order_update: { component: () => import("@/views/ecw/order/components/UpdateDetail"), id: this.processInstance.businessKey, path: this.processInstance.processDefinition?.formCustomViewPath, }, // 预付异常审核 prepay_excetion: { component: () => import("@/views/ecw/order/components/PrepayExceptionDetail"), id: this.processInstance.businessKey, path: this.processInstance.processDefinition?.formCustomViewPath, }, // 客户延期 customer_delay: { component: () => import("@/views/ecw/customer/components/Delay"), id: this.processInstance.businessKey, path: this.processInstance.processDefinition?.formCustomViewPath, }, //付款单审核-所有审核流程详情组件 finance_payment_approve: { component: () => import("@/views/ecw/financial/components/PaymentApproval"), id: this.processInstance.businessKey, path: this.processInstance.processDefinition?.formCustomViewPath, }, //收款单审核 finance_receipt_approve: { component: () => import("@/views/ecw/financial/components/CollectionApproval"), id: this.processInstance.businessKey, path: this.processInstance.processDefinition?.formCustomViewPath, }, //收款单核销 finance_receipt_write_off: { component: () => import("@/views/ecw/financial/components/CollectionWriteoff"), id: this.processInstance.businessKey, path: this.processInstance.processDefinition?.formCustomViewPath, }, //收款单反核销审核 finance_receipt_write_off_no: { component: () => import("@/views/ecw/financial/components/CollectionApproval"), id: this.processInstance.businessKey, path: this.processInstance.processDefinition?.formCustomViewPath, }, //收款单核销反审核 finance_receipt_approve_no: { component: () => import("@/views/ecw/financial/components/CollectionApproval"), id: this.processInstance.businessKey, path: this.processInstance.processDefinition?.formCustomViewPath, }, //收款单银行实收明细核销 finance_receipt_item_write_off: { component: () => import("@/views/ecw/financial/components/CollectionBankDetail"), id: this.processInstance.businessKey, path: this.processInstance.processDefinition?.formCustomViewPath, }, //收款单银行实收反核销 finance_receipt_item_write_off_no: { component: () => import("@/views/ecw/financial/components/CollectionBankDetail"), id: this.processInstance.businessKey, path: this.processInstance.processDefinition?.formCustomViewPath, }, //佣金付款单审核详情-关于佣金付款单所有审核详情 commissionPaymentDetails: { component: () => import( "@/views/ecw/financial/components/commissionPaymentDetails.vue" ), id: this.processInstance.businessKey, path: this.processInstance.processDefinition?.formCustomViewPath, }, /*撤销拆单*/ split_revoke: { component: () => import("@/views/ecw/order/components/SplitRevokeDetail"), id: this.processInstance.businessKey, }, // 不可出渠道异常审核 not_shiping_channel: { component: () => import("@/views/ecw/order/components/NotShipingChannel"), id: this.processInstance.businessKey, path: this.processInstance.processDefinition?.formCustomViewPath, }, // 出货批量加价审核 box_batch_markup: { component: () => import("@/views/ecw/box/components/batchMakeUpDetail.vue"), processId: this.processInstance.businessKey, type: this.processInstance.processDefinition?.formCustomViewPath, }, // 可获移交详情 customer_handover_details: { component: () => import( "@/views/ecw/customer/components/customer-handover-details.vue" ), processId: this.processInstance.businessKey, type: this.processInstance.processDefinition?.formCustomViewPath, }, // 出货审核 air_shipment: { component: "shippingDetail", processId: this.processInstance.businessKey, type: "shipment", }, //排单分拣审核 shipment_order_sorting: { component: "shippingDetail", processId: this.processInstance.businessKey, }, // 出货反审 shipment_review: { component: "shippingDetail", processId: this.processInstance.businessKey, }, // 删单退场 customs_declare_remove: { component: "shippingDetail", processId: this.processInstance.businessKey, type: "deleteExit", }, // 空运到仓审核 air_warehouse: { component: "shippingDetail", processId: this.processInstance.businessKey, type: "air_warehouse", }, // 空运到仓审核 air_warehouse_no: { component: "shippingDetail", processId: this.processInstance.businessKey, type: "air_warehouse", }, revoke_clear: { component: () => import("@/views/ecw/box/components/RevokeClear"), id: this.processInstance.businessKey, }, // 重量超限 over_weight_exception: { component: () => import( "@/views/ecw/order/exception/components/overweightException" ), id: this.processInstance.businessKey, path: this.processInstance.processDefinition?.formCustomViewPath, }, // 线路重量超限 line_weight_exception: { component: () => import( "@/views/ecw/order/exception/components/overweightException" ), id: this.processInstance.businessKey, path: this.processInstance.processDefinition?.formCustomViewPath, }, }; console.log( "formCustomViewPath", this.processInstance.processDefinition.formCustomViewPath.trim() ); return map[ this.processInstance.processDefinition.formCustomViewPath.trim() ]; }, }, data() { return { // 提交中 loading: false, // 遮罩层 processInstanceLoading: true, // 流程实例 id: undefined, // 流程实例的编号 processInstance: {}, // 流程表单详情 detailForm: { fields: [], }, isMust: true, // BPMN 数据 bpmnXML: null, bpmnControlForm: { prefix: "activiti", }, activityList: [], // 审批记录 tasksLoad: true, tasks: [], // 审批表单 runningTasks: [], auditForms: [], auditRule: { comment: [ { required: this.isMust, message: this.$t("审批建议不能为空"), trigger: "blur", }, ], }, // 转派审批人 userOptions: [], updateAssignee: { open: false, form: { assigneeUserId: undefined, }, rules: { assigneeUserId: [ { required: true, message: this.$t("新审批人不能为空"), trigger: "change", }, ], }, }, // 数据字典 categoryDictDatas: getDictDatas(DICT_TYPE.BPM_MODEL_CATEGORY), }; }, created() { this.id = this.$route.query.id; if (!this.id) { this.$message.error("未传递 id 参数,无法查看流程信息"); return; } this.getDetail(); // 获得用户列表 this.userOptions = []; listSimpleUsers().then((response) => { this.userOptions.push(...response.data); }); }, methods: { /** 获得流程实例 */ getDetail() { // 获得流程实例相关 this.processInstanceLoading = true; getProcessInstance(this.id).then((response) => { if (!response.data) { this.$message.error("查询不到流程信息!"); return; } // 设置流程信息 this.processInstance = response.data; console.log(this.processInstance); //银行实收明细核销不限制必填 lanbm 2024-05-24 add if ( this.processInstance.processDefinition.formCustomViewPath == undefined || this.processInstance.processDefinition.formCustomViewPath == null || this.processInstance.processDefinition.formCustomViewPath == "" ) { this.isMust = true; } else { if ( this.processInstance.processDefinition.formCustomViewPath.trim() == "finance_receipt_item_write_off" ) { this.isMust = false; } else { this.isMust = true; } } //end 银行实收明细核销不限制必填 lanbm 2024-05-24 add // 设置表单信息 if (this.processInstance.processDefinition.formType === 10) { this.detailForm = { ...JSON.parse(this.processInstance.processDefinition.formConf), disabled: true, // 表单禁用 formBtns: false, // 按钮隐藏 fields: decodeFields( this.processInstance.processDefinition.formFields ), }; // 设置表单的值 this.detailForm.fields.forEach((item) => { const val = this.processInstance.formVariables[item.__vModel__]; if (val) { item.__config__.defaultValue = val; } }); } // 加载流程图 getProcessDefinitionBpmnXML( this.processInstance.processDefinition.id ).then((response) => { this.bpmnXML = response.data; }); // 加载活动列表 getActivityList({ processInstanceId: this.processInstance.id, }).then((response) => { this.activityList = response.data; }); // 取消加载中 this.processInstanceLoading = false; }); // 获得流程任务列表(审批记录) this.tasksLoad = true; this.runningTasks = []; this.auditForms = []; getTaskListByProcessInstanceId(this.id).then((response) => { // 审批记录 this.tasks = response.data; // 排序,将未完成的排在前面,已完成的排在后面; this.tasks.sort((a, b) => { // 有已完成的情况,按照完成时间倒序 if (a.endTime && b.endTime) { return b.endTime - a.endTime; } else if (a.endTime) { return 1; } else if (b.endTime) { return -1; // 都是未完成,按照创建时间倒序 } else { return b.createTime - a.createTime; } }); // 需要审核的记录 const userId = store.getters.userId; this.tasks.forEach((task) => { if (task.result !== 1) { // 只有待处理才需要 return; } if (!task.assigneeUser || task.assigneeUser.id !== userId) { // 自己不是处理人 return; } this.runningTasks.push({ ...task }); this.auditForms.push({ comment: "", }); }); // 取消加载中 this.tasksLoad = false; }); }, /** 处理选择流程的按钮操作 **/ handleSelect(row) { // 设置选择的流程 this.selectProcessInstance = row; // 流程表单 if (row.formId) { // 设置对应的表单 this.detailForm = { ...JSON.parse(row.formConf), fields: decodeFields(row.formFields), }; } else if (row.formCustomCreatePath) { this.$router.push({ path: row.formCustomCreatePath }); // 这里暂时无需加载流程图,因为跳出到另外个 Tab; } }, /** 提交按钮 */ submitForm(params) { if (!params) { return; } // 设置表单禁用 const conf = params.conf; conf.disabled = true; // 表单禁用 conf.formBtns = false; // 按钮隐藏 // 提交表单,创建流程 const variables = params.values; createProcessInstance({ processDefinitionId: this.selectProcessInstance.id, variables: variables, }) .then((response) => { this.$modal.msgSuccess("发起流程成功"); // 关闭当前窗口 this.$tab.closeOpenPage(); this.$router.go(-1); }) .catch(() => { conf.disabled = false; // 表单开启 conf.formBtns = true; // 按钮展示 }); }, getDateStar(ms) { return getDate(ms); }, getTimelineItemIcon(item) { if (item.result === 1) { return "el-icon-time"; } if (item.result === 2) { return "el-icon-check"; } if (item.result === 3) { return "el-icon-close"; } if (item.result === 4) { return "el-icon-remove-outline"; } return ""; }, getTimelineItemType(item) { if (item.result === 1) { return "primary"; } if (item.result === 2) { return "success"; } if (item.result === 3) { return "danger"; } if (item.result === 4) { return "info"; } return ""; }, /** 处理审批通过和不通过的操作 */ handleAudit(task, pass) { const index = this.runningTasks.indexOf(task); this.$refs["form" + index][0].validate((valid) => { if (!valid) { return; } const data = { id: task.id, comment: this.auditForms[index].comment, copyUserIds: this.auditForms[index].copyUserIds, }; this.loading = true; if (pass) { approveTask(data) .then((response) => { let p = this.matterNum; //this.$store.commit('GET_MAATER', --p) this.$modal.msgSuccess("审批通过成功!"); this.getDetail(); // 获得最新详情 }) .finally(() => { this.loading = false; }); } else { rejectTask(data) .then((response) => { let p = this.matterNum; //this.$store.commit('GET_MAATER', --p) this.$modal.msgSuccess("审批不通过成功!"); this.getDetail(); // 获得最新详情 }) .finally(() => { this.loading = false; }); } }); }, /** 处理转派审批人 */ handleUpdateAssignee(task) { // 设置表单 this.resetUpdateAssigneeForm(); this.updateAssignee.form.id = task.id; // 设置为打开 this.updateAssignee.open = true; }, /** 提交转派审批人 */ submitUpdateAssigneeForm() { this.$refs["updateAssigneeForm"].validate((valid) => { if (!valid) { return; } updateTaskAssignee(this.updateAssignee.form).then((response) => { this.$modal.msgSuccess("转派任务成功!"); let p = this.matterNum; // this.$store.commit('GET_MAATER', --p) this.updateAssignee.open = false; this.getDetail(); // 获得最新详情 }); }); }, /** 取消转派审批人 */ cancelUpdateAssigneeForm() { this.updateAssignee.open = false; this.resetUpdateAssigneeForm(); }, /** 重置转派审批人 */ resetUpdateAssigneeForm() { this.updateAssignee.form = { id: undefined, assigneeUserId: undefined, }; this.resetForm("updateAssigneeForm"); }, /** 处理审批退回的操作 */ handleDelegate(task) { this.$modal.msgError("暂不支持【委派】功能,可以使用【转派】替代!"); }, /** 处理审批退回的操作 */ handleBack(task) { this.$modal.msgError("暂不支持【退回】功能!"); }, }, }; </script> <style lang="scss" scoped> .my-process-designer { height: calc(100vh - 200px); } .box-card { width: 100%; margin-bottom: 20px; } </style>