本专业变更统计-数据统计字段修改
This commit is contained in:
@@ -53,7 +53,6 @@ const getData = async () => {
|
||||
loading.value = true;
|
||||
const {data,error} = await homeNonApproverApi();
|
||||
if(!error){
|
||||
console.log(data)
|
||||
homeData.value = data;
|
||||
}
|
||||
loading.value = false;
|
||||
|
||||
@@ -10,12 +10,6 @@ import { specialtyStatisticsApi } from '@/service/api/statistics';
|
||||
const themeStore = useThemeStore();
|
||||
const { routerPushByKey } = useRouterPush();
|
||||
|
||||
const profHighRisk = [
|
||||
{ id: "MOC-2026-R01-0035", status: '审批中', title: 'R-201 反应釜搅拌器电机更换(55kW→75kW 防爆电机)' },
|
||||
{ id: "MOC-2026-R01-0036", status: '审批中', title: '聚合反应温度控制上限调整(78℃→82℃)' },
|
||||
{ id: "MOC-2026-R01-0037", status: '实施中', title: '原料环己烷供应商变更(新增 B 供应商)' },
|
||||
];
|
||||
|
||||
const loading = ref<boolean>(false);
|
||||
const homeData = ref<any>(null);
|
||||
|
||||
@@ -23,6 +17,10 @@ const homeData = ref<any>(null);
|
||||
const jumpTo = (key: string) => {
|
||||
routerPushByKey(key as any);
|
||||
}
|
||||
// 小时转换天
|
||||
const hourToDay = (hour: number) => {
|
||||
return Math.trunc((hour / 24) * 100) / 100;
|
||||
}
|
||||
|
||||
// 获取数据
|
||||
const getData = async () => {
|
||||
@@ -33,7 +31,6 @@ const getData = async () => {
|
||||
});
|
||||
if(!error){
|
||||
homeData.value = data;
|
||||
console.log(data);
|
||||
}
|
||||
loading.value = false;
|
||||
}
|
||||
@@ -44,7 +41,8 @@ onMounted(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NSpace vertical :size="16">
|
||||
<NSpin :show="loading" size="small">
|
||||
<NSpace vertical :size="16">
|
||||
<!-- 卡片数据 -->
|
||||
<NGrid cols="s:1 m:5 l:5" responsive="screen" :x-gap="16" :y-gap="16"
|
||||
:style="{
|
||||
@@ -62,7 +60,7 @@ onMounted(() => {
|
||||
<div class="flex items-center">
|
||||
<CountTo
|
||||
:start-value="0"
|
||||
:end-value="6"
|
||||
:end-value="homeData?.my_stats?.month_signed || 0"
|
||||
class="text-24px font-600 text-[#333]"
|
||||
/>
|
||||
</div>
|
||||
@@ -78,12 +76,12 @@ onMounted(() => {
|
||||
<div class="flex items-center">
|
||||
<CountTo
|
||||
:start-value="0"
|
||||
:end-value="1.8"
|
||||
:end-value="homeData?.my_stats?.avg_audit_days || 0"
|
||||
:decimals="1"
|
||||
class="text-26px font-600 text-[var(--success-color)]"
|
||||
/><p class="text-26px font-600 text-[var(--success-color)]">天</p>
|
||||
</div>
|
||||
<p class="text-12px">口径:签收→签出时长 · 目标 ≤2.5 天</p>
|
||||
<p class="text-12px">口径:签收→签出时长 · 目标 ≤{{hourToDay(homeData?.my_stats?.sign_timely_hours || 0)}} 天</p>
|
||||
</div>
|
||||
</NGi>
|
||||
<NGi>
|
||||
@@ -95,7 +93,7 @@ onMounted(() => {
|
||||
<div class="flex items-center">
|
||||
<CountTo
|
||||
:start-value="0"
|
||||
:end-value="95"
|
||||
:end-value="homeData?.my_stats?.timely_rate || 0"
|
||||
class="text-26px font-600 text-[var(--success-color)]"
|
||||
/><p class="text-26px font-600 text-[var(--success-color)]">%</p>
|
||||
</div>
|
||||
@@ -111,7 +109,7 @@ onMounted(() => {
|
||||
<div class="flex items-center">
|
||||
<CountTo
|
||||
:start-value="0"
|
||||
:end-value="2"
|
||||
:end-value="homeData?.my_stats?.risk_analysis_count || 0"
|
||||
class="text-26px font-600 text-[var(--theme-color)]"
|
||||
/><p class="text-26px font-600 text-[var(--theme-color)]">次</p>
|
||||
</div>
|
||||
@@ -127,7 +125,7 @@ onMounted(() => {
|
||||
<div class="flex items-center">
|
||||
<CountTo
|
||||
:start-value="0"
|
||||
:end-value="1"
|
||||
:end-value="homeData?.my_stats?.todo_total || 0"
|
||||
class="text-26px font-600 text-[var(--warning-color)]"
|
||||
/>
|
||||
</div>
|
||||
@@ -160,17 +158,17 @@ onMounted(() => {
|
||||
<span :class="e.avg_days > 2.5 ? 'font-medium text-[var(--error-color)]' : 'text-slate-500'">{{ e.avg_days }} 天</span>
|
||||
</div>
|
||||
<div class="h-2 overflow-hidden rounded-full bg-slate-100">
|
||||
<div class="h-full rounded-full" :class="e.avg_days > 2.5 ? 'bg-[var(--error-color)]' : 'bg-[var(--theme-color)]'" :style="{ width: `${Math.min(100, (e.avg_days / e.total) * 100)}%` }"></div>
|
||||
<div class="h-full rounded-full" :class="e.avg_days > hourToDay(homeData?.my_stats?.sign_timely_hours || 0) ? 'bg-[var(--error-color)]' : 'bg-[var(--theme-color)]'" :style="{ width: `${Math.min(100, (e.avg_days / e.total) * 100)}%` }"></div>
|
||||
</div>
|
||||
</div>
|
||||
<p v-if="homeData?.approver_time?.length===0" class="text-xs text-slate-400 text-center py-3">暂无数据</p>
|
||||
<div>
|
||||
<div class="mb-1 flex items-center justify-between text-xs">
|
||||
<span class="text-slate-600">考核目标</span>
|
||||
<span class="text-slate-500">2.5 天(标线)</span>
|
||||
<span class="text-slate-500">{{hourToDay(homeData?.my_stats?.sign_timely_hours || 0)}} 天(标线)</span>
|
||||
</div>
|
||||
<div class="h-2 overflow-hidden rounded-full bg-slate-100">
|
||||
<div class="h-full rounded-full bg-slate-300" :style="{ width: `${Math.min(100, (2.5 / 2.5) * 100)}%` }"></div>
|
||||
<div class="h-full rounded-full bg-slate-300" :style="{ width: `${Math.min(100, (hourToDay(homeData?.my_stats?.sign_timely_hours || 0) / hourToDay(homeData?.my_stats?.sign_timely_hours || 0)) * 100)}%` }"></div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-[11px] text-slate-400">考核数据来源:节点签收 → 签出时长自动统计;连续两月超标将纳入绩效面谈</p>
|
||||
@@ -190,11 +188,21 @@ onMounted(() => {
|
||||
<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="py-3 px-4">
|
||||
<div v-if="profHighRisk.length" class="space-y-2 pt-1">
|
||||
<div v-for="c in profHighRisk" :key="c.id" @click="jumpTo('my_highrisk')" 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">
|
||||
<div v-if="homeData?.high_risk?.total > 0" class="space-y-2 pt-1">
|
||||
<div v-for="c in homeData?.high_risk?.items || []" :key="c.id" @click="jumpTo('my_highrisk')" 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">
|
||||
<span class="min-w-0 flex-1">
|
||||
<span class="block truncate text-sm font-medium text-slate-800">{{ c.title }}</span>
|
||||
<span class="text-[11px] text-slate-400">{{ c.id }} · {{ c.status }}</span>
|
||||
<span class="block truncate text-sm font-medium text-slate-800">{{ c.change_title }}</span>
|
||||
<div class="flex items-center gap-2 text-[11px] text-slate-400 mt-1">
|
||||
<span>{{ c.change_no }}</span>
|
||||
<!-- 状态标签 -->
|
||||
<span v-if="c.change_status==='APPROVING'">审批中</span>
|
||||
<span v-if="c.change_status==='APPROVED'">已通过</span>
|
||||
<span v-if="c.change_status==='IMPLEMENTED'">待验收</span>
|
||||
<span v-if="c.change_status==='ACCEPTED'">待关闭</span>
|
||||
<span v-if="c.change_status==='CLOSED'">已关闭</span>
|
||||
<span v-if="c.change_status==='WITHDRAWN'">已撤回</span>
|
||||
<span v-if="c.change_status==='REJECTED'">已驳回</span>
|
||||
</div>
|
||||
</span>
|
||||
<Icon icon="formkit:right" class="size-14px text-slate-300" />
|
||||
</div>
|
||||
@@ -205,7 +213,8 @@ onMounted(() => {
|
||||
</NCard>
|
||||
</NGi>
|
||||
</NGrid>
|
||||
</NSpace>
|
||||
</NSpace>
|
||||
</NSpin>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
|
||||
@@ -1,132 +1,77 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue';
|
||||
import { Icon } from '@iconify/vue'
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { useThemeStore } from '@/store/modules/theme';
|
||||
import { getColorWithOpacity } from '@/utils/common';
|
||||
import RingChart from './modules/ringChart.vue';
|
||||
import ColumnChart from './modules/columnChart.vue';
|
||||
import { systemConfigApi } from "@/service/api/system";
|
||||
import { deptStatisticsApi } from '@/service/api/statistics';
|
||||
|
||||
const themeStore = useThemeStore();
|
||||
|
||||
const P_PERIODS = ["近一个月", "近三个月", "近半年", "近一年"];
|
||||
const period = ref<(typeof P_PERIODS)[number]>("近一年");
|
||||
|
||||
const DEPT_ACCEPT = [
|
||||
{ name: "工艺", value: 52 },
|
||||
{ name: "设备", value: 49 },
|
||||
{ name: "管理", value: 25 },
|
||||
];
|
||||
const ACCEPT_COLORS = ["#2080f0", "#7CC242", "#F5A623"];
|
||||
|
||||
const changeData = ref([
|
||||
{
|
||||
name: '一车间',
|
||||
value: 42,
|
||||
},
|
||||
{
|
||||
name: '二车间',
|
||||
value: 35,
|
||||
},
|
||||
{
|
||||
name: '三车间',
|
||||
value: 28,
|
||||
},
|
||||
{
|
||||
name: '供应部',
|
||||
value: 12,
|
||||
},
|
||||
{
|
||||
name: '质量部',
|
||||
value: 9,
|
||||
},
|
||||
]);
|
||||
const ADM_ACCEPT_DETAIL = [
|
||||
{ id: "MOC-2026-R01-0028", title: "成品包装规格调整", dept: "一车间", applyDate: "2026-02-20", useTime: "2026-03-15", acceptDate: "2026-04-10", cost: 3.2, result: "完全达到" },
|
||||
{ id: "MOC-2026-R01-0019", title: "R-201 搅拌密封改造", dept: "一车间", applyDate: "2026-03-18", useTime: "2026-04-12", acceptDate: "2026-05-20", cost: 6.8, result: "完全达到" },
|
||||
{ id: "MOC-2026-R01-0022", title: "循环水加药泵冲程临时调整", dept: "一车间", applyDate: "2026-04-25", useTime: "2026-05-18", acceptDate: "2026-06-30", cost: 1.5, result: "基本达到" },
|
||||
{ id: "MOC-2026-R02-0031", title: "冷冻盐水泵 P-103 叶轮材质变更", dept: "二车间", applyDate: "2026-06-30", useTime: "2026-07-24", acceptDate: "2026-08-02", cost: 4.6, result: "基本达到" },
|
||||
{ id: "MOC-2026-R03-0040", title: "原料环己烷供应商变更", dept: "供应部", applyDate: "2026-07-10", useTime: "2026-08-01", acceptDate: "2026-08-04", cost: 2.1, result: "完全达到" },
|
||||
];
|
||||
const admOpenStages = ref<{ name: string, n: number }[]>([
|
||||
{ name: "审批中(含会签)", n: 5 },
|
||||
{ name: "已批准待投用", n: 2 },
|
||||
{ name: "待验收", n: 0 },
|
||||
{ name: "待关闭", n: 1 },
|
||||
]);
|
||||
const loading = ref<boolean>(false);
|
||||
// 变更临期天数
|
||||
const remindDays = ref<number>(0);
|
||||
const homeData = ref<any>(null);
|
||||
|
||||
const EFFICIENCY_DATA = [
|
||||
{ d: "一车间", days: 6.2 }, { d: "二车间", days: 7.8 }, { d: "三车间", days: 9.4 }, { d: "供应部", days: 5.1 },
|
||||
];
|
||||
const ADM_PERSON_EFF = [
|
||||
{ p: "李主任", node: "部门审核", avg: 1.2, max: 2.5, onTime: 96 },
|
||||
{ p: "王仪表", node: "专业会签(仪表)", avg: 1.8, max: 3.0, onTime: 92 },
|
||||
{ p: "周设备", node: "专业会签(设备)", avg: 2.6, max: 4.1, onTime: 85 },
|
||||
{ p: "陈质量", node: "质量会签", avg: 1.6, max: 2.4, onTime: 95 },
|
||||
{ p: "王海燕", node: "安全审查", avg: 2.1, max: 3.5, onTime: 90 },
|
||||
{ p: "刘副总", node: "最终批准", avg: 1.5, max: 2.8, onTime: 94 },
|
||||
];
|
||||
const ADM_TEMP_DISP = [
|
||||
{ name: "到期恢复", value: 8, c: "#1D4E9C", note: "恢复原状并验收关闭" },
|
||||
{ name: "办理延期", value: 5, c: "#F5A623", note: "均符合「至多延期 1 次」" },
|
||||
{ name: "转为永久", value: 2, c: "#7CC242", note: "补办永久变更审批" },
|
||||
{ name: "超期未处理", value: 3, c: "#E15555", note: "系统已推送超期提醒至申请人" },
|
||||
];
|
||||
const ADM_REJECT_REASONS = [
|
||||
{ reason: "变更前后对比描述不完整 / 缺少核算数据", n: 4 },
|
||||
{ reason: "风险分析覆盖不足(情景缺失)", n: 3 },
|
||||
{ reason: "连带变更识别遗漏", n: 3 },
|
||||
{ reason: "所需材料不齐全", n: 2 },
|
||||
{ reason: "变更等级判定偏低", n: 2 },
|
||||
];
|
||||
const ADM_ARCHIVE_GAP = [
|
||||
{ item: "培训签到表", n: 3 }, { item: "PSSR 确认表", n: 2 }, { item: "变更验收单", n: 1 },
|
||||
];
|
||||
const ADM_ARCHIVE_TAGS = [
|
||||
{ k: "资料齐全", n: 76, c: "border-emerald-200 bg-emerald-50 text-emerald-700" },
|
||||
{ k: "缺培训签到", n: 3, c: "border-amber-200 bg-amber-50 text-amber-700" },
|
||||
{ k: "缺PSSR表", n: 2, c: "border-amber-200 bg-amber-50 text-amber-700" },
|
||||
{ k: "缺验收单", n: 1, c: "border-red-200 bg-red-50 text-red-700" },
|
||||
];
|
||||
// 获取数据
|
||||
const getData = async () => {
|
||||
loading.value = true;
|
||||
const {data,error} = await deptStatisticsApi({
|
||||
from: null,
|
||||
to: null,
|
||||
});
|
||||
if(!error){
|
||||
homeData.value = data;
|
||||
console.log(data);
|
||||
}
|
||||
loading.value = false;
|
||||
}
|
||||
|
||||
// 获取系统配置
|
||||
const getConfig = async () => {
|
||||
const {data,error} = await systemConfigApi();
|
||||
if(!error){
|
||||
// 解析 临时变更临期提醒
|
||||
const remindDaysGroup = data.find((group:{group_key:string}) => group.group_key === 'change_remind');
|
||||
if (remindDaysGroup) {
|
||||
remindDaysGroup?.items.forEach((item:any) => {
|
||||
if(item.item_key === 'temp_due_remind_days'){
|
||||
remindDays.value = Number(item.value);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getConfig();
|
||||
getData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NSpace vertical :size="16">
|
||||
<!-- 统计报表 -->
|
||||
<NCard :bordered="false" size="small" :style="{borderRadius: themeStore.themeRadius + 'px'}">
|
||||
<div class="flex flex-wrap items-center justify-between">
|
||||
<div class="flex items-center gap-1.5 text-sm font-semibold text-slate-700">
|
||||
<span>统计中心</span>
|
||||
<span class="text-xs font-normal text-slate-400">变更归口管理视角 · 全厂口径</span>
|
||||
</div>
|
||||
<div class="flex flex-wrap items-center gap-1.5 min-h-28px">
|
||||
<NButton size="tiny" round v-for="p in P_PERIODS" :key="p" @click="period = p"
|
||||
:ghost="period === p ? false : true"
|
||||
:type="period === p ? 'primary' : 'default'"
|
||||
>{{ p }}</NButton>
|
||||
<NButton size="small" class="text-xs ml-1">
|
||||
<Icon icon="material-symbols:download" class="size-14px mr-1" />导出
|
||||
</NButton>
|
||||
</div>
|
||||
</div>
|
||||
</NCard>
|
||||
<!-- 卡片数据 -->
|
||||
<NGrid cols="s:1 m:4 l:4" responsive="screen" :x-gap="16" :y-gap="16" :style="{'--theme-color': themeStore.themeColor}">
|
||||
<NGrid cols="s:1 m:4 l:4" responsive="screen" :x-gap="16" :y-gap="16">
|
||||
<NGi>
|
||||
<div
|
||||
class="flex-1 bg-white px-16px py-12px text-[#94a3b8]"
|
||||
:style="{ borderRadius: themeStore.themeRadius + 'px' }"
|
||||
>
|
||||
<p class="text-12px font-600">变更总数</p>
|
||||
<p class="text-12px font-600">本车间变更总数</p>
|
||||
<div class="flex items-center">
|
||||
<CountTo
|
||||
:start-value="0"
|
||||
:end-value="126"
|
||||
class="text-24px font-600 text-[var(--theme-color)]"
|
||||
class="text-24px font-600 text-slate-800"
|
||||
/>
|
||||
</div>
|
||||
<p class="text-12px">{{period}} · 全厂</p>
|
||||
<p class="text-12px">近一年 · 汇报口径</p>
|
||||
</div>
|
||||
</NGi>
|
||||
<NGi>
|
||||
@@ -134,15 +79,16 @@ const ADM_ARCHIVE_TAGS = [
|
||||
class="flex-1 bg-white px-16px py-12px text-[#94a3b8]"
|
||||
:style="{ borderRadius: themeStore.themeRadius + 'px' }"
|
||||
>
|
||||
<p class="text-12px font-600">重要变更</p>
|
||||
<p class="text-12px font-600">在办变更</p>
|
||||
<div class="flex items-center">
|
||||
<CountTo
|
||||
:start-value="0"
|
||||
:end-value="18"
|
||||
class="text-26px font-600 text-[var(--theme-color)]"
|
||||
class="text-26px font-600"
|
||||
:style="{color:themeStore.themeColor}"
|
||||
/>
|
||||
</div>
|
||||
<p class="text-12px">占比 14%</p>
|
||||
<p class="text-12px">实时 · 三大阶段分布见下</p>
|
||||
</div>
|
||||
</NGi>
|
||||
<NGi>
|
||||
@@ -150,16 +96,16 @@ const ADM_ARCHIVE_TAGS = [
|
||||
class="flex-1 bg-white px-16px py-12px text-[#94a3b8]"
|
||||
:style="{ borderRadius: themeStore.themeRadius + 'px' }"
|
||||
>
|
||||
<p class="text-12px font-600">变更费用合计</p>
|
||||
<p class="text-12px font-600">超期未关闭</p>
|
||||
<div class="flex items-center">
|
||||
<CountTo
|
||||
:start-value="0"
|
||||
:end-value="86.4"
|
||||
:decimals="1"
|
||||
class="text-26px font-600 text-[var(--theme-color)]"
|
||||
/><p class="text-26px font-600 text-[var(--theme-color)]">万</p>
|
||||
:end-value="86"
|
||||
class="text-26px font-600"
|
||||
:style="{color:themeStore.otherColor.error}"
|
||||
/>
|
||||
</div>
|
||||
<p class="text-12px">验收填报口径</p>
|
||||
<p class="text-12px">管理考核一票指标</p>
|
||||
</div>
|
||||
</NGi>
|
||||
<NGi>
|
||||
@@ -167,88 +113,120 @@ const ADM_ARCHIVE_TAGS = [
|
||||
class="flex-1 bg-white px-16px py-12px text-[#94a3b8]"
|
||||
:style="{ borderRadius: themeStore.themeRadius + 'px' }"
|
||||
>
|
||||
<p class="text-12px font-600">平均审批通过时长</p>
|
||||
<p class="text-12px font-600">我的审批按时率</p>
|
||||
<div class="flex items-center">
|
||||
<CountTo
|
||||
:start-value="0"
|
||||
:end-value="58"
|
||||
class="text-26px font-600 text-[var(--theme-color)]"
|
||||
/><p class="text-26px font-600 text-[var(--theme-color)]">%</p>
|
||||
class="text-26px font-600"
|
||||
:style="{color:themeStore.otherColor.success}"
|
||||
/><p class="text-26px font-600" :style="{color:themeStore.otherColor.success}">%</p>
|
||||
</div>
|
||||
<p class="text-12px">验收结论口径</p>
|
||||
<p class="text-12px">考核:目标 ≥90% · 达标</p>
|
||||
</div>
|
||||
</NGi>
|
||||
</NGrid>
|
||||
|
||||
<NGrid :x-gap="16" :y-gap="16" responsive="screen" item-responsive>
|
||||
<NGi span="24 s:24 m:24 l:14">
|
||||
<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">各车间变更数量({{period}})</p>
|
||||
<div class="py-3 px-4">
|
||||
<ColumnChart :data="changeData" style="height: 220px" />
|
||||
</div>
|
||||
</NCard>
|
||||
</NGi>
|
||||
<NGi span="24 s:24 m:24 l:10">
|
||||
<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">变更类型分布({{period}})</p>
|
||||
<div class="py-3 px-4">
|
||||
<RingChart :data="DEPT_ACCEPT" :colors="ACCEPT_COLORS" />
|
||||
</div>
|
||||
</NCard>
|
||||
</NGi>
|
||||
</NGrid>
|
||||
|
||||
<NGrid :x-gap="16" :y-gap="16" responsive="screen" item-responsive>
|
||||
<!-- 我的审批效率 -->
|
||||
<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="py-3 px-4">
|
||||
<div class="space-y-3">
|
||||
<div class="flex items-center gap-2 rounded-lg bg-slate-50 px-3 py-2.5">
|
||||
<span class="min-w-0 flex-1 text-sm text-slate-700">平均审批时长</span>
|
||||
<span class="text-base font-bold" :style="{color:themeStore.themeColor}">1.6 天</span>
|
||||
<span class="text-[11px]" :style="{color:themeStore.otherColor.success}">目标 ≤2 天</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 rounded-lg bg-slate-50 px-3 py-2.5">
|
||||
<span class="min-w-0 flex-1 text-sm text-slate-700">按时审批率</span>
|
||||
<span class="text-base font-bold" :style="{color:themeStore.themeColor}">92%</span>
|
||||
<span class="text-[11px]" :style="{color:themeStore.otherColor.success}">目标 ≥90%</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 rounded-lg bg-slate-50 px-3 py-2.5">
|
||||
<span class="min-w-0 flex-1 text-sm text-slate-700">驳回补充说明率</span>
|
||||
<span class="text-base font-bold" :style="{color:themeStore.themeColor}">100%</span>
|
||||
<span class="text-[11px]" :style="{color:themeStore.otherColor.success}">驳回必附整改指引</span>
|
||||
</div>
|
||||
<p class="text-[11px] text-slate-400">考核数据来源:本人节点签收 → 签出时长,系统自动统计,不可修改</p></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">本车间变更状态构成(实时)</p>
|
||||
<div class="py-3 px-4">
|
||||
<div class="space-y-2.5">
|
||||
<div v-for="item in homeData?.open_status_counts" :key="item.status" class="flex items-center gap-2">
|
||||
<!-- 审批中 -->
|
||||
<span v-if="item.status==='APPROVING'" class="h-2.5 w-2.5 shrink-0 rounded-sm" :style="{background:themeStore.otherColor.warning}"></span>
|
||||
<!-- 已批准待投用 -->
|
||||
<span v-if="item.status==='APPROVED'" class="h-2.5 w-2.5 shrink-0 rounded-sm" :style="{background:themeStore.themeColor}"></span>
|
||||
<!-- 待验收 -->
|
||||
<span v-if="item.status==='IMPLEMENTED'" class="h-2.5 w-2.5 shrink-0 rounded-sm" :style="{background:themeStore.otherColor.success}"></span>
|
||||
<!-- 待关闭 -->
|
||||
<span v-if="item.status==='ACCEPTED'" class="h-2.5 w-2.5 shrink-0 rounded-sm" :style="{background:themeStore.otherColor.error}"></span>
|
||||
<!-- 已驳回 -->
|
||||
<span v-if="item.status==='REJECTED'" class="h-2.5 w-2.5 shrink-0 rounded-sm" :style="{background:themeStore.otherColor.error}"></span>
|
||||
<span class="min-w-0 flex-1 text-sm text-slate-600">{{item.label}}</span>
|
||||
<span class="text-sm font-bold text-slate-800">{{item.count}}</span>
|
||||
</div>
|
||||
<p class="pt-1 text-[11px] text-slate-400">管理价值:一眼定位积压阶段,决定催办方向</p></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">临时变更监控(管理抓手)</p>
|
||||
<div class="py-3 px-4">
|
||||
<div class="space-y-3">
|
||||
<div class="rounded-lg border px-3 py-2">
|
||||
<div class="flex items-center gap-2 text-xs">
|
||||
<span class="h-2 w-2 rounded-full" :style="{ background: themeStore.otherColor.success }"></span>
|
||||
<span class="font-medium text-slate-700">正常(到期 > {{remindDays}} 天)</span>
|
||||
<span class="ml-auto font-semibold text-slate-600">{{homeData?.kpis?.unclosed_total || 0}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rounded-lg border px-3 py-2">
|
||||
<div class="flex items-center gap-2 text-xs">
|
||||
<span class="h-2 w-2 rounded-full" :style="{ background: themeStore.otherColor.warning }"></span>
|
||||
<span class="font-medium text-slate-700">临期(到期 ≤ {{remindDays}} 天)</span>
|
||||
<span class="ml-auto font-semibold text-slate-600">{{homeData?.kpis?.near_overdue_total || 0}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rounded-lg border px-3 py-2">
|
||||
<div class="flex items-center gap-2 text-xs">
|
||||
<span class="h-2 w-2 rounded-full" :style="{ background: themeStore.otherColor.error }"></span>
|
||||
<span class="font-medium text-slate-700">已超期</span>
|
||||
<span class="ml-auto font-semibold text-slate-600">{{homeData?.kpis?.overdue_total || 0}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<NButton size="small" ghost dashed block class="text-xs text-slate-400">前往变更台账查看处置 →</NButton>
|
||||
</div>
|
||||
</div>
|
||||
</NCard>
|
||||
</NGi>
|
||||
</NGrid>
|
||||
|
||||
<NGrid :x-gap="16" :y-gap="16" responsive="screen" item-responsive>
|
||||
<!-- 变更类型分布 -->
|
||||
<NGi span="24 s:24 m:24 l:10">
|
||||
<NCard :bordered="true" size="small" :content-style="{padding: 0}"
|
||||
:style="{
|
||||
borderRadius: themeStore.themeRadius + 'px',
|
||||
height: '100%',
|
||||
'--theme-color': themeStore.themeColor,
|
||||
'--error-color': themeStore.otherColor.error,
|
||||
'--warning-color': themeStore.otherColor.warning,
|
||||
'--success-color': themeStore.otherColor.success,
|
||||
'--error-bg': getColorWithOpacity(themeStore.otherColor.error,0.1),
|
||||
'--warning-bg': getColorWithOpacity(themeStore.otherColor.warning,0.1),
|
||||
'--theme-bg': getColorWithOpacity(themeStore.themeColor,0.1),
|
||||
}"
|
||||
>
|
||||
<p class=" text-base font-semibold border-b border-slate-100 p-3">各审批人审批时长(天 · {{period}} · 系统自动采集)</p>
|
||||
<div class="py-3 px-4">
|
||||
<table class="w-full text-xs">
|
||||
<thead>
|
||||
<tr class="border-b text-left text-slate-500">
|
||||
<th class="py-2 font-semibold">审批人 / 节点</th>
|
||||
<th class="w-[50px] py-2 text-right font-semibold">平均时长</th>
|
||||
<th class="w-[60px] py-2 text-right font-semibold">最长时长</th>
|
||||
<th class="w-[130px] py-2 font-semibold">及时率(≤2天)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="r in ADM_PERSON_EFF" :key="r.p" class="border-b last:border-0">
|
||||
<td class="py-2">
|
||||
<p class="text-xs font-medium text-slate-800">{{ r.p }}</p>
|
||||
<p class="text-[11px] text-slate-400">{{ r.node }}</p>
|
||||
</td>
|
||||
<td class="py-2 text-right text-xs font-bold text-slate-800">{{ r.avg.toFixed(1) }}</td>
|
||||
<td class="py-2 text-right text-xs text-slate-500">{{ r.max.toFixed(1) }}</td>
|
||||
<td class="py-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="h-1.5 flex-1 overflow-hidden rounded-full bg-slate-100">
|
||||
<div class="h-full rounded-full" :class="r.onTime >= 90 ? 'bg-[var(--success-color)]' : 'bg-[var(--warning-color)]'" :style="{ width: `${r.onTime}%` }" />
|
||||
</div>
|
||||
<span class="text-[11px] text-slate-500">{{ r.onTime }}%</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p class=" text-base font-semibold border-b border-slate-100 p-3">变更类型分布(近一年)</p>
|
||||
<RingChart :data="DEPT_ACCEPT" />
|
||||
</NCard>
|
||||
|
||||
</NGi>
|
||||
<NGi span="24 s:24 m:24 l:16">
|
||||
<!-- 风险增量与管控 -->
|
||||
<NGi span="24 s:24 m:24 l:14">
|
||||
<NCard
|
||||
:bordered="true"
|
||||
size="small"
|
||||
@@ -256,277 +234,43 @@ const ADM_ARCHIVE_TAGS = [
|
||||
:style="{
|
||||
borderRadius: themeStore.themeRadius + 'px',
|
||||
height: '100%',
|
||||
'--theme-color': themeStore.themeColor,
|
||||
'--error-color': themeStore.otherColor.error,
|
||||
'--warning-color': themeStore.otherColor.warning,
|
||||
'--success-color': themeStore.otherColor.success,
|
||||
'--error-bg': getColorWithOpacity(themeStore.otherColor.error,0.1),
|
||||
'--warning-bg': getColorWithOpacity(themeStore.otherColor.warning,0.1),
|
||||
}"
|
||||
>
|
||||
<p class=" text-base font-semibold border-b border-slate-100 p-3">变更是否达到预期效果及费用({{period}})</p>
|
||||
<div class="py-3 px-4">
|
||||
<div class="space-y-2.5">
|
||||
<div class="flex flex-wrap items-center gap-x-4 gap-y-1">
|
||||
<div class="flex items-center gap-1 text-[11px] text-slate-500">
|
||||
<span class="h-2 w-2 rounded-full bg-[var(--theme-color)]"></span>
|
||||
完全达到 73
|
||||
<p class=" text-base font-semibold border-b border-slate-100 p-3">风险增量与管控(近一年 · 本车间变更新增风险与管控落实)</p>
|
||||
<div class="py-3 px-4 space-y-2.5">
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
<div class="rounded-lg bg-red-50 px-3 py-2">
|
||||
<div class="text-[11px] text-slate-500">新增固有高风险项</div>
|
||||
<div class="text-xl font-bold" :style="{color:themeStore.otherColor.error}">{{homeData?.risk?.inherent_high || 0}}</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-1 text-[11px] text-slate-500">
|
||||
<span class="h-2 w-2 rounded-full bg-[var(--success-color)]"></span>
|
||||
基本达到 44
|
||||
<div class="rounded-lg bg-amber-50 px-3 py-2">
|
||||
<div class="text-[11px] text-slate-500">新增中风险项</div>
|
||||
<div class="text-xl font-bold" :style="{color:themeStore.otherColor.warning}">{{homeData?.risk?.inherent_mid || 0}}</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-1 text-[11px] text-slate-500">
|
||||
<span class="h-2 w-2 rounded-full bg-[var(--error-color)]"></span>
|
||||
未达到 9
|
||||
<div class="rounded-lg bg-slate-50 px-3 py-2">
|
||||
<div class="text-[11px] text-slate-500">剩余高风险项</div>
|
||||
<div class="text-xl font-bold" :style="{color:themeStore.otherColor.error}">{{homeData?.risk?.residual_high || 0}}</div>
|
||||
</div>
|
||||
<span class="ml-auto text-[11px] text-slate-500">费用合计 <b class="text-[var(--theme-color)]">86.4 万元</b></span>
|
||||
</div>
|
||||
<div class="overflow-x-auto rounded-lg border">
|
||||
<div class="min-w-[680px]">
|
||||
<div class="flex items-center gap-3 border-b bg-slate-50 px-3 py-1.5 text-[11px] font-semibold text-slate-500">
|
||||
<span class="min-w-0 flex-1">验收明细 · 变更名称 / 编号 / 部门</span>
|
||||
<span class="w-[84px] shrink-0">申请日期</span>
|
||||
<span class="w-[84px] shrink-0">投用日期</span>
|
||||
<span class="w-[84px] shrink-0">验收日期</span>
|
||||
<span class="w-[68px] shrink-0 text-right">费用(万元)</span>
|
||||
<span class="w-[76px] shrink-0 text-center">验收结论</span>
|
||||
<span class="w-[52px] shrink-0 text-right">操作</span>
|
||||
</div>
|
||||
<div class="divide-y">
|
||||
<div v-for="r in ADM_ACCEPT_DETAIL" :key="r.id" class="flex items-center gap-3 px-3 py-2 transition hover:bg-[#EAF0F9]/40">
|
||||
<span class="min-w-0 flex-1">
|
||||
<span class="block truncate text-xs font-medium text-slate-800">{{ r.title }}</span>
|
||||
<span class="block font-mono text-[11px] text-slate-400">{{ r.id }} · {{ r.dept }}</span>
|
||||
</span>
|
||||
<span class="w-[84px] shrink-0 text-xs text-slate-600">{{ r.applyDate }}</span>
|
||||
<span class="w-[84px] shrink-0 text-xs text-slate-600">{{ r.useTime }}</span>
|
||||
<span class="w-[84px] shrink-0 text-xs text-slate-600">{{ r.acceptDate }}</span>
|
||||
<span class="w-[68px] shrink-0 text-right text-xs font-bold text-slate-800">{{ r.cost.toFixed(1) }}</span>
|
||||
<span class="w-[76px] shrink-0 text-center">
|
||||
<NTag v-if="r.result==='完全达到'" size="small" type="success">{{ r.result }}</NTag>
|
||||
<NTag v-if="r.result==='基本达到'" size="small" type="info">{{ r.result }}</NTag>
|
||||
<NTag v-if="r.result==='未达到'" size="small" type="error">{{ r.result }}</NTag>
|
||||
</span>
|
||||
<span class="w-[52px] shrink-0 text-right">
|
||||
<NButton size="small" class="text-[11px]" @click="message.info(`演示:打开 ${r.id} 验收详情(含费用明细与运行数据)`)">查看</NButton>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-[11px] text-slate-400">明细为部分演示数据 · 全量见变更台账筛选「已关闭」</div>
|
||||
</div>
|
||||
</div>
|
||||
</NCard>
|
||||
</NGi>
|
||||
</NGrid>
|
||||
|
||||
<NGrid :x-gap="16" :y-gap="16" responsive="screen" item-responsive>
|
||||
<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%',
|
||||
'--error-color': themeStore.otherColor.error,
|
||||
'--warning-color': themeStore.otherColor.warning,
|
||||
'--success-color': themeStore.otherColor.success,
|
||||
'--error-bg': getColorWithOpacity(themeStore.otherColor.error,0.1),
|
||||
'--warning-bg': getColorWithOpacity(themeStore.otherColor.warning,0.1),
|
||||
}"
|
||||
>
|
||||
<p class=" text-base font-semibold border-b border-slate-100 p-3">变更带来的风险增量及管控({{period}})</p>
|
||||
<div class="py-3 px-4">
|
||||
<div class="space-y-3">
|
||||
<div class="grid grid-cols-2 gap-3">
|
||||
<div class="rounded-lg border border-[var(--error-color)] bg-[var(--error-bg)] px-3 py-2.5">
|
||||
<div class="text-[11px] text-slate-500">新增固有风险项</div>
|
||||
<div class="mt-1 text-sm font-bold text-slate-800">高 <b class="text-[var(--error-color)]">7</b> · 中 <b class="text-[var(--warning-color)]">21</b></div>
|
||||
</div>
|
||||
<div class="rounded-lg border border-[var(--warning-color)] bg-[var(--warning-bg)] px-3 py-2.5">
|
||||
<div class="text-[11px] text-slate-500">剩余风险项(管控中)</div>
|
||||
<div class="mt-1 text-sm font-bold text-slate-800">高 <b class="text-[var(--error-color)]">2</b> · 中 <b class="text-[var(--warning-color)]">9</b></div>
|
||||
<div class="rounded-lg bg-slate-50 px-3 py-2">
|
||||
<div class="text-[11px] text-slate-500">剩余中风险项</div>
|
||||
<div class="text-xl font-bold" :style="{color:themeStore.otherColor.warning}">{{homeData?.risk?.residual_mid || 0}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="flex items-center justify-between text-xs text-slate-500">
|
||||
<span>管控措施落实率</span><b class="text-[var(--success-color)]">92%</b>
|
||||
<div class="flex items-center gap-2 text-slate-500">
|
||||
<span class="text-xs">管控措施落实率</span>
|
||||
<div class="h-2 flex-1 rounded-full bg-slate-100">
|
||||
<div class="h-2 rounded-full" :style="{ background: themeStore.otherColor.success }" style="width: 96%"></div>
|
||||
</div>
|
||||
<div class="mt-1.5 h-1.5 w-full overflow-hidden rounded-full bg-slate-100">
|
||||
<div class="h-full rounded-full bg-[var(--success-color)]" :style="{ width: `92%` }"></div>
|
||||
<span class="font-semibold" :style="{color:themeStore.otherColor.success}">96%</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-[11px] text-slate-400">口径:风险分析记录表识别的新增固有高/中风险项,与验收时剩余风险项对比;剩余高风险项均挂接管控措施并跟踪落实</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%',
|
||||
'--theme-color': themeStore.themeColor,
|
||||
'--error-color': themeStore.otherColor.error,
|
||||
'--warning-color': themeStore.otherColor.warning,
|
||||
'--success-color': themeStore.otherColor.success,
|
||||
'--error-bg': getColorWithOpacity(themeStore.otherColor.error,0.1),
|
||||
'--warning-bg': getColorWithOpacity(themeStore.otherColor.warning,0.1),
|
||||
'--theme-bg': getColorWithOpacity(themeStore.themeColor,0.1),
|
||||
}"
|
||||
>
|
||||
<p class=" text-base font-semibold border-b border-slate-100 p-3">当前未关闭变更({{period}})</p>
|
||||
<div class="py-3 px-4">
|
||||
<div class="space-y-3">
|
||||
<div class="flex items-end gap-2">
|
||||
<span class="text-3xl font-extrabold leading-none text-[var(--theme-color)]">8</span>
|
||||
<span class="pb-0.5 text-[11px] text-slate-400">起 · 实时台账口径</span>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-1.5">
|
||||
<span v-for="s in admOpenStages" :key="s.name" class="rounded-md border border-[var(--theme-color)] bg-[var(--theme-bg)] px-2 py-0.5 text-[11px] text-[var(--theme-color)]">{{ s.name }} <b>{{ s.n }}</b></span>
|
||||
</div>
|
||||
<div class="rounded-lg border border-[var(--warning-color)] bg-[var(--warning-bg)] px-3 py-2 text-[11px] text-[var(--warning-color)]">
|
||||
临时变更临期 <b>1</b> 起 · 已到期未处置 <b class="text-[var(--error-color)]">1</b> 起(临期提醒天数可在通知设置调整)
|
||||
</div>
|
||||
<NButton size="small" ghost type="primary" block class="text-xs" @click="emit('go', 'ledger')">
|
||||
进入变更台账<Icon icon="formkit:right" class="size-12px" />
|
||||
</NButton>
|
||||
</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%',
|
||||
'--theme-color': themeStore.themeColor,
|
||||
'--error-color': themeStore.otherColor.error,
|
||||
'--warning-color': themeStore.otherColor.warning,
|
||||
'--success-color': themeStore.otherColor.success,
|
||||
'--error-bg': getColorWithOpacity(themeStore.otherColor.error,0.1),
|
||||
'--warning-bg': getColorWithOpacity(themeStore.otherColor.warning,0.1),
|
||||
'--theme-bg': getColorWithOpacity(themeStore.themeColor,0.1),
|
||||
}"
|
||||
>
|
||||
<p class=" text-base font-semibold border-b border-slate-100 p-3">驳回的变更申请({{period}})</p>
|
||||
<div class="py-3 px-4">
|
||||
<div class="space-y-3">
|
||||
<div class="flex items-end gap-2">
|
||||
<span class="text-3xl font-extrabold leading-none text-[var(--error-color)]">14</span>
|
||||
<span class="pb-0.5 text-[11px] text-slate-400">起 · 驳回率 11.1%</span>
|
||||
</div>
|
||||
<div class="rounded-lg border px-3 py-2.5 text-[11px] text-slate-500">
|
||||
驳回后修改重报通过率 <b class="text-[var(--success-color)]">78.6%</b>
|
||||
<div class="mt-0.5 text-slate-400">驳回均留痕并附带理由,申请人可「修改重报」</div>
|
||||
</div>
|
||||
<NButton size="small" ghost type="primary" block class="text-xs" @click="emit('go', 'ledger')">
|
||||
查看驳回单<Icon icon="formkit:right" class="size-12px" />
|
||||
</NButton>
|
||||
</div>
|
||||
<p class="mt-1.5 text-[11px] text-slate-400">高风险场景明细见「高风险」页(按部门筛选一车间)</p>
|
||||
</div>
|
||||
</NCard>
|
||||
</NGi>
|
||||
</NGrid>
|
||||
|
||||
<NGrid :x-gap="16" :y-gap="16" responsive="screen" item-responsive>
|
||||
<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">各部门审批时长(天 · {{period}})</p>
|
||||
<div class="py-3 px-4">
|
||||
<div class="space-y-3">
|
||||
<div v-for="e in EFFICIENCY_DATA" :key="e.d" class="flex items-center gap-3">
|
||||
<span class="w-14 shrink-0 text-xs text-slate-600">{{ e.d }}</span>
|
||||
<NProgress
|
||||
type="line"
|
||||
:percentage="(e.days / 10) * 100"
|
||||
:height="15"
|
||||
:border-radius="4"
|
||||
:fill-border-radius="4"
|
||||
>
|
||||
<span class="w-12 shrink-0 text-right text-xs font-bold text-slate-800">{{ e.days }} 天</span>
|
||||
</NProgress>
|
||||
</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%',
|
||||
'--theme-color': themeStore.themeColor,
|
||||
'--error-color': themeStore.otherColor.error,
|
||||
'--warning-color': themeStore.otherColor.warning,
|
||||
'--success-color': themeStore.otherColor.success,
|
||||
'--error-bg': getColorWithOpacity(themeStore.otherColor.error,0.1),
|
||||
'--warning-bg': getColorWithOpacity(themeStore.otherColor.warning,0.1),
|
||||
'--theme-bg': getColorWithOpacity(themeStore.themeColor,0.1),
|
||||
}"
|
||||
>
|
||||
<p class=" text-base font-semibold border-b border-slate-100 p-3">临时变更后续处置方式({{period}})</p>
|
||||
<div class="py-3 px-4">
|
||||
<div class="space-y-2.5">
|
||||
<div v-for="t in ADM_TEMP_DISP" :key="t.name" class="rounded-lg border px-3 py-2.5">
|
||||
<div class="flex items-center gap-1">
|
||||
<div class="flex items-center gap-1">
|
||||
<span v-if="t.name==='到期恢复'" class="h-2.5 w-2.5 rounded-sm bg-[var(--theme-color)]"></span>
|
||||
<span v-if="t.name==='办理延期'" class="h-2.5 w-2.5 rounded-sm bg-[var(--warning-color)]"></span>
|
||||
<span v-if="t.name==='转为永久'" class="h-2.5 w-2.5 rounded-sm bg-[var(--success-color)]"></span>
|
||||
<span v-if="t.name==='超期未处理'" class="h-2.5 w-2.5 rounded-sm bg-[var(--error-color)]"></span>
|
||||
<span class="text-xs font-medium text-slate-800">{{ t.name }}</span>
|
||||
<p class="mt-[1px] pl-1 text-[11px] text-slate-400">{{ t.note }}</p>
|
||||
</div>
|
||||
<span v-if="t.name==='到期恢复'" class="ml-auto text-sm font-extrabold text-[var(--theme-color)]">{{ t.value }}</span>
|
||||
<span v-if="t.name==='办理延期'" class="ml-auto text-sm font-extrabold text-[var(--warning-color)]">{{ t.value }}</span>
|
||||
<span v-if="t.name==='转为永久'" class="ml-auto text-sm font-extrabold text-[var(--success-color)]">{{ t.value }}</span>
|
||||
<span v-if="t.name==='超期未处理'" class="ml-auto text-sm font-extrabold text-[var(--error-color)]">{{ t.value }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-[11px] text-slate-400">处置子单(延期 / 转永久 / 恢复)均走简化审批并留痕,与本统计同源</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%',
|
||||
'--theme-color': themeStore.themeColor,
|
||||
'--error-color': themeStore.otherColor.error,
|
||||
'--warning-color': themeStore.otherColor.warning,
|
||||
'--success-color': themeStore.otherColor.success,
|
||||
'--error-bg': getColorWithOpacity(themeStore.otherColor.error,0.1),
|
||||
'--warning-bg': getColorWithOpacity(themeStore.otherColor.warning,0.1),
|
||||
'--theme-bg': getColorWithOpacity(themeStore.themeColor,0.1),
|
||||
}"
|
||||
>
|
||||
<p class=" text-base font-semibold border-b border-slate-100 p-3">主要驳回理由汇总({{period}} · 按驳回单数)</p>
|
||||
<div class="py-3 px-4">
|
||||
<div class="space-y-2.5">
|
||||
<div v-for="r in ADM_REJECT_REASONS" :key="r.reason">
|
||||
<div class="flex items-center justify-between text-xs">
|
||||
<span class="text-slate-600">{{ r.reason }}</span>
|
||||
</div>
|
||||
<NProgress
|
||||
type="line"
|
||||
:percentage="(r.n / 10) * 100"
|
||||
>
|
||||
<span class="w-12 shrink-0 text-right text-xs font-bold text-slate-800">{{ r.n }} 起</span>
|
||||
</NProgress>
|
||||
</div>
|
||||
<div class="text-[11px] text-slate-400">可用于申请端填报质量改进:TOP2 理由已纳入 AI 预识别检查项</div>
|
||||
</div>
|
||||
</div>
|
||||
</NCard>
|
||||
</NGi>
|
||||
</NGrid>
|
||||
|
||||
<!-- 变更投入和效果 -->
|
||||
<NGrid :x-gap="16" :y-gap="16" responsive="screen" item-responsive>
|
||||
<NGi span="24 s:24 m:24 l:24">
|
||||
<NCard :bordered="true" size="small" :content-style="{padding: 0}"
|
||||
@@ -537,55 +281,41 @@ const ADM_ARCHIVE_TAGS = [
|
||||
'--success-color': themeStore.otherColor.success,
|
||||
}"
|
||||
>
|
||||
<p class=" text-base font-semibold border-b border-slate-100 p-3">变更归档资料情况({{period}})</p>
|
||||
<div class="py-3 px-4">
|
||||
<div class="grid gap-4 grid-cols-12">
|
||||
<div class="flex items-center gap-4 col-span-4">
|
||||
<NProgress type="circle" :percentage="93.8" :offset-degree="180">
|
||||
<div class="flex flex-col items-center mt-2">
|
||||
<p class="flex text-xl font-bold leading-none text-[#1D2129]">
|
||||
93.8<span class="text-sm font-semibold">%</span>
|
||||
<div class="flex items-center justify-between p-3">
|
||||
<p class=" text-base font-semibold border-b border-slate-100">变更投入和效果(近一年 · 已验收变更)</p>
|
||||
<p class="text-[11px] text-slate-400">
|
||||
已验收 <b class="text-slate-700">3</b> 起 ·
|
||||
投入合计 <b :style="{color:themeStore.themeColor}">11.5</b> 万元 ·
|
||||
完全达到率 <b :style="{color:themeStore.otherColor.success}">67%</b>
|
||||
</p>
|
||||
<p class="mt-1 text-[11px] text-slate-400">Good</p>
|
||||
</div>
|
||||
</NProgress>
|
||||
<div class="space-y-1 text-xs text-slate-500">
|
||||
<div>应归档 <b class="text-slate-800">81</b> 起 · 已归档 <b class="text-[var(--success-color)]">76</b> 起</div>
|
||||
<div>待补齐资料 <b class="text-[var(--error-color)]">5</b> 起(已推送申请人补齐提醒)</div>
|
||||
<div class="text-[11px] text-slate-400">归档包确认关闭后只读锁定,不可修改删除</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-span-4">
|
||||
<p class="text-[11px] font-bold uppercase tracking-[0.14em] text-slate-400">资料缺项 TOP</p>
|
||||
<div class="mt-2 space-y-2">
|
||||
<div v-for="g in ADM_ARCHIVE_GAP" :key="g.item" class="flex items-center gap-2 text-xs">
|
||||
<span class="min-w-0 flex-1 text-slate-600">{{ g.item }}缺失</span>
|
||||
<div class="w-44">
|
||||
<NProgress
|
||||
type="line"
|
||||
status="warning"
|
||||
:percentage="(g.n / 5) * 100"
|
||||
>
|
||||
<span class="w-12 shrink-0 text-right text-xs font-bold text-slate-800">{{ g.n }}</span>
|
||||
</NProgress>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-span-4">
|
||||
<p class="text-[11px] font-bold uppercase tracking-[0.14em] text-slate-400">归档构成(已关闭 81 起)</p>
|
||||
<div class="mt-2 flex flex-wrap gap-1.5">
|
||||
<template v-for="x in ADM_ARCHIVE_TAGS" :key="x.k">
|
||||
<NTag v-if="x.k==='资料齐全'" size="small" type="success">{{ x.k }} {{ x.n }}</NTag>
|
||||
<NTag v-if="x.k==='缺培训签到' || x.k==='缺PSSR表'" size="small" type="warning">{{ x.k }} {{ x.n }}</NTag>
|
||||
<NTag v-if="x.k==='缺验收单'" size="small" type="error">{{ x.k }} {{ x.n }}</NTag>
|
||||
</template>
|
||||
</div>
|
||||
<NButton size="small" type="primary" ghost block class="mt-3 text-xs" @click="emit('go', 'knowledge')">
|
||||
进入资料库 / 归档<Icon icon="formkit:right" class="size-12px" />
|
||||
</NButton>
|
||||
</div>
|
||||
</div>
|
||||
<div class="py-3 px-4">
|
||||
<NTable size="small">
|
||||
<thead>
|
||||
<tr>
|
||||
<td>变更名称 / 编号</td>
|
||||
<td>申请日期</td>
|
||||
<td>投用日期</td>
|
||||
<td>验收日期</td>
|
||||
<td>费用(万元)</td>
|
||||
<td>验收结论</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>
|
||||
<!-- <NTag v-if="r.result_status===3" size="small" type="success">{{r.result_label}}</NTag>
|
||||
<NTag v-if="r.result_status===2" size="small" type="warning">{{r.result_label}}</NTag>
|
||||
<NTag v-if="r.result_status===1" size="small" type="error">{{r.result_label}}</NTag> -->
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</NTable>
|
||||
</div>
|
||||
</NCard>
|
||||
</NGi>
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { useEcharts } from '@/hooks/common/echarts';
|
||||
|
||||
defineOptions({
|
||||
name: 'RingChart'
|
||||
});
|
||||
|
||||
const props = defineProps<{ data: { name: string; value: number; }[]; }>();
|
||||
|
||||
const { domRef, updateOptions } = useEcharts(() => ({
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
axisPointer: {
|
||||
type: "shadow",
|
||||
textStyle: {
|
||||
color: "#fff",
|
||||
},
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
show:false,
|
||||
bottom: '20%',
|
||||
left: 'center',
|
||||
icon: 'circle',
|
||||
itemWidth: 10,
|
||||
itemHeight: 10,
|
||||
itemStyle: {
|
||||
borderWidth: 0
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
top: "5%",
|
||||
left: "5%",
|
||||
right: "5%",
|
||||
bottom: "11%",
|
||||
},
|
||||
calculable: true,
|
||||
xAxis: [
|
||||
{
|
||||
type: "category",
|
||||
boundaryGap: true, // 新增,固定柱子位置
|
||||
axisLine: {
|
||||
show: false,
|
||||
},
|
||||
axisLabel: {
|
||||
interval: 0,
|
||||
},
|
||||
splitLine: { show: false },
|
||||
axisTick: { show: false },
|
||||
splitArea: { show: false },
|
||||
data: [] as string[],
|
||||
},
|
||||
],
|
||||
yAxis: [
|
||||
{
|
||||
type: "value",
|
||||
show: false,
|
||||
},
|
||||
],
|
||||
series: [
|
||||
{
|
||||
type: "bar",
|
||||
barWidth: 45,
|
||||
barGap: "10%",
|
||||
color: "#2080f0",
|
||||
label: { show: true, position: 'top',color: '#333',fontWeight: 'bold' },
|
||||
data: [] as number[],
|
||||
},
|
||||
]
|
||||
}));
|
||||
|
||||
function init() {
|
||||
updateOptions(opts => {
|
||||
let allMonth = props.data.map((item:any) => item.name);
|
||||
let values = props.data.map((item:any) => item.value);
|
||||
opts.xAxis[0].data = allMonth;
|
||||
opts.series[0].data = values;
|
||||
return opts;
|
||||
});
|
||||
}
|
||||
|
||||
init();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="domRef" class="w-full h-220px overflow-hidden"></div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -6,7 +6,7 @@ defineOptions({
|
||||
name: 'RingChart'
|
||||
});
|
||||
|
||||
const props = defineProps<{ data?: { name: string; value: number }[]; colors?: string[] }>();
|
||||
const props = defineProps<{ data?: { name: string; value: number }[]; }>();
|
||||
|
||||
const { domRef, updateOptions } = useEcharts(() => ({
|
||||
tooltip: {
|
||||
@@ -24,7 +24,7 @@ const { domRef, updateOptions } = useEcharts(() => ({
|
||||
},
|
||||
},
|
||||
title: {
|
||||
text: `{a|126}\n{b|总数}`,
|
||||
text: `{a|126}\n{b|近一年}`,
|
||||
textStyle: {
|
||||
rich: {
|
||||
a: {
|
||||
@@ -50,7 +50,7 @@ const { domRef, updateOptions } = useEcharts(() => ({
|
||||
series: [
|
||||
{
|
||||
type: 'pie',
|
||||
color: ['#5da8ff', '#8e9dff', '#fedc69', '#26deca'],
|
||||
color: ["#2080f0", "#7CC242", "#F5A623"],
|
||||
radius: ['45%', '65%'],
|
||||
center: ['50%', '45%'],
|
||||
avoidLabelOverlap: false,
|
||||
@@ -73,7 +73,6 @@ const { domRef, updateOptions } = useEcharts(() => ({
|
||||
function init() {
|
||||
updateOptions(opts => {
|
||||
opts.series[0].data = props.data || [];
|
||||
opts.series[0].color = props.colors || [];
|
||||
return opts;
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user