Files
moc/src/views/professionalStatistics/index.vue
T

190 lines
8.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<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';
import RingChart from './modules/ringChart.vue';
const appStore = useAppStore();
const themeStore = useThemeStore();
const gap = computed(() => (appStore.isMobile ? 0 : 16));
const profEff = ref<{d: string, days: number, me?: boolean, target?: boolean}[]>([
{ d: `陈质量(本人)`, days: 1.8, me: true },
{ d: "仪表专业均值", days: 2.1, me: false },
{ d: "设备专业均值", days: 2.2, me: false },
{ d: "工艺专业均值", days: 2.6, me: false },
{ d: "考核目标", days: 2.5, me: false, target: true },
]);
const DEPT_ACCEPT = [
{ name: "工艺", value: 52 },
{ name: "设备", value: 49 },
{ name: "管理", value: 25 },
];
const ACCEPT_COLORS = ["#2080f0", "#7CC242", "#F5A623"];
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 供应商)' },
];
</script>
<template>
<NSpace vertical :size="16">
<!-- 卡片数据 -->
<NGrid cols="s:1 m:5 l:5" responsive="screen" :x-gap="gap" :y-gap="16"
:style="{
'--theme-color': themeStore.themeColor,
'--success-color': themeStore.otherColor.success,
'--warning-color': themeStore.otherColor.warning,
}"
>
<NGi>
<div
class="flex-1 bg-white px-16px py-12px text-[#94a3b8]"
:style="{ borderRadius: themeStore.themeRadius + 'px', height: '100%' }"
>
<p class="text-12px font-600">本月会签 / 审批</p>
<div class="flex items-center">
<CountTo
:start-value="0"
:end-value="6"
class="text-24px font-600 text-[#333]"
/>
</div>
<p class="text-12px">口径:节点签出记录</p>
</div>
</NGi>
<NGi>
<div
class="flex-1 bg-white px-16px py-12px text-[#94a3b8]"
:style="{ borderRadius: themeStore.themeRadius + 'px', height: '100%' }"
>
<p class="text-12px font-600">我的会签平均耗时</p>
<div class="flex items-center">
<CountTo
:start-value="0"
:end-value="1.8"
: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>
</div>
</NGi>
<NGi>
<div
class="flex-1 bg-white px-16px py-12px text-[#94a3b8]"
:style="{ borderRadius: themeStore.themeRadius + 'px', height: '100%' }"
>
<p class="text-12px font-600">按时完成率</p>
<div class="flex items-center">
<CountTo
:start-value="0"
:end-value="95"
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">考核:目标 ≥90%</p>
</div>
</NGi>
<NGi>
<div
class="flex-1 bg-white px-16px py-12px text-[#94a3b8]"
:style="{ borderRadius: themeStore.themeRadius + 'px', height: '100%' }"
>
<p class="text-12px font-600">参与风险分析</p>
<div class="flex items-center">
<CountTo
:start-value="0"
:end-value="2"
class="text-26px font-600 text-[var(--theme-color)]"
/><p class="text-26px font-600 text-[var(--theme-color)]">次</p>
</div>
<p class="text-12px">口径:HAZOP / JSA 分析组成员(选择式)记录</p>
</div>
</NGi>
<NGi>
<div
class="flex-1 bg-white px-16px py-12px text-[#94a3b8]"
:style="{ borderRadius: themeStore.themeRadius + 'px', height: '100%' }"
>
<p class="text-12px font-600">当前待我审批</p>
<div class="flex items-center">
<CountTo
:start-value="0"
:end-value="1"
class="text-26px font-600 text-[var(--warning-color)]"
/>
</div>
<p class="text-12px">实时 · 与工作台同源</p>
</div>
</NGi>
</NGrid>
<NGrid :x-gap="gap" :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%',
'--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">会签效率对比(考核 · 汇报)</p>
<div class="py-3 px-4">
<div class="space-y-3">
<div v-for="e in profEff" :key="e.d">
<div class="mb-1 flex items-center justify-between text-xs">
<span :class="e.me ? 'font-semibold text-[var(--theme-color)]' : 'text-slate-600'">{{ e.d }}</span>
<span :class="e.target ? 'text-slate-400' : e.days > 2.5 ? 'font-medium text-[var(--error-color)]' : 'text-slate-500'">{{ e.days }} 天{{ e.target ? "(标线)" : "" }}</span>
</div>
<div class="h-2 overflow-hidden rounded-full bg-slate-100">
<div class="h-full rounded-full" :class="e.target ? 'bg-slate-300' : e.me ? 'bg-[var(--theme-color)]' : e.days > 2.5 ? 'bg-[var(--error-color)]' : 'bg-[#6E93C6]'" :style="{ width: `${Math.min(100, (e.days / 4) * 100)}%` }" />
</div>
</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">
<RingChart :data="DEPT_ACCEPT" :colors="ACCEPT_COLORS" />
</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 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">
<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>
<ChevronRight class="h-3.5 w-3.5 shrink-0 text-slate-300" />
</div>
<p class="text-[11px] text-slate-400">更多高风险场景与分析记录见「高风险」页</p>
</div>
</div>
</NCard>
</NGi>
</NGrid>
</NSpace>
</template>
<style scoped></style>