From 9f5e836044835351021363824a704674e2789449 Mon Sep 17 00:00:00 2001
From: zss <zss@example.com>
Date: 星期三, 01 四月 2026 17:45:03 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/dev_银川_中盛建材' into dev_银川_中盛建材

---
 src/api/productionPlan/productionPlan.js                               |   12 
 src/views/index.vue                                                    |  222 ++++-
 src/views/costAccounting/stdVsActCostAnalysis/index.vue                |  541 ++++++-------
 src/views/productionManagement/processRoute/index.vue                  |    1 
 src/api/costAccounting/productionSettlementBatches.js                  |   53 +
 src/views/productionManagement/processRoute/processRouteItem/index.vue |   16 
 src/views/reportAnalysis/salesStatistics/index.vue                     |  790 ++++++++++++++++----
 src/views/productionPlan/productionPlan/index.vue                      |    8 
 src/api/reportAnalysis/salesStatistics.js                              |   16 
 src/views/productionPlan/trackProgress/index.vue                       |  667 ++++++++--------
 10 files changed, 1,501 insertions(+), 825 deletions(-)

diff --git a/src/api/costAccounting/productionSettlementBatches.js b/src/api/costAccounting/productionSettlementBatches.js
new file mode 100644
index 0000000..95a5fba
--- /dev/null
+++ b/src/api/costAccounting/productionSettlementBatches.js
@@ -0,0 +1,53 @@
+import request from "@/utils/request";
+
+// 鑾峰彇浜у搧绫诲埆锛堟寜鏈堜唤锛�
+export function getProductTypes(params) {
+  return request({
+    url: "/productionSettlementBatches/getProductTypes",
+    method: "get",
+    params,
+  });
+}
+
+// 鑾峰彇绉戠洰绫诲埆锛堟寜鏈堜唤锛�
+export function getSubjectNames(params) {
+  return request({
+    url: "/productionSettlementBatches/getSubjectNames",
+    method: "get",
+    params,
+  });
+}
+
+// 鏍囧噯鎴愭湰瀵煎叆锛坋l-upload 闇�瑕佸畬鏁� URL锛�
+export function getImportActionUrl() {
+  return `${import.meta.env.VITE_APP_BASE_API}/productionSettlementBatches/import`;
+}
+
+// 涓嬭浇瀵煎叆妯℃澘锛圙ET锛岃繑鍥� blob锛�
+export function downloadTemplate(params) {
+  return request({
+    url: "/productionSettlementBatches/downloadTemplate",
+    method: "get",
+    params,
+    responseType: "blob",
+  });
+}
+
+// 鏍哥畻鏌ヨ锛堟寜鏈堜唤/浜у搧绫诲瀷/绉戠洰/鎴愭湰绫诲瀷锛�
+export function getSettlement(params) {
+  return request({
+    url: "/productionSettlementBatches/getSettlement",
+    method: "get",
+    params,
+  });
+}
+
+// 姹囨�绘垚鏈紙绗簩妯″潡 KPI锛�
+export function getTotalCosts(params) {
+  return request({
+    url: "/productionSettlementBatches/getTotalCosts",
+    method: "get",
+    params,
+  });
+}
+
diff --git a/src/api/productionPlan/productionPlan.js b/src/api/productionPlan/productionPlan.js
index f064db9..beefbc8 100644
--- a/src/api/productionPlan/productionPlan.js
+++ b/src/api/productionPlan/productionPlan.js
@@ -68,4 +68,14 @@
     method: "post",
     data: query,
   });
-}
\ No newline at end of file
+}
+
+
+// 杩借釜杩涘害
+export function trackProgressByNo(query) {
+  return request({
+    url: "/track/trackProgressByNo",
+    method: "get",
+    params: query,
+  });
+}
diff --git a/src/api/reportAnalysis/salesStatistics.js b/src/api/reportAnalysis/salesStatistics.js
index 05b259e..bce6f28 100644
--- a/src/api/reportAnalysis/salesStatistics.js
+++ b/src/api/reportAnalysis/salesStatistics.js
@@ -14,4 +14,20 @@
     url: '/home/total',
     method: 'get'
   })
+}
+// 閿�閲忓垎鏋愯秼鍔垮浘
+export function getSalesAnalysisTrend(params) {
+  return request({
+    url: '/home/salesAnalysis',
+    method: 'get',
+    params: params
+  })
+}
+// 閿�鍞噾棰濆垎鏋�
+export function getSalesAmountAnalysis(params) {
+  return request({
+    url: '/home/salesAmount',
+    method: 'get',
+    params: params
+  })
 }
\ No newline at end of file
diff --git a/src/views/costAccounting/stdVsActCostAnalysis/index.vue b/src/views/costAccounting/stdVsActCostAnalysis/index.vue
index 51ff06c..55830cd 100644
--- a/src/views/costAccounting/stdVsActCostAnalysis/index.vue
+++ b/src/views/costAccounting/stdVsActCostAnalysis/index.vue
@@ -29,32 +29,30 @@
 
       <div class="filter-layout">
         <el-form :model="searchForm" :inline="true" class="filter-form">
-          <el-form-item label="鏈堜唤鑼冨洿">
+          <el-form-item label="鏈堜唤">
             <el-date-picker
-              v-model="searchForm.monthRange"
-              type="monthrange"
-              range-separator="鑷�"
-              start-placeholder="寮�濮嬫湀浠�"
-              end-placeholder="缁撴潫鏈堜唤"
+              v-model="searchForm.month"
+              type="month"
               value-format="YYYY-MM"
+              placeholder="閫夋嫨鏈堜唤"
               class="w-260"
-              @change="handleQuery"
+              @change="handleMonthChange"
             />
           </el-form-item>
-          <el-form-item label="浜у搧绫诲埆">
+          <el-form-item label="浜у搧绫诲瀷">
             <el-select
-              v-model="searchForm.category"
+              v-model="searchForm.productType"
               clearable
               filterable
-              placeholder="鍏ㄩ儴绫诲埆"
+              placeholder="鍏ㄩ儴绫诲瀷"
               class="w-180"
               @change="handleQuery"
             >
               <el-option
                 v-for="item in categoryOptions"
-                :key="item"
-                :label="item"
-                :value="item"
+                :key="item.value"
+                :label="item.label"
+                :value="item.value"
               />
             </el-select>
           </el-form-item>
@@ -62,12 +60,16 @@
             <el-select
               v-model="searchForm.costType"
               clearable
-              placeholder="鍏ㄩ儴绫诲瀷"
+              placeholder="鍏ㄩ儴鎴愭湰绫诲瀷"
               class="w-180"
               @change="handleQuery"
             >
-              <el-option label="鑳借�楁垚鏈�" value="鑳借�楁垚鏈�" />
-              <el-option label="鐢熶骇鎴愭湰" value="鐢熶骇鎴愭湰" />
+              <el-option
+                v-for="item in costTypeOptions"
+                :key="item.value"
+                :label="item.label"
+                :value="item.value"
+              />
             </el-select>
           </el-form-item>
         </el-form>
@@ -78,30 +80,31 @@
             <el-button class="lux-btn" @click="handleReset">閲嶇疆</el-button>
           </div>
           <div class="action-group">
-            <el-dropdown trigger="click" @command="handleImportCommand">
-              <el-button class="lux-btn" type="success" plain>
-                鏍囧噯鎴愭湰瀵煎叆
-                <el-icon class="el-icon--right"><ArrowDown /></el-icon>
-              </el-button>
-              <template #dropdown>
-                <el-dropdown-menu>
-                  <el-dropdown-item command="template">涓嬭浇瀵煎叆妯℃澘</el-dropdown-item>
-                  <el-dropdown-item command="upload">Excel 瀵煎叆</el-dropdown-item>
-                </el-dropdown-menu>
-              </template>
-            </el-dropdown>
-            <el-upload
-              ref="uploadRef"
-              class="hidden-upload"
-              :auto-upload="false"
-              :show-file-list="false"
-              accept=".xlsx,.xls"
-              :on-change="handleFileChange"
-            />
+            <el-button class="lux-btn" type="success" plain @click="openImportDialog">
+              鏍囧噯鎴愭湰瀵煎叆
+            </el-button>
           </div>
         </div>
       </div>
     </el-card>
+
+    <ImportDialog
+      ref="importDialogRef"
+      v-model="importDialogVisible"
+      title="鏍囧噯鎴愭湰瀵煎叆"
+      width="520px"
+      :headers="importHeaders"
+      :action="importAction"
+      :auto-upload="false"
+      :limit="1"
+      tip-text="浠呭厑璁稿鍏� xls銆亁lsx 鏍煎紡鏂囦欢銆�"
+      :show-download-template="true"
+      :on-success="handleImportSuccess"
+      @confirm="handleImportConfirm"
+      @download-template="downloadTemplate"
+      @close="handleImportDialogClose"
+      @cancel="handleImportDialogClose"
+    />
 
     <el-card class="panel-card glass-card kpi-card" shadow="never">
       <div class="kpi-strip">
@@ -194,29 +197,23 @@
         </div>
       </template>
       <el-table :data="pagedTableData" stripe class="lux-table" @sort-change="handleSortChange">
-        <el-table-column prop="month" label="鏈堜唤" width="110" />
-        <el-table-column prop="category" label="浜у搧绫诲埆" min-width="140" />
+        <el-table-column prop="periodTime" label="鏈堜唤" width="110" />
+        <el-table-column prop="productType" label="浜у搧绫诲瀷" min-width="140" />
         <el-table-column prop="costType" label="鎴愭湰绫诲瀷" min-width="120" />
-        <el-table-column prop="standardCost" label="鏍囧噯鎴愭湰(鍏�)" sortable="custom" align="right">
-          <template #default="scope">楼{{ formatMoney(scope.row.standardCost) }}</template>
+        <el-table-column prop="subjectName" label="绉戠洰" min-width="140" show-overflow-tooltip />
+        <el-table-column prop="budgetQty" label="棰勭畻鑰楅噺" sortable="custom" align="right" min-width="120" />
+        <el-table-column prop="budgetPrice" label="棰勭畻鍗曚环" sortable="custom" align="right" min-width="120" />
+        <el-table-column prop="budgetTotal" label="棰勭畻鎬绘垚鏈�" sortable="custom" align="right" min-width="130">
+          <template #default="scope">楼{{ formatMoney(scope.row.budgetTotal) }}</template>
         </el-table-column>
-        <el-table-column prop="actualCost" label="瀹為檯鎴愭湰(鍏�)" sortable="custom" align="right">
-          <template #default="scope">楼{{ formatMoney(scope.row.actualCost) }}</template>
+        <el-table-column prop="actualQty" label="瀹為檯鑰楅噺" sortable="custom" align="right" min-width="120" />
+        <el-table-column prop="actualPrice" label="瀹為檯鍗曚环" sortable="custom" align="right" min-width="120" />
+        <el-table-column prop="actualTotal" label="瀹為檯鎬绘垚鏈�" sortable="custom" align="right" min-width="130">
+          <template #default="scope">楼{{ formatMoney(scope.row.actualTotal) }}</template>
         </el-table-column>
-        <el-table-column prop="diff" label="宸紓(鍏�)" sortable="custom" align="right">
-          <template #default="scope">
-            <span :class="scope.row.diff >= 0 ? 'cost-value' : 'ok-value'">
-              {{ formatSignedMoney(scope.row.diff) }}
-            </span>
-          </template>
-        </el-table-column>
-        <el-table-column prop="diffRate" label="宸紓鐜�" sortable="custom" align="right">
-          <template #default="scope">
-            <span :class="scope.row.diffRate >= 0 ? 'cost-value' : 'ok-value'">
-              {{ formatPercent(scope.row.diffRate) }}
-            </span>
-          </template>
-        </el-table-column>
+        <el-table-column prop="diffQty" label="鑰楅噺宸紓" min-width="110" align="right" />
+        <el-table-column prop="diffPrice" label="鍗曚环宸紓" min-width="110" align="right" />
+        <el-table-column prop="diffTotal" label="鎬绘垚鏈樊寮�" min-width="110" align="right" />
       </el-table>
       <div class="pagination-container">
         <el-pagination
@@ -247,23 +244,40 @@
   ZoomIn,
 } from "@element-plus/icons-vue";
 import { ElMessage } from "element-plus";
+import ImportDialog from "@/components/Dialog/ImportDialog.vue";
+import { getToken } from "@/utils/auth.js";
 import * as echarts from "echarts";
-// import * as XLSX from "xlsx";
+import {
+  downloadTemplate as downloadProductionSettlementTemplate,
+  getImportActionUrl,
+  getSettlement,
+  getTotalCosts,
+  getProductTypes,
+} from "@/api/costAccounting/productionSettlementBatches";
 
-const getDefaultMonthRange = () => {
+const getDefaultMonth = () => {
   const end = new Date();
-  const start = new Date();
-  start.setMonth(start.getMonth() - 2);
-  return [start.toISOString().slice(0, 7), end.toISOString().slice(0, 7)];
+  return end.toISOString().slice(0, 7);
 };
 
 const searchForm = reactive({
-  monthRange: getDefaultMonthRange(),
-  category: "",
+  month: getDefaultMonth(),
+  productType: "",
   costType: "",
 });
 
-const uploadRef = ref();
+const categoryOptions = ref([]);
+const costTypeOptions = ref([]);
+
+const importDialogVisible = ref(false);
+const importDialogRef = ref(null);
+
+const importHeaders = computed(() => ({
+  Authorization: `Bearer ${getToken()}`,
+}));
+
+const importAction = computed(() => getImportActionUrl());
+
 const chartRef = ref(null);
 const largeChartRef = ref(null);
 let chartInstance = null;
@@ -271,150 +285,22 @@
 const largeChartVisible = ref(false);
 const currentChartOption = ref(null);
 
-// ------------------------------
-// 鍋囨暟鎹細鐢ㄤ簬鍏堣仈璋冮〉闈㈡覆鏌�
-// ------------------------------
-const actualCostSource = ref([]);
-const standardCostSource = ref([]);
-
-const fakeMonths = ["2026-01", "2026-02", "2026-03"];
-const fakeCategories = [
-  "绮夌叅鐏�",
-  "鐭崇伆",
-  "姘存偿",
-  "閾濈矇鑶�",
-  "鑴辨ā鍓�",
-  "鐭宠啅",
-  "鎵撳寘甯�",
-  "闃茶厫鍓傦紙鏉挎潗鐢級",
-  "姘у寲闀侊紙鏉挎潗鐢級",
-  "鍐锋尋涓濓紙鏉挎潗鐢級",
-  "鍗℃墸锛堟澘鏉愮敤锛�",
-  "鏉愭枡灏忚",
-  "姘�",
-  "鐢�",
-  "钂告苯",
-];
-
-const fakeCostType = (category) => (["姘�", "鐢�", "钂告苯"].includes(category) ? "鑳借�楁垚鏈�" : "鐢熶骇鎴愭湰");
-
-// 姣忎釜绫诲埆鐨勬爣鍑嗘垚鏈熀鍑嗗�硷紙浠呯敤浜庡亣鏁版嵁锛�
-const baseStandardCostByCategory = {
-  绮夌叅鐏�: 98000,
-  鐭崇伆: 52000,
-  姘存偿: 175000,
-  閾濈矇鑶�: 32000,
-  鑴辨ā鍓�: 21000,
-  鐭宠啅: 41000,
-  鎵撳寘甯�: 14500,
-  "闃茶厫鍓傦紙鏉挎潗鐢級": 12500,
-  "姘у寲闀侊紙鏉挎潗鐢級": 22000,
-  "鍐锋尋涓濓紙鏉挎潗鐢級": 9800,
-  "鍗℃墸锛堟澘鏉愮敤锛�": 8600,
-  鏉愭枡灏忚: 420000,
-  姘�: 6800,
-  鐢�: 26000,
-  钂告苯: 52000,
-};
-
-// 鏈堜唤娉㈠姩绯绘暟锛堣鍥捐〃鐪嬭捣鏉ユ洿鈥滅湡瀹炩�濅竴浜涳級
-const monthFactorByMonth = {
-  "2026-01": 1.0,
-  "2026-02": 1.06,
-  "2026-03": 0.97,
-};
-
-// 瀹為檯鎴愭湰鐩稿鏍囧噯鎴愭湰鐨勫亸绉绘瘮渚嬶紙鐢ㄤ簬娴嬭瘯姝h礋宸紓灞曠ず锛�
-const diffRatioByCategory = {
-  绮夌叅鐏�: 0.05,
-  鐭崇伆: -0.01,
-  姘存偿: 0.03,
-  閾濈矇鑶�: 0.0,
-  鑴辨ā鍓�: -0.04,
-  鐭宠啅: 0.02,
-  鎵撳寘甯�: -0.03,
-  "闃茶厫鍓傦紙鏉挎潗鐢級": 0.06,
-  "姘у寲闀侊紙鏉挎潗鐢級": -0.02,
-  "鍐锋尋涓濓紙鏉挎潗鐢級": 0.01,
-  "鍗℃墸锛堟澘鏉愮敤锛�": -0.05,
-  鏉愭枡灏忚: 0.02,
-  姘�: -0.01,
-  鐢�: 0.04,
-  钂告苯: -0.03,
-};
-
-const buildFakeSources = () => {
-  const stdRows = [];
-  const actRows = [];
-
-  for (const month of fakeMonths) {
-    const monthFactor = monthFactorByMonth[month] ?? 1;
-    const monthAdj = month === "2026-02" ? 0.005 : month === "2026-03" ? -0.006 : 0;
-
-    for (const category of fakeCategories) {
-      const costType = fakeCostType(category);
-      const base = baseStandardCostByCategory[category] ?? 0;
-      const standardCost = Math.round(base * monthFactor);
-      const diffRatio = (diffRatioByCategory[category] ?? 0) + monthAdj;
-      const actualCost = Math.round(standardCost * (1 + diffRatio));
-
-      stdRows.push({ month, category, costType, standardCost });
-      actRows.push({ month, category, costType, actualCost });
-    }
-  }
-
-  standardCostSource.value = stdRows;
-  actualCostSource.value = actRows;
-};
-
-buildFakeSources();
-
-const categoryOptions = computed(() => {
-  const all = [...actualCostSource.value, ...standardCostSource.value];
-  return Array.from(new Set(all.map((item) => item.category)));
+const settlementRows = ref([]);
+const totalCosts = reactive({
+  budgetTotal: 0,
+  actualTotal: 0,
+  diffTotal: 0,
+  diffRate: "0%",
 });
 
-const inRange = (value, range) => {
-  if (!Array.isArray(range) || range.length !== 2 || !range[0] || !range[1]) return true;
-  return value >= range[0] && value <= range[1];
-};
-
-const mergedRows = computed(() => {
-  const key = (item) => `${item.month}__${item.category}__${item.costType}`;
-  const stdMap = new Map(standardCostSource.value.map((item) => [key(item), item]));
-  const actMap = new Map(actualCostSource.value.map((item) => [key(item), item]));
-  const keySet = new Set([...stdMap.keys(), ...actMap.keys()]);
-  const rows = [];
-
-  for (const k of keySet) {
-    const std = stdMap.get(k);
-    const act = actMap.get(k);
-    const month = std?.month || act?.month || "";
-    const category = std?.category || act?.category || "";
-    const costType = std?.costType || act?.costType || "";
-    const standardCost = Number(std?.standardCost || 0);
-    const actualCost = Number(act?.actualCost || 0);
-    const diff = actualCost - standardCost;
-    const diffRate = standardCost === 0 ? 0 : (diff / standardCost) * 100;
-
-    rows.push({ month, category, costType, standardCost, actualCost, diff, diffRate });
-  }
-
-  return rows.sort((a, b) => {
-    if (a.month !== b.month) return a.month > b.month ? 1 : -1;
-    if (a.category !== b.category) return a.category.localeCompare(b.category, "zh-Hans-CN");
-    return a.costType.localeCompare(b.costType, "zh-Hans-CN");
+const tableData = computed(() => {
+  return (Array.isArray(settlementRows.value) ? settlementRows.value : []).filter((item) => {
+    const hitMonth = !searchForm.month || item.periodTime === searchForm.month;
+    const hitProductType = !searchForm.productType || item.productType === searchForm.productType;
+    const hitCostType = !searchForm.costType || item.costType === searchForm.costType;
+    return hitMonth && hitProductType && hitCostType;
   });
 });
-
-const tableData = computed(() =>
-  mergedRows.value.filter((item) => {
-    const hitMonth = inRange(item.month, searchForm.monthRange);
-    const hitCategory = !searchForm.category || item.category === searchForm.category;
-    const hitCostType = !searchForm.costType || item.costType === searchForm.costType;
-    return hitMonth && hitCategory && hitCostType;
-  })
-);
 
 const page = reactive({
   current: 1,
@@ -454,26 +340,45 @@
   return sortedTableData.value.slice(start, start + page.size);
 });
 
-const overview = computed(() => {
-  const standardCost = tableData.value.reduce((sum, item) => sum + item.standardCost, 0);
-  const actualCost = tableData.value.reduce((sum, item) => sum + item.actualCost, 0);
-  const diff = actualCost - standardCost;
-  const diffRate = standardCost === 0 ? 0 : (diff / standardCost) * 100;
-  return { standardCost, actualCost, diff, diffRate };
-});
+const overview = computed(() => ({
+  standardCost: Number(totalCosts.budgetTotal || 0),
+  actualCost: Number(totalCosts.actualTotal || 0),
+  diff: Number(totalCosts.diffTotal || 0),
+  diffRate: totalCosts.diffRate ?? "0%",
+}));
 
 const getChartData = () => {
-  const xAxis = tableData.value.map(
-    (item) => `${item.month}\n${item.category}-${item.costType.replace("鎴愭湰", "")}`
+  // 鍥捐〃鍙e緞锛氭寜鈥滅鐩�濇眹鎬诲睍绀哄叏閮ㄧ鐩�
+  const agg = new Map();
+  for (const row of tableData.value) {
+    const subjectName = String(row?.subjectName || "").trim() || "-";
+    const budgetTotal = Number(row?.budgetTotal || 0);
+    const actualTotal = Number(row?.actualTotal || 0);
+    const bucket = agg.get(subjectName) || { subjectName, budgetTotal: 0, actualTotal: 0 };
+    bucket.budgetTotal += Number.isFinite(budgetTotal) ? budgetTotal : 0;
+    bucket.actualTotal += Number.isFinite(actualTotal) ? actualTotal : 0;
+    agg.set(subjectName, bucket);
+  }
+
+  const rows = Array.from(agg.values()).sort((a, b) =>
+    String(a.subjectName).localeCompare(String(b.subjectName), "zh-Hans-CN")
   );
-  const standard = tableData.value.map((item) => item.standardCost);
-  const actual = tableData.value.map((item) => item.actualCost);
-  const diffRate = tableData.value.map((item) => Number(item.diffRate.toFixed(2)));
-  return { xAxis, standard, actual, diffRate };
+
+  const xAxis = rows.map((item) => item.subjectName);
+  const standard = rows.map((item) => item.budgetTotal);
+  const actual = rows.map((item) => item.actualTotal);
+  const diffRate = rows.map((item) => {
+    const base = Number(item.budgetTotal || 0);
+    const diff = Number(item.actualTotal || 0) - base;
+    if (!base) return 0;
+    return (diff / base) * 100;
+  });
+
+  return { xAxis, standard, actual, diffRate, rows };
 };
 
 const buildChartOption = () => {
-  const { xAxis, standard, actual, diffRate } = getChartData();
+  const { xAxis, standard, actual, diffRate, rows } = getChartData();
   return {
     animation: true,
     animationDuration: 920,
@@ -493,13 +398,17 @@
       textStyle: { color: "rgba(15, 23, 42, 0.88)" },
       extraCssText: "box-shadow: 0 12px 40px rgba(15, 23, 42, 0.12); border-radius: 12px;",
       formatter: (params) => {
-        const row = tableData.value[params[0]?.dataIndex] || {};
+        const row = rows?.[params[0]?.dataIndex] || {};
+        const budgetTotal = Number(row?.budgetTotal || 0);
+        const actualTotal = Number(row?.actualTotal || 0);
+        const diff = actualTotal - budgetTotal;
+        const rate = budgetTotal ? (diff / budgetTotal) * 100 : 0;
         return [
-          `${row.month || ""} ${row.category || ""} ${row.costType || ""}`,
-          `鏍囧噯鎴愭湰锛毬�${formatMoney(row.standardCost || 0)}`,
-          `瀹為檯鎴愭湰锛毬�${formatMoney(row.actualCost || 0)}`,
-          `宸紓锛�${formatSignedMoney(row.diff || 0)}`,
-          `宸紓鐜囷細${formatPercent(row.diffRate || 0)}`,
+          `绉戠洰锛�${row.subjectName || "-"}`,
+          `棰勭畻鎬绘垚鏈細楼${formatMoney(budgetTotal)}`,
+          `瀹為檯鎬绘垚鏈細楼${formatMoney(actualTotal)}`,
+          `宸紓锛�${formatSignedMoney(diff)}`,
+          `宸紓鐜囷細${formatPercent(rate)}`,
         ].join("<br/>");
       },
     },
@@ -636,72 +545,144 @@
   standardCostSource.value = Array.from(map.values());
 };
 
-const handleFileChange = async (uploadFile) => {
-  try {
-    const file = uploadFile.raw;
-    if (!file) return;
-    const data = await file.arrayBuffer();
-    const workbook = XLSX.read(data, { type: "array" });
-    const sheetName = workbook.SheetNames[0];
-    const sheet = workbook.Sheets[sheetName];
-    const rows = XLSX.utils.sheet_to_json(sheet, { defval: "" });
-    const parsed = parseImportedRows(rows);
-    if (!parsed.length) {
-      ElMessage.warning("瀵煎叆澶辫触锛氭ā鏉垮唴瀹逛负绌烘垨瀛楁涓嶅尮閰�");
-      return;
-    }
-    replaceStandardSourceByImport(parsed);
-    ElMessage.success(`瀵煎叆鎴愬姛锛�${parsed.length} 鏉℃爣鍑嗘垚鏈褰昤);
-    handleQuery();
-  } catch (error) {
-    console.error(error);
-    ElMessage.error("瀵煎叆澶辫触锛岃妫�鏌� Excel 鏍煎紡");
-  } finally {
-    uploadRef.value?.clearFiles?.();
-  }
+const openImportDialog = () => {
+  importDialogVisible.value = true;
 };
 
-const openUploadSelector = () => {
-  const input = uploadRef.value?.$el?.querySelector?.("input[type='file']");
-  if (!input) {
-    ElMessage.warning("涓婁紶缁勪欢灏氭湭灏辩华锛岃绋嶅悗閲嶈瘯");
-    return;
-  }
-  input.click();
+const handleImportConfirm = () => {
+  importDialogRef.value?.submit?.();
 };
 
-const handleImportCommand = (command) => {
-  if (command === "template") {
-    downloadTemplate();
-    return;
-  }
-  if (command === "upload") {
-    openUploadSelector();
-  }
+const handleImportDialogClose = () => {
+  importDialogRef.value?.clearFiles?.();
 };
 
 const downloadTemplate = () => {
-  const sample = [
-    { 鏈堜唤: "2026-03", 浜у搧绫诲埆: "绮夌叅鐏�", 鎴愭湰绫诲瀷: "鏍囧噯鐢熶骇鎴愭湰", 鏍囧噯鎴愭湰: 98000 },
-    { 鏈堜唤: "2026-03", 浜у搧绫诲埆: "姘存偿", 鎴愭湰绫诲瀷: "鏍囧噯鐢熶骇鎴愭湰", 鏍囧噯鎴愭湰: 175000 },
-    { 鏈堜唤: "2026-03", 浜у搧绫诲埆: "鐢�", 鎴愭湰绫诲瀷: "鏍囧噯鑳借�楁垚鏈�", 鏍囧噯鎴愭湰: 26000 },
-    { 鏈堜唤: "2026-03", 浜у搧绫诲埆: "钂告苯", 鎴愭湰绫诲瀷: "鏍囧噯鑳借�楁垚鏈�", 鏍囧噯鎴愭湰: 52000 },
-    { 鏈堜唤: "2026-03", 浜у搧绫诲埆: "姘�", 鎴愭湰绫诲瀷: "鏍囧噯鑳借�楁垚鏈�", 鏍囧噯鎴愭湰: 6800 },
-  ];
-  const ws = XLSX.utils.json_to_sheet(sample);
-  const wb = XLSX.utils.book_new();
-  XLSX.utils.book_append_sheet(wb, ws, "鏍囧噯鎴愭湰妯℃澘");
-  XLSX.writeFile(wb, "鏍囧噯鎴愭湰鎸夋湀瀵煎叆妯℃澘.xlsx");
-  ElMessage.success("妯℃澘宸蹭笅杞�");
+  downloadProductionSettlementTemplate({ periodTime: searchForm.month || undefined })
+    .then((data) => {
+      const blob =
+        data instanceof Blob
+          ? data
+          : new Blob([data], {
+              type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+            });
+      const url = window.URL.createObjectURL(blob);
+      const link = document.createElement("a");
+      link.href = url;
+      link.download = "鏍囧噯鎴愭湰瀵煎叆妯℃澘.xlsx";
+      document.body.appendChild(link);
+      link.click();
+      document.body.removeChild(link);
+      window.URL.revokeObjectURL(url);
+      ElMessage.success("妯℃澘涓嬭浇鎴愬姛");
+    })
+    .catch(() => {
+      ElMessage.error("妯℃澘涓嬭浇澶辫触");
+    });
 };
 
-const handleQuery = () => {
-  updateChart();
+const handleImportSuccess = (response) => {
+  const code = response?.code;
+  const msg = response?.msg || response?.message;
+  if (code === 200) {
+    ElMessage.success(msg || "瀵煎叆鎴愬姛");
+    importDialogVisible.value = false;
+    importDialogRef.value?.clearFiles?.();
+    handleQuery();
+    return;
+  }
+  ElMessage.error(msg || "瀵煎叆澶辫触");
+};
+
+const normalizeSettlementResponse = (data) => {
+  const map = data && typeof data === "object" ? data : {};
+  const rows = [];
+  for (const [costType, list] of Object.entries(map)) {
+    if (!Array.isArray(list)) continue;
+    for (const item of list) {
+      rows.push({
+        ...item,
+        periodTime: searchForm.month,
+        costType: costType,
+      });
+    }
+  }
+  return rows;
+};
+
+const fetchCategoryOptions = async () => {
+  if (!searchForm.month) {
+    categoryOptions.value = [];
+    return;
+  }
+  try {
+    const { data } = await getProductTypes({ periodTime: searchForm.month });
+    const list = Array.isArray(data) ? data : data?.records || [];
+    categoryOptions.value = list.map((item) => ({
+      label: item.label || item.name || item.typeName || item,
+      value: item.value || item.code || item.typeCode || item,
+    }));
+  } catch (e) {
+    categoryOptions.value = [];
+  }
+};
+
+const fetchCostTypeOptions = async () => {
+  if (!searchForm.month) {
+    costTypeOptions.value = [];
+    return;
+  }
+  try {
+    // 涓嶅甫 costType锛屾嬁鍒板畬鏁村垎缁� key 鐢ㄤ簬涓嬫媺閫夐」
+    const res = await getSettlement({ periodTime: searchForm.month });
+    const map = res?.data || {};
+    const keys = Object.keys(map || {});
+    costTypeOptions.value = keys.map((k) => ({ label: k, value: k }));
+  } catch (e) {
+    costTypeOptions.value = [];
+  }
+};
+
+const handleMonthChange = () => {
+  searchForm.productType = "";
+  searchForm.costType = "";
+  Promise.all([fetchCategoryOptions(), fetchCostTypeOptions()]).then(() => {
+    handleQuery();
+  });
+};
+
+const handleQuery = async () => {
+  try {
+    const params = {
+      periodTime: searchForm.month || undefined,
+      productType: searchForm.productType || undefined,
+      costType: searchForm.costType || undefined,
+    };
+    const [settlementRes, totalRes] = await Promise.all([getSettlement(params), getTotalCosts(params)]);
+    const map = settlementRes?.data || {};
+    const rows = normalizeSettlementResponse(map);
+    settlementRows.value = rows;
+
+    const totals = totalRes?.data || {};
+    totalCosts.budgetTotal = Number(totals.budgetTotal || 0);
+    totalCosts.actualTotal = Number(totals.actualTotal || 0);
+    totalCosts.diffTotal = Number(totals.diffTotal || 0);
+    totalCosts.diffRate = totals.diffRate ?? "0%";
+
+    updateChart();
+  } catch (e) {
+    settlementRows.value = [];
+    totalCosts.budgetTotal = 0;
+    totalCosts.actualTotal = 0;
+    totalCosts.diffTotal = 0;
+    totalCosts.diffRate = "0%";
+    updateChart();
+  }
 };
 
 const handleReset = () => {
-  searchForm.monthRange = getDefaultMonthRange();
-  searchForm.category = "";
+  searchForm.month = getDefaultMonth();
+  searchForm.productType = "";
   searchForm.costType = "";
   tableSort.prop = "";
   tableSort.order = "";
@@ -735,6 +716,7 @@
 };
 
 const formatPercent = (v) => {
+  if (typeof v === "string" && v.trim().endsWith("%")) return v.trim();
   const n = Number.parseFloat(v);
   const value = Number.isFinite(n) ? n : 0;
   const sign = value >= 0 ? "+" : "";
@@ -802,6 +784,9 @@
     }
     updateChart();
   });
+  Promise.all([fetchCategoryOptions(), fetchCostTypeOptions()]).then(() => {
+    handleQuery();
+  });
   window.addEventListener("resize", handleResize);
 });
 
diff --git a/src/views/index.vue b/src/views/index.vue
index c6f00fc..bd0d274 100644
--- a/src/views/index.vue
+++ b/src/views/index.vue
@@ -2,9 +2,9 @@
   <div class="home-page">
     <div class="top-bar">
       <div class="user-box">
-        <!-- <img :src="userStore.avatar"
+        <img :src="userStore.avatar"
              class="avatar"
-             alt="" /> -->
+             alt="" />
         <div>
           <div class="hello">{{ userStore.roleName || "绯荤粺绠$悊鍛�" }}锛屼綘濂�</div>
           <div class="sub">鐧诲綍鏃堕棿锛歿{ userStore.currentLoginTime }}</div>
@@ -16,9 +16,9 @@
                    type="primary"
                    plain
                    @click="refreshDashboardData">鍒锋柊鏁版嵁</el-button>
-        <el-button size="small"
+        <!-- <el-button size="small"
                    plain
-                   @click="configDialogVisible = true">棣栭〉閰嶇疆</el-button>
+                   @click="configDialogVisible = true">棣栭〉閰嶇疆</el-button> -->
       </div>
     </div>
     <div class="content-grid">
@@ -40,7 +40,7 @@
             </el-button>
           </div>
         </section>
-        <section class="section-card">
+        <!-- <section class="section-card">
           <div class="section-title">閲嶇偣寰呭姙</div>
           <div class="todo-row"
                v-for="todo in todos"
@@ -49,7 +49,7 @@
                     :type="todo.type">{{ todo.level }}</el-tag>
             <span>{{ todo.title }}</span>
           </div>
-        </section>
+        </section> -->
         <section class="section-card">
           <div class="section-title">缁忚惀鍏虫敞</div>
           <div class="focus-row"
@@ -61,33 +61,17 @@
         </section>
         <section class="section-card flex-fill-card">
           <div class="section-title-row">
-            <div class="section-title">浠婃棩寰呭鐞�</div>
+            <div class="section-title">浠婂勾閿�鍞噾棰濆垎鏋�</div>
             <el-radio-group v-model="pendingFilter"
                             size="small">
-              <el-radio-button label="all">鍏ㄩ儴</el-radio-button>
-              <el-radio-button label="mine">鎴戠殑</el-radio-button>
-              <el-radio-button label="high">楂樹紭鍏�</el-radio-button>
+              <el-radio-button label="mine">鏉挎潗</el-radio-button>
+              <el-radio-button label="high">鐮屽潡</el-radio-button>
             </el-radio-group>
           </div>
-          <div class="task-row"
-               v-for="task in filteredPendingTasks"
-               :key="task.id">
-            <div class="task-left">
-              <el-tag size="small"
-                      :type="task.type">{{ task.level }}</el-tag>
-              <span class="task-title">{{ task.title }}</span>
-            </div>
-            <el-button link
-                       type="primary"
-                       @click="goTo(task.path)">鍘诲鐞�</el-button>
-          </div>
-          <el-empty v-if="filteredPendingTasks.length === 0"
-                    description="鏆傛棤寰呭鐞嗕簨椤�"
-                    :image-size="80" />
         </section>
       </div>
       <div class="right-col">
-        <section class="section-card"
+        <!-- <section class="section-card"
                  v-if="isSectionVisible('trendCards')">
           <div class="section-title">鏈�杩�7澶╁叧閿寚鏍囪秼鍔�</div>
           <div class="trend-cards">
@@ -111,7 +95,7 @@
               </div>
             </div>
           </div>
-        </section>
+        </section> -->
         <section class="section-card"
                  v-if="isSectionVisible('planTrend')">
           <div class="section-title-row">
@@ -137,35 +121,25 @@
              v-if="isSectionVisible('qualityChart') || isSectionVisible('costChart')">
           <section class="section-card"
                    v-if="isSectionVisible('qualityChart')">
-            <div class="section-title-row">
-              <div class="section-title">璐ㄦ寮傚父鍒嗗竷</div>
-              <el-radio-group v-model="chartRangeQuality"
-                              size="small"
-                              @change="loadQualityData">
-                <el-radio-button :label="1">鍛�</el-radio-button>
-                <el-radio-button :label="2">鏈�</el-radio-button>
-                <el-radio-button :label="3">瀛e害</el-radio-button>
-              </el-radio-group>
-            </div>
+            <div class="section-title">浠婂勾鑳借�楃敤閲忚秼鍔�</div>
             <Echarts :chartStyle="chartStyle"
                      :grid="grid"
                      :tooltip="barTooltip"
-                     :xAxis="qualityXAxis"
+                     :xAxis="energyConsumptionXAxis"
                      :yAxis="valueYAxis"
-                     :series="qualitySeries"
+                     :series="energyConsumptionSeries"
                      style="height: 260px" />
           </section>
           <section class="section-card"
                    v-if="isSectionVisible('costChart')">
-            <div class="section-title">鑳借�椾笌鎴愭湰缁撴瀯</div>
+            <div class="section-title">浠婂勾鑳借�楃被鍨嬪崰姣�</div>
             <Echarts :chartStyle="chartStyle"
-                     :legend="costLegend"
                      :tooltip="pieTooltip"
-                     :series="costSeries"
+                     :series="energyTypeSeries"
                      style="height: 260px" />
           </section>
         </div>
-        <section class="section-card"
+        <!-- <section class="section-card"
                  v-if="isSectionVisible('warningCenter')">
           <div class="section-title">寮傚父棰勮涓績</div>
           <div class="warning-row"
@@ -183,7 +157,7 @@
           <el-empty v-if="warningList.length === 0"
                     description="鏆傛棤寮傚父棰勮"
                     :image-size="80" />
-        </section>
+        </section> -->
         <section class="section-card mini-table-wrap"
                  v-if="isSectionVisible('planTable')">
           <div class="section-title">鐢熶骇璁″垝鎵ц鏄庣粏</div>
@@ -299,6 +273,7 @@
     qualityInspectionStatistics,
     nonComplianceWarning,
   } from "@/api/viewIndex.js";
+  import { energyConsumptionDetailStatistics } from "@/api/energyManagement/energyType";
 
   const router = useRouter();
   const userStore = useUserStore();
@@ -542,6 +517,150 @@
       data: [],
     },
   ]);
+
+  // 鑳借�楃被鍨嬪崰姣旀暟鎹�
+  const energyTypeSeries = reactive([
+    {
+      type: "pie",
+      radius: ["40%", "70%"],
+      center: ["50%", "50%"],
+      avoidLabelOverlap: false,
+      itemStyle: {
+        borderRadius: 10,
+        borderColor: "#fff",
+        borderWidth: 2,
+      },
+      label: {
+        show: true,
+        formatter: "{b}: {d}%",
+      },
+      data: [
+        { value: 0, name: "姘�", itemStyle: { color: "#409EFF" } },
+        { value: 0, name: "鐢�", itemStyle: { color: "#E6A23C" } },
+        { value: 0, name: "姘�", itemStyle: { color: "#F56C6C" } },
+      ],
+    },
+  ]);
+
+  // 鑳借�楃敤閲忚秼鍔垮浘琛�
+  const energyConsumptionXAxis = reactive({
+    type: "category",
+    data: [],
+    axisLabel: {
+      rotate: 45,
+    },
+  });
+
+  const energyConsumptionSeries = reactive([
+    {
+      name: "鐢ㄦ按閲�",
+      type: "bar",
+      data: [],
+      itemStyle: { color: "#409EFF" },
+    },
+    {
+      name: "鐢ㄧ數閲�",
+      type: "bar",
+      data: [],
+      itemStyle: { color: "#E6A23C" },
+    },
+    {
+      name: "鐢ㄦ皵閲�",
+      type: "bar",
+      data: [],
+      itemStyle: { color: "#67C23A" },
+    },
+  ]);
+
+  // 妯℃嫙鑳借�楁暟鎹�
+  const energyData = reactive({
+    water: 120,
+    electricity: 350,
+    gas: 80,
+  });
+
+  // 鏇存柊鑳借�楃被鍨嬪崰姣斿浘琛ㄥ拰鑳借�楃敤閲忚秼鍔垮浘琛�
+  const updateEnergyTypeChart = () => {
+    // 鏋勫缓鍙傛暟锛氫粖骞寸殑骞村垵鍒板勾鏈互鍙婂ぉ鏁�
+    const currentYear = new Date().getFullYear();
+    const params = {
+      startDate: `${currentYear}-01-01`,
+      endDate: `${currentYear}-12-31`,
+      days: 365,
+      state: "骞�",
+    };
+
+    // 璋冪敤鎺ュ彛鑾峰彇鏁版嵁
+    energyConsumptionDetailStatistics(params)
+      .then(res => {
+        if (res.code === 200) {
+          const data = res.data;
+          // 澶勭悊鑳借�楃被鍨嬪崰姣旀暟鎹�
+          const energyTypeData = data.energyCostDtos || [];
+
+          // 璁$畻鍚勮兘鑰楃被鍨嬬殑鎬绘秷鑰楅噺
+          let total = 0;
+          const typeMap = {
+            姘�: 0,
+            鐢�: 0,
+            姘�: 0,
+          };
+
+          // 鍑嗗鑳借�楃敤閲忚秼鍔垮浘琛ㄦ暟鎹�
+          const dates = [];
+          const waterConsumptionData = [];
+          const electricityConsumptionData = [];
+          const gasConsumptionData = [];
+
+          energyTypeData.forEach(item => {
+            // 鏀堕泦鏃ユ湡鍜屽悇鑳借�楃被鍨嬫暟鎹�
+            if (item.meterReadingDate) {
+              dates.push(item.meterReadingDate);
+              waterConsumptionData.push(item.waterConsumption || 0);
+              electricityConsumptionData.push(item.electricityConsumption || 0);
+              gasConsumptionData.push(item.gasConsumption || 0);
+            }
+
+            // 璁$畻鎬绘秷鑰楅噺
+            if (item.waterConsumption)
+              typeMap.姘� += Number(item.waterConsumption);
+            if (item.electricityConsumption)
+              typeMap.鐢� += Number(item.electricityConsumption);
+            if (item.gasConsumption) typeMap.姘� += Number(item.gasConsumption);
+          });
+
+          total = typeMap.姘� + typeMap.鐢� + typeMap.姘�;
+
+          // 鏇存柊鑳借�楃被鍨嬪崰姣斿浘琛ㄦ暟鎹�
+          energyTypeSeries[0].data = [
+            {
+              value: total > 0 ? ((typeMap.姘� / total) * 100).toFixed(2) : 0,
+              name: "姘�",
+              itemStyle: { color: "#409EFF" },
+            },
+            {
+              value: total > 0 ? ((typeMap.鐢� / total) * 100).toFixed(2) : 0,
+              name: "鐢�",
+              itemStyle: { color: "#E6A23C" },
+            },
+            {
+              value: total > 0 ? ((typeMap.姘� / total) * 100).toFixed(2) : 0,
+              name: "姘�",
+              itemStyle: { color: "#F56C6C" },
+            },
+          ];
+
+          // 鏇存柊鑳借�楃敤閲忚秼鍔垮浘琛ㄦ暟鎹�
+          energyConsumptionXAxis.data = dates;
+          energyConsumptionSeries[0].data = waterConsumptionData;
+          energyConsumptionSeries[1].data = electricityConsumptionData;
+          energyConsumptionSeries[2].data = gasConsumptionData;
+        }
+      })
+      .catch(err => {
+        console.error("鑾峰彇鑳借�楁暟鎹紓甯革細", err);
+      });
+  };
 
   const planTable = reactive([]);
   const recentTrendCards = reactive([
@@ -976,18 +1095,19 @@
   };
 
   const refreshDashboardData = () => {
-    loadHomeTodos();
-    loadOrderAndProgress();
-    loadPlanTrend();
-    loadQualityData();
-    loadCostComposition();
-    loadWarningCenter();
+    // loadHomeTodos();
+    // loadOrderAndProgress();
+    // loadPlanTrend();
+    // loadQualityData();
+    // loadCostComposition();
+    // loadWarningCenter();
+    updateEnergyTypeChart();
     lastUpdatedAt.value = new Date().toLocaleString();
   };
 
   onMounted(() => {
     // initSectionConfig();
-    // refreshDashboardData();
+    refreshDashboardData();
   });
 </script>
 
diff --git a/src/views/productionManagement/processRoute/index.vue b/src/views/productionManagement/processRoute/index.vue
index f907915..d066a54 100644
--- a/src/views/productionManagement/processRoute/index.vue
+++ b/src/views/productionManagement/processRoute/index.vue
@@ -247,6 +247,7 @@
         bomId: row.bomId || null,
         description: row.description || "",
         type: "route",
+        status: row.status || false,
       },
     });
   };
diff --git a/src/views/productionManagement/processRoute/processRouteItem/index.vue b/src/views/productionManagement/processRoute/processRouteItem/index.vue
index d7fadd3..a2c5ce5 100644
--- a/src/views/productionManagement/processRoute/processRouteItem/index.vue
+++ b/src/views/productionManagement/processRoute/processRouteItem/index.vue
@@ -47,13 +47,15 @@
          class="section-header">
       <div class="section-title">宸ヨ壓璺嚎椤圭洰鍒楄〃</div>
       <div class="section-actions">
-        <div class="sort-tip">鎷栨嫿琛ㄦ牸鎺掑簭</div>
+        <div v-if="!routeInfo.status"
+             class="sort-tip">鎷栨嫿琛ㄦ牸鎺掑簭</div>
         <el-button icon="Grid"
                    @click="toggleView"
                    style="margin-right: 10px;">
           鍗$墖瑙嗗浘
         </el-button>
-        <el-button type="primary"
+        <el-button v-if="!routeInfo.status"
+                   type="primary"
                    @click="handleAdd">鏂板</el-button>
       </div>
     </div>
@@ -97,6 +99,7 @@
         </template>
       </el-table-column>
       <el-table-column label="鎿嶄綔"
+                       v-if="!routeInfo.status"
                        align="center"
                        fixed="right"
                        width="150">
@@ -119,13 +122,15 @@
       <div class="section-header">
         <div class="section-title">宸ヨ壓璺嚎椤圭洰鍒楄〃</div>
         <div class="section-actions">
-          <div class="sort-tip">闀挎寜鎷栨嫿鍗$墖鎺掑簭</div>
+          <div v-if="!routeInfo.status"
+               class="sort-tip">闀挎寜鎷栨嫿鍗$墖鎺掑簭</div>
           <el-button icon="Menu"
                      @click="toggleView"
                      style="margin-right: 10px;">
             琛ㄦ牸瑙嗗浘
           </el-button>
           <el-button type="primary"
+                     v-if="!routeInfo.status"
                      @click="handleAdd">鏂板</el-button>
         </div>
       </div>
@@ -150,6 +155,7 @@
               <el-button type="primary"
                          link
                          size="small"
+                         v-if="!routeInfo.status"
                          @click="handleEdit(item)"
                          :disabled="item.isComplete">缂栬緫</el-button>
               <el-button type="info"
@@ -159,6 +165,7 @@
               <el-button type="danger"
                          link
                          size="small"
+                         v-if="!routeInfo.status"
                          @click="handleDelete(item)"
                          :disabled="item.isComplete">鍒犻櫎</el-button>
             </div>
@@ -262,7 +269,7 @@
                       <span v-else>{{ row.unit }}</span>
                     </template>
                   </el-table-column>
-                   <el-table-column prop="unitPrice"
+                  <el-table-column prop="unitPrice"
                                    label="鍗曚环">
                     <template #default="{ row }">
                       <el-form-item v-if="bomDataValue.isEdit"
@@ -541,6 +548,7 @@
       dictLabel: route.query.dictLabel || "",
       bomId: route.query.bomId || null,
       description: route.query.description || "",
+      status: route.query.status === "true" ? true : false,
     };
     if (pageType.value === "order") {
       queryList2(route.query.orderId)
diff --git a/src/views/productionPlan/productionPlan/index.vue b/src/views/productionPlan/productionPlan/index.vue
index b337aa3..9cdbfd6 100644
--- a/src/views/productionPlan/productionPlan/index.vue
+++ b/src/views/productionPlan/productionPlan/index.vue
@@ -674,7 +674,10 @@
     router.push({
       path: "/productionPlan/trackProgress",
       query: {
-        applyNo: encodeURIComponent(row.applyNo),
+        id: row.id,
+        applyNo: row.applyNo,
+        productName: row.productName,
+        model: row.model,
       },
     });
   };
@@ -1559,4 +1562,7 @@
   //     margin-bottom: 0px !important;
   //   }
   // }
+  :deep(.el-table .el-table__body-wrapper tr td) {
+    background-color: #fff;
+  }
 </style>
diff --git a/src/views/productionPlan/trackProgress/index.vue b/src/views/productionPlan/trackProgress/index.vue
index 9a4ceda..92713f9 100644
--- a/src/views/productionPlan/trackProgress/index.vue
+++ b/src/views/productionPlan/trackProgress/index.vue
@@ -10,92 +10,118 @@
                    :model="searchForm"
                    class="search-form">
             <el-form-item label="鐢宠鍗曠紪鍙�">
-              <el-input v-model="searchForm.applyNo"
-                        placeholder="璇疯緭鍏ョ敵璇峰崟缂栧彿"
-                        style="width: 400px;"></el-input>
-            </el-form-item>
-            <el-form-item>
-              <el-button type="primary"
-                         @click="handleSearch">鎼滅储</el-button>
+              <el-select v-model="selectedApplyNo"
+                         filterable
+                         remote
+                         reserve-keyword
+                         placeholder="璇疯緭鍏ョ敵璇峰崟缂栧彿"
+                         :loading="applyNoLoading"
+                         :remote-method="handleApplyNoSearch"
+                         @change="handleSearch"
+                         style="width: 400px;">
+                <el-option v-for="option in applyNoOptions"
+                           :key="option.id"
+                           :label="option.applyNo+'-'+option.productName+'-'+option.model"
+                           :value="option.id" />
+              </el-select>
             </el-form-item>
           </el-form>
         </div>
       </template>
       <!-- 鍩虹淇℃伅 -->
-      <div class="detail-section">
+      <div v-if="rowData.productionPlanDto"
+           class="detail-section">
         <h3 class="section-title">鍩虹淇℃伅</h3>
-        <el-descriptions :column="3"
-                         border>
-          <el-descriptions-item label="鐢宠鍗曠紪鍙�">{{ rowData.applyNo || '-' }}</el-descriptions-item>
-          <el-descriptions-item label="浜у搧鍚嶇О">{{ rowData.productName || '-' }}</el-descriptions-item>
-          <el-descriptions-item label="浜у搧瑙勬牸">{{ rowData.model || '-' }}</el-descriptions-item>
-          <el-descriptions-item label="鐗╂枡缂栫爜">{{ rowData.materialCode || '-' }}</el-descriptions-item>
-          <el-descriptions-item label="涓嬪彂鏁伴噺">{{ rowData.assignedQuantity || 0 }} <span class="unit">鏂�</span></el-descriptions-item>
-          <el-descriptions-item label="褰撳墠鐘舵��">
-            <el-tag :type="getStatusType(rowData.status)">
-              {{ getStatusText(rowData.status) }}
-            </el-tag>
-          </el-descriptions-item>
-        </el-descriptions>
+        <el-skeleton :loading="loading"
+                     animated>
+          <template #template>
+            <el-skeleton-item variant="p"
+                              style="width: 80%" />
+            <el-skeleton-item variant="p"
+                              style="width: 60%" />
+            <el-skeleton-item variant="p"
+                              style="width: 40%" />
+          </template>
+          <el-descriptions :column="3"
+                           border>
+            <el-descriptions-item label="鐢宠鍗曠紪鍙�">{{ rowData.productionPlanDto?.applyNo || '-' }}</el-descriptions-item>
+            <el-descriptions-item label="浜у搧鍚嶇О">{{ rowData.productionPlanDto?.productName || '-' }}</el-descriptions-item>
+            <el-descriptions-item label="浜у搧瑙勬牸">{{ rowData.productionPlanDto?.model || '-' }}</el-descriptions-item>
+            <el-descriptions-item label="鐗╂枡缂栫爜">{{ rowData.productionPlanDto?.materialCode || '-' }}</el-descriptions-item>
+            <el-descriptions-item label="涓嬪彂鏁伴噺">{{ rowData.productionPlanDto?.assignedQuantity || 0 }} <span class="unit">鏂�</span></el-descriptions-item>
+            <el-descriptions-item label="褰撳墠鐘舵��">
+              <el-tag :type="getStatusType(rowData.productionPlanDto?.status)">
+                {{ getStatusText(rowData.productionPlanDto?.status) }}
+              </el-tag>
+            </el-descriptions-item>
+          </el-descriptions>
+        </el-skeleton>
       </div>
-      <div class="progress-container">
+      <el-empty v-else
+                description="璇锋悳绱㈢敵璇峰崟缂栧彿" />
+      <div v-if="rowData.orderDtoList"
+           class="progress-container">
         <div class="progress-section">
           <h3 class="section-title">璁㈠崟淇℃伅</h3>
-          <div v-for="item in rowData.orderList"
-               :key="item.orderNo"
-               class="order-item">
-            <el-descriptions :column="3"
-                             border>
-              <el-descriptions-item label="璁㈠崟缂栧彿">{{ item.orderNo || '-' }}</el-descriptions-item>
-              <!-- <el-descriptions-item label="璁㈠崟鐘舵��">
-                <el-tag :type="getStatusType(item.status)">{{ getStatusText(item.status) }}</el-tag>
-              </el-descriptions-item> -->
-              <el-descriptions-item label="寮�濮嬫棩鏈�">{{ item.startTime || '-' }}</el-descriptions-item>
-              <el-descriptions-item label="瀹屾垚杩涘害">
-                <el-progress :percentage="item.completionRate"
-                             :color="customColors(item.completionRate)"
-                             :status="item.completionRate === 100 ? 'success' : ''"
-                             style="width: 120px;" />
-              </el-descriptions-item>
-              <el-descriptions-item label="闇�姹傛暟閲�">{{ item.quantity || 0 }} <span class="unit">鏂�</span></el-descriptions-item>
-              <el-descriptions-item label="瀹屾垚鏁伴噺">{{ item.completeQuantity || 0 }} <span class="unit">鏂�</span></el-descriptions-item>
-              <el-descriptions-item label="鍓╀綑鏁伴噺">{{ item.remainingQuantity || 0 }} <span class="unit">鏂�</span></el-descriptions-item>
-            </el-descriptions>
-            <el-table :data="trackProgressForm.progressDetails"
-                      border
-                      style="width: auto; height: 200px">
-              <el-table-column prop="step"
-                               label="姝ラ锛堢偣鍑绘煡鐪嬭鎯咃級"
-                               align="center">
-                <template #default="{ row, $index }">
-                  <el-link v-if="$index!=0"
-                           @click="handleClickStep(row)"
-                           type="primary">{{ row.step }}</el-link>
-                  <span v-else>{{ row.step }}</span>
-                </template>
-              </el-table-column>
-              <!-- <el-table-column prop="status"
-                               label="鐘舵��"
-                               align="center">
-                <template #default="scope">
-                  <el-tag :type="scope.row.status === 'completed' ? 'success' : scope.row.status === 'processing' ? 'warning' : 'info'">
-                    {{ scope.row.status === 'completed' ? '宸插畬鎴�' : scope.row.status === 'processing' ? '杩涜涓�' : '寰呭紑濮�' }}
-                  </el-tag>
-                </template>
-              </el-table-column> -->
-              <el-table-column prop="quantity"
-                               label="鏁伴噺"
-                               align="center" />
-              <el-table-column prop="startTime"
-                               label="鏃堕棿"
-                               align="center" />
-              <el-table-column prop="startTime1"
-                               label="宀椾綅浜哄憳"
-                               align="center" />
-            </el-table>
-          </div>
+          <el-skeleton :loading="loading"
+                       animated>
+            <template #template>
+              <el-skeleton-item variant="p"
+                                style="width: 80%" />
+              <el-skeleton-item variant="p"
+                                style="width: 60%" />
+              <el-skeleton-item variant="p"
+                                style="width: 40%" />
+              <el-skeleton-item variant="p"
+                                style="width: 100%" />
+            </template>
+            <div v-for="(item, index) in rowData.orderDtoList"
+                 :key="item.productOrderDto?.npsNo || index"
+                 class="order-item">
+              <el-descriptions :column="3"
+                               border>
+                <el-descriptions-item label="璁㈠崟缂栧彿">{{ item.productOrderDto?.npsNo || '-' }}</el-descriptions-item>
+                <el-descriptions-item label="寮�濮嬫棩鏈�">{{ item.productOrderDto?.startTime || '-' }}</el-descriptions-item>
+                <el-descriptions-item label="瀹屾垚杩涘害">
+                  <el-progress :percentage="item.productOrderDto?.completionStatus"
+                               :color="customColors(item.productOrderDto?.completionStatus)"
+                               :status="item.productOrderDto?.completionStatus === 100 ? 'success' : ''"
+                               style="width: 120px;" />
+                </el-descriptions-item>
+                <el-descriptions-item label="闇�姹傛暟閲�">{{ item.productOrderDto?.quantity || 0 }} <span class="unit">鏂�</span></el-descriptions-item>
+                <el-descriptions-item label="瀹屾垚鏁伴噺">{{ item.productOrderDto?.completeQuantity || 0 }} <span class="unit">鏂�</span></el-descriptions-item>
+                <el-descriptions-item label="鍓╀綑鏁伴噺">{{ (item.productOrderDto?.quantity - item.productOrderDto?.completeQuantity) || 0 }} <span class="unit">鏂�</span></el-descriptions-item>
+              </el-descriptions>
+              <el-table :data="item.productionProductMainDtos"
+                        border
+                        style="width: auto; max-height: 200px">
+                <el-table-column prop="step"
+                                 label="鎶ュ伐锛堢偣鍑绘煡鐪嬭鎯咃級"
+                                 align="center">
+                  <template #default="{ row }">
+                    <el-link @click="handleClickStep(row)"
+                             type="primary">{{ row.productNo }}</el-link>
+                  </template>
+                </el-table-column>
+                <el-table-column prop="quantity"
+                                 label="鏁伴噺锛堟柟锛�"
+                                 align="center" />
+                <el-table-column prop="reportingTime"
+                                 label="鏃堕棿"
+                                 align="center" />
+                <el-table-column prop="schedule"
+                                 label="鐝"
+                                 align="center" />
+                <el-table-column prop="postName"
+                                 label="宀椾綅浜哄憳"
+                                 align="center" />
+              </el-table>
+            </div>
+          </el-skeleton>
         </div>
       </div>
+      <el-empty v-else-if="rowData.productionPlanDto"
+                description="鏆傛棤杩涘害" />
     </el-card>
     <!-- 鐢熶骇鎶ュ伐璇︽儏寮圭獥 -->
     <el-dialog v-model="detailDialogVisible"
@@ -104,142 +130,159 @@
                :close-on-click-modal="false"
                custom-class="custom-dialog">
       <div class="detail-container">
-        <!-- 鍩虹淇℃伅 -->
-        <div class="detail-section">
-          <h3 class="section-title">鍩虹淇℃伅</h3>
-          <el-descriptions :column="3"
-                           border>
-            <el-descriptions-item label="鐢熶骇璁㈠崟鍙�">{{ detailData.npsNo || '-' }}</el-descriptions-item>
-            <el-descriptions-item label="鐝粍"><el-tag :type="detailData.schedule == '鐧界彮' ? 'primary' : 'warning'">{{ detailData.schedule || '-' }}</el-tag></el-descriptions-item>
-            <el-descriptions-item label="宀椾綅浜哄憳">{{ detailData.postName || '-' }}</el-descriptions-item>
-            <el-descriptions-item label="浜у搧缂栫爜">{{ detailData.materialCode || '-' }}</el-descriptions-item>
-            <el-descriptions-item label="浜у搧鍚嶇О">{{ detailData.productName || '-' }}</el-descriptions-item>
-            <el-descriptions-item label="瑙勬牸">{{ detailData.model || '-' }}</el-descriptions-item>
-            <el-descriptions-item label="鍚堟牸鏁伴噺"><span class="num2">{{ detailData.qualifiedQuantity || 0 }}</span> <span class="unit">鏂�</span></el-descriptions-item>
-            <el-descriptions-item label="涓嶅悎鏍兼暟閲�"><span class="num3">{{ detailData.unqualifiedQuantity || 0 }}</span> <span class="unit">鏂�</span></el-descriptions-item>
-            <el-descriptions-item label="鎬绘暟閲�"><span class="num1">{{ detailData.quantity || 0 }}</span> <span class="unit">鏂�</span></el-descriptions-item>
-            <el-descriptions-item label="鎶ュ伐鏃堕棿">{{ formatTime(detailData.reportingTime) }}</el-descriptions-item>
-            <el-descriptions-item label="鍒涘缓鏃堕棿">{{ formatTime(detailData.createTime) }}</el-descriptions-item>
-            <el-descriptions-item label="鏇存柊鏃堕棿">{{ formatTime(detailData.updateTime) }}</el-descriptions-item>
-          </el-descriptions>
-        </div>
-        <!-- 宸ュ簭淇℃伅 -->
-        <div class="detail-section"
-             v-if="detailData.productionProductRouteItemDtoList && detailData.productionProductRouteItemDtoList.length > 0">
-          <h3 class="section-title">宸ュ簭淇℃伅</h3>
-          <div v-for="(process) in detailData.productionProductRouteItemDtoList"
-               :key="process.id"
-               class="process-item">
-            <div class="process-header">
-              <h4 class="process-title">{{ process.processName || '-' }}</h4>
-              <div class="process-info">
-                <span class="process-label">宀椾綅浜哄憳锛歿{ process.postName || '-' }}</span>
-                <span class="process-label">宸ュ簭ID锛歿{ process.processNo || '-' }}</span>
+        <el-skeleton :loading="dialogLoading"
+                     animated>
+          <template #template>
+            <el-skeleton-item variant="p"
+                              style="width: 80%" />
+            <el-skeleton-item variant="p"
+                              style="width: 60%" />
+            <el-skeleton-item variant="p"
+                              style="width: 40%" />
+            <el-skeleton-item variant="h3"
+                              style="width: 50%" />
+            <el-skeleton-item variant="p"
+                              style="width: 100%" />
+            <el-skeleton-item variant="p"
+                              style="width: 100%" />
+          </template>
+          <!-- 鍩虹淇℃伅 -->
+          <div class="detail-section">
+            <h3 class="section-title">鍩虹淇℃伅</h3>
+            <el-descriptions :column="3"
+                             border>
+              <el-descriptions-item label="鐢熶骇璁㈠崟鍙�">{{ detailData.npsNo || '-' }}</el-descriptions-item>
+              <el-descriptions-item label="鐝粍"><el-tag :type="detailData.schedule == '鐧界彮' ? 'primary' : 'warning'">{{ detailData.schedule || '-' }}</el-tag></el-descriptions-item>
+              <el-descriptions-item label="宀椾綅浜哄憳">{{ detailData.postName || '-' }}</el-descriptions-item>
+              <el-descriptions-item label="浜у搧缂栫爜">{{ detailData.materialCode || '-' }}</el-descriptions-item>
+              <el-descriptions-item label="浜у搧鍚嶇О">{{ detailData.productName || '-' }}</el-descriptions-item>
+              <el-descriptions-item label="瑙勬牸">{{ detailData.model || '-' }}</el-descriptions-item>
+              <el-descriptions-item label="鍚堟牸鏁伴噺"><span class="num2">{{ detailData.qualifiedQuantity || 0 }}</span> <span class="unit">鏂�</span></el-descriptions-item>
+              <el-descriptions-item label="涓嶅悎鏍兼暟閲�"><span class="num3">{{ detailData.unqualifiedQuantity || 0 }}</span> <span class="unit">鏂�</span></el-descriptions-item>
+              <el-descriptions-item label="鎬绘暟閲�"><span class="num1">{{ detailData.quantity || 0 }}</span> <span class="unit">鏂�</span></el-descriptions-item>
+              <el-descriptions-item label="鎶ュ伐鏃堕棿">{{ formatTime(detailData.reportingTime) }}</el-descriptions-item>
+              <el-descriptions-item label="鍒涘缓鏃堕棿">{{ formatTime(detailData.createTime) }}</el-descriptions-item>
+              <el-descriptions-item label="鏇存柊鏃堕棿">{{ formatTime(detailData.updateTime) }}</el-descriptions-item>
+            </el-descriptions>
+          </div>
+          <!-- 宸ュ簭淇℃伅 -->
+          <div class="detail-section"
+               v-if="detailData.productionProductRouteItemDtoList && detailData.productionProductRouteItemDtoList.length > 0">
+            <h3 class="section-title">宸ュ簭淇℃伅</h3>
+            <div v-for="(process) in detailData.productionProductRouteItemDtoList"
+                 :key="process.id"
+                 class="process-item">
+              <div class="process-header">
+                <h4 class="process-title">{{ process.processName || '-' }}</h4>
+                <div class="process-info">
+                  <span class="process-label">宀椾綅浜哄憳锛歿{ process.postName || '-' }}</span>
+                  <span class="process-label">宸ュ簭ID锛歿{ process.processNo || '-' }}</span>
+                </div>
               </div>
-            </div>
-            <!-- 宸ュ簭鍩烘湰淇℃伅 -->
-            <div class="process-details">
-              <el-descriptions :column="2"
-                               border>
-                <el-descriptions-item label="璁惧寮傚父鎯呭喌">{{ process.equipmentMalfunction || '-' }}</el-descriptions-item>
-                <el-descriptions-item label="褰撶彮璁惧澶勭疆">{{ process.equipmentDisposal || '-' }}</el-descriptions-item>
-                <el-descriptions-item label="宸ヨ壓浜哄憳浜ゅ緟"
-                                      :span="2">{{ process.processExplained || '-' }}</el-descriptions-item>
-              </el-descriptions>
-            </div>
-            <!-- 宸ュ簭鍙傛暟 -->
-            <div v-if="process.productionProductRouteItemParamDtoList && process.productionProductRouteItemParamDtoList.length > 0">
-              <!-- BOM淇℃伅 -->
-              <div class="param-section"
-                   v-if="getBomList(process.productionProductRouteItemParamDtoList).length > 0">
-                <h5 class="param-title">鎶曞叆鍝佷俊鎭�</h5>
-                <el-table :data="getBomList(process.productionProductRouteItemParamDtoList)"
-                          style="width: 100%"
-                          size="small">
-                  <el-table-column prop="paramName"
-                                   label="浜у搧鍚嶇О"
-                                   min-width="120"></el-table-column>
-                  <el-table-column prop="model"
-                                   label="瑙勬牸鍨嬪彿"
-                                   min-width="120"></el-table-column>
-                  <el-table-column prop="productValue"
-                                   label="鎶曞叆閲�"
-                                   min-width="100"></el-table-column>
-                  <el-table-column prop="unit"
-                                   label="鍗曚綅"
-                                   width="80"></el-table-column>
-                </el-table>
+              <!-- 宸ュ簭鍩烘湰淇℃伅 -->
+              <div class="process-details">
+                <el-descriptions :column="2"
+                                 border>
+                  <el-descriptions-item label="璁惧寮傚父鎯呭喌">{{ process.equipmentMalfunction || '-' }}</el-descriptions-item>
+                  <el-descriptions-item label="褰撶彮璁惧澶勭疆">{{ process.equipmentDisposal || '-' }}</el-descriptions-item>
+                  <el-descriptions-item label="宸ヨ壓浜哄憳浜ゅ緟"
+                                        :span="2">{{ process.processExplained || '-' }}</el-descriptions-item>
+                </el-descriptions>
               </div>
-              <!-- 鍙傛暟淇℃伅 -->
-              <div class="param-section"
-                   v-if="getParamList(process.productionProductRouteItemParamDtoList).length > 0">
-                <h5 class="param-title">鐢熶骇璁板綍</h5>
-                <el-card v-for="group in getParamGroups(process.productionProductRouteItemParamDtoList)"
-                         :key="group.sourceSort"
-                         class="detail-card"
-                         style="margin-top: 10px;">
-                  <template #header>
-                    <div class="card-header">
-                      <span v-if="Object.keys(getParamGroups(process.productionProductRouteItemParamDtoList)).length > 1">鐢熶骇璁板綍缁� - {{ group.sourceSort }}</span>
-                      <span v-else>鐢熶骇璁板綍</span>
-                    </div>
-                  </template>
-                  <el-table :data="group.items"
+              <!-- 宸ュ簭鍙傛暟 -->
+              <div v-if="process.productionProductRouteItemParamDtoList && process.productionProductRouteItemParamDtoList.length > 0">
+                <!-- BOM淇℃伅 -->
+                <div class="param-section"
+                     v-if="getBomList(process.productionProductRouteItemParamDtoList).length > 0">
+                  <h5 class="param-title">鎶曞叆鍝佷俊鎭�</h5>
+                  <el-table :data="getBomList(process.productionProductRouteItemParamDtoList)"
                             style="width: 100%"
-                            :row-class-name="rowClassName">
+                            size="small">
                     <el-table-column prop="paramName"
-                                     label="鎸囨爣" />
+                                     label="浜у搧鍚嶇О"
+                                     min-width="120"></el-table-column>
+                    <el-table-column prop="model"
+                                     label="瑙勬牸鍨嬪彿"
+                                     min-width="120"></el-table-column>
+                    <el-table-column prop="productValue"
+                                     label="鎶曞叆閲�"
+                                     min-width="100"></el-table-column>
                     <el-table-column prop="unit"
                                      label="鍗曚綅"
-                                     width="100">
-                      <template #default="scope">
-                        {{ scope.row.unit || "/" }}
-                      </template>
-                    </el-table-column>
-                    <el-table-column prop="standardText"
-                                     label="鏍囧噯鍊�" />
-                    <el-table-column prop="paramValue"
-                                     label="瀹為檯鍊�" />
-                    <el-table-column prop="result"
-                                     label="缁撴灉"
-                                     width="100">
-                      <template #default="scope">
-                        <el-tag :type="scope.row.result === '鍚堟牸' ? 'success' : 'danger'">
-                          {{ scope.row.result }}
-                        </el-tag>
-                      </template>
-                    </el-table-column>
+                                     width="80"></el-table-column>
                   </el-table>
-                </el-card>
+                </div>
+                <!-- 鍙傛暟淇℃伅 -->
+                <div class="param-section"
+                     v-if="getParamList(process.productionProductRouteItemParamDtoList).length > 0">
+                  <h5 class="param-title">鐢熶骇璁板綍</h5>
+                  <el-card v-for="group in getParamGroups(process.productionProductRouteItemParamDtoList)"
+                           :key="group.sourceSort"
+                           class="detail-card"
+                           style="margin-top: 10px;">
+                    <template #header>
+                      <div class="card-header">
+                        <span v-if="Object.keys(getParamGroups(process.productionProductRouteItemParamDtoList)).length > 1">鐢熶骇璁板綍缁� - {{ group.sourceSort }}</span>
+                        <span v-else>鐢熶骇璁板綍</span>
+                      </div>
+                    </template>
+                    <el-table :data="group.items"
+                              style="width: 100%"
+                              :row-class-name="rowClassName">
+                      <el-table-column prop="paramName"
+                                       label="鎸囨爣" />
+                      <el-table-column prop="unit"
+                                       label="鍗曚綅"
+                                       width="100">
+                        <template #default="scope">
+                          {{ scope.row.unit || "/" }}
+                        </template>
+                      </el-table-column>
+                      <el-table-column prop="standardText"
+                                       label="鏍囧噯鍊�" />
+                      <el-table-column prop="paramValue"
+                                       label="瀹為檯鍊�" />
+                      <el-table-column prop="result"
+                                       label="缁撴灉"
+                                       width="100">
+                        <template #default="scope">
+                          <el-tag :type="scope.row.result === '鍚堟牸' ? 'success' : 'danger'">
+                            {{ scope.row.result }}
+                          </el-tag>
+                        </template>
+                      </el-table-column>
+                    </el-table>
+                  </el-card>
+                </div>
               </div>
-            </div>
-            <!-- 涓婁紶鏂囦欢 -->
-            <div class="file-section"
-                 v-if="process.fileList && process.fileList.length > 0">
-              <h5 class="file-title">涓婁紶鏂囦欢</h5>
-              <div class="file-grid">
-                <div v-for="file in process.fileList"
-                     :key="file.id"
-                     class="file-item">
-                  <el-image style="width: 100px; height: 100px"
-                            v-if="file.fileUrl"
-                            :src="baseUrl + file.fileUrl"
-                            :zoom-rate="1.2"
-                            :max-scale="7"
-                            :alt="file.fileName"
-                            :min-scale="0.2"
-                            :preview-src-list="formatFileList(process.fileList)"
-                            show-progress
-                            :initial-index="4"
-                            fit="cover" />
-                  <div class="file-info">
-                    <span class="file-name">{{ file.fileName || '-' }}</span>
+              <!-- 涓婁紶鏂囦欢 -->
+              <div class="file-section"
+                   v-if="process.fileList && process.fileList.length > 0">
+                <h5 class="file-title">涓婁紶鏂囦欢</h5>
+                <div class="file-grid">
+                  <div v-for="file in process.fileList"
+                       :key="file.id"
+                       class="file-item">
+                    <el-image style="width: 100px; height: 100px"
+                              v-if="file.fileUrl"
+                              :src="baseUrl + file.fileUrl"
+                              :zoom-rate="1.2"
+                              :max-scale="7"
+                              :alt="file.fileName"
+                              :min-scale="0.2"
+                              :preview-src-list="formatFileList(process.fileList)"
+                              show-progress
+                              :initial-index="4"
+                              fit="cover" />
+                    <div class="file-info">
+                      <span class="file-name">{{ file.fileName || '-' }}</span>
+                    </div>
                   </div>
                 </div>
               </div>
             </div>
           </div>
-        </div>
+        </el-skeleton>
       </div>
       <template #footer>
         <div class="dialog-footer">
@@ -255,6 +298,11 @@
   import { ElMessage } from "element-plus";
   import { useRouter, useRoute } from "vue-router";
   import dayjs from "dayjs";
+  import {
+    trackProgressByNo,
+    productionPlanListPage,
+  } from "@/api/productionPlan/productionPlan";
+  import { productionReportDetail } from "@/api/productionManagement/productionReporting.js";
 
   const router = useRouter();
   const route = useRoute();
@@ -271,15 +319,21 @@
     remark: "",
   });
 
-  // 鎼滅储琛ㄥ崟
-  const searchForm = reactive({
-    applyNo: "",
-  });
-
   // 鐢熶骇鎶ュ伐璇︽儏寮圭獥
   const detailDialogVisible = ref(false);
   const detailData = ref({});
   const baseUrl = import.meta.env.VITE_APP_BASE_API;
+
+  // 鍔犺浇鐘舵��
+  const loading = ref(false);
+  // 寮圭獥鍔犺浇鐘舵��
+  const dialogLoading = ref(false);
+
+  // 鐢宠鍗曚笅鎷夋鏁版嵁
+  const applyNoOptions = ref([]);
+  const applyNoLoading = ref(false);
+  const applyNoQuery = ref("");
+  const selectedApplyNo = ref(null);
 
   // 鑾峰彇鐘舵�佺被鍨�
   const getStatusType = status => {
@@ -392,28 +446,52 @@
     router.push("/productionPlan/productionPlan");
   };
 
+  // 澶勭悊鐢宠鍗曠紪鍙锋悳绱�
+  const handleApplyNoSearch = query => {
+    if (query) {
+      applyNoLoading.value = true;
+      productionPlanListPage({
+        current: -1,
+        size: -1,
+        applyNo: query,
+      })
+        .then(res => {
+          // 杞崲鏁版嵁鏍煎紡涓轰笅鎷夋鎵�闇�鐨勬牸寮�
+          applyNoOptions.value = res.data.records;
+        })
+        .catch(error => {
+          console.error(error);
+        })
+        .finally(() => {
+          applyNoLoading.value = false;
+        });
+    } else {
+      applyNoOptions.value = [];
+    }
+  };
+
   // 澶勭悊鎼滅储
   const handleSearch = () => {
-    const applyNo = searchForm.applyNo.trim();
-    if (!applyNo) {
-      ElMessage.warning("璇疯緭鍏ョ敵璇峰崟缂栧彿");
+    if (!selectedApplyNo.value) {
+      ElMessage.warning("璇烽�夋嫨鐢宠鍗曠紪鍙�");
       return;
     }
-    // 杩欓噷鍙互娣诲姞鎼滅储閫昏緫锛屼緥濡傝皟鐢ˋPI鑾峰彇鏁版嵁
-    // 鐩墠浣跨敤妯℃嫙鏁版嵁
-    ElMessage.success(`鎼滅储鐢宠鍗曠紪鍙�: ${applyNo}`);
-    // 妯℃嫙鎼滅储缁撴灉
-    rowData.applyNo = applyNo;
-    rowData.productName = "鎼滅储缁撴灉浜у搧";
-    rowData.model = "鎼滅储缁撴灉瑙勬牸";
-    rowData.materialCode = "MAT-" + applyNo;
-    rowData.assignedQuantity = 100;
-    rowData.status = 1;
-    trackProgressForm.progressDetails = generateProgressDetails(1);
-    trackProgressForm.completionRate = calculateCompletionRate(
-      trackProgressForm.progressDetails
-    );
-    rowData.orderList = generateOrderList();
+    // 璋冪敤API鑾峰彇鏁版嵁
+    loading.value = true;
+    trackProgressByNo({ productionPlanId: selectedApplyNo.value })
+      .then(res => {
+        console.log(res, "鎼滅储缁撴灉");
+        // 鍚堝苟鏁版嵁鍒皉owData
+        Object.assign(rowData, res.data);
+        ElMessage.success("鎼滅储鎴愬姛");
+      })
+      .catch(error => {
+        ElMessage.error("鎼滅储澶辫触锛岃绋嶅悗閲嶈瘯");
+        console.error(error);
+      })
+      .finally(() => {
+        loading.value = false;
+      });
   };
 
   // 鐢熸垚妯℃嫙璁㈠崟鏁版嵁
@@ -451,97 +529,23 @@
 
   // 澶勭悊鐐瑰嚮姝ラ鏌ョ湅璇︽儏
   const handleClickStep = row => {
-    // 杩欓噷鍙互娣诲姞鑾峰彇鎶ュ伐璇︽儏鏁版嵁鐨勯�昏緫
-    // 鐩墠浣跨敤妯℃嫙鏁版嵁
-    detailData.value = {
-      npsNo: "NPS-2026-001",
-      schedule: "鐧界彮",
-      postName: "寮犱笁",
-      materialCode: rowData.materialCode || "MAT-001",
-      productName: rowData.productName || "浜у搧A",
-      model: rowData.model || "瑙勬牸A",
-      qualifiedQuantity: 100,
-      unqualifiedQuantity: 5,
-      quantity: 105,
-      reportingTime: new Date(),
-      createTime: new Date(),
-      updateTime: new Date(),
-      productionProductRouteItemDtoList: [
-        {
-          id: 1,
-          processName: "宸ュ簭1",
-          postName: "寮犱笁",
-          processNo: "PROC-001",
-          equipmentMalfunction: "鏃犲紓甯�",
-          equipmentDisposal: "姝e父杩愯",
-          processExplained: "鎸夌収鏍囧噯宸ヨ壓鎿嶄綔",
-          productionProductRouteItemParamDtoList: [
-            {
-              id: 11,
-              paramName: "鍘熸潗鏂橝",
-              model: "鍨嬪彿A",
-              productValue: "100",
-              unit: "kg",
-              bomId: 101,
-            },
-            {
-              id: 12,
-              paramName: "娓╁害",
-              paramValue: "25",
-              unit: "掳C",
-              sourceSort: 1,
-              valueMode: 2,
-              minValue: 20,
-              maxValue: 30,
-            },
-            {
-              id: 13,
-              paramName: "鍘嬪姏",
-              paramValue: "1.5",
-              unit: "MPa",
-              sourceSort: 1,
-              valueMode: 2,
-              minValue: 1.0,
-              maxValue: 2.0,
-            },
-            {
-              id: 14,
-              paramName: "杞��",
-              paramValue: "1500",
-              unit: "rpm",
-              sourceSort: 2,
-              valueMode: 1,
-              standardValue: "1500",
-            },
-            {
-              id: 15,
-              paramName: "鐢垫祦",
-              paramValue: "12",
-              unit: "A",
-              sourceSort: 2,
-              valueMode: 2,
-              minValue: 10,
-              maxValue: 15,
-            },
-          ],
-          fileList: [
-            {
-              id: 21,
-              fileName: "鐢熶骇璁板綍1.jpg",
-              fileUrl: "/upload/files/20260301/12345.jpg",
-              fileSize: 1024000,
-            },
-            {
-              id: 22,
-              fileName: "鐢熶骇璁板綍2.jpg",
-              fileUrl: "/upload/files/20260301/67890.jpg",
-              fileSize: 2048000,
-            },
-          ],
-        },
-      ],
-    };
-    detailDialogVisible.value = true;
+    // 鑾峰彇鎶ュ伐璇︽儏鏁版嵁
+    dialogLoading.value = true;
+    productionReportDetail(row.id)
+      .then(res => {
+        console.log(res, "鎶ュ伐璇︽儏");
+        // 灏咥PI杩斿洖鐨勬暟鎹祴鍊肩粰detailData
+        detailData.value = res.data;
+        // 鎵撳紑寮圭獥
+        detailDialogVisible.value = true;
+      })
+      .catch(error => {
+        ElMessage.error("鑾峰彇鎶ュ伐璇︽儏澶辫触锛岃绋嶅悗閲嶈瘯");
+        console.error(error);
+      })
+      .finally(() => {
+        dialogLoading.value = false;
+      });
   };
 
   // 鏍煎紡鍖栨椂闂�
@@ -637,29 +641,26 @@
   // 椤甸潰鍔犺浇鏃惰幏鍙栨暟鎹�
   onMounted(() => {
     // 浠庤矾鐢卞弬鏁颁腑鑾峰彇鏁版嵁
-    applyNo.value = route.query.applyNo
-      ? decodeURIComponent(route.query.applyNo)
+    selectedApplyNo.value = route.query.applyNo
+      ? route.query.applyNo +
+        "-" +
+        route.query.productName +
+        "-" +
+        route.query.model
       : null;
-    searchForm.applyNo = applyNo.value;
 
-    // 鐢熸垚鍋囨暟鎹�
-    rowData.applyNo = applyNo.value || "APPLY-2026-001";
-    rowData.productName = "娴嬭瘯浜у搧";
-    rowData.model = "娴嬭瘯瑙勬牸";
-    rowData.materialCode = "MAT-001";
-    rowData.assignedQuantity = 233;
-    rowData.status = 1;
-    // 璧嬪�肩粰琛ㄥ崟鏁版嵁
-    trackProgressForm.materialCode = rowData.materialCode;
-    trackProgressForm.currentStatus = rowData.status;
-    trackProgressForm.progressDetails = generateProgressDetails(rowData.status);
-    trackProgressForm.completionRate = calculateCompletionRate(
-      trackProgressForm.progressDetails
-    );
-    trackProgressForm.remark = "";
-
-    // 鐢熸垚妯℃嫙璁㈠崟鏁版嵁
-    rowData.orderList = generateOrderList();
+    if (route.query.id) {
+      loading.value = true;
+      trackProgressByNo({ productionPlanId: route.query.id })
+        .then(res => {
+          console.log(res, "杩借釜杩涘害");
+          // 鍚堝苟鏁版嵁鍒皉owData
+          Object.assign(rowData, res.data);
+        })
+        .finally(() => {
+          loading.value = false;
+        });
+    }
   });
 </script>
 
diff --git a/src/views/reportAnalysis/salesStatistics/index.vue b/src/views/reportAnalysis/salesStatistics/index.vue
index 9f35388..f500213 100644
--- a/src/views/reportAnalysis/salesStatistics/index.vue
+++ b/src/views/reportAnalysis/salesStatistics/index.vue
@@ -6,7 +6,7 @@
     <div class="bi-topbar">
       <img class="bi-topbar-title-bg"
            src="@/assets/BI/biaoti.png"
-           alt="閿�鍞湅鏉跨粺璁�" />
+           alt="閿�鍞粺璁$湅鏉�" />
       <div class="bi-topbar-content">
         <div class="bi-topbar-left">
           <button class="fullscreen-btn"
@@ -35,7 +35,7 @@
           <span>26鈩�</span>
           <span class="bi-topbar-sep">婀垮害锛�1</span> -->
         </div>
-        <div class="bi-topbar-title">閿�鍞湅鏉跨粺璁�</div>
+        <div class="bi-topbar-title">閿�鍞粺璁$湅鏉�</div>
         <div class="bi-topbar-meta">
           <span class="bi-topbar-time">{{ currentTime }}</span>
           <span class="bi-topbar-sep">|</span>
@@ -50,19 +50,19 @@
                      title="閿�閲忓垎鏋愯秼鍔垮浘" />
         <div class="panel-tabs">
           <span class="tab-item"
-                :class="{ active: blockTimeDimension === 'year' }"
-                @click="handleBlockTimeDimensionChange('year')">骞�</span>
+                :class="{ active: chartTimeDimension === '骞�' }"
+                @click="handleChartTimeDimensionChange('骞�')">骞�</span>
           <span class="tab-item"
-                :class="{ active: blockTimeDimension === 'month' }"
-                @click="handleBlockTimeDimensionChange('month')">鏈�</span>
+                :class="{ active: chartTimeDimension === '鏈�' }"
+                @click="handleChartTimeDimensionChange('鏈�')">鏈�</span>
         </div>
         <div class="panel-tabs2">
           <span class="tab-item"
-                :class="{ active: blockProductType === '鐮屽潡' }"
-                @click="handleBlockProductTypeChange('鐮屽潡')">鐮屽潡</span>
+                :class="{ active: chartProductType === '鐮屽潡' }"
+                @click="handleChartProductTypeChange('鐮屽潡')">鐮屽潡</span>
           <span class="tab-item"
-                :class="{ active: blockProductType === '鏉挎潗' }"
-                @click="handleBlockProductTypeChange('鏉挎潗')">鏉挎潗</span>
+                :class="{ active: chartProductType === '鏉挎潗' }"
+                @click="handleChartProductTypeChange('鏉挎潗')">鏉挎潗</span>
         </div>
         <div class="bi-panel-body">
           <div class="chart-unit-row">
@@ -78,19 +78,19 @@
                      title="閿�鍞噾棰濆垎鏋�" />
         <div class="panel-tabs">
           <span class="tab-item"
-                :class="{ active: boardTimeDimension === 'year' }"
-                @click="handleBoardTimeDimensionChange('year')">骞�</span>
+                :class="{ active: chartTimeDimension2 === '骞�' }"
+                @click="handleChartTimeDimensionChange2('骞�')">骞�</span>
           <span class="tab-item"
-                :class="{ active: boardTimeDimension === 'month' }"
-                @click="handleBoardTimeDimensionChange('month')">鏈�</span>
+                :class="{ active: chartTimeDimension2 === '鏈�' }"
+                @click="handleChartTimeDimensionChange2('鏈�')">鏈�</span>
         </div>
         <div class="panel-tabs2">
           <span class="tab-item"
-                :class="{ active: boardProductType === '鐮屽潡' }"
-                @click="handleBoardProductTypeChange('鐮屽潡')">鐮屽潡</span>
+                :class="{ active: chartProductType2 === '鐮屽潡' }"
+                @click="handleChartProductTypeChange2('鐮屽潡')">鐮屽潡</span>
           <span class="tab-item"
-                :class="{ active: boardProductType === '鏉挎潗' }"
-                @click="handleBoardProductTypeChange('鏉挎潗')">鏉挎潗</span>
+                :class="{ active: chartProductType2 === '鏉挎潗' }"
+                @click="handleChartProductTypeChange2('鏉挎潗')">鏉挎潗</span>
         </div>
         <div class="bi-panel-body">
           <div class="chart-unit-row">
@@ -131,27 +131,27 @@
                      title="閿�閲忔暟鎹粺璁�" />
         <div class="panel-tabs">
           <span class="tab-item"
-                :class="{ active: blockTimeDimension === 'year' }"
-                @click="handleBlockTimeDimensionChange('year')">骞�</span>
+                :class="{ active: tableTimeDimension === '骞�' }"
+                @click="handleTableTimeDimensionChange('骞�')">骞�</span>
           <span class="tab-item"
-                :class="{ active: blockTimeDimension === 'month' }"
-                @click="handleBlockTimeDimensionChange('month')">鏈�</span>
+                :class="{ active: tableTimeDimension === '鏈�' }"
+                @click="handleTableTimeDimensionChange('鏈�')">鏈�</span>
         </div>
         <div class="panel-tabs2">
           <span class="tab-item"
-                :class="{ active: blockProductType === '鐮屽潡' }"
-                @click="handleBlockProductTypeChange('鐮屽潡')">鐮屽潡</span>
+                :class="{ active: tableProductType === '鐮屽潡' }"
+                @click="handleTableProductTypeChange('鐮屽潡')">鐮屽潡</span>
           <span class="tab-item"
-                :class="{ active: blockProductType === '鏉挎潗' }"
-                @click="handleBlockProductTypeChange('鏉挎潗')">鏉挎潗</span>
+                :class="{ active: tableProductType === '鏉挎潗' }"
+                @click="handleTableProductTypeChange('鏉挎潗')">鏉挎潗</span>
         </div>
         <div class="bi-panel-body">
           <div class="chart-filter-tabs">
-            <span v-for="area in salesAreas"
+            <span v-for="area in tableSalesAreas"
                   :key="area"
                   class="cf-tab"
-                  :class="{ active: blockSelectedArea === area }"
-                  @click="handleBlockAreaChange(area)">{{ area }}</span>
+                  :class="{ active: tableSelectedArea === area }"
+                  @click="handleTableAreaChange(area)">{{ area }}</span>
           </div>
           <div class="scroll-table-container">
             <table class="scroll-table">
@@ -166,10 +166,10 @@
               </thead>
               <div class="scroll-table-content">
                 <tbody ref="blockTableBody">
-                  <tr :class="item.sort % 2 === 0 ? 'evenTableTr' : 'oddTableTr'"
-                      v-for="(item, index) in blockSalesData"
+                  <tr :class="(index + 1) % 2 === 0 ? 'evenTableTr' : 'oddTableTr'"
+                      v-for="(item, index) in filteredTableSalesData"
                       :key="item.period + item.area + index">
-                    <td>{{ item.sort }}</td>
+                    <td>{{ index + 1 }}</td>
                     <td>{{ item.productType }}</td>
                     <td>{{ item.period }}</td>
                     <td>{{ item.area }}</td>
@@ -181,7 +181,7 @@
           </div>
           <div class="panel-summary-row">
             <div class="summary-label">鍚堣</div>
-            <div class="summary-value">127384 m鲁</div>
+            <div class="summary-value">{{ filteredTableSalesTotal }} m鲁</div>
           </div>
         </div>
       </div>
@@ -211,44 +211,46 @@
                      title="閿�鍞鏁版嵁缁熻" />
         <div class="panel-tabs">
           <span class="tab-item"
-                :class="{ active: boardTimeDimension === 'year' }"
-                @click="handleBoardTimeDimensionChange('year')">骞�</span>
+                :class="{ active: tableTimeDimension2 === '骞�' }"
+                @click="handleTableTimeDimensionChange2('骞�')">骞�</span>
           <span class="tab-item"
-                :class="{ active: boardTimeDimension === 'month' }"
-                @click="handleBoardTimeDimensionChange('month')">鏈�</span>
+                :class="{ active: tableTimeDimension2 === '鏈�' }"
+                @click="handleTableTimeDimensionChange2('鏈�')">鏈�</span>
         </div>
         <div class="panel-tabs2">
           <span class="tab-item"
-                :class="{ active: boardProductType === '鐮屽潡' }"
-                @click="handleBoardProductTypeChange('鐮屽潡')">鐮屽潡</span>
+                :class="{ active: tableProductType2 === '鐮屽潡' }"
+                @click="handleTableProductTypeChange2('鐮屽潡')">鐮屽潡</span>
           <span class="tab-item"
-                :class="{ active: boardProductType === '鏉挎潗' }"
-                @click="handleBoardProductTypeChange('鏉挎潗')">鏉挎潗</span>
+                :class="{ active: tableProductType2 === '鏉挎潗' }"
+                @click="handleTableProductTypeChange2('鏉挎潗')">鏉挎潗</span>
         </div>
         <div class="bi-panel-body">
           <div class="chart-filter-tabs">
-            <span v-for="area in salesAreas"
+            <span v-for="area in tableSalesAreas"
                   :key="area"
                   class="cf-tab"
-                  :class="{ active: boardSelectedArea === area }"
-                  @click="handleBoardAreaChange(area)">{{ area }}</span>
+                  :class="{ active: tableSelectedArea === area }"
+                  @click="handleTableAreaChange2(area)">{{ area }}</span>
           </div>
           <div class="scroll-table-container">
             <table class="scroll-table">
               <thead>
                 <tr>
                   <th>搴忓彿</th>
+                  <th>浜у搧绫诲瀷</th>
                   <th>骞存湀</th>
                   <th>閿�鍞尯</th>
-                  <th>閿�鍞锛堜竾鍏冿級</th>
+                  <th>閿�鍞锛堝厓锛�</th>
                 </tr>
               </thead>
               <div class="scroll-table-content">
                 <tbody ref="boardTableBody">
-                  <tr :class="item.sort % 2 === 0 ? 'evenTableTr' : 'oddTableTr'"
-                      v-for="(item, index) in boardSalesData"
+                  <tr :class="(index + 1) % 2 === 0 ? 'evenTableTr' : 'oddTableTr'"
+                      v-for="(item, index) in filteredAmountSalesData"
                       :key="item.period + item.area + index">
-                    <td>{{ item.sort }}</td>
+                    <td>{{ index + 1 }}</td>
+                    <td>{{ item.productType }}</td>
                     <td>{{ item.period }}</td>
                     <td>{{ item.area }}</td>
                     <td>{{ item.sales }}</td>
@@ -259,7 +261,7 @@
           </div>
           <div class="panel-summary-row">
             <div class="summary-label">鍚堣</div>
-            <div class="summary-value2">127384 涓囧厓</div>
+            <div class="summary-value2">{{ filteredAmountSalesTotal }} 鍏�</div>
           </div>
         </div>
       </div>
@@ -283,6 +285,8 @@
   import {
     getDashboardStatistics,
     getCustomerTrends,
+    getSalesAnalysisTrend,
+    getSalesAmountAnalysis,
   } from "@/api/reportAnalysis/salesStatistics";
 
   const router = useRouter();
@@ -343,10 +347,21 @@
   const boardTableBody = ref(null);
 
   // 閫夋嫨鍣ㄦ暟鎹�
-  const blockTimeDimension = ref("year");
-  const blockSelectedArea = ref("鍏ㄩ儴");
-  const blockProductType = ref("鐮屽潡");
-  const boardTimeDimension = ref("year");
+  // 閿�閲忓垎鏋愯秼鍔垮浘
+  const chartTimeDimension = ref("骞�");
+  const chartTimeDimension2 = ref("骞�");
+
+  const chartSelectedArea = ref("鍏ㄩ儴");
+  const chartProductType = ref("鐮屽潡");
+  const chartProductType2 = ref("鐮屽潡");
+
+  // 閿�閲忔暟鎹粺璁�
+  const tableTimeDimension = ref("骞�");
+  const tableSelectedArea = ref("鍏ㄩ儴");
+  const tableSelectedArea2 = ref("鍏ㄩ儴");
+
+  const tableProductType = ref("鐮屽潡");
+  const boardTimeDimension = ref("骞�");
   const boardSelectedArea = ref("鍏ㄩ儴");
   const boardProductType = ref("鏉挎潗");
   const customerTimeDimension = ref("骞�");
@@ -675,6 +690,14 @@
 
   // 瀹㈡埛瓒嬪娍鏁版嵁
   const customerTrendsData = ref([]);
+  // 閿�閲忓垎鏋愯秼鍔挎暟鎹�
+  const salesAnalysisTrendData = ref([]);
+  // 閿�閲忔暟鎹粺璁¤〃鏍兼暟鎹�
+  const tableSalesData = ref([]);
+  // 閿�閲忔暟鎹粺璁¤〃鏍兼�昏
+  const tableSalesTotal = ref(0);
+  // 鍔ㄦ�侀攢鍞尯鍩熷垪琛�
+  const tableSalesAreas = ref([]);
 
   // 鍙樺寲鐜囪绠楋紙妯℃嫙锛�
   const salesVolumeChange = ref("+5.2");
@@ -717,6 +740,126 @@
     }
   };
 
+  // 鑾峰彇閿�閲忓垎鏋愯秼鍔挎暟鎹�
+  const fetchSalesAnalysisTrendData = async () => {
+    try {
+      const response = await getSalesAnalysisTrend({
+        type: chartProductType.value, // 鐮屽潡鎴栨澘鏉�
+        days: chartTimeDimension.value, // 骞存垨鏈�
+      });
+      if (response && response.data) {
+        // API杩斿洖鐨勬暟鎹粨鏋勫涓嬶細
+        // {
+        //   "dates": ["2026-01-01", "2025-01-01", ...],
+        //   "customerTrends": [{"鍐呰挋鍙�": 470, "閾跺窛": 3600, ...}, ...]
+        // }
+        salesAnalysisTrendData.value = response.data;
+        updateCharts();
+      }
+    } catch (error) {
+      console.error("鑾峰彇閿�閲忓垎鏋愯秼鍔挎暟鎹け璐�:", error);
+    }
+  };
+
+  // 鑾峰彇閿�閲忔暟鎹粺璁¤〃鏍兼暟鎹�
+  const fetchTableSalesData = async () => {
+    try {
+      const response = await getSalesAnalysisTrend({
+        type: tableProductType.value, // 鐮屽潡鎴栨澘鏉�
+        days: tableTimeDimension.value, // 骞存垨鏈�
+      });
+      if (response && response.data) {
+        // API杩斿洖鐨勬暟鎹粨鏋勫涓嬶細
+        // {
+        //   "dates": ["2026-01-01", "2025-01-01", ...],
+        //   "customerTrends": [{"鍐呰挋鍙�": 470, "閾跺窛": 3600, ...}, ...]
+        // }
+        updateTableSalesData(response.data);
+      }
+    } catch (error) {
+      console.error("鑾峰彇閿�閲忔暟鎹粺璁¤〃鏍兼暟鎹け璐�:", error);
+    }
+  };
+
+  // 鏇存柊閿�閲忔暟鎹粺璁¤〃鏍�
+  const updateTableSalesData = data => {
+    if (!data || !data.dates || !data.customerTrends) {
+      return;
+    }
+    console.log(data, "datas");
+    const dates = data.dates;
+    const customerTrends = data.customerTrends;
+    const tableData = [];
+    let total = 0;
+    const areaSet = new Set();
+
+    dates.forEach((date, index) => {
+      const trend = customerTrends[index];
+      if (trend) {
+        // 鎻愬彇鎵�鏈夐攢鍞尯鍩�
+        Object.keys(trend).forEach(area => {
+          if (area !== "鍏ㄩ儴") {
+            areaSet.add(area);
+            const sales = trend[area] || 0;
+            tableData.push({
+              period: date,
+              area: area,
+              productType: tableProductType.value,
+              sales: sales,
+              sort: tableData.length + 1,
+            });
+            total += sales;
+          }
+        });
+      }
+    });
+
+    // 鏇存柊閿�鍞尯鍩熷垪琛紝娣诲姞"鍏ㄩ儴"閫夐」
+    tableSalesAreas.value = ["鍏ㄩ儴", ...Array.from(areaSet)];
+    // 纭繚 tableSelectedArea 鍦ㄩ攢鍞尯鍩熷垪琛ㄤ腑
+    if (
+      tableSalesAreas.value.length > 0 &&
+      !tableSalesAreas.value.includes(tableSelectedArea.value)
+    ) {
+      tableSelectedArea.value = "鍏ㄩ儴";
+    }
+
+    console.log(tableData);
+    tableSalesData.value = tableData;
+    tableSalesTotal.value = total;
+  };
+
+  // 澶勭悊鍥捐〃鏃堕棿缁村害鍙樺寲
+  const handleChartTimeDimensionChange = dimension => {
+    chartTimeDimension.value = dimension;
+    fetchSalesAnalysisTrendData();
+  };
+
+  // 澶勭悊鍥捐〃浜у搧绫诲瀷鍙樺寲
+  const handleChartProductTypeChange = type => {
+    chartProductType.value = type;
+    fetchSalesAnalysisTrendData();
+  };
+
+  // 澶勭悊琛ㄦ牸鏃堕棿缁村害鍙樺寲
+  const handleTableTimeDimensionChange = dimension => {
+    tableTimeDimension.value = dimension;
+    fetchTableSalesData();
+    // 閲嶆柊鍚姩婊氬姩锛屾牴鎹椂闂寸淮搴﹀喅瀹氭槸鍚︽粴鍔�
+    startBlockTableScroll();
+  };
+
+  // 澶勭悊琛ㄦ牸浜у搧绫诲瀷鍙樺寲
+  const handleTableProductTypeChange = type => {
+    tableProductType.value = type;
+    fetchTableSalesData();
+  };
+
+  // 澶勭悊琛ㄦ牸閿�鍞尯鍩熷彉鍖�
+  const handleTableAreaChange = area => {
+    tableSelectedArea.value = area;
+  };
+
   // 琛ㄦ牸鏁版嵁
   const tableData = computed(() => {
     return filteredData.value.map(item => {
@@ -734,17 +877,45 @@
     });
   });
 
+  // 绛涢�夊悗鐨勮〃鏍兼暟鎹�
+  const filteredTableSalesData = computed(() => {
+    if (tableSelectedArea.value === "鍏ㄩ儴") {
+      // 鎸夊勾鏈堝垎缁勬眹鎬绘暟鎹�
+      const groupedData = {};
+      tableSalesData.value.forEach(item => {
+        const key = item.period;
+        if (!groupedData[key]) {
+          groupedData[key] = {
+            period: item.period,
+            area: "鍏ㄩ儴",
+            productType: item.productType,
+            sales: 0,
+            sort: 0,
+          };
+        }
+        groupedData[key].sales += item.sales;
+      });
+      // 杞崲涓烘暟缁勫苟鎸夊勾鏈堟帓搴�
+      return Object.values(groupedData).sort((a, b) => {
+        return new Date(b.period) - new Date(a.period);
+      });
+    } else {
+      return tableSalesData.value.filter(
+        item => item.area === tableSelectedArea.value
+      );
+    }
+  });
+
+  // 绛涢�夊悗鐨勮〃鏍兼暟鎹�昏
+  const filteredTableSalesTotal = computed(() => {
+    return filteredTableSalesData.value.reduce(
+      (total, item) => total + item.sales,
+      0
+    );
+  });
+
   // 閿�閲忚秼鍔垮浘琛ㄩ厤缃�
   const salesVolumeChartOption = computed(() => {
-    // 涓烘瘡涓攢鍞尯鐢熸垚鏁版嵁
-    const salesAreas = [
-      "鍏ㄩ儴",
-      "A閿�鍞尯",
-      "B閿�鍞尯",
-      "C閿�鍞尯",
-      "D閿�鍞尯",
-      "E閿�鍞尯",
-    ];
     const colors = [
       "#00A4ED",
       "#34D8F7",
@@ -752,54 +923,111 @@
       "#8A6BFF",
       "#C8C447",
       "#FF6B6B",
+      "#FF9500",
+      "#4CD964",
+      "#5AC8FA",
     ];
-    const year = 2024;
     const periodType = blockTimeDimension.value;
 
     // 鐢熸垚鏃堕棿娈�
     let periods = [];
-    if (periodType === "year") {
-      // 骞村害鏁版嵁锛�12涓湀
-      for (let month = 1; month <= 12; month++) {
-        periods.push(`${year}-${month.toString().padStart(2, "0")}`);
+    let salesAreas = [];
+    let series = [];
+
+    if (
+      salesAnalysisTrendData.value &&
+      salesAnalysisTrendData.value.dates &&
+      salesAnalysisTrendData.value.customerTrends
+    ) {
+      // 浣跨敤API杩斿洖鐨勬棩鏈�
+      periods = salesAnalysisTrendData.value.dates;
+      // 鎻愬彇閿�鍞尯鍩�
+      const customerTrends = salesAnalysisTrendData.value.customerTrends;
+      if (customerTrends.length > 0) {
+        // 鎻愬彇閿�鍞尯鍩熷苟纭繚"鍏ㄩ儴"鍦ㄧ涓�涓綅缃�
+        const allAreas = Object.keys(customerTrends[0]);
+        salesAreas = allAreas.sort((a, b) => {
+          if (a === "鍏ㄩ儴") return -1;
+          if (b === "鍏ㄩ儴") return 1;
+          return 0;
+        });
+        // 涓烘瘡涓攢鍞尯鐢熸垚鏁版嵁
+        series = salesAreas.map((area, index) => {
+          const data = customerTrends.map(trend => trend[area] || 0);
+          return {
+            name: area,
+            data: data,
+            type: "line",
+            smooth: false,
+            // symbolSize: getResponsiveValue(8),
+            lineStyle: {
+              width: getResponsiveValue(1),
+              color: colors[index % colors.length],
+            },
+            itemStyle: { color: colors[index % colors.length] },
+            areaStyle: {
+              opacity: 0.4,
+              color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+                { offset: 0, color: colors[index % colors.length] + "80" },
+                { offset: 1, color: colors[index % colors.length] + "00" },
+              ]),
+            },
+          };
+        });
       }
     } else {
-      // 鏈堝害鏁版嵁锛�30澶�
-      const month = 1;
-      for (let day = 1; day <= 30; day++) {
-        periods.push(
-          `${year}-${month.toString().padStart(2, "0")}-${day
-            .toString()
-            .padStart(2, "0")}`
-        );
+      // 妯℃嫙鏁版嵁
+      salesAreas = [
+        "鍏ㄩ儴",
+        "A閿�鍞尯",
+        "B閿�鍞尯",
+        "C閿�鍞尯",
+        "D閿�鍞尯",
+        "E閿�鍞尯",
+      ];
+      const year = 2024;
+      if (periodType === "year") {
+        // 骞村害鏁版嵁锛�12涓湀
+        for (let month = 1; month <= 12; month++) {
+          periods.push(`${year}-${month.toString().padStart(2, "0")}`);
+        }
+      } else {
+        // 鏈堝害鏁版嵁锛�30澶�
+        const month = 1;
+        for (let day = 1; day <= 30; day++) {
+          periods.push(
+            `${year}-${month.toString().padStart(2, "0")}-${day
+              .toString()
+              .padStart(2, "0")}`
+          );
+        }
       }
-    }
+      // 涓烘瘡涓攢鍞尯鐢熸垚鏁版嵁
+      series = salesAreas.map((area, index) => {
+        const data = periods.map(() => {
+          return periodType === "year"
+            ? Math.floor(Math.random() * 500) + 800
+            : Math.floor(Math.random() * 50) + 20;
+        });
 
-    // 涓烘瘡涓攢鍞尯鐢熸垚鏁版嵁
-    const series = salesAreas.map((area, index) => {
-      const data = periods.map(() => {
-        return periodType === "year"
-          ? Math.floor(Math.random() * 500) + 800
-          : Math.floor(Math.random() * 50) + 20;
+        return {
+          name: area,
+          data: data,
+          type: "line",
+          smooth: false,
+          // symbolSize: getResponsiveValue(8),
+          lineStyle: { width: getResponsiveValue(1), color: colors[index] },
+          itemStyle: { color: colors[index] },
+          areaStyle: {
+            opacity: 0.4,
+            color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+              { offset: 0, color: colors[index] + "80" },
+              { offset: 1, color: colors[index] + "00" },
+            ]),
+          },
+        };
       });
-
-      return {
-        name: area,
-        data: data,
-        type: "line",
-        smooth: false,
-        // symbolSize: getResponsiveValue(8),
-        lineStyle: { width: getResponsiveValue(1), color: colors[index] },
-        itemStyle: { color: colors[index] },
-        areaStyle: {
-          opacity: 0.4,
-          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
-            { offset: 0, color: colors[index] + "80" },
-            { offset: 1, color: colors[index] + "00" },
-          ]),
-        },
-      };
-    });
+    }
 
     return {
       backgroundColor: "transparent",
@@ -864,15 +1092,20 @@
 
   // 閿�鍞噾棰濊秼鍔垮浘琛ㄩ厤缃�
   const salesAmountChartOption = computed(() => {
-    // 涓烘瘡涓攢鍞尯鐢熸垚鏁版嵁
-    const salesAreas = [
-      "鍏ㄩ儴",
-      "A閿�鍞尯",
-      "B閿�鍞尯",
-      "C閿�鍞尯",
-      "D閿�鍞尯",
-      "E閿�鍞尯",
-    ];
+    const { dates = [], customerTrends = [] } = salesAmountChartData.value;
+
+    // 鎻愬彇鎵�鏈夐攢鍞尯鍩�
+    const areaSet = new Set();
+    customerTrends.forEach(item => {
+      Object.keys(item).forEach(key => areaSet.add(key));
+    });
+    // 纭繚"鍏ㄩ儴"鍦ㄧ涓�涓綅缃�
+    const salesAreas = Array.from(areaSet).sort((a, b) => {
+      if (a === "鍏ㄩ儴") return -1;
+      if (b === "鍏ㄩ儴") return 1;
+      return 0;
+    });
+
     const colors = [
       "#00A4ED",
       "#34D8F7",
@@ -881,48 +1114,26 @@
       "#C8C447",
       "#FF6B6B",
     ];
-    const year = 2024;
-    const periodType = boardTimeDimension.value;
-
-    // 鐢熸垚鏃堕棿娈�
-    let periods = [];
-    if (periodType === "year") {
-      // 骞村害鏁版嵁锛�12涓湀
-      for (let month = 1; month <= 12; month++) {
-        periods.push(`${year}-${month.toString().padStart(2, "0")}`);
-      }
-    } else {
-      // 鏈堝害鏁版嵁锛�30澶�
-      const month = 1;
-      for (let day = 1; day <= 30; day++) {
-        periods.push(
-          `${year}-${month.toString().padStart(2, "0")}-${day
-            .toString()
-            .padStart(2, "0")}`
-        );
-      }
-    }
 
     // 涓烘瘡涓攢鍞尯鐢熸垚鏁版嵁
     const series = salesAreas.map((area, index) => {
-      const data = periods.map(() => {
-        return periodType === "year"
-          ? Math.floor(Math.random() * 50000) + 80000
-          : Math.floor(Math.random() * 5000) + 2000;
-      });
+      const data = customerTrends.map(item => item[area] || 0);
 
       return {
         name: area,
         data: data,
         type: "bar",
         smooth: true,
-        lineStyle: { width: getResponsiveValue(3), color: colors[index] },
-        itemStyle: { color: colors[index] },
+        lineStyle: {
+          width: getResponsiveValue(3),
+          color: colors[index % colors.length],
+        },
+        itemStyle: { color: colors[index % colors.length] },
         areaStyle: {
           opacity: 0.2,
           color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
-            { offset: 0, color: colors[index] + "80" },
-            { offset: 1, color: colors[index] + "00" },
+            { offset: 0, color: colors[index % colors.length] + "80" },
+            { offset: 1, color: colors[index % colors.length] + "00" },
           ]),
         },
       };
@@ -937,7 +1148,7 @@
         borderWidth: getResponsiveValue(1),
         textStyle: { color: "#B8C8E0", fontSize: getResponsiveValue(11) },
         formatter: function (params) {
-          let result = params[0].name + "<br/>";
+          let result = params[0]?.name + "<br/>" || "";
           params.forEach(param => {
             result += `${param.marker}${param.seriesName}: ${param.value} 鍏�<br/>`;
           });
@@ -964,7 +1175,7 @@
       },
       xAxis: {
         type: "category",
-        data: periods,
+        data: dates,
         axisLine: { lineStyle: { color: "rgba(184,200,224,0.25)" } },
         axisTick: { show: false },
         axisLabel: {
@@ -1164,7 +1375,12 @@
           areaSet.add(key);
         });
       });
-      salesAreas = Array.from(areaSet);
+      // 纭繚"鍏ㄩ儴"鍦ㄧ涓�涓綅缃�
+      salesAreas = Array.from(areaSet).sort((a, b) => {
+        if (a === "鍏ㄩ儴") return -1;
+        if (b === "鍏ㄩ儴") return 1;
+        return 0;
+      });
 
       // 涓烘瘡涓攢鍞尯鍩熺敓鎴愭暟鎹�
       series = salesAreas.map((area, index) => {
@@ -1382,15 +1598,18 @@
   let boardScrollTimer = null;
   let blockCurrentIndex = 0;
   let boardCurrentIndex = 0;
-
   const startBlockTableScroll = () => {
     if (blockScrollTimer) {
       clearInterval(blockScrollTimer);
     }
 
-    const scrollTable = () => {
-      if (!blockTableBody.value || blockSalesData.value.length === 0) return;
+    // 鍙湁褰撴椂闂寸淮搴︿笉鏄�"骞�"鏃舵墠鍚姩婊氬姩
+    if (tableTimeDimension.value === "骞�") {
+      return;
+    }
 
+    const scrollTable = () => {
+      if (!blockTableBody.value) return;
       const rows = blockTableBody.value.querySelectorAll("tr");
       if (rows.length === 0) return;
 
@@ -1403,9 +1622,10 @@
         blockTableBody.value.style.transition = "none";
         blockTableBody.value.style.transform = "translateY(0)";
 
-        const firstItem = blockSalesData.value[0];
-        blockSalesData.value.shift();
-        blockSalesData.value.push(firstItem);
+        // 鐩存帴鎿嶄綔DOM锛屽皢绗竴琛岀Щ鍒版渶鍚�
+        const firstRow = rows[0];
+        blockTableBody.value.removeChild(firstRow);
+        blockTableBody.value.appendChild(firstRow);
       }, 500);
     };
 
@@ -1450,6 +1670,10 @@
       clearInterval(boardScrollTimer);
       boardScrollTimer = null;
     }
+    if (amountScrollTimer.value) {
+      clearInterval(amountScrollTimer.value);
+      amountScrollTimer.value = null;
+    }
   };
 
   // 澶勭悊鏃堕棿缁村害閫夋嫨
@@ -1462,7 +1686,7 @@
     boardTimeDimension.value = dimension;
     generateBoardSalesData();
   };
-
+  const blockProductType = ref("鐮屽潡");
   // 澶勭悊浜у搧绫诲瀷閫夋嫨
   const handleBlockProductTypeChange = type => {
     blockProductType.value = type;
@@ -1473,7 +1697,7 @@
     boardProductType.value = type;
     generateBoardSalesData();
   };
-
+  const blockSelectedArea = ref("鍏ㄩ儴");
   // 澶勭悊閿�鍞尯閫夋嫨
   const handleBlockAreaChange = area => {
     blockSelectedArea.value = area;
@@ -1490,6 +1714,7 @@
     customerTimeDimension.value = dimension;
     fetchCustomerTrendsData();
   };
+  const blockTimeDimension = ref("骞�");
 
   // 鐢熸垚鐮屽潡閿�鍞暟鎹�
   const generateBlockSalesData = () => {
@@ -1622,18 +1847,269 @@
     // 鑾峰彇鏁版嵁
     await fetchDashboardData();
     await fetchCustomerTrendsData();
+    await fetchSalesAnalysisTrendData();
+    await fetchTableSalesData();
+    await fetchSalesAmountChartData();
+    await fetchSalesAmountTableData();
 
     // 绛夊緟DOM鏇存柊鍚庡垵濮嬪寲鍥捐〃
     nextTick(() => {
       initCharts();
       // 鍚姩琛ㄦ牸婊氬姩鍔ㄧ敾
       startBlockTableScroll();
-      startBoardTableScroll();
+      startAmountTableScroll();
     });
 
     // 娣诲姞绐楀彛澶у皬鍙樺寲鐩戝惉
     window.addEventListener("resize", handleResize);
     document.addEventListener("fullscreenchange", handleFullscreenChange);
+  });
+
+  // 鐩戝惉鍥捐〃鏃堕棿缁村害鍜屼骇鍝佺被鍨嬪彉鍖�
+  watch([chartTimeDimension, chartProductType], async () => {
+    await fetchSalesAnalysisTrendData();
+  });
+
+  // 鐩戝惉琛ㄦ牸鏃堕棿缁村害鍜屼骇鍝佺被鍨嬪彉鍖�
+  watch([tableTimeDimension, tableProductType], async () => {
+    await fetchTableSalesData();
+  });
+
+  // 閿�鍞噾棰濆垎鏋愬浘琛ㄦ暟鎹紙鍙充笂锛�
+  const salesAmountChartData = ref({
+    dates: [],
+    customerTrends: [],
+  });
+
+  // 閿�鍞鏁版嵁缁熻琛ㄦ牸鏁版嵁锛堝彸涓嬶級
+  const salesAmountTableData = ref({
+    dates: [],
+    customerTrends: [],
+  });
+
+  // 閿�鍞鏁版嵁缁熻琛ㄦ牸绛涢�夌姸鎬侊紙鍙充笅锛�
+  const tableTimeDimension2 = ref("骞�");
+  const tableProductType2 = ref("鐮屽潡");
+
+  // 閿�鍞鏁版嵁缁熻琛ㄦ牸鏁版嵁
+  const amountSalesData = ref([]);
+  const amountScrollTimer = ref(null);
+
+  // 鑾峰彇閿�鍞噾棰濆垎鏋愬浘琛ㄦ暟鎹紙鍙充笂锛�
+  const fetchSalesAmountChartData = async () => {
+    try {
+      const response = await getSalesAmountAnalysis({
+        type: chartProductType2.value,
+        days: chartTimeDimension2.value,
+      });
+      if (response?.data) {
+        salesAmountChartData.value = response.data;
+        updateCharts();
+      }
+    } catch (error) {
+      console.error("鑾峰彇閿�鍞噾棰濆垎鏋愬浘琛ㄦ暟鎹け璐�:", error);
+      // 浣跨敤妯℃嫙鏁版嵁
+      salesAmountChartData.value = {
+        dates: [
+          "2026-01-01",
+          "2025-01-01",
+          "2024-01-01",
+          "2023-01-01",
+          "2022-01-01",
+        ],
+        customerTrends: [
+          { 鍐呰挋鍙�: 100, 閾跺窛: 200, 鑷彁: 300, 鍏朵粬: 150, 鍏ㄩ儴: 750 },
+          { 鍐呰挋鍙�: 80, 閾跺窛: 180, 鑷彁: 280, 鍏朵粬: 130, 鍏ㄩ儴: 670 },
+          { 鍐呰挋鍙�: 90, 閾跺窛: 190, 鑷彁: 290, 鍏朵粬: 140, 鍏ㄩ儴: 710 },
+          { 鍐呰挋鍙�: 70, 閾跺窛: 170, 鑷彁: 270, 鍏朵粬: 120, 鍏ㄩ儴: 630 },
+          { 鍐呰挋鍙�: 110, 閾跺窛: 210, 鑷彁: 310, 鍏朵粬: 160, 鍏ㄩ儴: 790 },
+        ],
+      };
+    }
+  };
+
+  // 鑾峰彇閿�鍞鏁版嵁缁熻琛ㄦ牸鏁版嵁锛堝彸涓嬶級
+  const fetchSalesAmountTableData = async () => {
+    try {
+      const response = await getSalesAmountAnalysis({
+        type: tableProductType2.value,
+        days: tableTimeDimension2.value,
+      });
+      if (response?.data) {
+        salesAmountTableData.value = response.data;
+        updateAmountSalesData();
+      }
+    } catch (error) {
+      console.error("鑾峰彇閿�鍞鏁版嵁缁熻琛ㄦ牸鏁版嵁澶辫触:", error);
+      // 浣跨敤妯℃嫙鏁版嵁
+      salesAmountTableData.value = {
+        dates: [
+          "2026-01-01",
+          "2025-01-01",
+          "2024-01-01",
+          "2023-01-01",
+          "2022-01-01",
+        ],
+        customerTrends: [
+          { 鍐呰挋鍙�: 100, 閾跺窛: 200, 鑷彁: 300, 鍏朵粬: 150, 鍏ㄩ儴: 750 },
+          { 鍐呰挋鍙�: 80, 閾跺窛: 180, 鑷彁: 280, 鍏朵粬: 130, 鍏ㄩ儴: 670 },
+          { 鍐呰挋鍙�: 90, 閾跺窛: 190, 鑷彁: 290, 鍏朵粬: 140, 鍏ㄩ儴: 710 },
+          { 鍐呰挋鍙�: 70, 閾跺窛: 170, 鑷彁: 270, 鍏朵粬: 120, 鍏ㄩ儴: 630 },
+          { 鍐呰挋鍙�: 110, 閾跺窛: 210, 鑷彁: 310, 鍏朵粬: 160, 鍏ㄩ儴: 790 },
+        ],
+      };
+      updateAmountSalesData();
+    }
+  };
+
+  // 鏇存柊閿�鍞噾棰濆垎鏋愯〃鏍兼暟鎹�
+  const updateAmountSalesData = () => {
+    const data = [];
+    const { dates, customerTrends } = salesAmountTableData.value;
+
+    // 鎻愬彇鎵�鏈夐攢鍞尯鍩�
+    const areaSet = new Set();
+    customerTrends.forEach(item => {
+      Object.keys(item).forEach(key => areaSet.add(key));
+    });
+
+    // 鏇存柊閿�鍞尯鍩熷垪琛紝纭繚"鍏ㄩ儴"鍦ㄧ涓�浣�
+    tableSalesAreas.value = [
+      "鍏ㄩ儴",
+      ...Array.from(areaSet).filter(area => area !== "鍏ㄩ儴"),
+    ];
+
+    // 纭繚閫変腑鐨勫尯鍩熷湪鍒楄〃涓�
+    if (!tableSalesAreas.value.includes(tableSelectedArea.value)) {
+      tableSelectedArea.value = "鍏ㄩ儴";
+    }
+
+    // 鐢熸垚琛ㄦ牸鏁版嵁
+    dates.forEach((date, index) => {
+      const trends = customerTrends[index] || {};
+      Object.keys(trends).forEach(area => {
+        data.push({
+          period: date,
+          area: area,
+          productType: tableProductType2.value,
+          sales: trends[area],
+          sort: data.length + 1,
+        });
+      });
+    });
+
+    amountSalesData.value = data;
+  };
+
+  // 绛涢�夊悗鐨勯攢鍞噾棰濆垎鏋愯〃鏍兼暟鎹�
+  const filteredAmountSalesData = computed(() => {
+    if (tableSelectedArea.value === "鍏ㄩ儴") {
+      // 鎸夊勾鏈堝垎缁勬眹鎬绘暟鎹�
+      const groupedData = {};
+      amountSalesData.value.forEach(item => {
+        const key = item.period;
+        if (!groupedData[key]) {
+          groupedData[key] = {
+            period: item.period,
+            area: "鍏ㄩ儴",
+            productType: tableProductType2.value,
+            sales: 0,
+          };
+        }
+        groupedData[key].sales += item.sales;
+      });
+      // 杞崲涓烘暟缁勫苟鎸夊勾鏈堟帓搴�
+      return Object.values(groupedData).sort((a, b) => {
+        return new Date(b.period) - new Date(a.period);
+      });
+    } else {
+      return amountSalesData.value.filter(
+        item => item.area === tableSelectedArea.value
+      );
+    }
+  });
+
+  // 閿�鍞噾棰濆垎鏋愯〃鏍兼�昏
+  const filteredAmountSalesTotal = computed(() => {
+    return filteredAmountSalesData.value.reduce(
+      (total, item) => total + item.sales,
+      0
+    );
+  });
+
+  // 澶勭悊閿�鍞噾棰濆垎鏋愬浘琛ㄦ椂闂寸淮搴﹀彉鍖栵紙鍙充笂锛�
+  const handleChartTimeDimensionChange2 = dimension => {
+    chartTimeDimension2.value = dimension;
+    fetchSalesAmountChartData();
+  };
+
+  // 澶勭悊閿�鍞噾棰濆垎鏋愬浘琛ㄤ骇鍝佺被鍨嬪彉鍖栵紙鍙充笂锛�
+  const handleChartProductTypeChange2 = type => {
+    chartProductType2.value = type;
+    fetchSalesAmountChartData();
+  };
+
+  // 澶勭悊閿�鍞鏁版嵁缁熻琛ㄦ牸鏃堕棿缁村害鍙樺寲锛堝彸涓嬶級
+  const handleTableTimeDimensionChange2 = dimension => {
+    tableTimeDimension2.value = dimension;
+    fetchSalesAmountTableData();
+    // 閲嶆柊鍚姩婊氬姩锛屾牴鎹椂闂寸淮搴﹀喅瀹氭槸鍚︽粴鍔�
+    startAmountTableScroll();
+  };
+
+  // 澶勭悊閿�鍞鏁版嵁缁熻琛ㄦ牸浜у搧绫诲瀷鍙樺寲锛堝彸涓嬶級
+  const handleTableProductTypeChange2 = type => {
+    tableProductType2.value = type;
+    fetchSalesAmountTableData();
+  };
+
+  // 澶勭悊閿�鍞鏁版嵁缁熻琛ㄦ牸閿�鍞尯鍙樺寲锛堝彸涓嬶級
+  const handleTableAreaChange2 = area => {
+    tableSelectedArea.value = area;
+  };
+
+  // 鍚姩閿�鍞噾棰濆垎鏋愯〃鏍兼粴鍔�
+  const startAmountTableScroll = () => {
+    if (amountScrollTimer.value) {
+      clearInterval(amountScrollTimer.value);
+    }
+    // 鍙湁褰撴椂闂寸淮搴︿笉鏄�"骞�"鏃舵墠鍚姩婊氬姩
+    if (tableTimeDimension2.value === "骞�") {
+      return;
+    }
+
+    const scrollTable = () => {
+      if (!boardTableBody.value) return;
+      const rows = boardTableBody.value.querySelectorAll("tr");
+      if (rows.length === 0) return;
+
+      const rowHeight = rows[0].offsetHeight;
+
+      boardTableBody.value.style.transition = "transform 0.5s ease-in-out";
+      boardTableBody.value.style.transform = `translateY(-${rowHeight}px)`;
+
+      setTimeout(() => {
+        boardTableBody.value.style.transition = "none";
+        boardTableBody.value.style.transform = "translateY(0)";
+
+        // 鐩存帴鎿嶄綔DOM锛屽皢绗竴琛岀Щ鍒版渶鍚�
+        const firstRow = rows[0];
+        boardTableBody.value.removeChild(firstRow);
+        boardTableBody.value.appendChild(firstRow);
+      }, 500);
+    };
+
+    amountScrollTimer.value = setInterval(scrollTable, 2000);
+  };
+
+  // 鐩戝惉閿�鍞噾棰濆垎鏋愬浘琛ㄦ椂闂寸淮搴﹀拰浜у搧绫诲瀷鍙樺寲锛堝彸涓婏級
+  watch([chartTimeDimension2, chartProductType2], async () => {
+    // await fetchSalesAmountChartData();
+  });
+
+  // 鐩戝惉閿�鍞鏁版嵁缁熻琛ㄦ牸鏃堕棿缁村害鍜屼骇鍝佺被鍨嬪彉鍖栵紙鍙充笅锛�
+  watch([tableTimeDimension2, tableProductType2], async () => {
+    // await fetchSalesAmountTableData();
   });
 
   // 鑾峰彇浜у搧绫诲瀷鏍囩绫诲瀷
@@ -1958,12 +2434,12 @@
   }
 
   /* .scroll-table tbody tr:nth-child(odd) {
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                background-color: rgba(64, 158, 255, 0.05);
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                }
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  background-color: rgba(64, 158, 255, 0.05);
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  }
 
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              .scroll-table tbody tr:nth-child(even) {
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  background-color: rgba(64, 158, 255, 0.1);
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    } */
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                .scroll-table tbody tr:nth-child(even) {
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    background-color: rgba(64, 158, 255, 0.1);
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      } */
   .oddTableTr {
     background-color: rgba(64, 158, 255, 0.05);
   }
@@ -2062,7 +2538,7 @@
     font-size: 1.4vh;
     font-weight: 800;
     color: #00a4ed;
-    margin-right: 5.8vh;
+    margin-right: 1.8vh;
     text-shadow: 0 0 1vh rgba(0, 164, 237, 0.5);
   }
   .diamond {

--
Gitblit v1.9.3