From 137bf2c0666b60cfc0d98b1a9ca7ead860ee4e7c Mon Sep 17 00:00:00 2001
From: 吴羡 <16976746+Xian-TT3@user.noreply.gitee.com>
Date: 星期三, 28 十月 2026 17:57:29 +0800
Subject: [PATCH] feat(device,supply,satisfaction): 设备计划改造、耗材采购调整与满意度照片上传

---
 src/views/CNAS/resourceDemand/device/component/equipmentVerificationPlan.vue |  133 ++++++++++++++++++++++++++++++-------------
 1 files changed, 92 insertions(+), 41 deletions(-)

diff --git a/src/views/CNAS/resourceDemand/device/component/equipmentVerificationPlan.vue b/src/views/CNAS/resourceDemand/device/component/equipmentVerificationPlan.vue
index b79641d..119dd16 100644
--- a/src/views/CNAS/resourceDemand/device/component/equipmentVerificationPlan.vue
+++ b/src/views/CNAS/resourceDemand/device/component/equipmentVerificationPlan.vue
@@ -51,8 +51,12 @@
           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="120" prop="deviceModel" show-overflow-tooltip></el-table-column>
+        <el-table-column label="鏍告煡鏃堕棿" min-width="120">
+          <template #default="scope">
+            {{ scope.row.completeDate || formatCheckMonth(null, null, scope.row.checkTime) }}
+          </template>
+        </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>
@@ -89,7 +93,7 @@
               @click="handleRecord(scope.row)">瀹℃牳</el-button>
             <el-button v-if="scope.row.recordStatus === 2 || scope.row.recordStatus === 3"
               size="small" link type="primary" @click="handleDown(scope.row)">瀵煎嚭</el-button>
-            <el-button v-if="scope.row.recordStatus === 0 && scope.row.recordContrastStatus === 0"
+            <el-button v-if="scope.row.recordStatus !== 2"
               size="small" link type="danger" @click="deleteFun1(scope.row.planDetailsId)">鍒犻櫎</el-button>
           </template>
         </el-table-column>
@@ -107,16 +111,20 @@
           <div class="form-section-title">鍩烘湰淇℃伅</div>
           <el-row :gutter="12">
             <el-col :span="12">
-              <el-form-item label="浠櫒鍚嶇О锛�" prop="deviceName">
+              <el-form-item label="璁惧鍚嶇О锛�" prop="deviceName">
                 <el-input v-model="form.deviceName" disabled size="small"></el-input>
               </el-form-item>
             </el-col>
             <el-col :span="12">
               <el-form-item label="妫�鏌ユ棩鏈燂細" prop="checkTime">
-                <el-date-picker v-model="form.checkTime" :disabled="operationType === 'view'" clearable
-                  format="YYYY-MM" placeholder="閫夋嫨妫�鏌ユ棩鏈�" size="small" style="width:100%" type="month"
-                  value-format="YYYY-MM">
-                </el-date-picker>
+                <el-input v-if="operationType === 'view'" :model-value="formatCheckMonth(null, null, form.checkTime)"
+                  disabled size="small"></el-input>
+                <template v-else>
+                  <el-date-picker v-model="checkTimeEditValue" clearable format="YYYY-MM-DD" placeholder="閫夋嫨妫�鏌ユ棩鏈�"
+                    size="small" style="width:100%" type="date" value-format="YYYY-MM-DD">
+                  </el-date-picker>
+                  <div v-if="isMonthOnlyCheckTime" class="check-time-tip">绯荤粺鐧昏鍙埌鏈堜唤锛岄�夋嫨鍏蜂綋鏃ユ湡鍚庡皢鎸夋棩淇濆瓨</div>
+                </template>
               </el-form-item>
             </el-col>
             <el-col :span="8">
@@ -212,7 +220,7 @@
         </div>
       </el-form>
       <template #footer><span class="dialog-footer">
-        <el-button @click="resetForm">鍙� 娑�</el-button>
+        <el-button @click="handleCancel">鍙� 娑�</el-button>
         <el-button :loading="submitFormLoading" type="primary" @click="submitForm"
           v-if="operationType !== 'view'">纭� 璁�</el-button>
       </span></template>
@@ -234,7 +242,7 @@
             <span class="export-panel-label">璁惧鍚嶇О</span>{{ downRow.deviceName || '鈥�' }}
           </div>
           <div class="export-panel-item">
-            <span class="export-panel-label">鏍告煡鏃堕棿</span>{{ formatCheckMonth(null, null, downRow.checkTime) || '鈥�' }}
+            <span class="export-panel-label">鏍告煡鏃堕棿</span>{{ downRow.completeDate || formatCheckMonth(null, null, downRow.checkTime) || '鈥�' }}
           </div>
         </div>
         <div v-if="!canExport" class="export-panel-tip">
@@ -259,8 +267,8 @@
 import CheckRecord from "./checkRecord.vue";
 import LimsAttachment from '@/components/Attachment/lims-attachment.vue'
 import {
-  pageDeviceExaminePlan,
   getExaminePlanByYear,
+  getExaminePlanYears,
   exportDeviceExaminePlanDetail,
   delDeviceExaminePlanDetail,
   pageDeviceExaminePlanDetail,
@@ -340,30 +348,24 @@
   },
   // 鏂规硶闆嗗悎
   methods: {
-    // 骞翠唤涓嬫媺鍙繚鐣欐湁璁″垝鏄庣粏鐨勫勾浠斤紝绌哄勾浠借嚜鍔ㄦ秷澶�
+    // 骞翠唤涓嬫媺鍙繚鐣欐湁璁″垝鏄庣粏鐨勫勾浠斤紝绌哄勾浠借鍒掕嚜鍔ㄥ垹闄わ紝榛樿鏄剧ず鏈勾搴︼紙鏈勾搴︽棤璁″垝鏃堕��鍥炴渶鏂板勾浠斤級
     loadYearOptions() {
-      pageDeviceExaminePlan({
-        current: 1,
-        size: 99,
-      }).then(res => {
-        let years = []
-        if (res.code == 200) {
-          years = (res.data.records || []).map(r => r.planYear).filter(Boolean)
-        }
-        const options = [...new Set(years)].sort((a, b) => b.localeCompare(a))
-        this.yearOptions = options
+      const currentYear = String(new Date().getFullYear())
+      const finish = (years) => {
+        let options = [...new Set((years || []).map(y => String(y)).filter(Boolean))]
+        options.sort((a, b) => b.localeCompare(a))
         if (options.length === 0) {
-          this.planYear = ''
-          this.planInfo = {}
-          this.yearTableDetailData = []
-          this.pagination1.total = 0
-          return
+          options = [currentYear]
         }
-        if (options.indexOf(this.planYear) === -1) {
-          const currentYear = String(new Date().getFullYear())
-          this.planYear = options.indexOf(currentYear) > -1 ? currentYear : options[0]
-        }
+        this.yearOptions = options
+        const keep = options.indexOf(String(this.planYear)) > -1
+        this.planYear = keep ? String(this.planYear) : (options.includes(currentYear) ? currentYear : options[0])
         this.loadPlan()
+      }
+      getExaminePlanYears().then(res => {
+        finish(res.code == 200 ? (res.data || []) : [])
+      }).catch(() => {
+        finish([])
       })
     },
     // 鍒囨崲骞翠唤
@@ -471,7 +473,10 @@
       this.$nextTick(() => {
         this.form = this.HaveJson(row)
         if (this.operationType !== 'view') {
-          this.draftRestore('equipmentVerificationPlan', 'form', this.form.planDetailsId, 'dialogVisible')
+          const rowDeviceName = this.form.deviceName
+          this.draftRestore('equipmentVerificationPlan', 'form', this.form.planDetailsId, 'dialogVisible',
+            // 璁惧鍚嶇О鏄鐢ㄥ瓧娈碉紝鑽夌閲屼负绌鸿鏄庢槸琚〃鍗曢噸缃竻绌虹殑搴熻崏绋匡紝鐩存帴涓㈠純
+            draft => !!draft.deviceName || !rowDeviceName)
         }
       })
     },
@@ -496,7 +501,7 @@
     },
     // 鏄庣粏-鍒犻櫎
     deleteFun1(id) {
-      this.$confirm('鍒犻櫎鍚庯紝鑻ヨ璁惧杩樻湁瀹℃牳閫氳繃鐨勬牳鏌ヨ褰曪紝妗f鐨勬渶杩戞牳鏌ユ棩鏈熷皢鍥為��鍒版渶杩戜竴娆″畬鎴愯褰曪紱鑻ユ病鏈夛紝鍒欐竻绌烘。妗堢殑鏍告煡鏃ユ湡鍜屾牳鏌ュ懆鏈熴�傛槸鍚︾户缁�?', '鎻愮ず', {
+      this.$confirm('鍒犻櫎鍚庯紝璇ヨ鐨勬牳鏌ヨ褰曪紙鏈鏍告垨瀹℃牳涓嶉�氳繃锛夊強闄勪欢浼氫竴骞跺垹闄わ紱鑻ヨ璁惧杩樻湁瀹℃牳閫氳繃鐨勬牳鏌ヨ褰曪紝妗f鐨勬渶杩戞牳鏌ユ棩鏈熷皢鍥為��鍒版渶杩戜竴娆″畬鎴愯褰曪紱鑻ユ病鏈夛紝鍒欐竻绌烘。妗堢殑鏍告煡鏃ユ湡鍜屾牳鏌ュ懆鏈熴�傛槸鍚︾户缁�?', '鎻愮ず', {
         confirmButtonText: '纭畾',
         cancelButtonText: '鍙栨秷',
         type: 'warning'
@@ -512,13 +517,39 @@
         });
       });
     },
-    // 瀵煎嚭骞村害璁″垝琛�
+    // 瀵煎嚭骞村害璁″垝琛紙Excel锛夛細鏈夌瓫閫夋潯浠跺鍑虹瓫閫夌粨鏋滐紝娌℃湁绛涢�夊鍑鸿骞翠唤鍏ㄩ儴
     downLoadPost() {
-      exportDeviceExaminePlanDetail({ planId: this.planInfo.planId }).then(res => {
-        this.saveDocx(res, '浠櫒璁惧鏈熼棿鏍告煡璁″垝琛�.docx')
+      exportDeviceExaminePlanDetail({
+        planId: this.planInfo.planId,
+        deviceName: this.searchForm.deviceName,
+        deviceNumber: this.searchForm.deviceNumber,
+      }).then(res => {
+        const planName = this.planInfo.planName || (this.planYear ? this.planYear + '骞村害璁惧鏍告煡璁″垝' : '璁惧鏍告煡璁″垝')
+        this.saveDocx(res, planName + '.xlsx', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
+      }).catch(() => { })
+    },
+    // 鏈鏄惁鏈夋敼鍔紙鍚墦寮�鏃舵仮澶嶇殑鑽夌锛�
+    hasUnsavedEdit() {
+      const state = this.draftStates && this.draftStates['equipmentVerificationPlan']
+      return !!state && this.draftSnapshot(state) !== state.baseline
+    },
+    // 鍙栨秷锛氭棤缂栬緫鐩存帴閫�鍑猴紱鏈夌紪杈戝厛纭锛岀‘璁ゅ悗涓㈠純鑽夌閫�鍑�
+    handleCancel() {
+      if (this.operationType === 'view' || !this.hasUnsavedEdit()) {
+        this.dialogVisible = false
+        return
+      }
+      this.$confirm('鏄惁纭鍙栨秷缂栬緫锛熸湰娆$紪杈戣褰曚笉淇濆瓨锛�', '鎻愮ず', {
+        confirmButtonText: '纭畾',
+        cancelButtonText: '缁х画缂栬緫',
+        type: 'warning'
+      }).then(() => {
+        this.draftClear('equipmentVerificationPlan')
+        this.dialogVisible = false
       }).catch(() => { })
     },
     resetForm() {
+      // 鍙充笂瑙掑叧闂椂 close 浜嬩欢鍏堜簬鏄鹃殣鐩戝惉瑙﹀彂锛屽厛鎶婅崏绋垮瓨涓嬪啀閲嶇疆琛ㄥ崟锛岄伩鍏嶉噸缃悗鐨勭┖鍐呭琚瓨鎴愯崏绋�
       this.draftStop('equipmentVerificationPlan')
       this.$refs.modelForm.resetFields();
       this.dialogVisible = false
@@ -539,8 +570,7 @@
     },
     // 鎵撳紑闄勪欢
     openAttachment(row) {
-      const isImage = /\.(jpg|jpeg|png|gif)$/i.test(row.fileUrl)
-      window.open(this.javaApi + (isImage ? '/img/' : '/word/') + row.fileUrl, '_blank')
+      return this.$download.saveAs(row.fileUrl, row.fileName)
     },
     // 鍒楄〃闄勪欢鍒楀彧璇绘煡鐪嬶紙涓婁紶/鍒犻櫎鍏ュ彛鍙湪缂栬緫銆佹柊澧炲脊绐楀唴锛�
     handleAttachment(row) {
@@ -558,7 +588,7 @@
       this.downloadDialog = true
     },
     // 瀵煎嚭缁撴灉鎷︽埅: 鍚庣杩斿洖閿欒 JSON 鏃舵彁绀洪敊璇�, 涓嶅瓨鎴愬潖鏂囦欢
-    saveDocx(res, filename) {
+    saveDocx(res, filename, mime = 'application/msword') {
       const reader = new FileReader();
       reader.readAsText(res, 'utf-8');
       reader.onload = () => {
@@ -568,11 +598,11 @@
           try { msg = JSON.parse(text).msg || msg; } catch (e) { }
           this.$message.error(msg);
         } else {
-          this.$download.saveAs(new Blob([res], { type: 'application/msword' }), filename);
+          this.$download.saveAs(new Blob([res], { type: mime }), filename);
         }
       };
       reader.onerror = () => {
-        this.$download.saveAs(new Blob([res], { type: 'application/msword' }), filename);
+        this.$download.saveAs(new Blob([res], { type: mime }), filename);
       };
     },
     // 鏍告煡璁板綍瀵煎嚭
@@ -624,6 +654,19 @@
         return [...list, { id, name: this.form.checkChargerUser || String(id) }]
       }
       return list
+    },
+    // 鏃ユ湡鎺т欢鍙帴鍙� YYYY-MM-DD锛涚郴缁熺櫥璁扮殑寰呮牳鏌ヨ鍙湁骞存湀锛屾湭鏀规棩鏈熸椂涓嶈兘鎶娾�滄棩鈥濆啓杩涜〃鍗�
+    checkTimeEditValue: {
+      get() {
+        const val = this.form.checkTime || ''
+        return /^\d{4}-\d{2}$/.test(val) ? `${val}-01` : val
+      },
+      set(val) {
+        this.form.checkTime = val || ''
+      }
+    },
+    isMonthOnlyCheckTime() {
+      return /^\d{4}-\d{2}$/.test(this.form.checkTime || '')
     },
   },
 }
@@ -712,6 +755,14 @@
   margin-bottom: 12px;
 }
 
+.check-time-tip {
+  width: 100%;
+  font-size: 12px;
+  line-height: 1.4;
+  color: #909399;
+  margin-top: 2px;
+}
+
 .export-panel {
   border: 1px solid #e4e7ed;
   border-radius: 6px;

--
Gitblit v1.9.3