详情页-风险评估方法显示修改

This commit is contained in:
2026-10-13 10:00:18 +08:00
parent f355f6fe11
commit 842f7f0941
4 changed files with 2089 additions and 2019 deletions
+40 -18
View File
@@ -185,7 +185,7 @@ const opinion = ref<string>("");
// 已阅 AI 建议
const readSuggest = () => {
aiRead.value = true;
window.$message?.success(`${roleName} 已阅 AI 建议,时间与操作已写入审批留痕`);
window.$message?.success(`${roleName.value} 已阅 AI 建议,时间与操作已写入审批留痕`);
}
// 采纳为行动项
const acceptSuggest = (s: any) => {
@@ -456,7 +456,9 @@ onMounted(() => {
<p
class="rounded-sm bg-[var(--theme-color)] px-3 py-1 text-xs font-semibold text-white"
:style="{'--theme-color': themeStore.themeColor}"
>变更申请表</p>
>
变更申请表
</p>
<NButton ghost size="small" class="text-xs" @click="exportFile('change')"><Icon icon="material-symbols:download" class="size-16px" />导出变更申请表</NButton>
</div>
<div
@@ -527,7 +529,12 @@ onMounted(() => {
<div class="grid border-b grid-cols-[100px_1fr]">
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">风险评估方法</p>
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
{{currentInfo?.apply_form?.risk_tools?.join('、')}}
<template v-for="(item,index) in currentInfo?.apply_form?.risk_tools" :key="index">
<span v-if="index!==0">、</span>
<span v-if="item==='RISK'">风险预分析</span>
<span v-else-if="item==='RISK_CHECK'">风险检查表</span>
<span v-else>{{ item }}</span>
</template>
</div>
</div>
<div class="grid border-b grid-cols-[100px_1fr]">
@@ -554,7 +561,9 @@ onMounted(() => {
<p
class="rounded-sm bg-[var(--theme-color)] px-3 py-1 text-xs font-semibold text-white"
:style="{'--theme-color': themeStore.themeColor}"
>变更附带资料</p>
>
变更附带资料
</p>
<NButton ghost size="small" class="text-xs" @click="downloadFile(null)"><Icon icon="material-symbols:download" class="size-16px" />一键下载</NButton>
</div>
<NTable size="small">
@@ -594,7 +603,9 @@ onMounted(() => {
<p
class="rounded-sm bg-[var(--theme-color)] px-3 py-1 text-xs font-semibold text-white"
:style="{'--theme-color': themeStore.themeColor}"
>风险分析记录表</p>
>
风险分析记录表
</p>
<NButton ghost size="small" class="text-xs" @click="exportFile('risk')"><Icon icon="material-symbols:download" class="size-16px" />导出风险分析记录表</NButton>
</div>
<NTable size="small">
@@ -643,7 +654,7 @@ onMounted(() => {
<span class="text-sm font-semibold text-slate-700">PSSR 检查内容</span>
</div>
<div class="space-y-2.5 border p-3" :style="{borderRadius: themeStore.themeRadius + 'px'}">
<div v-for="(pssr,index) in pssrlist" class="border" :key="index" :style="{borderRadius: themeStore.themeRadius + 'px'}">
<div v-for="(pssr,index) in pssrlist" :key="index" class="border" :style="{borderRadius: themeStore.themeRadius + 'px'}">
<div class="bg-slate-100 px-3 py-1.6 font-medium text-slate-600">{{ pssr.g }}</div>
<div v-for="item in pssr.items" :key="item.id" class="flex items-center border-t px-3 py-1.6">
<p class="flex-1">{{ item.content }}</p>
@@ -685,7 +696,9 @@ onMounted(() => {
<p
class="rounded-sm bg-[var(--theme-color)] px-3 py-1 text-xs font-semibold text-white"
:style="{'--theme-color': themeStore.themeColor}"
>审批记录</p>
>
审批记录
</p>
</div>
<NTable size="small">
<thead>
@@ -713,8 +726,10 @@ onMounted(() => {
<template v-for="(n, i) in currentInfo?.approval_flow?.steps" :key="n.name">
<div class="flex items-center gap-1">
<Icon v-if="i !== 0" icon="formkit:right" class="size-14px text-slate-300" />
<div class="rounded-lg border px-3 py-2 text-center"
:class="n.status === 'PASSED' ? 'border-emerald-300 bg-emerald-50' : n.status === 'PENDING' ? 'border-amber-400 bg-amber-50' : n.status === 'REJECTED' ? 'border-red-300 bg-red-50' :'border-amber-400 bg-amber-50'">
<div
class="rounded-lg border px-3 py-2 text-center"
:class="n.status === 'PASSED' ? 'border-emerald-300 bg-emerald-50' : n.status === 'PENDING' ? 'border-amber-400 bg-amber-50' : n.status === 'REJECTED' ? 'border-red-300 bg-red-50' :'border-amber-400 bg-amber-50'"
>
<p class="text-xs font-medium">
{{ n.name }}
</p>
@@ -776,7 +791,9 @@ onMounted(() => {
textColor: tagTextColor(matchLabel(levelList,level)?.color),
borderColor: tagBorderColor(matchLabel(levelList,level)?.color),
}"
>{{ matchLabel(levelList,level)?.label? matchLabel(levelList,level)?.label+'变更':'' }}</NTag>
>
{{ matchLabel(levelList,level)?.label? matchLabel(levelList,level)?.label+'变更':'' }}
</NTag>
<span class="text-xs text-slate-400">合计得分 <b class="text-[#17407F]">{{ totalScore }}</b> 分(&lt;20 分为一般,≥20 分为重要)</span>
</div>
<NTable size="small">
@@ -906,7 +923,9 @@ onMounted(() => {
<div
class="mt-0.5 text-[11px] leading-snug"
:class="d.over ? 'text-[var(--error-color)]' : 'text-slate-400'"
>{{ d.note }}</div>
>
{{ d.note }}
</div>
</div>
</div>
<!-- AI 审批建议(版本冻结 · 建议分级 · 已阅留痕 · 无感审计) -->
@@ -947,12 +966,16 @@ onMounted(() => {
<div class="leading-relaxed text-slate-700">{{ s.text }}</div>
<div class="mt-1.5">
<div v-if="s.st === '待定'" class="flex gap-3">
<NButton text type="success" class="text-xs hover:underline"
@click="acceptSuggest(s)">
<NButton
text type="success" class="text-xs hover:underline"
@click="acceptSuggest(s)"
>
采纳为行动项
</NButton>
<NButton text class="text-xs hover:underline"
@click="rejectSuggest(s)">
<NButton
text class="text-xs hover:underline"
@click="rejectSuggest(s)"
>
已知悉,不采纳
</NButton>
</div>
@@ -980,7 +1003,6 @@ onMounted(() => {
</div>
</div>
</div>
</div>
</NDrawerContent>
</NDrawer>
@@ -1004,7 +1026,7 @@ onMounted(() => {
<span>上传时间:{{ previewFile?.created_at }}</span>
<span v-if="previewFile?.version">{{ `版本:${previewFile?.version}(受控)` }}</span>
</div>
<previewComponent v-if="previewFile" :previewFile="previewFile" />
<PreviewComponent v-if="previewFile" :preview-file="previewFile" />
</div>
</template>
</NModal>
@@ -1027,8 +1049,8 @@ onMounted(() => {
<NTag v-for="item in rejectQuick" :key="item" class="cursor-pointer" size="small" type="error" @click="rejectReason += item + ';'">{{ item }}</NTag>
</div>
<NInput
class="mt-3"
v-model:value="rejectReason"
class="mt-3"
type="textarea"
:autosize="{ minRows: 3 }"
placeholder="驳回意见(必填),将退回至申请人/指定节点…"
+44 -23
View File
@@ -376,7 +376,7 @@ const getDetail = async () => {
flowList.value = data?.disposal_approval_flow?.steps || [];
steps.value = data?.disposal_approval_flow?.steps || [];
}else{
let template = templateList.value.find((item: any) =>
const template = templateList.value.find((item: any) =>
item.level === data?.apply_form?.change_level &&
item.category === data?.apply_form?.change_type &&
item.duration === data?.apply_form?.duration_type
@@ -553,7 +553,7 @@ const togglePicker = (s: any) => {
// 添加审批步骤人员
const addMember = (s: any, v: string | null) => {
if (v && !s.members.some((m:any) => m.user_name === v)){
let info = findUserInTree(memberList.value, v);
const info = findUserInTree(memberList.value, v);
s.members.push({ user_id: Number(v), user_name: info?.user_name || '', org_id: info?.org_id || '', org_name: info?.org_name || '', specialty: "", is_sign: 0 });
pick.value = null;
pickerStepId.value = null;
@@ -665,7 +665,9 @@ onMounted(async () => {
<p
class="rounded-sm bg-[var(--theme-color)] px-3 py-1 text-xs font-semibold text-white"
:style="{'--theme-color': themeStore.themeColor}"
>变更申请表</p>
>
变更申请表
</p>
<NButton ghost size="small" class="text-xs" @click="exportFile('change')"><Icon icon="material-symbols:download" class="size-16px" />导出变更申请表</NButton>
</div>
<div
@@ -736,7 +738,12 @@ onMounted(async () => {
<div class="grid border-b grid-cols-[100px_1fr]">
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">风险评估方法</p>
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
{{currentInfo?.apply_form?.risk_tools?.join('、')}}
<template v-for="(item,index) in currentInfo?.apply_form?.risk_tools" :key="index">
<span v-if="index!==0">、</span>
<span v-if="item==='RISK'">风险预分析</span>
<span v-else-if="item==='RISK_CHECK'">风险检查表</span>
<span v-else>{{ item }}</span>
</template>
</div>
</div>
<div class="grid border-b grid-cols-[100px_1fr]">
@@ -763,7 +770,9 @@ onMounted(async () => {
<p
class="rounded-sm bg-[var(--theme-color)] px-3 py-1 text-xs font-semibold text-white"
:style="{'--theme-color': themeStore.themeColor}"
>变更附带资料</p>
>
变更附带资料
</p>
<NButton ghost size="small" class="text-xs" @click="downloadFile(null)"><Icon icon="material-symbols:download" class="size-16px" />一键下载</NButton>
</div>
<NTable size="small">
@@ -803,7 +812,9 @@ onMounted(async () => {
<p
class="rounded-sm bg-[var(--theme-color)] px-3 py-1 text-xs font-semibold text-white"
:style="{'--theme-color': themeStore.themeColor}"
>风险分析记录表</p>
>
风险分析记录表
</p>
<NButton ghost size="small" class="text-xs" @click="exportFile('risk')"><Icon icon="material-symbols:download" class="size-16px" />导出风险分析记录表</NButton>
</div>
<NTable size="small">
@@ -852,7 +863,7 @@ onMounted(async () => {
<span class="text-sm font-semibold text-slate-700">PSSR 检查内容</span>
</div>
<div class="space-y-2.5 border p-3" :style="{borderRadius: themeStore.themeRadius + 'px'}">
<div v-for="(pssr,index) in pssrList" class="border" :key="index" :style="{borderRadius: themeStore.themeRadius + 'px'}">
<div v-for="(pssr,index) in pssrList" :key="index" class="border" :style="{borderRadius: themeStore.themeRadius + 'px'}">
<div class="bg-slate-100 px-3 py-1.6 font-medium text-slate-600">{{ pssr.g }}</div>
<div v-for="item in pssr.items" :key="item.id" class="flex items-center border-t px-3 py-1.6">
<p class="flex-1">{{ item.content }}</p>
@@ -894,7 +905,9 @@ onMounted(async () => {
<p
class="rounded-sm bg-[var(--theme-color)] px-3 py-1 text-xs font-semibold text-white"
:style="{'--theme-color': themeStore.themeColor}"
>审批记录</p>
>
审批记录
</p>
</div>
<NTable size="small">
<thead>
@@ -922,8 +935,10 @@ onMounted(async () => {
<template v-for="(n, i) in currentInfo?.approval_flow?.steps" :key="n.name">
<div class="flex items-center gap-1">
<Icon v-if="i !== 0" icon="formkit:right" class="size-14px text-slate-300" />
<div class="rounded-lg border px-3 py-2 text-center"
:class="n.status === 'PASSED' ? 'border-emerald-300 bg-emerald-50' : n.status === 'PENDING' ? 'border-amber-400 bg-amber-50' : n.status === 'REJECTED' ? 'border-red-300 bg-red-50' :'border-amber-400 bg-amber-50'">
<div
class="rounded-lg border px-3 py-2 text-center"
:class="n.status === 'PASSED' ? 'border-emerald-300 bg-emerald-50' : n.status === 'PENDING' ? 'border-amber-400 bg-amber-50' : n.status === 'REJECTED' ? 'border-red-300 bg-red-50' :'border-amber-400 bg-amber-50'"
>
<p class="text-xs font-medium">
{{ n.name }}
</p>
@@ -951,7 +966,8 @@ onMounted(async () => {
</template>
{{ m.user_name }}
</NTag>
<div v-if="m.status === 'PENDING'"
<div
v-if="m.status === 'PENDING'"
class="cursor-pointer inline-flex h-6 items-center gap-1 rounded-md border border-amber-300 bg-white px-2 text-[11px] text-amber-700 transition hover:bg-amber-100"
@click="handleReminder(m)"
>
@@ -961,7 +977,6 @@ onMounted(async () => {
</div>
</div>
</div>
</div>
</NCard>
</NGi>
@@ -1055,7 +1070,7 @@ onMounted(async () => {
<p class="text-xs text-slate-400">{{ confirmedPssr }}/{{ totalPssr }} 已确认</p>
</div>
<div class="p-2 space-y-2">
<div v-for="(pssr,index) in pssrList" class="border" :key="index" :style="{borderRadius: themeStore.themeRadius + 'px'}">
<div v-for="(pssr,index) in pssrList" :key="index" class="border" :style="{borderRadius: themeStore.themeRadius + 'px'}">
<div class="bg-slate-100 px-2 py-1.5 font-medium text-xs text-slate-600 flex items-center justify-between">
{{ pssr.g }}
<NButton text size="small" type="primary" class="text-xs" @click="addItem(index)">
@@ -1064,10 +1079,10 @@ onMounted(async () => {
</div>
<div v-for="(item,subIndex) in pssr.items" :key="subIndex" class="flex items-center border-t px-2 py-1 gap-2">
<NInput v-if="!item.id" v-model:value="item.content" size="small" type="textarea" :autosize="{minRows: 1}" placeholder="填写检查项内容" class="w-full text-xs"></NInput>
<NButton v-if="!item.id" text type="success" @click="saveItem(index, subIndex)" title="保存检查项">
<NButton v-if="!item.id" text type="success" title="保存检查项" @click="saveItem(index, subIndex)">
<Icon icon="boxicons:save" class="size-16px" />
</NButton>
<NButton v-if="!item.id" text type="error" @click="pssrList[index].items.splice(subIndex, 1)" title="删除">
<NButton v-if="!item.id" text type="error" title="删除" @click="pssrList[index].items.splice(subIndex, 1)">
<Icon icon="ep:delete" class="size-14px" />
</NButton>
<p v-if="item.id" class="flex-1 text-xs">{{ item.content }}</p>
@@ -1143,7 +1158,9 @@ onMounted(async () => {
textColor: tagTextColor(matchLabel(levelList,level)?.color),
borderColor: tagBorderColor(matchLabel(levelList,level)?.color),
}"
>{{ matchLabel(levelList,level)?.label? matchLabel(levelList,level)?.label+'变更':'' }}</NTag>
>
{{ matchLabel(levelList,level)?.label? matchLabel(levelList,level)?.label+'变更':'' }}
</NTag>
<span class="text-xs text-slate-400">合计得分 <b class="text-[#17407F]">{{ totalScore }}</b> 分(&lt;20 分为一般,≥20 分为重要)</span>
</div>
<NTable size="small">
@@ -1180,7 +1197,7 @@ onMounted(async () => {
<NCheckbox :checked="s.countersign" size="small" @update:checked="(v) => setStepCountersign(s, v)">
<span class="text-xs text-slate-500">专业会签步骤</span>
</NCheckbox>
<NButton ghost type="primary" size="tiny" @click="togglePicker(s)" title="添加预设人员" class="ml-auto">
<NButton ghost type="primary" size="tiny" title="添加预设人员" class="ml-auto" @click="togglePicker(s)">
<Icon icon="ic:round-plus" class="size-16px" />
</NButton>
</div>
@@ -1192,11 +1209,13 @@ onMounted(async () => {
<span class="shrink-0 truncate text-xs font-medium text-slate-700">{{ m.user_name }}</span>
<template v-if="s.countersign">
<span class="text-xs text-slate-400"><span class="text-red-500">*</span>专业:</span>
<NSelect :value="m.specialty || null" clearable size="small" placeholder="请选择专业" class="w-28"
<NSelect
:value="m.specialty || null" clearable size="small" placeholder="请选择专业" class="w-28"
:options="SPECIALTIES"
@update:value="(v) => selectSpecialty(Number(idx), Number(mIdx), v)"
/>
<NCheckbox :checked="m.is_sign" size="small"
<NCheckbox
:checked="m.is_sign" size="small"
:checked-value="1"
:unchecked-value="0"
@update:checked="(v) => selectSign(Number(idx), Number(mIdx), v)"
@@ -1204,16 +1223,18 @@ onMounted(async () => {
<span class="text-xs text-slate-500">必须参与会签</span>
</NCheckbox>
</template>
<NButton text type="error" @click="delMember(s, m.user_id)" title="删除该人员">
<NButton text type="error" title="删除该人员" @click="delMember(s, m.user_id)">
<Icon icon="iconamoon:trash" class="size-16px" />
</NButton>
</div>
<p v-if="s.countersign && s.members.length" class="text-[11px] leading-5 text-slate-400">
必须参与会签:勾选的人员必须参与专业会签,未勾选的人员为可选会签(按需参加)
</p>
<NCascader v-if="pickerStepId === s.id" :value="pick" :options="memberList"
<NCascader
v-if="pickerStepId === s.id" :value="pick" :options="memberList"
placeholder="请选择人员" size="small" check-strategy="child" :show-path="false" expand-trigger="click"
class="w-56" :on-update:value="(v) => addMember(s, v)" />
class="w-56" :on-update:value="(v) => addMember(s, v)"
/>
<span v-if="s.members.length === 0" class="text-xs leading-7 text-slate-300">未预设</span>
</div>
@@ -1245,7 +1266,7 @@ onMounted(async () => {
<span>上传时间:{{ previewFile?.created_at }}</span>
<span v-if="previewFile?.version">{{ `版本:${previewFile?.version}(受控)` }}</span>
</div>
<previewComponent v-if="previewFile" :previewFile="previewFile" />
<PreviewComponent v-if="previewFile" :preview-file="previewFile" />
</div>
</template>
</NModal>
+29 -12
View File
@@ -342,7 +342,9 @@ onMounted(() => {
<p
class="rounded-sm bg-[var(--theme-color)] px-3 py-1 text-xs font-semibold text-white"
:style="{'--theme-color': themeStore.themeColor}"
>变更申请表</p>
>
变更申请表
</p>
<NButton ghost size="small" class="text-xs" @click="exportFile('change')"><Icon icon="material-symbols:download" class="size-16px" />导出变更申请表</NButton>
</div>
<div
@@ -413,7 +415,12 @@ onMounted(() => {
<div class="grid border-b grid-cols-[100px_1fr]">
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">风险评估方法</p>
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
{{currentInfo?.apply_form?.risk_tools?.join('、')}}
<template v-for="(item,index) in currentInfo?.apply_form?.risk_tools" :key="index">
<span v-if="index!==0">、</span>
<span v-if="item==='RISK'">风险预分析</span>
<span v-else-if="item==='RISK_CHECK'">风险检查表</span>
<span v-else>{{ item }}</span>
</template>
</div>
</div>
<div class="grid border-b grid-cols-[100px_1fr]">
@@ -440,7 +447,9 @@ onMounted(() => {
<p
class="rounded-sm bg-[var(--theme-color)] px-3 py-1 text-xs font-semibold text-white"
:style="{'--theme-color': themeStore.themeColor}"
>变更附带资料</p>
>
变更附带资料
</p>
<NButton ghost size="small" class="text-xs" @click="downloadFile(null)"><Icon icon="material-symbols:download" class="size-16px" />一键下载</NButton>
</div>
<NTable size="small">
@@ -480,7 +489,9 @@ onMounted(() => {
<p
class="rounded-sm bg-[var(--theme-color)] px-3 py-1 text-xs font-semibold text-white"
:style="{'--theme-color': themeStore.themeColor}"
>风险分析记录表</p>
>
风险分析记录表
</p>
<NButton ghost size="small" class="text-xs" @click="exportFile('risk')"><Icon icon="material-symbols:download" class="size-16px" />导出风险分析记录表</NButton>
</div>
<NTable size="small">
@@ -529,7 +540,7 @@ onMounted(() => {
<span class="text-sm font-semibold text-slate-700">PSSR 检查内容</span>
</div>
<div class="space-y-2.5 border p-3" :style="{borderRadius: themeStore.themeRadius + 'px'}">
<div v-for="(pssr,index) in pssrlist" class="border" :key="index" :style="{borderRadius: themeStore.themeRadius + 'px'}">
<div v-for="(pssr,index) in pssrlist" :key="index" class="border" :style="{borderRadius: themeStore.themeRadius + 'px'}">
<div class="bg-slate-100 px-3 py-1.6 font-medium text-slate-600">{{ pssr.g }}</div>
<div v-for="item in pssr.items" :key="item.id" class="flex items-center border-t px-3 py-1.6">
<p class="flex-1">{{ item.content }}</p>
@@ -571,7 +582,9 @@ onMounted(() => {
<p
class="rounded-sm bg-[var(--theme-color)] px-3 py-1 text-xs font-semibold text-white"
:style="{'--theme-color': themeStore.themeColor}"
>审批记录</p>
>
审批记录
</p>
</div>
<NTable size="small">
<thead>
@@ -599,8 +612,10 @@ onMounted(() => {
<template v-for="(n, i) in currentInfo?.approval_flow?.steps" :key="n.name">
<div class="flex items-center gap-1">
<Icon v-if="i !== 0" icon="formkit:right" class="size-14px text-slate-300" />
<div class="rounded-lg border px-3 py-2 text-center"
:class="n.status === 'PASSED' ? 'border-emerald-300 bg-emerald-50' : n.status === 'PENDING' ? 'border-amber-400 bg-amber-50' : n.status === 'REJECTED' ? 'border-red-300 bg-red-50' :'border-amber-400 bg-amber-50'">
<div
class="rounded-lg border px-3 py-2 text-center"
:class="n.status === 'PASSED' ? 'border-emerald-300 bg-emerald-50' : n.status === 'PENDING' ? 'border-amber-400 bg-amber-50' : n.status === 'REJECTED' ? 'border-red-300 bg-red-50' :'border-amber-400 bg-amber-50'"
>
<p class="text-xs font-medium">
{{ n.name }}
</p>
@@ -628,7 +643,8 @@ onMounted(() => {
</template>
{{ m.user_name }}
</NTag>
<div v-if="m.status === 'PENDING'"
<div
v-if="m.status === 'PENDING'"
class="cursor-pointer inline-flex h-6 items-center gap-1 rounded-md border border-amber-300 bg-white px-2 text-[11px] text-amber-700 transition hover:bg-amber-100"
@click="handleReminder(m)"
>
@@ -638,7 +654,6 @@ onMounted(() => {
</div>
</div>
</div>
</div>
</NCard>
<!-- 变更类型判定说明(右侧抽屉) -->
@@ -681,7 +696,9 @@ onMounted(() => {
textColor: tagTextColor(matchLabel(levelList,level)?.color),
borderColor: tagBorderColor(matchLabel(levelList,level)?.color),
}"
>{{ matchLabel(levelList,level)?.label? matchLabel(levelList,level)?.label+'变更':'' }}</NTag>
>
{{ matchLabel(levelList,level)?.label? matchLabel(levelList,level)?.label+'变更':'' }}
</NTag>
<span class="text-xs text-slate-400">合计得分 <b class="text-[#17407F]">{{ totalScore }}</b> 分(&lt;20 分为一般,≥20 分为重要)</span>
</div>
<NTable size="small">
@@ -723,7 +740,7 @@ onMounted(() => {
<span>上传时间:{{ previewFile?.created_at }}</span>
<span v-if="previewFile?.version">{{ `版本:${previewFile?.version}(受控)` }}</span>
</div>
<previewComponent v-if="previewFile" :previewFile="previewFile" />
<PreviewComponent v-if="previewFile" :preview-file="previewFile" />
</div>
</template>
</NModal>
+23 -13
View File
@@ -288,18 +288,19 @@ onUnmounted(() => {
</div>
<div class="flex flex-col gap-3">
<template v-if="homeData?.todo_approvals?.total > 0">
<div v-for="row in homeData?.todo_approvals?.items || []" :key="row.change_id" @click="jumpTo('details_approval',row.change_id)"
class="cursor-pointer flex w-full items-center gap-3 border px-3.5 py-2.5 text-left transition"
<div
v-for="row in homeData?.todo_approvals?.items || []" :key="row.change_id" class="cursor-pointer flex w-full items-center gap-3 border px-3.5 py-2.5 text-left transition"
:style="{
borderRadius: themeStore.themeRadius + 'px',
borderColor: row.overdue_status===2?getColorWithOpacity(themeStore.otherColor.error, 0.25):getColorWithOpacity(themeStore.themeColor, 0.25),
backgroundColor: row.overdue_status===2?getColorWithOpacity(themeStore.otherColor.error, 0.05):getColorWithOpacity(themeStore.themeColor, 0.05),
}"
@click="jumpTo('details_approval',row.change_id)"
>
<div class="min-w-0 flex-1">
<div class="flex flex-wrap items-center gap-2">
<span class="font-mono text-[11px] text-slate-400">{{ row.change_no }}</span>
<NTag class="text-[11px]" v-if="row.urgent===1" type="error" size="small">紧急</NTag>
<NTag v-if="row.urgent===1" class="text-[11px]" type="error" size="small">紧急</NTag>
<!-- 变更等级 -->
<NTag
size="small"
@@ -308,7 +309,9 @@ onUnmounted(() => {
textColor: tagTextColor(matchObj(levelList,row.change_level)?.color),
borderColor: tagBorderColor(matchObj(levelList,row.change_level)?.color),
}"
>{{matchObj(levelList,row.change_level)?.label}}</NTag>
>
{{ matchObj(levelList,row.change_level)?.label }}
</NTag>
<!-- 变更类型 -->
<NTag
size="small"
@@ -317,10 +320,12 @@ onUnmounted(() => {
textColor: tagTextColor(matchObj(typeList,row.change_type)?.color),
borderColor: tagBorderColor(matchObj(typeList,row.change_type)?.color),
}"
>{{matchObj(typeList,row.change_type)?.label}}</NTag>
>
{{ matchObj(typeList,row.change_type)?.label }}
</NTag>
<NTag class="text-[11px]" v-if="row.duration_type===2" type="warning" size="small">临时</NTag>
<NTag class="text-[11px]" v-else type="info" size="small">永久</NTag>
<NTag v-if="row.duration_type===2" class="text-[11px]" type="warning" size="small">临时</NTag>
<NTag v-else class="text-[11px]" type="info" size="small">永久</NTag>
<span v-if="row.overdue_status===2" class="text-xs" :style="{ color: themeStore.otherColor.error }">已超期 {{ row.overdue_days }} 天</span>
</div>
<div class="mt-1 flex items-center gap-2">
@@ -360,13 +365,14 @@ onUnmounted(() => {
</div>
<div class="flex flex-col gap-3">
<template v-if="homeData?.unclosed_progress?.total > 0">
<div v-for="row in homeData?.unclosed_progress?.items || []" :key="row.change_id" @click="jumpTo('details_index',row.change_id)"
class="cursor-pointer flex w-full items-center gap-3 border px-3.5 py-2.5 text-left transition hover:border-[var(--hover-border)] hover:bg-[var(--hover-bg)]"
<div
v-for="row in homeData?.unclosed_progress?.items || []" :key="row.change_id" class="cursor-pointer flex w-full items-center gap-3 border px-3.5 py-2.5 text-left transition hover:border-[var(--hover-border)] hover:bg-[var(--hover-bg)]"
:style="{
borderRadius: themeStore.themeRadius + 'px',
'--hover-border': getColorWithOpacity(themeStore.themeColor, 0.25),
'--hover-bg': getColorWithOpacity(themeStore.themeColor, 0.05)
}"
@click="jumpTo('details_index',row.change_id)"
>
<div class="min-w-0 flex-1">
<div class="flex flex-wrap items-center gap-2">
@@ -387,7 +393,9 @@ onUnmounted(() => {
textColor: tagTextColor(matchObj(levelList,row.change_level)?.color),
borderColor: tagBorderColor(matchObj(levelList,row.change_level)?.color),
}"
>{{matchObj(levelList,row.change_level)?.label}}</NTag>
>
{{ matchObj(levelList,row.change_level)?.label }}
</NTag>
</div>
<div class="mt-1 flex items-center gap-2 font-mono text-[11px] text-slate-400">
<span>{{ row.change_no }}</span>
@@ -433,7 +441,8 @@ onUnmounted(() => {
</div>
<div class="flex flex-col gap-3">
<template v-if="homeData?.temp_after_use?.total > 0">
<div v-for="row in homeData?.temp_after_use?.items || []" :key="row.change_id"
<div
v-for="row in homeData?.temp_after_use?.items || []" :key="row.change_id"
class="flex w-full items-center gap-3 border px-3.5 py-2.5 text-left transition"
:style="{
borderRadius: themeStore.themeRadius + 'px',
@@ -484,15 +493,16 @@ onUnmounted(() => {
</div>
<div class="flex flex-col gap-3">
<template v-if="homeData?.key_attention?.total > 0">
<div v-for="row in homeData?.key_attention?.items || []" :key="row.change_id"
<div
v-for="row in homeData?.key_attention?.items || []" :key="row.change_id"
class="cursor-pointer flex w-full items-center gap-3 border px-3.5 py-2.5 text-left transition !hover:border-[var(--hover-border)]"
@click="jumpTo('details_index',row.change_id)"
:style="{
borderRadius: themeStore.themeRadius + 'px',
'--hover-border': getColorWithOpacity(themeStore.otherColor.error, 0.3),
backgroundColor: getColorWithOpacity(themeStore.otherColor.error, 0.05),
borderColor: getColorWithOpacity(themeStore.otherColor.error, 0.05),
}"
@click="jumpTo('details_index',row.change_id)"
>
<div class="min-w-0 flex-1">
<div class="flex flex-wrap items-center gap-2">