关闭确认静态页面完成
This commit is contained in:
@@ -0,0 +1,213 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue';
|
||||
import { useAppStore } from '@/store/modules/app';
|
||||
import { Icon } from '@iconify/vue'
|
||||
import { useThemeStore } from '@/store/modules/theme';
|
||||
import { getColorWithOpacity } from '@/utils/common';
|
||||
|
||||
const appStore = useAppStore();
|
||||
const themeStore = useThemeStore();
|
||||
const gap = computed(() => (appStore.isMobile ? 0 : 16));
|
||||
|
||||
const emit = defineEmits<{ go: [v: string, preset?: string];}>();
|
||||
|
||||
const restoresDone = ref<boolean>(false);
|
||||
const restores = ref<{ item: string, done: boolean }[]>([
|
||||
{ item: "安全阀起跳压力已恢复至原设定 0.8MPa(恢复操作票 CAO-2026-0812)", done: true },
|
||||
{ item: "恢复后运行参数核对:连续 24h 无起跳、阀体无泄漏", done: false },
|
||||
{ item: "恢复性检查记录与现场照片已上传", done: false },
|
||||
]);
|
||||
const canRestore = ref<boolean>(false);
|
||||
const readyToClose = ref<boolean>(false);
|
||||
|
||||
const checks = ref<{ item: string, done: boolean, note?: string }[]>([
|
||||
{ item: "变更验收完成(结论:基本达到 · 遗留项 2 项已登记跟踪)", done: true },
|
||||
{ item: "资料上传齐全(验收报告、运行记录、恢复确认记录)", done: false, note: "缺:更新后的安全阀台账" },
|
||||
{ item: "行动项全部关闭(4/4,含「关闭前完成」标记项)", done: true },
|
||||
{ item: "受控文件已更新至生效版(P&ID Rev.4、操作规程)", done: false, note: "安全阀台账待更新发布" },
|
||||
{ item: "培训考核完成(12/12 人),签到与成绩已归档", done: true },
|
||||
]);
|
||||
|
||||
const archiving = ref<boolean>(false);
|
||||
const step = ref<number>(0);
|
||||
const archivedHash = ref<string | null>(null);
|
||||
const allDone = computed(() => checks.value.every((c: { done: boolean }) => c.done));
|
||||
const isCloser = ref<boolean>(true);
|
||||
const startArchive = () => { step.value = 0; archiving.value = true; };
|
||||
|
||||
// 关闭即归档:自动归档八步流程
|
||||
const ARCHIVE_STEPS = [
|
||||
"关闭触发:接收「同意关闭」归档指令(不可逆)",
|
||||
"文件收集:申请表 / 审批记录 / 风险分析 / 培训 / PSSR / 验收单生成 PDF",
|
||||
"附件归集:原始附件、培训签到照片、PSSR 现场照片、验收签字文件",
|
||||
"受控文件复制:生效版与被替代旧版物理复制,与工作区脱离",
|
||||
"清单生成:自动生成归档索引与文件更新清单(新旧版本对照)",
|
||||
"打包锁定:写入归档区(装置 / 年份 / 变更单号),设为只读",
|
||||
"哈希存证:计算归档包 SHA-256 哈希值入库,防篡改校验",
|
||||
"状态更新:变更为「已关闭-已归档」,首页数据同步",
|
||||
];
|
||||
const closedAt = ref<string | null>(null);
|
||||
|
||||
const OVERDUE_LIST = [
|
||||
{ id: "MOC-2026-R01-0039", title: "V-102 安全阀起跳压力临时调整", stage: "待关闭", days: 4 },
|
||||
{ id: "MOC-2026-R02-0031", title: "冷冻盐水泵 P-103 叶轮材质变更", stage: "待验收", days: 7 },
|
||||
{ id: "MOC-2026-R01-0029", title: "操作规程修订(夏季工况)", stage: "审批中", days: 3 },
|
||||
];
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NSpace vertical :size="16">
|
||||
<!-- 关闭确认 -->
|
||||
<NCard
|
||||
:bordered="false"
|
||||
size="small"
|
||||
:style="{
|
||||
borderRadius: themeStore.themeRadius + 'px',
|
||||
'--error-color': themeStore.otherColor.error,
|
||||
'--success-color': themeStore.otherColor.success,
|
||||
'--success-bg': getColorWithOpacity(themeStore.otherColor.success, 0.1),
|
||||
'--warning-color': themeStore.otherColor.warning,
|
||||
'--warning-bg': getColorWithOpacity(themeStore.otherColor.warning, 0.1),
|
||||
'--theme-color': themeStore.themeColor,
|
||||
'--theme-bg': getColorWithOpacity(themeStore.themeColor, 0.1),
|
||||
}"
|
||||
>
|
||||
<div class="space-y-4">
|
||||
<NCard :bordered="true" :content-style="{ padding: '0' }" size="small" :style="{ borderRadius: themeStore.themeRadius + 'px' }">
|
||||
<div class="py-3 px-4 border-b flex items-center justify-between">
|
||||
<div class="flex items-center gap-2 text-base font-semibold">
|
||||
<Icon icon="system-uicons:reset" class="size-16px text-[var(--error-color)]" />临时变更恢复确认 · 期限 30 天
|
||||
</div>
|
||||
<NTag v-if="restoresDone" size="small" type="success">恢复确认完成</NTag>
|
||||
<NTag v-else size="small" type="error">已超期 4 天 · 已升级上报刘副总</NTag>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<div class="flex flex-wrap gap-x-6 gap-y-1 text-xs text-slate-500">
|
||||
<span>计划恢复时间:2026-08-14(临时调整起跳压力 0.88MPa → 恢复原设定 0.8MPa)</span>
|
||||
<span class="text-[var(--error-color)]">超期未恢复:每日 08:00 提醒申请人与属地负责人,已自动升级上报分管领导</span>
|
||||
</div>
|
||||
<div class="space-y-2 pt-3">
|
||||
<div v-for="(r, i) in restores" :key="r.item" class="flex items-center gap-3 rounded-lg border p-3"
|
||||
:class="r.done ? 'border-emerald-200 bg-emerald-50/40' : 'border-amber-200 bg-amber-50/40'">
|
||||
<Icon v-if="r.done" icon="material-symbols:check-circle-outline" class="size-20px text-[var(--success-color)]" />
|
||||
<Icon v-else icon="system-uicons:reset" class="size-18px text-[var(--warning-color)]" />
|
||||
<div class="flex-1 text-sm">{{ r.item }}</div>
|
||||
<NButton v-if="!r.done && canRestore" size="small" ghost class="text-xs"
|
||||
@click="restores = restores.map((x, xi) => (xi === i ? { ...x, done: true } : x)); toast.success('演示:恢复确认完成(移动端可拍照上传凭证)');">
|
||||
<Icon icon="ant-design:camera-outlined" class="size-16px mr-1" />
|
||||
确认恢复
|
||||
</NButton>
|
||||
<span v-if="!r.done && !canRestore" class="text-xs text-slate-400">待申请人 / 属地负责人确认</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="restoresDone" class="mt-3 rounded-lg bg-emerald-50 px-3 py-2 text-xs text-emerald-700">
|
||||
临时变更恢复确认完成,恢复操作票、参数核对记录与照片将自动纳入归档包「5-验收记录」
|
||||
</div>
|
||||
</div>
|
||||
</NCard>
|
||||
<NCard :bordered="true" :content-style="{ padding: '0' }" size="small" :style="{ borderRadius: themeStore.themeRadius + 'px' }">
|
||||
<div class="py-3 px-4 border-b flex items-center justify-between">
|
||||
<div class="flex items-center gap-2 text-base font-semibold">
|
||||
<Icon icon="material-symbols:check-circle-outline" class="size-18px text-slate-500" />关闭校验 · MOC-2026-R01-0039(紧急变更补办)
|
||||
</div>
|
||||
<NTag v-if="readyToClose" size="small" type="success">校验全绿 · 已推送专责</NTag>
|
||||
<NTag v-else size="small" type="warning">超期 4 天</NTag>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<div class="flex items-center gap-2 rounded-lg bg-[var(--theme-bg)] px-3 py-2 text-xs text-[var(--theme-color)]">
|
||||
<Icon icon="lucide:bell" class="size-14px" />
|
||||
前置条件(验收完成 / 资料齐全 / 行动项关闭 / 恢复确认 / 受控文件更新)全部满足后,系统自动推送变更主管部门专责(王海燕 · 安全环保部),并抄送申请人与属地负责人
|
||||
</div>
|
||||
<div class="space-y-2 pt-3">
|
||||
<div v-for="(c, i) in checks" :key="c.item" class="flex items-center gap-3 rounded-lg border p-3"
|
||||
:class="c.done ? 'border-emerald-200 bg-emerald-50/40' : 'border-red-200 bg-[#FFF2F0]'">
|
||||
<Icon v-if="c.done" icon="material-symbols:check-circle-outline" class="size-20px text-[var(--success-color)]" />
|
||||
<Icon v-else icon="ant-design:close-circle-outlined" class="size-18px text-[var(--error-color)]" />
|
||||
<div class="flex-1 text-sm">{{ c.item }}<span v-if="c.note" class="ml-2 text-xs text-[var(--error-color)]">{{ c.note }}</span></div>
|
||||
<NButton v-if="!c.done" text type="primary"
|
||||
@click="checks = checks.map((x, xi) => (xi === i ? { ...x, done: true } : x)); toast.success('演示:资料已补充上传,关闭校验清单已同步更新并重新推送专责');">去补充</NButton>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 关闭按钮区 -->
|
||||
<div v-if="!archivedHash && !archiving" class="mt-4 space-y-2">
|
||||
<div v-if="readyToClose" class="flex items-center gap-2 rounded-lg bg-[var(--theme-bg)] px-3 py-2 text-xs text-[var(--theme-color)]">
|
||||
<Icon icon="lucide:bell" class="size-14px" />
|
||||
系统已于今日 09:12 自动推送关闭待办至变更主管部门专责(王海燕)· 系统消息 + 企业微信
|
||||
</div>
|
||||
<div class="flex flex-wrap items-center justify-between gap-2 rounded-lg bg-slate-50 p-3">
|
||||
<span class="text-sm text-slate-500">
|
||||
{{ !restoresDone
|
||||
? '临时变更尚未完成恢复确认,禁止关闭(恢复确认是临时变更关闭的前置条件)'
|
||||
: allDone
|
||||
? isCloser
|
||||
? '全部条件满足。确认关闭后系统记录关闭时间与关闭人,并自动生成归档包(副本归档 · 只读锁定 · 哈希存证)'
|
||||
: '全部条件满足,待变更主管部门专责(王海燕 · 安全环保部)确认关闭'
|
||||
: '存在未满足条件,禁止关闭;确需例外须填写说明并经分管领导确认' }}
|
||||
</span>
|
||||
<NButton v-if="isCloser" size="small" type="primary" :disabled="!readyToClose" class="text-xs" @click="startArchive">
|
||||
<Icon icon="uil:lock" class="size-14px mr-1" /> 确认关闭并归档
|
||||
</NButton>
|
||||
<span v-else class="text-xs text-[var(--warning-color)]">仅变更主管部门专责可确认关闭 · 切换至「王海燕 · 安全工程师」体验</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 自动归档流程 -->
|
||||
<div v-if="archiving" class="mt-4 space-y-1.5 rounded-lg border border-[var(--theme-color)] bg-[var(--theme-bg)] p-4">
|
||||
<div class="mb-2 flex items-center gap-2 text-sm font-semibold text-[var(--theme-color)]">
|
||||
<Icon icon="ri:loader-4-fill" class="size-18px animate-spin" />
|
||||
系统自动归档中,无需人工整理…
|
||||
</div>
|
||||
<div v-for="(s, i) in ARCHIVE_STEPS" :key="s" class="flex items-center gap-2 text-xs"
|
||||
:class="i < step ? 'text-[var(--success-color)]' : i === step ? 'font-medium text-[var(--theme-color)]' : 'text-slate-400'">
|
||||
<Icon v-if="i < step" icon="material-symbols:check-circle-outline" class="size-16px" />
|
||||
<Icon v-else-if="i === step" icon="ri:loader-4-fill" class="size-16px animate-spin" />
|
||||
<span v-else class="h-3.5 w-3.5 shrink-0 rounded-full border border-slate-300"></span>
|
||||
{{ i + 1 }}. {{ s }}
|
||||
</div>
|
||||
</div>
|
||||
<!-- 归档完成 -->
|
||||
<div v-if="archivedHash" class="mt-4 space-y-3 rounded-lg border border-emerald-300 bg-emerald-50/60 p-4">
|
||||
<div class="flex flex-wrap items-center gap-2 text-sm font-semibold text-emerald-800">
|
||||
<Icon icon="uil:lock" class="size-18px" /> 已关闭-已归档 · 归档包只读锁定,任何角色不可修改或删除
|
||||
</div>
|
||||
<div class="grid gap-1.5 text-xs text-emerald-800/90 sm:grid-cols-2">
|
||||
<span>关闭时间:{{ closedAt }} · 关闭人:王海燕(变更管理专责 · 安全环保部)</span>
|
||||
<span>归档路径:归档区 / 01-常减压装置 / 2026 / MOC-2026-R01-0039/</span>
|
||||
<span class="flex items-center gap-1"><Hash class="h-3 w-3" /> SHA-256:{{ archivedHash }}</span>
|
||||
<span>归档内容:6 类文件夹 + 归档索引.txt(共 24 个文件,18.4MB)</span>
|
||||
<span>防篡改:系统定期校验哈希值,异常自动告警并从备份恢复</span>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<NButton size="small" type="success" class="text-xs" @click="emit('go', 'knowledge')">
|
||||
<Icon icon="lucide:folder-archive" class="size-14px mr-1" /> 查看归档包
|
||||
</NButton>
|
||||
<NButton size="small" type="primary" class="text-xs" @click="toast.success('演示:下载完整归档包(ZIP,用于外部审计)')">
|
||||
<Icon icon="material-symbols:download" class="size-18px" /> 下载 ZIP
|
||||
</NButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</NCard>
|
||||
<NCard :bordered="true" :content-style="{ padding: '0' }" size="small" :style="{ borderRadius: themeStore.themeRadius + 'px' }">
|
||||
<div class="py-3 px-4 border-b flex items-center justify-between">
|
||||
<div class="flex items-center gap-2 text-base font-semibold">
|
||||
<Icon icon="proicons:alert-triangle" class="size-18px text-slate-500" />关闭提醒
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-2 p-4">
|
||||
<div v-for="o in OVERDUE_LIST" :key="o.id" class="flex items-center justify-between rounded-lg border border-amber-200 bg-amber-50 px-3 py-2">
|
||||
<div class="min-w-0">
|
||||
<div class="truncate text-sm">{{ o.title }}</div>
|
||||
<div class="text-xs text-slate-500">{{ o.id }} · {{ o.stage }}</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<NTag size="small" type="error">超期 {{ o.days }} 天</NTag>
|
||||
<NButton size="small" class="text-xs" @click="toast.info('演示:已催办(系统消息 + 企业微信)')">催办</NButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</NCard>
|
||||
</div>
|
||||
</NCard>
|
||||
</NSpace>
|
||||
</template>
|
||||
@@ -45,7 +45,6 @@ const { domRef, updateOptions } = useEcharts(() => ({
|
||||
},
|
||||
formatter: function (name: string) {
|
||||
var info = props.data?.find((item: { name: string }) => item.name === name);
|
||||
console.group(info)
|
||||
if(info){
|
||||
return '{name|'+name+'} {count|'+(info.value)+' 起}{rate|'+(info.rate)+' %} {money|'+(info.money)+' 万元}';
|
||||
}else{
|
||||
|
||||
Reference in New Issue
Block a user