From 18c90ce15d6836dd3dcf54ed01c34c32a592ee6c Mon Sep 17 00:00:00 2001
From: yuan <123@>
Date: 星期一, 22 六月 2026 17:17:13 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/dev_pro_河南鹤壁' into dev_pro_河南鹤壁_泽淇实业

---
 src/views/reportAnalysis/PSIDataAnalysis/components/left-top.vue         |    2 
 src/views/reportAnalysis/PSIDataAnalysis/psiNavigation.js                |   15 +
 src/views/reportAnalysis/dataDashboard/components/basic/right-top.vue    |    9 
 src/views/reportAnalysis/productionAnalysis/components/left-top.vue      |    2 
 src/views/reportAnalysis/dataDashboard/components/basic/right-bottom.vue |    9 
 src/views/reportAnalysis/PSIDataAnalysis/index.vue                       |    4 
 src/views/reportAnalysis/productionAnalysis/components/center-center.vue |   21 ++
 src/views/reportAnalysis/productionAnalysis/components/right-top.vue     |    2 
 src/views/equipmentManagement/upkeep/Form/detailDia.vue                  |  118 +++++++++++
 src/views/reportAnalysis/productionAnalysis/components/left-bottom.vue   |    2 
 src/views/reportAnalysis/PSIDataAnalysis/components/PanelHeader.vue      |   30 ++
 src/views/reportAnalysis/productionAnalysis/productionNavigation.js      |   19 +
 src/views/reportAnalysis/dataDashboard/components/PanelHeader.vue        |   30 ++
 src/views/reportAnalysis/productionAnalysis/components/right-bottom.vue  |    2 
 src/views/equipmentManagement/upkeep/index.vue                           |   40 +++
 src/views/reportAnalysis/productionAnalysis/components/center-top.vue    |   22 ++
 src/views/reportAnalysis/PSIDataAnalysis/components/left-bottom.vue      |    2 
 src/views/productionManagement/productionReporting/index.vue             |   16 
 src/views/equipmentManagement/upkeep/Form/RecordDetailDia.vue            |   99 +++++++++
 src/views/reportAnalysis/PSIDataAnalysis/components/center-bottom.vue    |    2 
 src/views/reportAnalysis/PSIDataAnalysis/components/center-top.vue       |   22 ++
 src/views/salesManagement/indicatorStats/index.vue                       |   74 ++++++-
 src/views/reportAnalysis/productionAnalysis/components/PanelHeader.vue   |   30 ++
 src/views/reportAnalysis/productionAnalysis/components/center-bottom.vue |    2 
 src/views/reportAnalysis/PSIDataAnalysis/components/center-center.vue    |   21 ++
 25 files changed, 554 insertions(+), 41 deletions(-)

diff --git a/src/views/equipmentManagement/upkeep/Form/RecordDetailDia.vue b/src/views/equipmentManagement/upkeep/Form/RecordDetailDia.vue
new file mode 100644
index 0000000..074628c
--- /dev/null
+++ b/src/views/equipmentManagement/upkeep/Form/RecordDetailDia.vue
@@ -0,0 +1,99 @@
+<template>
+	<FormDialog
+		v-model="dialogVisitable"
+		title="淇濆吇璁板綍璇︽儏"
+		width="800px"
+		operation-type="detail"
+		@close="cancel"
+	>
+		<el-descriptions border :column="2">
+			<el-descriptions-item label="璁惧鍚嶇О">
+				{{ detailData.deviceName || '--' }}
+			</el-descriptions-item>
+			<el-descriptions-item label="瑙勬牸鍨嬪彿">
+				{{ detailData.deviceModel || '--' }}
+			</el-descriptions-item>
+			<el-descriptions-item label="璁″垝淇濆吇鏃ユ湡">
+				{{ formatDate(detailData.maintenancePlanTime) }}
+			</el-descriptions-item>
+			<el-descriptions-item label="褰曞叆浜�">
+				{{ detailData.createUserName || '--' }}
+			</el-descriptions-item>
+			<el-descriptions-item label="淇濆吇椤圭洰" :span="2">
+				{{ detailData.machineryCategory || '--' }}
+			</el-descriptions-item>
+			<el-descriptions-item label="瀹為檯淇濆吇浜�">
+				{{ detailData.maintenanceActuallyName || '--' }}
+			</el-descriptions-item>
+			<el-descriptions-item label="瀹為檯淇濆吇鏃ユ湡">
+				{{ formatDate(detailData.maintenanceActuallyTime) }}
+			</el-descriptions-item>
+			<el-descriptions-item label="淇濆吇缁撴灉" :span="2">
+				{{ detailData.maintenanceResult || '--' }}
+			</el-descriptions-item>
+			<el-descriptions-item label="鐘舵��" :span="2">
+				<el-tag v-if="detailData.status === 2" type="danger">澶辫触</el-tag>
+				<el-tag v-else-if="detailData.status === 1" type="success">瀹岀粨</el-tag>
+				<el-tag v-else type="warning">寰呬繚鍏�</el-tag>
+			</el-descriptions-item>
+		</el-descriptions>
+
+		<div v-if="fileList && fileList.length > 0" class="image-section">
+			<div class="image-title">淇濆吇闄勪欢(鍥剧墖)锛�</div>
+			<AttachmentUploadImage
+				v-model:fileList="fileList"
+				:disabled="true"
+			/>
+		</div>
+	</FormDialog>
+</template>
+
+<script setup>
+import FormDialog from "@/components/Dialog/FormDialog.vue";
+import { ref } from "vue";
+import dayjs from "dayjs";
+import { attachmentList } from "@/api/basicData/storageAttachment.js";
+import AttachmentUploadImage from '@/components/AttachmentUpload/image/index.vue';
+
+const dialogVisitable = ref(false);
+const detailData = ref({});
+const fileList = ref([]);
+
+const formatDate = (date) => {
+	return date ? dayjs(date).format("YYYY-MM-DD") : "--";
+};
+
+const openDialog = (row) => {
+	dialogVisitable.value = true;
+	detailData.value = { ...row };
+	fileList.value = [];
+
+	if (row.id) {
+		attachmentList({
+			recordType: 'device_maintenance',
+			recordId: row.id,
+		}).then(res => {
+			if (res && res.data) {
+				fileList.value = res.data || [];
+			}
+		});
+	}
+};
+
+const cancel = () => {
+	dialogVisitable.value = false;
+};
+
+defineExpose({ openDialog });
+</script>
+
+<style scoped>
+.image-section {
+	margin-top: 20px;
+}
+.image-title {
+	font-weight: bold;
+	margin-bottom: 10px;
+	color: #606266;
+}
+</style>
diff --git a/src/views/equipmentManagement/upkeep/Form/detailDia.vue b/src/views/equipmentManagement/upkeep/Form/detailDia.vue
new file mode 100644
index 0000000..c80691a
--- /dev/null
+++ b/src/views/equipmentManagement/upkeep/Form/detailDia.vue
@@ -0,0 +1,118 @@
+<template>
+	<FormDialog
+		v-model="dialogVisitable"
+		title="淇濆吇浠诲姟璇︽儏"
+		width="800px"
+		operation-type="detail"
+		@close="cancel"
+	>
+		<el-descriptions border :column="2">
+			<el-descriptions-item label="璁惧鍚嶇О">
+				{{ detailData.taskName || '--' }}
+			</el-descriptions-item>
+			<el-descriptions-item label="瑙勬牸鍨嬪彿">
+				{{ detailData.deviceModel || '--' }}
+			</el-descriptions-item>
+			<el-descriptions-item label="褰曞叆浜�">
+				{{ detailData.registrant || '--' }}
+			</el-descriptions-item>
+			<el-descriptions-item label="鐧昏鏃堕棿">
+				{{ detailData.registrationDate || '--' }}
+			</el-descriptions-item>
+			<el-descriptions-item label="淇濆吇椤圭洰" :span="2">
+				{{ detailData.machineryCategory || '--' }}
+			</el-descriptions-item>
+			<el-descriptions-item label="淇濆吇浜�">
+				{{ detailData.maintenancePerson || '--' }}
+			</el-descriptions-item>
+			<el-descriptions-item label="浠诲姟棰戠巼">
+				{{ formatFrequencyType(detailData.frequencyType) }}
+			</el-descriptions-item>
+			<el-descriptions-item label="鎵ц鏃堕棿">
+				{{ formatFrequencyDetail(detailData.frequencyDetail) }}
+			</el-descriptions-item>
+			<el-descriptions-item label="瀹氭椂浠诲姟">
+				<el-tag :type="detailData.isActive === 1 ? 'success' : 'info'">
+					{{ detailData.isActive === 1 ? '寮�鍚�' : '鍏抽棴' }}
+				</el-tag>
+			</el-descriptions-item>
+			<el-descriptions-item label="澶囨敞" :span="2">
+				{{ detailData.remarks || '--' }}
+			</el-descriptions-item>
+		</el-descriptions>
+
+		<div v-if="fileList && fileList.length > 0" class="image-section">
+			<div class="image-title">璁惧鍥剧墖锛�</div>
+			<AttachmentUploadImage
+				v-model:fileList="fileList"
+				:disabled="true"
+			/>
+		</div>
+	</FormDialog>
+</template>
+
+<script setup>
+import FormDialog from "@/components/Dialog/FormDialog.vue";
+import { ref } from "vue";
+import { getLedgerById } from "@/api/equipmentManagement/ledger";
+import AttachmentUploadImage from '@/components/AttachmentUpload/image/index.vue';
+
+const dialogVisitable = ref(false);
+const detailData = ref({});
+const fileList = ref([]);
+
+const formatFrequencyType = (type) => {
+	const map = {
+		DAILY: "姣忔棩",
+		WEEKLY: "姣忓懆",
+		MONTHLY: "姣忔湀",
+		QUARTERLY: "瀛e害",
+	};
+	return map[type] || "--";
+};
+
+const formatFrequencyDetail = (detail) => {
+	if (!detail) return "--";
+	const replacements = {
+		MON: "鍛ㄤ竴",
+		TUE: "鍛ㄤ簩",
+		WED: "鍛ㄤ笁",
+		THU: "鍛ㄥ洓",
+		FRI: "鍛ㄤ簲",
+		SAT: "鍛ㄥ叚",
+		SUN: "鍛ㄦ棩",
+	};
+	return detail.replace(/MON|TUE|WED|THU|FRI|SAT|SUN/g, match => replacements[match]);
+};
+
+const openDialog = (row) => {
+	dialogVisitable.value = true;
+	detailData.value = { ...row };
+	fileList.value = [];
+
+	if (row.taskId) {
+		getLedgerById(row.taskId).then(res => {
+			if (res.code === 200 && res.data) {
+				fileList.value = res.data.storageBlobVOs || [];
+			}
+		});
+	}
+};
+
+const cancel = () => {
+	dialogVisitable.value = false;
+};
+
+defineExpose({ openDialog });
+</script>
+
+<style scoped>
+.image-section {
+	margin-top: 20px;
+}
+.image-title {
+	font-weight: bold;
+	margin-bottom: 10px;
+	color: #606266;
+}
+</style>
diff --git a/src/views/equipmentManagement/upkeep/index.vue b/src/views/equipmentManagement/upkeep/index.vue
index 52ad842..cd1adff 100644
--- a/src/views/equipmentManagement/upkeep/index.vue
+++ b/src/views/equipmentManagement/upkeep/index.vue
@@ -78,6 +78,11 @@
             <template #operation="{ row }">
               <el-button type="primary"
                          link
+                         @click="handleDetail(row)">
+                璇︽儏
+              </el-button>
+              <el-button type="primary"
+                         link
                          @click="editScheduledTask(row)">
                 缂栬緫
               </el-button>
@@ -177,6 +182,11 @@
                       type="warning">寰呬繚鍏�</el-tag>
             </template>
             <template #operation="{ row }">
+              <el-button type="primary"
+                         link
+                         @click="handleRecordDetail(row)">
+                璇︽儏
+              </el-button>
               <!-- 杩欎釜鍔熻兘璺熸柊澧炰繚鍏诲姛鑳戒竴妯′竴鏍凤紝鏈夊暐鎰忎箟锛� -->
               <!-- <el-button
               type="primary"
@@ -219,6 +229,8 @@
                       @ok="getTableData" />
     <FormDia ref="formDiaRef"
              @closeDia="getScheduledTableData" />
+    <DetailDia ref="detailDiaRef" />
+    <RecordDetailDia ref="recordDetailDiaRef" />
     <FileList v-if="fileDialogVisible"
               v-model:visible="fileDialogVisible"
               :record-type="'device_maintenance'"
@@ -241,6 +253,8 @@
   import PlanModal from "./Form/PlanModal.vue";
   import MaintenanceModal from "./Form/MaintenanceModal.vue";
   import FormDia from "./Form/formDia.vue";
+  import DetailDia from "./Form/detailDia.vue";
+  import RecordDetailDia from "./Form/RecordDetailDia.vue";
   import {
     getUpkeepPage,
     delUpkeep,
@@ -263,6 +277,10 @@
   const maintainModalRef = ref();
   // 瀹氭椂浠诲姟寮圭獥鎺у埗鍣�
   const formDiaRef = ref();
+  // 瀹氭椂浠诲姟璇︽儏寮圭獥鎺у埗鍣�
+  const detailDiaRef = ref();
+  // 淇濆吇璁板綍璇︽儏寮圭獥鎺у埗鍣�
+  const recordDetailDiaRef = ref();
   // 闄勪欢寮圭獥
   const fileListDialogRef = ref(null);
   const fileDialogVisible = ref(false);
@@ -314,7 +332,7 @@
     {
       prop: "frequencyType",
       label: "棰戞",
-      minWidth: 50,
+      minWidth: 80,
       // PIMTable 浣跨敤鐨勬槸 formatData锛岃�屼笉鏄� Element-Plus 鐨� formatter
       formatData: cell =>
         ({
@@ -371,7 +389,7 @@
       dataType: "slot",
       slot: "operation",
       align: "center",
-      width: "150px",
+      width: "160px",
     },
   ]);
 
@@ -445,7 +463,7 @@
       dataType: "slot",
       slot: "operation",
       align: "center",
-      width: "350px",
+      width: "250px",
     },
   ]);
 
@@ -503,6 +521,14 @@
     if (row) {
       nextTick(() => {
         formDiaRef.value?.openDialog("edit", row);
+      });
+    }
+  };
+
+  const handleDetail = row => {
+    if (row) {
+      nextTick(() => {
+        detailDiaRef.value?.openDialog(row);
       });
     }
   };
@@ -578,6 +604,14 @@
     maintainModalRef.value.open(row.id, row);
   };
 
+  const handleRecordDetail = row => {
+    if (row) {
+      nextTick(() => {
+        recordDetailDiaRef.value?.openDialog(row);
+      });
+    }
+  };
+
   const addPlan = () => {
     planModalRef.value.openModal();
   };
diff --git a/src/views/productionManagement/productionReporting/index.vue b/src/views/productionManagement/productionReporting/index.vue
index ee7b8ad..a24d691 100644
--- a/src/views/productionManagement/productionReporting/index.vue
+++ b/src/views/productionManagement/productionReporting/index.vue
@@ -180,27 +180,27 @@
     {
       label: "鎶ュ伐鍗曞彿",
       prop: "productNo",
-      width: 120,
+      width: 140,
     },
     {
       label: "鎶ュ伐浜哄憳",
       prop: "nickName",
       width: 120,
     },
-    {
-      label: "宸ユ椂锛坔锛�",
-      width: 100,
-      prop: "workHour",
-    },
+    // {
+    //   label: "宸ユ椂锛坔锛�",
+    //   width: 100,
+    //   prop: "workHour",
+    // },
     {
       label: "宸ュ簭",
       prop: "process",
-      width: 120,
+      width: 100,
     },
     {
       label: "宸ュ崟缂栧彿",
       prop: "workOrderNo",
-      width: 120,
+      width: 140,
     },
     {
       label: "閿�鍞悎鍚屽彿",
diff --git a/src/views/reportAnalysis/PSIDataAnalysis/components/PanelHeader.vue b/src/views/reportAnalysis/PSIDataAnalysis/components/PanelHeader.vue
index 313f1df..fad818d 100644
--- a/src/views/reportAnalysis/PSIDataAnalysis/components/PanelHeader.vue
+++ b/src/views/reportAnalysis/PSIDataAnalysis/components/PanelHeader.vue
@@ -1,17 +1,35 @@
 <template>
-  <div class="panel-header">
+  <div
+    class="panel-header"
+    :class="{ clickable: !!to }"
+    @click="handleClick"
+  >
     <span class="panel-title">{{ title }}</span>
   </div>
 </template>
 
 <script setup>
-defineProps({
+import { useRouter } from 'vue-router'
+
+const props = defineProps({
   title: {
     type: String,
     required: true,
     default: ''
+  },
+  to: {
+    type: String,
+    default: ''
   }
 })
+
+const router = useRouter()
+
+const handleClick = () => {
+  if (props.to) {
+    router.push(props.to)
+  }
+}
 </script>
 
 <style scoped>
@@ -30,4 +48,12 @@
   padding-left: 46px;
   line-height: 36px;
 }
+
+.panel-header.clickable {
+  cursor: pointer;
+}
+
+.panel-header.clickable:hover .panel-title {
+  color: #43e8fc;
+}
 </style>
diff --git a/src/views/reportAnalysis/PSIDataAnalysis/components/center-bottom.vue b/src/views/reportAnalysis/PSIDataAnalysis/components/center-bottom.vue
index e5a1781..b9b0d89 100644
--- a/src/views/reportAnalysis/PSIDataAnalysis/components/center-bottom.vue
+++ b/src/views/reportAnalysis/PSIDataAnalysis/components/center-bottom.vue
@@ -1,6 +1,6 @@
 <template>
   <div>
-    <PanelHeader title="鍑哄叆搴撹秼鍔�" />
+    <PanelHeader title="鍑哄叆搴撹秼鍔�" to="/inventoryManagement/receiptManagement" />
     <div class="main-panel panel-item-customers">
       <div class="filters-row">
 
diff --git a/src/views/reportAnalysis/PSIDataAnalysis/components/center-center.vue b/src/views/reportAnalysis/PSIDataAnalysis/components/center-center.vue
index 6e39eb1..068f05a 100644
--- a/src/views/reportAnalysis/PSIDataAnalysis/components/center-center.vue
+++ b/src/views/reportAnalysis/PSIDataAnalysis/components/center-center.vue
@@ -2,7 +2,7 @@
   <div>
     <!-- 璁惧缁熻 -->
     <div class="equipment-stats">
-      <div class="equipment-header">
+      <div class="equipment-header clickable" @click="handleNavigate">
         <img
           src="@/assets/BI/shujutongjiicon@2x.png"
           alt="鍥炬爣"
@@ -28,8 +28,19 @@
 
 <script setup>
 import { ref, onMounted, inject, watch } from 'vue'
+import { useRouter } from 'vue-router'
 import Echarts from '@/components/Echarts/echarts.vue'
 import { productTurnoverDays } from '@/api/viewIndex.js'
+import { getPsiRoute } from '../psiNavigation.js'
+
+const router = useRouter()
+
+const handleNavigate = () => {
+  const path = getPsiRoute('浜у搧鍛ㄨ浆澶╂暟')
+  if (path) {
+    router.push(path)
+  }
+}
 
 const chartStyle = { width: '100%', height: '100%' }
 const grid = { left: '3%', right: '4%', bottom: '3%', top: '4%', containLabel: true }
@@ -119,6 +130,14 @@
   padding-bottom: 2px;
 }
 
+.equipment-header.clickable {
+  cursor: pointer;
+}
+
+.equipment-header.clickable:hover .equipment-title {
+  opacity: 0.85;
+}
+
 .equipment-title {
   font-weight: 500;
   font-size: 18px;
diff --git a/src/views/reportAnalysis/PSIDataAnalysis/components/center-top.vue b/src/views/reportAnalysis/PSIDataAnalysis/components/center-top.vue
index 055fb66..80657c4 100644
--- a/src/views/reportAnalysis/PSIDataAnalysis/components/center-top.vue
+++ b/src/views/reportAnalysis/PSIDataAnalysis/components/center-top.vue
@@ -6,6 +6,8 @@
         v-for="item in statItems"
         :key="item.name"
         class="stat-card"
+        :class="{ clickable: !!getStatRoute(item.name) }"
+        @click="handleStatClick(item.name)"
       >
         <img src="@/assets/BI/icon@2x.png" alt="鍥炬爣" class="card-icon" />
         <div class="card-content">
@@ -25,9 +27,21 @@
 
 <script setup>
 import { ref, onMounted, inject, watch } from 'vue'
+import { useRouter } from 'vue-router'
 import { salesPurchaseStorageProductCount } from '@/api/viewIndex.js'
+import { getPsiRoute } from '../psiNavigation.js'
 
+const router = useRouter()
 const statItems = ref([])
+
+const getStatRoute = (name) => getPsiRoute(name)
+
+const handleStatClick = (name) => {
+  const path = getStatRoute(name)
+  if (path) {
+    router.push(path)
+  }
+}
 
 const formatPercent = (val) => {
   const num = Number(val) || 0
@@ -81,6 +95,14 @@
   height: 142px;
 }
 
+.stat-card.clickable {
+  cursor: pointer;
+}
+
+.stat-card.clickable:hover .card-label {
+  color: #43e8fc;
+}
+
 .card-icon {
   width: 100px;
   height: 100px;
diff --git a/src/views/reportAnalysis/PSIDataAnalysis/components/left-bottom.vue b/src/views/reportAnalysis/PSIDataAnalysis/components/left-bottom.vue
index 65a72fe..aa27c0e 100644
--- a/src/views/reportAnalysis/PSIDataAnalysis/components/left-bottom.vue
+++ b/src/views/reportAnalysis/PSIDataAnalysis/components/left-bottom.vue
@@ -1,6 +1,6 @@
 <template>
   <div>
-    <PanelHeader title="閲囪喘鍝佸垎甯�" />
+    <PanelHeader title="閲囪喘鍝佸垎甯�" to="/procurementManagement/procurementLedger" />
     <div class="main-panel panel-item-customers">
       <CarouselCards :items="cardItems" :visible-count="3" />
       <div class="pie-chart-wrapper" ref="pieWrapperRef">
diff --git a/src/views/reportAnalysis/PSIDataAnalysis/components/left-top.vue b/src/views/reportAnalysis/PSIDataAnalysis/components/left-top.vue
index f5dac31..cf2a234 100644
--- a/src/views/reportAnalysis/PSIDataAnalysis/components/left-top.vue
+++ b/src/views/reportAnalysis/PSIDataAnalysis/components/left-top.vue
@@ -1,6 +1,6 @@
 <template>
   <div>
-    <PanelHeader title="閿�鍞搧鍒嗗竷" />
+    <PanelHeader title="閿�鍞搧鍒嗗竷" to="/salesManagement/salesLedger" />
     <div class="main-panel panel-item-customers">
       <CarouselCards :items="cardItems" :visible-count="3" />
       <div class="pie-chart-wrapper" ref="pieWrapperRef">
diff --git a/src/views/reportAnalysis/PSIDataAnalysis/index.vue b/src/views/reportAnalysis/PSIDataAnalysis/index.vue
index f81e482..3f8d3df 100644
--- a/src/views/reportAnalysis/PSIDataAnalysis/index.vue
+++ b/src/views/reportAnalysis/PSIDataAnalysis/index.vue
@@ -34,8 +34,8 @@
 
       <!-- 鍙充晶鍖哄煙 -->
       <div class="right-panel">
-        <RightBottom />
-        <RightTop />
+        <RightBottom header-to="/salesManagement/receiptPaymentLedger" />
+        <RightTop header-to="/procurementManagement/paymentLedger" />
       </div>
     </div>
     </div>
diff --git a/src/views/reportAnalysis/PSIDataAnalysis/psiNavigation.js b/src/views/reportAnalysis/PSIDataAnalysis/psiNavigation.js
new file mode 100644
index 0000000..425e666
--- /dev/null
+++ b/src/views/reportAnalysis/PSIDataAnalysis/psiNavigation.js
@@ -0,0 +1,15 @@
+export const PSI_ROUTE_MAP = {
+  閿�鍞搧鍒嗗竷: '/salesManagement/salesLedger',
+  閲囪喘鍝佸垎甯�: '/procurementManagement/procurementLedger',
+  閿�鍞骇鍝佹暟: '/salesManagement/salesLedger',
+  閲囪喘浜у搧鏁�: '/procurementManagement/procurementLedger',
+  鍌ㄥ瓨浜у搧鏁�: '/inventoryManagement/stockManagement',
+  瀹㈡埛璐$尞鎺掑悕: '/salesManagement/receiptPaymentLedger',
+  渚涘簲鍟嗛噰璐帓鍚�: '/procurementManagement/paymentLedger',
+  鍑哄叆搴撹秼鍔�: '/inventoryManagement/receiptManagement',
+  浜у搧鍛ㄨ浆澶╂暟: '/inventoryManagement/stockManagement',
+}
+
+export function getPsiRoute(name) {
+  return PSI_ROUTE_MAP[name] || ''
+}
diff --git a/src/views/reportAnalysis/dataDashboard/components/PanelHeader.vue b/src/views/reportAnalysis/dataDashboard/components/PanelHeader.vue
index 313f1df..fad818d 100644
--- a/src/views/reportAnalysis/dataDashboard/components/PanelHeader.vue
+++ b/src/views/reportAnalysis/dataDashboard/components/PanelHeader.vue
@@ -1,17 +1,35 @@
 <template>
-  <div class="panel-header">
+  <div
+    class="panel-header"
+    :class="{ clickable: !!to }"
+    @click="handleClick"
+  >
     <span class="panel-title">{{ title }}</span>
   </div>
 </template>
 
 <script setup>
-defineProps({
+import { useRouter } from 'vue-router'
+
+const props = defineProps({
   title: {
     type: String,
     required: true,
     default: ''
+  },
+  to: {
+    type: String,
+    default: ''
   }
 })
+
+const router = useRouter()
+
+const handleClick = () => {
+  if (props.to) {
+    router.push(props.to)
+  }
+}
 </script>
 
 <style scoped>
@@ -30,4 +48,12 @@
   padding-left: 46px;
   line-height: 36px;
 }
+
+.panel-header.clickable {
+  cursor: pointer;
+}
+
+.panel-header.clickable:hover .panel-title {
+  color: #43e8fc;
+}
 </style>
diff --git a/src/views/reportAnalysis/dataDashboard/components/basic/right-bottom.vue b/src/views/reportAnalysis/dataDashboard/components/basic/right-bottom.vue
index bcdba84..9c0ce9a 100644
--- a/src/views/reportAnalysis/dataDashboard/components/basic/right-bottom.vue
+++ b/src/views/reportAnalysis/dataDashboard/components/basic/right-bottom.vue
@@ -1,6 +1,6 @@
 <template>
   <div>
-    <PanelHeader title="瀹㈡埛璐$尞鎺掑悕" />
+    <PanelHeader title="瀹㈡埛璐$尞鎺掑悕" :to="headerTo" />
     <div class="panel-item-customers">
       <div class="switch-container">
         <DateTypeSwitch v-model="dateType" @change="handleDateTypeChange" />
@@ -28,6 +28,13 @@
 import DateTypeSwitch from '../DateTypeSwitch.vue'
 import { customerContributionRanking } from '@/api/viewIndex.js'
 
+defineProps({
+  headerTo: {
+    type: String,
+    default: ''
+  }
+})
+
 const chartStyle = {
   width: '100%',
   height: '100%',
diff --git a/src/views/reportAnalysis/dataDashboard/components/basic/right-top.vue b/src/views/reportAnalysis/dataDashboard/components/basic/right-top.vue
index 399354e..36741a9 100644
--- a/src/views/reportAnalysis/dataDashboard/components/basic/right-top.vue
+++ b/src/views/reportAnalysis/dataDashboard/components/basic/right-top.vue
@@ -1,6 +1,6 @@
 <template>
   <div>
-    <PanelHeader title="渚涘簲鍟嗛噰璐帓鍚�" />
+    <PanelHeader title="渚涘簲鍟嗛噰璐帓鍚�" :to="headerTo" />
     <div class="panel-item-customers">
       <div class="switch-container">
         <DateTypeSwitch v-model="radio1" @change="handleDateTypeChange" />
@@ -27,6 +27,13 @@
 import DateTypeSwitch from '../DateTypeSwitch.vue'
 import { supplierPurchaseRanking } from '@/api/viewIndex.js'
 
+defineProps({
+  headerTo: {
+    type: String,
+    default: ''
+  }
+})
+
 const chartStyle = {
   width: '100%',
   height: '100%',
diff --git a/src/views/reportAnalysis/productionAnalysis/components/PanelHeader.vue b/src/views/reportAnalysis/productionAnalysis/components/PanelHeader.vue
index 313f1df..fad818d 100644
--- a/src/views/reportAnalysis/productionAnalysis/components/PanelHeader.vue
+++ b/src/views/reportAnalysis/productionAnalysis/components/PanelHeader.vue
@@ -1,17 +1,35 @@
 <template>
-  <div class="panel-header">
+  <div
+    class="panel-header"
+    :class="{ clickable: !!to }"
+    @click="handleClick"
+  >
     <span class="panel-title">{{ title }}</span>
   </div>
 </template>
 
 <script setup>
-defineProps({
+import { useRouter } from 'vue-router'
+
+const props = defineProps({
   title: {
     type: String,
     required: true,
     default: ''
+  },
+  to: {
+    type: String,
+    default: ''
   }
 })
+
+const router = useRouter()
+
+const handleClick = () => {
+  if (props.to) {
+    router.push(props.to)
+  }
+}
 </script>
 
 <style scoped>
@@ -30,4 +48,12 @@
   padding-left: 46px;
   line-height: 36px;
 }
+
+.panel-header.clickable {
+  cursor: pointer;
+}
+
+.panel-header.clickable:hover .panel-title {
+  color: #43e8fc;
+}
 </style>
diff --git a/src/views/reportAnalysis/productionAnalysis/components/center-bottom.vue b/src/views/reportAnalysis/productionAnalysis/components/center-bottom.vue
index f4f4024..ce746c7 100644
--- a/src/views/reportAnalysis/productionAnalysis/components/center-bottom.vue
+++ b/src/views/reportAnalysis/productionAnalysis/components/center-bottom.vue
@@ -1,6 +1,6 @@
 <template>
   <div>
-    <PanelHeader title="鐢熶骇璁㈠崟瀹屾垚杩涘害" />
+    <PanelHeader title="鐢熶骇璁㈠崟瀹屾垚杩涘害" to="/productionManagement/productionOrder" />
     <div class="main-panel">
       <div class="panel-item-customers">
         <CarouselCards :items="cardItems" :visible-count="4" />
diff --git a/src/views/reportAnalysis/productionAnalysis/components/center-center.vue b/src/views/reportAnalysis/productionAnalysis/components/center-center.vue
index 7221b47..c56a4f8 100644
--- a/src/views/reportAnalysis/productionAnalysis/components/center-center.vue
+++ b/src/views/reportAnalysis/productionAnalysis/components/center-center.vue
@@ -2,7 +2,7 @@
   <div>
     <!-- 璁惧缁熻 -->
     <div class="equipment-stats">
-      <div class="equipment-header">
+      <div class="equipment-header clickable" @click="handleNavigate">
         <img
           src="@/assets/BI/shujutongjiicon@2x.png"
           alt="鍥炬爣"
@@ -32,10 +32,21 @@
 
 <script setup>
 import { ref, onMounted, inject, watch, nextTick } from 'vue'
+import { useRouter } from 'vue-router'
 import * as echarts from 'echarts'
 import Echarts from '@/components/Echarts/echarts.vue'
 import { inputOutputAnalysis } from '@/api/viewIndex.js'
 import DateTypeSwitch from "@/views/reportAnalysis/productionAnalysis/components/DateTypeSwitch.vue";
+import { getProductionRoute } from '../productionNavigation.js'
+
+const router = useRouter()
+
+const handleNavigate = () => {
+  const path = getProductionRoute('鎶曞叆浜у嚭鍒嗘瀽')
+  if (path) {
+    router.push(path)
+  }
+}
 
 const dateType = ref(3) // 1=鍛� 2=鏈� 3=瀛e害
 const chartRef = ref(null)
@@ -204,6 +215,14 @@
   padding-bottom: 2px;
 }
 
+.equipment-header.clickable {
+  cursor: pointer;
+}
+
+.equipment-header.clickable:hover .equipment-title {
+  opacity: 0.85;
+}
+
 .equipment-title {
   font-weight: 500;
   font-size: 18px;
diff --git a/src/views/reportAnalysis/productionAnalysis/components/center-top.vue b/src/views/reportAnalysis/productionAnalysis/components/center-top.vue
index a806150..7a3deef 100644
--- a/src/views/reportAnalysis/productionAnalysis/components/center-top.vue
+++ b/src/views/reportAnalysis/productionAnalysis/components/center-top.vue
@@ -6,6 +6,8 @@
         v-for="item in statItems"
         :key="item.name"
         class="stat-card"
+        :class="{ clickable: !!getStatRoute(item.name) }"
+        @click="handleStatClick(item.name)"
       >
         <img src="@/assets/BI/icon@2x.png" alt="鍥炬爣" class="card-icon" />
         <div class="card-content">
@@ -25,9 +27,21 @@
 
 <script setup>
 import { ref, onMounted, inject, watch } from 'vue'
+import { useRouter } from 'vue-router'
 import { orderCount } from '@/api/viewIndex.js'
+import { getProductionRoute } from '../productionNavigation.js'
 
+const router = useRouter()
 const statItems = ref([])
+
+const getStatRoute = (name) => getProductionRoute(name)
+
+const handleStatClick = (name) => {
+  const path = getStatRoute(name)
+  if (path) {
+    router.push(path)
+  }
+}
 
 const formatPercent = (val) => {
   const num = Number(val) || 0
@@ -81,6 +95,14 @@
   height: 142px;
 }
 
+.stat-card.clickable {
+  cursor: pointer;
+}
+
+.stat-card.clickable:hover .card-label {
+  color: #43e8fc;
+}
+
 .card-icon {
   width: 100px;
   height: 100px;
diff --git a/src/views/reportAnalysis/productionAnalysis/components/left-bottom.vue b/src/views/reportAnalysis/productionAnalysis/components/left-bottom.vue
index b7c7358..e6e8189 100644
--- a/src/views/reportAnalysis/productionAnalysis/components/left-bottom.vue
+++ b/src/views/reportAnalysis/productionAnalysis/components/left-bottom.vue
@@ -1,6 +1,6 @@
 <template>
   <div>
-    <PanelHeader title="鍦ㄥ埗鍝佺粺璁″垎鏋�" />
+    <PanelHeader title="鍦ㄥ埗鍝佺粺璁″垎鏋�" to="/productionManagement/productionOrder" />
     <div class="main-panel panel-item-customers">
       <CarouselCards :items="cardItems" :visible-count="3" />
       <div class="chart-wrapper">
diff --git a/src/views/reportAnalysis/productionAnalysis/components/left-top.vue b/src/views/reportAnalysis/productionAnalysis/components/left-top.vue
index 37c82f0..8b25973 100644
--- a/src/views/reportAnalysis/productionAnalysis/components/left-top.vue
+++ b/src/views/reportAnalysis/productionAnalysis/components/left-top.vue
@@ -1,6 +1,6 @@
 <template>
   <div>
-    <PanelHeader title="宸ュ簭浜у嚭鍒嗘瀽" />
+    <PanelHeader title="宸ュ簭浜у嚭鍒嗘瀽" to="/productionManagement/processStatistics" />
     <div class="main-panel panel-item-customers">
       <div class="filters-row">
         <DateTypeSwitch v-model="dateType" @change="handleDateTypeChange" />
diff --git a/src/views/reportAnalysis/productionAnalysis/components/right-bottom.vue b/src/views/reportAnalysis/productionAnalysis/components/right-bottom.vue
index c3d3db3..33c5c20 100644
--- a/src/views/reportAnalysis/productionAnalysis/components/right-bottom.vue
+++ b/src/views/reportAnalysis/productionAnalysis/components/right-bottom.vue
@@ -1,6 +1,6 @@
 <template>
   <div>
-    <PanelHeader title="鐢熶骇鏍哥畻鍒嗘瀽" />
+    <PanelHeader title="鐢熶骇鏍哥畻鍒嗘瀽" to="/productionManagement/productionCosting" />
     <div class="main-panel panel-item-customers">
       <div class="filters-row">
         <DateTypeSwitch v-model="dateType" @change="handleDateTypeChange" />
diff --git a/src/views/reportAnalysis/productionAnalysis/components/right-top.vue b/src/views/reportAnalysis/productionAnalysis/components/right-top.vue
index 5ac7035..8e6ffef 100644
--- a/src/views/reportAnalysis/productionAnalysis/components/right-top.vue
+++ b/src/views/reportAnalysis/productionAnalysis/components/right-top.vue
@@ -1,6 +1,6 @@
 <template>
   <div>
-    <PanelHeader title="宸ュ崟鎵ц鏁堢巼鍒嗘瀽" />
+    <PanelHeader title="宸ュ崟鎵ц鏁堢巼鍒嗘瀽" to="/productionManagement/productionManagement/workOrderEdit/index" />
     <div class="main-panel panel-item-customers">
       <div class="filters-row">
         <DateTypeSwitch v-model="dateType" @change="handleDateTypeChange" />
diff --git a/src/views/reportAnalysis/productionAnalysis/productionNavigation.js b/src/views/reportAnalysis/productionAnalysis/productionNavigation.js
new file mode 100644
index 0000000..38b45e8
--- /dev/null
+++ b/src/views/reportAnalysis/productionAnalysis/productionNavigation.js
@@ -0,0 +1,19 @@
+const PRODUCTION_ORDER_ROUTE = '/productionManagement/productionOrder'
+
+export const PRODUCTION_ROUTE_MAP = {
+  宸ュ簭浜у嚭鍒嗘瀽: '/productionManagement/processStatistics',
+  鍦ㄥ埗鍝佺粺璁″垎鏋�: PRODUCTION_ORDER_ROUTE,
+  鐢熶骇璁㈠崟鏁�: PRODUCTION_ORDER_ROUTE,
+  宸插畬鎴愯鍗曟暟: PRODUCTION_ORDER_ROUTE,
+  寰呯敓浜ц鍗�: PRODUCTION_ORDER_ROUTE,
+  寰呯敓浜ц鍗曟暟: PRODUCTION_ORDER_ROUTE,
+  鐢熶骇璁㈠崟瀹屾垚杩涘害: PRODUCTION_ORDER_ROUTE,
+  鐢熶骇璁㈠崟瀹屾垚杩涘害鏁�: PRODUCTION_ORDER_ROUTE,
+  鎶曞叆浜у嚭鍒嗘瀽: '/productionManagement/productionReporting',
+  宸ュ崟鎵ц鏁堢巼鍒嗘瀽: '/productionManagement/productionManagement/workOrderEdit/index',
+  鐢熶骇鏍哥畻鍒嗘瀽: '/productionManagement/productionCosting',
+}
+
+export function getProductionRoute(name) {
+  return PRODUCTION_ROUTE_MAP[name] || ''
+}
diff --git a/src/views/salesManagement/indicatorStats/index.vue b/src/views/salesManagement/indicatorStats/index.vue
index 8ae15ed..7e5e5ba 100644
--- a/src/views/salesManagement/indicatorStats/index.vue
+++ b/src/views/salesManagement/indicatorStats/index.vue
@@ -2,7 +2,7 @@
   <div class="app-container indicator-stats">
     <!-- KPI 姹囨�� -->
     <el-row :gutter="20" class="stats-row">
-      <el-col :xs="24" :sm="12" :md="8">
+      <el-col :xs="24" :sm="12" :md="6">
         <div class="stat-card stat-card-blue">
           <div class="stat-icon-wrapper">
             <div class="stat-icon">
@@ -16,7 +16,7 @@
           <div class="stat-bg-decoration"></div>
         </div>
       </el-col>
-      <el-col :xs="24" :sm="12" :md="8">
+      <el-col :xs="24" :sm="12" :md="6">
         <div class="stat-card stat-card-green">
           <div class="stat-icon-wrapper">
             <div class="stat-icon">
@@ -30,7 +30,21 @@
           <div class="stat-bg-decoration"></div>
         </div>
       </el-col>
-      <el-col :xs="24" :sm="12" :md="8">
+      <el-col :xs="24" :sm="12" :md="6">
+        <div class="stat-card stat-card-purple">
+          <div class="stat-icon-wrapper">
+            <div class="stat-icon">
+              <el-icon :size="32"><Goods /></el-icon>
+            </div>
+          </div>
+          <div class="stat-content">
+            <div class="stat-value">{{ formatQuantity(indicatorKpis.productSalesQuantity) }}</div>
+            <div class="stat-label">浜у搧閿�鍞暟閲�</div>
+          </div>
+          <div class="stat-bg-decoration"></div>
+        </div>
+      </el-col>
+      <el-col :xs="24" :sm="12" :md="6">
         <div class="stat-card stat-card-orange">
           <div class="stat-icon-wrapper">
             <div class="stat-icon">
@@ -132,7 +146,7 @@
 
 <script setup>
 import { ref, reactive, onMounted, onUnmounted, nextTick } from 'vue'
-import { Document, Van, Tickets, Search, Refresh } from '@element-plus/icons-vue'
+import { Document, Van, Tickets, Search, Refresh, Goods } from '@element-plus/icons-vue'
 import * as echarts from 'echarts'
 import { getTotalStatistics, getStatisticsTable } from '@/api/salesManagement/indicatorStats'
 import { productTreeList } from '@/api/basicData/product.js'
@@ -142,6 +156,7 @@
 const indicatorKpis = reactive({
   orderCount: 0,
   salesAmount: 0,
+  productSalesQuantity: 0,
   shipRate: 0
 })
 
@@ -161,6 +176,11 @@
 const productOptions = ref([])
 const customerOption = ref([])
 
+const formatQuantity = (value) => {
+  const num = Number(value)
+  if (Number.isNaN(num)) return '0'
+  return num.toLocaleString(undefined, { maximumFractionDigits: 2 })
+}
 // 杞崲浜у搧鏍戞暟鎹紝灏� id 鏀逛负 value
 function convertIdToValue(data) {
   return data.map((item) => {
@@ -234,7 +254,7 @@
     if (res && res.data) {
       indicatorKpis.orderCount = res.data.total || 0
       indicatorKpis.salesAmount = res.data.contractAmountTotal || 0
-      // 鍙戣揣鐜囧鏋滄帴鍙f病鏈夎繑鍥烇紝淇濇寔鍘熷�兼垨璁句负0
+      indicatorKpis.productSalesQuantity = res.data.productQuantityTotal || 0
       indicatorKpis.shipRate = res.data.shipRate || 0
     }
   } catch (error) {
@@ -282,12 +302,19 @@
   if (indicatorChart) indicatorChart.dispose()
   indicatorChart = echarts.init(indicatorChartRef.value)
   
-  // 鏍规嵁鎺ュ彛杩斿洖鐨勬暟鎹粨鏋勬洿鏂板浘琛�
-  // 鎺ュ彛杩斿洖: dateList, orderCountList, salesAmountList
+  // 鎺ュ彛杩斿洖: dateList, orderCountList, salesAmountList, productQuantityList
   const option = {
     title: { text: '澶氱淮搴﹂攢鍞寚鏍囪秼鍔�', left: 'center' },
     tooltip: { trigger: 'axis' },
-    legend: { data: ['璁㈠崟鏁�', '閿�鍞'], top: 30 },
+    legend: {
+      data: ['璁㈠崟鏁�', '閿�鍞', '浜у搧閿�鍞暟閲�'],
+      top: 30,
+      selected: {
+        '璁㈠崟鏁�': false,
+        '閿�鍞': true,
+        '浜у搧閿�鍞暟閲�': true
+      }
+    },
     grid: { left: '3%', right: '8%', bottom: '3%', containLabel: true },
     xAxis: { 
       type: 'category', 
@@ -322,6 +349,13 @@
         yAxisIndex: 0,
         data: chartData.salesAmountList || [], 
         itemStyle: { color: '#67c23a' } 
+      },
+      { 
+        name: '浜у搧閿�鍞暟閲�', 
+        type: 'line', 
+        yAxisIndex: 1,
+        data: chartData.productQuantityList || [], 
+        itemStyle: { color: '#f56c6c' } 
       }
     ]
   }
@@ -335,7 +369,15 @@
   const option = {
     title: { text: '澶氱淮搴﹂攢鍞寚鏍囪秼鍔�', left: 'center' },
     tooltip: { trigger: 'axis' },
-    legend: { data: ['璁㈠崟鏁�', '閿�鍞'], top: 30 },
+    legend: {
+      data: ['璁㈠崟鏁�', '閿�鍞', '浜у搧閿�鍞暟閲�'],
+      top: 30,
+      selected: {
+        '璁㈠崟鏁�': false,
+        '閿�鍞': true,
+        '浜у搧閿�鍞暟閲�': true
+      }
+    },
     grid: { left: '3%', right: '8%', bottom: '3%', containLabel: true },
     xAxis: { type: 'category', data: [] },
     yAxis: [
@@ -355,7 +397,8 @@
     ],
     series: [
       { name: '璁㈠崟鏁�', type: 'line', yAxisIndex: 1, data: [], itemStyle: { color: '#409eff' } },
-      { name: '閿�鍞', type: 'bar', yAxisIndex: 0, data: [], itemStyle: { color: '#67c23a' } }
+      { name: '閿�鍞', type: 'bar', yAxisIndex: 0, data: [], itemStyle: { color: '#67c23a' } },
+      { name: '浜у搧閿�鍞暟閲�', type: 'line', yAxisIndex: 1, data: [], itemStyle: { color: '#f56c6c' } }
     ]
   }
   indicatorChart.setOption(option)
@@ -523,6 +566,17 @@
       background: #e6a23c;
     }
   }
+
+  &.stat-card-purple {
+    .stat-icon {
+      background: linear-gradient(135deg, #9b59b6 0%, #b37fcc 100%);
+      color: #fff;
+    }
+    
+    .stat-bg-decoration {
+      background: #9b59b6;
+    }
+  }
 }
 
 .chart-card,

--
Gitblit v1.9.3