From 0c9aa3e1d5cfbf2245f9e7462e1d27cc8c7827d1 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期三, 14 十月 2026 18:29:49 +0800
Subject: [PATCH] feat: 客户签订合同展示、质检合格率卡片、生产订单选择默认状态修正

---
 src/views/dashboard/analytics/modules/kpi-cards.vue |  130 ++++++++++++++++++++++++++++++++-----------
 1 files changed, 97 insertions(+), 33 deletions(-)

diff --git a/src/views/dashboard/analytics/modules/kpi-cards.vue b/src/views/dashboard/analytics/modules/kpi-cards.vue
index 88853ef..055f8f6 100644
--- a/src/views/dashboard/analytics/modules/kpi-cards.vue
+++ b/src/views/dashboard/analytics/modules/kpi-cards.vue
@@ -22,12 +22,60 @@
   navigate: [name: string];
 }>();
 
-const qualityRate = computed(() => {
-  const total =
-    props.summary.todayQualifiedQuantity +
-    props.summary.todayUnqualifiedQuantity;
-  return total === 0 ? 0 : (props.summary.todayQualifiedQuantity / total) * 100;
-});
+/**
+ * 璐ㄩ噺鍚堟牸鐜囷細鏉ユ枡 / 杩囩▼ / 鍑鸿揣涓変釜妫�楠岀幆鑺傦紝鍚勮嚜涓�寮犲崱鐗�
+ *
+ * 鐢卞悗绔寜銆屽悎鏍兼暟閲� / 妫�楠屾暟閲忋�嶈绠楋紙涓嶈繃婊ゅ崟鎹姸鎬侊紝鏃犳椂闂撮檺鍒讹級锛�
+ * 璇ョ幆鑺傛病鏈夋楠屾暟鎹椂鍚庣杩斿洖 null銆�
+ */
+const qualityRates = computed(() => [
+  {
+    key: 'quality-iqc',
+    label: '鏉ユ枡鍚堟牸鐜�',
+    rate: props.summary.iqcQualifiedRate,
+    checkQuantity: props.summary.iqcCheckQuantity,
+    routeName: 'MesQcIqc',
+    icon: 'lucide:package-check',
+    iconClass: 'bg-gradient-to-br from-orange-500 to-amber-400 shadow-lg shadow-orange-500/25',
+    textClass: 'text-orange-600 dark:text-orange-400',
+    washClass: 'bg-gradient-to-br from-orange-500/5 to-amber-500/5',
+    glowClass: 'bg-orange-400/10',
+  },
+  {
+    key: 'quality-ipqc',
+    label: '杩囩▼鍚堟牸鐜�',
+    rate: props.summary.ipqcQualifiedRate,
+    checkQuantity: props.summary.ipqcCheckQuantity,
+    routeName: 'MesQcIpqc',
+    icon: 'lucide:workflow',
+    iconClass: 'bg-gradient-to-br from-cyan-500 to-teal-400 shadow-lg shadow-cyan-500/25',
+    textClass: 'text-cyan-600 dark:text-cyan-400',
+    washClass: 'bg-gradient-to-br from-cyan-500/5 to-teal-500/5',
+    glowClass: 'bg-cyan-400/10',
+  },
+  {
+    key: 'quality-oqc',
+    label: '鍑鸿揣鍚堟牸鐜�',
+    rate: props.summary.oqcQualifiedRate,
+    checkQuantity: props.summary.oqcCheckQuantity,
+    routeName: 'MesQcOqc',
+    icon: 'lucide:truck',
+    iconClass: 'bg-gradient-to-br from-pink-500 to-rose-400 shadow-lg shadow-pink-500/25',
+    textClass: 'text-pink-600 dark:text-pink-400',
+    washClass: 'bg-gradient-to-br from-pink-500/5 to-rose-500/5',
+    glowClass: 'bg-pink-400/10',
+  },
+]);
+
+/** 鍚堟牸鐜囧睍绀烘枃妗堬紙涓�浣嶅皬鏁帮紝涓庡師銆岃川閲忓悎鏍肩巼銆嶅崱鐗囦竴鑷达級锛屾棤鏁版嵁鏃剁敤銆屸�斻�嶈�屼笉鏄� 0% */
+function formatRate(rate: null | number | undefined) {
+  return rate === null || rate === undefined ? '鈥�' : rate.toFixed(1);
+}
+
+/** 鏃犳楠屾暟鎹椂涓嶆覆鏌撶櫨鍒嗗彿锛岄伩鍏嶅嚭鐜般�屸��%銆� */
+function hasRate(rate: null | number | undefined) {
+  return rate !== null && rate !== undefined;
+}
 
 const equipmentRate = computed(() => {
   if (props.summary.machineryTotal === 0) return 0;
@@ -63,9 +111,9 @@
 <template>
   <Row :gutter="16">
     <!-- 鐢熶骇璁㈠崟 -->
-    <Col :lg="6" :md="12" :sm="12" :xl="6" :xs="24" class="mb-4">
+    <Col :lg="6" :md="12" :sm="12" :xl="4" :xs="24" class="mb-4">
       <div
-        class="glass-tilt group overflow-hidden rounded-2xl border-0"
+        class="glass-tilt group h-full overflow-hidden rounded-2xl border-0"
         :class="{ 'cursor-pointer': canNavigate('MesProWorkOrder') }"
         :style="tiltStyle('order')"
         @mousemove="(e: MouseEvent) => onMouseMove(e, 'order')"
@@ -95,9 +143,9 @@
     </Col>
 
     <!-- 浠婃棩浜ч噺 -->
-    <Col :lg="6" :md="12" :sm="12" :xl="6" :xs="24" class="mb-4">
+    <Col :lg="6" :md="12" :sm="12" :xl="4" :xs="24" class="mb-4">
       <div
-        class="glass-tilt group overflow-hidden rounded-2xl border-0"
+        class="glass-tilt group h-full overflow-hidden rounded-2xl border-0"
         :class="{ 'cursor-pointer': canNavigate('MesProFeedback') }"
         :style="tiltStyle('output')"
         @mousemove="(e: MouseEvent) => onMouseMove(e, 'output')"
@@ -126,44 +174,60 @@
       </div>
     </Col>
 
-    <!-- 璐ㄩ噺鍚堟牸鐜� -->
-    <Col :lg="6" :md="12" :sm="12" :xl="6" :xs="24" class="mb-4">
+    <!-- 璐ㄩ噺鍚堟牸鐜囷細鏉ユ枡 / 杩囩▼ / 鍑鸿揣锛屽悇涓�寮犲崱鐗� -->
+    <Col
+      v-for="item in qualityRates"
+      :key="item.key"
+      :lg="6"
+      :md="12"
+      :sm="12"
+      :xl="4"
+      :xs="24"
+      class="mb-4"
+    >
       <div
-        class="glass-tilt group overflow-hidden rounded-2xl border-0"
-        :class="{ 'cursor-pointer': canNavigate('MesQcRecord') }"
-        :style="tiltStyle('quality')"
-        @mousemove="(e: MouseEvent) => onMouseMove(e, 'quality')"
-        @mouseleave="onMouseLeave('quality')"
-        @click="canNavigate('MesQcRecord') && emit('navigate', 'MesQcRecord')"
+        class="glass-tilt group h-full overflow-hidden rounded-2xl border-0"
+        :class="{ 'cursor-pointer': canNavigate(item.routeName) }"
+        :style="tiltStyle(item.key)"
+        @mousemove="(e: MouseEvent) => onMouseMove(e, item.key)"
+        @mouseleave="onMouseLeave(item.key)"
+        @click="canNavigate(item.routeName) && emit('navigate', item.routeName)"
       >
         <div class="relative z-10 flex items-center gap-4 p-5">
-          <div class="flex size-12 flex-shrink-0 items-center justify-center rounded-xl bg-gradient-to-br from-orange-500 to-amber-400 shadow-lg shadow-orange-500/25 transition-transform duration-300 group-hover:scale-110">
-            <IconifyIcon class="size-6 text-white" icon="lucide:shield-check" />
+          <div
+            class="flex size-12 flex-shrink-0 items-center justify-center rounded-xl transition-transform duration-300 group-hover:scale-110"
+            :class="item.iconClass"
+          >
+            <IconifyIcon class="size-6 text-white" :icon="item.icon" />
           </div>
           <div class="min-w-0 flex-1">
-            <div class="mb-1 text-xs font-medium text-gray-500 dark:text-gray-400">璐ㄩ噺鍚堟牸鐜�</div>
+            <div class="mb-1 text-xs font-medium text-gray-500 dark:text-gray-400">{{ item.label }}</div>
             <div class="flex items-baseline gap-1">
-              <CountTo
-                class="text-2xl font-bold leading-tight"
-                :class="qualityRate >= 95 ? 'text-emerald-600 dark:text-emerald-400' : qualityRate >= 80 ? 'text-orange-600 dark:text-orange-400' : 'text-red-600 dark:text-red-400'"
-                :decimals="1" :end-val="qualityRate" :duration="1200"
-              />
-              <span class="text-xs text-gray-400">%</span>
+              <span class="text-2xl font-bold leading-tight" :class="item.textClass">
+                {{ formatRate(item.rate) }}
+              </span>
+              <span v-if="hasRate(item.rate)" class="text-xs text-gray-400">%</span>
             </div>
-            <div class="mt-1 text-xs text-gray-400">
-              鍚堟牸 {{ summary.todayQualifiedQuantity }} | 涓嶈壇 {{ summary.todayUnqualifiedQuantity }}
+            <div class="mt-1 flex items-center gap-1 text-xs text-gray-400">
+              <span>妫�楠� {{ item.checkQuantity }}</span>
             </div>
           </div>
         </div>
-        <div class="absolute inset-0 -z-0 bg-gradient-to-br from-orange-500/5 to-amber-500/5 opacity-0 transition-opacity duration-300 group-hover:opacity-100" />
-        <div class="absolute -right-6 -top-6 size-24 rounded-full bg-orange-400/10 blur-xl transition-all duration-300 group-hover:scale-150" />
+        <div
+          class="absolute inset-0 -z-0 opacity-0 transition-opacity duration-300 group-hover:opacity-100"
+          :class="item.washClass"
+        />
+        <div
+          class="absolute -right-6 -top-6 size-24 rounded-full blur-xl transition-all duration-300 group-hover:scale-150"
+          :class="item.glowClass"
+        />
       </div>
     </Col>
 
     <!-- 璁惧杩愯鐜� -->
-    <Col :lg="6" :md="12" :sm="12" :xl="6" :xs="24" class="mb-4">
+    <Col :lg="6" :md="12" :sm="12" :xl="4" :xs="24" class="mb-4">
       <div
-        class="glass-tilt group overflow-hidden rounded-2xl border-0"
+        class="glass-tilt group h-full overflow-hidden rounded-2xl border-0"
         :class="{ 'cursor-pointer': canNavigate('MesDvMachinery') }"
         :style="tiltStyle('equip')"
         @mousemove="(e: MouseEvent) => onMouseMove(e, 'equip')"

--
Gitblit v1.9.3