From c6e96cdb8b1cfb51e9a45bf86c38d1353e983127 Mon Sep 17 00:00:00 2001
From: 吴羡 <16976746+Xian-TT3@user.noreply.gitee.com>
Date: 星期一, 19 十月 2026 15:19:48 +0800
Subject: [PATCH] 设备模块业务完善及前序页面优化

---
 src/views/CNAS/resourceDemand/device/component/equipmentVerificationPlan.vue |  690 +++++++++++++++++++++++++++------------------------------
 1 files changed, 329 insertions(+), 361 deletions(-)

diff --git a/src/views/CNAS/resourceDemand/device/component/equipmentVerificationPlan.vue b/src/views/CNAS/resourceDemand/device/component/equipmentVerificationPlan.vue
index acb3591..028e5e2 100644
--- a/src/views/CNAS/resourceDemand/device/component/equipmentVerificationPlan.vue
+++ b/src/views/CNAS/resourceDemand/device/component/equipmentVerificationPlan.vue
@@ -1,137 +1,101 @@
 <template>
   <!--  璁惧鏍告煡璁″垝-->
   <div>
-    <div>
-      <div style="margin: 10px 0;display: flex;align-items: center;justify-content: space-between;">
-        <div class="title">
-          <span style="font-weight: bold">骞村害璁″垝琛�</span>
+    <div style="margin: 10px 0 14px;">
+      <div class="plan-top">
+        <div class="plan-top-left">
+          <span class="title" style="margin-bottom: 0;">{{ planInfo.planName || (planYear + '骞村害璁惧鏍告煡璁″垝') }}</span>
+          <el-select v-model="planYear" size="small" style="width: 110px; margin-left: 16px;" @change="handleYearChange">
+            <el-option v-for="y in yearOptions" :key="y" :label="y" :value="y"></el-option>
+          </el-select>
         </div>
-        <div style="display: flex;align-items: center;">
-          <el-button size="small" type="primary" @click="getYearTableData">鍒锋柊</el-button>
-          <el-button size="small" type="primary" @click="addYearPlan('add')">鏂板</el-button>
-          <!--          <el-upload ref="upload" :action="action"-->
-          <!--                     :before-upload="beforeUpload" :headers="uploadHeader" :on-error="onError"-->
-          <!--                     :on-success="handleSuccessUp" :show-file-list="false" accept='.xls,.xlsx'>-->
-          <!--            <el-button :loading="upLoading" size="small" type="primary">瀵煎叆</el-button>-->
-          <!--          </el-upload>-->
+        <div>
+          <el-button size="small" type="primary" @click="loadPlan">鍒锋柊</el-button>
+          <el-button size="small" type="primary" :disabled="planInfo.ratifyStatus === 1"
+            @click="tellApprove">鎵瑰噯閫氱煡</el-button>
+          <el-button size="small" type="primary"
+            :disabled="planInfo.ratifyStatus === 1 || userId != planInfo.ratifyUserId" @click="handleApprove">鎵瑰噯</el-button>
+          <el-button size="small" type="primary" @click="downLoadPost">瀵煎嚭</el-button>
         </div>
       </div>
+      <div class="plan-info-bar">
+        <span>缂栧埗浜猴細{{ planInfo.writeName || '鈥�' }}</span>
+        <span>缂栧埗鏃ユ湡锛歿{ planInfo.writeTimeStr || '鈥�' }}</span>
+        <span v-if="planInfo.ratifyStatus === 1">鎵瑰噯鐘舵�侊細<el-tag type="success">鎵瑰噯</el-tag></span>
+        <span v-else-if="planInfo.ratifyStatus === 0">鎵瑰噯鐘舵�侊細<el-tag type="danger">涓嶆壒鍑�</el-tag></span>
+        <span v-if="planInfo.ratifyRemark">鎵瑰噯鍐呭锛歿{ planInfo.ratifyRemark }}</span>
+        <span v-if="isRatified && planInfo.ratifyName">鎵瑰噯浜猴細{{ planInfo.ratifyName }}</span>
+        <span v-if="isRatified && planInfo.ratifyTimeStr">鎵瑰噯鏃堕棿锛歿{ planInfo.ratifyTimeStr }}</span>
+      </div>
+    </div>
+    <div class="search">
       <div>
-        <el-table ref="yearTable" v-loading="yearTableDataLoading" :data="yearTableData"
-                  height="calc(60vh - 16em)"
- border
-                  highlight-current-row @current-change="currentChange">
-          <!-- 琛ㄦ牸鍒� -->
-          <el-table-column align="center" header-align="center" label="搴忓彿" prop="prop" type="index"
-            width="70"></el-table-column>
-          <el-table-column label="骞翠唤" min-width="80" prop="planYear"></el-table-column>
-          <el-table-column label="璁″垝鍚嶇О" min-width="180" prop="planName" show-overflow-tooltip></el-table-column>
-          <el-table-column label="缂栧埗浜�" min-width="100" prop="writeName"></el-table-column>
-          <el-table-column label="缂栧埗鏃ユ湡" min-width="160" prop="writeTime"></el-table-column>
-          <el-table-column label="鎵瑰噯鐘舵��" min-width="100" prop="ratifyStatus">
-            <template #default="scope">
-              <el-tag v-if="scope.row.ratifyStatus === 1" type="success">鎵瑰噯</el-tag>
-              <el-tag v-if="scope.row.ratifyStatus === 0" type="danger">涓嶆壒鍑�</el-tag>
-            </template>
-          </el-table-column>
-          <el-table-column label="鎵瑰噯鍐呭" min-width="150" prop="ratifyRemark"></el-table-column>
-          <el-table-column label="鎵瑰噯浜�" min-width="100" prop="ratifyName"></el-table-column>
-          <el-table-column label="鎵瑰噯鏃堕棿" min-width="150" prop="ratifyTime"></el-table-column>
-          <!-- 鎿嶄綔鎸夐挳 -->
-          <el-table-column align="center" fixed="right" label="鎿嶄綔" min-width="240">
-            <template #default="scope">
-              <el-button :disabled="scope.row.ratifyStatus === 1" size="small" link type="primary"
-                @click="addYearPlan('edit', scope.row)">缂栬緫</el-button>
-              <el-button :disabled="scope.row.ratifyStatus === 1" size="small" link type="primary"
-                @click="tellApprove(scope.row.planId)">鎵瑰噯閫氱煡</el-button>
-              <el-button :disabled="scope.row.ratifyStatus === 1 || userId != scope.row.ratifyUserId" size="small"
-                link type="primary" @click="handleApprove(scope.row.planId)">鎵瑰噯</el-button>
-              <el-button size="small" link type="primary" @click="downLoadPost(scope.row.planId)">瀵煎嚭</el-button>
-              <el-button :disabled="scope.row.ratifyStatus === 1" size="small" link type="danger"
-                @click="deleteFun(scope.row.planId)">鍒犻櫎</el-button>
-            </template>
-          </el-table-column>
-        </el-table>
-        <el-pagination :current-page="1" :page-size="pagination.size" :page-sizes="[10, 20, 30, 50, 100]"
-                       background :total="pagination.total" layout="->,total, sizes, prev, pager, next, jumper"
-                       @size-change="handleSizeChange" @current-change="handleCurrentChange">
-        </el-pagination>
+        <el-form :model="searchForm" ref="searchForm" size="small" :inline="true">
+          <el-form-item label="璁惧缂栧彿" prop="deviceNumber">
+            <el-input v-model="searchForm.deviceNumber" clearable size="small"
+              @keyup.enter="handleQuery"></el-input>
+          </el-form-item>
+          <el-form-item label="璁惧鍚嶇О" prop="deviceName">
+            <el-input v-model="searchForm.deviceName" clearable size="small"
+              @keyup.enter="handleQuery"></el-input>
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" size="small" @click="handleQuery">鏌ヨ</el-button>
+            <el-button size="small" @click="reset">閲嶇疆</el-button>
+          </el-form-item>
+        </el-form>
       </div>
     </div>
     <div>
-      <div class="title">
-        <span style="font-weight: bold">骞村害璁″垝鏄庣粏琛�</span>
-      </div>
-      <div class="search">
-        <div>
-          <el-form :model="searchForm" ref="searchForm" size="small" :inline="true">
-            <el-form-item label="璁惧缂栧彿" prop="deviceNumber">
-              <el-input v-model="searchForm.deviceNumber" clearable size="small"
-                        @keyup.enter="getYearTableDetailData(currentRow)"></el-input>
-            </el-form-item>
-            <el-form-item label="璁惧鍚嶇О" prop="deviceName">
-              <el-input v-model="searchForm.deviceName" clearable size="small"
-                        @keyup.enter="getYearTableDetailData(currentRow)"></el-input>
-            </el-form-item>
-            <el-form-item>
-              <el-button type="primary" size="small" @click="getYearTableDetailData(currentRow)">鏌ヨ</el-button>
-              <el-button size="small" @click="reset">閲嶇疆</el-button>
-            </el-form-item>
-          </el-form>
-        </div>
-        <div>
-          <el-button size="small" type="primary" @click="handleForm('add')">鏂板</el-button>
-        </div>
-      </div>
-      <div>
-        <el-table ref="yearTableDetailData" v-loading="yearTableDetailDataLoading" :data="yearTableDetailData"
- border
-                  :height="'calc(100vh - 34em)'" style="width: 100% ;">
-          <!-- 琛ㄦ牸鍒� -->
-          <el-table-column align="center" header-align="center" label="搴忓彿" prop="prop" type="index"
-            width="70"></el-table-column>
-          <el-table-column label="璁惧缂栧彿" min-width="180" prop="deviceNumber"></el-table-column>
-          <el-table-column label="璁惧鍚嶇О" min-width="180" prop="deviceName" show-overflow-tooltip></el-table-column>
-          <el-table-column label="鏍告煡鏃堕棿" min-width="150" prop="checkTime"></el-table-column>
-          <el-table-column label="鏍告煡鎸囨爣" min-width="150" prop="checkIndex"> </el-table-column>
-          <el-table-column label="鏍告煡鏂规硶" min-width="150" prop="checkMethod"></el-table-column>
-          <el-table-column label="缁撴灉濡備綍鍒ゅ畾" min-width="150" prop="howResults"></el-table-column>
-          <el-table-column label="鏍告煡璐熻矗浜�" min-width="150" prop="checkChargerUser"></el-table-column>
-          <el-table-column label="璁板綍鐘舵��" min-width="100" prop="recordStatus">
-            <template #default="scope">
-              <el-tag type="" v-if="scope.row.recordStatus === 0" disable-transitions>鏈紑濮�</el-tag>
-              <el-tag type="warning" v-if="scope.row.recordStatus === 1" disable-transitions>寰呮壒鍑�</el-tag>
-              <el-tag type="success" v-if="scope.row.recordStatus === 2" disable-transitions>閫氳繃</el-tag>
-              <el-tag type="danger" v-if="scope.row.recordStatus === 3" disable-transitions>涓嶉�氳繃</el-tag>
-            </template>
-          </el-table-column>
-          <el-table-column label="瀵规瘮鐘舵��" min-width="100" prop="recordContrastStatus">
-            <template #default="scope">
-              <el-tag type="" v-if="scope.row.recordContrastStatus === 0" disable-transitions>鏈紑濮�</el-tag>
-              <el-tag type="warning" v-if="scope.row.recordContrastStatus === 1" disable-transitions>寰呮壒鍑�</el-tag>
-              <el-tag type="success" v-if="scope.row.recordContrastStatus === 2" disable-transitions>閫氳繃</el-tag>
-              <el-tag type="danger" v-if="scope.row.recordContrastStatus === 3" disable-transitions>涓嶉�氳繃</el-tag>
-            </template>
-          </el-table-column>
-          <el-table-column label="澶囨敞" min-width="150" prop="remark"></el-table-column>
-          <!-- 鎿嶄綔鎸夐挳 -->
-          <el-table-column align="center" fixed="right" label="鎿嶄綔" min-width="260">
-            <template #default="scope">
-              <el-button size="small" link type="primary" @click="handleForm('edit', scope.row)">缂栬緫</el-button>
-              <el-button size="small" link type="primary" @click="handleForm('view', scope.row)">鏌ョ湅</el-button>
-              <el-button size="small" link type="primary" @click="handleRecord(scope.row)">璁板綍</el-button>
-              <el-button size="small" link type="primary" @click="handleCheck(scope.row)">瀵规瘮</el-button>
-              <el-button size="small" link type="primary" @click="handleDown(scope.row)">瀵煎嚭</el-button>
-              <el-button size="small" link type="danger"
-                @click="deleteFun1(scope.row.planDetailsId)">鍒犻櫎</el-button>
-            </template>
-          </el-table-column>
-        </el-table>
-        <el-pagination :current-page="1" :page-size="pagination1.size" :page-sizes="[10, 20, 30, 50, 100]"
-          :total="pagination1.total" layout="->,total, sizes, prev, pager, next, jumper" background
-          @size-change="handleSizeChange1" @current-change="handleCurrentChange1">
-        </el-pagination>
-      </div>
+      <el-table ref="yearTableDetailData" v-loading="yearTableDetailDataLoading" :data="yearTableDetailData" border
+        :row-class-name="tableRowClassName" :height="'calc(100vh - 29em)'" style="width: 100%;">
+        <!-- 琛ㄦ牸鍒� -->
+        <el-table-column align="center" header-align="center" label="搴忓彿" prop="prop" type="index"
+          width="70"></el-table-column>
+        <el-table-column label="璁惧缂栧彿" min-width="170" prop="deviceNumber"></el-table-column>
+        <el-table-column label="璁惧鍚嶇О" min-width="180" prop="deviceName" show-overflow-tooltip></el-table-column>
+        <el-table-column label="鏍告煡鏃堕棿" min-width="120" prop="checkTime"
+          :formatter="formatCheckMonth"></el-table-column>
+        <el-table-column label="鏍告煡鎸囨爣" min-width="140" prop="checkIndex"> </el-table-column>
+        <el-table-column label="鏍告煡鏂规硶" min-width="140" prop="checkMethod" show-overflow-tooltip></el-table-column>
+        <el-table-column label="缁撴灉濡備綍鍒ゅ畾" min-width="140" prop="howResults" show-overflow-tooltip></el-table-column>
+        <el-table-column label="鏍告煡璐熻矗浜�" min-width="120" prop="checkChargerUser"></el-table-column>
+        <el-table-column label="璁板綍鐘舵��" min-width="100" prop="recordStatus">
+          <template #default="scope">
+            <el-tag type="" v-if="scope.row.recordStatus === 0" disable-transitions>鏈紑濮�</el-tag>
+            <el-tag type="warning" v-if="scope.row.recordStatus === 1" disable-transitions>寰呮壒鍑�</el-tag>
+            <el-tag type="success" v-if="scope.row.recordStatus === 2" disable-transitions>閫氳繃</el-tag>
+            <el-tag type="danger" v-if="scope.row.recordStatus === 3" disable-transitions>涓嶉�氳繃</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="瀵规瘮鐘舵��" min-width="100" prop="recordContrastStatus">
+          <template #default="scope">
+            <el-tag type="" v-if="scope.row.recordContrastStatus === 0" disable-transitions>鏈紑濮�</el-tag>
+            <el-tag type="warning" v-if="scope.row.recordContrastStatus === 1" disable-transitions>寰呮壒鍑�</el-tag>
+            <el-tag type="success" v-if="scope.row.recordContrastStatus === 2" disable-transitions>閫氳繃</el-tag>
+            <el-tag type="danger" v-if="scope.row.recordContrastStatus === 3" disable-transitions>涓嶉�氳繃</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="澶囨敞" min-width="130" prop="remark"></el-table-column>
+        <!-- 鎿嶄綔鎸夐挳 -->
+        <el-table-column align="center" fixed="right" label="鎿嶄綔" min-width="260">
+          <template #default="scope">
+            <el-button size="small" link type="primary" :disabled="planInfo.ratifyStatus === 1"
+              @click="handleForm('edit', scope.row)">缂栬緫</el-button>
+            <el-button size="small" link type="primary" @click="handleForm('view', scope.row)">鏌ョ湅</el-button>
+            <el-button size="small" link type="primary" @click="handleRecord(scope.row)">璁板綍</el-button>
+            <el-button size="small" link type="primary" @click="handleCheck(scope.row)">瀵规瘮</el-button>
+            <el-button size="small" link type="primary" @click="handleDown(scope.row)">瀵煎嚭</el-button>
+            <el-button size="small" link type="danger" :disabled="planInfo.ratifyStatus === 1"
+              @click="deleteFun1(scope.row.planDetailsId)">鍒犻櫎</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <el-pagination :current-page="pagination1.current" :page-size="pagination1.size"
+        :page-sizes="[10, 20, 30, 50, 100]" :total="pagination1.total"
+        layout="->,total, sizes, prev, pager, next, jumper" background
+        @size-change="handleSizeChange1" @current-change="handleCurrentChange1">
+      </el-pagination>
     </div>
     <el-dialog :close-on-click-modal="false" :close-on-press-escape="false" v-model="dialogVisible" title="璁惧鏍告煡璁″垝"
       width="80%" @close="resetForm">
@@ -175,7 +139,7 @@
           <el-form-item label="鏍告煡璐d换浜猴細" prop="checkChargerUserId">
             <el-select v-model="form.checkChargerUserId" @change="setCheckChargerUser"
               :disabled="operationType === 'view'" placeholder="璇烽�夋嫨" size="small" style="width: 100%">
-              <el-option v-for="item in userList" :key="item.id" :label="item.name" :value="item.id"></el-option>
+              <el-option v-for="item in chargerOptions" :key="item.id" :label="item.name" :value="item.id"></el-option>
             </el-select>
           </el-form-item>
         </el-col>
@@ -185,10 +149,10 @@
           </el-form-item>
         </el-col>
       </el-form>
-      <template #footer><span  class="dialog-footer">
+      <template #footer><span class="dialog-footer">
         <el-button @click="resetForm">鍙� 娑�</el-button>
-        <el-button :loading="submitFormLoading" type="primary" @click="submitForm" v-if="operationType !== 'view'">纭�
-          璁�</el-button>
+        <el-button :loading="submitFormLoading" type="primary" @click="submitForm"
+          v-if="operationType !== 'view'">纭� 璁�</el-button>
       </span></template>
     </el-dialog>
     <el-dialog v-model="approvalDialog" title="鎵瑰噯" width="30%" @close="approvalDialog = false">
@@ -196,17 +160,19 @@
         鎵瑰噯澶囨敞锛�
         <el-input v-model="ratifyRemark" type="textarea"></el-input>
       </span>
-      <template #footer><span  class="dialog-footer">
+      <template #footer><span class="dialog-footer">
         <el-button :loading="approvalLoading" @click="handleApproval(0)">涓嶆壒鍑�</el-button>
         <el-button :loading="approvalLoading" type="primary" @click="handleApproval(1)">鎵� 鍑�</el-button>
       </span></template>
     </el-dialog>
     <el-dialog v-model="downloadDialog" title="瀵煎嚭" width="600px">
       <span>
-        <el-button :loading="outLoading" plain type="primary" @click="controlDown">鏍告煡璁板綍</el-button>
-        <el-button :loading="outLoading" plain type="primary" @click="processingDown">鏍告煡姣斿璁板綍</el-button>
+        <el-button :loading="outLoading" type="primary" :disabled="!downRow.recordStatus"
+          @click="controlDown">鏍告煡璁板綍</el-button>
+        <el-button :loading="outLoading" type="primary" :disabled="!downRow.recordContrastStatus"
+          @click="processingDown">鏍告煡姣斿璁板綍</el-button>
       </span>
-      <template #footer><span  class="dialog-footer">
+      <template #footer><span class="dialog-footer">
         <el-button @click="downloadDialog = false">鍙� 娑�</el-button>
       </span></template>
     </el-dialog>
@@ -218,30 +184,26 @@
           </el-option>
         </el-select>
       </span>
-      <template #footer><span  class="dialog-footer">
+      <template #footer><span class="dialog-footer">
         <el-button :loading="notificationLoading" @click="closeNotificationDia">鍙� 娑�</el-button>
         <el-button :loading="notificationLoading" type="primary" @click="notification">鎻� 浜�</el-button>
       </span></template>
     </el-dialog>
     <equipment-check v-if="equipmentCheck" ref="equipmentCheck" @closeDialog="closeDialog"></equipment-check>
     <check-record v-if="checkRecord" ref="checkRecord" @closeDialog1="closeDialog1"></check-record>
-    <add-verification-year-plan-dia v-if="addYearPlanDia" ref="addYearPlanDia"
-      @closeDia="closeDia"></add-verification-year-plan-dia>
   </div>
 </template>
 
 <script>
 import EquipmentCheck from "./equipmentCheck.vue";
 import CheckRecord from "./checkRecord.vue";
-import AddVerificationYearPlanDia from "./addVerificationYearPlanDia.vue";
 import {
   pageDeviceExaminePlan,
+  getExaminePlanByYear,
   submitRatifyDeviceExaminePlan,
   exportDeviceExaminePlanDetail,
-  delDeviceExaminePlan,
   delDeviceExaminePlanDetail,
   pageDeviceExaminePlanDetail,
-  addDeviceExaminePlanDetail,
   updateDeviceExaminePlanDetail,
   ratifyDeviceExaminePlan,
   exportReviewExamineRecordDetail,
@@ -249,10 +211,13 @@
 } from '@/api/cnas/resourceDemand/device.js'
 import { selectUserCondition } from "@/api/performance/class";
 import { mapGetters } from "@/utils/store-compat";
+import draftSave from '@/mixins/draftSave'
+import { formatListDate } from './dateFormat'
 export default {
   name: "equipment-verification-plan",
   // import 寮曞叆鐨勭粍浠堕渶瑕佹敞鍏ュ埌瀵硅薄涓墠鑳戒娇鐢�
-  components: { AddVerificationYearPlanDia, CheckRecord, EquipmentCheck },
+  components: { CheckRecord, EquipmentCheck },
+  mixins: [draftSave],
   props: {
     clickNodeVal: {
       type: Object,
@@ -264,19 +229,15 @@
   data() {
     // 杩欓噷瀛樻斁鏁版嵁
     return {
-      upLoading: false,
+      planYear: '',
+      yearOptions: [],
+      planInfo: {},
       dialogVisible: false,
       searchForm: {
         deviceName: '',
         deviceNumber: '',
       },
-      yearTableData: [],
       yearTableDetailData: [],
-      pagination: {
-        size: 10,
-        current: 1,
-        total: 0,
-      },
       pagination1: {
         size: 10,
         current: 1,
@@ -300,9 +261,7 @@
         deviceNumber: [{ required: true, message: '璇峰~鍐欒澶囩紪鍙�', trigger: 'blur' }],
         checkMethod: [{ required: true, message: '璇峰~鍐欐牳鏌ユ柟娉�', trigger: 'blur' }],
       },
-      yearTableDataLoading: false,
       yearTableDetailDataLoading: false,
-      currentRow: {},
       approvalDialog: false,
       approvalLoading: false,
       submitFormLoading: false,
@@ -311,7 +270,6 @@
       userList: [],
       equipmentCheck: false,
       checkRecord: false,
-      addYearPlanDia: false,
       downloadDialog: false,
       outLoading: false,
       downRow: {},
@@ -319,60 +277,168 @@
       notificationDia: false,
       notificationLoading: false,
       ratifyUserId: '',
-      planId: ''
     }
   },
   mounted() {
-    this.getYearTableData()
+    this.loadYearOptions()
   },
   // 鏂规硶闆嗗悎
   methods: {
-    // 鏌ヨ骞村害璁″垝琛�
-    getYearTableData() {
-      this.yearTableDataLoading = true
+    // 骞翠唤涓嬫媺閫夐」锛氬凡鏈夎鍒掑勾浠� + 褰撳墠骞翠唤
+    loadYearOptions() {
       pageDeviceExaminePlan({
         current: 1,
         size: 99,
       }).then(res => {
+        let years = []
         if (res.code == 200) {
-          this.yearTableData = res.data.records
-          this.pagination.total = res.data.total
-          if (this.yearTableData.length > 0) {
-            this.currentRow = this.yearTableData[0]
-            this.$refs.yearTable.setCurrentRow(this.currentRow)
-          }
+          years = (res.data.records || []).map(r => r.planYear).filter(Boolean)
         }
-        this.yearTableDataLoading = false
+        const currentYear = String(new Date().getFullYear())
+        if (years.indexOf(currentYear) === -1) {
+          years.push(currentYear)
+        }
+        this.yearOptions = [...new Set(years)].sort((a, b) => b.localeCompare(a))
+        this.planYear = currentYear
+        this.loadPlan()
+      })
+    },
+    // 鍒囨崲骞翠唤
+    handleYearChange() {
+      this.pagination1.current = 1
+      this.loadPlan()
+    },
+    // 鏌ヨ骞翠唤璁″垝锛堜笉瀛樺湪鑷姩鍒涘缓骞惰ˉ鍏ㄥ埌鐐规槑缁嗭級锛岄殢鍚庡埛鏂版槑缁�
+    loadPlan() {
+      getExaminePlanByYear({ planYear: this.planYear }).then(res => {
+        if (res.code == 200) {
+          this.planInfo = res.data || {}
+        }
+        this.getYearTableDetailData()
+      }).catch(() => {
+        this.planInfo = {}
+        this.yearTableDetailData = []
+        this.pagination1.total = 0
+        this.yearTableDetailDataLoading = false
+      })
+    },
+    // 鏌ヨ鏉′欢鍙樺寲鍚庝粠绗竴椤靛紑濮嬫煡
+    handleQuery() {
+      this.pagination1.current = 1
+      this.getYearTableDetailData()
+    },
+    // 鏄庣粏-鏌ヨ
+    getYearTableDetailData() {
+      if (!this.planInfo.planId) {
+        return
+      }
+      this.yearTableDetailDataLoading = true
+      pageDeviceExaminePlanDetail({
+        current: this.pagination1.current,
+        size: this.pagination1.size,
+        planId: this.planInfo.planId,
+        deviceName: this.searchForm.deviceName,
+        deviceNumber: this.searchForm.deviceNumber,
+      }).then(res => {
+        if (res.code == 200) {
+          this.yearTableDetailData = res.data.records
+          this.pagination1.total = res.data.total
+        }
+        this.yearTableDetailDataLoading = false
       }).catch(err => {
-        this.yearTableDataLoading = false
+        this.yearTableDetailDataLoading = false
       })
     },
-    // 鍒嗛〉
-    handleSizeChange(val) {
-      this.pagination.size = val
-      this.getYearTableData()
+    // 鍒扮偣闇�鏍告煡鐨勮鏍囩孩
+    // 鏍告煡鏃堕棿鎸夋湀浠芥樉绀猴紙鍏煎鍘嗗彶鏁版嵁涓殑瀹屾暣鏃ユ湡锛�
+    formatCheckMonth(row, column, cellValue) {
+      if (cellValue === null || cellValue === undefined || cellValue === '') {
+        return cellValue
+      }
+      const str = String(cellValue).trim().replace(/[./]/g, '-')
+      const matched = str.match(/^(\d{4})-(\d{1,2})/)
+      if (matched) {
+        return `${matched[1]}-${matched[2].padStart(2, '0')}`
+      }
+      const formatted = formatListDate(str)
+      const fallback = String(formatted).match(/^(\d{4})-(\d{1,2})/)
+      return fallback ? `${fallback[1]}-${fallback[2].padStart(2, '0')}` : cellValue
+    },
+    tableRowClassName({ row }) {
+      return row.redFlag === 1 ? 'red-row' : ''
+    },
+    reset() {
+      this.searchForm = {
+        deviceName: '',
+        deviceNumber: '',
+      }
+      this.pagination1.current = 1
+      this.getYearTableDetailData()
     },
     // 鍒嗛〉
-    handleCurrentChange(val) {
-      this.pagination.current = val
-      this.getYearTableData()
+    handleSizeChange1(val) {
+      this.pagination1.size = val
+      this.getYearTableDetailData()
     },
-    // 鎵撳紑鏂板寮规
-    addYearPlan(type, row) {
-      this.addYearPlanDia = true
+    // 鍒嗛〉
+    handleCurrentChange1(val) {
+      this.pagination1.current = val
+      this.getYearTableDetailData()
+    },
+    // 鎵撳紑鏄庣粏寮规
+    handleForm(type, row) {
+      this.getUserList()
+      this.operationType = type
+      this.dialogVisible = true
+      this.form.planId = this.planInfo.planId
       this.$nextTick(() => {
-        this.$refs.addYearPlanDia.openDialog(type, row)
+        this.form = this.HaveJson(row)
+        if (this.operationType !== 'view') {
+          this.draftRestore('equipmentVerificationPlan', 'form', this.form.planDetailsId, 'dialogVisible')
+        }
       })
     },
-    closeDia() {
-      this.addYearPlanDia = false
-      this.getYearTableData()
+    // 鎻愪氦琛ㄥ崟
+    submitForm() {
+      this.$refs.modelForm.validate(valid => {
+        if (valid) {
+          this.submitFormLoading = true
+          updateDeviceExaminePlanDetail(this.form).then(res => {
+            if (res.code == 200) {
+              this.$message.success('淇敼鎴愬姛')
+              this.draftClear('equipmentVerificationPlan')
+              this.dialogVisible = false
+              this.getYearTableDetailData()
+            }
+            this.submitFormLoading = false
+          }).catch(err => {
+            this.submitFormLoading = false
+          })
+        }
+      })
+    },
+    // 鏄庣粏-鍒犻櫎
+    deleteFun1(id) {
+      this.$confirm('姝ゆ搷浣滃皢姘镐箙鍒犻櫎璇ユ潯鏄庣粏, 鏄惁缁х画?', '鎻愮ず', {
+        confirmButtonText: '纭畾',
+        cancelButtonText: '鍙栨秷',
+        type: 'warning'
+      }).then(() => {
+        delDeviceExaminePlanDetail({ planDetailsId: id }).then(res => {
+          this.$message.success('鍒犻櫎鎴愬姛锛�');
+          this.getYearTableDetailData()
+        });
+      }).catch(() => {
+        this.$message({
+          type: 'info',
+          message: '宸插彇娑堝垹闄�'
+        });
+      });
     },
     // 鎵撳紑鎻愪氦鎵瑰噯寮规
-    tellApprove(planId) {
+    tellApprove() {
       this.getUserList1()
       this.notificationDia = true
-      this.planId = planId
     },
     // 鍏抽棴鎻愪氦鎵瑰噯寮规
     closeNotificationDia() {
@@ -388,163 +454,23 @@
       this.notificationLoading = true
       submitRatifyDeviceExaminePlan({
         ratifyUserId: this.ratifyUserId,
-        planId: this.planId,
+        planId: this.planInfo.planId,
       }).then(res => {
         this.notificationLoading = false
         if (res.code == 200) {
           this.closeNotificationDia()
-          this.getYearTableData()
+          this.loadPlan()
         }
       }).catch(err => {
         this.notificationLoading = false
       })
     },
-    // 骞村害璁″垝琛�-鎵瑰噯
-    handleApprove(id) {
-      this.currentRowId = id
+    // 鎵瑰噯
+    handleApprove() {
+      this.currentRowId = this.planInfo.planId
       this.approvalDialog = true
     },
-    // 骞村害璁″垝琛�-瀵煎嚭
-    downLoadPost(planId) {
-      exportDeviceExaminePlanDetail({ planId }).then(res => {
-        const blob = new Blob([res], { type: 'application/msword' });
-        this.$download.saveAs(blob, '浠櫒璁惧鏈熼棿鏍告煡璁″垝琛�.docx')
-      })
-    },
-    // 骞村害璁″垝琛�-鍒犻櫎
-    deleteFun(id) {
-      this.$confirm('姝ゆ搷浣滃皢姘镐箙鍒犻櫎璇ユ枃浠�, 鏄惁缁х画?', '鎻愮ず', {
-        confirmButtonText: '纭畾',
-        cancelButtonText: '鍙栨秷',
-        type: 'warning'
-      }).then(() => {
-        delDeviceExaminePlan({ planId: id }).then(res => {
-          this.$message.success('鍒犻櫎鎴愬姛锛�');
-          this.getYearTableData();
-        });
-      }).catch(() => {
-        this.$message({
-          type: 'info',
-          message: '宸插彇娑堝垹闄�'
-        });
-      });
-    },
-    // 骞村害璁″垝璇︽儏琛�-鍒犻櫎
-    deleteFun1(id) {
-      this.$confirm('姝ゆ搷浣滃皢姘镐箙鍒犻櫎璇ユ枃浠�, 鏄惁缁х画?', '鎻愮ず', {
-        confirmButtonText: '纭畾',
-        cancelButtonText: '鍙栨秷',
-        type: 'warning'
-      }).then(() => {
-        delDeviceExaminePlanDetail({ planDetailsId: id }).then(res => {
-          this.$message.success('鍒犻櫎鎴愬姛锛�');
-          this.getYearTableDetailData(this.currentRow)
-        });
-      }).catch(() => {
-        this.$message({
-          type: 'info',
-          message: '宸插彇娑堝垹闄�'
-        });
-      });
-    },
-    currentChange(row) {
-      this.currentRow = row
-      this.getYearTableDetailData(this.currentRow)
-    },
-    getYearTableDetailData(row) {
-      this.yearTableDetailDataLoading = true
-      pageDeviceExaminePlanDetail({
-        current: this.pagination1.current,
-        size: this.pagination1.size,
-        planId: row.planId,
-        deviceName: this.searchForm.deviceName,
-        deviceNumber: this.searchForm.deviceNumber,
-      }).then(res => {
-        if (res.code == 200) {
-          this.yearTableDetailData = res.data.records
-          this.pagination1.total = res.data.total
-        }
-        this.yearTableDetailDataLoading = false
-      }).catch(err => {
-        this.yearTableDetailDataLoading = false
-      })
-    },
-    reset() {
-      this.searchForm = {
-        deviceName: '',
-        deviceNumber: '',
-      }
-      this.getYearTableDetailData(this.currentRow)
-    },
-    // 鍒嗛〉
-    handleSizeChange1(val) {
-      this.pagination1.size = val
-      this.getYearTableDetailData(this.currentRow)
-    },
-    // 鍒嗛〉
-    handleCurrentChange1(val) {
-      this.pagination1.current = val
-      this.getYearTableDetailData(this.currentRow)
-    },
-    // 鎵撳紑寮规
-    handleForm(type, row) {
-      this.getUserList()
-      this.operationType = type
-      this.dialogVisible = true
-      this.form.planId = this.currentRow.planId
-      if (this.operationType !== 'add') {
-        this.$nextTick(() => {
-          this.form = this.HaveJson(row)
-        })
-      } else {
-        this.form = {
-          deviceNumber: '',
-          deviceName: '',
-          checkTime: '',
-          checkIndex: '',
-          checkMethod: '',
-          howResults: '',
-          checkChargerUserId: '',
-          checkChargerUser: '',
-          remark: '',
-          planId: this.currentRow.planId,
-          planDetailsId: '',
-        }
-      }
-    },
-    // 鎻愪氦琛ㄥ崟
-    submitForm() {
-      this.$refs.modelForm.validate(valid => {
-        if (valid) {
-          if (this.operationType === 'add') {
-            this.submitFormLoading = true
-            addDeviceExaminePlanDetail(this.form).then(res => {
-              if (res.code == 200) {
-                this.$message.success('鏂板鎴愬姛')
-                this.dialogVisible = false
-                this.getYearTableData()
-              }
-              this.submitFormLoading = false
-            }).catch(err => {
-              this.submitFormLoading = false
-            })
-          } else {
-            this.submitFormLoading = true
-            updateDeviceExaminePlanDetail(this.form).then(res => {
-              if (res.code == 200) {
-                this.$message.success('鏂板鎴愬姛')
-                this.dialogVisible = false
-                this.getYearTableData()
-              }
-              this.submitFormLoading = false
-            }).catch(err => {
-              this.submitFormLoading = false
-            })
-          }
-        }
-      })
-    },
-    // 鎻愪氦鎵瑰噯
+    // 鎻愪氦鎵瑰噯缁撴灉
     handleApproval(status) {
       const personTrainingUpdateDto = {
         planId: this.currentRowId,
@@ -556,14 +482,21 @@
         if (res.code === 200) {
           this.$message.success('鎻愪氦鎴愬姛锛�');
           this.approvalDialog = false
-          this.getYearTableData();
+          this.loadPlan()
         }
         this.approvalLoading = false
       }).catch(() => {
         this.approvalLoading = false
       })
     },
+    // 瀵煎嚭骞村害璁″垝琛�
+    downLoadPost() {
+      exportDeviceExaminePlanDetail({ planId: this.planInfo.planId }).then(res => {
+        this.saveDocx(res, '浠櫒璁惧鏈熼棿鏍告煡璁″垝琛�.docx')
+      }).catch(() => { })
+    },
     resetForm() {
+      this.draftStop('equipmentVerificationPlan')
       this.$refs.modelForm.resetFields();
       this.dialogVisible = false
     },
@@ -577,7 +510,7 @@
     // 鍏抽棴瀵规瘮寮规
     closeDialog() {
       this.equipmentCheck = false
-      this.getYearTableDetailData(this.currentRow)
+      this.getYearTableDetailData()
     },
     // 鎵撳紑璁板綍寮规
     handleRecord(row) {
@@ -589,20 +522,39 @@
     // 鍏抽棴璁板綍寮规
     closeDialog1() {
       this.checkRecord = false
-      this.getYearTableDetailData(this.currentRow)
+      this.getYearTableDetailData()
     },
     // 鎵撳紑瀵煎嚭寮规
     handleDown(row) {
       this.downRow = row
       this.downloadDialog = true
     },
+    // 瀵煎嚭缁撴灉鎷︽埅: 鍚庣杩斿洖閿欒 JSON 鏃舵彁绀洪敊璇�, 涓嶅瓨鎴愬潖鏂囦欢
+    saveDocx(res, filename) {
+      const reader = new FileReader();
+      reader.readAsText(res, 'utf-8');
+      reader.onload = () => {
+        const text = (reader.result || '').trim();
+        if (text.startsWith('{') || text.startsWith('[')) {
+          let msg = '瀵煎嚭澶辫触';
+          try { msg = JSON.parse(text).msg || msg; } catch (e) { }
+          this.$message.error(msg);
+        } else {
+          this.$download.saveAs(new Blob([res], { type: 'application/msword' }), filename);
+        }
+      };
+      reader.onerror = () => {
+        this.$download.saveAs(new Blob([res], { type: 'application/msword' }), filename);
+      };
+    },
     // 鏍告煡璁板綍瀵煎嚭
     controlDown() {
       this.outLoading = true
       exportReviewExamineRecordDetail({ planDetailsId: this.downRow.planDetailsId }).then(res => {
         this.outLoading = false
-        const blob = new Blob([res], { type: 'application/octet-stream' });
-        this.$download.saveAs(blob, '浠櫒璁惧鏈熼棿鏍告煡璁板綍琛�.doc')
+        this.saveDocx(res, '浠櫒璁惧鏈熼棿鏍告煡璁板綍琛�.doc')
+      }).catch(() => {
+        this.outLoading = false
       })
     },
     // 鏍告煡瀵规瘮瀵煎嚭
@@ -610,33 +562,10 @@
       this.outLoading = true
       exportReviewExamineRecordContrast({ planDetailsId: this.downRow.planDetailsId }).then(res => {
         this.outLoading = false
-        const blob = new Blob([res], { type: 'application/octet-stream' });
-        this.$download.saveAs(blob, '浠櫒璁惧鏈熼棿鏍告煡姣斿璁板綍琛�.doc')
+        this.saveDocx(res, '浠櫒璁惧鏈熼棿鏍告煡姣斿璁板綍琛�.doc')
+      }).catch(() => {
+        this.outLoading = false
       })
-    },
-    // 瀵煎叆娴佺▼
-    beforeUpload(file) {
-      if (file.size > 1024 * 1024 * 10) {
-        this.$message.error('涓婁紶鏂囦欢涓嶈秴杩�10M');
-        this.$refs.upload.clearFiles()
-        return false;
-      } else {
-        this.upLoading = true;
-        return true;
-      }
-    },
-    onError(err, file, fileList) {
-      this.$message.error('涓婁紶澶辫触')
-      this.$refs.upload.clearFiles()
-    },
-    handleSuccessUp(response) {
-      this.upLoading = false;
-      if (response.code == 200) {
-        this.$message.success('涓婁紶鎴愬姛');
-        this.getYearTableData()
-      } else {
-        this.$message.error(response.message)
-      }
     },
     getUserList() {
       selectUserCondition().then(res => {
@@ -658,26 +587,36 @@
       });
     }
   },
-  // 鐢ㄤ簬涓婁紶鏂囦欢鐨勪俊鎭�
   computed: {
-    action() {
-      return this.javaApi + '/deviceExaminePlan/importDeviceExaminePlan'
-    },
     ...mapGetters(["userId"]),
+    // 鏄惁宸插畬鎴愬鎵癸紙鎵瑰噯/涓嶆壒鍑嗭級
+    isRatified() {
+      return this.planInfo.ratifyStatus === 0 || this.planInfo.ratifyStatus === 1;
+    },
+    // 璐d换浜轰笅鎷夛細宸蹭繚瀛樼殑璐d换浜轰笉鍦ㄥ�欓�夊垪琛ㄦ椂琛ヤ竴鏉★紝閬垮厤鍥炴樉鎴愮敤鎴稩D
+    chargerOptions() {
+      const list = this.userList || []
+      const id = this.form.checkChargerUserId
+      if (id && !list.some(item => String(item.id) === String(id))) {
+        return [...list, { id, name: this.form.checkChargerUser || String(id) }]
+      }
+      return list
+    },
   },
 }
 </script>
 
 <style scoped>
 .search {
-  height: 46px;
   display: flex;
   justify-content: space-between;
+  margin-bottom: 10px;
 }
+
 .title {
   position: relative;
   font-size: 16px;
-  color: #333;
+  color: var(--lims-text);
   font-weight: 400;
   padding-left: 10px;
   margin-bottom: 10px;
@@ -693,4 +632,33 @@
   background-color: var(--el-color-primary);
   border-radius: 2px;
 }
+
+.plan-top {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  flex-wrap: wrap;
+}
+
+.plan-top-left {
+  display: flex;
+  align-items: center;
+}
+
+.plan-info-bar {
+  display: flex;
+  align-items: center;
+  flex-wrap: wrap;
+  gap: 32px;
+  background: #f5f7fa;
+  border-radius: 4px;
+  padding: 10px 16px;
+  margin-top: 14px;
+  font-size: 14px;
+  color: #606266;
+}
+
+:deep(.red-row td) {
+  background: #ffcccc !important;
+}
 </style>

--
Gitblit v1.9.3