From 26cd65ace0c8787b5ff6feff3e6270fb371e1a9c Mon Sep 17 00:00:00 2001
From: zhuguifei <zhuguifei@zhuguifeideiMac.local>
Date: 星期四, 11 九月 2025 13:41:23 +0800
Subject: [PATCH] 添加质量预测性维护两个页面

---
 src/views/index.vue | 1037 +++++++++++++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 883 insertions(+), 154 deletions(-)

diff --git a/src/views/index.vue b/src/views/index.vue
index 4e40cdb..714f6a7 100644
--- a/src/views/index.vue
+++ b/src/views/index.vue
@@ -1,176 +1,905 @@
 <template>
   <div class="app-container home">
-    <el-row :gutter="20">
-      <el-col :sm="24" :lg="12" style="padding-left: 20px">
-        <h2>RuoYi-Vue-Plus鍚庡彴绠$悊绯荤粺</h2>
-        <p>
-          RuoYi-Vue-Plus 鏄熀浜� RuoYi-Vue 閽堝 鍒嗗竷寮忛泦缇� 鍦烘櫙鍗囩骇(涓嶅吋瀹瑰師妗嗘灦)
-          <br/>
-          * 鍓嶇寮�鍙戞鏋� Vue銆丒lement UI<br/>
-          * 鍚庣寮�鍙戞鏋� Spring Boot<br/>
-          * 瀹瑰櫒妗嗘灦 Undertow 鍩轰簬 Netty 鐨勯珮鎬ц兘瀹瑰櫒<br/>
-          * 鏉冮檺璁よ瘉妗嗘灦 Sa-Token 鏀寔澶氱粓绔璇佺郴缁�<br/>
-          * 鍏崇郴鏁版嵁搴� MySQL 閫傞厤 8.X 鏈�浣� 5.7<br/>
-          * 缂撳瓨鏁版嵁搴� Redis 閫傞厤 6.X 鏈�浣� 4.X<br/>
-          * 鏁版嵁搴撴鏋� Mybatis-Plus 蹇�� CRUD 澧炲姞寮�鍙戞晥鐜�<br/>
-          * 鏁版嵁搴撴鏋� p6spy 鏇村己鍔茬殑 SQL 鍒嗘瀽<br/>
-          * 澶氭暟鎹簮妗嗘灦 dynamic-datasource 鏀寔涓讳粠涓庡绉嶇被鏁版嵁搴撳紓鏋�<br/>
-          * 搴忓垪鍖栨鏋� Jackson 缁熶竴浣跨敤 jackson 楂樻晥鍙潬<br/>
-          * Redis瀹㈡埛绔� Redisson 鎬ц兘寮哄姴銆丄PI涓板瘜<br/>
-          * 鍒嗗竷寮忛檺娴� Redisson 鍏ㄥ眬銆佽姹侷P銆侀泦缇D 澶氱闄愭祦<br/>
-          * 鍒嗗竷寮忛攣 Lock4j 娉ㄨВ閿併�佸伐鍏烽攣 澶氱澶氭牱<br/>
-          * 鍒嗗竷寮忓箓绛� Lock4j 鍩轰簬鍒嗗竷寮忛攣瀹炵幇<br/>
-          * 鍒嗗竷寮忛摼璺拷韪� SkyWalking 鏀寔閾捐矾杩借釜銆佺綉鏍煎垎鏋愩�佸害閲忚仛鍚堛�佸彲瑙嗗寲<br/>
-          * 鍒嗗竷寮忎换鍔¤皟搴� Xxl-Job 楂樻�ц兘 楂樺彲闈� 鏄撴墿灞�<br/>
-          * 鏂囦欢瀛樺偍 Minio 鏈湴瀛樺偍<br/>
-          * 鏂囦欢瀛樺偍 涓冪墰銆侀樋閲屻�佽吘璁�	浜戝瓨鍌�<br/>
-          * 鐩戞帶妗嗘灦 SpringBoot-Admin 鍏ㄦ柟浣嶆湇鍔$洃鎺�<br/>
-          * 鏍¢獙妗嗘灦 Validation 澧炲己鎺ュ彛瀹夊叏鎬� 涓ヨ皑鎬�<br/>
-          * Excel妗嗘灦 Alibaba EasyExcel 鎬ц兘浼樺紓 鎵╁睍鎬у己<br/>
-          * 鏂囨。妗嗘灦 SpringDoc銆乯avadoc 鏃犳敞瑙i浂鍏ヤ镜鍩轰簬java娉ㄩ噴<br/>
-          * 宸ュ叿绫绘鏋� Hutool銆丩ombok 鍑忓皯浠g爜鍐椾綑 澧炲姞瀹夊叏鎬�<br/>
-          * 浠g爜鐢熸垚鍣� 閫傞厤MP銆丼pringDoc瑙勮寖鍖栦唬鐮� 涓�閿敓鎴愬墠鍚庣浠g爜<br/>
-          * 閮ㄧ讲鏂瑰紡 Docker 瀹瑰櫒缂栨帓 涓�閿儴缃蹭笟鍔¢泦缇�<br/>
-          * 鍥介檯鍖� SpringMessage Spring鏍囧噯鍥介檯鍖栨柟妗�<br/>
-        </p>
-        <p>
-          <b>褰撳墠鐗堟湰:</b> <span>v{{ version }}</span>
-        </p>
-        <p>
-          <el-tag type="danger">&yen;鍏嶈垂寮�婧�</el-tag>
-        </p>
-        <p>
-          <el-button
-            type="primary"
-            icon="Cloudy"
-            plain
-            @click="goTarget('https://gitee.com/JavaLionLi/RuoYi-Vue-Plus')"
-            >璁块棶鐮佷簯</el-button
-          >
-          <el-button
-            type="primary"
-            icon="Cloudy"
-            plain
-            @click="goTarget('https://github.com/JavaLionLi/RuoYi-Vue-Plus')"
-            >璁块棶GitHub</el-button
-          >
-          <el-button
-            type="primary"
-            icon="Cloudy"
-            plain
-            @click="goTarget('https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/pages?sort_id=4106467&doc_id=1469725')"
-          >鏇存柊鏃ュ織</el-button
-          >
-        </p>
-      </el-col>
+    <div class="p-5">
+      <div style="display: flex" class="gap-4">
 
-      <el-col :sm="24" :lg="12" style="padding-left: 50px">
-        <el-row>
-          <el-col :span="12">
-            <h2>鎶�鏈�夊瀷</h2>
-          </el-col>
-        </el-row>
-        <el-row>
-          <el-col :span="6">
-            <h4>鍚庣鎶�鏈�</h4>
-            <ul>
-              <li>SpringBoot</li>
-              <li>Sa-Token</li>
-              <li>JWT</li>
-              <li>MyBatis</li>
-              <li>Druid</li>
-              <li>Jackson</li>
-              <li>...</li>
-            </ul>
-          </el-col>
-          <el-col :span="6">
-            <h4>鍓嶇鎶�鏈�</h4>
-            <ul>
-              <li>Vue</li>
-              <li>Vuex</li>
-              <li>Element-ui</li>
-              <li>Axios</li>
-              <li>Sass</li>
-              <li>Quill</li>
-              <li>...</li>
-            </ul>
-          </el-col>
-        </el-row>
-      </el-col>
-    </el-row>
-    <el-divider />
+        <el-card style="width: 100%;flex: 1;" class="mb-4">
+
+       <div style="display: flex">
+         <div>
+           <el-statistic  :value="batchScore" :suffix="'鍒�'" :precision="1" :value-style="{fontSize: '30px',fontWeight: 'bold'}">
+             <template #title>
+               <div style="display: inline-flex; align-items: center;font-size: 18px">
+                 缁煎悎璐ㄩ噺璇勫垎
+                 <el-tooltip effect="dark" content="" placement="top">
+                   <el-icon style="margin-left: 4px" :size="12">
+                     <Warning />
+                   </el-icon>
+                 </el-tooltip>
+               </div>
+             </template>
+           </el-statistic>
+           <div class="statistic-footer">
+             <div class="footer-item">
+               <span>杈冩槰澶�</span>
+               <span :class="{ 'green': batchScore > 9.4, 'red': batchScore <= 9.4 }">
+                <el-icon v-if="batchScore > 9.4">
+                  <CaretTop />
+                </el-icon>
+                <el-icon v-else>
+                  <CaretBottom />
+                </el-icon>
+              </span>
+             </div>
+           </div>
+         </div>
+         <div style="flex: 1;display: flex;justify-content: center;align-items: center">
+           <el-image style="width: 60px; height: 60px" :src="q1" fit="contain" />
+         </div>
+       </div>
+
+
+        </el-card>
+        <el-card style="flex: 1" class="mb-4">
+
+
+          <div style="display: flex">
+            <div>
+              <el-statistic :value="qualityRate" :suffix="'%'" :value-style="{fontSize: '30px',fontWeight: 'bold'}">
+                <template #title>
+                  <div style="display: inline-flex; align-items: center;font-size: 18px">
+                    鑹搧鐜�
+                    <el-tooltip effect="dark" content="" placement="top">
+                      <el-icon style="margin-left: 4px" :size="12">
+                        <Warning />
+                      </el-icon>
+                    </el-tooltip>
+                  </div>
+                </template>
+              </el-statistic>
+              <div class="statistic-footer">
+                <div class="footer-item">
+                  <span>杈冩槰澶�</span>
+                  <span :class="{ 'green': qualityRate >= 95, 'red': qualityRate < 95 }">
+                <el-icon v-if="qualityRate >= 95">
+                  <CaretTop />
+                </el-icon>
+                <el-icon v-else>
+                  <CaretBottom />
+                </el-icon>
+              </span>
+                </div>
+              </div>
+            </div>
+            <div style="flex: 1;display: flex;justify-content: center;align-items: center">
+              <el-image style="width: 60px; height: 60px" :src="q2" fit="contain" />
+            </div>
+          </div>
+
+
+        </el-card>
+        <el-card style="flex: 1" class="mb-4">
+
+
+          <div style="display: flex">
+            <div>
+              <el-statistic :value="checkNum" :suffix="'pcs'" :value-style="{fontSize: '30px',fontWeight: 'bold'}">
+                <template #title>
+                  <div style="display: inline-flex; align-items: center;font-size: 18px">
+                    妫�娴嬫暟閲�
+                    <el-tooltip effect="dark" content="" placement="top">
+                      <el-icon style="margin-left: 4px" :size="12">
+                        <Warning />
+                      </el-icon>
+                    </el-tooltip>
+                  </div>
+                </template>
+              </el-statistic>
+              <div class="statistic-footer">
+                <div class="footer-item">
+                  <span>杈冩槰澶�</span>
+                  <span :class="{ 'green': batchScore > 1, 'red': batchScore <= 1 }">
+                <el-icon v-if="batchScore > 1">
+                  <CaretTop />
+                </el-icon>
+                <el-icon v-else>
+                  <CaretBottom />
+                </el-icon>
+              </span>
+                </div>
+              </div>
+            </div>
+            <div style="flex: 1;display: flex;justify-content: center;align-items: center">
+              <el-image style="width: 60px; height: 60px" :src="q3" fit="contain" />
+            </div>
+          </div>
+
+
+        </el-card>
+        <el-card style="flex: 1" class="mb-4">
+
+
+          <div style="display: flex">
+            <div>
+              <el-statistic :value="ngCountNum" :suffix="'pcs'"  :value-style="{fontSize: '30px',fontWeight: 'bold'}">
+                <template #title>
+                  <div style="display: inline-flex; align-items: center;font-size: 18px">
+                    寮傚父鏁伴噺
+                    <el-tooltip effect="dark" content="" placement="top">
+                      <el-icon style="margin-left: 4px" :size="12">
+                        <Warning />
+                      </el-icon>
+                    </el-tooltip>
+                  </div>
+                </template>
+              </el-statistic>
+              <div class="statistic-footer">
+                <div class="footer-item">
+                  <span>杈冩槰澶�</span>
+                  <span :class="{ 'green': ngCountNum < 50, 'red': ngCountNum  >= 50 }">
+                <el-icon v-if="ngCountNum >= 50">
+                  <CaretTop />
+                </el-icon>
+                <el-icon v-else>
+                  <CaretBottom />
+                </el-icon>
+              </span>
+
+                  <span style="margin-left: 10px">棰勬祴寮傚父鐜�:</span>
+                  <span  class="red" v-if="qualityRate > 80"> {{(((100-qualityRate)/ 3)+0.1).toFixed(1) }}% </span>
+                  <span v-else > 3.7%</span>
+                </div>
+              </div>
+            </div>
+            <div style="flex: 1;display: flex;justify-content: center;align-items: center">
+              <el-image style="width: 60px; height: 60px" :src="q4" fit="contain" />
+            </div>
+          </div>
+        </el-card>
+      </div>
+      <!-- 璁惧鍋ュ悍鐘舵�佸彲瑙嗗寲 -->
+      <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
+        <el-card shadow="hover" class="h-420" >
+          <template #header>
+            <div class="card-header">
+              <span>鍋ュ悍搴﹁瘎鍒�</span>
+            </div>
+          </template>
+          <div ref="healthChartRef" class="h-400 w-full"></div>
+        </el-card>
+
+        <el-card shadow="hover" class="h-420">
+          <template #header>
+            <div class="card-header">
+              <span>璐ㄩ噺棰勮淇℃伅</span>
+            </div>
+          </template>
+<!--          <div class="grid grid-cols-2 gap-2">-->
+<!--            <div class="p-2 bg-blue-50 rounded">-->
+<!--              <p class="text-sm text-gray-600">榻愮撼淇濇姢鐢靛帇(榛�)</p>-->
+<!--              <p class="text-xl">39.00 V 鈮� result 鈮� 49.00 V</p>-->
+<!--            </div>-->
+<!--            <div class="p-2 bg-yellow-50 rounded">-->
+<!--              <p class="text-sm text-gray-600">璺濈</p>-->
+<!--              <p class="text-xl">4.75 mm 鈮� result 鈮� 5.15 mm</p>-->
+<!--            </div>-->
+<!--            <div class="p-2 bg-red-50 rounded">-->
+<!--              <p class="text-sm text-gray-600">鍘嬮檷(榛�)1</p>-->
+<!--              <p class="text-xl">0.30 V 鈮� result 鈮� 3.00 V</p>-->
+<!--            </div>-->
+<!--            <div class="p-2 bg-green-50 rounded">-->
+<!--              <p class="text-sm text-gray-600">鍥炲樊</p>-->
+<!--              <p class="text-xl">0.05 mm 鈮� result 鈮� 1.00 mm</p>-->
+<!--            </div>-->
+<!--            <div class="p-2 bg-blue-50 rounded">-->
+<!--              <p class="text-sm text-gray-600">婕忕數娴�(榛�)1</p>-->
+<!--              <p class="text-xl">result 鈮� 800.00 uA</p>-->
+<!--            </div>-->
+<!--            <div class="p-2 bg-yellow-50 rounded">-->
+<!--              <p class="text-sm text-gray-600"></p>-->
+<!--              <p class="text-xl font-bold"></p>-->
+<!--            </div>-->
+<!--          </div>-->
+
+          <el-table size="large"   :data="warnBatchList" style="width: 100%" :border="true" stripe>
+            <el-table-column prop="batchTime" label="棰勮鏃堕棿" />
+            <el-table-column prop="batchCode" label="鎵规鍙�"  width="140" />
+            <el-table-column prop="gw" label="璁惧/宸ヤ綅"  />
+            <el-table-column prop="yc" label="寮傚父绫诲瀷"   />
+            <el-table-column prop="cd" label="涓ラ噸绋嬪害">
+              <template #default="{ row }">
+                <el-tag :type="getStatusTagType(row.cd)">{{ row.cd }}</el-tag>
+              </template>
+            </el-table-column>
+
+
+          </el-table>
+        </el-card>
+      </div>
+
+
+      <el-card shadow="hover" class="mb-6">
+        <template #header>
+          <div class="card-header">
+            <span>妫�娴嬫壒娆�</span>
+            <el-date-picker
+              v-model="batchDate"
+              type="date"
+              placeholder="閫夋嫨鏃ユ湡"
+              :disabled-date="disabledDate"
+              :shortcuts="shortcuts"
+              @change="changeBatchDate"
+            />
+          </div>
+        </template>
+        <div class="grid grid-cols-1 gap-4">
+          <!-- 杩欓噷灏嗘斁缃璀﹁〃鏍� -->
+          <el-table v-loading="loading" :data="batchList" style="width: 100%" :border="true" stripe>
+            <el-table-column prop="batchCode" label="鎵规鍙�" width="180" />
+            <el-table-column prop="prodModel" label="浜у搧鍨嬪彿" width="180" />
+            <el-table-column prop="num" label="妫�娴嬫暟閲�" width="120" />
+            <el-table-column prop="okNum" label="鑹搧鏁伴噺" width="120" />
+            <el-table-column prop="ngNum" label="涓嶈壇鏁伴噺" width="120" />
+            <el-table-column prop="lpv" label="鑹搧鐜�" width="120">
+              <template #default="{ row }">
+                <el-tag :type="goodProductsRate(row) >= 95 ? 'success' : 'warning'"> {{ goodProductsRate(row) }} % </el-tag>
+              </template>
+            </el-table-column>
+            <el-table-column prop="whjy" label="缁存姢寤鸿">
+              <template #default="{ row }">
+                <el-tag :type="goodProductsRate(row) >= 95 ? 'success' : 'warning'">
+                  {{ goodProductsRate(row) >= 95 ? '鑹搧鐜囨寚鏍囧凡浼樺紓锛岃鍏虫敞璁惧缁煎悎鏁堢巼' : '棰勮锛屾鏌ュ伐鑹哄弬鏁版槸鍚︾鍚堟爣鍑嗭紝浼樺寲鍏抽敭鍙傛暟' }}
+                </el-tag>
+              </template>
+            </el-table-column>
+            <el-table-column label="鎿嶄綔" width="180">
+              <template #default="{ row }">
+                <el-button link type="primary" @click="handleDetail(row)">璇︽儏</el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </div>
+      </el-card>
+
+
+
+
+
+      <!-- 澶囦欢淇℃伅 -->
+      <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
+        <!-- 鎵规鍚堟牸鐜囪秼鍔� -->
+        <el-card shadow="hover" class="h-420">
+          <template #header>
+            <div class="card-header">
+              <span>鎵规鍚堟牸鐜囪秼鍔�</span>
+            </div>
+          </template>
+          <div ref="batchRateTrendRef" class="h-400 w-full"></div>
+        </el-card>
+
+
+        <el-card shadow="hover" class="h-420">
+          <template #header>
+            <div class="card-header">
+              <span>杩戜竴鍛∟G椤筎OP5</span>
+            </div>
+          </template>
+          <div ref="ngChartRef" class="h-400 w-full"></div>
+        </el-card>
+      </div>
+    </div>
   </div>
 </template>
 
-<script setup name="Index">
-const version = ref('5.0.0-SNAPSHOT')
+<script setup name="Index" lang="ts">
+import { onMounted, ref } from 'vue';
+import { useRouter } from 'vue-router';
+import { ElMessage } from 'element-plus';
+import * as echarts from 'echarts';
 
-function goTarget(url) {
-  window.open(url, '__blank')
+import q1 from '@/assets/images/quailty/q1.png';
+import q2 from '@/assets/images/quailty/q2.png';
+import q3 from '@/assets/images/quailty/q3.png';
+import q4 from '@/assets/images/quailty/q4.png';
+
+import { queryQualityHealth, queryBatchList,queryPwbatchList ,queryNgrank} from '@/api/qms/index';
+import { BatchVO } from '@/api/qms/batch/types';
+import { listBatch } from '@/api/qms/batch';
+
+const batchScore = ref(0);
+const qualityRate = ref(0);
+const checkNum = ref(0);
+const ngCountNum = ref(0);
+
+const batchDate = ref('');
+
+const healthChartRef = ref<HTMLElement | null>(null);
+const batchRateTrendRef = ref<HTMLElement | null>(null);
+const ngChartRef = ref<HTMLElement | null>(null);
+const healthChart = ref();
+const batchRateChart = ref();
+const ngChart = ref();
+const router = useRouter();
+
+const loading = ref(false);
+const batchList = ref<BatchVO[]>([]);
+const warnBatchList = ref<any>([]);
+
+
+const gwList = [
+  "寰満鐢电郴缁熻殌鍒绘満",
+  "鏅跺渾閿悎鏈�",
+  "浼犳劅鍣ㄦ牎鍑嗙珯",
+  "钖勮啘娌夌Н璁惧",
+  "鍏夊埢鏈�",
+  "绂诲瓙娉ㄥ叆鏈�",
+  "鍖栧鏈烘鎶涘厜璁惧",
+  "鐑鐞嗙倝",
+  "灏佽娴嬭瘯绔�",
+  "婵�鍏変慨璋冭澶�",
+  "鐢垫�ц兘娴嬭瘯鍙�",
+  "鍏夊妫�娴嬩华",
+  "鐪熺┖闀�鑶滄満",
+  "瓒呭0娉㈡竻娲楁満",
+  "X灏勭嚎妫�娴嬩华"
+]
+const ycList =  [
+  "铓�鍒绘繁搴﹀亸宸�",
+  "閿悎鍘嬪姏寮傚父",
+  "鏍″噯鏁版嵁鍋忕Щ",
+  "娌夌Н閫熺巼娉㈠姩",
+  "鍏夊埢瀵瑰噯鍋忓樊",
+  "绂诲瓙娉ㄥ叆鍓傞噺寮傚父",
+  "鎶涘厜鍘氬害涓嶅潎",
+  "娓╁害绋冲畾鎬у紓甯�",
+  "灏佽瀵嗗皝鎬т笉鑹�",
+  "鐢甸樆鍊煎亸宸�",
+  "鐏垫晱搴﹀紓甯�",
+  "鍝嶅簲鏃堕棿瓒呴檺",
+  "淇″彿婕傜Щ寮傚父",
+  "绾挎�у害鍋忓樊",
+  "闆剁偣婕傜Щ寮傚父",
+  "杩囪浇鎭㈠寮傚父",
+  "缁濈紭鐢甸樆涓嶈冻",
+  "浠嬭川鑰愬帇涓嶅悎鏍�",
+  "棰戠巼鍝嶅簲寮傚父",
+  "淇″櫔姣斾笉杈炬爣"
+];
+
+const cdList = [
+  "楂�", "楂�", "涓�", "涓�", "楂�",
+  "涓�", "涓�", "楂�", "楂�", "涓�",
+  "楂�", "涓�", "涓�", "涓�", "浣�",
+  "涓�", "楂�", "楂�", "涓�", "浣�"
+];
+const getStatusTagType = (status: string) => {
+  switch (status) {
+    case '楂�': return 'danger';
+    case '涓�': return 'warning';
+    case '浣�': return 'info';
+  }
+};
+
+function changeBatchDate(date: Date){
+  getBatch(date ? date : new Date())
+
 }
+async function queryWarnBatchList(){
+  const queryParams = {
+    pageNum: 1,
+    pageSize: 6
+  };
+  const res:any = await listBatch(queryParams);
+
+  if(res && res.rows){
+    warnBatchList.value = [];
+    res.rows.forEach((item,index) => {
+      item.gw = gwList[index];
+      item.yc = ycList[index];
+      item.cd = cdList[index];
+      item.batchTime = item.batchTime.substring(0,10);
+      warnBatchList.value.push(item);
+    })
+  }
+
+}
+
+const shortcuts = [
+  {
+    text: '浠婂ぉ',
+    value: new Date(),
+  },
+  {
+    text: '鏄ㄥぉ',
+    value: () => {
+      const date = new Date()
+      date.setTime(date.getTime() - 3600 * 1000 * 24)
+      return date
+    },
+  },
+  {
+    text: '涓�鍛ㄥ墠',
+    value: () => {
+      const date = new Date()
+      date.setTime(date.getTime() - 3600 * 1000 * 24 * 7)
+      return date
+    },
+  },
+]
+
+const disabledDate = (time: Date) => {
+  return time.getTime() > Date.now()
+}
+
+
+
+
+
+
+const goodProductsRate = (row) => {
+  if (row.num > 0 && row.okNum > 0) {
+    return Math.round((row.okNum / row.num) * 100);
+  }
+};
+
+
+
+
+
+
+
+
+
+
+const generateWorkOrder = (record) => {
+  // 宸ュ崟鐢熸垚閫昏緫
+  ElMessage.success(`宸蹭负 ${record.name} 鐢熸垚宸ュ崟`);
+};
+
+const handleDetail = (record) => {
+  router.push({ path: '/quality/detail', query: { id: record.id } });
+};
+
+const initHealthChart = () => {
+  if (healthChartRef.value) {
+    healthChart.value = echarts.init(healthChartRef.value);
+    const option = {
+      tooltip: {
+        trigger: 'axis',
+        axisPointer: {
+          type: 'shadow'
+        }
+      },
+      xAxis: {
+        type: 'category',
+        data: ['1鏈�', '2鏈�', '3鏈�', '4鏈�', '5鏈�', '6鏈�', '7鏈�', '8鏈�', '9鏈�', '10鏈�', '11鏈�', '12鏈�']
+      },
+      yAxis: {
+        type: 'value',
+        name: '寰楀垎',
+        minInterval: 1
+      },
+      series: [
+        {
+          name: '璐ㄩ噺鏁版嵁',
+          type: 'bar',
+          barWidth: '50%',
+          data: [
+            { value: 9.8, itemStyle: { color: '#52c41a' } },
+            { value: 9.9, itemStyle: { color: '#52c41a' } },
+            { value: 9.7, itemStyle: { color: '#52c41a' } },
+            { value: 9.8, itemStyle: { color: '#52c41a' } },
+            { value: 9.9, itemStyle: { color: '#52c41a' } },
+            { value: 9.8, itemStyle: { color: '#52c41a' } },
+            { value: 9.9, itemStyle: { color: '#52c41a' } },
+            { value: 9.8, itemStyle: { color: '#52c41a' } },
+            { value: 9.8, itemStyle: { color: '#52c41a' } }
+          ],
+          label: {
+            show: true,
+            position: 'top',
+            formatter: '{c}鍒�'
+          }
+        }
+      ]
+    };
+    healthChart.value.setOption(option);
+
+    window.addEventListener('resize', () => {
+      healthChart.value.resize();
+    });
+  }
+};
+
+const initBatchRateChart = () => {
+  if (batchRateTrendRef.value) {
+    batchRateChart.value = echarts.init(batchRateTrendRef.value);
+    const option = {
+      color: ['#FFBF00'],
+      tooltip: {
+        trigger: 'axis',
+        axisPointer: {
+          type: 'cross',
+          label: {
+            backgroundColor: '#6a7985'
+          }
+        }
+      },
+
+      xAxis: [
+        {
+          splitLine: { show: false },
+          type: 'category',
+          boundaryGap: false,
+          data: ['08-01', '08-02', '08-03', '08-04', '08-05', '08-06', '08-07']
+        }
+      ],
+      yAxis: [
+        {
+          splitLine: { show: false },
+          type: 'value',
+          name: '妫�娴嬪悎鏍肩巼',
+          min: 80, // 璁剧疆鏈�灏忓�间负90
+          max: 100, // 璁剧疆鏈�澶у�间负100
+          interval: 5, // 璁剧疆鍒诲害闂撮殧涓�1
+          axisLabel: {
+            formatter: '{value}%' // 娣诲姞鐧惧垎姣旂鍙�
+          }
+        }
+      ],
+      series: [
+        {
+          name: '',
+          type: 'line',
+          stack: 'Total',
+          smooth: true,
+          lineStyle: {
+            width: 0
+          },
+          showSymbol: false,
+          areaStyle: {
+            opacity: 0.8,
+            color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+              {
+                offset: 0,
+                color: 'rgb(128, 255, 165)'
+              },
+              {
+                offset: 1,
+                color: 'rgb(1, 191, 236)'
+              }
+            ])
+          },
+          emphasis: {
+            focus: 'series'
+          },
+          data: [99, 98, 95, 99, 92, 98, 96],
+
+        }
+      ]
+    };
+
+    option && batchRateChart.value.setOption(option);
+
+
+    window.addEventListener('resize', () => {
+      batchRateChart.value.resize();
+    });
+  }
+};
+
+const initNgChart = () => {
+  if (ngChartRef.value) {
+    ngChart.value = echarts.init(ngChartRef.value);
+    const option = {
+
+      tooltip: {
+        trigger: 'axis',
+        axisPointer: {
+          type: 'shadow'
+        }
+      },
+      grid: {
+        left: '120px', // 澧炲姞宸︿晶杈硅窛锛屼负鏍囩鐣欏嚭鏇村绌洪棿
+        top: '0px',
+      },
+      xAxis: {
+        type: 'value',
+        boundaryGap: [0, 0.01],
+        splitLine: { show: false }
+      },
+      yAxis: {
+        splitLine: { show: false },
+        type: 'category',
+        data: [
+          '闈欐�佹秷鑰楃數娴�2',
+          '鍥炲樊',
+          '鐭矾淇濇姢娑堣�楃數娴�(榛�)2',
+          '鍔ㄦ�佹秷鑰楃數娴�2',
+          '璺濈',
+          '鍘嬮檷(榛�)2'
+        ]
+      },
+      series: [
+        {
+          name: '',
+          type: 'bar',
+          barWidth: '60%',
+          data: [100, 90, 80, 70, 60, 10],
+          itemStyle: {
+            color: '#faad14'  // 淇敼鏌辩姸鍥鹃鑹�
+          },
+          label: {
+            show: true,
+            position: 'right',
+            formatter: '{c}娆�'
+          }
+        }
+      ]
+    };
+
+    option && ngChart.value.setOption(option);
+
+
+
+    window.addEventListener('resize', () => {
+      ngChart.value.resize();
+    });
+  }
+};
+
+const getHealth = async () => {
+  const res: any = await queryQualityHealth();
+  if (res && res.yAxis) {
+    const xAxisData = [];
+    const minValue = res.yAxis.reduce((min, item) => {
+      return min === null ? item.value : Math.min(min, item.value);
+    }, null);
+    res.yAxis.forEach((item, index) => {
+      if (item.value >= 9.5) {
+        item.itemStyle = { color: '#52c41a' };
+      } else if (item.value < 9.5 && item.value >= 9.0) {
+        item.itemStyle = { color: '#faad14' };
+      } else {
+        item.itemStyle = { color: '#f5222d' };
+      }
+      if (item.value == minValue) {
+        item.itemStyle = { color: '#faad14' };
+      }
+      xAxisData.push(item);
+    });
+    updateHealthData(res.xAxis, xAxisData);
+  }
+};
+
+const getBatch = async (date = new Date()) => {
+  loading.value = true;
+
+  const res: any = await queryBatchList({
+    pageNum: 1,
+    pageSize: 10,
+    params: {
+      startTime: formatDate(date) + ' 00:00:00',
+      endTime: formatDate(date) + ' 23:59:59'
+    }
+  });
+  if (!res || !res.rows) {
+    return;
+  }
+  batchList.value = res.rows;
+
+  checkNum.value = res.rows.reduce((sum, item) => sum + (item.num || 0), 0);
+
+  ngCountNum.value = res.rows.reduce((sum, item) => sum + (item.ngNum || 0), 0);
+  // 璁$畻oknum鎬诲拰
+  const totalOkNum = res.rows.reduce((sum, item) => sum + (item.okNum || 0), 0);
+  // 璁$畻鑹搧鐜� (閬垮厤闄や互0鐨勬儏鍐�)
+  const yieldRate = checkNum.value > 0 ? (totalOkNum / checkNum.value) * 100 : 0;
+  qualityRate.value = Number(yieldRate.toFixed(2));
+  batchScore.value =  Number(((yieldRate/10 )-0.1).toFixed(1));
+  if(batchScore.value == -0.1){
+    batchScore.value = 0;
+  }
+  loading.value = false;
+};
+
+const getPwbatch = async () => {
+  const res: any = await queryPwbatchList();
+  if (res && res.yAxis) {
+    updatePwbatchData(res.xAxis, res.yAxis);
+  }
+};
+
+
+const getNgrank = async () => {
+  const res: any = await queryNgrank();
+  if (res && res.yAxis) {
+    updateNgrankData(res.xAxis, res.yAxis);
+  }
+};
+
+const formatDate = (date) => {
+  const year = date.getFullYear();
+  const month = String(date.getMonth() + 1).padStart(2, '0');
+  const day = String(date.getDate()).padStart(2, '0');
+  return `${year}-${month}-${day}`;
+};
+
+function updateHealthData(xAxis, yAxis) {
+  healthChart.value.setOption({
+    xAxis: {
+      type: 'category',
+      data: xAxis
+    },
+    series: [
+      {
+        data: yAxis
+      }
+    ]
+  });
+}
+
+
+function updatePwbatchData(xAxis, yAxis) {
+  batchRateChart.value.setOption({
+    xAxis: {
+      type: 'category',
+      data: xAxis
+    },
+    series: [
+      {
+        data: yAxis
+      }
+    ]
+  });
+}
+
+
+function updateNgrankData(xAxis, yAxis) {
+  ngChart.value.setOption({
+    yAxis: {
+      type: 'category',
+      data: xAxis,
+      inverse: true,
+    },
+    series: [
+      {
+        data: yAxis
+      }
+    ]
+  });
+}
+
+onMounted(() => {
+  queryWarnBatchList();
+  initHealthChart();
+  initBatchRateChart();
+  initNgChart();
+  getHealth();
+  getBatch();
+  getPwbatch();
+  getNgrank();
+});
 </script>
 
 <style scoped lang="scss">
-.home {
-  blockquote {
-    padding: 10px 20px;
-    margin: 0 0 20px;
-    font-size: 17.5px;
-    border-left: 5px solid #eee;
-  }
-  hr {
-    margin-top: 20px;
-    margin-bottom: 20px;
-    border: 0;
-    border-top: 1px solid #eee;
-  }
-  .col-item {
-    margin-bottom: 20px;
-  }
+.h-500 {
+  height: 500px;
+}
 
-  ul {
-    padding: 0;
-    margin: 0;
-  }
+.card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  font-weight: bold;
+}
 
-  font-family: "open sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
-  font-size: 13px;
-  color: #676a6c;
-  overflow-x: hidden;
+.grid {
+  display: grid;
+}
 
-  ul {
-    list-style-type: none;
-  }
+.grid-cols-1 {
+  grid-template-columns: repeat(1, minmax(0, 1fr));
+}
 
-  h4 {
-    margin-top: 0px;
-  }
+.grid-cols-2 {
+  grid-template-columns: repeat(2, minmax(0, 1fr));
+}
 
-  h2 {
-    margin-top: 10px;
-    font-size: 26px;
-    font-weight: 100;
-  }
+.gap-4 {
+  gap: 1rem;
+}
 
-  p {
-    margin-top: 10px;
+.mb-6 {
+  margin-bottom: 1.5rem;
+}
 
-    b {
-      font-weight: 700;
-    }
-  }
+.p-5 {
+  padding: 1.25rem;
+}
 
-  .update-log {
-    ol {
-      display: block;
-      list-style-type: decimal;
-      margin-block-start: 1em;
-      margin-block-end: 1em;
-      margin-inline-start: 0;
-      margin-inline-end: 0;
-      padding-inline-start: 40px;
-    }
+.w-full {
+  width: 100%;
+}
+
+.h-400 {
+  height: 400px;
+}
+
+.h-420 {
+  height: 420px;
+}
+
+.bg-blue-50 {
+  background-color: #eff6ff;
+}
+
+.bg-yellow-50 {
+  background-color: #fffbeb;
+}
+
+.bg-red-50 {
+  background-color: #fef2f2;
+}
+
+.bg-green-50 {
+  background-color: #f0fdf4;
+}
+
+.rounded {
+  border-radius: 0.25rem;
+}
+
+.text-sm {
+  font-size:14px;
+}
+
+.text-xl {
+  font-size: 14px;
+}
+
+.font-bold {
+  font-weight: 700;
+}
+
+.text-gray-600 {
+  color: #4b5563;
+}
+
+@media (min-width: 768px) {
+  .md\:grid-cols-2 {
+    grid-template-columns: repeat(2, minmax(0, 1fr));
   }
 }
-</style>
 
+.statistic-footer {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  flex-wrap: wrap;
+  font-size: 12px;
+  color: var(--el-text-color-regular);
+  margin-top: 16px;
+}
+
+.statistic-footer .footer-item {
+  font-size: 14px;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.statistic-footer .footer-item span:last-child {
+  display: inline-flex;
+  align-items: center;
+  margin-left: 4px;
+}
+
+.green {
+  color: var(--el-color-success);
+}
+
+.red {
+  color: var(--el-color-error);
+}
+</style>

--
Gitblit v1.9.3