From 1378fc4cd7abc24ed3a982e09437c2c8a74e9f2f Mon Sep 17 00:00:00 2001
From: 647556386 <647556386@qq.com>
Date: 星期二, 27 一月 2026 19:06:32 +0800
Subject: [PATCH] 代码优化

---
 项目代码/WIDESEA_WMSClient/src/views/Home.vue |  818 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 806 insertions(+), 12 deletions(-)

diff --git "a/\351\241\271\347\233\256\344\273\243\347\240\201/WIDESEA_WMSClient/src/views/Home.vue" "b/\351\241\271\347\233\256\344\273\243\347\240\201/WIDESEA_WMSClient/src/views/Home.vue"
index 820437a..9ad82a0 100644
--- "a/\351\241\271\347\233\256\344\273\243\347\240\201/WIDESEA_WMSClient/src/views/Home.vue"
+++ "b/\351\241\271\347\233\256\344\273\243\347\240\201/WIDESEA_WMSClient/src/views/Home.vue"
@@ -1,24 +1,818 @@
 <template>
-  <div class="title"></div>
+  <div class="wms-dashboard">
+    <!-- 缁熻鍗$墖鍖哄煙 -->
+    <el-row :gutter="20" class="stats-card-row">
+      <el-col :span="4">
+        <div class="stats-card">
+          <div class="metric-icon">
+            <el-icon :size="32"><Box /></el-icon>
+          </div>
+          <div class="card-title">寰呭叆搴撹鍗�</div>
+          <div class="card-value">{{ bigscreendata.unInBoundOrderCount }}</div>
+        </div>
+      </el-col>
+      <el-col :span="4">
+        <div class="stats-card">
+          <div class="metric-icon">
+            <el-icon :size="32"><Document /></el-icon>
+          </div>
+          <div class="card-title">寰呭嚭搴撹鍗�</div>
+          <div class="card-value">{{ bigscreendata.unOutBoundOrderCount }}</div>
+        </div>
+      </el-col>
+      <el-col :span="4">
+        <div class="stats-card">
+          <div class="metric-icon">
+            <el-icon :size="32"><Download /></el-icon>
+          </div>
+          <div class="card-title">浠婃棩鍏ュ簱瀹屾垚绠辨暟</div>
+          <div class="card-value">{{ bigscreendata.inboundCount }}</div>
+        </div>
+      </el-col>
+      <el-col :span="4">
+        <div class="stats-card">
+          <div class="metric-icon">
+            <el-icon :size="32"><Upload /></el-icon>
+          </div>
+          <div class="card-title">浠婃棩鍑哄簱瀹屾垚绠辨暟</div>
+          <div class="card-value">{{ bigscreendata.outboundCount }}</div>
+        </div>
+      </el-col>
+      <el-col :span="4">
+        <div class="stats-card">
+          <div class="metric-icon">
+            <el-icon :size="32"><Box /></el-icon>
+          </div>
+          <div class="card-title">鏈夎揣鏂欑</div>
+          <div class="card-value">{{ formatNumber(bigscreendata.inStockPallet) }}</div>
+        </div>
+      </el-col>
+      <el-col :span="4">
+        <div class="stats-card">
+          <div class="metric-icon">
+            <el-icon :size="32"><Box /></el-icon>
+          </div>
+          <div class="card-title">绌虹鏁伴噺</div>
+          <div class="card-value">{{ formatNumber(bigscreendata.freeStockPallet) }}</div>
+        </div>
+      </el-col>
+    </el-row>
+
+    <!-- 鍥捐〃鍖哄煙锛堢涓�琛岋級 -->
+    <el-row :gutter="20" class="chart-row">
+      <el-col :span="8">
+        <div class="chart-card">
+          <div class="chart-title">搴撲綅鍒╃敤鐜�</div>
+          <div ref="locationRateRef" class="chart-container"></div>
+        </div>
+      </el-col>
+      <el-col :span="8">
+        <div class="chart-card">
+          <div class="chart-title">鐗╂枡涓存湡淇℃伅</div>
+          <div class="expiration-table-container">
+            <el-table 
+              :data="expirationTableData" 
+              border 
+              stripe 
+              style="width: 100%;"
+              :empty-text="emptyText"
+            >
+              <el-table-column prop="materielCode" label="鐗╂枡缂栫爜" align="center" />
+              <el-table-column prop="materielName" label="鐗╂枡鍚嶇О" align="center" show-overflow-tooltip />
+              <el-table-column prop="batchNo" label="鎵规鍙�" align="center" />
+              <el-table-column prop="validDate" label="鏈夋晥鏈�" align="center" />
+              <el-table-column label="涓存湡绛夌骇" align="center">
+                <template #default="{ row }">
+                  <span :class="getExpireLevelClass(row.expireLevel)">{{ row.expireLevel }}</span>
+                </template>
+              </el-table-column>
+              <el-table-column prop="daysToExpiration" label="涓存湡澶╂暟" align="center">
+                <template #default="{ row }">
+                  <span :class="row.daysToExpiration < 0 ? 'text-red' : ''">
+                    {{ row.daysToExpiration < 0 ? '宸茶繃鏈�' : `${row.daysToExpiration}澶ー }}
+                  </span>
+                </template>
+              </el-table-column>
+              <el-table-column prop="stockQuantity" label="搴撳瓨鏁伴噺" align="center" />
+              <el-table-column prop="locationCode" label="搴撲綅" align="center" />
+              <el-table-column prop="palletCode" label="鎵樼洏缂栧彿" align="center" />
+            </el-table>
+          </div>
+        </div>
+      </el-col>
+      <el-col :span="8">
+        <div class="chart-card">
+          <div class="chart-title">杩�7鏃ュ嚭鍏ュ簱鍗曟嵁瓒嬪娍</div>
+          <div ref="stockTrendRef" class="chart-container"></div>
+        </div>
+      </el-col>
+    </el-row>
+
+    <!-- 琛ㄦ牸鍖哄煙 - 瀹炴椂浣滀笟鐩戞帶锛堝尯鍒嗘甯�/澶辫触浣滀笟锛� -->
+    <el-row :gutter="20" class="table-row" width="100%">
+      <!-- 宸︿晶锛氬綋澶╂甯镐綔涓氬崟鎹� -->
+      <el-col :span="12">
+        <div class="table-card">
+          <div class="table-title">瀹炴椂浣滀笟鐩戞帶锛堟甯稿崟鎹級</div>
+          <el-table 
+            :data="normalShowTaskList" 
+            border 
+            style="width: 100%;"
+            :empty-text="normalShowTaskList.length === 0 ? '鏆傛棤姝e父浣滀笟鏁版嵁' : ''"
+          >
+            <el-table-column prop="upperOrderNo" label="鍗曟嵁缂栧彿" />
+            <el-table-column label="鍗曟嵁鐘舵��" >
+              <template #default="{ row }">
+                <span class="task-status" :class="getStatusClass(row.taskStatus)">
+                  {{ getTaskStatusText(row.taskStatus, row.taskType) }}
+                </span>
+              </template>
+            </el-table-column>
+            <el-table-column label="鍗曟嵁绫诲瀷" >
+              <template #default="{ row }">
+                <span class="task-type" :class="getTypeClass(row.taskType)">
+                  {{ getTaskTypeText(row) }}
+                </span>
+              </template>
+            </el-table-column>
+            <el-table-column label="鍥炰紶MES鐘舵��" >
+              <template #default="{ row }">
+                <span class="task-status" :class="getMESStatusClass(row.returnToMESStatus)">
+                  {{ getMESStatusText(row.returnToMESStatus) }}
+                </span>
+              </template>
+            </el-table-column>
+            <el-table-column prop="factoryArea" label="鍘傚尯" />
+            <el-table-column prop="modifier" label="淇敼浜�" />
+            <el-table-column prop="createDate" label="鍒涘缓鏃堕棿"/>
+            <el-table-column prop="modifyDate" label="淇敼鏃堕棿"/>
+          </el-table>
+          <div class="table-pagination">
+            <el-pagination 
+              layout="prev, pager, next, jumper" 
+              v-model:current-page="normalCurrentPage"
+              :page-size="5"
+              :total="normalTaskList.length" 
+              @current-change="handleNormalPageChange"
+            />
+          </div>
+        </div>
+      </el-col>
+      <!-- 鍙充晶锛氳繎3澶╁洖浼犲け璐�/閮ㄥ垎澶辫触鍗曟嵁 -->
+      <el-col :span="12">
+        <div class="table-card">
+          <div class="table-title">瀹炴椂浣滀笟鐩戞帶锛堝洖浼犲け璐ワ級</div>
+          <el-table 
+            :data="failShowTaskList" 
+            border 
+            style="width: 100%;"
+            :empty-text="failShowTaskList.length === 0 ? '鏆傛棤鍥炰紶澶辫触鏁版嵁' : ''"
+          >
+            <el-table-column prop="upperOrderNo" label="鍗曟嵁缂栧彿" />
+            <el-table-column label="鍗曟嵁鐘舵��" >
+              <template #default="{ row }">
+                <span class="task-status" :class="getStatusClass(row.taskStatus)">
+                  {{ getTaskStatusText(row.taskStatus, row.taskType) }}
+                </span>
+              </template>
+            </el-table-column>
+            <el-table-column label="鍗曟嵁绫诲瀷" >
+              <template #default="{ row }">
+                <span class="task-type" :class="getTypeClass(row.taskType)">
+                  {{ getTaskTypeText(row) }}
+                </span>
+              </template>
+            </el-table-column>
+            <el-table-column label="鍥炰紶MES鐘舵��" >
+              <template #default="{ row }">
+                <span class="task-status" :class="getMESStatusClass(row.returnToMESStatus)">
+                  {{ getMESStatusText(row.returnToMESStatus) }}
+                </span>
+              </template>
+            </el-table-column>
+            <el-table-column prop="remark" label="澶辫触鍘熷洜" show-overflow-tooltip />
+            <el-table-column prop="factoryArea" label="鍘傚尯" />
+            <el-table-column prop="modifier" label="淇敼浜�" />
+            <el-table-column prop="createDate" label="鍒涘缓鏃堕棿"/>
+            <el-table-column prop="modifyDate" label="淇敼鏃堕棿"/>
+          </el-table>
+          <div class="table-pagination">
+            <el-pagination 
+              layout="prev, pager, next, jumper" 
+              v-model:current-page="failCurrentPage"
+              :page-size="5"
+              :total="failTaskList.length" 
+              @current-change="handleFailPageChange"
+            />
+          </div>
+        </div>
+      </el-col>
+    </el-row>
+  </div>
 </template>
 
-<script>
-import { ref, reactive } from 'vue'
+<script setup>
+import { ref, onMounted, onUnmounted, nextTick, computed, watch } from 'vue';
+import * as echarts from 'echarts';
+import http from "@/api/http.js";
+import { Box, Document, Download, Upload } from '@element-plus/icons-vue';
+import { ElMessage } from 'element-plus';
 
-export default {
-  setup() {
+// 鍝嶅簲寮忔暟鎹�
+const bigscreendata = ref({
+  totalStockQuantity: 0,
+  unOutBoundOrderCount: 0,
+  unInBoundOrderCount:0,
+  dailyCompletionRate: 0,
+  unhandledExceptionCount: 0,
+  locationUtilizationRate: 0,
+  inStockPallet: 0,
+  freeStockPallet: 0,
+  dailyInOutBoundList: [],
+  completeTask: [], // 鍚庣杩斿洖鐨勪换鍔℃暟鎹紙褰撳ぉ姝e父+杩�3澶╁け璐ワ級
+  inboundCount: 0,
+  outboundCount: 0,
+  inventoryLocationDist: [], 
+  exceptionTypeTrend: [],    
+  nearExpirationList: []      
+});
+
+// 涓存湡琛ㄦ牸鏁版嵁锛堜繚鎸佷笉鍙橈級
+const expirationTableData = computed(() => {
+  const expirationList = bigscreendata.value.nearExpirationList || [];
+  const uniqueMap = new Map();
+  expirationList.forEach(item => {
+    const uniqueKey = [item.materielCode, item.batchNo, item.palletCode].join('|');
+    if (!uniqueMap.has(uniqueKey)) uniqueMap.set(uniqueKey, item);
+  });
+  const uniqueExpirationList = Array.from(uniqueMap.values());
+  return uniqueExpirationList.map(item => {
+    const daysToExpiration = item.daysToExpiration || 0;
+    let expireLevel = '';
+    if (daysToExpiration < 0) expireLevel = '宸茶繃鏈�';
+    else if (daysToExpiration <= 7) expireLevel = '7澶╁唴涓存湡';
+    else if (daysToExpiration <= 15) expireLevel = '15澶╁唴涓存湡';
+    else if (daysToExpiration <= 30) expireLevel = '30澶╁唴涓存湡';
+    else expireLevel = '30澶╀互涓�';
     return {
+      materielCode: item.materielCode,
+      materielName: item.materielName,
+      batchNo: item.batchNo,
+      validDate: item.validDate,
+      daysToExpiration: daysToExpiration,
+      expireLevel: expireLevel,
+      stockQuantity: item.stockQuantity || 0,
+      locationCode: item.locationCode,
+      palletCode: item.palletCode,
+      unit: item.unit
+    };
+  });
+});
 
-    }
+const emptyText = computed(() => {
+  const expirationList = bigscreendata.value.nearExpirationList || [];
+  return expirationList.length === 0 ? '鏆傛棤涓存湡鐗╂枡鏁版嵁' : '';
+});
+
+const getExpireLevelClass = (level) => {
+  switch(level) {
+    case '宸茶繃鏈�': return 'expire-level expired';
+    case '7澶╁唴涓存湡': return 'expire-level urgent';
+    case '15澶╁唴涓存湡': return 'expire-level warning';
+    case '30澶╁唴涓存湡': return 'expire-level normal';
+    case '30澶╀互涓�': return 'expire-level low';
+    default: return 'expire-level default';
   }
-}
+};
+
+// 涓氬姟绫诲瀷鏄犲皠
+const inboundBusinessTypeMap = {
+  11: "閲囪喘鍏ュ簱", 12: "鏉傛敹鍗�", 13: "鐢熶骇閫�鏂欏崟",
+  14: "澶栧崗閫�鏂欏崟", 15: "閿�鍞��搴撳崟", 3: "璋冩嫧鍏ュ簱鍗�"
+};
+const outboundBusinessTypeMap = {
+  21: "宸ュ崟棰嗘枡鍑哄簱鍗�", 22: "鏉傚彂鍗�", 23: "閫�璐у崟",
+  24: "閿�鍞嚭搴撳崟", 25: "澶栧崗棰嗘枡鐢宠鍗�", 2: "璋冩嫧鍑哄簱鍗�"
+};
+
+// 鎷嗗垎锛氬綋澶╂甯镐綔涓氬崟鎹�
+const normalTaskList = computed(() => {
+  const taskData = (bigscreendata.value.completeTask[0] || {});
+  const inboundOrders = taskData.inboundOrders || [];
+  const outboundOrders = taskData.outboundOrders || [];
+  
+  // 鏍煎紡鍖栧叆搴撹鍗�
+  const formattedInbound = inboundOrders.map(item => ({
+    upperOrderNo: item.upperOrderNo || item.inboundOrderNo,
+    taskStatus: item.orderStatus || 0,
+    taskType: 'inbound',
+    businessType: item.businessType || '',
+    returnToMESStatus: item.returnToMESStatus || 0,
+    factoryArea: item.factoryArea || '',
+    modifier: item.modifier || '',
+    createDate: item.createDate || '',
+    modifyDate: item.modifyDate || '',
+    remark: item.remark || ''
+  }));
+  
+  // 鏍煎紡鍖栧嚭搴撹鍗�
+  const formattedOutbound = outboundOrders.map(item => ({
+    upperOrderNo: item.upperOrderNo || item.orderNo,
+    taskStatus: item.orderStatus || 0,
+    taskType: 'outbound',
+    businessType: item.businessType || '',
+    returnToMESStatus: item.returnToMESStatus || 0,
+    factoryArea: item.factoryArea || '',
+    modifier: item.modifier || '',
+    createDate: item.createDate || '',
+    modifyDate: item.modifyDate || '',
+    remark: item.remark || ''
+  }));
+  
+  return [...formattedInbound, ...formattedOutbound];
+});
+
+// 鎷嗗垎锛氳繎3澶╁洖浼犲け璐�/閮ㄥ垎澶辫触鍗曟嵁
+const failTaskList = computed(() => {
+  const taskData = (bigscreendata.value.completeTask[0] || {});
+  const inboundFailOrders = taskData.inboundReturnFailOrders || [];
+  const outboundFailOrders = taskData.outboundReturnFailOrders || [];
+  
+  const formattedInboundFail = inboundFailOrders.map(item => ({
+    upperOrderNo: item.upperOrderNo || item.inboundOrderNo,
+    taskStatus: item.orderStatus || 0,
+    taskType: 'inbound',
+    businessType: item.businessType || '',
+    returnToMESStatus: item.returnToMESStatus || 0,
+    factoryArea: item.factoryArea || '',
+    modifier: item.modifier || '',
+    createDate: item.createDate || '',
+    modifyDate: item.modifyDate || '',
+    remark: item.remark || ''
+  }));
+  
+  const formattedOutboundFail = outboundFailOrders.map(item => ({
+    upperOrderNo: item.upperOrderNo || item.orderNo,
+    taskStatus: item.orderStatus || 0,
+    taskType: 'outbound',
+    businessType: item.businessType || '',
+    returnToMESStatus: item.returnToMESStatus || 0,
+    factoryArea: item.factoryArea || '',
+    modifier: item.modifier || '',
+    createDate: item.createDate || '',
+    modifyDate: item.modifyDate || '',
+    remark: item.remark || ''
+  }));
+  
+  return [...formattedInboundFail, ...formattedOutboundFail];
+});
+
+// 鍒嗛〉&杞挱鐩稿叧鍝嶅簲寮忓彉閲�
+const normalCurrentPage = ref(1);
+const failCurrentPage = ref(1);
+const normalShowTaskList = ref([]);
+const failShowTaskList = ref([]);
+let normalCarouselTimer = null;
+let failCarouselTimer = null;
+
+// 淇锛氬崟鎹姸鎬佹枃鏈紙鏂板taskType鍙傛暟锛�
+const getTaskStatusText = (statusNum, taskType) => {
+  const statusMap = {
+    0: "鏈紑濮�",
+    1: taskType === 'inbound' ? "鍏ュ簱涓�" : (taskType === 'outbound' ? "鍑哄簱涓�" : "澶勭悊涓�"),
+    2: "澶勭悊涓�",
+    3: "宸插畬鎴�",
+    4: "宸插彇娑�",
+    5: "寮傚父"
+  };
+  return statusMap[statusNum] ;
+};
+
+// MES鍥炰紶鐘舵�佹槧灏�
+const mesStatusMap = {
+  0: "鏈洖浼�", 1: "鍥炰紶鎴愬姛", 2: "鍥炰紶澶辫触",
+  3: "閮ㄥ垎鍥炰紶鎴愬姛", 4: "閮ㄥ垎鍥炰紶澶辫触"
+};
+const getMESStatusText = (statusNum) => {
+  if (statusNum === undefined || statusNum === null || isNaN(statusNum)) return "鏈煡鐘舵��";
+  return mesStatusMap[statusNum] || `鏈煡鐘舵��(${statusNum})`;
+};
+const getMESStatusClass = (statusNum) => {
+  if (statusNum === undefined || statusNum === null || isNaN(statusNum)) return "status-unknown";
+  const classMap = { 0: "status-pending", 1: "status-completed", 2: "status-error", 3: "status-processing", 4: "status-error" };
+  return classMap[statusNum] || "status-unknown";
+};
+
+// 鍗曟嵁绫诲瀷鏂囨湰/鏍峰紡
+const getTaskTypeText = (row) => {
+  const businessType = Number(row.businessType) || 0;
+  if (row.taskType === 'inbound') {
+    return inboundBusinessTypeMap[businessType] || `鏈煡绫诲瀷(${businessType})`;
+  } else if (row.taskType === 'outbound') {
+    return outboundBusinessTypeMap[businessType] || `鏈煡绫诲瀷(${businessType})`;
+  }
+  return "鍏朵粬浣滀笟";
+};
+const getStatusClass = (statusNum) => {
+  if (statusNum === undefined || statusNum === null || isNaN(statusNum)) return "status-unknown";
+  const classMap = { 0: "status-pending", 1: "status-processing", 2: "status-processing", 3: "status-completed", 4: "status-canceled", 5: "status-error" };
+  return classMap[statusNum] || "status-unknown";
+};
+const getTypeClass = (taskType) => {
+  const classMap = { 'inbound': "type-inbound", 'outbound': "type-outbound" };
+  return classMap[taskType] || "type-other";
+};
+
+// 鏁板瓧鏍煎紡鍖�
+const formatNumber = (num) => {
+  if (!num) return '0';
+  return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
+};
+
+// 鍒濆鍖栬〃鏍兼暟鎹紙鍒嗛〉+杞挱锛�
+const initTableData = () => {
+  // 鍋滄鏃у畾鏃跺櫒
+  clearInterval(normalCarouselTimer);
+  clearInterval(failCarouselTimer);
+
+  // 姝e父鍗曟嵁鍒嗛〉/杞挱
+  const loadNormalData = (page) => {
+    const start = (page - 1) * 5;
+    const end = start + 5;
+    normalShowTaskList.value = normalTaskList.value.slice(start, end);
+  };
+  loadNormalData(normalCurrentPage.value);
+
+  // 澶辫触鍗曟嵁鍒嗛〉/杞挱
+  const loadFailData = (page) => {
+    const start = (page - 1) * 5;
+    const end = start + 5;
+    failShowTaskList.value = failTaskList.value.slice(start, end);
+  };
+  loadFailData(failCurrentPage.value);
+
+  // 杞挱閫昏緫锛堜粎鏁版嵁瓒呰繃5鏉℃椂寮�鍚級
+  if (normalTaskList.value.length > 5) {
+    normalCarouselTimer = setInterval(() => {
+      normalCurrentPage.value = normalCurrentPage.value >= Math.ceil(normalTaskList.value.length / 5) ? 1 : normalCurrentPage.value + 1;
+      loadNormalData(normalCurrentPage.value);
+    }, 5000);
+  }
+  if (failTaskList.value.length > 5) {
+    failCarouselTimer = setInterval(() => {
+      failCurrentPage.value = failCurrentPage.value >= Math.ceil(failTaskList.value.length / 5) ? 1 : failCurrentPage.value + 1;
+      loadFailData(failCurrentPage.value);
+    }, 5000);
+  }
+};
+
+// 鍒嗛〉鍒囨崲浜嬩欢
+const handleNormalPageChange = (page) => {
+  clearInterval(normalCarouselTimer); // 鎵嬪姩鍒囨崲鍒嗛〉鏃跺仠姝㈣疆鎾�
+  normalCurrentPage.value = page;
+  const start = (page - 1) * 5;
+  const end = start + 5;
+  normalShowTaskList.value = normalTaskList.value.slice(start, end);
+};
+const handleFailPageChange = (page) => {
+  clearInterval(failCarouselTimer);
+  failCurrentPage.value = page;
+  const start = (page - 1) * 5;
+  const end = start + 5;
+  failShowTaskList.value = failTaskList.value.slice(start, end);
+};
+
+// 鐩戝惉鏁版嵁鍙樺寲锛岄噸鏂板垵濮嬪寲琛ㄦ牸
+watch([normalTaskList, failTaskList], () => {
+  initTableData();
+}, { deep: true });
+
+// 鑾峰彇鍚庣鏁版嵁
+const fetchBigGreenData = async () => {
+  try {
+    const res = await http.get('/api/BigScreen/GetBigGreenData');
+    bigscreendata.value = res.data || res;
+    nextTick(() => {
+      initTableData();
+      refreshCharts();
+    });
+  } catch (error) {
+    ElMessage.error('鏁版嵁鑾峰彇澶辫触锛岃妫�鏌ュ悗绔帴鍙f槸鍚︽甯�');
+    console.error('鏁版嵁鑾峰彇澶辫触锛�', error);
+  }
+};
+
+// 鍥捐〃鐩稿叧锛堢簿绠�鍐椾綑閫昏緫锛�
+const stockTrendRef = ref(null);
+const locationRateRef = ref(null);
+let stockTrendChart = null;
+let locationRateChart = null;
+
+const initStockTrend = () => {
+  if (!stockTrendRef.value) return;
+  if (stockTrendChart) stockTrendChart.dispose();
+  stockTrendChart = echarts.init(stockTrendRef.value);
+  const trendData = bigscreendata.value.dailyInOutBoundList;
+  const maxInbound = trendData.length ? Math.max(...trendData.map(item => item.dailyInboundQuantity || 0)) : 0;
+  const maxOutbound = trendData.length ? Math.max(...trendData.map(item => item.dailyOutboundQuantity || 0)) : 0;
+  const maxValue = Math.max(maxInbound, maxOutbound);
+  const option = {
+    tooltip: { trigger: 'axis', axisPointer: { type: 'cross' } },
+    legend: { data: ['鍏ュ簱閲�', '鍑哄簱閲�'], top: 10 },
+    grid: { left: '3%', right: '4%', bottom: '3%', top: '15%', containLabel: true },
+    xAxis: { type: 'category', boundaryGap: true, data: trendData.map(item => item.date) },
+    yAxis: { type: 'value', name: '鏁伴噺', min: 0, max: maxValue > 0 ? Math.ceil(maxValue * 1.2) : 10 },
+    series: [
+      { name: '鍏ュ簱閲�', type: 'bar', barWidth: '30%', data: trendData.map(item => item.dailyInboundQuantity), itemStyle: { color: '#52c41a', borderRadius: [4, 4, 0, 0] } },
+      { name: '鍑哄簱閲�', type: 'bar', barWidth: '30%', data: trendData.map(item => item.dailyOutboundQuantity), itemStyle: { color: '#1890ff', borderRadius: [4, 4, 0, 0] } }
+    ]
+  };
+  stockTrendChart.setOption(option);
+  return stockTrendChart;
+};
+
+const initLocationRate = () => {
+  if (!locationRateRef.value) return;
+  if (locationRateChart) locationRateChart.dispose();
+  locationRateChart = echarts.init(locationRateRef.value);
+  const utilizationRate = bigscreendata.value.locationUtilizationRate || 0;
+  const freeRate = 100 - utilizationRate;
+  const option = {
+    tooltip: { trigger: 'item', formatter: '{b}: {c}%' },
+    legend: { bottom: 0, left: 'center', data: ['宸插崰鐢ㄥ簱浣�', '绌洪棽搴撲綅'], textStyle: { fontSize: 12, color: '#666' } },
+    graphic: [
+      { type: 'text', left: 'right', top: '10%', style: { text: `${utilizationRate}%`, fontSize: 24, fontWeight: 'bold', fill: '#333' } },
+      { type: 'text', left: 'right', top: '25%', style: { text: '搴撲綅鍒╃敤鐜�', fontSize: 14, fill: '#666' } }
+    ],
+    series: [{
+      type: 'pie', radius: ['50%', '70%'], center: ['40%', '50%'],
+      avoidLabelOverlap: false, label: { show: false }, labelLine: { show: false },
+      data: [
+        { value: utilizationRate, name: '宸插崰鐢ㄥ簱浣�', itemStyle: { color: '#1890ff' } },
+        { value: freeRate, name: '绌洪棽搴撲綅', itemStyle: { color: '#e5e9f2' } }
+      ]
+    }]
+  };
+  locationRateChart.setOption(option);
+  return locationRateChart;
+};
+
+const refreshCharts = () => {
+  [initStockTrend, initLocationRate].forEach(initFunc => {
+    const chart = initFunc();
+    if (chart) chart.resize();
+  });
+};
+
+// 闃叉姈澶勭悊resize浜嬩欢
+let resizeTimer = null;
+const handleResize = () => {
+  clearTimeout(resizeTimer);
+  resizeTimer = setTimeout(() => {
+    [stockTrendChart, locationRateChart].forEach(chart => {
+      if (chart) chart.resize();
+    });
+  }, 200);
+};
+
+// 鐢熷懡鍛ㄦ湡
+onMounted(() => {
+  fetchBigGreenData();
+  nextTick(() => {
+    initStockTrend();
+    initLocationRate();
+    window.addEventListener('resize', handleResize);
+  });
+});
+
+onUnmounted(() => {
+  // 閿�姣佸浘琛ㄥ拰瀹氭椂鍣�
+  [stockTrendChart, locationRateChart].forEach(chart => {
+    if (chart) chart.dispose();
+  });
+  [normalCarouselTimer, failCarouselTimer, resizeTimer].forEach(timer => {
+    clearInterval(timer);
+    clearTimeout(timer);
+  });
+  window.removeEventListener('resize', handleResize);
+});
 </script>
 
 <style scoped>
-.title {
-  line-height: 70vh;
-  text-align: center;
-  font-size: 28px;
-  color: orange;
+.wms-dashboard {
+  padding: 24px;
+  background: linear-gradient(135deg, #f0f2f5 0%, #e6e9f0 100%);
+  min-height: 100vh;
+  box-sizing: border-box;
+  font-family: "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;
 }
+
+.stats-card-row, .chart-row, .table-row {
+  margin-bottom: 20px;
+}
+
+.stats-card, .chart-card, .table-card {
+  background: #fff;
+  border-radius: 8px;
+  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.04);
+  border: 1px solid #ebeef5;
+}
+
+.stats-card {
+  height: 140px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+  padding: 20px 15px;
+  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+  position: relative;
+  overflow: hidden;
+  background: linear-gradient(145deg, #ffffff 0%, #f9fafc 100%);
+}
+
+.stats-card:hover {
+  transform: translateY(-6px) scale(1.02);
+  box-shadow: 0 12px 24px rgba(0, 0, 0, 0.1);
+  border-color: #409eff;
+  background: linear-gradient(145deg, #ffffff 0%, #f0f2f5 100%);
+}
+
+.metric-icon {
+  width: 56px;
+  height: 56px;
+  border-radius: 16px;
+  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  color: white;
+  margin-bottom: 12px;
+  box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
+  transition: all 0.3s ease;
+}
+
+.card-title {
+  font-size: 15px;
+  color: #606266;
+  margin-bottom: 10px;
+  font-weight: 500;
+  letter-spacing: 0.5px;
+}
+
+.card-value {
+  font-size: 32px;
+  font-weight: 700;
+  margin: 8px 0 4px;
+  color: #2c3e50;
+  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
+  line-height: 1.2;
+  background: linear-gradient(to right, #409eff, #36cfc9);
+  -webkit-background-clip: text;
+  -webkit-text-fill-color: transparent;
+  background-clip: text;
+}
+
+.chart-card {
+  height: 400px;
+  padding: 24px;
+  display: flex;
+  flex-direction: column;
+  background: linear-gradient(180deg, #ffffff 0%, #f8f9fa 100%);
+  border: none;
+  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.06);
+  border-radius: 12px;
+  transition: all 0.3s ease;
+  overflow: hidden;
+  position: relative;
+}
+
+.chart-card:hover {
+  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
+  transform: translateY(-2px);
+}
+
+.chart-container {
+  width: 100%;
+  height: 100%;
+  min-height: 300px;
+  flex: 1;
+  position: relative;
+  border-radius: 8px;
+  background: rgba(255, 255, 255, 0.7);
+  backdrop-filter: blur(5px);
+  box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.03);
+}
+
+.expiration-table-container {
+  width: 100%;
+  height: 100%;
+  min-height: 300px;
+  flex: 1;
+  overflow-y: auto;
+}
+
+.expire-level {
+  padding: 2px 8px;
+  border-radius: 4px;
+  font-size: 12px;
+  font-weight: 500;
+}
+.expire-level.expired { background-color: #fff2f0; color: #ff4d4f; border: 1px solid #ffccc7; }
+.expire-level.urgent { background-color: #fff7e6; color: #fa8c16; border: 1px solid #ffd591; }
+.expire-level.warning { background-color: #f6ffed; color: #52c41a; border: 1px solid #b7eb8f; }
+.expire-level.normal { background-color: #e6f7ff; color: #1890ff; border: 1px solid #91d5ff; }
+.expire-level.low { background-color: #f0f2f5; color: #666666; border: 1px solid #d9d9d9; }
+.expire-level.default { background-color: #fafafa; color: #8c8c8c; border: 1px solid #e8e8e8; }
+
+.text-red { color: #ff4d4f; font-weight: 500; }
+
+.chart-title, .table-title {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 24px;
+  font-size: 18px;
+  font-weight: 600;
+  color: #2c3e50;
+  padding-left: 12px;
+  border-left: 4px solid #409eff;
+  position: relative;
+  letter-spacing: 0.5px;
+}
+
+.table-card {
+  padding: 24px;
+  background: #fff;
+  border-radius: 12px;
+  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.06);
+  border: 1px solid rgba(0, 0, 0, 0.04);
+  overflow: hidden;
+  transition: all 0.3s ease;
+}
+
+.table-card:hover {
+  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
+  transform: translateY(-2px);
+}
+
+.table-pagination {
+  display: flex;
+  justify-content: flex-end;
+  align-items: center;
+  margin-top: 20px;
+  padding-top: 15px;
+  border-top: 1px solid #ebeef5;
+}
+
+:deep(.el-table) {
+  border-radius: 6px;
+  overflow: hidden;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
+}
+:deep(.el-table th) { background-color: #f5f7fa; color: #606266; font-weight: 600; padding: 12px 0; }
+:deep(.el-table td) { padding: 12px 0; }
+:deep(.el-table--border) { border-radius: 6px; }
+:deep(.el-table--border::after), :deep(.el-table--group::after), :deep(.el-table::before), :deep(.el-table__fixed-right::before), :deep(.el-table__fixed::before) { display: none; }
+
+:deep(.el-pagination .btn-prev), :deep(.el-pagination .btn-next), :deep(.el-pagination .el-pager li) {
+  border-radius: 4px;
+  margin: 0 2px;
+  transition: all 0.3s;
+}
+:deep(.el-pagination .btn-prev:hover), :deep(.el-pagination .btn-next:hover), :deep(.el-pagination .el-pager li:hover) {
+  transform: translateY(-2px);
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+}
+:deep(.el-pagination .el-pager li.active) {
+  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+  color: #fff;
+}
+
+.task-status, .task-type {
+  display: inline-block;
+  padding: 6px 12px;
+  border-radius: 20px;
+  font-size: 13px;
+  font-weight: 500;
+  text-align: center;
+  min-width: 80px;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
+  transition: all 0.2s ease;
+  letter-spacing: 0.5px;
+}
+
+.status-pending { background-color: rgba(64, 158, 255, 0.1); color: #409eff; border: 1px solid rgba(64, 158, 255, 0.2); }
+.status-processing { background-color: rgba(103, 194, 58, 0.1); color: #67c23a; border: 1px solid rgba(103, 194, 58, 0.2); }
+.status-completed { background-color: rgba(103, 194, 58, 0.1); color: #67c23a; border: 1px solid rgba(103, 194, 58, 0.2); }
+.status-suspended { background-color: rgba(230, 162, 60, 0.1); color: #e6a23c; border: 1px solid rgba(230, 162, 60, 0.2); }
+.status-canceled { background-color: rgba(144, 147, 153, 0.1); color: #909399; border: 1px solid rgba(144, 147, 153, 0.2); }
+.status-error { background-color: rgba(245, 108, 108, 0.1); color: #f56c6c; border: 1px solid rgba(245, 108, 108, 0.2); }
+.status-unknown { background-color: rgba(144, 147, 153, 0.1); color: #909399; border: 1px solid rgba(144, 147, 153, 0.2); }
+
+.type-inbound { background-color: rgba(64, 158, 255, 0.1); color: #409eff; border: 1px solid rgba(64, 158, 255, 0.2); }
+.type-outbound { background-color: rgba(103, 194, 58, 0.1); color: #67c23a; border: 1px solid rgba(103, 194, 58, 0.2); }
+.type-transfer { background-color: rgba(230, 162, 60, 0.1); color: #e6a23c; border: 1px solid rgba(230, 162, 60, 0.2); }
+.type-other { background-color: rgba(144, 147, 153, 0.1); color: #909399; border: 1px solid rgba(144, 147, 153, 0.2); }
+.type-unknown { background-color: rgba(144, 147, 153, 0.1); color: #909399; border: 1px solid rgba(144, 147, 153, 0.2); }
 </style>
\ No newline at end of file

--
Gitblit v1.9.3