全工厂统计概览页面完成

This commit is contained in:
2026-09-30 14:49:22 +08:00
parent 8206121d46
commit 071d751f79
10 changed files with 522 additions and 300 deletions
+75 -86
View File
@@ -1,63 +1,48 @@
<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 { getColorWithOpacity } from '@/utils/common';
import RingChart from './modules/ringChart.vue';
import ColumnChart from './modules/columnChart.vue';
import ColumnChart2 from './modules/columnChart2.vue';
import { factoryStatisticsApi } from '@/service/api/statistics';
const appStore = useAppStore();
const themeStore = useThemeStore();
const gap = computed(() => (appStore.isMobile ? 0 : 16));
const DEPT_ACCEPT = [
{ name: "工艺", value: 52 },
{ name: "设备", value: 49 },
{ name: "管理", value: 25 },
];
const ACCEPT_COLORS = ["#2080f0", "#7CC242", "#F5A623"];
const changeData = ref([
{
name: '2月',
value: 42,
},
{
name: '3月',
value: 35,
},
{
name: '4月',
value: 28,
},
{
name: '5月',
value: 12,
},
{
name: '6月',
value: 9,
},
{
name: '7月',
value: 33,
},
]);
const DEFAULT_EFF = [
{ pct: 85, label: "按期投用率", c: "#1D4E9C" },
{ pct: 64, label: "培训按期完成率", c: "#F5A623" },
{ pct: 25, label: "超期变更占比", c: "#E15555" },
];
const DEFAULT_EXPORTS = ["变更数量统计", "变更周期分析", "超期预警报表", "风险分析执行", "PSSR 与验收", "关闭及时率"];
const loading = ref<boolean>(false);
const homeData = ref<any>(null);
// 导出数据
const exportData = (type: string) => {
window.$message?.info('还差接口')
}
// 获取数据
const getData = async () => {
loading.value = true;
const {data,error} = await factoryStatisticsApi({
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" :style="{'--theme-color': themeStore.themeColor,'--theme-bg': getColorWithOpacity(themeStore.themeColor, 0.1)}">
<NGrid cols="s:1 m:4 l:4" responsive="screen" :x-gap="16" :y-gap="16" :style="{'--theme-color': themeStore.themeColor,'--theme-bg': getColorWithOpacity(themeStore.themeColor, 0.1)}">
<NGi>
<div
class="bg-white px-16px py-12px text-[#94a3b8]"
@@ -65,12 +50,11 @@ const DEFAULT_EXPORTS = ["变更数量统计", "变更周期分析", "超期预
>
<p class="text-12px font-600 text-center">按期关闭率</p>
<div class="flex justify-center py-2.5">
<NProgress type="circle" :percentage="93.8" :offset-degree="180">
<NProgress type="circle" :percentage="homeData?.gauges?.ontime_close_rate || 0" :offset-degree="180">
<div class="flex flex-col items-center mt-2">
<p class="flex items-end text-2xl font-bold leading-none text-[#1D2129]">
93.8<span class="text-sm font-semibold">%</span>
{{homeData?.gauges?.ontime_close_rate || 0}}<span class="text-sm font-semibold">%</span>
</p>
<p class="mt-1 text-[11px] text-slate-400">Good</p>
</div>
</NProgress>
</div>
@@ -84,68 +68,57 @@ const DEFAULT_EXPORTS = ["变更数量统计", "变更周期分析", "超期预
>
<p class="text-12px font-600 text-center">PSSR 完成率</p>
<div class="flex justify-center py-2.5">
<NProgress type="circle" :percentage="96" :offset-degree="180" status="success">
<NProgress type="circle" :percentage="homeData?.gauges?.pssr_rate || 0" :offset-degree="180" status="success">
<div class="flex flex-col items-center mt-2">
<p class="flex items-end text-2xl font-bold leading-none text-[#1D2129]">
96<span class="text-sm font-semibold">%</span>
{{homeData?.gauges?.pssr_rate || 0}}<span class="text-sm font-semibold">%</span>
</p>
<p class="mt-1 text-[11px] text-slate-400">Excellent</p>
</div>
</NProgress>
</div>
<p class="text-12px text-center">近一年 · 全厂</p>
</div>
</NGi>
<NGi>
<div
class="bg-white px-16px py-12px text-[#94a3b8]"
:style="{ borderRadius: themeStore.themeRadius + 'px', height: '100%' }"
>
<p class="text-12px font-600 text-center">验收一次通过率</p>
<div class="flex justify-center py-2.5">
<NProgress type="circle" :percentage="88" :offset-degree="180" status="warning">
<div class="flex flex-col items-center mt-2">
<p class="flex items-end 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>
</div>
<p class="text-12px text-center">近一年 · 全厂</p>
</div>
</NGi>
<NGi>
<div
class="bg-white px-16px py-12px text-[#94a3b8] flex flex-col justify-center items-center"
:style="{ borderRadius: themeStore.themeRadius + 'px', height: '100%' }"
>
<p class="text-12px font-600 text-center">当月临时变更数量</p>
<p class="mt-2 text-[40px] font-bold leading-none text-[#1D2129] text-center">{{homeData?.gauges?.month_created || 0}}</p>
<p class="text-12px text-center mt-1">近一年 · 全厂</p>
</div>
</NGi>
<NGi>
<div
class="bg-white px-16px py-12px text-[#94a3b8] flex flex-col justify-center items-center"
:style="{ borderRadius: themeStore.themeRadius + 'px', height: '100%' }"
>
<p class="text-12px font-600 text-center">平均关闭时长</p>
<p class="mt-2 text-[40px] font-bold leading-none text-[#1D2129] text-center">8.2</p>
<p class="mt-2 text-[40px] font-bold leading-none text-[#1D2129] text-center">{{homeData?.gauges?.avg_close_days || 0}}</p>
<p class="text-12px text-center mt-1">天 · 优于行业均值</p>
<span class="mt-2 rounded-full bg-[var(--theme-bg)] px-2 py-0.5 text-[11px] font-medium text-[var(--theme-color)]">环比 ↓ 0.6 天</span>
</div>
</NGi>
</NGrid>
<NGrid :x-gap="gap" :y-gap="16" responsive="screen" item-responsive>
<NGi span="24 s:24 m:24 l:8">
<NGrid :x-gap="16" :y-gap="16" responsive="screen" item-responsive>
<NGi span="24 s:24 m:24 l:12">
<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">
<ColumnChart :data="changeData" style="height: 220px" />
<ColumnChart v-if="homeData" :data="homeData?.monthly_counts || []" />
</div>
</NCard>
</NGi>
<NGi span="24 s:24 m:24 l:8">
<NGi span="24 s:24 m:24 l:6">
<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">
<RingChart :data="DEPT_ACCEPT" :colors="ACCEPT_COLORS" />
<RingChart v-if="homeData" :data="homeData?.type_dist || []" />
</div>
</NCard>
</NGi>
<NGi span="24 s:24 m:24 l:8">
<NGi span="24 s:24 m:24 l:6">
<NCard :bordered="true" size="small" :content-style="{padding: 0}"
:style="{
borderRadius: themeStore.themeRadius + 'px',
@@ -158,15 +131,31 @@ const DEFAULT_EXPORTS = ["变更数量统计", "变更周期分析", "超期预
<p class=" text-base font-semibold border-b border-slate-100 p-3">变更效率指标</p>
<div class="py-3 px-4">
<div class="space-y-5">
<div v-for="r in DEFAULT_EFF" :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 text-slate-400">{{ r.label }}</span>
<span class="text-2xl font-bold text-[#1D2129]">{{homeData?.eff?.ontime_use_rate || 0}}<span class="text-sm font-semibold">%</span></span>
<span class="text-xs text-slate-400">按期投用率</span>
</div>
<div class="mt-1.5 h-1 w-full overflow-hidden rounded-full bg-slate-100">
<div v-if="r.label==='按期投用率'" class="h-full rounded-full bg-[var(--theme-color)]" :style="{ width: `${r.pct}%` }"></div>
<div v-if="r.label==='培训按期完成率'" class="h-full rounded-full bg-[var(--warning-color)]" :style="{ width: `${r.pct}%` }"></div>
<div v-if="r.label==='超期变更占比'" class="h-full rounded-full bg-[var(--error-color)]" :style="{ width: `${r.pct}%` }"></div>
<div class="h-full rounded-full bg-[var(--theme-color)]" :style="{ width: `${homeData?.eff?.ontime_use_rate || 0}%` }"></div>
</div>
</div>
<div>
<div class="flex items-baseline gap-2">
<span class="text-2xl font-bold text-[#1D2129]">{{homeData?.eff?.train_upload_rate || 0}}<span class="text-sm font-semibold">%</span></span>
<span class="text-xs text-slate-400">培训按期完成率</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(--warning-color)]" :style="{ width: `${homeData?.eff?.train_upload_rate || 0}%` }"></div>
</div>
</div>
<div>
<div class="flex items-baseline gap-2">
<span class="text-2xl font-bold text-[#1D2129]">{{homeData?.eff?.overdue_rate || 0}}<span class="text-sm font-semibold">%</span></span>
<span class="text-xs text-slate-400">超期变更占比</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(--error-color)]" :style="{ width: `${homeData?.eff?.overdue_rate || 0}%` }"></div>
</div>
</div>
<div class="text-[11px] text-slate-400">近一年 · 全厂口径 · 超期占比越低越好</div>
@@ -176,12 +165,12 @@ const DEFAULT_EXPORTS = ["变更数量统计", "变更周期分析", "超期预
</NGi>
</NGrid>
<NGrid :x-gap="gap" :y-gap="16" responsive="screen" item-responsive>
<NGrid :x-gap="16" :y-gap="16" responsive="screen" item-responsive>
<NGi span="24 s:24 m:24 l:16">
<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">
<ColumnChart :data="changeData" style="height: 220px" />
<ColumnChart2 v-if="homeData" :data="homeData?.cycle_trend || []" />
</div>
</NCard>
</NGi>
@@ -197,7 +186,7 @@ const DEFAULT_EXPORTS = ["变更数量统计", "变更周期分析", "超期预
<p class=" text-base font-semibold border-b border-slate-100 p-3">报表导出</p>
<div class="py-3 px-4">
<div class="grid grid-cols-2 gap-2">
<div v-for="r in DEFAULT_EXPORTS" :key="r" @click="message.success(`演示:${r}已导出 Excel`)"
<div v-for="r in DEFAULT_EXPORTS" :key="r" @click="exportData(r)"
class="cursor-pointer flex items-center gap-2 rounded-lg border px-3 py-2.5 text-sm hover:border-[var(--theme-color)] hover:bg-[var(--theme-bg)]">
<Icon icon="akar-icons:file" class="size-16px text-slate-400" />
{{ r }}