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                   |  946 ++++++++++++++++-
 src/assets/images/quailty/q1.png      |    0 
 /dev/null                             |  856 ----------------
 src/api/qms/index/index.ts            |   43 
 src/assets/images/quailty/order.png   |    0 
 src/assets/images/quailty/q2.png      |    0 
 src/views/qms/quality/index.vue       |    2 
 src/views/qms/quality/detail.vue      | 1244 +++++++++++++++++++++++
 src/assets/images/quailty/q4.png      |    0 
 src/assets/images/quailty/q3.png      |    0 
 src/assets/images/quailty/product.jpg |    0 
 11 files changed, 2,171 insertions(+), 920 deletions(-)

diff --git a/src/api/qms/index/index.ts b/src/api/qms/index/index.ts
new file mode 100644
index 0000000..49da19a
--- /dev/null
+++ b/src/api/qms/index/index.ts
@@ -0,0 +1,43 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { BatchQuery, BatchVO } from '@/api/qms/batch/types';
+
+/**
+ * 鏌ヨ璐ㄩ噺鍋ュ悍搴�
+ * @param query
+ * @returns {*}
+ */
+
+export const queryQualityHealth = (): AxiosPromise<any> => {
+  return request({
+    url: '/qms/quality/health',
+    method: 'get'
+  });
+};
+
+// 鏌ヨ鎵规
+export const queryBatchList = (query?: BatchQuery): AxiosPromise<BatchVO[]> => {
+  return request({
+    url: '/qms/quality/batch',
+    method: 'get',
+    params: query
+  });
+};
+
+export const queryPwbatchList = (): AxiosPromise<any> => {
+  return request({
+    url: '/qms/quality/pwbatch',
+    method: 'get'
+  });
+};
+
+export const queryNgrank = (): AxiosPromise<any> => {
+  return request({
+    url: '/qms/quality/ngrank',
+    method: 'get'
+  });
+};
+
+
+
+
diff --git a/src/assets/images/quailty/order.png b/src/assets/images/quailty/order.png
new file mode 100644
index 0000000..660a2ac
--- /dev/null
+++ b/src/assets/images/quailty/order.png
Binary files differ
diff --git a/src/assets/images/quailty/product.jpg b/src/assets/images/quailty/product.jpg
new file mode 100644
index 0000000..03fa25b
--- /dev/null
+++ b/src/assets/images/quailty/product.jpg
Binary files differ
diff --git a/src/assets/images/quailty/q1.png b/src/assets/images/quailty/q1.png
new file mode 100644
index 0000000..bdd1b58
--- /dev/null
+++ b/src/assets/images/quailty/q1.png
Binary files differ
diff --git a/src/assets/images/quailty/q2.png b/src/assets/images/quailty/q2.png
new file mode 100644
index 0000000..607bf00
--- /dev/null
+++ b/src/assets/images/quailty/q2.png
Binary files differ
diff --git a/src/assets/images/quailty/q3.png b/src/assets/images/quailty/q3.png
new file mode 100644
index 0000000..a49d2cb
--- /dev/null
+++ b/src/assets/images/quailty/q3.png
Binary files differ
diff --git a/src/assets/images/quailty/q4.png b/src/assets/images/quailty/q4.png
new file mode 100644
index 0000000..6b7eff7
--- /dev/null
+++ b/src/assets/images/quailty/q4.png
Binary files differ
diff --git a/src/views/index.vue b/src/views/index.vue
index 85a21e8..714f6a7 100644
--- a/src/views/index.vue
+++ b/src/views/index.vue
@@ -1,85 +1,905 @@
 <template>
   <div class="app-container home">
-    <el-row :gutter="20">
-      <el-col :sm="24" :lg="12" style="padding-left: 20px">
-        <h2>鍏板疂杞﹂棿璐ㄩ噺绠$悊绯荤粺</h2>
+    <div class="p-5">
+      <div style="display: flex" class="gap-4">
 
-      </el-col>
+        <el-card style="width: 100%;flex: 1;" class="mb-4">
 
-      <el-col :sm="24" :lg="12" style="padding-left: 20px">
+       <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-col>
-    </el-row>
-    <el-divider />
+
+        </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" lang="ts">
-const goTarget = (url: string) => {
-  window.open(url, '__blank');
+import { onMounted, ref } from 'vue';
+import { useRouter } from 'vue-router';
+import { ElMessage } from 'element-plus';
+import * as echarts from 'echarts';
+
+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;
+}
+
+.grid {
+  display: grid;
+}
+
+.grid-cols-1 {
+  grid-template-columns: repeat(1, minmax(0, 1fr));
+}
+
+.grid-cols-2 {
+  grid-template-columns: repeat(2, minmax(0, 1fr));
+}
+
+.gap-4 {
+  gap: 1rem;
+}
+
+.mb-6 {
+  margin-bottom: 1.5rem;
+}
+
+.p-5 {
+  padding: 1.25rem;
+}
+
+.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));
   }
+}
 
-  font-family: 'open sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
-  font-size: 13px;
-  color: #676a6c;
-  overflow-x: hidden;
+.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;
+}
 
-  ul {
-    list-style-type: none;
-  }
+.statistic-footer .footer-item {
+  font-size: 14px;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
 
-  h4 {
-    margin-top: 0px;
-  }
+.statistic-footer .footer-item span:last-child {
+  display: inline-flex;
+  align-items: center;
+  margin-left: 4px;
+}
 
-  h2 {
-    margin-top: 10px;
-    font-size: 26px;
-    font-weight: 100;
-  }
+.green {
+  color: var(--el-color-success);
+}
 
-  p {
-    margin-top: 10px;
-
-    b {
-      font-weight: 700;
-    }
-  }
-
-  .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;
-    }
-  }
+.red {
+  color: var(--el-color-error);
 }
 </style>
diff --git a/src/views/qms/ai/detail.vue b/src/views/qms/ai/detail.vue
deleted file mode 100644
index 60d491e..0000000
--- a/src/views/qms/ai/detail.vue
+++ /dev/null
@@ -1,856 +0,0 @@
-<template>
-  <div class="device-detail-container">
-    <el-page-header @back="goBack">
-      <template #content>
-        <span class="text-large font-600 mr-3"> SMT璐寸墖鏈洪娴嬫�х淮鎶よ鎯�</span>
-      </template>
-    </el-page-header>
-
-    <el-row :gutter="16" class="mt-4">
-      <!-- 璁惧鍥剧墖鍜岃澶囧熀鏈俊鎭悎骞� -->
-      <el-col :span="10">
-        <el-card class="mb-4" :style="{ height: '440px' }">
-          <template #header>
-            <div class="card-header">
-              <span>璁惧淇℃伅</span>
-            </div>
-          </template>
-          <el-row :gutter="16">
-            <el-col :span="12">
-              <div class="device-image-container">
-                <img :src="deviceInfo.imageUrl" alt="璁惧鍥剧墖" class="device-image" />
-              </div>
-            </el-col>
-            <el-col :span="12">
-              <el-descriptions border :column="1"  class="custom-descriptions">
-                <el-descriptions-item label="璁惧鍚嶇О">{{ deviceInfo.deviceName }}</el-descriptions-item>
-                <el-descriptions-item label="璁惧绫诲瀷">{{ deviceInfo.deviceType }}</el-descriptions-item>
-                <el-descriptions-item label="璁惧缂栧彿">{{ deviceInfo.deviceId }}</el-descriptions-item>
-                <el-descriptions-item label="瀹夎鏃ユ湡">{{ deviceInfo.installDate }}</el-descriptions-item>
-                <el-descriptions-item label="浣跨敤骞撮檺">{{ deviceInfo.serviceLife }}骞�</el-descriptions-item>
-                <el-descriptions-item label="褰撳墠鐘舵��">
-                  <el-tag :type="getStatusTagType(deviceInfo.status)">{{ deviceInfo.status }}</el-tag>
-                </el-descriptions-item>
-              </el-descriptions>
-            </el-col>
-          </el-row>
-        </el-card>
-      </el-col>
-
-      <!-- 璁惧鍋ュ悍鐘舵�佷笌缁存姢寤鸿 -->
-      <el-col :span="14">
-        <el-card class="mb-4" :style="{ height: '440px' }">
-          <template #header>
-            <div class="card-header">
-              <span>璁惧鍋ュ悍鐘舵�佷笌缁存姢寤鸿</span>
-            </div>
-          </template>
-          <el-row :gutter="16">
-            <el-col :span="8">
-              <el-statistic
-                title="鏁翠綋鍋ュ悍搴�"
-                :value="healthData.overallHealth"
-                :precision="0"
-                :suffix="'%'"
-                :value-style="{ color: healthData.healthColor }"
-              />
-            </el-col>
-            <el-col :span="8">
-              <el-statistic
-                title="棰勬祴鍓╀綑瀵垮懡"
-                :value="healthData.predictedLife"
-                :suffix="'澶�'"
-              />
-            </el-col>
-            <el-col :span="8">
-              <el-statistic
-                title="鏁呴殰椋庨櫓绛夌骇"
-                :value="healthData.riskLevel"
-                :value-style="{ color: healthData.riskColor }"
-              />
-            </el-col>
-          </el-row>
-          <div class="mt-4">
-            <el-progress
-              :percentage="healthData.overallHealth"
-              :color="healthData.healthColor"
-              :show-text="false"
-            />
-          </div>
-
-          <el-divider content-position="left">棰勬祴鎬х淮鎶ゅ缓璁�</el-divider>
-          <div class="table-container">
-
-          <el-table
-            ref="maintenanceTable"
-            :data="displayMaintenanceData"
-            height="246"
-            size="large"
-            stripe
-          >
-            <el-table-column prop="type" label="缁存姢绫诲瀷" />
-            <el-table-column prop="content" label="缁存姢鍐呭" />
-            <el-table-column prop="suggestedTime" label="寤鸿鏃堕棿" />
-            <el-table-column prop="urgency" label="绱ф�ョ▼搴�">
-              <template #default="{ row }">
-                <el-tag :type="getUrgencyTagType(row.urgency)">{{ row.urgency }}</el-tag>
-              </template>
-            </el-table-column>
-            <el-table-column label="鎿嶄綔" width="80">
-              <template #default="{ row }">
-                <el-button link type="primary" size="small" @click="handleMaintenance(row)">澶勭悊</el-button>
-              </template>
-            </el-table-column>
-          </el-table>
-
-          </div>
-        </el-card>
-      </el-col>
-
-      <el-col :span="24">
-        <el-card class="mb-4">
-          <template #header>
-            <div class="card-header">
-              <span>璁惧鏁版嵁</span>
-            </div>
-          </template>
-          <el-row :gutter="16">
-            <el-col :span="4">
-              <el-statistic title="X杞存�荤Щ鍔ㄨ窛绂�" :value="healthData.xAxisTravel" :precision="2" :suffix="'km'">
-                <template #prefix>
-                  <el-icon  style="vertical-align: -0.125em"><TrendCharts /></el-icon>
-                </template>
-              </el-statistic>
-            </el-col>
-            <el-col :span="4">
-              <el-statistic title="Y杞存�荤Щ鍔ㄨ窛绂�" :value="healthData.yAxisTravel" :precision="2" :suffix="'km'">
-                <template #prefix>
-                  <el-icon  style="vertical-align: -0.125em"><TrendCharts /></el-icon>
-                </template>
-              </el-statistic>
-            </el-col>
-            <el-col :span="4">
-              <el-statistic title="鍗″甫娆℃暟" :value="healthData.tapeJamCount" :suffix="'娆�'">
-                <template #prefix>
-                  <el-icon  style="vertical-align: -0.125em"><Warning /></el-icon>
-                </template>
-              </el-statistic>
-            </el-col>
-            <el-col :span="4">
-              <el-statistic title="鍗℃枡娆℃暟" :value="healthData.materialJamCount" :suffix="'娆�'">
-                <template #prefix>
-                  <el-icon  style="vertical-align: -0.125em"><Warning /></el-icon>
-                </template>
-              </el-statistic>
-            </el-col>
-            <el-col :span="4">
-              <el-statistic title="鎷兼澘鏁�" :value="healthData.panelCount" :suffix="'鍧�'">
-                <template #prefix>
-                  <el-icon  style="vertical-align: -0.125em"><Grid /></el-icon>
-                </template>
-              </el-statistic>
-            </el-col>
-            <el-col :span="4">
-              <el-statistic title="鍑洪敊鍋滄満鏃堕棿" :value="healthData.downtime" :suffix="'绉�'">
-                <template #prefix>
-                  <el-icon  style="vertical-align: -0.125em"><Clock /></el-icon>
-                </template>
-              </el-statistic>
-            </el-col>
-          </el-row>
-        </el-card>
-      </el-col>
-    </el-row>
-
-    <!-- 瀹炴椂鏁版嵁瓒嬪娍鍥� -->
-    <el-card class="mb-4">
-      <template #header>
-        <div class="card-header">
-          <span>瀹炴椂鏁版嵁瓒嬪娍鍥�</span>
-        </div>
-      </template>
-      <el-row :gutter="16" class="mt-4">
-        <el-col :span="8">
-          <div id="ambientTemperatureHumidityChart" style="height: 300px;"></div>
-        </el-col>
-        <el-col :span="8">
-          <div id="motorTemperatureChart" style="height: 300px;"></div>
-        </el-col>
-        <el-col :span="8">
-          <div id="motorVibrationChart" style="height: 300px;"></div>
-        </el-col>
-      </el-row>
-
-      <!-- 璐磋澶�/鍚稿槾 -->
-      <el-row :gutter="16" class="mt-4">
-        <el-col :span="8">
-          <div id="nozzleVacuumChart" style="height: 300px;"></div>
-        </el-col>
-        <el-col :span="8">
-          <div id="nozzleFlowChart" style="height: 300px;"></div>
-        </el-col>
-        <el-col :span="8">
-          <div id="placementSpeedChart" style="height: 300px;"></div>
-        </el-col>
-      </el-row>
-    </el-card>
-
-    <el-row :gutter="16">
-      <!-- 閮ㄤ欢瀵垮懡棰勬祴 -->
-      <el-col :span="12">
-        <el-card class="mb-4" :style="{ height: '560px' }">
-          <template #header>
-            <div class="card-header">
-              <span>閮ㄤ欢瀵垮懡棰勬祴</span>
-            </div>
-          </template>
-          <el-table
-            :data="sparePartData"
-            size="large"
-            stripe
-          >
-            <el-table-column prop="name" label="閮ㄤ欢鍚嶇О" />
-            <el-table-column prop="currentLife" label="鐞嗚瀵垮懡" />
-            <el-table-column prop="remainingLife" label="棰勬祴鍓╀綑瀵垮懡" />
-            <el-table-column prop="status" label="鐘舵��">
-              <template #default="{ row }">
-                <el-tag :type="getStatusTagType(row.status)">{{ row.status }}</el-tag>
-              </template>
-            </el-table-column>
-          </el-table>
-        </el-card>
-      </el-col>
-
-      <!-- 鍘嗗彶缁存姢璁板綍 -->
-      <el-col :span="12">
-        <el-card class="mb-4" :style="{ height: '560px' }">
-          <template #header>
-            <div class="card-header">
-              <span>鍘嗗彶缁存姢璁板綍</span>
-            </div>
-          </template>
-          <el-timeline>
-            <el-timeline-item
-              v-for="item in historyData"
-              :key="item.id"
-              :type="getTimelineItemType(item.color)"
-              :timestamp="item.date"
-            >
-              {{ item.type }}: {{ item.description }}
-            </el-timeline-item>
-          </el-timeline>
-        </el-card>
-      </el-col>
-    </el-row>
-  </div>
-</template>
-
-<script lang="ts">
-import { defineComponent, reactive, onMounted, onUnmounted, ref, nextTick } from 'vue';
-import { useRouter } from 'vue-router';
-import * as echarts from 'echarts';
-import {
-  TrendCharts,
-  Warning,
-  Grid,
-  Clock
-} from '@element-plus/icons-vue';
-import { ElMessage } from 'element-plus';
-import img from '@/assets/images/JUKI.png';
-
-
-export default defineComponent({
-  name: 'SmtMachineDetail',
-  components: {
-    TrendCharts,
-    Warning,
-    Grid,
-    Clock
-  },
-  setup() {
-    const router = useRouter();
-
-    const goBack = () => {
-      router.go(-1);
-    };
-
-    // 妯℃嫙鏁版嵁
-    const deviceInfo = reactive({
-      deviceName: 'SMT璐寸墖鏈�',
-      deviceType: '璐寸墖鏈�',
-      deviceId: 'GPC2012A101',
-      installDate: '2012-06-08',
-      serviceLife: 15,
-      status: '杩愯涓�',
-      statusColor: '#52c41a',
-      imageUrl: img
-    });
-
-    const healthData = reactive({
-      overallHealth: 82,
-      healthColor: '#52c41a',
-      predictedLife: 635,
-      riskLevel: '浣庨闄�',
-      riskColor: '#1a7ac4',
-      xAxisTravel: 300.179,
-      yAxisTravel: 233.39,
-      tapeJamCount: 6,
-      materialJamCount: 15,
-      panelCount: 2480,
-      downtime: 4.5,
-    });
-
-    const maintenanceData = reactive([
-      {
-        key: '1',
-        type: '1鍙疯创瑁呯郴缁熺淮鎶�',
-        content: '鍚稿槾鐪熺┖鍘嬪姏鍋忎綆',
-        suggestedTime: '2025-07-05',
-        urgency: '涓瓑'
-      },
-      {
-        key: '6',
-        type: '4鍙疯创瑁呯郴缁熺淮鎶�',
-        content: 'T杞撮┈杈惧鍛藉憡鎬�',
-        suggestedTime: '2025-07-05',
-        urgency: '涓瓑'
-      },
-      {
-        key: '2',
-        type: '杩愬姩绯荤粺淇濆吇',
-        content: 'X/Y杞翠己鏈嶇數鏈烘鼎婊戞鏌�',
-        suggestedTime: '2025-06-20',
-        urgency: '浣�'
-      },
-      {
-        key: '3',
-        type: '渚涙枡绯荤粺妫�鏌�',
-        content: '椋炶揪鍗″甫/鍗℃枡娆℃暟娓呴浂',
-        suggestedTime: '2025-06-10',
-        urgency: '浣�'
-      },
-      {
-        key: '4',
-        type: '2鍙疯创瑁呯郴缁熺淮鎶�',
-        content: '鐪熺┖鍘嬪姏涓嶇ǔ瀹�',
-        suggestedTime: '2025-07-05',
-        urgency: '浣�'
-      },
-      {
-        key: '5',
-        type: '3鍙疯创瑁呯郴缁熺淮鎶�',
-        content: 'Z杞撮┈杈剧數娴佸紓甯�',
-        suggestedTime: '2025-07-05',
-        urgency: '浣�'
-      },
-      {
-        key: '7',
-        type: '5鍙疯创瑁呭ご缁存姢',
-        content: '鐪熺┖鍘嬪姏涓嶇ǔ瀹�',
-        suggestedTime: '2025-07-05',
-        urgency: '浣�'
-      },
-      {
-        key: '8',
-        type: '6鍙疯创瑁呭ご缁存姢',
-        content: '鐪熺┖鍘嬪姏涓嶇ǔ瀹�',
-        suggestedTime: '2025-07-05',
-        urgency: '浣�'
-      },
-    ]);
-
-    const getUrgencyTagType = (urgency: string) => {
-      switch (urgency) {
-        case '楂�': return 'danger';
-        case '涓瓑': return 'warning';
-        case '浣�': return 'success';
-        default: return 'info';
-      }
-    };
-
-    const getStatusTagType = (status: string) => {
-      switch (status) {
-        case '杩愯涓�': return 'success';
-        case '棰勮': return 'warning';
-        case '鍗遍櫓': return 'danger';
-        case '鑹ソ': return 'success';
-        default: return 'info';
-      }
-    };
-
-    const getTimelineItemType = (color: string) => {
-      switch (color) {
-        case 'green': return 'success';
-        case 'red': return 'danger';
-        default: return 'primary';
-      }
-    };
-
-    // const fetchDeviceData = async () => {
-    //   try {
-    //     const res = await getDeviceDataSmt();
-    //     Object.assign(healthData, res);
-    //   } catch (error) {
-    //     console.error('鑾峰彇璁惧鏁版嵁澶辫触:', error);
-    //   }
-    // };
-
-    let deviceDataInterval: number | undefined;
-    // fetchDeviceData();
-    // deviceDataInterval = setInterval(fetchDeviceData, 3000);
-
-    const sparePartData = reactive([
-      {
-        key: '1',
-        name: '1鍙疯创瑁呯郴缁烼杞翠己鏈嶇數鏈�',
-        currentLife: '15000灏忔椂',
-        remainingLife: '1451灏忔椂',
-        status: '棰勮'
-      },
-      {
-        key: '5',
-        name: '1鍙疯创瑁呯郴缁焃杞翠己鏈嶇數鏈�',
-        currentLife: '15000灏忔椂',
-        remainingLife: '7521灏忔椂',
-        status: '鑹ソ'
-      },
-      {
-        key: '9',
-        name: '1鍙疯创瑁呯郴缁熺湡绌虹數纾侀榾',
-        currentLife: '10000灏忔椂',
-        remainingLife: '2154灏忔椂',
-        status: '鑹ソ'
-      },
-      {
-        key: '2',
-        name: '1鍙疯创瑁呭ご',
-        currentLife: '1000000娆�',
-        remainingLife: '425542娆�',
-        status: '鑹ソ'
-      },
-      {
-        key: '6',
-        name: '2鍙疯创瑁呯郴缁烼杞翠己鏈嶇數鏈�',
-        currentLife: '15000灏忔椂',
-        remainingLife: '7540灏忔椂',
-        status: '鑹ソ'
-      },
-      {
-        key: '7',
-        name: '2鍙疯创瑁呯郴缁焃杞翠己鏈嶇數鏈�',
-        currentLife: '15000灏忔椂',
-        remainingLife: '7521灏忔椂',
-        status: '鑹ソ'
-      },
-      {
-        key: '9',
-        name: '2鍙疯创瑁呯郴缁熺湡绌虹數纾侀榾',
-        currentLife: '10000灏忔椂',
-        remainingLife: '2154灏忔椂',
-        status: '鑹ソ'
-      },
-      {
-        key: '8',
-        name: '2鍙疯创瑁呭ご',
-        currentLife: '1000000娆�',
-        remainingLife: '751251娆�',
-        status: '鑹ソ'
-      },
-      {
-        key: '3',
-        name: '椋炶揪',
-        currentLife: '96涓湀',
-        remainingLife: '43涓湀',
-        status: '鑹ソ'
-      },
-    ]);
-
-    const historyData = reactive([
-      {
-        id: '1',
-        date: '2025-07-22',
-        type: '瀹氭湡淇濆吇',
-        description: '瀹屾垚鏈堝害淇濆吇锛屼笣鏉嗗杞ㄦ敞娌癸紝鎶涙枡娓呯悊',
-        color: 'green'
-      },
-      {
-        id: '1',
-        date: '2025-06-18',
-        type: '瀹氭湡淇濆吇',
-        description: '瀹屾垚鏈堝害淇濆吇锛屾槗鎹熶欢鏇存崲',
-        color: 'green'
-      },
-      {
-        id: '1',
-        date: '2025-05-15',
-        type: '瀹氭湡淇濆吇',
-        description: '瀹屾垚瀛e害淇濆吇锛屾鏌ヨ繍鍔ㄧ郴缁熸鼎婊�',
-        color: 'green'
-      },
-      {
-        id: '1',
-        date: '2025-04-20',
-        type: '瀹氭湡淇濆吇',
-        description: '瀹屾垚鏈堝害淇濆吇锛岄槻灏樿繃婊ょ綉娓呯悊锛屽杞ㄦ敞娌�',
-        color: 'green'
-      },
-      {
-        id: '1',
-        date: '2025-03-16',
-        type: '瀹氭湡淇濆吇',
-        description: '瀹屾垚鏈堝害淇濆吇锛岀湡绌哄�兼牎鍑�',
-        color: 'green'
-      },
-      {
-        id: '1',
-        date: '2025-02-13',
-        type: '瀹氭湡淇濆吇',
-        description: '瀹屾垚鏈堝害淇濆吇锛屽惛鍢存鏌ユ洿鎹紝鎶涙枡娓呯悊锛岀浉鏈哄弬鏁版牎鍑�',
-        color: 'green'
-      },
-      {
-        id: '2',
-        date: '2025-01-20',
-        type: '鏁呴殰缁翠慨',
-        description: '淇鍚稿槾鍫靛闂',
-        color: 'red'
-      },
-      {
-        id: '3',
-        date: '2025-01-15',
-        type: '瀹氭湡淇濆吇',
-        description: '瀹屾垚骞村害淇濆吇锛岃创瑁呯郴缁熸牎鍑嗭紝鏄撴崯浠舵洿鎹紝鏍″噯瑙嗚绯荤粺',
-        color: 'green'
-      }
-    ]);
-
-    const handleMaintenance = (record: any) => {
-      console.log('澶勭悊缁存姢寤鸿:', record);
-      ElMessage.info(`澶勭悊缁存姢寤鸿: ${record.type}`);
-    };
-
-    const maintenanceTable = ref();
-
-    // 鐢ㄤ簬鏄剧ず鐨勭淮鎶ゆ暟鎹紙鏀寔鏃犻檺婊氬姩锛�
-    const displayMaintenanceData = ref([...maintenanceData]);
-    let scrollInterval: ReturnType<typeof setInterval> | undefined;
-
-    // 鍚姩鑷姩婊氬姩
-    const startAutoScroll = () => {
-      scrollInterval = setInterval(() => {
-        if (displayMaintenanceData.value.length > 0) {
-          // 灏嗙涓�椤圭Щ鍒版渶鍚�
-          const firstItem = displayMaintenanceData.value.shift();
-          if (firstItem) {
-            displayMaintenanceData.value.push(firstItem);
-          }
-        }
-      }, 1000); // 姣�3绉掓粴鍔ㄤ竴娆�
-    };
-
-    onMounted(() => {
-      nextTick(() => {
-        initCharts();
-        startAutoScroll(); // 鍚姩鑷姩婊氬姩
-      });
-    });
-
-    onUnmounted(() => {
-      if (deviceDataInterval) {
-        clearInterval(deviceDataInterval);
-      }
-      if (scrollInterval) {
-        clearInterval(scrollInterval);
-      }
-    });
-
-    const initCharts = () => {
-      // 鍥捐〃鍒濆鍖栦唬鐮侊紙涓庝箣鍓嶇浉鍚岋級
-      // 鍒濆鍖栧浘琛�
-      const initChart = (chartId: string, title: string, seriesConfig: Array<{ name: string, data: any[], unit: string, baseValue: number, fluctuation: number, color: string }>) => {
-        const chart = echarts.init(document.getElementById(chartId));
-
-        const updateChart = () => {
-          // 鐢熸垚鏂扮殑鏁版嵁鐐�
-          const now = new Date();
-          const time = `${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}`;
-
-          seriesConfig.forEach(s => {
-            const newValue = (s.baseValue + (Math.random() * 2 - 1) * s.fluctuation).toFixed(2);
-            s.data.push({
-              time,
-              value: newValue
-            });
-            if (s.data.length > 24) {
-              s.data.shift();
-            }
-          });
-
-          const option = {
-            title: {
-              text: title,
-              left: 'center'
-            },
-            tooltip: {
-              trigger: 'axis',
-              formatter: (params) => {
-                let result = `${params[0].axisValueLabel}<br/>`;
-                params.forEach(param => {
-                  result += `${param.marker} ${param.seriesName}: ${param.data}${seriesConfig[param.seriesIndex].unit}<br/>`;
-                });
-                return result;
-              }
-            },
-            grid: {
-              left: '8%', // 澧炲姞宸︿晶杈硅窛
-              right: '5%',
-              bottom: '10%',
-              containLabel: true
-            },
-            xAxis: {
-              type: 'category',
-              data: seriesConfig[0].data.map(item => item.time)
-            },
-            yAxis: seriesConfig.map((s, index) => ({
-              type: 'value',
-              name: s.name,
-              position: index === 0 ? 'left' : 'right',
-              axisLine: {
-                show: true,
-              },
-              axisLabel: {
-                formatter: (value) => `${value}${s.unit}`
-              }
-            })),
-            series: seriesConfig.map((s, index) => ({
-                name: s.name,
-                data: s.data.map(item => parseFloat(item.value)),
-                type: 'line',
-                smooth: true,
-                yAxisIndex: index,
-                lineStyle: {
-                  width: 2,
-                  color: s.color
-                },
-                areaStyle: {
-                  opacity: 0.8,
-                  color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
-                    {
-                      offset: 0,
-                      color: 'rgba(84,112,198,0.3)'
-                    },
-                    {
-                      offset: 1,
-                      color: 'rgba(84,112,198,0)'
-                    }
-                  ])
-                },
-              }
-            )),
-          };
-          chart.setOption(option);
-        };
-
-        seriesConfig.forEach(s => {
-          s.data = [];
-          // 鐢熸垚鍒濆鏁版嵁鐐癸紙60涓偣锛�5鍒嗛挓鏁版嵁锛�
-          for (let i = 0; i < 24; i++) {
-            const now = new Date(Date.now() - (24 - i) * 5000); // 鐢熸垚杩囧幓5鍒嗛挓鐨勬暟鎹�
-            const time = `${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}`;
-            const newValue = (s.baseValue + (Math.random() * 2 - 1) * s.fluctuation).toFixed(2);
-            s.data.push({
-              time,
-              value: newValue
-            });
-          }
-        })
-
-
-        // 鍒濆娓叉煋
-        updateChart();
-
-        // 姣�5绉掓洿鏂颁竴娆℃暟鎹�
-        const intervalId = setInterval(updateChart, 5000);
-
-        window.addEventListener('resize', () => {
-          chart.resize();
-        });
-
-
-      };
-
-      // 鍒濆鍖栧悇涓浘琛�
-      initChart('motorTemperatureChart', '浜ч噺', [
-        { name: '浜ч噺', data: [], unit: 'pcs/h', baseValue: 175, fluctuation: 25, color: '#5470C6' },
-      ]);
-
-      initChart('motorVibrationChart', '鎶涙枡鐜�', [
-        { name: '鎶涙枡鐜�', data: [], unit: '%', baseValue: 0.15, fluctuation: 0.01, color: '#5470C6' },
-      ]);
-
-      initChart('nozzleVacuumChart', '鍚稿槾鐪熺┖鍘嬪姏', [
-        { name: '鍘嬪姏', data: [], unit: 'kPa', baseValue: -45, fluctuation: 5, color: '#5470C6' },
-      ]);
-
-      initChart('nozzleFlowChart', '鍚稿槾鍚规皵鍘嬪姏', [
-        { name: '鍘嬪姏', data: [], unit: 'kPa', baseValue: 20, fluctuation: 5, color: '#5470C6' },
-      ]);
-
-      initChart('placementSpeedChart', '璐磋閫熷害', [
-        { name: '閫熷害', data: [], unit: 'chips/h', baseValue: 9000, fluctuation: 1500, color: '#5470C6' },
-      ]);
-
-      const ambientTemperatureData: any[] = [];
-      const ambientHumidityData: any[] = [];
-      initChart('ambientTemperatureHumidityChart', '鐜娓╂箍搴�', [
-        { name: '娓╁害', data: ambientTemperatureData, unit: '掳C', baseValue: 25, fluctuation: 1, color: '#5470C6' },
-        { name: '婀垮害', data: ambientHumidityData, unit: '%', baseValue: 60, fluctuation: 5, color: '#91cc75' }
-      ]);
-    };
-
-    return {
-      deviceInfo,
-      healthData,
-      maintenanceData,
-      displayMaintenanceData,
-      sparePartData,
-      historyData,
-      goBack,
-      getUrgencyTagType,
-      getStatusTagType,
-      getTimelineItemType,
-      handleMaintenance,
-      maintenanceTable,
-
-    };
-  }
-});
-</script>
-
-<style scoped>
-.device-detail-container {
-  padding: 16px;
-  background: #f0f2f5;
-}
-
-.page-header-content {
-  display: flex;
-  flex-direction: column;
-}
-
-.page-header-title {
-  font-size: 18px;
-  font-weight: bold;
-}
-
-.page-header-subtitle {
-  font-size: 14px;
-  color: #666;
-  margin-top: 4px;
-}
-
-.card-header {
-  font-weight: bold;
-}
-
-.device-image-container {
-  display: flex;
-  justify-content: center;
-  align-items: center;
-  height: 330px;
-  overflow: hidden;
-}
-
-.device-image {
-  max-width: 100%;
-  max-height: 100%;
-  object-fit: contain;
-}
-
-.mt-4 {
-  margin-top: 1rem;
-}
-
-.mb-4 {
-  margin-bottom: 1rem;
-}
-
-
-.custom-descriptions {
-  height: 357px; /* 璁剧疆鏁翠釜鎻忚堪鍒楄〃鐨勯珮搴� */
-}
-
-.custom-descriptions :deep(.el-descriptions__body) {
-  height: 100%;
-}
-
-.custom-descriptions :deep(.el-descriptions__table) {
-  height: 100%;
-}
-
-.custom-descriptions :deep(.el-descriptions__table tbody) {
-  height: 100%;
-  display: flex;
-  flex-direction: column;
-}
-
-.custom-descriptions :deep(.el-descriptions__table tr) {
-  flex: 1;
-  display: flex;
-}
-
-.custom-descriptions :deep(.el-descriptions__table td) {
-  flex: 1;
-  display: flex;
-  align-items: center;
-}
-
-.custom-descriptions :deep(.el-descriptions__table .el-descriptions__label) {
-  display: flex;
-  align-items: center;
-  justify-content: flex-start;
-}
-
-.custom-descriptions :deep(.el-descriptions__table .el-descriptions__content) {
-  display: flex;
-  align-items: center;
-  justify-content: flex-start;
-}
-
-/*
-.table-container {
-  position: relative;
-  height: 246px;
-  overflow: hidden;
-}
-
-.table-container :deep(.el-table__body-wrapper) {
-  overflow: hidden;
-}
-
-.table-container :deep(.el-table__body) {
-  animation: scrollTable 20s linear infinite;
-}
-
-.table-container:hover :deep(.el-table__body) {
-  animation-play-state: paused;
-}
-
-@keyframes scrollTable {
-  0% {
-    transform: translateY(0);
-  }
-  100% {
-    transform: translateY(-100%);
-  }
-}
-
-
-.table-container :deep(.el-table__header-wrapper) {
-  position: sticky;
-  top: 0;
-  background: white;
-  z-index: 10;
-}
-*/
-</style>
diff --git a/src/views/qms/quality/detail.vue b/src/views/qms/quality/detail.vue
new file mode 100644
index 0000000..a15460b
--- /dev/null
+++ b/src/views/qms/quality/detail.vue
@@ -0,0 +1,1244 @@
+<template>
+  <div class="device-detail-container">
+    <el-page-header @back="goBack">
+      <template #content>
+        <span class="text-large font-600 mr-3"> 鎵规璇︽儏鍒嗘瀽</span>
+      </template>
+    </el-page-header>
+
+    <el-row :gutter="16" class="mt-4">
+      <!-- 璁惧鍥剧墖鍜岃澶囧熀鏈俊鎭悎骞� -->
+      <el-col :span="10">
+        <el-card class="mb-4" :style="{ height: '440px' }">
+          <template #header>
+            <div class="card-header">
+              <span>鐢熶骇鎵规淇℃伅</span>
+            </div>
+          </template>
+          <el-row :gutter="16">
+            <el-col :span="12">
+              <div class="device-image-container">
+                <img :src="img" alt="璁惧鍥剧墖" class="device-image" />
+              </div>
+            </el-col>
+            <el-col :span="12">
+              <el-descriptions border :column="1"  class="custom-descriptions">
+                <el-descriptions-item label="鎵规缂栧彿">{{ batch.batchCode }}</el-descriptions-item>
+                <el-descriptions-item label="浜у搧鍨嬪彿">{{ batch.prodModel }}</el-descriptions-item>
+                <el-descriptions-item label="鐢熶骇绾�">A绾�</el-descriptions-item>
+                <el-descriptions-item label="鐢熶骇鏃堕棿">{{ batch.batchTime }}</el-descriptions-item>
+                <el-descriptions-item label="鐢熶骇鐘舵��">
+                  <el-tag v-if="batchIsToday(batch.batchTime)" type="primary">鐢熶骇涓�</el-tag>
+                  <el-tag v-else type="success">宸插畬鎴�</el-tag>
+                </el-descriptions-item>
+              </el-descriptions>
+            </el-col>
+          </el-row>
+        </el-card>
+      </el-col>
+
+      <!-- 璁惧鍋ュ悍鐘舵�佷笌缁存姢寤鸿 -->
+      <el-col :span="14">
+        <el-card class="mb-4" :style="{ height: '440px' }">
+          <template #header>
+            <div class="card-header">
+              <span>鐢熶骇璐ㄩ噺鍋ュ悍鐘舵�佷笌缁存姢寤鸿</span>
+            </div>
+          </template>
+          <el-row :gutter="16">
+            <el-col :span="8">
+              <el-statistic
+                title="鏁翠綋鍋ュ悍搴�"
+                :value="healthRate"
+                :precision="0"
+                :suffix="'%'"
+                :value-style="{ color: healthData.healthColor }"
+              />
+            </el-col>
+            <el-col :span="8">
+              <el-statistic
+                title="杩囩▼鑳藉姏鎸囨暟 (Cpk)"
+                :precision="2"
+                :value="healthData.predictedLife"
+
+              />
+            </el-col>
+            <el-col :span="8">
+              <el-statistic
+                title="璐ㄩ噺椋庨櫓绛夌骇"
+                :value="healthData.riskLevel"
+                :value-style="{ color: healthData.riskColor }"
+              />
+            </el-col>
+          </el-row>
+          <div class="mt-4">
+            <el-progress
+              :percentage="healthData.overallHealth"
+              :color="healthData.healthColor"
+              :show-text="false"
+            />
+          </div>
+
+          <el-divider content-position="left">棰勬祴鎬х淮鎶ゅ缓璁�</el-divider>
+          <div class="table-container">
+
+          <el-table
+            ref="maintenanceTable"
+            :data="displayMaintenanceData"
+            height="246"
+            size="large"
+            stripe
+          >
+            <el-table-column prop="type" label="缁存姢绫诲瀷" />
+            <el-table-column prop="content" label="缁存姢鍐呭" />
+            <el-table-column prop="suggestedTime" label="寤鸿鏃堕棿" />
+            <el-table-column prop="urgency" label="绱ф�ョ▼搴�">
+              <template #default="{ row }">
+                <el-tag :type="getUrgencyTagType(row.urgency)">{{ row.urgency }}</el-tag>
+              </template>
+            </el-table-column>
+            <el-table-column label="鎿嶄綔" width="80">
+              <template #default="{ row }">
+                <el-button link type="primary" size="small" @click="handleMaintenance(row)">澶勭悊</el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+
+          </div>
+        </el-card>
+      </el-col>
+
+      <el-col :span="24">
+        <el-card class="mb-4">
+          <template #header>
+            <div class="card-header">
+              <span>璐ㄩ噺鎸囨爣姹囨��</span>
+            </div>
+          </template>
+          <el-row :gutter="16">
+            <el-col :span="8" style="display: flex;justify-content: center;align-items: center">
+              <el-statistic title="鏈壒鑹巼" :value="healthRate" :precision="2" :suffix="'%'">
+                <template #prefix>
+<!--                  <el-icon  style="vertical-align: -0.125em"><TrendCharts /></el-icon>-->
+                </template>
+              </el-statistic>
+            </el-col>
+
+            <el-col :span="8" style="display: flex;justify-content: center;align-items: center">
+              <el-statistic title="涓嶈壇鍝佹暟" :value="batch.ngNum"   :suffix="'pcs'">
+                <template #prefix>
+<!--                  <el-icon  style="vertical-align: -0.125em"><TrendCharts /></el-icon>-->
+                </template>
+              </el-statistic>
+            </el-col>
+
+
+
+            <el-col :span="8" style="display: flex;justify-content: center;align-items: center">
+              <el-statistic title="浣庝簬骞冲潎姘村钩" :value="belowRate" :precision="2" :suffix="'%'">
+                <template #prefix>
+<!--                  <el-icon  style="vertical-align: -0.125em"><TrendCharts /></el-icon>-->
+                </template>
+              </el-statistic>
+            </el-col>
+          </el-row>
+
+
+
+        </el-card>
+      </el-col>
+    </el-row>
+
+    <!-- 瀹炴椂鏁版嵁瓒嬪娍鍥� -->
+    <el-card class="mb-4">
+      <template #header>
+        <div class="card-header">
+          <span>鐢熶骇鏁版嵁</span>
+        </div>
+      </template>
+      <el-row :gutter="16" class="mt-4">
+        <el-col :span="8">
+          <div id="ambientTemperatureHumidityChart" style="height: 300px;"></div>
+        </el-col>
+        <el-col :span="8">
+          <div id="motorTemperatureChart" style="height: 300px;"></div>
+        </el-col>
+        <el-col :span="8">
+          <div id="motorVibrationChart" style="height: 300px;"></div>
+        </el-col>
+      </el-row>
+
+      <!-- 璐磋澶�/鍚稿槾 -->
+      <el-row :gutter="16" class="mt-4">
+        <el-col :span="8">
+          <div id="nozzleVacuumChart" style="height: 300px;"></div>
+        </el-col>
+        <el-col :span="8">
+          <div id="nozzleFlowChart" style="height: 300px;"></div>
+        </el-col>
+        <el-col :span="8">
+          <div id="placementSpeedChart" style="height: 300px;"></div>
+        </el-col>
+      </el-row>
+    </el-card>
+
+    <el-row :gutter="16">
+      <!-- 閮ㄤ欢瀵垮懡棰勬祴 -->
+      <el-col :span="12">
+        <el-card class="mb-4" :style="{ height: '560px' }">
+          <template #header>
+            <div class="card-header">
+              <span>鍏抽敭閮ㄤ欢瀵垮懡棰勬祴</span>
+              <el-tooltip content="鍩轰簬璁惧杩愯鏁版嵁鍜屼紶鎰熷櫒鐩戞祴鐨勯娴嬫�х淮鎶ゅ垎鏋�" placement="top">
+                <el-icon><Warning /></el-icon>
+              </el-tooltip>
+            </div>
+          </template>
+
+
+
+
+          <div class="health-summary">
+            <el-row :gutter="16">
+              <el-col :span="8" class="summary-item">
+                <div class="summary-value" style="color: #67C23A;">{{ healthyCount }}</div>
+                <div class="summary-label">鍋ュ悍</div>
+              </el-col>
+              <el-col :span="8" class="summary-item">
+                <div class="summary-value" style="color: #E6A23C;">{{ warningCount }}</div>
+                <div class="summary-label">棰勮</div>
+              </el-col>
+              <el-col :span="8" class="summary-item">
+                <div class="summary-value" style="color: #F56C6C;">{{ criticalCount }}</div>
+                <div class="summary-label">绱ф��</div>
+              </el-col>
+            </el-row>
+          </div>
+
+          <el-table
+            :data="sensorComponentData"
+            stripe
+
+            :row-class-name="tableRowClassName"
+          >
+            <el-table-column prop="name" label="閮ㄤ欢鍚嶇О"   />
+            <el-table-column label="鍋ュ悍鐘舵��"  >
+              <template #default="{ row }">
+                <el-tag
+                  :type="getHealthStatusType(row.healthStatus)"
+                  size="small"
+                >
+                  {{ row.healthStatus }}
+                </el-tag>
+              </template>
+            </el-table-column>
+            <el-table-column label="鍓╀綑瀵垮懡" >
+              <template #default="{ row }">
+                <div class="life-progress">
+                  <el-progress
+                    :percentage="row.remainingPercentage"
+                    :color="getProgressColor(row.remainingPercentage)"
+                    :show-text="false"
+                    :stroke-width="12"
+                  />
+                  <span class="life-text">{{ row.remainingLife }}</span>
+                </div>
+              </template>
+            </el-table-column>
+            <el-table-column label="棰勬祴鏇存柊鏃堕棿" width="120">
+              <template #default="{ row }">
+                {{ row.lastUpdate }}
+              </template>
+            </el-table-column>
+            <el-table-column label="鎿嶄綔" width="80">
+              <template #default="{ row }">
+                <el-button
+                  link
+                  type="primary"
+                  size="small"
+                  @click="showComponentDetail(row)"
+                >
+                  璇︽儏
+                </el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+
+        </el-card>
+      </el-col>
+
+      <!-- 鍘嗗彶缁存姢璁板綍 -->
+      <el-col :span="12">
+        <el-card class="mb-4" :style="{ height: '560px' }">
+          <template #header>
+            <div class="card-header">
+              <span>鍘嗗彶寮傚父浜嬩欢鍒嗘瀽</span>
+            </div>
+          </template>
+          <el-timeline>
+            <el-timeline-item
+              v-for="item in historyData"
+              :key="item.id"
+              :type="getTimelineItemType(item.color)"
+              :timestamp="item.date"
+            >
+              {{ item.type }}: {{ item.description }}
+            </el-timeline-item>
+          </el-timeline>
+        </el-card>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+
+
+<script setup lang="ts">
+import { ref, reactive, onMounted, onUnmounted, nextTick } from 'vue';
+import { useRouter,useRoute } from 'vue-router';
+import * as echarts from 'echarts';
+import {
+  TrendCharts,
+  Warning,
+  Grid,
+  Clock
+} from '@element-plus/icons-vue';
+import { ElMessage } from 'element-plus';
+import img from  '@/assets/images/quailty/product.jpg'
+import { getBatch } from '@/api/qms/batch';
+import { BatchVO } from '@/api/qms/batch/types';
+
+const batch= ref<BatchVO>({});
+const router = useRouter();
+const route = useRoute();
+const batchId = route.query.id
+
+const healthRate = ref(0);
+const belowRate = ref(0);
+
+
+const goBack = () => {
+  router.go(-1);
+};
+
+
+function getBatchDetail(){
+  getBatch(batchId).then(res => {
+    if(res){
+      batch.value = res.data;
+      initCharts2();
+     if(batch.value && batch.value.num > 0 && batch.value.okNum > 0){
+       const yieldRate =   (batch.value.okNum / batch.value.num) * 100;
+       healthRate.value =  Number(yieldRate.toFixed(1));
+
+       if(healthRate.value < 80 ){
+         belowRate.value =  10.11;
+         healthData.riskLevel = "楂橀闄�"
+         healthData.riskColor = "#f56c6c"
+
+       }else if(healthRate.value>=80&& healthRate.value<90){
+         healthData.riskLevel = "涓闄�"
+         healthData.riskColor = "#faad14"
+         belowRate.value =  6.37;
+       } else if(healthRate.value>90&& healthRate.value<95){
+         belowRate.value =  3.15;
+       }  else if(healthRate.value>95&& healthRate.value<=100){
+         belowRate.value = 0.32 ;
+       }else {
+         belowRate.value = 0;
+
+       }
+     }
+
+    }
+  })
+}
+
+
+
+
+const healthData = reactive({
+  overallHealth: 82,
+  healthColor: '#52c41a',
+  predictedLife: 1.31,
+  riskLevel: '浣庨闄�',
+  riskColor: '#52c41a',
+  xAxisTravel: 300.179,
+  yAxisTravel: 233.39,
+  tapeJamCount: 6,
+  materialJamCount: 15,
+  panelCount: 2480,
+  downtime: 4.5,
+});
+// 鐢熸垚鐩稿鏃堕棿鍑芥暟
+const generateRelativeTime = (daysAgo) => {
+  const date = new Date();
+  date.setDate(date.getDate() - daysAgo);
+  return date.toISOString().split('T')[0];
+};
+
+const maintenanceData = reactive([
+  {
+    key: '1',
+    type: '1鍙疯创瑁呯郴缁熺淮鎶�',
+    content: '鍚稿槾鐪熺┖鍘嬪姏鍋忎綆锛岄渶瑕佹竻娲佹垨鏇存崲鍚稿槾',
+    suggestedTime: generateRelativeTime(3),
+    urgency: '涓瓑'
+  },
+  {
+    key: '2',
+    type: '2鍙峰洖娴佺剨鐐夌淮鎶�',
+    content: '娓╁尯娓╁害娉㈠姩瓒呰繃鏍囧噯鑼冨洿锛岄渶瑕佹牎鍑嗘俯搴︿紶鎰熷櫒',
+    suggestedTime: generateRelativeTime(1),
+    urgency: '浣�'
+  },
+  {
+    key: '3',
+    type: '3鍙稟OI妫�娴嬩华缁存姢',
+    content: '鐩告満闀滃ご鏈夌伆灏橈紝褰卞搷妫�娴嬬簿搴︼紝闇�瑕佹竻娲侀暅澶�',
+    suggestedTime: generateRelativeTime(2),
+    urgency: '浣�'
+  },
+  {
+    key: '4',
+    type: '4鍙烽敗鑶忓嵃鍒锋満缁存姢',
+    content: '鍒垁鍘嬪姏涓嶅潎鍖�锛岄渶瑕佽皟鏁存垨鏇存崲鍒垁',
+    suggestedTime: generateRelativeTime(3),
+    urgency: '涓瓑'
+  },
+  {
+    key: '5',
+    type: '5鍙稴PI妫�娴嬩华缁存姢',
+    content: '婵�鍏夋祴閲忔ā鍧楅渶瑕侀噸鏂版牎鍑�',
+    suggestedTime: generateRelativeTime(5),
+    urgency: '涓瓑'
+  },
+  {
+    key: '6',
+    type: '6鍙稾-Ray妫�娴嬩华缁存姢',
+    content: 'X灏勭嚎婧愬伐浣滄椂闂存帴杩戠淮鎶ゅ懆鏈燂紝闇�瑕侀闃叉�х淮鎶�',
+    suggestedTime: generateRelativeTime(4),
+    urgency: '浣�'
+  }
+]);
+
+const getUrgencyTagType = (urgency: string) => {
+  switch (urgency) {
+    case '楂�': return 'danger';
+    case '涓瓑': return 'warning';
+    case '浣�': return 'success';
+    default: return 'info';
+  }
+};
+
+const batchIsToday = (date: string) => {
+  const today = new Date();
+  const inputDate = new Date(date);
+
+  return inputDate.toDateString() === today.toDateString();
+};
+
+const getTimelineItemType = (color: string) => {
+  switch (color) {
+    case 'green': return 'success';
+    case 'red': return 'danger';
+    default: return 'primary';
+  }
+};
+
+const sparePartData = reactive([
+  {
+    key: '1',
+    name: '1鍙疯创瑁呯郴缁烼杞翠己鏈嶇數鏈�',
+    currentLife: '15000灏忔椂',
+    remainingLife: '1451灏忔椂',
+    status: '棰勮'
+  },
+  {
+    key: '5',
+    name: '1鍙疯创瑁呯郴缁焃杞翠己鏈嶇數鏈�',
+    currentLife: '15000灏忔椂',
+    remainingLife: '7521灏忔椂',
+    status: '鑹ソ'
+  },
+  {
+    key: '9',
+    name: '1鍙疯创瑁呯郴缁熺湡绌虹數纾侀榾',
+    currentLife: '10000灏忔椂',
+    remainingLife: '2154灏忔椂',
+    status: '鑹ソ'
+  },
+  {
+    key: '2',
+    name: '1鍙疯创瑁呭ご',
+    currentLife: '1000000娆�',
+    remainingLife: '425542娆�',
+    status: '鑹ソ'
+  },
+  {
+    key: '6',
+    name: '2鍙疯创瑁呯郴缁烼杞翠己鏈嶇數鏈�',
+    currentLife: '15000灏忔椂',
+    remainingLife: '7540灏忔椂',
+    status: '鑹ソ'
+  },
+  {
+    key: '7',
+    name: '2鍙疯创瑁呯郴缁焃杞翠己鏈嶇數鏈�',
+    currentLife: '15000灏忔椂',
+    remainingLife: '7521灏忔椂',
+    status: '鑹ソ'
+  },
+  {
+    key: '9',
+    name: '2鍙疯创瑁呯郴缁熺湡绌虹數纾侀榾',
+    currentLife: '10000灏忔椂',
+    remainingLife: '2154灏忔椂',
+    status: '鑹ソ'
+  },
+  {
+    key: '8',
+    name: '2鍙疯创瑁呭ご',
+    currentLife: '1000000娆�',
+    remainingLife: '751251娆�',
+    status: '鑹ソ'
+  },
+  {
+    key: '3',
+    name: '椋炶揪',
+    currentLife: '96涓湀',
+    remainingLife: '43涓湀',
+    status: '鑹ソ'
+  },
+]);
+
+// 寮傚父浜嬩欢鍒嗘瀽鏁版嵁
+// 寮傚父浜嬩欢鍒嗘瀽鏁版嵁
+const historyData = reactive([
+  {
+    id: '1',
+    date: '2025-09-12 14:25:36',
+    type: '铓�鍒绘繁搴﹀紓甯�',
+    description: '寰満鐢电郴缁熻殌鍒绘満妫�娴嬪埌铓�鍒绘繁搴﹀紓甯革細2.8渭m (姝e父鑼冨洿: 2.3-2.5渭m)',
+    color: 'red'
+  },
+  {
+    id: '2',
+    date: '2025-08-21 13:40:22',
+    type: '娓╁害绋冲畾鎬у紓甯�',
+    description: '鐑鐞嗙倝娓╁害娉㈠姩瓒呰繃鍏佽鑼冨洿卤0.5掳C锛岃揪鍒奥�0.8掳C',
+    color: 'orange'
+  },
+  {
+    id: '3',
+    date: '2025-08-03 12:15:48',
+    type: '鐢甸樆鍊煎亸宸�',
+    description: '妫�娴嬪埌浼犳劅鍣ㄧ數闃诲�艰秴鍑哄叕宸寖鍥绰�5%锛屽疄闄呭亸宸负+7.2%',
+    color: 'red'
+  },
+  {
+    id: '4',
+    date: '2025-07-12 11:30:15',
+    type: '娌夌Н閫熺巼娉㈠姩',
+    description: '钖勮啘娌夌Н璁惧娌夌Н閫熺巼涓嶇ǔ瀹氾紝娉㈠姩骞呭害杈惧埌卤8%',
+    color: 'orange'
+  },
+  {
+    id: '5',
+    date: '2025-06-01 10:45:33',
+    type: '鏍″噯鏁版嵁鍋忕Щ',
+    description: '浼犳劅鍣ㄦ牎鍑嗙珯妫�娴嬪埌闆剁偣婕傜Щ0.3mV锛岄渶瑕侀噸鏂版牎鍑�',
+    color: 'yellow'
+  },
+  {
+    id: '6',
+    date: '2025-04-17 09:20:57',
+    type: '閿悎鍘嬪姏寮傚父',
+    description: '鏅跺渾閿悎鏈哄帇鍔涗紶鎰熷櫒璇绘暟寮傚父锛屽疄闄呭帇鍔涙瘮璁惧畾鍊间綆12%',
+    color: 'orange'
+  },
+  {
+    id: '7',
+    date: '2025-03-26 08:55:12',
+    type: '鍏夊妫�娴嬪紓甯�',
+    description: '鍏夊妫�娴嬩华鍙戠幇3涓紶鎰熷櫒琛ㄩ潰瀛樺湪寰皬鍒掔棔',
+    color: 'yellow'
+  },
+  {
+    id: '8',
+    date: '2025-01-3 08:30:45',
+    type: '鐪熺┖搴︿笉瓒�',
+    description: '鐪熺┖闀�鑶滄満鐪熺┖搴︿笅闄嶈嚦0.005Pa锛屼綆浜庢爣鍑�0.001Pa',
+    color: 'red'
+  },
+
+]);
+
+const handleMaintenance = (record: any) => {
+  console.log('澶勭悊缁存姢寤鸿:', record);
+  // ElMessage.info(`澶勭悊缁存姢寤鸿: ${record.type}`);
+};
+
+const maintenanceTable = ref();
+
+// 鐢ㄤ簬鏄剧ず鐨勭淮鎶ゆ暟鎹紙鏀寔鏃犻檺婊氬姩锛�
+const displayMaintenanceData = ref([...maintenanceData]);
+let scrollInterval: ReturnType<typeof setInterval> | undefined;
+
+// 鍚姩鑷姩婊氬姩
+const startAutoScroll = () => {
+  scrollInterval = setInterval(() => {
+    if (displayMaintenanceData.value.length > 0) {
+      // 灏嗙涓�椤圭Щ鍒版渶鍚�
+      const firstItem = displayMaintenanceData.value.shift();
+      if (firstItem) {
+        displayMaintenanceData.value.push(firstItem);
+      }
+    }
+  }, 1000); // 姣�3绉掓粴鍔ㄤ竴娆�
+};
+
+onMounted(() => {
+  getBatchDetail()
+  nextTick(() => {
+    startAutoScroll(); // 鍚姩鑷姩婊氬姩
+  });
+});
+
+onUnmounted(() => {
+  if (scrollInterval) {
+    clearInterval(scrollInterval);
+  }
+});
+
+const initCharts = () => {
+  // 鍥捐〃鍒濆鍖栦唬鐮�
+  const initChart = (chartId: string, title: string, seriesConfig: Array<{ name: string, data: any[], unit: string, baseValue: number, fluctuation: number, color: string }>) => {
+    const chart = echarts.init(document.getElementById(chartId));
+
+    const updateChart = () => {
+      // 鐢熸垚鏂扮殑鏁版嵁鐐�
+      const now = new Date();
+      const time = `${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}`;
+
+      seriesConfig.forEach(s => {
+        const newValue = (s.baseValue + (Math.random() * 2 - 1) * s.fluctuation).toFixed(2);
+        s.data.push({
+          time,
+          value: newValue
+        });
+        if (s.data.length > 24) {
+          s.data.shift();
+        }
+      });
+
+      const option = {
+        title: {
+          text: title,
+          left: 'center'
+        },
+        tooltip: {
+          trigger: 'axis',
+          formatter: (params) => {
+            let result = `${params[0].axisValueLabel}<br/>`;
+            params.forEach(param => {
+              result += `${param.marker} ${param.seriesName}: ${param.data}${seriesConfig[param.seriesIndex].unit}<br/>`;
+            });
+            return result;
+          }
+        },
+        grid: {
+          left: '8%', // 澧炲姞宸︿晶杈硅窛
+          right: '5%',
+          bottom: '10%',
+          containLabel: true
+        },
+        xAxis: {
+          type: 'category',
+          data: seriesConfig[0].data.map(item => item.time)
+        },
+        yAxis: seriesConfig.map((s, index) => ({
+          type: 'value',
+          name: s.name,
+          position: index === 0 ? 'left' : 'right',
+          axisLine: {
+            show: true,
+          },
+          axisLabel: {
+            formatter: (value) => `${value}${s.unit}`
+          }
+        })),
+        series: seriesConfig.map((s, index) => ({
+            name: s.name,
+            data: s.data.map(item => parseFloat(item.value)),
+            type: 'line',
+            smooth: true,
+            yAxisIndex: index,
+            lineStyle: {
+              width: 2,
+              color: s.color
+            },
+            areaStyle: {
+              opacity: 0.8,
+              color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+                {
+                  offset: 0,
+                  color: 'rgba(84,112,198,0.3)'
+                },
+                {
+                  offset: 1,
+                  color: 'rgba(84,112,198,0)'
+                }
+              ])
+            },
+          }
+        )),
+      };
+      chart.setOption(option);
+    };
+
+    seriesConfig.forEach(s => {
+      s.data = [];
+      // 鐢熸垚鍒濆鏁版嵁鐐癸紙60涓偣锛�5鍒嗛挓鏁版嵁锛�
+      for (let i = 0; i < 24; i++) {
+        const now = new Date(Date.now() - (24 - i) * 5000); // 鐢熸垚杩囧幓5鍒嗛挓鐨勬暟鎹�
+        const time = `${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}`;
+        const newValue = (s.baseValue + (Math.random() * 2 - 1) * s.fluctuation).toFixed(2);
+        s.data.push({
+          time,
+          value: newValue
+        });
+      }
+    })
+
+    // 鍒濆娓叉煋
+    updateChart();
+
+    // 姣�5绉掓洿鏂颁竴娆℃暟鎹�
+    const intervalId = setInterval(updateChart, 5000);
+
+    window.addEventListener('resize', () => {
+      chart.resize();
+    });
+  };
+
+  // 鍒濆鍖栧悇涓浘琛�
+  initChart('motorTemperatureChart', '浜ч噺', [
+    { name: '浜ч噺', data: [], unit: 'pcs/h', baseValue: 175, fluctuation: 25, color: '#5470C6' },
+  ]);
+
+  initChart('motorVibrationChart', '鎶涙枡鐜�', [
+    { name: '鎶涙枡鐜�', data: [], unit: '%', baseValue: 0.15, fluctuation: 0.01, color: '#5470C6' },
+  ]);
+
+  initChart('nozzleVacuumChart', '鍚稿槾鐪熺┖鍘嬪姏', [
+    { name: '鍘嬪姏', data: [], unit: 'kPa', baseValue: -45, fluctuation: 5, color: '#5470C6' },
+  ]);
+
+  initChart('nozzleFlowChart', '鍚稿槾鍚规皵鍘嬪姏', [
+    { name: '鍘嬪姏', data: [], unit: 'kPa', baseValue: 20, fluctuation: 5, color: '#5470C6' },
+  ]);
+
+  initChart('placementSpeedChart', '璐磋閫熷害', [
+    { name: '閫熷害', data: [], unit: 'chips/h', baseValue: 9000, fluctuation: 1500, color: '#5470C6' },
+  ]);
+
+  const ambientTemperatureData: any[] = [];
+  const ambientHumidityData: any[] = [];
+  initChart('ambientTemperatureHumidityChart', '鐜娓╂箍搴�', [
+    { name: '娓╁害', data: ambientTemperatureData, unit: '掳C', baseValue: 25, fluctuation: 1, color: '#5470C6' },
+    { name: '婀垮害', data: ambientHumidityData, unit: '%', baseValue: 60, fluctuation: 5, color: '#91cc75' }
+  ]);
+};
+
+
+const initCharts2 = () => {
+  // 鐢熸垚鏃堕棿杞存暟鎹�
+  const generateTimeAxis = (isToday) => {
+    const baseTimes = ['08:30', '09:30', '10:30', '11:30', '12:30', '13:30', '14:30', '15:30', '16:30', '17:00'];
+
+    if (!isToday) {
+      return baseTimes;
+    }
+
+    const now = new Date();
+    const currentHour = now.getHours();
+    const currentMinute = now.getMinutes();
+    const currentTime = `${currentHour}:${currentMinute.toString().padStart(2, '0')}`;
+
+    // 鎵惧埌褰撳墠鏃堕棿鍦ㄥ熀纭�鏃堕棿鏁扮粍涓殑浣嶇疆
+    const currentIndex = baseTimes.findIndex(time => {
+      const [hour, minute] = time.split(':').map(Number);
+      const timeInMinutes = hour * 60 + minute;
+      const currentInMinutes = currentHour * 60 + currentMinute;
+      return timeInMinutes >= currentInMinutes;
+    });
+
+    // 濡傛灉褰撳墠鏃堕棿鏃╀簬8:30锛岃繑鍥炲畬鏁存暟缁�
+    if (currentIndex === -1) {
+      return baseTimes;
+    }
+
+    // 鎴彇鍒板綋鍓嶆椂闂翠箣鍓嶇殑鏃堕棿鐐�
+    return baseTimes.slice(0, currentIndex + 1);
+  };
+
+  // 鎴彇鏁版嵁浠ュ尮閰嶆椂闂磋酱闀垮害
+  const truncateData = (data, targetLength) => {
+    return data.slice(0, targetLength);
+  };
+
+  // 鍥捐〃鍒濆鍖栦唬鐮�
+  const initChart = (chartId, title, seriesConfig, isToday) => {
+    const chart = echarts.init(document.getElementById(chartId));
+    const timeAxis = generateTimeAxis(isToday);
+
+    const option = {
+      title: {
+        text: title,
+        left: 'center'
+      },
+      tooltip: {
+        trigger: 'axis',
+        formatter: (params) => {
+          let result = `${params[0].axisValueLabel}<br/>`;
+          params.forEach(param => {
+            result += `${param.marker} ${param.seriesName}: ${param.data}${seriesConfig[param.seriesIndex].unit}<br/>`;
+          });
+          return result;
+        }
+      },
+      grid: {
+        left: '8%',
+        right: '5%',
+        bottom: '10%',
+        containLabel: true
+      },
+      xAxis: {
+        type: 'category',
+        data: timeAxis
+      },
+      yAxis: seriesConfig.map((s, index) => ({
+        type: 'value',
+        name: s.name,
+        position: index === 0 ? 'left' : 'right',
+        axisLine: {
+          show: true,
+        },
+        axisLabel: {
+          formatter: (value) => `${value}${s.unit}`
+        }
+      })),
+      series: seriesConfig.map((s, index) => ({
+        name: s.name,
+        data: truncateData(s.data, timeAxis.length),
+        type: 'line',
+        smooth: true,
+        yAxisIndex: index,
+        lineStyle: {
+          width: 2,
+          color: s.color
+        },
+        areaStyle: {
+          opacity: 0.8,
+          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+            {
+              offset: 0,
+              color: 'rgba(84,112,198,0.3)'
+            },
+            {
+              offset: 1,
+              color: 'rgba(84,112,198,0)'
+            }
+          ])
+        },
+      })),
+    };
+    chart.setOption(option);
+
+    window.addEventListener('resize', () => {
+      chart.resize();
+    });
+  };
+
+  // 鍋囪鏈変竴涓彉閲忚〃绀烘槸鍚︽槸浠婂ぉ
+  const isToday = batchIsToday(batch.value.batchTime); // 鍙互鏍规嵁瀹為檯鎯呭喌璁剧疆涓簍rue鎴杅alse
+
+  // 鍒濆鍖栧悇涓浘琛�
+  initChart('motorTemperatureChart', '铓�鍒绘繁搴�(渭m)', [
+    {
+      name: '铓�鍒绘繁搴�',
+      data: [2.35, 2.38, 2.42, 2.45, 2.51, 2.48, 2.52, 2.55, 2.58, 2.60],
+      unit: '渭m',
+      color: '#5470C6'
+    },
+  ], isToday);
+
+  initChart('motorVibrationChart', '閿悎鍘嬪姏(MPa)', [
+    {
+      name: '閿悎鍘嬪姏',
+      data: [15.2, 15.5, 15.8, 16.1, 15.9, 16.2, 16.0, 16.3, 16.1, 16.4],
+      unit: 'MPa',
+      color: '#91cc75'
+    },
+  ], isToday);
+
+  initChart('nozzleVacuumChart', '娌夌Н閫熺巼(脜/min)', [
+    {
+      name: '娌夌Н閫熺巼',
+      data: [120, 118, 122, 125, 128, 126, 124, 127, 129, 131],
+      unit: '脜/min',
+      color: '#fac858'
+    },
+  ], isToday);
+
+  initChart('nozzleFlowChart', '娓╁害鎺у埗(掳C)', [
+    {
+      name: '娓╁害',
+      data: [350, 352, 355, 358, 356, 354, 351, 353, 357, 359],
+      unit: '掳C',
+      color: '#ee6666'
+    },
+  ], isToday);
+
+  initChart('placementSpeedChart', '鐪熺┖搴�(Pa)', [
+    {
+      name: '鐪熺┖搴�',
+      data: [0.0012, 0.0015, 0.0018, 0.0021, 0.0019, 0.0020, 0.0017, 0.0022, 0.0020, 0.0018],
+      unit: 'Pa',
+      color: '#73c0de'
+    },
+  ], isToday);
+
+  initChart('ambientTemperatureHumidityChart', '鐢垫祦瀵嗗害(A/cm虏)', [
+    {
+      name: '鐢垫祦瀵嗗害',
+      data: [2.1, 2.2, 2.3, 2.4, 2.35, 2.38, 2.32, 2.36, 2.39, 2.42],
+      unit: 'A/cm虏',
+      color: '#3ba272'
+    }
+  ], isToday);
+};
+
+
+
+// 鑾峰彇闅忔満澶╂暟锛堢敤浜庢ā鎷熶笉鍚岀殑鏇存柊鏃堕棿锛�
+const getRandomDaysAgo = (min, max) => {
+  return Math.floor(Math.random() * (max - min + 1)) + min;
+};
+
+const sensorComponentData = reactive([
+  {
+    id: '1',
+    name: '铓�鍒诲弽搴旇厰瀹�',
+    healthStatus: '鑹ソ',
+    remainingLife: '285澶�',
+    remainingPercentage: 85,
+    totalLife: '5骞�',
+    currentUsage: '2.5骞�',
+    lastUpdate: generateRelativeTime(3),
+    maintenanceHistory: '涓婃缁存姢: 2025-06-15'
+  },
+  {
+    id: '2',
+    name: '鏅跺渾浼犺緭鏈烘鑷�',
+    healthStatus: '棰勮',
+    remainingLife: '45澶�',
+    remainingPercentage: 25,
+    totalLife: '80涓囨',
+    currentUsage: '60涓囨',
+    lastUpdate: generateRelativeTime(7),
+    maintenanceHistory: '涓婃缁存姢: 2025-07-20'
+  },
+  {
+    id: '3',
+    name: '鐪熺┖娉电郴缁�',
+    healthStatus: '绱ф��',
+    remainingLife: '7澶�',
+    remainingPercentage: 5,
+    totalLife: '20000灏忔椂',
+    currentUsage: '19500灏忔椂',
+    lastUpdate: generateRelativeTime(2),
+    maintenanceHistory: '涓婃缁存姢: 2025-03-10'
+  },
+  {
+    id: '4',
+    name: '娓╁害鎺у埗绯荤粺',
+    healthStatus: '鑹ソ',
+    remainingLife: '180澶�',
+    remainingPercentage: 70,
+    totalLife: '3骞�',
+    currentUsage: '1.5骞�',
+    lastUpdate: generateRelativeTime(4),
+    maintenanceHistory: '涓婃缁存姢: 2025-05-22'
+  },
+  {
+    id: '5',
+    name: '鍖栧娌夌Н鍠峰ご',
+    healthStatus: '棰勮',
+    remainingLife: '30澶�',
+    remainingPercentage: 20,
+    totalLife: '1000鎵规',
+    currentUsage: '850鎵规',
+    lastUpdate: generateRelativeTime(3),
+    maintenanceHistory: '涓婃缁存姢: 2025-04-18'
+  },
+  {
+    id: '6',
+    name: '鍏夊妫�娴嬮暅澶�',
+    healthStatus: '鑹ソ',
+    remainingLife: '365澶�',
+    remainingPercentage: 90,
+    totalLife: '4骞�',
+    currentUsage: '1骞�',
+    lastUpdate: generateRelativeTime(18),
+    maintenanceHistory: '涓婃缁存姢: 2025-01-15'
+  },
+  {
+    id: '7',
+    name: '绂诲瓙娉ㄥ叆婧�',
+    healthStatus: '绱ф��',
+    remainingLife: '14澶�',
+    remainingPercentage: 8,
+    totalLife: '15000灏忔椂',
+    currentUsage: '14500灏忔椂',
+    lastUpdate: generateRelativeTime(2),
+    maintenanceHistory: '涓婃缁存姢: 2024-12-05'
+  }
+]);
+
+// 璁$畻鍋ュ悍鐘舵�佺粺璁�
+const healthyCount = computed(() =>
+  sensorComponentData.filter(item => item.healthStatus === '鑹ソ').length
+);
+
+const warningCount = computed(() =>
+  sensorComponentData.filter(item => item.healthStatus === '棰勮').length
+);
+
+const criticalCount = computed(() =>
+  sensorComponentData.filter(item => item.healthStatus === '绱ф��').length
+);
+
+// 琛ㄦ牸琛屾牱寮�
+const tableRowClassName = ({ row }) => {
+  if (row.healthStatus === '绱ф��') {
+    return 'warning-row';
+  } else if (row.healthStatus === '棰勮') {
+    return 'warning-row-light';
+  }
+  return '';
+};
+
+// 鑾峰彇鍋ュ悍鐘舵�佹爣绛剧被鍨�
+const getHealthStatusType = (status) => {
+  const statusMap = {
+    '鑹ソ': 'success',
+    '棰勮': 'warning',
+    '绱ф��': 'danger'
+  };
+  return statusMap[status] || 'info';
+};
+
+// 鑾峰彇杩涘害鏉¢鑹�
+const getProgressColor = (percentage) => {
+  if (percentage > 60) return '#67C23A';
+  if (percentage > 30) return '#E6A23C';
+  return '#F56C6C';
+};
+
+// 鏄剧ず閮ㄤ欢璇︽儏
+const showComponentDetail = (component) => {
+  ElMessageBox.confirm(
+    `閮ㄤ欢鍚嶇О: ${component.name}
+鍋ュ悍鐘舵��: ${component.healthStatus}
+鍓╀綑瀵垮懡: ${component.remainingLife}
+鎬昏璁″鍛�: ${component.totalLife}
+褰撳墠浣跨敤: ${component.currentUsage}
+${component.maintenanceHistory}`,
+    '閮ㄤ欢璇︽儏',
+    {
+      confirmButtonText: '纭畾',
+      cancelButtonText: '鍏抽棴',
+      type: 'info'
+    }
+  );
+};
+</script>
+
+
+<style scoped>
+.device-detail-container {
+  padding: 16px;
+  background: #f0f2f5;
+}
+
+.page-header-content {
+  display: flex;
+  flex-direction: column;
+}
+
+.page-header-title {
+  font-size: 18px;
+  font-weight: bold;
+}
+
+.page-header-subtitle {
+  font-size: 14px;
+  color: #666;
+  margin-top: 4px;
+}
+
+.card-header {
+  font-weight: bold;
+}
+
+.device-image-container {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  height: 330px;
+  overflow: hidden;
+}
+
+.device-image {
+  max-width: 100%;
+  max-height: 100%;
+  object-fit: contain;
+}
+
+.mt-4 {
+  margin-top: 1rem;
+}
+
+.mb-4 {
+  margin-bottom: 1rem;
+}
+
+
+.custom-descriptions {
+  height: 357px; /* 璁剧疆鏁翠釜鎻忚堪鍒楄〃鐨勯珮搴� */
+}
+
+.custom-descriptions :deep(.el-descriptions__body) {
+  height: 100%;
+}
+
+.custom-descriptions :deep(.el-descriptions__table) {
+  height: 100%;
+}
+
+.custom-descriptions :deep(.el-descriptions__table tbody) {
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+}
+
+.custom-descriptions :deep(.el-descriptions__table tr) {
+  flex: 1;
+  display: flex;
+}
+
+.custom-descriptions :deep(.el-descriptions__table td) {
+  flex: 1;
+  display: flex;
+  align-items: center;
+}
+
+.custom-descriptions :deep(.el-descriptions__table .el-descriptions__label) {
+  display: flex;
+  align-items: center;
+  justify-content: flex-start;
+}
+
+.custom-descriptions :deep(.el-descriptions__table .el-descriptions__content) {
+  display: flex;
+  align-items: center;
+  justify-content: flex-start;
+}
+
+/*
+.table-container {
+  position: relative;
+  height: 246px;
+  overflow: hidden;
+}
+
+.table-container :deep(.el-table__body-wrapper) {
+  overflow: hidden;
+}
+
+.table-container :deep(.el-table__body) {
+  animation: scrollTable 20s linear infinite;
+}
+
+.table-container:hover :deep(.el-table__body) {
+  animation-play-state: paused;
+}
+
+@keyframes scrollTable {
+  0% {
+    transform: translateY(0);
+  }
+  100% {
+    transform: translateY(-100%);
+  }
+}
+
+
+.table-container :deep(.el-table__header-wrapper) {
+  position: sticky;
+  top: 0;
+  background: white;
+  z-index: 10;
+}
+*/
+/* 鍦╯tyle閮ㄥ垎娣诲姞浠ヤ笅鏍峰紡 */
+.life-progress {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+}
+
+.life-text {
+  font-size: 12px;
+  color: #606266;
+  min-width: 40px;
+}
+
+.health-summary {
+  padding: 10px 0;
+}
+
+.summary-item {
+  text-align: center;
+  padding: 8px 0;
+}
+
+.summary-value {
+  font-size: 24px;
+  font-weight: bold;
+  margin-bottom: 4px;
+}
+
+.summary-label {
+  font-size: 12px;
+  color: #909399;
+}
+
+:deep(.warning-row) {
+  --el-table-tr-bg-color: var(--el-color-danger-light-9);
+}
+
+:deep(.warning-row-light) {
+  --el-table-tr-bg-color: var(--el-color-warning-light-9);
+}
+
+:deep(.el-table .warning-row:hover > td) {
+  background-color: var(--el-color-danger-light-7) !important;
+}
+
+:deep(.el-table .warning-row-light:hover > td) {
+  background-color: var(--el-color-warning-light-7) !important;
+}
+</style>
diff --git a/src/views/qms/ai/index.vue b/src/views/qms/quality/index.vue
similarity index 99%
rename from src/views/qms/ai/index.vue
rename to src/views/qms/quality/index.vue
index d010fb5..01dfb28 100644
--- a/src/views/qms/ai/index.vue
+++ b/src/views/qms/quality/index.vue
@@ -6,7 +6,7 @@
         <el-card shadow="hover" class="h-full">
           <template #header>
             <div class="card-header">
-              <span>璁惧鍋ュ悍搴﹁瘎鍒�</span>
+              <span>璐ㄩ噺鍋ュ悍搴﹁瘎鍒�</span>
             </div>
           </template>
           <!-- 杩欓噷灏嗘斁缃仴搴峰害鍒嗗竷鍥捐〃 -->

--
Gitblit v1.9.3