YanZhuProject/yanzhu-ui/src/views/flowable/task/myProcess/detail/detailDrawer.vue

579 lines
19 KiB
Vue

<template>
<div class="app-detailDrawer">
<el-drawer
v-if="onOpen"
:visible.sync="onOpen"
ref="drawer"
direction="rtl"
size="70%"
>
<template slot="title">
<div>
流程详情 【{{ title }}】 - 当前进度【{{ jdtitle }}】<span v-if="showjd">
- 当前节点【{{ options.taskName }}】</span
>
</div>
</template>
<div class="drawer">
<div class="drawerLeft">
<div class="block containers">
<div class="canvas" ref="flowCanvas"></div>
<div class="maskLayer" />
</div>
<el-timeline>
<el-timeline-item
v-for="(item, index) in flowRecordList"
:key="index"
:icon="setIcon(item)"
:color="setColor(item)"
>
<p style="font-weight: 700">
{{ getSort(index) }}{{ item.taskName }}{{ item.commentResult }}
</p>
<el-card :body-style="{ padding: '6px' }">
<el-descriptions class="margin-top" :column="1" size="small" border>
<el-descriptions-item
v-if="item.assigneeName"
label-class-name="my-label"
:labelStyle="labelStyle"
>
<template slot="label"><i class="el-icon-user"></i>办理人</template>
{{ item.assigneeName }}
<el-tag type="info" size="mini">{{ item.deptName }}</el-tag>
</el-descriptions-item>
<el-descriptions-item
v-if="item.candidate"
label-class-name="my-label"
:labelStyle="labelStyle"
>
<template slot="label"><i class="el-icon-user"></i>候选办理</template>
{{ item.candidate }}
</el-descriptions-item>
<el-descriptions-item
v-if="item.deleteReason"
label-class-name="my-label"
:labelStyle="labelStyle"
>
<template slot="label"><i class="el-icon-user"></i>驳回节点</template>
{{ getDeleteReason(item.deleteReason) }}
</el-descriptions-item>
<el-descriptions-item
label-class-name="my-label"
:labelStyle="labelStyle"
>
<template slot="label"><i class="el-icon-date"></i>接收时间</template>
{{ item.startTime }}
</el-descriptions-item>
<el-descriptions-item
v-if="item.endTime"
label-class-name="my-label"
:labelStyle="labelStyle"
>
<template slot="label"><i class="el-icon-date"></i>处理时间</template>
{{ item.endTime }}
</el-descriptions-item>
<el-descriptions-item
v-if="item.duration"
label-class-name="my-label"
:labelStyle="labelStyle"
>
<template slot="label"><i class="el-icon-time"></i>处理耗时</template>
{{ getDurationDateStr(item.duration) }}
</el-descriptions-item>
<el-descriptions-item
v-if="item.message"
label-class-name="my-label"
:labelStyle="labelStyle"
>
<template slot="label"
><i class="el-icon-tickets"></i>处理意见</template
>
{{ item.message }}
</el-descriptions-item>
</el-descriptions>
</el-card>
</el-timeline-item>
</el-timeline>
</div>
<div class="drawerRight">
<el-form label-width="80px">
<el-form-item label="项目单位">
{{ initData.projParName }}
</el-form-item>
<el-form-item label="项目名称">
{{ initData.projParName }}
</el-form-item>
<el-form-item label="申请类型">
{{ title }}
</el-form-item>
<el-form-item label="申请人">
<label
>{{ initData.createBy }}
<el-tag type="info" size="mini">{{
initData.createByDeptName
}}</el-tag></label
>
</el-form-item>
<el-form-item label="申请原因">
{{ initData.applyReason }}
</el-form-item>
<el-form-item label="申请附件" v-if="initData.applyFiles">
<div v-for="(file, index) in initData.applyFiles.split(',')" :key="index">
<el-button
size="mini"
type="text"
icon="el-icon-paperclip"
@click="handledownload(file)"
>{{ file.substring(file.lastIndexOf("/") + 1) }}</el-button
>
</div>
</el-form-item>
<el-form-item label="申请时间">
{{ parseTime(initData.updateTime, "{y}-{m}-{d} {h}:{i}") }}
</el-form-item>
<el-form-item label="使用时间">
{{ initData.applyReason }}
</el-form-item>
<el-divider content-position="left">申请明细</el-divider>
<el-table stripe :data="initData.proProjectApplyDetailList">
<el-table-column label="序号" width="40" type="index"></el-table-column>
<el-table-column label="申请明细" align="left">
<template slot-scope="scope">
<el-breadcrumb separator=">">
<el-breadcrumb-item>{{ scope.row.superTypeName }}</el-breadcrumb-item>
<el-breadcrumb-item>{{ scope.row.typeName }}</el-breadcrumb-item>
<el-breadcrumb-item class="assetsName">{{
scope.row.assetsName
}}</el-breadcrumb-item>
</el-breadcrumb>
</template>
</el-table-column>
<el-table-column label="规格" prop="assetsVersion"></el-table-column>
<el-table-column label="数量" prop="number">
<template slot-scope="scope">
<label
>{{ scope.row.number }}
<el-tag type="info" size="mini">{{
scope.row.assetsUnit
}}</el-tag></label
>
</template>
</el-table-column>
<el-table-column
label="说明"
prop="useReason"
width="150"
></el-table-column>
</el-table>
<div style="text-align: center">
<el-button type="danger" @click="doCanel"> </el-button>
</div>
</el-form>
</div>
</div>
</el-drawer>
</div>
</template>
<script>
import { flowXmlAndNode } from "@/api/flowable/definition";
import { CustomViewer as BpmnViewer } from "@/components/customBpmn";
import { findCommentByProcInsId } from "@/api/flowable/businessKey";
import { getProjectApply } from "@/api/project/projectApply";
export default {
components: {},
props: {},
data() {
return {
// 抽屉层
onOpen: false,
// 遮罩层
loading: false,
// 标题
title: "",
jdtitle: "",
// 表单参数
form: {},
// 表单校验
rules: {},
bpmnViewer: null,
options: {},
flowRecordList: [],
showjd: false,
//label样式
labelStyle: { width: "180px" },
initData: {},
};
},
computed: {},
watch: {},
created() {},
mounted() {},
beforeDestroy() {},
methods: {
setIcon(row) {
if (row.endTime) {
if (row.commentResult == "驳回") {
return "el-icon-close";
} else {
return "el-icon-check";
}
} else {
return "el-icon-time";
}
},
setColor(row) {
if (row.endTime) {
if (row.commentResult == "驳回") {
return "#f56c6c";
} else {
return "#2bc418";
}
} else {
return "#b3bdbb";
}
},
getSort(i) {
let num = this.flowRecordList.length - i;
if (num < 10) {
num = "0" + num;
}
return num + ". ";
},
doCanel() {
this.onOpen = false;
},
show(options) {
this.options = options;
this.title = options.procDefName;
this.deptName = options.startDeptName;
this.nickName = options.startUserName;
this.onOpen = true;
this.showjd = false;
if (options.finishTime == null) {
this.jdtitle = "进行中";
this.showjd = true;
} else if (options.finishTime != null && options.assigneeId == null) {
this.jdtitle = "已终止";
} else {
this.jdtitle = "已完成";
}
this.getFlowRecordList(options.procInsId, options.deployId);
this.getFormDatasList(options.businessKey);
flowXmlAndNode({ procInsId: options.procInsId, deployId: options.deployId }).then(
(res) => {
this.initFlowImage(res.data);
}
);
},
async initFlowImage(data) {
const self = this;
try {
self.bpmnViewer = new BpmnViewer({
container: this.$refs.flowCanvas,
height: "100px",
});
await self.bpmnViewer.importXML(data.xmlData);
// 自适应
self.bpmnViewer.get("canvas").zoom("fit-viewport", "auto");
if (data.nodeData !== undefined && data.nodeData.length > 0) {
self.fillColor(data.nodeData);
}
} catch (err) {
console.error(err.message, err.warnings);
}
},
/** 流程流转记录 */
getFlowRecordList(procInsId, deployId) {
// const that = this
// const params = {procInsId: procInsId, deployId: deployId}
// flowRecord(params).then(res => {
// that.flowRecordList = res.data.flowList;
// }).catch(res => {
// this.$message.error("数据异常,请联系管理员...");
// })
const that = this;
const params = { procInsId: procInsId };
findCommentByProcInsId(params)
.then((res) => {
that.flowRecordList = res.data;
})
.catch((res) => {
this.$message.error("数据异常,请联系管理员...");
});
},
/** 流程表单数据 */
getFormDatasList(businessKey) {
getProjectApply(businessKey)
.then((res) => {
if (res.code == 200) {
this.initData = res.data;
} else {
this.$message.error("数据异常,请联系管理员...");
}
})
.catch((res) => {
this.$message.error("数据异常,请联系管理员...");
});
},
// 设置高亮颜色的
fillColor(nodeData) {
const canvas = this.bpmnViewer.get("canvas");
this.bpmnViewer.getDefinitions().rootElements[0].flowElements.forEach((n) => {
const completeTask = nodeData.find((m) => m.key === n.id);
const todoTask = nodeData.find((m) => !m.completed);
const endTask = nodeData[nodeData.length - 1];
if (n.$type === "bpmn:UserTask") {
if (completeTask) {
canvas.addMarker(
n.id,
completeTask.completed ? "highlight" : "highlight-todo"
);
n.outgoing?.forEach((nn) => {
const targetTask = nodeData.find((m) => m.key === nn.targetRef.id);
if (targetTask) {
if (
todoTask &&
completeTask.key === todoTask.key &&
!todoTask.completed
) {
canvas.addMarker(
nn.id,
todoTask.completed ? "highlight" : "highlight-todo"
);
canvas.addMarker(
nn.targetRef.id,
todoTask.completed ? "highlight" : "highlight-todo"
);
} else {
canvas.addMarker(
nn.id,
targetTask.completed ? "highlight" : "highlight-todo"
);
canvas.addMarker(
nn.targetRef.id,
targetTask.completed ? "highlight" : "highlight-todo"
);
}
}
});
}
}
// 排他网关
else if (n.$type === "bpmn:ExclusiveGateway") {
if (completeTask) {
canvas.addMarker(
n.id,
completeTask.completed ? "highlight" : "highlight-todo"
);
n.outgoing?.forEach((nn) => {
const targetTask = nodeData.find((m) => m.key === nn.targetRef.id);
if (targetTask) {
canvas.addMarker(
nn.id,
targetTask.completed ? "highlight" : "highlight-todo"
);
canvas.addMarker(
nn.targetRef.id,
targetTask.completed ? "highlight" : "highlight-todo"
);
}
});
}
}
// 并行网关
else if (n.$type === "bpmn:ParallelGateway") {
if (completeTask) {
canvas.addMarker(
n.id,
completeTask.completed ? "highlight" : "highlight-todo"
);
n.outgoing?.forEach((nn) => {
const targetTask = nodeData.find((m) => m.key === nn.targetRef.id);
if (targetTask) {
canvas.addMarker(
nn.id,
targetTask.completed ? "highlight" : "highlight-todo"
);
canvas.addMarker(
nn.targetRef.id,
targetTask.completed ? "highlight" : "highlight-todo"
);
}
});
}
} else if (n.$type === "bpmn:StartEvent") {
n.outgoing.forEach((nn) => {
const completeTask = nodeData.find((m) => m.key === nn.targetRef.id);
if (completeTask) {
canvas.addMarker(nn.id, "highlight");
canvas.addMarker(n.id, "highlight");
return;
}
});
} else if (n.$type === "bpmn:EndEvent") {
if (endTask.key === n.id && endTask.completed) {
canvas.addMarker(n.id, "highlight");
return;
}
}
});
},
getDurationDateStr(val) {
// 计算出相差天数
let days = Math.floor(val / (24 * 3600 * 1000));
// 计算出小时数
let leave1 = val % (24 * 3600 * 1000); // 计算天数后剩余的毫秒数
let hours = Math.floor(leave1 / (3600 * 1000));
// 计算相差分钟数
let leave2 = leave1 % (3600 * 1000); // 计算小时数后剩余的毫秒数
let minutes = Math.floor(leave2 / (60 * 1000));
// 计算相差秒数
let leave3 = leave2 % (60 * 1000); // 计算分钟数后剩余的毫秒数
let seconds = Math.round(leave3 / 1000);
if (days > 0) {
if (days < 10) days = "0" + days;
if (hours < 10) hours = "0" + hours;
if (minutes < 10) minutes = "0" + minutes;
if (seconds < 10) seconds = "0" + seconds;
return days + "天" + hours + "小时" + minutes + "分钟" + seconds + "秒";
}
if (hours > 0) {
if (hours < 10) hours = "0" + hours;
if (minutes < 10) minutes = "0" + minutes;
if (seconds < 10) seconds = "0" + seconds;
return hours + "小时" + minutes + "分钟" + seconds + "秒";
}
if (minutes > 0) {
if (minutes < 10) minutes = "0" + minutes;
if (seconds < 10) seconds = "0" + seconds;
return minutes + "分钟" + seconds + "秒";
}
if (seconds > 0) {
if (seconds < 10) seconds = "0" + seconds;
return seconds + "秒";
}
},
handledownload(url) {
this.$download.resource(url);
},
getDeleteReason(val) {
val = val.replace("Change activity to ", "");
let flowRecordList = this.flowRecordList;
for (let i = 0; i < flowRecordList.length; i++) {
if (flowRecordList[i].taskDefKey == val) {
return "驳回至" + flowRecordList[i].taskName;
}
}
},
},
};
</script>
<style lang="scss">
.app-detailDrawer {
.drawer {
width: 100%;
height: 100%;
padding-left: 20px;
padding-right: 20px;
padding-bottom: 20px;
.drawerLeft {
width: 50%;
min-width: 280px;
height: 100%;
float: left;
border-right: 1px solid #dcdfe6;
overflow-y: scroll;
padding-right: 20px;
.bjs-powered-by {
display: none !important;
}
.maskLayer {
width: 100%;
height: 100px;
position: absolute;
z-index: 9999;
top: 77px;
}
}
.drawerRight {
width: 50%;
min-width: 400px;
height: 100%;
float: left;
padding-left: 20px;
}
}
.containers {
width: 100%;
height: 150px;
.canvas {
width: 100%;
height: 100px;
}
.panel {
position: absolute;
right: 0;
top: 50px;
width: 300px;
}
.load {
margin-right: 10px;
}
.el-form-item__label {
font-size: 13px;
}
.djs-palette {
left: 0px !important;
top: 0px;
border-top: none;
}
.djs-container svg {
min-height: 150px;
}
.highlight.djs-shape .djs-visual > :nth-child(1) {
fill: green !important;
stroke: green !important;
fill-opacity: 0.2 !important;
}
.highlight.djs-shape .djs-visual > :nth-child(2) {
fill: green !important;
}
.highlight.djs-shape .djs-visual > path {
fill: green !important;
fill-opacity: 0.2 !important;
stroke: green !important;
}
.highlight.djs-connection > .djs-visual > path {
stroke: green !important;
}
.highlight-todo.djs-connection > .djs-visual > path {
stroke: orange !important;
stroke-dasharray: 4px !important;
fill-opacity: 0.2 !important;
}
.highlight-todo.djs-shape .djs-visual > :nth-child(1) {
fill: orange !important;
stroke: orange !important;
stroke-dasharray: 4px !important;
fill-opacity: 0.2 !important;
}
.overlays-div {
font-size: 10px;
color: red;
width: 100px;
top: -20px !important;
}
}
}
.assetsName {
font-weight: 800;
color: #409eff;
}
</style>