From fb81f5966eedb985735eecffcfe22eb550c86654 Mon Sep 17 00:00:00 2001
From: yyb <995253665@qq.com>
Date: 星期五, 15 五月 2026 11:38:36 +0800
Subject: [PATCH] Merge branch 'dev_NEW_pro' of http://114.132.189.42:9002/r/product-inventory-management into dev_NEW_pro

---
 src/views/productionManagement/productionProcess/index.vue                |   20 +
 src/views/reportAnalysis/PSIDataAnalysis/components/left-top.vue          |    9 
 multiple/config.json                                                      |    2 
 src/views/reportAnalysis/productionAnalysis/index.vue                     |   16 
 src/views/equipmentManagement/measurementEquipment/components/formDia.vue |   34 -
 src/views/equipmentManagement/upkeep/Form/PlanModal.vue                   |   13 
 src/views/reportAnalysis/dataDashboard/index.vue                          |   16 
 src/components/ProcessParamListDialog.vue                                 |   34 +
 src/views/financialManagement/generalLedger/index.vue                     |    4 
 src/views/equipmentManagement/repair/Modal/AcceptanceModal.vue            |  144 +++++++++
 src/views/reportAnalysis/dataDashboard/components/basic/right-top.vue     |    9 
 src/views/reportAnalysis/productionAnalysis/components/left-top.vue       |    9 
 src/views/financialManagement/voucher/index.vue                           |  107 ++++++
 src/views/reportAnalysis/dataDashboard/components/basic/right-bottom.vue  |    9 
 src/views/personnelManagement/contractManagement/index.vue                |   22 +
 src/views/reportAnalysis/PSIDataAnalysis/index.vue                        |   16 
 src/views/collaborativeApproval/sealManagement/index.vue                  |   82 ++++
 src/views/reportAnalysis/productionAnalysis/components/center-center.vue  |    9 
 src/views/reportAnalysis/productionAnalysis/components/right-top.vue      |    9 
 src/views/reportAnalysis/productionAnalysis/components/left-bottom.vue    |    9 
 src/views/financialManagement/assets/intangibleAssets.vue                 |    2 
 src/views/financialManagement/voucher/detailLedger.vue                    |    2 
 src/views/financialManagement/voucher/generalLedger.vue                   |   18 
 src/views/reportAnalysis/productionAnalysis/components/right-bottom.vue   |    9 
 src/views/equipmentManagement/upkeep/index.vue                            |    5 
 src/views/equipmentManagement/repair/Modal/MaintainModal.vue              |    5 
 src/views/personnelManagement/employeeRecord/index.vue                    |   59 ++-
 src/views/equipmentManagement/repair/Modal/RepairModal.vue                |   38 ++
 src/views/equipmentManagement/repair/index.vue                            |   36 ++
 src/views/reportAnalysis/dataDashboard/components/basic/center-bottom.vue |    9 
 src/views/financialManagement/assets/fixedAssets.vue                      |    2 
 src/views/reportAnalysis/productionAnalysis/components/center-top.vue     |    9 
 src/views/reportAnalysis/PSIDataAnalysis/components/left-bottom.vue       |    9 
 src/views/reportAnalysis/dataDashboard/components/basic/left-bottom.vue   |    9 
 src/api/equipmentManagement/repair.js                                     |   13 
 src/views/equipmentManagement/measurementEquipment/index.vue              |   22 
 src/views/reportAnalysis/PSIDataAnalysis/components/center-bottom.vue     |    9 
 src/views/reportAnalysis/PSIDataAnalysis/components/center-top.vue        |    9 
 src/views/reportAnalysis/productionAnalysis/components/center-bottom.vue  |   27 +
 src/views/equipmentManagement/upkeep/Form/formDia.vue                     |   22 +
 src/views/reportAnalysis/PSIDataAnalysis/components/center-center.vue     |    9 
 src/views/reportAnalysis/dataDashboard/components/basic/center-top.vue    |   44 +
 src/views/reportAnalysis/dataDashboard/components/basic/left-top.vue      |    9 
 43 files changed, 787 insertions(+), 162 deletions(-)

diff --git a/multiple/config.json b/multiple/config.json
index 802ef67..6a0b9e6 100644
--- a/multiple/config.json
+++ b/multiple/config.json
@@ -44,7 +44,7 @@
   },
   "BTYX": {
     "env": {
-      "VITE_APP_TITLE": "娌冲崡甯お浼橀�夎繘鍑哄彛鏈夐檺鍏徃",
+      "VITE_APP_TITLE": "娌冲崡甯お浼橀�夐鍝佹湁闄愬叕鍙�",
       "VITE_BASE_API": "http://1.15.17.182:9056",
       "VITE_JAVA_API": "http://1.15.17.182:9057"
     },
diff --git a/src/api/equipmentManagement/repair.js b/src/api/equipmentManagement/repair.js
index 0233ae6..16bfd28 100644
--- a/src/api/equipmentManagement/repair.js
+++ b/src/api/equipmentManagement/repair.js
@@ -70,3 +70,16 @@
     data,
   });
 };
+
+/**
+ * @desc 楠屾敹瀹℃壒
+ * @param {楠屾敹鍙傛暟} data
+ * @returns
+ */
+export const repairAcceptance = (data) => {
+  return request({
+    url: `/device/repair/acceptance`,
+    method: "post",
+    data,
+  });
+};
diff --git a/src/components/ProcessParamListDialog.vue b/src/components/ProcessParamListDialog.vue
index 38e892d..deee249 100644
--- a/src/components/ProcessParamListDialog.vue
+++ b/src/components/ProcessParamListDialog.vue
@@ -130,6 +130,7 @@
             </el-form-item>
             <el-form-item label="鏍囧噯鍊�">
               <el-input v-model="selectedParam.standardValue"
+                        @input="val => onStandardValueInput(val, selectedParam)"
                         placeholder="璇疯緭鍏ラ粯璁ゅ��" />
             </el-form-item>
             <el-form-item label="鏄惁蹇呭~">
@@ -144,7 +145,8 @@
         </div>
       </div>
       <template #footer>
-        <el-button type="primary" @click="handleParamSelectSubmit">纭畾</el-button>
+        <el-button type="primary"
+                   @click="handleParamSelectSubmit">纭畾</el-button>
         <el-button @click="selectParamDialogVisible = false">鍙栨秷</el-button>
       </template>
     </el-dialog>
@@ -174,11 +176,13 @@
         <el-form-item label="鏍囧噯鍊�"
                       prop="standardValue">
           <el-input v-model="editParamForm.standardValue"
+                    @input="val => onStandardValueInput(val, editParamForm)"
                     placeholder="璇疯緭鍏ユ爣鍑嗗��" />
         </el-form-item>
       </el-form>
       <template #footer>
-        <el-button type="primary" @click="handleEditParamSubmit">纭畾</el-button>
+        <el-button type="primary"
+                   @click="handleEditParamSubmit">纭畾</el-button>
         <el-button @click="editParamDialogVisible = false">鍙栨秷</el-button>
       </template>
     </el-dialog>
@@ -266,8 +270,32 @@
     paramFormat: "",
     unit: "",
   });
+
+  const onStandardValueInput = (val, target) => {
+    const data = target.value || target;
+    const type = data.paramType || data.parameterType;
+    if (type === 1) {
+      // 鏁板�兼牸寮忥細涓嶈兘杈撳叆涓枃鎴栬嫳鏂囧瓧绗�
+      data.standardValue = val.replace(/[a-zA-Z\u4e00-\u9fa5]/g, "");
+    }
+  };
+
   const editParamRules = ref({
-    // standardValue: [{ required: true, message: "璇疯緭鍏ユ爣鍑嗗��", trigger: "blur" }],
+    standardValue: [
+      {
+        validator: (rule, value, callback) => {
+          const type =
+            editParamForm.value.paramType || editParamForm.value.parameterType;
+          if (type === 1 && value) {
+            if (/[a-zA-Z\u4e00-\u9fa5]/.test(value)) {
+              return callback(new Error("鏁板�兼牸寮忎笉鑳藉寘鍚腑鑻辨枃瀛楃"));
+            }
+          }
+          callback();
+        },
+        trigger: "blur",
+      },
+    ],
   });
   const editParamFormRef = ref(null);
 
diff --git a/src/views/collaborativeApproval/sealManagement/index.vue b/src/views/collaborativeApproval/sealManagement/index.vue
index a6232c2..9d68848 100644
--- a/src/views/collaborativeApproval/sealManagement/index.vue
+++ b/src/views/collaborativeApproval/sealManagement/index.vue
@@ -87,10 +87,18 @@
         </el-form-item>
         <el-form-item label="绱ф�ョ▼搴�" prop="urgency">
           <el-radio-group v-model="sealForm.urgency">
-            <el-radio label="normal">鏅��</el-radio>
-            <el-radio label="urgent">绱ф��</el-radio>
-            <el-radio label="very-urgent">鐗规��</el-radio>
+            <el-radio value="normal">鏅��</el-radio>
+            <el-radio value="urgent">绱ф��</el-radio>
+            <el-radio value="very-urgent">鐗规��</el-radio>
           </el-radio-group>
+        </el-form-item>
+        <el-form-item label="闄勪欢涓婁紶">
+          <AttachmentUploadFile
+            v-model:fileList="sealForm.storageBlobDTOs"
+            :limit="10"
+            :fileSize="50"
+            buttonText="鐐瑰嚮涓婁紶闄勪欢"
+          />
         </el-form-item>
       </el-form>
     </FormDialog>
@@ -119,8 +127,27 @@
           </el-descriptions-item>
           <el-descriptions-item label="鐢宠鍘熷洜" :span="2">{{ currentSealDetail.reason }}</el-descriptions-item>
         </el-descriptions>
+        <!-- 闄勪欢鍒楄〃 -->
+        <div v-if="currentSealDetail.storageBlobVOList?.length || currentSealDetail.storageBlobDTOs?.length" class="attachment-section">
+          <div class="attachment-title">闄勪欢鍒楄〃锛�</div>
+          <el-table :data="currentSealDetail.storageBlobVOList || currentSealDetail.storageBlobDTOs" border class="attachment-table">
+            <el-table-column label="闄勪欢鍚嶇О" show-overflow-tooltip>
+              <template #default="scope">
+                {{ scope.row.originalFilename || scope.row.name || scope.row.fileName || '鏈懡鍚嶆枃浠�' }}
+              </template>
+            </el-table-column>
+            <el-table-column fixed="right" label="鎿嶄綔" width="150" align="center">
+              <template #default="scope">
+                <el-button link type="primary" size="small" @click="previewFile(scope.row)">棰勮</el-button>
+                <el-button link type="primary" size="small" @click="downloadFile(scope.row)">涓嬭浇</el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </div>
       </div>
     </FormDialog>
+    <!-- 鏂囦欢棰勮缁勪欢 -->
+    <FilePreview ref="filePreviewRef" />
 
   </div>
 </template>
@@ -134,6 +161,9 @@
 import useUserStore from '@/store/modules/user'
 import FormDialog from '@/components/Dialog/FormDialog.vue'
 import PIMTable from '@/components/PIMTable/PIMTable.vue'
+import AttachmentUploadFile from '@/components/AttachmentUpload/file/index.vue'
+import FilePreview from '@/components/filePreview/index.vue'
+import download from '@/plugins/download.js'
 
 // 鍝嶅簲寮忔暟鎹�
 // 鐢ㄥ嵃鐢宠鐩稿叧
@@ -143,6 +173,7 @@
 const tableLoading = ref(false)
 const showSealDetailDialog = ref(false)
 const currentSealDetail = ref(null)
+const filePreviewRef = ref(null)
 const sealFormRef = ref()
 const userList = ref([])
 const sealForm = reactive({
@@ -152,7 +183,8 @@
   reason: '',
   approveUserId: '',
   urgency: 'normal',
-  status: 'pending'
+  status: 'pending',
+  storageBlobDTOs: []
 })
 
 const sealRules = {
@@ -281,7 +313,8 @@
         reason: '',
         approveUserId: '',
         urgency: 'normal',
-        status: 'pending'
+        status: 'pending',
+        storageBlobDTOs: []
       })
       }
     }).catch(err => {
@@ -301,7 +334,8 @@
     reason: '',
     approveUserId: '',
     urgency: 'normal',
-    status: 'pending'
+    status: 'pending',
+    storageBlobDTOs: []
   })
   // 娓呴櫎琛ㄥ崟楠岃瘉鐘舵��
   if (sealFormRef.value) {
@@ -318,6 +352,27 @@
 const viewSealDetail = (row) => {
   currentSealDetail.value = row
   showSealDetailDialog.value = true
+}
+
+// 棰勮鏂囦欢
+const previewFile = (row) => {
+  const url = row.previewURL || row.previewUrl || row.url
+  if (url && filePreviewRef.value) {
+    filePreviewRef.value.open(url)
+  } else {
+    ElMessage.warning('鏂囦欢鍦板潃鏃犳晥锛屾棤娉曢瑙�')
+  }
+}
+
+// 涓嬭浇鏂囦欢
+const downloadFile = (row) => {
+  const url = row.downloadURL || row.downloadUrl || row.url
+  if (url) {
+    const filename = row.originalFilename || row.name || row.fileName || 'download'
+    download.byUrl(url, filename)
+  } else {
+    ElMessage.warning('鏂囦欢鍦板潃鏃犳晥锛屾棤娉曚笅杞�')
+  }
 }
 // 瀹℃壒鐢ㄥ嵃鐢宠
 const approveSeal = (row) => {
@@ -421,4 +476,19 @@
 .ml-10 {
   margin-left: 10px;
 }
+
+.attachment-section {
+  margin-top: 20px;
+}
+
+.attachment-title {
+  font-size: 14px;
+  color: #606266;
+  margin-bottom: 10px;
+  font-weight: 500;
+}
+
+.attachment-table {
+  border-radius: 4px;
+}
 </style>
diff --git a/src/views/equipmentManagement/measurementEquipment/components/formDia.vue b/src/views/equipmentManagement/measurementEquipment/components/formDia.vue
index 6b7feec..16ac41f 100644
--- a/src/views/equipmentManagement/measurementEquipment/components/formDia.vue
+++ b/src/views/equipmentManagement/measurementEquipment/components/formDia.vue
@@ -36,15 +36,6 @@
 				</el-row>
 				<el-row :gutter="30">
 					<el-col :span="12">
-						<el-form-item label="瀹夎浣嶇疆锛�" prop="instationLocation">
-							<el-input
-								v-model="form.instationLocation"
-								placeholder="璇疯緭鍏�"
-								clearable
-							/>
-						</el-form-item>
-					</el-col>
-					<el-col :span="12">
 						<el-form-item label="妫�瀹氬崟浣嶏細" prop="unit">
               <el-input
                   v-model="form.unit"
@@ -53,17 +44,17 @@
               />
 						</el-form-item>
 					</el-col>
-				</el-row>
-        <el-row :gutter="30">
-          <el-col :span="12">
-            <el-form-item label="璇佷功缂栧彿锛�" prop="model">
+					<el-col :span="12">
+						<el-form-item label="璇佷功缂栧彿锛�" prop="model">
               <el-input
                   v-model="form.model"
                   placeholder="璇疯緭鍏�"
                   clearable
               />
             </el-form-item>
-          </el-col>
+					</el-col>
+				</el-row>
+        <el-row :gutter="30">
           <el-col :span="12">
             <el-form-item label="鏈�鏂伴壌瀹氭棩鏈燂細" prop="mostDate">
               <el-date-picker
@@ -77,8 +68,6 @@
               />
             </el-form-item>
           </el-col>
-        </el-row>
-        <el-row :gutter="30">
           <el-col :span="12">
             <el-form-item label="鏈夋晥鏃ユ湡(澶�)锛�" prop="valid">
               <el-input
@@ -91,15 +80,6 @@
               >
               <template #append>鏃�</template>
               </el-input>
-            </el-form-item>
-          </el-col>
-          <el-col :span="12">
-            <el-form-item label="妫�瀹氬懆鏈燂細" prop="cycle">
-              <el-input
-                  v-model="form.cycle"
-                  placeholder="璇疯緭鍏ユ瀹氬懆鏈�"
-                  clearable
-              />
             </el-form-item>
           </el-col>
         </el-row>
@@ -184,10 +164,8 @@
 	form: {
 		code: "",
     name: "",
-    instationLocation: "",
     mostDate:"",
 		model: "",
-    cycle:"",
 		validDate: "",
 		nextDate: "",
 		userId: "",
@@ -203,9 +181,7 @@
 		nextDate: [{required: true, message: "璇烽�夋嫨", trigger: "change"}],
 		userId: [{required: true, message: "璇烽�夋嫨", trigger: "change"}],
 		recordDate: [{required: true, message: "璇烽�夋嫨", trigger: "change"}],
-    instationLocation: [{required: true, message: "璇疯緭鍏�", trigger: "blur"}],
     mostDate: [{required: true, message: "璇烽�夋嫨", trigger: "change"}],
-    cycle: [{required: true, message: "璇烽�夋嫨", trigger: "blur"}],
     valid: [
       {required: true, message: "璇疯緭鍏�", trigger: "blur"},
       {
diff --git a/src/views/equipmentManagement/measurementEquipment/index.vue b/src/views/equipmentManagement/measurementEquipment/index.vue
index c1d5379..52c52a1 100644
--- a/src/views/equipmentManagement/measurementEquipment/index.vue
+++ b/src/views/equipmentManagement/measurementEquipment/index.vue
@@ -89,12 +89,6 @@
     align: "center",
   },
 	{
-		label: "瀹夎浣嶇疆",
-		prop: "instationLocation",
-		width: 150,
-    align:"center"
-	},
-	{
 		label: "妫�瀹氬崟浣�",
 		prop: "unit",
 		width: 200,
@@ -131,10 +125,20 @@
     align:"center"
 	},
   {
-    label: "妫�瀹氬懆鏈�(澶�)",
-    prop: "cycle",
+    label: "蹇埌鏈熸彁閱�",
+    prop: "valid",
     width: 130,
-    align:"center"
+    align: "center",
+    formatData: (cell) => {
+      if (!cell) return "";
+      const validDate = new Date(cell);
+      const now = new Date();
+      const diffDays = Math.ceil((validDate - now) / (1000 * 60 * 60 * 24));
+      if (diffDays <= 7 && diffDays >= 0) {
+        return "鈿狅笍 " + diffDays + "澶╁悗鍒版湡";
+      }
+      return "";
+    }
   },
   {
     label: "鐘舵��",
diff --git a/src/views/equipmentManagement/repair/Modal/AcceptanceModal.vue b/src/views/equipmentManagement/repair/Modal/AcceptanceModal.vue
new file mode 100644
index 0000000..6d61a9f
--- /dev/null
+++ b/src/views/equipmentManagement/repair/Modal/AcceptanceModal.vue
@@ -0,0 +1,144 @@
+<template>
+  <FormDialog
+    v-model="visible"
+    title="楠屾敹瀹℃壒"
+    width="500px"
+    @confirm="submitForm"
+    @cancel="handleCancel"
+    @close="handleCancel"
+  >
+    <el-form :model="form" :rules="rules" label-width="100px">
+      <el-form-item label="楠屾敹浜�" prop="acceptanceName">
+        <el-select
+          v-model="form.acceptanceName"
+          placeholder="璇烽�夋嫨楠屾敹浜�"
+          filterable
+          style="width: 100%"
+        >
+          <el-option
+            v-for="item in userList"
+            :key="item.userId"
+            :label="item.nickName"
+            :value="item.nickName"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="楠屾敹鏃堕棿" prop="acceptanceTime">
+        <el-date-picker
+          v-model="form.acceptanceTime"
+          type="datetime"
+          placeholder="璇烽�夋嫨楠屾敹鏃堕棿"
+          format="YYYY-MM-DD HH:mm:ss"
+          value-format="YYYY-MM-DD HH:mm:ss"
+          style="width: 100%"
+        />
+      </el-form-item>
+      <el-form-item label="楠屾敹澶囨敞" prop="acceptanceRemark">
+        <el-input
+          v-model="form.acceptanceRemark"
+          type="textarea"
+          :rows="3"
+          placeholder="璇疯緭鍏ラ獙鏀跺娉�"
+        />
+      </el-form-item>
+    </el-form>
+  </FormDialog>
+</template>
+
+<script setup>
+import FormDialog from "@/components/Dialog/FormDialog.vue";
+import { ref, reactive } from "vue";
+import { ElMessage } from "element-plus";
+import { userListNoPageByTenantId } from "@/api/system/user.js";
+import { repairAcceptance } from "@/api/equipmentManagement/repair";
+import dayjs from "dayjs";
+
+defineOptions({
+  name: "楠屾敹瀹℃壒寮圭獥",
+});
+
+const emits = defineEmits(["ok"]);
+
+const visible = ref(false);
+const loading = ref(false);
+const repairId = ref(null);
+const userList = ref([]);
+
+const form = reactive({
+  acceptanceName: undefined,
+  acceptanceTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
+  acceptanceRemark: undefined,
+});
+
+const rules = {
+  acceptanceName: [
+    { required: true, message: "璇烽�夋嫨楠屾敹浜�", trigger: "change" },
+  ],
+  acceptanceTime: [
+    { required: true, message: "璇烽�夋嫨楠屾敹鏃堕棿", trigger: "change" },
+  ],
+  acceptanceRemark: [
+    { required: true, message: "璇疯緭鍏ラ獙鏀跺娉�", trigger: "blur" },
+  ],
+};
+
+// 鍔犺浇鐢ㄦ埛鍒楄〃
+const loadUserList = async () => {
+  const { data } = await userListNoPageByTenantId();
+  userList.value = data;
+};
+
+// 鎵撳紑寮圭獥
+const open = async (row) => {
+  repairId.value = row.id;
+  visible.value = true;
+  // 閲嶇疆琛ㄥ崟
+  form.acceptanceName = undefined;
+  form.acceptanceTime = dayjs().format("YYYY-MM-DD HH:mm:ss");
+  form.acceptanceRemark = undefined;
+  await loadUserList();
+};
+
+// 鎻愪氦琛ㄥ崟
+const submitForm = async () => {
+  if (!form.acceptanceName) {
+    ElMessage.warning("璇烽�夋嫨楠屾敹浜�");
+    return;
+  }
+  if (!form.acceptanceTime) {
+    ElMessage.warning("璇烽�夋嫨楠屾敹鏃堕棿");
+    return;
+  }
+  if (!form.acceptanceRemark) {
+    ElMessage.warning("璇疯緭鍏ラ獙鏀跺娉�");
+    return;
+  }
+
+  loading.value = true;
+  try {
+    const { code } = await repairAcceptance({
+      id: repairId.value,
+      acceptanceName: form.acceptanceName,
+      acceptanceTime: form.acceptanceTime,
+      acceptanceRemark: form.acceptanceRemark,
+    });
+    if (code === 200) {
+      ElMessage.success("楠屾敹閫氳繃");
+      visible.value = false;
+      emits("ok");
+    }
+  } finally {
+    loading.value = false;
+  }
+};
+
+const handleCancel = () => {
+  visible.value = false;
+};
+
+defineExpose({
+  open,
+});
+</script>
+
+<style lang="scss" scoped></style>
diff --git a/src/views/equipmentManagement/repair/Modal/MaintainModal.vue b/src/views/equipmentManagement/repair/Modal/MaintainModal.vue
index b0b09f0..b39ce08 100644
--- a/src/views/equipmentManagement/repair/Modal/MaintainModal.vue
+++ b/src/views/equipmentManagement/repair/Modal/MaintainModal.vue
@@ -16,8 +16,7 @@
       </el-form-item>
       <el-form-item label="缁翠慨鐘舵��">
         <el-select v-model="form.status">
-          <el-option label="寰呮姤淇�" :value="0"></el-option>
-          <el-option label="瀹岀粨" :value="1"></el-option>
+          <el-option label="寰呴獙鏀�" :value="3"></el-option>
           <el-option label="澶辫触" :value="2"></el-option>
         </el-select>
       </el-form-item>
@@ -118,7 +117,7 @@
     data.maintenanceTime 
       ? dayjs(data.maintenanceTime).format("YYYY-MM-DD HH:mm:ss")
       : dayjs().format("YYYY-MM-DD HH:mm:ss");
-  form.status = 1; // 榛樿鐘舵�佷负瀹岀粨
+  form.status = 3; // 榛樿鐘舵�佷负寰呴獙鏀�
   // multiple 閫夋嫨鍣ㄨ姹傛暟缁勶紱鍚庣甯歌繑鍥� "1,2,3"
   if (Array.isArray(data?.sparePartsIds)) {
     form.sparePartsIds = data.sparePartsIds.map((v) => Number(v)).filter((v) => Number.isFinite(v));
diff --git a/src/views/equipmentManagement/repair/Modal/RepairModal.vue b/src/views/equipmentManagement/repair/Modal/RepairModal.vue
index 5e31943..4e73833 100644
--- a/src/views/equipmentManagement/repair/Modal/RepairModal.vue
+++ b/src/views/equipmentManagement/repair/Modal/RepairModal.vue
@@ -49,19 +49,44 @@
           </el-form-item>
         </el-col>
         <el-col :span="12">
-          <el-form-item label="椤圭洰">
-            <el-input v-model="form.machineryCategory" placeholder="璇疯緭鍏ラ」鐩�" />
+          <el-form-item label="鎶ヤ慨鎶ヤ慨椤圭洰">
+            <el-input v-model="form.machineryCategory" placeholder="璇疯緭鍏ユ姤淇姤淇」鐩�" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row>
+        <el-col :span="12">
+          <el-form-item label="缁翠慨浜�">
+            <el-input v-model="form.maintenanceName" placeholder="璇疯緭鍏ョ淮淇汉濮撳悕" />
           </el-form-item>
         </el-col>
       </el-row>
       <el-row v-if="id">
         <el-col :span="12">
           <el-form-item label="鎶ヤ慨鐘舵��">
-            <el-select v-model="form.status">
+            <el-select v-model="form.status" disabled>
               <el-option label="寰呯淮淇�" :value="0"></el-option>
-              <el-option label="瀹岀粨" :value="1"></el-option>
+              <el-option label="宸查獙鏀�" :value="1"></el-option>
               <el-option label="澶辫触" :value="2"></el-option>
             </el-select>
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <!-- 楠屾敹淇℃伅灞曠ず -->
+      <el-row v-if="id && form.status === 1">
+        <el-col :span="12">
+          <el-form-item label="楠屾敹浜�">
+            <el-input v-model="form.acceptanceName" disabled />
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="楠屾敹鏃堕棿">
+            <el-input v-model="form.acceptanceTime" disabled />
+          </el-form-item>
+        </el-col>
+        <el-col :span="24">
+          <el-form-item label="楠屾敹澶囨敞">
+            <el-input v-model="form.acceptanceRemark" type="textarea" :rows="2" disabled />
           </el-form-item>
         </el-col>
       </el-row>
@@ -131,6 +156,7 @@
   status: 0, // 鎶ヤ慨鐘舵��
   machineryCategory: undefined,
   storageBlobDTOs: [],
+  maintenanceName: undefined, // 缁翠慨浜�
 });
 
 const setDeviceModel = (deviceId) => {
@@ -148,6 +174,10 @@
   form.status = data.status;
   form.machineryCategory = data.machineryCategory;
   form.storageBlobDTOs = data.storageBlobVOs || [];
+  form.maintenanceName = data.maintenanceName;
+  form.acceptanceName = data.acceptanceName;
+  form.acceptanceTime = data.acceptanceTime;
+  form.acceptanceRemark = data.acceptanceRemark;
 };
 
 const sendForm = async () => {
diff --git a/src/views/equipmentManagement/repair/index.vue b/src/views/equipmentManagement/repair/index.vue
index f3a4330..2835356 100644
--- a/src/views/equipmentManagement/repair/index.vue
+++ b/src/views/equipmentManagement/repair/index.vue
@@ -100,13 +100,14 @@
         <template #statusRef="{ row }">
           <el-tag v-if="row.status === 2" type="danger">澶辫触</el-tag>
           <el-tag v-if="row.status === 1" type="success">瀹岀粨</el-tag>
+          <el-tag v-if="row.status === 3" type="info">寰呴獙鏀�</el-tag>
           <el-tag v-if="row.status === 0" type="warning">寰呯淮淇�</el-tag>
         </template>
         <template #operation="{ row }">
           <el-button
             type="primary"
             link
-            :disabled="row.status === 1"
+            :disabled="row.status === 1 || row.status === 3"
             @click="editRepair(row.id)"
           >
             缂栬緫
@@ -114,15 +115,23 @@
           <el-button
             type="success"
             link
-            :disabled="row.status === 1"
+            :disabled="row.status !== 0"
             @click="addMaintain(row)"
           >
             缁翠慨
           </el-button>
           <el-button
+            type="warning"
+            link
+            :disabled="row.status !== 3"
+            @click="openAcceptance(row)"
+          >
+            楠屾敹
+          </el-button>
+          <el-button
             type="danger"
             link
-            :disabled="row.status === 1"
+            :disabled="row.status === 1 || row.status === 3"
             @click="delRepairByIds(row.id)"
           >
             鍒犻櫎
@@ -139,6 +148,7 @@
     </div>
     <RepairModal ref="repairModalRef" @ok="getTableData"/>
     <MaintainModal ref="maintainModalRef" @ok="getTableData"/>
+    <AcceptanceModal ref="acceptanceModalRef" @ok="getTableData"/>
     <FileList v-if="fileDialogVisible"  v-model:visible="fileDialogVisible" :record-type="'device_repair'" :record-id="recordId"  />
   </div>
 </template>
@@ -151,6 +161,7 @@
 import {ElMessageBox, ElMessage} from "element-plus";
 import dayjs from "dayjs";
 import MaintainModal from "./Modal/MaintainModal.vue";
+import AcceptanceModal from "./Modal/AcceptanceModal.vue";
 const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue"));
 
 defineOptions({
@@ -162,6 +173,7 @@
 // 妯℃�佹瀹炰緥
 const repairModalRef = ref();
 const maintainModalRef = ref();
+const acceptanceModalRef = ref();
 
 // 琛ㄦ牸澶氶�夋閫変腑椤�
 const multipleList = ref([]);
@@ -197,7 +209,7 @@
         prop: "deviceModel",
       },
       {
-        label: "椤圭洰",
+        label: "鎶ヤ慨椤圭洰",
         align: "center",
         prop: "machineryCategory",
       },
@@ -232,6 +244,17 @@
         align: "center",
         prop: "maintenanceTime",
         formatData: (cell) => (cell ? dayjs(cell).format("YYYY-MM-DD") : ""),
+      },
+      {
+        label: "楠屾敹浜�",
+        align: "center",
+        prop: "acceptanceName",
+      },
+      {
+        label: "楠屾敹鏃堕棿",
+        align: "center",
+        prop: "acceptanceTime",
+        formatData: (cell) => (cell ? dayjs(cell).format("YYYY-MM-DD HH:mm:ss") : ""),
       },
       {
         label: "鐘舵��",
@@ -301,6 +324,11 @@
   maintainModalRef.value.open(row.id, row);
 };
 
+// 鎵撳紑楠屾敹寮圭獥
+const openAcceptance = (row) => {
+  acceptanceModalRef.value.open(row);
+};
+
 const changePage = ({page, limit}) => {
   pagination.currentPage = page;
   pagination.pageSize = limit;
diff --git a/src/views/equipmentManagement/upkeep/Form/PlanModal.vue b/src/views/equipmentManagement/upkeep/Form/PlanModal.vue
index ee59ce2..8a9cd98 100644
--- a/src/views/equipmentManagement/upkeep/Form/PlanModal.vue
+++ b/src/views/equipmentManagement/upkeep/Form/PlanModal.vue
@@ -32,10 +32,10 @@
           disabled
         />
       </el-form-item>
-      <el-form-item label="椤圭洰">
+      <el-form-item label="淇濆吇椤圭洰">
         <el-input
             v-model="form.machineryCategory"
-            placeholder="璇疯緭鍏ラ」鐩�"
+            placeholder="璇疯緭鍏ヤ繚鍏婚」鐩�"
         />
       </el-form-item>
       <el-form-item label="褰曞叆浜�">
@@ -61,6 +61,13 @@
           <el-option label="瀹岀粨" :value="1"></el-option>
           <el-option label="澶辫触" :value="2"></el-option>
         </el-select>
+      </el-form-item>
+      <el-form-item label="淇濆吇浜�">
+        <el-input
+          v-model="form.maintenancePerson"
+          placeholder="璇疯緭鍏ヤ繚鍏讳汉濮撳悕"
+          clearable
+        />
       </el-form-item>
       <el-form-item label="璁″垝淇濆吇鏃ユ湡">
         <el-date-picker
@@ -124,6 +131,7 @@
   status: 0, //淇濅慨鐘舵��
   machineryCategory: undefined,
   storageBlobDTOs: [],
+  maintenancePerson: undefined, // 淇濆吇浜�
 });
 
 const setDeviceModel = (deviceId) => {
@@ -142,6 +150,7 @@
   form.createUser = Number(data.createUser);
   form.status = data.status;
   form.machineryCategory = data.machineryCategory;
+  form.maintenancePerson = data.maintenancePerson;
   if (data.maintenancePlanTime) {
     form.maintenancePlanTime = dayjs(data.maintenancePlanTime).format(
       "YYYY-MM-DD HH:mm:ss"
diff --git a/src/views/equipmentManagement/upkeep/Form/formDia.vue b/src/views/equipmentManagement/upkeep/Form/formDia.vue
index 9550b08..6856ae1 100644
--- a/src/views/equipmentManagement/upkeep/Form/formDia.vue
+++ b/src/views/equipmentManagement/upkeep/Form/formDia.vue
@@ -67,10 +67,20 @@
 			</el-row>
 			<el-row>
 				<el-col :span="12">
-					<el-form-item label="璁惧椤圭洰" prop="machineryCategory">
+					<el-form-item label="淇濆吇椤圭洰" prop="machineryCategory">
 						<el-input
 							v-model.trim="form.machineryCategory"
-							placeholder="璇疯緭鍏ヨ澶囬」鐩�"
+							placeholder="璇疯緭鍏ヤ繚鍏婚」鐩�"
+							maxlength="100"
+							clearable
+						/>
+					</el-form-item>
+				</el-col>
+				<el-col :span="12">
+					<el-form-item label="淇濆吇浜�" prop="maintenancePerson">
+						<el-input
+							v-model.trim="form.maintenancePerson"
+							placeholder="璇疯緭鍏ヤ繚鍏讳汉濮撳悕"
 							maxlength="100"
 							clearable
 						/>
@@ -173,13 +183,14 @@
 		week: '',
 		time: '',
 		deviceModel: undefined, // 瑙勬牸鍨嬪彿
-		registrationDate: ''
+		registrationDate: '',
+		maintenancePerson: '' // 淇濆吇浜�
 	},
 	rules: {
 		taskId: [{ required: true, message: "璇烽�夋嫨璁惧", trigger: "change" },],
 		inspector: [{ required: true, message: "璇烽�夋嫨褰曞叆浜�", trigger: "blur" },],
 		registrationDate: [{ required: true, message: "璇烽�夋嫨鐧昏鏃堕棿", trigger: "change" }],
-		machineryCategory: [{ required: true, message: "璇疯緭鍏ヨ澶囬」鐩�", trigger: "blur" }]
+		machineryCategory: [{ required: true, message: "璇疯緭鍏ヤ繚鍏婚」鐩�", trigger: "blur" }]
 	}
 })
 const { form, rules } = toRefs(data)
@@ -259,7 +270,8 @@
 		week: '',
 		time: '',
 		deviceModel: undefined,
-		registrationDate: ''
+		registrationDate: '',
+		maintenancePerson: ''
 	}
 }
 
diff --git a/src/views/equipmentManagement/upkeep/index.vue b/src/views/equipmentManagement/upkeep/index.vue
index 2fc3eae..6bdbc8f 100644
--- a/src/views/equipmentManagement/upkeep/index.vue
+++ b/src/views/equipmentManagement/upkeep/index.vue
@@ -300,7 +300,7 @@
       prop: "deviceModel",
     },
     {
-      label: "璁惧椤圭洰",
+      label: "淇濆吇椤圭洰",
       prop: "machineryCategory",
       minWidth: 120,
       formatData: cell => cell || "--",
@@ -342,6 +342,7 @@
         );
       },
     },
+    { prop: "maintenancePerson", label: "淇濆吇浜�", minWidth: 100 },
     { prop: "registrant", label: "鐧昏浜�", minWidth: 100 },
     { prop: "registrationDate", label: "鐧昏鏃ユ湡", minWidth: 100 },
     {
@@ -378,7 +379,7 @@
       prop: "createUserName",
     },
     {
-      label: "璁惧椤圭洰",
+      label: "淇濆吇椤圭洰",
       align: "center",
       prop: "machineryCategory",
       formatData: cell => cell || "--",
diff --git a/src/views/financialManagement/assets/fixedAssets.vue b/src/views/financialManagement/assets/fixedAssets.vue
index c6241c8..24b4cc3 100644
--- a/src/views/financialManagement/assets/fixedAssets.vue
+++ b/src/views/financialManagement/assets/fixedAssets.vue
@@ -38,7 +38,7 @@
         <div>
           <el-button type="primary" @click="add" icon="Plus">鏂板璧勪骇</el-button>
           <el-button type="warning" @click="handleDepreciation" icon="Money">鎶樻棫璁℃彁</el-button>
-          <el-button @click="handleOut" icon="Download">瀵煎嚭</el-button>
+          <!-- <el-button @click="handleOut" icon="Download">瀵煎嚭</el-button> -->
         </div>
       </div>
       <PIMTable
diff --git a/src/views/financialManagement/assets/intangibleAssets.vue b/src/views/financialManagement/assets/intangibleAssets.vue
index 47820c2..4642166 100644
--- a/src/views/financialManagement/assets/intangibleAssets.vue
+++ b/src/views/financialManagement/assets/intangibleAssets.vue
@@ -39,7 +39,7 @@
         <div>
           <el-button type="primary" @click="add" icon="Plus">鏂板璧勪骇</el-button>
           <el-button type="warning" @click="handleAmortization" icon="Money">鎽婇攢璁℃彁</el-button>
-          <el-button @click="handleOut" icon="Download">瀵煎嚭</el-button>
+          <!-- <el-button @click="handleOut" icon="Download">瀵煎嚭</el-button> -->
         </div>
       </div>
       <PIMTable
diff --git a/src/views/financialManagement/generalLedger/index.vue b/src/views/financialManagement/generalLedger/index.vue
index 556567b..a7b1d30 100644
--- a/src/views/financialManagement/generalLedger/index.vue
+++ b/src/views/financialManagement/generalLedger/index.vue
@@ -44,8 +44,8 @@
           <el-button type="primary"
                      @click="add"
                      icon="Plus">鏂板</el-button>
-          <el-button @click="handleOut"
-                     icon="Download">瀵煎嚭</el-button>
+          <!-- <el-button @click="handleOut"
+                     icon="Download">瀵煎嚭</el-button> -->
         </div>
       </div>
       <el-table ref="tableRef"
diff --git a/src/views/financialManagement/voucher/detailLedger.vue b/src/views/financialManagement/voucher/detailLedger.vue
index 1909d0e..c07574c 100644
--- a/src/views/financialManagement/voucher/detailLedger.vue
+++ b/src/views/financialManagement/voucher/detailLedger.vue
@@ -32,7 +32,7 @@
           <el-form-item>
             <el-button type="primary" @click="getTableData">鏌ヨ</el-button>
             <el-button @click="resetFilters">閲嶇疆</el-button>
-            <el-button @click="handlePrint" icon="Printer">鎵撳嵃</el-button>
+<!--            <el-button @click="handlePrint" icon="Printer">鎵撳嵃</el-button>-->
             <el-button @click="handleOut" icon="Download">瀵煎嚭</el-button>
           </el-form-item>
         </el-form>
diff --git a/src/views/financialManagement/voucher/generalLedger.vue b/src/views/financialManagement/voucher/generalLedger.vue
index 9683487..b362279 100644
--- a/src/views/financialManagement/voucher/generalLedger.vue
+++ b/src/views/financialManagement/voucher/generalLedger.vue
@@ -32,34 +32,34 @@
           <el-form-item>
             <el-button type="primary" @click="getTableData">鏌ヨ</el-button>
             <el-button @click="resetFilters">閲嶇疆</el-button>
-            <el-button @click="handlePrint" icon="Printer">鎵撳嵃</el-button>
-            <el-button @click="handleOut" icon="Download">瀵煎嚭</el-button>
+<!--            <el-button @click="handlePrint" icon="Printer">鎵撳嵃</el-button>-->
+            <!-- <el-button @click="handleOut" icon="Download">瀵煎嚭</el-button> -->
           </el-form-item>
         </el-form>
 
         <div class="table_list">
           <el-table :data="dataList" border style="width: 100%">
-            <el-table-column prop="date" label="鏃ユ湡" width="120" />
-            <el-table-column prop="voucherNo" label="鍑瘉瀛楀彿" width="120" />
-            <el-table-column prop="summary" label="鎽樿" min-width="200" show-overflow-tooltip />
-            <el-table-column prop="debit" label="鍊熸柟" width="150">
+            <el-table-column prop="date" label="鏃ユ湡"/>
+            <!-- <el-table-column prop="voucherNo" label="鍑瘉瀛楀彿" width="120" /> -->
+            <!-- <el-table-column prop="summary" label="鎽樿" min-width="200" show-overflow-tooltip /> -->
+            <el-table-column prop="debit" label="鍊熸柟">
               <template #default="{ row }">
                 <span v-if="row.debit > 0" class="text-danger">楼{{ formatMoney(row.debit) }}</span>
                 <span v-else>-</span>
               </template>
             </el-table-column>
-            <el-table-column prop="credit" label="璐锋柟" width="150">
+            <el-table-column prop="credit" label="璐锋柟">
               <template #default="{ row }">
                 <span v-if="row.credit > 0" class="text-success">楼{{ formatMoney(row.credit) }}</span>
                 <span v-else>-</span>
               </template>
             </el-table-column>
-            <el-table-column label="鏂瑰悜" width="80">
+            <el-table-column label="鏂瑰悜">
               <template #default="{ row }">
                 <el-tag :type="row.direction === '鍊�' ? 'success' : 'danger'" size="small">{{ row.direction }}</el-tag>
               </template>
             </el-table-column>
-            <el-table-column label="浣欓" width="150">
+            <el-table-column label="浣欓">
               <template #default="{ row }">
                 <span :class="row.balance >= 0 ? 'text-primary' : 'text-warning'">楼{{ formatMoney(Math.abs(row.balance)) }}</span>
               </template>
diff --git a/src/views/financialManagement/voucher/index.vue b/src/views/financialManagement/voucher/index.vue
index 03c0856..1aa6f69 100644
--- a/src/views/financialManagement/voucher/index.vue
+++ b/src/views/financialManagement/voucher/index.vue
@@ -32,13 +32,13 @@
     <div class="table_list">
       <div class="actions">
         <div>
-          <el-statistic title="鍊熸柟鍚堣" :value="totalDebit" precision="2" prefix="楼" />
-          <el-statistic title="璐锋柟鍚堣" :value="totalCredit" precision="2" prefix="楼" style="margin-left: 30px;" />
+          <el-statistic title="鍊熸柟鍚堣" :value="totalDebit" :precision="2" prefix="楼" />
+          <el-statistic title="璐锋柟鍚堣" :value="totalCredit" :precision="2" prefix="楼" style="margin-left: 30px;" />
         </div>
         <div>
           <el-button type="primary" @click="add" icon="Plus">鏂板鍑瘉</el-button>
-          <el-button @click="handleImport" icon="Upload">瀵煎叆</el-button>
-          <el-button @click="handleOut" icon="Download">瀵煎嚭</el-button>
+          <!-- <el-button @click="handleImport" icon="Upload">瀵煎叆</el-button> -->
+          <!-- <el-button @click="handleOut" icon="Download">瀵煎嚭</el-button> -->
         </div>
       </div>
       <PIMTable
@@ -84,6 +84,11 @@
               <span class="label">鍑瘉瀛楋細</span>
               <el-select v-model="form.voucherPrefix" :disabled="isViewMode" style="width: 70px;">
                 <el-option label="璁�" value="璁�" />
+                <el-option label="鐜�" value="鐜�" />
+                <el-option label="閾�" value="閾�" />
+                <el-option label="杞�" value="杞�" />
+                <el-option label="鏀�" value="鏀�" />
+                <el-option label="浠�" value="浠�" />
               </el-select>
               <el-input v-model="form.voucherNum" :disabled="isViewMode" style="width: 60px;" />
               <span class="label" style="margin-left: 5px;">鍙�</span>
@@ -96,7 +101,6 @@
               <span class="label">闄勪欢锛�</span>
               <el-input-number v-model="form.attachmentCount" :disabled="isViewMode" :min="0" :controls="false" style="width: 60px;" />
               <span class="label" style="margin-left: 5px;">寮�</span>
-              <el-button type="primary" link :disabled="isViewMode" style="margin-left: 10px;">涓婁紶鏂囦欢</el-button>
             </div>
           </div>
           <div class="voucher-table">
@@ -153,12 +157,12 @@
                       @change="(val) => handleSubjectChange(val, rowIndex)"
                       @focus="selectRow(rowIndex)"
                     />
-                    <div class="subject-name">{{ entry.subjectName }}</div>
+                    <!-- <div class="subject-name">{{ entry.subjectName }}</div> -->
                   </td>
                   <!-- 鍊熸柟11鍒� -->
                   <template v-if="editingCell.row === rowIndex && editingCell.type === 'debit'">
                     <td colspan="11" class="debit-input-cell">
-                      <el-input-number ref="amountInputRef" v-model="entry.debit" :disabled="isViewMode" :min="0" :precision="2" :controls="false" size="small" @blur="finishEdit" class="full-width-input" />
+                      <el-input-number ref="amountInputRef" v-model="entry.debit" :disabled="isViewMode" :min="0" :precision="2" :controls="false" :value-on-clear="undefined" size="small" @blur="finishEdit" class="full-width-input" />
                     </td>
                   </template>
                   <template v-else>
@@ -169,7 +173,7 @@
                   <!-- 璐锋柟11鍒� -->
                   <template v-if="editingCell.row === rowIndex && editingCell.type === 'credit'">
                     <td colspan="11" class="credit-input-cell">
-                      <el-input-number ref="amountInputRef" v-model="entry.credit" :disabled="isViewMode" :min="0" :precision="2" :controls="false" size="small" @blur="finishEdit" class="full-width-input" />
+                      <el-input-number ref="amountInputRef" v-model="entry.credit" :disabled="isViewMode" :min="0" :precision="2" :controls="false" :value-on-clear="undefined" size="small" @blur="finishEdit" class="full-width-input" />
                     </td>
                   </template>
                   <template v-else>
@@ -217,7 +221,36 @@
               </el-select>
             </div>
           </div>
+          <!-- 缂栬緫妯″紡锛氫娇鐢� AttachmentUploadFile 涓婁紶缁勪欢 -->
+          <div class="voucher-attachment-upload" v-if="!isViewMode">
+            <div class="attachment-label">闄勪欢涓婁紶锛�</div>
+            <AttachmentUploadFile
+              v-model:fileList="form.attachments"
+              :disabled="isViewMode"
+              :limit="10"
+              :fileSize="50"
+              buttonText="鐐瑰嚮涓婁紶闄勪欢"
+              @change="handleAttachmentChange"
+            />
+          </div>
         </el-form>
+        <!-- 鏌ョ湅妯″紡锛氬睍绀洪檮浠跺垪琛紙鏀惧湪 el-form 澶栭潰锛岄伩鍏嶈 disabled锛� -->
+        <div class="voucher-attachment-upload" v-if="isViewMode && form.attachments?.length">
+          <div class="attachment-label">闄勪欢鍒楄〃锛�</div>
+          <el-table :data="form.attachments" border class="attachment-table">
+            <el-table-column label="闄勪欢鍚嶇О" show-overflow-tooltip>
+              <template #default="scope">
+                {{ scope.row.originalFilename || scope.row.name || scope.row.fileName || '鏈懡鍚嶆枃浠�' }}
+              </template>
+            </el-table-column>
+            <el-table-column fixed="right" label="鎿嶄綔" width="150" align="center">
+              <template #default="scope">
+                <el-button link type="primary" size="small" @click="previewFile(scope.row)">棰勮</el-button>
+                <el-button link type="primary" size="small" @click="downloadFile(scope.row)">涓嬭浇</el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </div>
       </div>
       <template #footer>
         <div>
@@ -226,6 +259,8 @@
         </div>
       </template>
     </FormDialog>
+    <!-- 鏂囦欢棰勮缁勪欢 -->
+    <FilePreview ref="filePreviewRef" />
   </div>
 </template>
 
@@ -233,6 +268,10 @@
 import { ref, reactive, onMounted, computed, nextTick } from "vue";
 import { ElMessage, ElMessageBox } from "element-plus";
 import FormDialog from "@/components/Dialog/FormDialog.vue";
+import AttachmentUploadFile from "@/components/AttachmentUpload/file/index.vue";
+import FileList from "@/components/Dialog/FileList.vue";
+import FilePreview from "@/components/filePreview/index.vue";
+import download from "@/plugins/download.js";
 import useUserStore from "@/store/modules/user";
 import { userListNoPageByTenantId } from "@/api/system/user";
 import { listAccountSubject } from "@/api/financialManagement/accountSubject";
@@ -284,6 +323,7 @@
 const isEdit = ref(false);
 const currentId = ref(null);
 const isViewMode = computed(() => dialogMode.value === "view");
+const filePreviewRef = ref(null);
 
 const fallbackSubjectTree = [
   { subjectCode: "1001", subjectName: "搴撳瓨鐜伴噾", balanceDirection: "鍊熸柟", children: [] },
@@ -326,8 +366,8 @@
   subjectName: "",
   balanceDirection: "",
   summary: "",
-  debit: 0,
-  credit: 0,
+  debit: undefined,
+  credit: undefined,
 });
 
 const createDefaultForm = () => ({
@@ -336,6 +376,7 @@
   voucherNum: "",
   voucherDate: "",
   attachmentCount: 0,
+  attachments: [],
   entries: [createEmptyEntry(), createEmptyEntry()],
   creator: getDefaultCreator(),
   remark: "",
@@ -490,6 +531,31 @@
   form.entries.push(createEmptyEntry());
 };
 
+const handleAttachmentChange = (fileList) => {
+  form.attachmentCount = fileList?.length || 0;
+};
+
+// 浣跨敤椤圭洰灏佽鐨� filePreview 缁勪欢棰勮鏂囦欢
+const previewFile = (row) => {
+  const url = row.previewURL || row.previewUrl || row.url;
+  if (url && filePreviewRef.value) {
+    filePreviewRef.value.open(url);
+  } else {
+    ElMessage.warning('鏂囦欢鍦板潃鏃犳晥锛屾棤娉曢瑙�');
+  }
+};
+
+// 浣跨敤椤圭洰灏佽鐨� download 鎻掍欢涓嬭浇鏂囦欢
+const downloadFile = (row) => {
+  const url = row.downloadURL || row.downloadUrl || row.url;
+  if (url) {
+    const filename = row.originalFilename || row.name || row.fileName || 'download';
+    download.byUrl(url, filename);
+  } else {
+    ElMessage.warning('鏂囦欢鍦板潃鏃犳晥锛屾棤娉曚笅杞�');
+  }
+};
+
 const selectRow = (index) => {
   selectedRowIndex.value = index;
 };
@@ -589,10 +655,13 @@
     const { data } = await getVoucherDetail(row.id);
     const detail = data || row;
     const parts = (detail.voucherNo || "").split("-");
-    Object.assign(form, createDefaultForm(), detail, {
+    const attachments = detail.storageBlobVOList || detail.storageBlobDTOs || detail.attachments || [];
+    Object.assign(form, createDefaultForm(), {
+      ...detail,
       voucherPrefix: parts[0] || "璁�",
       voucherNum: parts[1] || "",
       creator: detail.creator || getDefaultCreator(),
+      attachments,
       entries:
         detail.entries?.map(item => ({
           subjectCode: item.subjectCode || "",
@@ -696,6 +765,7 @@
         remark: form.remark,
         debit: totalDebitEntry.value,
         credit: totalCreditEntry.value,
+        storageBlobDTOs: form.attachments || [],
         entries: validEntries.map(entry => ({
           subjectCode: entry.subjectCode,
           subjectName: entry.subjectName,
@@ -801,6 +871,21 @@
   }
 }
 
+.voucher-attachment-upload {
+  margin-top: 15px;
+  padding: 0 10px;
+
+  .attachment-label {
+    font-size: 14px;
+    color: #606266;
+    margin-bottom: 10px;
+  }
+
+  .attachment-table {
+    border-radius: 4px;
+  }
+}
+
 .voucher-table {
   border: 1px solid #dcdfe6;
   border-right: none;
diff --git a/src/views/personnelManagement/contractManagement/index.vue b/src/views/personnelManagement/contractManagement/index.vue
index a55a502..074b9ac 100644
--- a/src/views/personnelManagement/contractManagement/index.vue
+++ b/src/views/personnelManagement/contractManagement/index.vue
@@ -23,6 +23,12 @@
         :total="page.total"></PIMTable>
     </div>
     <form-dia ref="formDia" @close="handleQuery"></form-dia>
+    <renew-contract
+        v-if="isShowRenewContractModal"
+        v-model:visible="isShowRenewContractModal"
+        :id="id"
+        @completed="handleQuery"
+    />
 
     <!-- 鍚堝悓瀵煎叆瀵硅瘽妗� -->
     <el-dialog
@@ -71,8 +77,9 @@
 
 <script setup>
 import { Search } from "@element-plus/icons-vue";
-import { onMounted, ref } from "vue";
+import { onMounted, ref, defineAsyncComponent } from "vue";
 import FormDia from "@/views/personnelManagement/contractManagement/components/formDia.vue";
+const RenewContract = defineAsyncComponent(() => import("@/views/personnelManagement/employeeRecord/components/RenewContract.vue"));
 import { ElMessageBox } from "element-plus";
 import { staffOnJobListPage } from "@/api/personnelManagement/staffOnJob.js";
 import dayjs from "dayjs";
@@ -183,7 +190,7 @@
     label: "鎿嶄綔",
     align: "center",
     fixed: 'right',
-    width: 120,
+    width: 160,
     operation: [
       {
         name: "璇︽儏",
@@ -191,11 +198,22 @@
         clickFun: (row) => {
           openForm("edit", row);
         },
+      },
+      {
+        name: "缁鍚堝悓",
+        type: "text",
+        showHide: row => row.staffState === 1,
+        clickFun: (row) => {
+          isShowRenewContractModal.value = true;
+          id.value = row.id;
+        },
       }
     ],
   },
 ]);
 const filesDia = ref()
+const isShowRenewContractModal = ref(false);
+const id = ref(0);
 const tableData = ref([]);
 const selectedRows = ref([]);
 const tableLoading = ref(false);
diff --git a/src/views/personnelManagement/employeeRecord/index.vue b/src/views/personnelManagement/employeeRecord/index.vue
index cd4ecf5..5dda8c7 100644
--- a/src/views/personnelManagement/employeeRecord/index.vue
+++ b/src/views/personnelManagement/employeeRecord/index.vue
@@ -52,16 +52,14 @@
           :tableLoading="tableLoading"
           @pagination="pagination"
           :total="page.total"
-      ></PIMTable>
+      >
+        <template #positiveDate="{ row }">
+          <span :class="getPositiveDateClass(row.positiveDate)">{{ row.positiveDate }}</span>
+        </template>
+      </PIMTable>
     </div>
     <show-form-dia ref="formDia" @close="handleQuery"></show-form-dia>
     <new-or-edit-form-dia ref="formDiaNewOrEditFormDia" @close="handleQuery"></new-or-edit-form-dia>
-    <renew-contract
-        v-if="isShowRenewContractModal"
-        v-model:visible="isShowRenewContractModal"
-        :id="id"
-        @completed="handleQuery"
-    />
     
     <!-- 瀵煎叆瀵硅瘽妗� -->
     <el-dialog :title="upload.title" v-model="upload.open" width="400px" append-to-body>
@@ -107,7 +105,6 @@
 
 const NewOrEditFormDia = defineAsyncComponent(() => import("@/views/personnelManagement/employeeRecord/components/NewOrEditFormDia.vue"));
 const ShowFormDia = defineAsyncComponent(() => import( "@/views/personnelManagement/employeeRecord/components/Show.vue"));
-const RenewContract = defineAsyncComponent(() => import( "@/views/personnelManagement/employeeRecord/components/RenewContract.vue"));
 
 const data = reactive({
   searchForm: {
@@ -119,8 +116,6 @@
   deptOptions: [],
 });
 const { searchForm, deptOptions } = toRefs(data);
-const isShowRenewContractModal = ref(false);
-const id = ref(0);
 const tableColumn = ref([
   {
     label: "鐘舵��",
@@ -177,6 +172,13 @@
     width: 120,
   },
   {
+    label: "杞鏃ユ湡",
+    prop: "positiveDate",
+    width: 120,
+    dataType: "slot",
+    slot: "positiveDate",
+  },
+  {
     label: "骞撮緞",
     prop: "age",
   },
@@ -208,22 +210,6 @@
           openFormNewOrEditFormDia("edit", row);
         },
       },
-      {
-        name: "缁鍚堝悓",
-        type: "text",
-        showHide: row => row.staffState === 1,
-        clickFun: (row) => {
-          isShowRenewContractModal.value = true;
-          id.value = row.id;
-        },
-      },
-      // {
-      //   name: "璇︽儏",
-      //   type: "text",
-      //   clickFun: (row) => {
-      //     openForm("edit", row);
-      //   },
-      // },
     ],
   },
 ]);
@@ -253,6 +239,22 @@
   // 涓婁紶鐨勫湴鍧�
   url: import.meta.env.VITE_APP_BASE_API + "/staff/staffOnJob/import"
 })
+
+// 鍒ゆ柇杞鏃ユ湡鏄惁鍦�7澶╁唴
+const getPositiveDateClass = (positiveDate) => {
+  if (!positiveDate) return '';
+  const today = new Date();
+  today.setHours(0, 0, 0, 0);
+  const positive = new Date(positiveDate);
+  positive.setHours(0, 0, 0, 0);
+  const diffTime = positive - today;
+  const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
+  // 7澶╁唴杞锛堝寘鎷粖澶╋級鏄剧ず璀﹀憡鑹�
+  if (diffDays >= 0 && diffDays <= 7) {
+    return 'positive-date-warning';
+  }
+  return '';
+};
 
 const fetchDeptOptions = () => {
     deptTreeSelect().then(response => {
@@ -402,4 +404,9 @@
 .search_title2 {
   margin-left: 10px;
 }
+
+.positive-date-warning {
+  color: #f56c6c;
+  font-weight: bold;
+}
 </style>
diff --git a/src/views/productionManagement/productionProcess/index.vue b/src/views/productionManagement/productionProcess/index.vue
index 6d007a4..747b8de 100644
--- a/src/views/productionManagement/productionProcess/index.vue
+++ b/src/views/productionManagement/productionProcess/index.vue
@@ -243,6 +243,7 @@
             </el-form-item>
             <el-form-item label="鏍囧噯鍊�">
               <el-input v-model="selectedParam.standardValue"
+                        @input="val => onStandardValueInput(val, selectedParam)"
                         placeholder="璇疯緭鍏ラ粯璁ゅ��" />
             </el-form-item>
           </el-form>
@@ -273,6 +274,7 @@
         <el-form-item label="鏍囧噯鍊�"
                       prop="standardValue">
           <el-input v-model="editParamForm.standardValue"
+                    @input="val => onStandardValueInput(val, editParamForm)"
                     placeholder="璇疯緭鍏ユ爣鍑嗗��" />
         </el-form-item>
       </el-form>
@@ -392,7 +394,18 @@
     technologyParamId: null,
     paramName: "",
     standardValue: null,
+    paramType: null,
   });
+
+  const onStandardValueInput = (val, target) => {
+    const data = target.value || target;
+    const type = data.paramType;
+    if (type === 1) {
+      // 鏁板�兼牸寮忥細涓嶈兘杈撳叆涓枃鎴栬嫳鏂囧瓧绗�
+      data.standardValue = val.replace(/[a-zA-Z\u4e00-\u9fa5]/g, "");
+    }
+  };
+
   const editParamRules = {
     standardValue: [
       {
@@ -403,6 +416,12 @@
           if (value === null || value === undefined || value === "") {
             callback(new Error("璇疯緭鍏ユ爣鍑嗗��"));
           } else {
+            const type = editParamForm.paramType;
+            if (type === 1 && value) {
+              if (/[a-zA-Z\u4e00-\u9fa5]/.test(value)) {
+                return callback(new Error("鏁板�兼牸寮忎笉鑳藉寘鍚腑鑻辨枃瀛楃"));
+              }
+            }
             callback();
           }
         },
@@ -717,6 +736,7 @@
     editParamForm.technologyParamId = row.technologyParamId;
     editParamForm.paramName = row.paramName;
     editParamForm.standardValue = row.standardValue;
+    editParamForm.paramType = row.paramType;
     editParamDialogVisible.value = true;
   };
 
diff --git a/src/views/reportAnalysis/PSIDataAnalysis/components/center-bottom.vue b/src/views/reportAnalysis/PSIDataAnalysis/components/center-bottom.vue
index ccd7504..f4e49b6 100644
--- a/src/views/reportAnalysis/PSIDataAnalysis/components/center-bottom.vue
+++ b/src/views/reportAnalysis/PSIDataAnalysis/components/center-bottom.vue
@@ -23,7 +23,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted } from 'vue'
+import { ref, onMounted, inject, watch } from 'vue'
 import * as echarts from 'echarts'
 import Echarts from '@/components/Echarts/echarts.vue'
 import PanelHeader from './PanelHeader.vue'
@@ -151,6 +151,13 @@
   fetchData()
 }
 
+const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
+if (dataDashboardRefreshTick) {
+  watch(dataDashboardRefreshTick, () => {
+    fetchData()
+  })
+}
+
 onMounted(() => {
   fetchData()
 })
diff --git a/src/views/reportAnalysis/PSIDataAnalysis/components/center-center.vue b/src/views/reportAnalysis/PSIDataAnalysis/components/center-center.vue
index 0f3ec84..6e39eb1 100644
--- a/src/views/reportAnalysis/PSIDataAnalysis/components/center-center.vue
+++ b/src/views/reportAnalysis/PSIDataAnalysis/components/center-center.vue
@@ -27,7 +27,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted } from 'vue'
+import { ref, onMounted, inject, watch } from 'vue'
 import Echarts from '@/components/Echarts/echarts.vue'
 import { productTurnoverDays } from '@/api/viewIndex.js'
 
@@ -82,6 +82,13 @@
     })
 }
 
+const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
+if (dataDashboardRefreshTick) {
+  watch(dataDashboardRefreshTick, () => {
+    fetchData()
+  })
+}
+
 onMounted(() => {
   fetchData()
 })
diff --git a/src/views/reportAnalysis/PSIDataAnalysis/components/center-top.vue b/src/views/reportAnalysis/PSIDataAnalysis/components/center-top.vue
index 0937b32..055fb66 100644
--- a/src/views/reportAnalysis/PSIDataAnalysis/components/center-top.vue
+++ b/src/views/reportAnalysis/PSIDataAnalysis/components/center-top.vue
@@ -24,7 +24,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted } from 'vue'
+import { ref, onMounted, inject, watch } from 'vue'
 import { salesPurchaseStorageProductCount } from '@/api/viewIndex.js'
 
 const statItems = ref([])
@@ -52,6 +52,13 @@
     })
 }
 
+const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
+if (dataDashboardRefreshTick) {
+  watch(dataDashboardRefreshTick, () => {
+    fetchData()
+  })
+}
+
 onMounted(() => {
   fetchData()
 })
diff --git a/src/views/reportAnalysis/PSIDataAnalysis/components/left-bottom.vue b/src/views/reportAnalysis/PSIDataAnalysis/components/left-bottom.vue
index 669c826..65a72fe 100644
--- a/src/views/reportAnalysis/PSIDataAnalysis/components/left-bottom.vue
+++ b/src/views/reportAnalysis/PSIDataAnalysis/components/left-bottom.vue
@@ -22,7 +22,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted, onBeforeUnmount, computed } from 'vue'
+import { ref, onMounted, onBeforeUnmount, computed, inject, watch } from 'vue'
 import Echarts from '@/components/Echarts/echarts.vue'
 import PanelHeader from './PanelHeader.vue'
 import CarouselCards from './CarouselCards.vue'
@@ -205,6 +205,13 @@
     })
 }
 
+const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
+if (dataDashboardRefreshTick) {
+  watch(dataDashboardRefreshTick, () => {
+    fetchData()
+  })
+}
+
 onMounted(() => {
   fetchData()
   initBackground()
diff --git a/src/views/reportAnalysis/PSIDataAnalysis/components/left-top.vue b/src/views/reportAnalysis/PSIDataAnalysis/components/left-top.vue
index 8fcaa42..f5dac31 100644
--- a/src/views/reportAnalysis/PSIDataAnalysis/components/left-top.vue
+++ b/src/views/reportAnalysis/PSIDataAnalysis/components/left-top.vue
@@ -21,7 +21,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted, onBeforeUnmount, computed } from 'vue'
+import { ref, onMounted, onBeforeUnmount, computed, inject, watch } from 'vue'
 import { productSalesAnalysis } from '@/api/viewIndex.js'
 import PanelHeader from './PanelHeader.vue'
 import CarouselCards from './CarouselCards.vue'
@@ -175,6 +175,13 @@
     })
 }
 
+const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
+if (dataDashboardRefreshTick) {
+  watch(dataDashboardRefreshTick, () => {
+    fetchData()
+  })
+}
+
 onMounted(() => {
   fetchData()
   initBackground()
diff --git a/src/views/reportAnalysis/PSIDataAnalysis/index.vue b/src/views/reportAnalysis/PSIDataAnalysis/index.vue
index 065b59d..f81e482 100644
--- a/src/views/reportAnalysis/PSIDataAnalysis/index.vue
+++ b/src/views/reportAnalysis/PSIDataAnalysis/index.vue
@@ -43,7 +43,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue'
+import { ref, onMounted, onBeforeUnmount, nextTick, provide } from 'vue'
 import autofit from 'autofit.js'
 import LeftBottom from './components/left-bottom.vue'
 import CenterCenter from './components/center-center.vue'
@@ -65,6 +65,12 @@
 
 // 鐢ㄦ埛store
 const userStore = useUserStore()
+
+/** 涓� dataDashboard 鍏辩敤娉ㄥ叆鍚嶏紝瀛愮粍浠讹紙鍚鐢ㄧ殑 right-top/right-bottom锛夋瘡鍒嗛挓鍒锋柊 */
+const DASHBOARD_REFRESH_MS = 60 * 1000
+const dataDashboardRefreshTick = ref(0)
+provide('dataDashboardRefreshTick', dataDashboardRefreshTick)
+let dashboardPollTimer = null
 
 // 璁$畻缂╂斁姣斾緥
 const calculateScale = () => {
@@ -140,9 +146,17 @@
   window.addEventListener('fullscreenchange', handleFullscreenChange)
   window.addEventListener('webkitfullscreenchange', handleFullscreenChange)
   window.addEventListener('MSFullscreenChange', handleFullscreenChange)
+
+  dashboardPollTimer = setInterval(() => {
+    dataDashboardRefreshTick.value++
+  }, DASHBOARD_REFRESH_MS)
 })
 
 onBeforeUnmount(() => {
+  if (dashboardPollTimer) {
+    clearInterval(dashboardPollTimer)
+    dashboardPollTimer = null
+  }
   window.removeEventListener('resize', handleResize)
   window.removeEventListener('fullscreenchange', handleFullscreenChange)
   window.removeEventListener('webkitfullscreenchange', handleFullscreenChange)
diff --git a/src/views/reportAnalysis/dataDashboard/components/basic/center-bottom.vue b/src/views/reportAnalysis/dataDashboard/components/basic/center-bottom.vue
index a4824a2..c28c2fa 100644
--- a/src/views/reportAnalysis/dataDashboard/components/basic/center-bottom.vue
+++ b/src/views/reportAnalysis/dataDashboard/components/basic/center-bottom.vue
@@ -20,7 +20,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted, computed } from 'vue'
+import { ref, onMounted, computed, inject, watch } from 'vue'
 import { deptStaffDistribution } from '@/api/viewIndex.js'
 import PanelHeader from '../PanelHeader.vue'
 import Echarts from '@/components/Echarts/echarts.vue'
@@ -148,6 +148,13 @@
   })
 }
 
+const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
+if (dataDashboardRefreshTick) {
+  watch(dataDashboardRefreshTick, () => {
+    getDeptStaffDistribution()
+  })
+}
+
 onMounted(() => {
   getDeptStaffDistribution()
 })
diff --git a/src/views/reportAnalysis/dataDashboard/components/basic/center-top.vue b/src/views/reportAnalysis/dataDashboard/components/basic/center-top.vue
index 950038e..a7d0174 100644
--- a/src/views/reportAnalysis/dataDashboard/components/basic/center-top.vue
+++ b/src/views/reportAnalysis/dataDashboard/components/basic/center-top.vue
@@ -110,7 +110,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue'
+import { ref, onMounted, onBeforeUnmount, nextTick, inject, watch } from 'vue'
 import { homeTodos, summaryStatistics } from '@/api/viewIndex.js'
 import { getLedgerPage } from '@/api/equipmentManagement/ledger.js'
 import { getRepairPage } from '@/api/equipmentManagement/repair.js'
@@ -175,8 +175,23 @@
   })
 }
 
+const destroyTodoListScroll = () => {
+  const todoListEl = refTodoList.value
+  if (todoListEl) {
+    if (todoListEl._animationFrame) {
+      cancelAnimationFrame(todoListEl._animationFrame)
+      todoListEl._animationFrame = null
+    }
+    if (todoListEl._pauseTimer) {
+      clearInterval(todoListEl._pauseTimer)
+      todoListEl._pauseTimer = null
+    }
+  }
+}
+
 // 鍒濆鍖栧緟鍔炰簨椤瑰垪琛ㄦ粴鍔ㄥ姛鑳�
 const initTodoListScroll = () => {
+  destroyTodoListScroll()
   const todoListEl = refTodoList.value
   // 寮哄埗鍚敤婊氬姩锛屼笉妫�鏌ヤ换浣曟潯浠�
   if (todoListEl) {
@@ -259,6 +274,7 @@
 
 // 寰呭姙浜嬮」
 const todoInfoS = () => {
+  destroyTodoListScroll()
   homeTodos().then((res) => {
     todoList.value = res.data
     // 鍦ㄨ幏鍙栧埌寰呭姙浜嬮」鏁版嵁鍚庯紝鍒濆鍖栨粴鍔ㄥ姛鑳�
@@ -268,25 +284,25 @@
   })
 }
 
-onMounted(() => {
+const refreshCenterTopData = () => {
   getNum()
   getLedgerNum()
   todoInfoS()
+}
+
+const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
+if (dataDashboardRefreshTick) {
+  watch(dataDashboardRefreshTick, () => {
+    refreshCenterTopData()
+  })
+}
+
+onMounted(() => {
+  refreshCenterTopData()
 })
 
 onBeforeUnmount(() => {
-  // 娓呯悊寰呭姙浜嬮」鍒楄〃鐨勫姩鐢诲拰瀹氭椂鍣�
-  const todoListEl = refTodoList.value
-  if (todoListEl) {
-    if (todoListEl._animationFrame) {
-      cancelAnimationFrame(todoListEl._animationFrame)
-      todoListEl._animationFrame = null
-    }
-    if (todoListEl._pauseTimer) {
-      clearInterval(todoListEl._pauseTimer)
-      todoListEl._pauseTimer = null
-    }
-  }
+  destroyTodoListScroll()
 })
 </script>
 
diff --git a/src/views/reportAnalysis/dataDashboard/components/basic/left-bottom.vue b/src/views/reportAnalysis/dataDashboard/components/basic/left-bottom.vue
index 58c83d8..bab6024 100644
--- a/src/views/reportAnalysis/dataDashboard/components/basic/left-bottom.vue
+++ b/src/views/reportAnalysis/dataDashboard/components/basic/left-bottom.vue
@@ -40,7 +40,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted } from 'vue'
+import { ref, onMounted, inject, watch } from 'vue'
 import Echarts from '@/components/Echarts/echarts.vue'
 import PanelHeader from '../PanelHeader.vue'
 import DateTypeSwitch from '../DateTypeSwitch.vue'
@@ -192,6 +192,13 @@
   getCustomerRevenueAnalysis()
 }
 
+const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
+if (dataDashboardRefreshTick) {
+  watch(dataDashboardRefreshTick, () => {
+    getCustomerRevenueAnalysis()
+  })
+}
+
 onMounted(() => {
   fetchCustomerOptions()
 })
diff --git a/src/views/reportAnalysis/dataDashboard/components/basic/left-top.vue b/src/views/reportAnalysis/dataDashboard/components/basic/left-top.vue
index 5b7e29e..16791de 100644
--- a/src/views/reportAnalysis/dataDashboard/components/basic/left-top.vue
+++ b/src/views/reportAnalysis/dataDashboard/components/basic/left-top.vue
@@ -21,7 +21,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted, onBeforeUnmount } from 'vue'
+import { ref, onMounted, onBeforeUnmount, inject, watch } from 'vue'
 import Echarts from '@/components/Echarts/echarts.vue'
 import PanelHeader from '../PanelHeader.vue'
 import { productCategoryDistribution } from '@/api/viewIndex.js'
@@ -207,6 +207,13 @@
 }
 
 
+const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
+if (dataDashboardRefreshTick) {
+  watch(dataDashboardRefreshTick, () => {
+    loadData()
+  })
+}
+
 onMounted(() => {
   loadData()
   initBackground()
diff --git a/src/views/reportAnalysis/dataDashboard/components/basic/right-bottom.vue b/src/views/reportAnalysis/dataDashboard/components/basic/right-bottom.vue
index bbcd5f0..6fcd80f 100644
--- a/src/views/reportAnalysis/dataDashboard/components/basic/right-bottom.vue
+++ b/src/views/reportAnalysis/dataDashboard/components/basic/right-bottom.vue
@@ -22,7 +22,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted, computed } from 'vue'
+import { ref, onMounted, computed, inject, watch } from 'vue'
 import Echarts from '@/components/Echarts/echarts.vue'
 import PanelHeader from '../PanelHeader.vue'
 import DateTypeSwitch from '../DateTypeSwitch.vue'
@@ -308,6 +308,13 @@
   fetchCustomerRanking()
 }
 
+const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
+if (dataDashboardRefreshTick) {
+  watch(dataDashboardRefreshTick, () => {
+    fetchCustomerRanking()
+  })
+}
+
 onMounted(() => {
   fetchCustomerRanking()
 })
diff --git a/src/views/reportAnalysis/dataDashboard/components/basic/right-top.vue b/src/views/reportAnalysis/dataDashboard/components/basic/right-top.vue
index 21696fa..96e4548 100644
--- a/src/views/reportAnalysis/dataDashboard/components/basic/right-top.vue
+++ b/src/views/reportAnalysis/dataDashboard/components/basic/right-top.vue
@@ -21,7 +21,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted, computed } from 'vue'
+import { ref, onMounted, computed, inject, watch } from 'vue'
 import Echarts from '@/components/Echarts/echarts.vue'
 import PanelHeader from '../PanelHeader.vue'
 import DateTypeSwitch from '../DateTypeSwitch.vue'
@@ -331,6 +331,13 @@
   fetchSupplierRanking()
 }
 
+const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
+if (dataDashboardRefreshTick) {
+  watch(dataDashboardRefreshTick, () => {
+    fetchSupplierRanking()
+  })
+}
+
 onMounted(() => {
   fetchSupplierRanking()
 })
diff --git a/src/views/reportAnalysis/dataDashboard/index.vue b/src/views/reportAnalysis/dataDashboard/index.vue
index 67a700f..ff53a7b 100644
--- a/src/views/reportAnalysis/dataDashboard/index.vue
+++ b/src/views/reportAnalysis/dataDashboard/index.vue
@@ -44,7 +44,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue'
+import { ref, onMounted, onBeforeUnmount, nextTick, provide } from 'vue'
 import autofit from 'autofit.js'
 import LeftTop from './components/basic/left-top.vue'
 import LeftBottom from './components/basic/left-bottom.vue'
@@ -65,6 +65,12 @@
 
 // 鐢ㄦ埛store
 const userStore = useUserStore()
+
+// 澶у睆鎺ュ彛杞闂撮殧
+const DASHBOARD_REFRESH_MS = 60 * 1000
+const dataDashboardRefreshTick = ref(0)
+provide('dataDashboardRefreshTick', dataDashboardRefreshTick)
+let dashboardPollTimer = null
 
 // 璁$畻缂╂斁姣斾緥
 const calculateScale = () => {
@@ -140,9 +146,17 @@
   window.addEventListener('fullscreenchange', handleFullscreenChange)
   window.addEventListener('webkitfullscreenchange', handleFullscreenChange)
   window.addEventListener('MSFullscreenChange', handleFullscreenChange)
+
+  dashboardPollTimer = setInterval(() => {
+    dataDashboardRefreshTick.value++
+  }, DASHBOARD_REFRESH_MS)
 })
 
 onBeforeUnmount(() => {
+  if (dashboardPollTimer) {
+    clearInterval(dashboardPollTimer)
+    dashboardPollTimer = null
+  }
   window.removeEventListener('resize', handleResize)
   window.removeEventListener('fullscreenchange', handleFullscreenChange)
   window.removeEventListener('webkitfullscreenchange', handleFullscreenChange)
diff --git a/src/views/reportAnalysis/productionAnalysis/components/center-bottom.vue b/src/views/reportAnalysis/productionAnalysis/components/center-bottom.vue
index 46a870a..f4f4024 100644
--- a/src/views/reportAnalysis/productionAnalysis/components/center-bottom.vue
+++ b/src/views/reportAnalysis/productionAnalysis/components/center-bottom.vue
@@ -51,7 +51,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue'
+import { ref, onMounted, onBeforeUnmount, nextTick, inject, watch } from 'vue'
 import { getProgressStatistics } from '@/api/viewIndex.js'
 import PanelHeader from './PanelHeader.vue'
 import CarouselCards from './CarouselCards.vue'
@@ -132,17 +132,22 @@
   }, 150)
 }
 
-const initProgressTableScroll = () => {
-  const tableContainer = progressTableRef.value
-  if (!tableContainer) return
+const stopProgressTableScroll = () => {
   if (progressTableScrollTimer.value) {
     cancelAnimationFrame(progressTableScrollTimer.value)
     progressTableScrollTimer.value = null
   }
-  if (tableContainer._pauseTimer) {
+  const tableContainer = progressTableRef.value
+  if (tableContainer?._pauseTimer) {
     clearInterval(tableContainer._pauseTimer)
     tableContainer._pauseTimer = null
   }
+}
+
+const initProgressTableScroll = () => {
+  const tableContainer = progressTableRef.value
+  if (!tableContainer) return
+  stopProgressTableScroll()
   const tbody = tableContainer.querySelector('tbody')
   if (!tbody) return
   const originalCount = progressTableData.value.length
@@ -198,6 +203,7 @@
 const progressStatisticsInfo = () => {
   getProgressStatistics()
     .then((res) => {
+      stopProgressTableScroll()
       if (!res || !res.data) return
       const obj = {
         totalOrderCount: res.data.totalOrderCount || 0,
@@ -224,14 +230,19 @@
     })
 }
 
+const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
+if (dataDashboardRefreshTick) {
+  watch(dataDashboardRefreshTick, () => {
+    progressStatisticsInfo()
+  })
+}
+
 onMounted(() => {
   progressStatisticsInfo()
 })
 
 onBeforeUnmount(() => {
-  if (progressTableScrollTimer.value) {
-    cancelAnimationFrame(progressTableScrollTimer.value)
-  }
+  stopProgressTableScroll()
   if (tableScrollTimeout.value) clearTimeout(tableScrollTimeout.value)
   const tableContainer = progressTableRef.value
   if (tableContainer?._pauseTimer) {
diff --git a/src/views/reportAnalysis/productionAnalysis/components/center-center.vue b/src/views/reportAnalysis/productionAnalysis/components/center-center.vue
index 96bcada..a65f4f8 100644
--- a/src/views/reportAnalysis/productionAnalysis/components/center-center.vue
+++ b/src/views/reportAnalysis/productionAnalysis/components/center-center.vue
@@ -27,7 +27,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted } from 'vue'
+import { ref, onMounted, inject, watch } from 'vue'
 import * as echarts from 'echarts'
 import Echarts from '@/components/Echarts/echarts.vue'
 import { inputOutputAnalysis } from '@/api/viewIndex.js'
@@ -146,6 +146,13 @@
     })
 }
 
+const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
+if (dataDashboardRefreshTick) {
+  watch(dataDashboardRefreshTick, () => {
+    fetchData()
+  })
+}
+
 onMounted(() => {
   fetchData()
 })
diff --git a/src/views/reportAnalysis/productionAnalysis/components/center-top.vue b/src/views/reportAnalysis/productionAnalysis/components/center-top.vue
index 7201828..a806150 100644
--- a/src/views/reportAnalysis/productionAnalysis/components/center-top.vue
+++ b/src/views/reportAnalysis/productionAnalysis/components/center-top.vue
@@ -24,7 +24,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted } from 'vue'
+import { ref, onMounted, inject, watch } from 'vue'
 import { orderCount } from '@/api/viewIndex.js'
 
 const statItems = ref([])
@@ -52,6 +52,13 @@
     })
 }
 
+const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
+if (dataDashboardRefreshTick) {
+  watch(dataDashboardRefreshTick, () => {
+    fetchData()
+  })
+}
+
 onMounted(() => {
   fetchData()
 })
diff --git a/src/views/reportAnalysis/productionAnalysis/components/left-bottom.vue b/src/views/reportAnalysis/productionAnalysis/components/left-bottom.vue
index 9f6a8c1..b7c7358 100644
--- a/src/views/reportAnalysis/productionAnalysis/components/left-bottom.vue
+++ b/src/views/reportAnalysis/productionAnalysis/components/left-bottom.vue
@@ -22,7 +22,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted } from 'vue'
+import { ref, onMounted, inject, watch } from 'vue'
 import Echarts from '@/components/Echarts/echarts.vue'
 import PanelHeader from './PanelHeader.vue'
 import CarouselCards from './CarouselCards.vue'
@@ -143,6 +143,13 @@
     })
 }
 
+const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
+if (dataDashboardRefreshTick) {
+  watch(dataDashboardRefreshTick, () => {
+    workInProcessTurnoverInfo()
+  })
+}
+
 onMounted(() => {
   workInProcessTurnoverInfo()
 })
diff --git a/src/views/reportAnalysis/productionAnalysis/components/left-top.vue b/src/views/reportAnalysis/productionAnalysis/components/left-top.vue
index fd52b1b..37c82f0 100644
--- a/src/views/reportAnalysis/productionAnalysis/components/left-top.vue
+++ b/src/views/reportAnalysis/productionAnalysis/components/left-top.vue
@@ -23,7 +23,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted, onBeforeUnmount, computed } from 'vue'
+import { ref, onMounted, onBeforeUnmount, computed, inject, watch } from 'vue'
 import { processOutputAnalysis } from '@/api/viewIndex.js'
 import PanelHeader from './PanelHeader.vue'
 import Echarts from '@/components/Echarts/echarts.vue'
@@ -170,6 +170,13 @@
   fetchData()
 }
 
+const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
+if (dataDashboardRefreshTick) {
+  watch(dataDashboardRefreshTick, () => {
+    fetchData()
+  })
+}
+
 onMounted(() => {
   fetchData()
   initBackground()
diff --git a/src/views/reportAnalysis/productionAnalysis/components/right-bottom.vue b/src/views/reportAnalysis/productionAnalysis/components/right-bottom.vue
index 28de03b..62356e7 100644
--- a/src/views/reportAnalysis/productionAnalysis/components/right-bottom.vue
+++ b/src/views/reportAnalysis/productionAnalysis/components/right-bottom.vue
@@ -22,7 +22,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted } from 'vue'
+import { ref, onMounted, inject, watch } from 'vue'
 import { productionAccountingAnalysis } from '@/api/viewIndex.js'
 import PanelHeader from './PanelHeader.vue'
 import DateTypeSwitch from './DateTypeSwitch.vue'
@@ -157,6 +157,13 @@
     })
 }
 
+const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
+if (dataDashboardRefreshTick) {
+  watch(dataDashboardRefreshTick, () => {
+    fetchData()
+  })
+}
+
 onMounted(() => {
   fetchData()
 })
diff --git a/src/views/reportAnalysis/productionAnalysis/components/right-top.vue b/src/views/reportAnalysis/productionAnalysis/components/right-top.vue
index d3a9eb9..5ec836f 100644
--- a/src/views/reportAnalysis/productionAnalysis/components/right-top.vue
+++ b/src/views/reportAnalysis/productionAnalysis/components/right-top.vue
@@ -22,7 +22,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted } from 'vue'
+import { ref, onMounted, inject, watch } from 'vue'
 import { workOrderEfficiencyAnalysis } from '@/api/viewIndex.js'
 import PanelHeader from './PanelHeader.vue'
 import Echarts from '@/components/Echarts/echarts.vue'
@@ -152,6 +152,13 @@
     })
 }
 
+const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
+if (dataDashboardRefreshTick) {
+  watch(dataDashboardRefreshTick, () => {
+    fetchData()
+  })
+}
+
 onMounted(() => {
   fetchData()
 })
diff --git a/src/views/reportAnalysis/productionAnalysis/index.vue b/src/views/reportAnalysis/productionAnalysis/index.vue
index e179150..7e03bbd 100644
--- a/src/views/reportAnalysis/productionAnalysis/index.vue
+++ b/src/views/reportAnalysis/productionAnalysis/index.vue
@@ -44,7 +44,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue'
+import { ref, onMounted, onBeforeUnmount, nextTick, provide } from 'vue'
 import autofit from 'autofit.js'
 import LeftBottom from './components/left-bottom.vue'
 import CenterCenter from './components/center-center.vue'
@@ -66,6 +66,12 @@
 
 // 鐢ㄦ埛store
 const userStore = useUserStore()
+
+/** 涓庡叾瀹冮┚椹惰埍鍏辩敤娉ㄥ叆鍚嶏紝瀛愮粍浠舵瘡鍒嗛挓鍒锋柊鎺ュ彛鏁版嵁 */
+const DASHBOARD_REFRESH_MS = 60 * 1000
+const dataDashboardRefreshTick = ref(0)
+provide('dataDashboardRefreshTick', dataDashboardRefreshTick)
+let dashboardPollTimer = null
 
 // 璁$畻缂╂斁姣斾緥
 const calculateScale = () => {
@@ -141,9 +147,17 @@
   window.addEventListener('fullscreenchange', handleFullscreenChange)
   window.addEventListener('webkitfullscreenchange', handleFullscreenChange)
   window.addEventListener('MSFullscreenChange', handleFullscreenChange)
+
+  dashboardPollTimer = setInterval(() => {
+    dataDashboardRefreshTick.value++
+  }, DASHBOARD_REFRESH_MS)
 })
 
 onBeforeUnmount(() => {
+  if (dashboardPollTimer) {
+    clearInterval(dashboardPollTimer)
+    dashboardPollTimer = null
+  }
   window.removeEventListener('resize', handleResize)
   window.removeEventListener('fullscreenchange', handleFullscreenChange)
   window.removeEventListener('webkitfullscreenchange', handleFullscreenChange)

--
Gitblit v1.9.3