Files
zhgh_zjvtit/target/classes/static/components/plugins/snaker/snakerFlowHisApproval.vue
T
2026-08-26 14:25:17 +08:00

380 lines
9.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="approval-sidebar">
<div class="sidebar-header">
<h4>审批记录</h4>
</div>
<div class="timeline-container" v-if="historyApprovalRecords.length > 0">
<div class="timeline-wrapper">
<div
v-for="(record, index) in historyApprovalRecords"
:key="record.id"
class="timeline-item">
<!-- 时间线节点 -->
<div class="timeline-node">
<div class="timeline-dot" :class="getDotClass(record.taskState)"></div>
<div class="timeline-line" v-if="index < historyApprovalRecords.length - 1"></div>
</div>
<!-- 审批内容 -->
<div class="timeline-content">
<div class="approval-card">
<div class="card-header">
<span class="task-name">{{ record.displayName }}</span>
<span class="approval-time">{{ formatTimestamp(record.finishTime || record.createdAt) }}</span>
</div>
<div class="card-body">
<div class="info-item" v-if="record.operator && record.operator !== 'flow.auto'">
<span class="label">办理人</span>
<span class="value">{{ getOperatorName(record) }}</span>
</div>
<div class="info-item" v-if="record.ext && record.ext.submitType">
<span class="label">操作</span>
<span class="value submit-type" :class="'submit-' + record.ext.submitType">
{{ getSubmitTypeText(record.ext.submitType) }}
</span>
</div>
<div class="info-item" v-if="record.ext && record.ext.opinion">
<span class="label">意见</span>
<span class="value">{{ record.ext.opinion }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div v-else class="no-records">
暂无审批记录
</div>
</div>
</template>
<script>
module.exports = {
name: "SnakerFlowHisApproval",
props: {
task_id: {
type: String | Number,
required: true
}
},
data() {
return {
// 历史审批记录
historyApprovalRecords: [],
// 加载状态
loading: false,
// 任务状态枚举
taskStateEnum: {
DOING: 10,
FINISHED: 20,
WITHDRAW: 30,
INTERRUPT: 40,
PENDING: 50,
ABANDON: 99
}
}
},
computed: {
// 获取实例ID(从task_id获取流程实例信息)
instanceId() {
return GetQueryString("instanceId")
}
},
created() {
this.loadHistoryApprovalRecords()
},
watch: {
task_id: {
handler(newVal) {
if (newVal) {
this.loadHistoryApprovalRecords()
}
},
immediate: true
}
},
methods: {
// 加载历史审批记录
async loadHistoryApprovalRecords() {
if (!this.instanceId && !this.task_id) return
this.loading = true
try {
const params = this.instanceId ?
{ instanceId: this.instanceId } :
{ taskId: this.task_id }
const response = await $.post("/flow/common/approvalRecord", params)
if (response.code === 0) {
this.historyApprovalRecords = response.data || []
}
} catch (error) {
console.error("加载历史审批记录失败:", error)
} finally {
this.loading = false
}
},
// 格式化时间戳
formatTimestamp(timestamp) {
if (!timestamp) return ""
const date = new Date(timestamp)
return date.toLocaleString("zh-CN", {
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit"
})
},
// 获取操作人姓名
getOperatorName(record) {
if (!record.operator || record.operator === 'flow.auto') {
return "系统自动"
}
if (record.ext && record.ext.operatorName) {
return record.ext.operatorName
}
return record.operator
},
// 获取提交类型文本
getSubmitTypeText(submitType) {
const typeMap = {
'agree': '同意',
'reject': '拒绝',
'back': '退回',
'transfer': '转办',
'delegate': '委托',
'submit': '提交'
}
return typeMap[submitType] || submitType
},
// 获取节点样式类
getDotClass(state) {
switch (state) {
case this.taskStateEnum.FINISHED:
return "dot-success"
case this.taskStateEnum.WITHDRAW:
return "dot-warning"
case this.taskStateEnum.INTERRUPT:
case this.taskStateEnum.ABANDON:
return "dot-danger"
case this.taskStateEnum.PENDING:
return "dot-info"
case this.taskStateEnum.DOING:
return "dot-primary"
default:
return "dot-default"
}
}
}
}
</script>
<style scoped>
.approval-sidebar {
width: 320px;
background: #fff;
border: 1px solid #ddd;
height: fit-content;
max-height: 80vh;
overflow: hidden;
display: flex;
flex-direction: column;
}
.sidebar-header {
background: #f5f5f5;
border-bottom: 1px solid #ddd;
padding: 12px 16px;
flex-shrink: 0;
}
.sidebar-header h4 {
margin: 0;
font-size: 14px;
font-weight: normal;
color: #333;
}
.timeline-container {
flex: 1;
overflow-y: auto;
padding: 16px;
}
.timeline-wrapper {
position: relative;
}
.timeline-item {
display: flex;
margin-bottom: 20px;
position: relative;
}
.timeline-item:last-child {
margin-bottom: 0;
}
.timeline-node {
position: relative;
margin-right: 12px;
display: flex;
flex-direction: column;
align-items: center;
}
.timeline-dot {
width: 12px;
height: 12px;
border-radius: 50%;
border: 2px solid #fff;
position: relative;
z-index: 2;
}
.dot-success {
background: #52c41a;
}
.dot-warning {
background: #faad14;
}
.dot-danger {
background: #f5222d;
}
.dot-primary {
background: #1890ff;
}
.dot-info {
background: #999;
}
.dot-default {
background: #d9d9d9;
}
.timeline-line {
width: 1px;
background: #e8e8e8;
flex: 1;
margin-top: 4px;
min-height: 30px;
}
.timeline-content {
flex: 1;
min-width: 0;
}
.approval-card {
background: #fff;
border: 1px solid #e8e8e8;
border-radius: 2px;
}
.card-header {
background: #fafafa;
border-bottom: 1px solid #e8e8e8;
padding: 8px 12px;
display: flex;
justify-content: space-between;
align-items: center;
}
.task-name {
font-size: 13px;
font-weight: bold;
color: #333;
flex: 1;
}
.approval-time {
font-size: 12px;
color: #999;
}
.card-body {
padding: 12px;
}
.info-item {
display: flex;
margin-bottom: 6px;
font-size: 12px;
line-height: 1.5;
}
.info-item:last-child {
margin-bottom: 0;
}
.label {
color: #666;
min-width: 50px;
flex-shrink: 0;
}
.value {
color: #333;
flex: 1;
word-break: break-all;
}
.submit-type {
font-weight: bold;
}
.submit-agree {
color: #52c41a;
}
.submit-reject {
color: #f5222d;
}
.submit-back {
color: #faad14;
}
.submit-transfer, .submit-delegate, .submit-submit {
color: #1890ff;
}
.no-records {
padding: 40px 20px;
text-align: center;
color: #999;
font-size: 14px;
}
/* 滚动条样式 */
.timeline-container::-webkit-scrollbar {
width: 6px;
}
.timeline-container::-webkit-scrollbar-track {
background: #f1f1f1;
}
.timeline-container::-webkit-scrollbar-thumb {
background: #c1c1c1;
}
.timeline-container::-webkit-scrollbar-thumb:hover {
background: #a8a8a8;
}
</style>