安全与风险统计页面完成
This commit is contained in:
@@ -233,13 +233,12 @@ const local: App.I18n.Schema = {
|
||||
home: '首页',
|
||||
my: '我的操作台',
|
||||
my_initiatechange: '发起变更',
|
||||
my_highrisk: '本专业高风险',
|
||||
my_highrisk: '高风险',
|
||||
my_mytask: '我的任务',
|
||||
my_mydraft: '我的草稿',
|
||||
my_pendingchange: '待投用变更',
|
||||
my_effect: '变更投入和效果',
|
||||
my_datachangecenter: '变更数据中心',
|
||||
my_closeconfirm: '关闭确认',
|
||||
changeledger: '变更台账',
|
||||
changestatistics: '本部门变更统计',
|
||||
docs: '资料管理',
|
||||
|
||||
@@ -30,7 +30,6 @@ export const views: Record<LastLevelRouteKey, RouteComponent | (() => Promise<Ro
|
||||
factoryoverview: () => import("@/views/factoryOverview/index.vue"),
|
||||
home: () => import("@/views/home/index.vue"),
|
||||
login: () => import("@/views/login/index.vue"),
|
||||
my_closeconfirm: () => import("@/views/my/closeConfirm/index.vue"),
|
||||
my_datachangecenter: () => import("@/views/my/dataChangeCenter/index.vue"),
|
||||
my_effect: () => import("@/views/my/effect/index.vue"),
|
||||
my_highrisk: () => import("@/views/my/highRisk/index.vue"),
|
||||
|
||||
@@ -205,15 +205,6 @@ export const generatedRoutes: GeneratedRoute[] = [
|
||||
order: 2
|
||||
},
|
||||
children: [
|
||||
{
|
||||
name: 'my_closeconfirm',
|
||||
path: '/my/closeconfirm',
|
||||
component: 'view.my_closeconfirm',
|
||||
meta: {
|
||||
title: '关闭确认',
|
||||
i18nKey: 'route.my_closeconfirm'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'my_datachangecenter',
|
||||
path: '/my/datachangecenter',
|
||||
@@ -237,7 +228,7 @@ export const generatedRoutes: GeneratedRoute[] = [
|
||||
path: '/my/highrisk',
|
||||
component: 'view.my_highrisk',
|
||||
meta: {
|
||||
title: '本专业高风险',
|
||||
title: '高风险',
|
||||
i18nKey: 'route.my_highrisk'
|
||||
}
|
||||
},
|
||||
|
||||
@@ -181,7 +181,6 @@ const routeMap: RouteMap = {
|
||||
"home": "/home",
|
||||
"login": "/login/:module(pwd-login)?",
|
||||
"my": "/my",
|
||||
"my_closeconfirm": "/my/closeconfirm",
|
||||
"my_datachangecenter": "/my/datachangecenter",
|
||||
"my_effect": "/my/effect",
|
||||
"my_highrisk": "/my/highrisk",
|
||||
|
||||
@@ -47,7 +47,14 @@ export function changeDataCenterApi(params: {from: string | null, to: string | n
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// 安全与风险统计
|
||||
export function safeRiskStatisticsApi(params: {from: string | null, to: string | null}) {
|
||||
return request({
|
||||
url: `/api/reports/safety-risk`,
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
// 本部门变更统计
|
||||
export function departmentStatisticsApi(params: {from: string | null, to: string | null}) {
|
||||
|
||||
Vendored
-2
@@ -35,7 +35,6 @@ declare module "@elegant-router/types" {
|
||||
"home": "/home";
|
||||
"login": "/login/:module(pwd-login)?";
|
||||
"my": "/my";
|
||||
"my_closeconfirm": "/my/closeconfirm";
|
||||
"my_datachangecenter": "/my/datachangecenter";
|
||||
"my_effect": "/my/effect";
|
||||
"my_highrisk": "/my/highrisk";
|
||||
@@ -134,7 +133,6 @@ declare module "@elegant-router/types" {
|
||||
| "factoryoverview"
|
||||
| "home"
|
||||
| "login"
|
||||
| "my_closeconfirm"
|
||||
| "my_datachangecenter"
|
||||
| "my_effect"
|
||||
| "my_highrisk"
|
||||
|
||||
@@ -324,7 +324,7 @@ onMounted(() => {
|
||||
|
||||
<template>
|
||||
<NSpace vertical :size="16">
|
||||
<!-- 本专业高风险 -->
|
||||
<!-- 高风险 -->
|
||||
<NSpin :show="loading" size="small">
|
||||
<NCard :bordered="false" size="small" :style="{ borderRadius: themeStore.themeRadius + 'px' }">
|
||||
<div
|
||||
|
||||
@@ -335,11 +335,11 @@ onUnmounted(() => {
|
||||
</NGi>
|
||||
<!-- 右侧 -->
|
||||
<NGi span="24 s:24 m:24 l:8">
|
||||
<!-- 本专业高风险变更 -->
|
||||
<!-- 高风险变更 -->
|
||||
<NCard :bordered="false" size="small" :style="{ borderRadius: themeStore.themeRadius + 'px' }">
|
||||
<div class="flex items-center mb-3 gap-2">
|
||||
<Icon icon="lucide:shield-alert" class="size-16px" :style="{ color: themeStore.themeColor }" />
|
||||
<p class="text-13px font-700 text-#64749a">本专业高风险变更</p>
|
||||
<p class="text-13px font-700 text-#64749a">高风险变更</p>
|
||||
<p class="text-11px text-#94a3b8">在办 · 建议重点关注</p>
|
||||
</div>
|
||||
<template v-if="homeData?.high_risk?.total > 0">
|
||||
|
||||
@@ -1,213 +0,0 @@
|
||||
<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>
|
||||
@@ -1,4 +1,4 @@
|
||||
<!-- 本专业高风险 -->
|
||||
<!-- 高风险 -->
|
||||
<script setup lang="ts">
|
||||
import { useThemeStore } from '@/store/modules/theme';
|
||||
import Risk from './modules/risk.vue';
|
||||
|
||||
@@ -167,7 +167,7 @@ const profHighRisk = [
|
||||
</NGi>
|
||||
<NGi span="24 s:24 m:24 l:8">
|
||||
<NCard :bordered="true" size="small" :content-style="{padding: 0}" :style="{ borderRadius: themeStore.themeRadius + 'px', height: '100%' }">
|
||||
<p class=" text-base font-semibold border-b border-slate-100 p-3">本专业高风险在办(直达风险分析)</p>
|
||||
<p class=" text-base font-semibold border-b border-slate-100 p-3">高风险在办(直达风险分析)</p>
|
||||
<div class="py-3 px-4">
|
||||
<div class="space-y-2 pt-1">
|
||||
<div v-for="c in profHighRisk" :key="c.id" @click="emit('go', 'risk')" class="cursor-pointer flex w-full items-center gap-2 rounded-lg border px-3 py-2 text-left hover:border-red-300 hover:bg-red-50/30">
|
||||
@@ -177,7 +177,7 @@ const profHighRisk = [
|
||||
</span>
|
||||
<ChevronRight class="h-3.5 w-3.5 shrink-0 text-slate-300" />
|
||||
</div>
|
||||
<p class="text-[11px] text-slate-400">更多高风险场景与分析记录见「本专业高风险」页</p>
|
||||
<p class="text-[11px] text-slate-400">更多高风险场景与分析记录见「高风险」页</p>
|
||||
</div>
|
||||
</div>
|
||||
</NCard>
|
||||
|
||||
@@ -1,83 +1,61 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue';
|
||||
import { useAppStore } from '@/store/modules/app';
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { Icon } from '@iconify/vue'
|
||||
import { useThemeStore } from '@/store/modules/theme';
|
||||
import { TEMP_WATCH } from "@/typings/model";
|
||||
import { useRouterPush } from '@/hooks/common/router';
|
||||
import RingChart from './modules/ringChart.vue';
|
||||
import ColumnChart from './modules/columnChart.vue';
|
||||
import { safeRiskStatisticsApi } from '@/service/api/statistics';
|
||||
import { urgeApi } from '@/service/api/change';
|
||||
|
||||
const appStore = useAppStore();
|
||||
const themeStore = useThemeStore();
|
||||
const gap = computed(() => (appStore.isMobile ? 0 : 16));
|
||||
const { routerPushByKey } = useRouterPush();
|
||||
|
||||
const addRisk = ref([
|
||||
{
|
||||
name: '2月',
|
||||
highRisk: 28,
|
||||
middleRisk: 27,
|
||||
},
|
||||
{
|
||||
name: '3月',
|
||||
highRisk: 28,
|
||||
middleRisk: 27,
|
||||
},
|
||||
{
|
||||
name: '4月',
|
||||
highRisk: 28,
|
||||
middleRisk: 27,
|
||||
},
|
||||
{
|
||||
name: '5月',
|
||||
highRisk: 28,
|
||||
middleRisk: 27,
|
||||
},
|
||||
{
|
||||
name: '6月',
|
||||
highRisk: 28,
|
||||
middleRisk: 27,
|
||||
},
|
||||
{
|
||||
name: '7月',
|
||||
highRisk: 28,
|
||||
middleRisk: 27,
|
||||
},
|
||||
]);
|
||||
const RISK_COLORS = ["#f5222d", "#faad14"];
|
||||
|
||||
const DEPT_ACCEPT = [
|
||||
{ name: "高风险项", value: 1 },
|
||||
{ name: "中风险项", value: 6 },
|
||||
{ name: "低风险项", value: 12 },
|
||||
];
|
||||
const ACCEPT_COLORS = ["#f5222d", "#faad14", "#b2bcca"];
|
||||
const PSSR_EXEC = [
|
||||
{ pct: 94, label: "投用前完成率", detail: "29/31 变更 · 投用时培训 / PSSR 资料已齐", status: "finish" },
|
||||
{ pct: 88, label: "行动项按期关闭率", detail: "15/17 项 · 2 项跟进中(风险分析建议措施转入)", status: "close" },
|
||||
{ pct: 100, label: "投用后补传率", detail: "0 起 · 投用前未完成而先行投用", status: "fix" },
|
||||
];
|
||||
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 },
|
||||
];
|
||||
const loading = ref<boolean>(false);
|
||||
const btnLoading = ref<boolean>(false);
|
||||
const homeData = ref<any>(null);
|
||||
const SAFETY_EXPORTS = ["高风险变更清单", "新增固有风险项月度表", "剩余风险与措施落实表", "PSSR 执行统计", "超期未关闭清单", "验收一次通过率分析"];
|
||||
// 催办
|
||||
const handleReminder = (id: string) => {
|
||||
window.$message?.success(`已催办 ${id} 当前节点负责人(系统消息 + 企业微信)`)
|
||||
const handleReminder = async (id: number) => {
|
||||
btnLoading.value = true;
|
||||
const {error} = await urgeApi(id);
|
||||
if(!error){
|
||||
window.$message?.success('催办成功')
|
||||
}
|
||||
btnLoading.value = false;
|
||||
}
|
||||
// 导出报表
|
||||
const handleExport = (name: string) => {
|
||||
window.$message?.success(`${name}已导出 Excel`)
|
||||
window.$message?.info('还差接口')
|
||||
}
|
||||
|
||||
// 跳转页面
|
||||
const jumpTo = (key:string) => {
|
||||
routerPushByKey(key as any);
|
||||
}
|
||||
|
||||
// 获取数据
|
||||
const getData = async () => {
|
||||
loading.value = true;
|
||||
const {data,error} = await safeRiskStatisticsApi({
|
||||
from: null,
|
||||
to: null
|
||||
})
|
||||
if(!error){
|
||||
homeData.value = data;
|
||||
}
|
||||
loading.value = false;
|
||||
}
|
||||
onMounted(() => {
|
||||
getData();
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NSpace vertical :size="16">
|
||||
<!-- 卡片数据 -->
|
||||
<NGrid
|
||||
cols="s:1 m:4 l:4" responsive="screen" :x-gap="gap" :y-gap="16"
|
||||
cols="s:1 m:4 l:4" responsive="screen" :x-gap="16" :y-gap="16"
|
||||
:style="{
|
||||
'--error-color':themeStore.otherColor.error,
|
||||
'--warning-color':themeStore.otherColor.warning
|
||||
@@ -85,13 +63,14 @@ const handleExport = (name: string) => {
|
||||
>
|
||||
<NGi>
|
||||
<div
|
||||
class="flex-1 flex items-center gap-3 bg-white px-16px py-12px text-[#94a3b8]"
|
||||
class="flex-1 flex items-center gap-3 bg-white px-16px py-12px text-[#94a3b8] cursor-pointer"
|
||||
:style="{ borderRadius: themeStore.themeRadius + 'px' }"
|
||||
@click="jumpTo('my_highrisk')"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<CountTo
|
||||
:start-value="0"
|
||||
:end-value="4"
|
||||
:end-value="homeData?.kpis?.high_risk_in_progress || 0"
|
||||
class="text-28px font-600 text-[var(--error-color)]"
|
||||
/><p class="mt-10px ml-5px">起</p>
|
||||
</div>
|
||||
@@ -109,7 +88,7 @@ const handleExport = (name: string) => {
|
||||
<div class="flex items-center">
|
||||
<CountTo
|
||||
:start-value="0"
|
||||
:end-value="1"
|
||||
:end-value="homeData?.kpis?.residual_high || 0"
|
||||
class="text-28px font-600 text-[var(--error-color)]"
|
||||
/><p class="mt-10px ml-5px">项</p>
|
||||
</div>
|
||||
@@ -127,7 +106,7 @@ const handleExport = (name: string) => {
|
||||
<div class="flex items-center">
|
||||
<CountTo
|
||||
:start-value="0"
|
||||
:end-value="6"
|
||||
:end-value="homeData?.kpis?.residual_mid || 0"
|
||||
class="text-28px font-600 text-[var(--warning-color)]"
|
||||
/><p class="mt-10px ml-5px">项</p>
|
||||
</div>
|
||||
@@ -139,26 +118,26 @@ const handleExport = (name: string) => {
|
||||
</NGi>
|
||||
<NGi>
|
||||
<div
|
||||
class="flex-1 flex items-center gap-3 bg-white px-16px py-12px text-[#94a3b8]"
|
||||
class="flex-1 flex items-center gap-3 bg-white px-16px py-12px text-[#94a3b8] cursor-pointer"
|
||||
:style="{ borderRadius: themeStore.themeRadius + 'px' }"
|
||||
@click="jumpTo('changeledger')"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<CountTo
|
||||
:start-value="0"
|
||||
:end-value="3"
|
||||
:end-value="homeData?.kpis?.overdue_unclosed || 0"
|
||||
class="text-28px font-600 text-[var(--error-color)]"
|
||||
/><p class="mt-10px ml-5px">起</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-xs font-semibold text-slate-600">超期未关闭</p>
|
||||
<p class="text-[11px] text-slate-400">含临时变更到期 1 起</p>
|
||||
</div>
|
||||
</div>
|
||||
</NGi>
|
||||
</NGrid>
|
||||
|
||||
<NGrid
|
||||
:x-gap="gap" :y-gap="16" responsive="screen" item-responsive
|
||||
:x-gap="16" :y-gap="16" responsive="screen" item-responsive
|
||||
:style="{
|
||||
'--error-color':themeStore.otherColor.error,
|
||||
'--warning-color':themeStore.otherColor.warning,
|
||||
@@ -169,14 +148,14 @@ const handleExport = (name: string) => {
|
||||
<NGi span="24 s:24 m:24 l:8">
|
||||
<NCard :bordered="true" size="small" :content-style="{ padding: '0' }" :style="{ borderRadius: themeStore.themeRadius + 'px', height: '100%' }">
|
||||
<p class=" text-base font-semibold border-b border-slate-100 p-3">月度新增固有风险项(管控前)</p>
|
||||
<ColumnChart :data="addRisk" :colors="RISK_COLORS" style="height: 100%;" />
|
||||
<ColumnChart v-if="homeData" :data="homeData?.monthly_inherent || []" />
|
||||
</NCard>
|
||||
</NGi>
|
||||
<NGi span="24 s:24 m:24 l:8">
|
||||
<NCard :bordered="true" size="small" :content-style="{ padding: '0' }" :style="{ borderRadius: themeStore.themeRadius + 'px', height: '100%' }">
|
||||
<p class=" text-base font-semibold border-b border-slate-100 p-3">验收达标 · 变更类型 · 变更时限分布</p>
|
||||
<RingChart :data="DEPT_ACCEPT" :colors="ACCEPT_COLORS" />
|
||||
<div class="px-3 pt-2 pb-3">
|
||||
<RingChart v-if="homeData" :data="homeData?.residual_dist || null" />
|
||||
<!-- <div class="px-3 pt-2 pb-3">
|
||||
<div class="border-t pt-2.5">
|
||||
<div class="flex items-baseline justify-between">
|
||||
<span class="text-xs text-slate-500">管控措施落实率</span>
|
||||
@@ -187,49 +166,49 @@ const handleExport = (name: string) => {
|
||||
</div>
|
||||
<div class="mt-1 text-[11px] text-slate-400">剩余高风险项 1 项:措施已落实 · 复核中(聚合反应温度上限调整 · 联锁传动试验)</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
</NCard>
|
||||
</NGi>
|
||||
<NGi span="24 s:24 m:24 l:8">
|
||||
<NCard :bordered="true" size="small" :content-style="{ padding: '0' }" :style="{ borderRadius: themeStore.themeRadius + 'px', height: '100%' }">
|
||||
<p class=" text-base font-semibold border-b border-slate-100 p-3">PSSR 执行情况</p>
|
||||
<div class="space-y-5 px-3 pt-5 pb-3">
|
||||
<div v-for="r in PSSR_EXEC" :key="r.label">
|
||||
<!-- 投用前完成率 -->
|
||||
<div>
|
||||
<div class="flex items-baseline gap-2">
|
||||
<span class="text-2xl font-bold text-[#1D2129]">{{ r.pct }}<span class="text-sm font-semibold">%</span></span>
|
||||
<span class="text-xs font-semibold text-slate-500">{{ r.label }}</span>
|
||||
<span class="text-2xl font-bold text-[#1D2129]">{{ homeData?.pssr?.pre_use_rate || 0 }}<span class="text-sm font-semibold">%</span></span>
|
||||
<span class="text-xs font-semibold text-slate-500">投用前完成率</span>
|
||||
</div>
|
||||
<div class="mt-1.5 h-1 w-full overflow-hidden rounded-full bg-slate-100">
|
||||
<div v-if="r.status==='finish'" class="h-full rounded-full bg-[var(--theme-color)]" :style="{ width: `${r.pct}%`}"></div>
|
||||
<div v-if="r.status==='close'" class="h-full rounded-full bg-[var(--success-color)]" :style="{ width: `${r.pct}%`}"></div>
|
||||
<div v-if="r.status==='fix'" class="h-full rounded-full bg-[#b2bcca]" :style="{ width: `${r.pct}%`}"></div>
|
||||
<div class="h-full rounded-full bg-[var(--theme-color)]" :style="{ width: `${homeData?.pssr?.pre_use_rate || 0}%` }"></div>
|
||||
</div>
|
||||
<div class="mt-1 text-[11px] text-slate-400">{{ r.detail }}</div>
|
||||
<div class="mt-1 text-[11px] text-slate-400">{{ homeData?.pssr?.pre_use_done || 0 }}/{{ homeData?.pssr?.pre_use_total || 0 }}变更 · 投用时培训 / PSSR 资料已齐</div>
|
||||
</div>
|
||||
<!-- 行动项按期关闭率 -->
|
||||
<div>
|
||||
<div class="flex items-baseline gap-2">
|
||||
<span class="text-2xl font-bold text-[#1D2129]">{{ homeData?.pssr?.action_rate || 0 }}<span class="text-sm font-semibold">%</span></span>
|
||||
<span class="text-xs font-semibold text-slate-500">行动项按期关闭率</span>
|
||||
</div>
|
||||
<div class="mt-1.5 h-1 w-full overflow-hidden rounded-full bg-slate-100">
|
||||
<div class="h-full rounded-full bg-[var(--success-color)]" :style="{ width: `${homeData?.pssr?.action_rate || 0}%`}"></div>
|
||||
</div>
|
||||
<div class="mt-1 text-[11px] text-slate-400">{{ homeData?.pssr?.action_confirmed || 0 }}/{{ homeData?.pssr?.action_total || 0 }}项</div>
|
||||
</div>
|
||||
</div>
|
||||
</NCard>
|
||||
</NGi>
|
||||
</NGrid>
|
||||
<NGrid :x-gap="gap" :y-gap="16" responsive="screen" item-responsive :style="{'--theme-color':themeStore.themeColor}">
|
||||
<NGrid :x-gap="16" :y-gap="16" responsive="screen" item-responsive :style="{'--theme-color':themeStore.themeColor}">
|
||||
<NGi span="24 s:24 m:24 l:8">
|
||||
<NCard :bordered="true" size="small" :content-style="{ padding: '0' }" :style="{ borderRadius: themeStore.themeRadius + 'px', height: '100%' }">
|
||||
<p class=" text-base font-semibold border-b border-slate-100 p-3">验收与投用质量</p>
|
||||
<div class="flex pt-5 pb-3">
|
||||
<div class="flex justify-center pt-5 pb-3">
|
||||
<div class="w-50% flex flex-col items-center gap-1.5">
|
||||
<NProgress type="circle" :percentage="88" :color="themeStore.otherColor.warning" :offset-degree="180">
|
||||
<NProgress type="circle" :percentage="homeData?.accept?.on_time_rate || 0" :offset-degree="180">
|
||||
<div class="flex flex-col items-center">
|
||||
<p class="text-2xl font-bold leading-none text-[#1D2129]">88<span class="text-sm font-semibold">%</span></p>
|
||||
<p class="mt-1 text-[11px] text-slate-400">Fair</p>
|
||||
</div>
|
||||
</NProgress>
|
||||
<span class="text-xs font-semibold text-slate-600">验收一次通过率</span>
|
||||
<span class="text-[11px] text-slate-400">近一年 · 全厂</span>
|
||||
</div>
|
||||
<div class="w-50% flex flex-col items-center gap-1.5">
|
||||
<NProgress type="circle" :percentage="85" :offset-degree="180">
|
||||
<div class="flex flex-col items-center">
|
||||
<p class="text-2xl font-bold leading-none text-[#1D2129]">85<span class="text-sm font-semibold">%</span></p>
|
||||
<p class="mt-1 text-[11px] text-slate-400">Good</p>
|
||||
<p class="text-2xl font-bold leading-none text-[#1D2129]">{{homeData?.accept?.on_time_rate || 0}}<span class="text-sm font-semibold">%</span></p>
|
||||
<!-- <p class="mt-1 text-[11px] text-slate-400">Good</p> -->
|
||||
</div>
|
||||
</NProgress>
|
||||
<span class="text-xs font-semibold text-slate-600">按期投用率</span>
|
||||
@@ -242,13 +221,23 @@ const handleExport = (name: string) => {
|
||||
<NCard :bordered="true" size="small" :content-style="{ padding: '0' }" :style="{ borderRadius: themeStore.themeRadius + 'px', height: '100%' }">
|
||||
<p class=" text-base font-semibold border-b border-slate-100 p-3">超期未关闭清单</p>
|
||||
<div class="space-y-2 p-3">
|
||||
<div v-for="o in OVERDUE_LIST" :key="o.id" class="flex items-center gap-2 rounded-lg border border-red-200 bg-red-50/40 px-3 py-2">
|
||||
<div v-for="o in homeData?.overdue_list || []" :key="o.change_id" class="flex items-center gap-2 rounded-lg border border-red-200 bg-red-50/40 px-3 py-2">
|
||||
<span class="min-w-0 flex-1">
|
||||
<span class="block truncate text-xs font-medium text-slate-800">{{ o.title }}</span>
|
||||
<span class="text-[11px] text-slate-400">{{ o.id }} · 卡在 {{ o.stage }}</span>
|
||||
<div class="text-[11px] text-slate-400">
|
||||
{{ o.change_no }} · 卡在
|
||||
<!-- 状态标签 -->
|
||||
<span v-if="o.status==='APPROVING'">审批中</span>
|
||||
<span v-if="o.status==='APPROVED'">已通过</span>
|
||||
<span v-if="o.status==='IMPLEMENTED'">待验收</span>
|
||||
<span v-if="o.status==='ACCEPTED'">待关闭</span>
|
||||
<span v-if="o.status==='CLOSED'">已关闭</span>
|
||||
<span v-if="o.status==='WITHDRAWN'">已撤回</span>
|
||||
<span v-if="o.status==='REJECTED'">已驳回</span>
|
||||
</div>
|
||||
</span>
|
||||
<NTag size="small" type="error">超期 {{ o.days }} 天</NTag>
|
||||
<NButton size="small" ghost class="text-xs" @click="handleReminder(o.id)">催办</NButton>
|
||||
<NTag size="small" type="error">超期 {{ o.overdue_days }} 天</NTag>
|
||||
<NButton size="small" ghost class="text-xs" :disabled="btnLoading" @click="handleReminder(o.change_id)">催办</NButton>
|
||||
</div>
|
||||
</div>
|
||||
</NCard>
|
||||
|
||||
@@ -3,10 +3,11 @@ import { ref } from 'vue';
|
||||
import { useEcharts } from '@/hooks/common/echarts';
|
||||
|
||||
defineOptions({
|
||||
name: 'RingChart'
|
||||
name: 'ColumnChart'
|
||||
});
|
||||
|
||||
const props = defineProps<{ data: { name: string; highRisk: number; middleRisk: number }[]; colors: string[] }>();
|
||||
const props = defineProps<{ data: any[]; }>();
|
||||
const COLORS = ['#f5222d', '#faad14'];
|
||||
|
||||
const { domRef, updateOptions } = useEcharts(() => ({
|
||||
tooltip: {
|
||||
@@ -19,7 +20,7 @@ const { domRef, updateOptions } = useEcharts(() => ({
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
bottom: '20%',
|
||||
bottom: 10,
|
||||
left: 'center',
|
||||
icon: 'circle',
|
||||
itemWidth: 10,
|
||||
@@ -29,10 +30,10 @@ const { domRef, updateOptions } = useEcharts(() => ({
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
top: "10%",
|
||||
top: "3%",
|
||||
left: "5%",
|
||||
right: "5%",
|
||||
bottom: "35%",
|
||||
bottom: "40%",
|
||||
},
|
||||
calculable: true,
|
||||
xAxis: [
|
||||
@@ -44,6 +45,7 @@ const { domRef, updateOptions } = useEcharts(() => ({
|
||||
},
|
||||
axisLabel: {
|
||||
interval: 0,
|
||||
rotate: 50,
|
||||
},
|
||||
splitLine: { show: false },
|
||||
axisTick: { show: false },
|
||||
@@ -62,9 +64,9 @@ const { domRef, updateOptions } = useEcharts(() => ({
|
||||
name: "高风险项",
|
||||
stack: "总数",
|
||||
type: "bar",
|
||||
barWidth: 30,
|
||||
barWidth: 20,
|
||||
barGap: "10%",
|
||||
color: "#00B42A",
|
||||
color: COLORS[0],
|
||||
data: [] as number[],
|
||||
},
|
||||
// 中风险项 - 橙色
|
||||
@@ -72,23 +74,33 @@ const { domRef, updateOptions } = useEcharts(() => ({
|
||||
name: "中风险项",
|
||||
stack: "总数",
|
||||
type: "bar",
|
||||
barWidth: 30,
|
||||
color: "#FF7D00",
|
||||
barWidth: 20,
|
||||
color: COLORS[1],
|
||||
data: [] as number[],
|
||||
},
|
||||
]
|
||||
],
|
||||
// dataZoom: [{ // 使用dataZoom组件
|
||||
// show: months.value.length<=5?false:true,
|
||||
// type: 'slider', // 内置型数据区域缩放组件
|
||||
// start: 0, // 数据窗口范围的起始百分比
|
||||
// end: months.value.length<=4?100:(4/months.value.length)*100, // 数据窗口范围的结束百分比
|
||||
// zoomLock: true,
|
||||
// handleSize: 0,// 两边的按钮大小
|
||||
// moveHandleSize: 10,
|
||||
// height: 10,
|
||||
// brushSelect: false,
|
||||
// top: '93%'
|
||||
// }]
|
||||
}));
|
||||
|
||||
function init() {
|
||||
updateOptions(opts => {
|
||||
let allMonth = props.data.map((item:any) => item.name);
|
||||
let highRis = props.data.map((item:any) => item.highRisk);
|
||||
let middleRisk = props.data.map((item:any) => item.middleRisk);
|
||||
let allMonth = props.data.map((item:any) => item.month);
|
||||
let highRis = props.data.map((item:any) => item.high);
|
||||
let middleRisk = props.data.map((item:any) => item.mid);
|
||||
opts.xAxis[0].data = allMonth;
|
||||
opts.series[0].data = highRis;
|
||||
opts.series[1].data = middleRisk;
|
||||
opts.series[0].color = props.colors[0];
|
||||
opts.series[1].color = props.colors[1];
|
||||
return opts;
|
||||
});
|
||||
}
|
||||
@@ -97,7 +109,7 @@ init();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="domRef" class="w-full h-220px overflow-hidden"></div>
|
||||
<div ref="domRef" class="w-full h-200px overflow-hidden"></div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
|
||||
@@ -6,7 +6,8 @@ defineOptions({
|
||||
name: 'RingChart'
|
||||
});
|
||||
|
||||
const props = defineProps<{ data?: { name: string; value: number }[]; colors?: string[] }>();
|
||||
const props = defineProps<{ data: any; }>();
|
||||
const chartData = ref<any[]>([]);
|
||||
|
||||
const { domRef, updateOptions } = useEcharts(() => ({
|
||||
tooltip: {
|
||||
@@ -14,7 +15,7 @@ const { domRef, updateOptions } = useEcharts(() => ({
|
||||
formatter: '{b}: {c} ({d}%)'
|
||||
},
|
||||
legend: {
|
||||
bottom: 0,
|
||||
bottom: 10,
|
||||
left: 'center',
|
||||
icon: 'circle',
|
||||
itemWidth: 10,
|
||||
@@ -22,9 +23,27 @@ const { domRef, updateOptions } = useEcharts(() => ({
|
||||
itemStyle: {
|
||||
borderWidth: 0
|
||||
},
|
||||
textStyle: {
|
||||
rich: {
|
||||
name: {
|
||||
padding: [0, 0, 0, 0],
|
||||
},
|
||||
count: {
|
||||
padding: [0, 0, 0, 0],
|
||||
},
|
||||
}
|
||||
},
|
||||
formatter: function (name: string) {
|
||||
var info = chartData.value?.find((item: { name: string }) => item.name === name);
|
||||
if(info){
|
||||
return '{name|'+name+'} {count|'+(info.value)+'}';
|
||||
}else{
|
||||
return name;
|
||||
}
|
||||
}
|
||||
},
|
||||
title: {
|
||||
text: `{a|19}\n{b|剩余风险项}`,
|
||||
text: '',
|
||||
textStyle: {
|
||||
rich: {
|
||||
a: {
|
||||
@@ -50,7 +69,7 @@ const { domRef, updateOptions } = useEcharts(() => ({
|
||||
series: [
|
||||
{
|
||||
type: 'pie',
|
||||
color: ['#5da8ff', '#8e9dff', '#fedc69', '#26deca'],
|
||||
color: ["#f5222d", "#faad14", "#b2bcca"],
|
||||
radius: ['45%', '65%'],
|
||||
center: ['50%', '45%'],
|
||||
avoidLabelOverlap: false,
|
||||
@@ -71,9 +90,19 @@ const { domRef, updateOptions } = useEcharts(() => ({
|
||||
}));
|
||||
|
||||
function init() {
|
||||
if (!props.data) {
|
||||
return;
|
||||
}
|
||||
updateOptions(opts => {
|
||||
opts.series[0].data = props.data || [];
|
||||
opts.series[0].color = props.colors || [];
|
||||
const total = props.data.high + props.data.mid + props.data.low;
|
||||
const data = [
|
||||
{name:'高风险项',value:props.data.high},
|
||||
{name:'中风险项',value:props.data.mid},
|
||||
{name:'低风险项',value:props.data.low},
|
||||
]
|
||||
chartData.value = data;
|
||||
opts.series[0].data = data;
|
||||
opts.title.text = `{a|${total}}\n{b|剩余风险项}`;
|
||||
return opts;
|
||||
});
|
||||
}
|
||||
@@ -82,7 +111,7 @@ init();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="domRef" class="w-full h-220px overflow-hidden"></div>
|
||||
<div ref="domRef" class="w-full h-200px overflow-hidden"></div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
|
||||
@@ -167,7 +167,7 @@ const profHighRisk = [
|
||||
</NGi>
|
||||
<NGi span="24 s:24 m:24 l:8">
|
||||
<NCard :bordered="true" size="small" :content-style="{padding: 0}" :style="{ borderRadius: themeStore.themeRadius + 'px', height: '100%' }">
|
||||
<p class=" text-base font-semibold border-b border-slate-100 p-3">本专业高风险在办(直达风险分析)</p>
|
||||
<p class=" text-base font-semibold border-b border-slate-100 p-3">高风险在办(直达风险分析)</p>
|
||||
<div class="py-3 px-4">
|
||||
<div class="space-y-2 pt-1">
|
||||
<div v-for="c in profHighRisk" :key="c.id" @click="emit('go', 'risk')" class="cursor-pointer flex w-full items-center gap-2 rounded-lg border px-3 py-2 text-left hover:border-red-300 hover:bg-red-50/30">
|
||||
@@ -177,7 +177,7 @@ const profHighRisk = [
|
||||
</span>
|
||||
<ChevronRight class="h-3.5 w-3.5 shrink-0 text-slate-300" />
|
||||
</div>
|
||||
<p class="text-[11px] text-slate-400">更多高风险场景与分析记录见「本专业高风险」页</p>
|
||||
<p class="text-[11px] text-slate-400">更多高风险场景与分析记录见「高风险」页</p>
|
||||
</div>
|
||||
</div>
|
||||
</NCard>
|
||||
|
||||
Reference in New Issue
Block a user