You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
157 lines
5.3 KiB
157 lines
5.3 KiB
<template> |
|
<div class="flow" style="height: 100%"> |
|
<header class="flex between v-center flow-header" ref="flowHeaderRef"> |
|
<span> |
|
<span class="second mr-8">流程操作</span> |
|
</span> |
|
</header> |
|
<el-scrollbar max-height="calc(100% - 33px)"> |
|
<div class="flow-container"> |
|
<div v-for="(item, index) in actionHistory" :key="item.id"> |
|
<div class="mb-4 mt-4 flow-info"> |
|
<span class="second mr-8">{{ item.crtTime }}</span> |
|
<span class="mr-8">{{ item.departName }}</span> |
|
<span class="mr-8">{{ item.crtName }}</span> |
|
<span class="text-primary mr-8 text-bold">{{ item.actionName }}</span> |
|
<span style="color: #9e9e9e; cursor: pointer" @click="handleShowDetai(item)">详情</span> |
|
</div> |
|
<div |
|
class="flow-time" |
|
:danger="shouldHighlight(item)" |
|
:title="getOvertimeTip(item)" |
|
> |
|
<span class="second mr-8">用时</span> |
|
<span class="primary">{{ |
|
formatTimeText(getConsumingTime(item.crtTime, index)) |
|
}}</span> |
|
</div> |
|
</div> |
|
<div |
|
class="text-center mt-20" |
|
v-if="!actionHistory.length" |
|
style="color: #999" |
|
> |
|
无 |
|
</div> |
|
</div> |
|
</el-scrollbar> |
|
</div> |
|
|
|
<el-dialog :title="activeHistory.crtTime + ' ' + (activeHistory.departName || '') + ' ' + activeHistory.crtName + ' ' + activeHistory.actionName" v-model="show"> |
|
<div style="min-height: 100px"> |
|
<div v-if="activeHistory.json"> |
|
<div >{{ activeHistory.json.data?.departName }}</div> |
|
<div >{{ activeHistory.json.data?.completionComment }}</div> |
|
<div>{{ activeHistory.json.data?.requirement }}</div> |
|
<div>{{ activeHistory.json.data?.comments }}</div> |
|
</div> |
|
</div> |
|
</el-dialog> |
|
</template> |
|
<script setup> |
|
import { formatTimeText } from "@/utils/util"; |
|
import moment from 'moment' |
|
import useCatchStore from "@/stores/modules/catch.ts"; |
|
|
|
const actionHistory = inject('actionHistory') |
|
const negative = inject('negative') |
|
const show = ref(false) |
|
|
|
function getConsumingTime(crtTime, index) { |
|
if (index === 0) { |
|
return moment(crtTime).diff(moment(negative.value.crtTime), "seconds") |
|
} |
|
return moment(crtTime).diff(moment(actionHistory.value[index - 1].crtTime), "seconds") |
|
} |
|
const catchStore = useCatchStore(); |
|
// 触发字典加载 |
|
catchStore.getDicts(["approveShouldHighlight"]); |
|
// 在 computed 中通过 store 直接访问 |
|
const highlightKeywords = computed(() => catchStore.dict.approveShouldHighlight || []); |
|
const shouldHighlight = (item) => { |
|
const keywords = highlightKeywords.value; |
|
const matchKeyword = keywords.some(k => item.actionName?.includes(k.dictLabel)); |
|
if (!matchKeyword) return false; |
|
|
|
return item.duration > 86400; |
|
} |
|
const getOvertimeTip = (item) => { |
|
const keywords = highlightKeywords.value; |
|
const matchKeyword = keywords.some(k => item.actionName?.includes(k.dictLabel)); |
|
if (!matchKeyword || !item.duration) { |
|
return ''; |
|
} |
|
|
|
if (item.duration <= 86400) { |
|
return ''; |
|
} |
|
|
|
const overtimeSeconds = item.duration - 86400; |
|
const days = Math.floor(overtimeSeconds / 86400); |
|
const hours = Math.floor((overtimeSeconds % 86400) / 3600); |
|
const minutes = Math.floor((overtimeSeconds % 3600) / 60); |
|
|
|
return `超时 ${days}天${hours}时${minutes}分`; |
|
} |
|
const activeHistory = ref({}) |
|
function handleShowDetai(item) { |
|
activeHistory.value = item |
|
if (item.dataJson) { |
|
activeHistory.value.json = JSON.parse(item.dataJson) |
|
} |
|
show.value = true |
|
} |
|
</script> |
|
<style lang="scss" scoped> |
|
.flow { |
|
.flow-header { |
|
background: #f5f6ff; |
|
padding: 8px; |
|
font-size: 12px; |
|
} |
|
.flow-container { |
|
background-color: #eff0f5; |
|
padding: 12px 8px; |
|
min-height: 120px; |
|
font-size: 12px; |
|
.second { |
|
color: #999; |
|
} |
|
.flow-time { |
|
display: inline-flex; |
|
padding: 6px; |
|
margin-left: 6px; |
|
background-color: #f5f6ff; |
|
border-left: 2px solid #00d050; |
|
padding-left: 20px; |
|
&[danger="true"] { |
|
border-color: #ff0000; |
|
span { |
|
color: #ff0000; |
|
} |
|
} |
|
} |
|
.flow-info { |
|
position: relative; |
|
padding-left: 20px; |
|
&::before { |
|
display: block; |
|
content: ""; |
|
width: 10px; |
|
height: 10px; |
|
border-radius: 50%; |
|
background-color: #bfbfbf; |
|
position: absolute; |
|
left: 0; |
|
top: 50%; |
|
transform: translateY(-50%); |
|
} |
|
} |
|
& > div:first-child .flow-info::before { |
|
width: 12px; |
|
height: 12px; |
|
background-color: var(--primary-color); |
|
} |
|
} |
|
} |
|
</style>
|
|
|