From d2eed0eb7c2f9537d5eaab7ccc3b6ab258959227 Mon Sep 17 00:00:00 2001
From: 吴羡 <16976746+Xian-TT3@user.noreply.gitee.com>
Date: 星期六, 24 十月 2026 20:48:11 +0800
Subject: [PATCH] feat(device): 设备核查计划附件上传与运行记录导出调整

---
 src/api/cnas/resourceDemand/device.js                                        |    9 
 src/views/CNAS/resourceDemand/device/index.vue                               |    5 
 src/components/Attachment/lims-attachment.vue                                |  141 ++++++
 src/views/CNAS/resourceDemand/device/component/record.vue                    |  385 ++++++++++--------
 src/views/CNAS/resourceDemand/device/component/checkRecord.vue               |  317 ++++++++++----
 src/views/CNAS/resourceDemand/device/component/equipmentVerificationPlan.vue |  391 +++++++++++++-----
 6 files changed, 852 insertions(+), 396 deletions(-)

diff --git a/src/api/cnas/resourceDemand/device.js b/src/api/cnas/resourceDemand/device.js
index 2ed9d05..ada69dc 100644
--- a/src/api/cnas/resourceDemand/device.js
+++ b/src/api/cnas/resourceDemand/device.js
@@ -379,6 +379,15 @@
   });
 }
 
+// 鏌ユ壘鍙鐢ㄧ殑鏍告煡璁″垝鏄庣粏锛堝彧鏌ヨ锛屼笉鏂板锛�
+export function findExaminePlanDetail(query) {
+  return request({
+    url: "/deviceExaminePlan/findExaminePlanDetail",
+    method: "get",
+    params: query,
+  });
+}
+
 // 鏂板璁惧鏍告煡璁″垝璇︽儏
 export function addDeviceExaminePlanDetail(data) {
   return request({
diff --git a/src/components/Attachment/lims-attachment.vue b/src/components/Attachment/lims-attachment.vue
index e99027c..62ae50d 100644
--- a/src/components/Attachment/lims-attachment.vue
+++ b/src/components/Attachment/lims-attachment.vue
@@ -1,10 +1,39 @@
 <template>
-  <div>
-    <el-dialog :title="dialogTitle" v-model="visible" width="760px">
+  <div class="lims-attachment">
+    <div v-if="inline" class="attachment-inline">
       <div class="attachment-header">
-        <div class="el-upload__tip">{{ tip }}</div>
-        <el-upload :action="uploadAction" :headers="uploadHeader" multiple :show-file-list="false"
-          :on-success="handleUploadSuccess" :on-error="handleUploadError">
+        <div class="el-upload__tip">
+          {{ readonly ? '浠呭彲棰勮銆佷笅杞介檮浠�' : ((currentId || deferUpload) ? tip : emptyTip) }}
+        </div>
+        <el-upload v-if="!readonly" :action="uploadAction" :headers="uploadHeader" multiple
+          :show-file-list="false" :disabled="!canUpload" :auto-upload="!deferUpload"
+          :on-change="handleFileChange" :on-success="handleUploadSuccess"
+          :on-error="handleUploadError">
+          <el-button size="small" type="primary" :disabled="!canUpload">涓婁紶闄勪欢</el-button>
+        </el-upload>
+      </div>
+      <el-table :data="displayList" border size="small" max-height="180" style="margin-top:8px">
+        <el-table-column label="鏂囦欢鍚嶇О" prop="fileName" min-width="220" show-overflow-tooltip />
+        <el-table-column label="涓婁紶鏃堕棿" prop="createTime" width="160" />
+        <el-table-column label="鎿嶄綔" width="170">
+          <template #default="scope">
+            <template v-if="scope.row.pending">
+              <el-button link type="danger" @click="removePending(scope.row)">鍒犻櫎</el-button>
+            </template>
+            <template v-else>
+              <el-button link type="primary" @click="previewFile(scope.row)">棰勮</el-button>
+              <el-button link type="primary" @click="downloadFile(scope.row)">涓嬭浇</el-button>
+              <el-button v-if="!readonly" link type="danger" @click="removeFile(scope.row)">鍒犻櫎</el-button>
+            </template>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+    <el-dialog v-else :title="dialogTitle" v-model="visible" width="760px" append-to-body @close="$emit('closed')">
+      <div class="attachment-header">
+        <div class="el-upload__tip">{{ readonly ? '浠呭彲棰勮銆佷笅杞介檮浠�' : tip }}</div>
+        <el-upload v-if="!readonly" :action="uploadAction" :headers="uploadHeader" multiple
+          :show-file-list="false" :on-success="handleUploadSuccess" :on-error="handleUploadError">
           <el-button size="small" type="primary">涓婁紶闄勪欢</el-button>
         </el-upload>
       </div>
@@ -15,7 +44,7 @@
           <template #default="scope">
             <el-button link type="primary" @click="previewFile(scope.row)">棰勮</el-button>
             <el-button link type="primary" @click="downloadFile(scope.row)">涓嬭浇</el-button>
-            <el-button link type="danger" @click="removeFile(scope.row)">鍒犻櫎</el-button>
+            <el-button v-if="!readonly" link type="danger" @click="removeFile(scope.row)">鍒犻櫎</el-button>
           </template>
         </el-table-column>
       </el-table>
@@ -51,6 +80,7 @@
   components: {
     filePreview
   },
+  emits: ['closed'],
   props: {
     // 涓婁紶鎺ュ彛鍦板潃锛屽 /supplierManagement/uploadAttachment
     uploadUrl: {
@@ -91,12 +121,54 @@
     tip: {
       type: String,
       default: '鏀寔浠绘剰鏍煎紡鏂囦欢锛屽崟涓枃浠朵笉瓒呰繃200MB'
+    },
+    // 鍙妯″紡锛氫粎棰勮/涓嬭浇锛屼笉鏄剧ず涓婁紶鍜屽垹闄�
+    readonly: {
+      type: Boolean,
+      default: false
+    },
+    // 鍐呭祵妯″紡锛氱洿鎺ユ覆鏌撲笂浼犲尯鍜岄檮浠跺垪琛紝涓嶅脊绠$悊寮圭獥
+    inline: {
+      type: Boolean,
+      default: false
+    },
+    // 鍐呭祵妯″紡鍏宠仈涓昏〃ID锛屽彉鍖栨椂鑷姩鍔犺浇闄勪欢
+    mainId: {
+      type: [String, Number],
+      default: ''
+    },
+    // 鍐呭祵妯″紡鏈叧鑱斾富琛↖D鏃剁殑鎻愮ず
+    emptyTip: {
+      type: String,
+      default: '璇峰厛閫夋嫨鏁版嵁鍚庡啀涓婁紶闄勪欢'
+    },
+    // 鍐呭祵妯″紡锛氭病鏈変富琛↖D鏃朵篃鍏佽閫夋嫨鏂囦欢锛屽厛鏆傚瓨鍦ㄩ〉闈紝鎻愪氦鏃跺啀缁熶竴涓婁紶
+    deferUpload: {
+      type: Boolean,
+      default: false
+    }
+  },
+  watch: {
+    mainId: {
+      immediate: true,
+      handler(val) {
+        if (!this.inline) {
+          return
+        }
+        const field = this.idField || this.idParam
+        this.currentRow = { [field]: val }
+        this.attachmentList = []
+        if (val !== null && val !== undefined && val !== '') {
+          this.loadList()
+        }
+      }
     }
   },
   data() {
     return {
       visible: false,
       attachmentList: [],
+      pendingFiles: [],
       currentRow: {},
       previewVisible: false,
       previewRow: {},
@@ -107,6 +179,19 @@
     currentId() {
       const field = this.idField || this.idParam
       return this.currentRow ? this.currentRow[field] : undefined
+    },
+    canUpload() {
+      return !this.readonly && (!!this.currentId || this.deferUpload)
+    },
+    displayList() {
+      const pending = this.pendingFiles.map(item => ({
+        id: 'pending_' + item.uid,
+        uid: item.uid,
+        fileName: item.fileName,
+        createTime: '寰呬笂浼�',
+        pending: true
+      }))
+      return pending.concat(this.attachmentList)
     },
     dialogTitle() {
       const name = this.nameField && this.currentRow ? this.currentRow[this.nameField] : ''
@@ -171,6 +256,42 @@
     handleUploadError() {
       this.$message.error('涓婁紶澶辫触锛屾枃浠跺彲鑳借秴杩�200MB')
     },
+    // 寤惰繜涓婁紶妯″紡锛氭枃浠跺厛鏆傚瓨鍦ㄩ〉闈紝鎻愪氦淇濆瓨鏃跺啀缁熶竴涓婁紶
+    handleFileChange(file) {
+      if (!this.deferUpload || !file || !file.raw) {
+        return
+      }
+      this.pendingFiles.push({ uid: file.uid, fileName: file.name, raw: file.raw })
+    },
+    removePending(row) {
+      this.pendingFiles = this.pendingFiles.filter(item => item.uid !== row.uid)
+    },
+    // 鎻愪氦鏃惰皟鐢細鎶婃殏瀛樼殑闄勪欢涓婁紶鍒版寚瀹氫富琛↖D锛屽叏閮ㄦ垚鍔熸墠绠楀畬鎴�
+    flushPending(planDetailsId) {
+      if (!this.pendingFiles.length) {
+        return Promise.resolve()
+      }
+      const field = this.idField || this.idParam
+      this.currentRow = { [field]: planDetailsId }
+      return Promise.all(this.pendingFiles.slice().map(item => {
+        const formData = new FormData()
+        formData.append('file', item.raw)
+        return request({
+          url: this.uploadUrl,
+          method: 'post',
+          params: { [this.idParam]: planDetailsId },
+          data: formData,
+          headers: { 'Content-Type': 'multipart/form-data', repeatSubmit: false }
+        }).then(res => {
+          if (!res || res.code !== 200) {
+            throw new Error((res && res.msg) || ('闄勪欢鈥�' + item.fileName + '鈥濅笂浼犲け璐�'))
+          }
+          this.pendingFiles = this.pendingFiles.filter(pending => pending.uid !== item.uid)
+        })
+      })).then(() => {
+        this.loadList()
+      })
+    },
     previewFile(row) {
       this.previewRow = row
       this.previewUrl = this.fullUrl(row.fileUrl)
@@ -201,9 +322,17 @@
 </script>
 
 <style scoped>
+.lims-attachment {
+  width: 100%;
+}
+
 .attachment-header {
   display: flex;
   justify-content: space-between;
   align-items: center;
 }
+
+.attachment-inline {
+  width: 100%;
+}
 </style>
diff --git a/src/views/CNAS/resourceDemand/device/component/checkRecord.vue b/src/views/CNAS/resourceDemand/device/component/checkRecord.vue
index d2ab78a..214d943 100644
--- a/src/views/CNAS/resourceDemand/device/component/checkRecord.vue
+++ b/src/views/CNAS/resourceDemand/device/component/checkRecord.vue
@@ -1,61 +1,125 @@
 <template>
   <div>
     <el-dialog :close-on-click-modal="false" :close-on-press-escape="false" v-model="dialogVisible"
-      :title="currentStep === 0 ? '鏂板鏍告煡璁板綍' : '璁惧鏍告煡璁板綍'" width="50%" @close="resetForm">
-      <el-steps v-if="currentStep === 1" :active="1" align-center finish-status="success">
+      :title="currentStep === 0 ? '鏂板鏍告煡璁板綍' : '璁惧鏍告煡璁板綍'" top="5vh" width="960px" @close="resetForm">
+      <el-steps v-if="currentStep === 1" class="record-steps" :active="1" align-center finish-status="success">
         <el-step title="濉啓鏍告煡璁板綍"></el-step>
         <el-step title="瀹℃牳"></el-step>
       </el-steps>
-      <el-form ref="recordForm" :model="form" :rules="rules" label-width="110px">
-        <el-form-item label="璁惧缂栧彿锛�" prop="deviceNumber">
-          <el-input v-model="form.deviceNumber" disabled size="small"></el-input>
-        </el-form-item>
-        <el-form-item label="璁惧鍚嶇О锛�" prop="deviceName">
-          <el-select v-if="currentStep === 0" v-model="selectedDeviceId" clearable filterable
-            placeholder="璇烽�夋嫨璁惧" size="small" style="width: 100%" @change="changeMachineName">
-            <el-option v-for="item in equipOptions" :key="item.id" :label="item.label + '-' + item.value"
-              :value="item.id"></el-option>
-          </el-select>
-          <el-input v-else v-model="form.deviceName" disabled size="small"></el-input>
-        </el-form-item>
-        <el-form-item label="鏍告煡鏃堕棿锛�" prop="checkTime">
-          <el-date-picker v-model="form.checkTime" :disabled="currentStep !== 0" clearable format="YYYY-MM"
-            placeholder="閫夋嫨鏃ユ湡" size="small" style="width: 100%" type="month" value-format="YYYY-MM">
-          </el-date-picker>
-        </el-form-item>
-        <el-form-item label="鏍告煡鎸囨爣锛�" prop="checkIndex">
-          <el-input v-model="form.checkIndex" :disabled="currentStep !== 0" clearable size="small"></el-input>
-        </el-form-item>
-        <el-form-item label="鏍告煡鏂规硶锛�" prop="checkMethod">
-          <el-input v-model="form.checkMethod" :disabled="currentStep !== 0" clearable size="small"
-            type="textarea"></el-input>
-        </el-form-item>
-        <el-form-item label="缁撴灉濡備綍鍒ゅ畾锛�" prop="howResults">
-          <el-input v-model="form.howResults" :disabled="currentStep !== 0" clearable size="small"
-            type="textarea"></el-input>
-        </el-form-item>
-        <el-form-item label="鏍告煡璐d换浜猴細" prop="checkChargerUserId">
-          <el-select v-if="currentStep === 0" v-model="form.checkChargerUserId" clearable filterable
-            placeholder="璇烽�夋嫨" size="small" style="width: 100%" @change="setCheckChargerUser">
-            <el-option v-for="item in chargerOptions" :key="item.id" :label="item.name"
-              :value="item.id"></el-option>
-          </el-select>
-          <el-input v-else v-model="form.checkChargerUser" disabled size="small"></el-input>
-        </el-form-item>
-        <el-form-item label="澶囨敞锛�" prop="remark">
-          <el-input v-model="form.remark" :disabled="currentStep !== 0" clearable size="small"></el-input>
-        </el-form-item>
-        <el-form-item label="闄勪欢锛�">
-          <el-upload v-if="currentStep === 0" :action="javaApi + '/deviceScope/uploadFile'" :headers="uploadHeader"
-            :limit="1" :on-exceed="handleUploadExceed" :before-upload="beforeAttachmentUpload"
-            :on-success="handleAttachmentSuccess" :on-remove="handleAttachmentRemove">
-            <el-button size="small" type="primary">閫夋嫨闄勪欢</el-button>
-          </el-upload>
-          <el-link v-if="form.fileUrl" type="primary" @click="openAttachment">
-            {{ form.fileName || '鏌ョ湅闄勪欢' }}
-          </el-link>
-          <span v-else-if="currentStep !== 0">鈥�</span>
-        </el-form-item>
+      <el-form ref="recordForm" :model="form" :rules="rules" label-width="104px">
+        <div class="form-section">
+          <div class="form-section-title">鍩烘湰淇℃伅</div>
+          <el-row :gutter="12">
+            <el-col :span="12">
+              <el-form-item label="浠櫒鍚嶇О锛�" prop="deviceName">
+                <el-select v-if="currentStep === 0" v-model="selectedDeviceId" clearable filterable
+                  placeholder="璇烽�夋嫨璁惧" size="small" style="width: 100%" @change="changeMachineName">
+                  <el-option v-for="item in equipOptions" :key="item.id" :label="item.label + '-' + item.value"
+                    :value="item.id"></el-option>
+                </el-select>
+                <el-input v-else 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-if="currentStep === 0" v-model="form.checkTime" clearable format="YYYY-MM-DD"
+                  placeholder="閫夋嫨妫�鏌ユ棩鏈�" size="small" style="width: 100%" type="date" value-format="YYYY-MM-DD"
+                  @change="resolveAttachmentPlan">
+                </el-date-picker>
+                <el-input v-else v-model="form.checkTime" disabled size="small"></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item label="绠$悊缂栧彿锛�" prop="deviceNumber">
+                <el-input v-model="form.deviceNumber" disabled size="small"></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item label="璁惧鍨嬪彿锛�" prop="deviceModel">
+                <el-input v-model="form.deviceModel" disabled size="small"></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item label="鏍告煡浜猴細" prop="checkChargerUserId">
+                <el-select v-if="currentStep === 0" v-model="form.checkChargerUserId" clearable filterable
+                  placeholder="璇烽�夋嫨" size="small" style="width: 100%" @change="setCheckChargerUser">
+                  <el-option v-for="item in chargerOptions" :key="item.id" :label="item.name"
+                    :value="item.id"></el-option>
+                </el-select>
+                <el-input v-else v-model="form.checkChargerUser" disabled size="small"></el-input>
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </div>
+        <div class="form-section">
+          <div class="form-section-title">鏍告煡鍐呭</div>
+          <el-row :gutter="12">
+            <el-col :span="8">
+              <el-form-item label="鐜娓╂箍搴︼細" prop="environment">
+                <el-input v-model="form.environment" :disabled="currentStep !== 0" clearable size="small"
+                  placeholder="濡傦細25鈩� / 50%RH"></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item label="鏍告煡渚濇嵁锛�" prop="checkBasis">
+                <el-input v-model="form.checkBasis" :disabled="currentStep !== 0" clearable size="small"></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item label="鏍告煡鎸囨爣锛�" prop="checkIndex">
+                <el-input v-model="form.checkIndex" :disabled="currentStep !== 0" clearable size="small"></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item label="鏍告煡鏂瑰紡锛�" prop="checkMethod">
+                <el-input v-model="form.checkMethod" :disabled="currentStep !== 0" clearable :rows="2" size="small"
+                  type="textarea"></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item label="缁撴灉濡備綍鍒ゅ畾锛�" prop="howResults">
+                <el-input v-model="form.howResults" :disabled="currentStep !== 0" clearable :rows="2" size="small"
+                  type="textarea"></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item label="澶栬鎯呭喌锛�">
+                <el-radio-group v-model="form.appearanceStatus" :disabled="currentStep !== 0">
+                  <el-radio value="鑹ソ">鑹ソ</el-radio>
+                  <el-radio value="涓�鑸�">涓�鑸�</el-radio>
+                  <el-radio value="鎹熷潖">鎹熷潖</el-radio>
+                </el-radio-group>
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item label="杩愯鐘舵�侊細">
+                <el-radio-group v-model="form.runningStatus" :disabled="currentStep !== 0">
+                  <el-radio value="姝e父">姝e父</el-radio>
+                  <el-radio value="寮傚父">寮傚父</el-radio>
+                  <el-radio value="鍋滄満">鍋滄満</el-radio>
+                </el-radio-group>
+              </el-form-item>
+            </el-col>
+            <el-col :span="24">
+              <el-form-item label="澶囨敞锛�" prop="remark">
+                <el-input v-model="form.remark" :disabled="currentStep !== 0" clearable size="small"></el-input>
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </div>
+        <div class="form-section">
+          <div class="form-section-title">闄勪欢璧勬枡</div>
+          <el-form-item label-width="0">
+            <lims-attachment ref="recordAttachment" inline upload-url="/deviceExaminePlan/uploadAttachment"
+              select-url="/deviceExaminePlan/selectAttachments" delete-url="/deviceExaminePlan/deleteAttachment"
+              id-param="planDetailsId" name-field="deviceName" title="鏍告煡璁板綍闄勪欢"
+              :main-id="form.planDetailsId" :readonly="currentStep === 1"
+              :defer-upload="currentStep === 0" :tip="attachmentTip"></lims-attachment>
+            <el-link v-if="form.fileUrl" type="primary" @click="openAttachment">
+              {{ form.fileName || '鏌ョ湅鍘熼檮浠�' }}
+            </el-link>
+          </el-form-item>
+        </div>
       </el-form>
       <template #footer><span class="dialog-footer">
         <el-button @click="resetForm">鍙� 娑�</el-button>
@@ -74,22 +138,28 @@
   addExamineRecord,
   reviewExamineRecord,
   deviceScopeSearch,
+  findExaminePlanDetail,
   resolveExaminePlanDetail,
   updateDeviceExaminePlanDetail,
 } from '@/api/cnas/resourceDemand/device.js'
 import { selectUserCondition } from "@/api/performance/class";
-import draftSave from '@/mixins/draftSave'
+import LimsAttachment from '@/components/Attachment/lims-attachment.vue'
 
 const createEmptyForm = () => ({
   deviceId: '',
   deviceName: '',
   deviceNumber: '',
+  deviceModel: '',
   checkTime: '',
   checkIndex: '',
   checkMethod: '',
   howResults: '',
   checkChargerUserId: '',
   checkChargerUser: '',
+  environment: '',
+  checkBasis: '',
+  appearanceStatus: '',
+  runningStatus: '',
   remark: '',
   fileName: '',
   fileUrl: '',
@@ -97,7 +167,7 @@
 })
 export default {
   name: "check-record",
-  mixins: [draftSave],
+  components: { LimsAttachment },
   data() {
     // 杩欓噷瀛樻斁鏁版嵁
     return {
@@ -109,7 +179,7 @@
       submitFormLoading: false,
       userList: [],
       rules: {
-        checkMethod: [{ required: true, message: '璇峰~鍐欐牳鏌ユ柟娉�', trigger: 'blur' }],
+        checkMethod: [{ required: true, message: '璇峰~鍐欐牳鏌ユ柟寮�', trigger: 'blur' }],
       },
     }
   },
@@ -124,12 +194,17 @@
         deviceId: row.deviceId || '',
         deviceName: row.deviceName || '',
         deviceNumber: row.deviceNumber || '',
-        checkTime: (row.checkTime || '').substring(0, 7),
+        deviceModel: row.deviceModel || '',
+        checkTime: row.checkTime || '',
         checkIndex: row.checkIndex || '',
         checkMethod: row.checkMethod || '',
         howResults: row.howResults || '',
         checkChargerUserId: row.checkChargerUserId || '',
         checkChargerUser: row.checkChargerUser || '',
+        environment: row.environment || '',
+        checkBasis: row.checkBasis || '',
+        appearanceStatus: row.appearanceStatus || '',
+        runningStatus: row.runningStatus || '',
         remark: row.remark || '',
         fileName: row.fileName || '',
         fileUrl: row.fileUrl || '',
@@ -143,17 +218,14 @@
       this.form = createEmptyForm()
       this.selectedDeviceId = ''
       const now = new Date()
-      this.form.checkTime = now.getFullYear() + '-' + String(now.getMonth() + 1).padStart(2, '0')
+      this.form.checkTime = now.getFullYear() + '-' + String(now.getMonth() + 1).padStart(2, '0') + '-' + String(now.getDate()).padStart(2, '0')
       this.getEquipOptions()
       this.getUserList()
       this.$nextTick(() => {
         if (this.$refs.recordForm) {
           this.$refs.recordForm.clearValidate()
         }
-        this.draftRestore('checkRecordForm', 'form', 'new', 'dialogVisible')
-        if (this.form.deviceId) {
-          this.selectedDeviceId = this.form.deviceId
-        }
+        this.resolveAttachmentPlan()
       })
     },
     // 鎸夎澶� id 鍥炲~鍚嶇О鍜岀紪鍙凤紝閬垮厤鍚屽悕璁惧閫夐敊
@@ -163,11 +235,14 @@
         this.form.deviceId = item.id
         this.form.deviceName = item.deviceName
         this.form.deviceNumber = item.managementNumber
+        this.form.deviceModel = item.specificationModel || ''
       } else {
         this.form.deviceId = ''
         this.form.deviceName = ''
         this.form.deviceNumber = ''
+        this.form.deviceModel = ''
       }
+      this.resolveAttachmentPlan()
     },
     setCheckChargerUser(value) {
       const item = this.userList.find(user => user.id === value)
@@ -214,28 +289,40 @@
       if (this.form.howResults) params.howResults = this.form.howResults
       if (this.form.checkChargerUserId) params.checkChargerUserId = this.form.checkChargerUserId
       if (this.form.checkChargerUser) params.checkChargerUser = this.form.checkChargerUser
+      if (this.form.deviceModel) params.deviceModel = this.form.deviceModel
+      params.environment = this.form.environment || ''
+      params.checkBasis = this.form.checkBasis || ''
+      params.appearanceStatus = this.form.appearanceStatus || ''
+      params.runningStatus = this.form.runningStatus || ''
       if (this.form.remark) params.remark = this.form.remark
       if (this.form.fileName) params.fileName = this.form.fileName
       if (this.form.fileUrl) params.fileUrl = this.form.fileUrl
-      updateDeviceExaminePlanDetail(params).then(res => {
-        if (res.code !== 200) {
-          this.$message.error(res.msg || '淇濆瓨鏍告煡璁板綍澶辫触')
-          this.submitFormLoading = false
-          return
-        }
-        addExamineRecord({ planDetailsId }).then(recordRes => {
-          if (recordRes.code == 200) {
-            this.$message.success('鏍告煡璁板綍宸叉彁浜わ紝绛夊緟瀹℃牳')
-            this.draftClear('checkRecordForm')
-            this.resetForm()
-          } else {
-            this.$message.error(recordRes.msg || '鎻愪氦鏍告煡璁板綍澶辫触')
+      // 闄勪欢鍏堟殏瀛樺湪椤甸潰涓婏紝纭鎻愪氦鏃跺啀杩炲悓鏍告煡璁板綍涓�璧蜂繚瀛橈紝鍙栨秷鍒欎粈涔堥兘涓嶇暀
+      const attachmentRef = this.$refs.recordAttachment
+      const flushPending = attachmentRef ? attachmentRef.flushPending(planDetailsId) : Promise.resolve()
+      flushPending.then(() => {
+        updateDeviceExaminePlanDetail(params).then(res => {
+          if (res.code !== 200) {
+            this.$message.error(res.msg || '淇濆瓨鏍告煡璁板綍澶辫触')
+            this.submitFormLoading = false
+            return
           }
-          this.submitFormLoading = false
+          addExamineRecord({ planDetailsId }).then(recordRes => {
+            if (recordRes.code == 200) {
+              this.$message.success('鏍告煡璁板綍宸叉彁浜わ紝绛夊緟瀹℃牳')
+              this.resetForm()
+            } else {
+              this.$message.error(recordRes.msg || '鎻愪氦鏍告煡璁板綍澶辫触')
+            }
+            this.submitFormLoading = false
+          }).catch(() => {
+            this.submitFormLoading = false
+          })
         }).catch(() => {
           this.submitFormLoading = false
         })
       }).catch(() => {
+        // 涓婁紶澶辫触鐨勫叿浣撳師鍥犵敱 request 鎷︽埅鍣ㄧ粺涓�鎻愮ず
         this.submitFormLoading = false
       })
     },
@@ -249,7 +336,6 @@
       reviewExamineRecord(params).then(res => {
         if (res.code == 200) {
           this.$message.success(statue === 1 ? '瀹℃牳閫氳繃' : '宸查��鍥�')
-          this.draftClear('checkRecordForm')
           this.resetForm()
         }
         this.submitFormLoading = false
@@ -258,7 +344,6 @@
       })
     },
     resetForm() {
-      this.draftStop('checkRecordForm')
       this.dialogVisible = false
       this.$emit('closeDialog1')
     },
@@ -283,30 +368,27 @@
         this.userList = res.data
       })
     },
-    // 闄勪欢
-    beforeAttachmentUpload(file) {
-      if (file.size > 1024 * 1024 * 10) {
-        this.$message.error('涓婁紶鏂囦欢涓嶈秴杩�10M')
-        return false
+    // 闄勪欢鍐呭祵鍦ㄨ〃鍗曢噷锛氳澶�+鏃ユ湡纭畾鍚庡彧鏌ュ彲澶嶇敤鏄庣粏锛屼笉鎻愬墠寤烘。锛岄伩鍏嶅彇娑堝悗鐣欎笅绌鸿褰�
+    resolveAttachmentPlan() {
+      if (this.currentStep !== 0 || !this.selectedDeviceId || !this.form.checkTime) {
+        this.form.planDetailsId = ''
+        return
       }
-      return true
+      const deviceId = this.selectedDeviceId
+      const checkTime = this.form.checkTime
+      this.form.planDetailsId = ''
+      findExaminePlanDetail({ deviceId, checkTime }).then(res => {
+        if (res.code !== 200 || !res.data) {
+          return
+        }
+        // 璇锋眰鏈熼棿鐢ㄦ埛鍙兘宸插垏鎹㈣澶囨垨鏃ユ湡锛岄伩鍏嶅洖濉繃鏈熸槑缁�
+        if (this.selectedDeviceId === deviceId && this.form.checkTime === checkTime) {
+          this.form.planDetailsId = res.data.planDetailsId
+        }
+      }).catch(() => {
+      })
     },
-    handleUploadExceed() {
-      this.$message.warning('浠呮敮鎸佷竴涓檮浠讹紝璇峰厛绉婚櫎宸蹭笂浼犵殑闄勪欢')
-    },
-    handleAttachmentSuccess(response) {
-      if (response.code == 200) {
-        this.form.fileName = response.data.name
-        this.form.fileUrl = response.data.url
-        this.$message.success('闄勪欢涓婁紶鎴愬姛')
-      } else {
-        this.$message.error(response.msg || '闄勪欢涓婁紶澶辫触')
-      }
-    },
-    handleAttachmentRemove() {
-      this.form.fileName = ''
-      this.form.fileUrl = ''
-    },
+    // 鍏煎鍘嗗彶鍗曢檮浠�
     openAttachment() {
       if (!this.form.fileUrl) {
         return
@@ -316,6 +398,10 @@
     },
   },
   computed: {
+    // 闄勪欢涓嶆彁鍓嶄笂浼狅紝閫夊ソ鍚庨殢鏍告煡璁板綍涓�璧锋彁浜や繚瀛�
+    attachmentTip() {
+      return '鍙洿鎺ラ�夋嫨闄勪欢锛岀偣鈥滅‘璁も�濇椂闅忔牳鏌ヨ褰曚竴璧蜂繚瀛�'
+    },
     // 璐d换浜轰笅鎷夛細宸蹭繚瀛樼殑璐d换浜轰笉鍦ㄥ�欓�夊垪琛ㄦ椂琛ヤ竴鏉★紝閬垮厤鍥炴樉鎴愮敤鎴稩D
     chargerOptions() {
       const list = this.userList || []
@@ -328,3 +414,36 @@
   },
 }
 </script>
+
+<style scoped>
+.record-steps {
+  margin-bottom: 14px;
+}
+
+.form-section {
+  padding: 12px 14px 0;
+  border: 1px solid #ebeef5;
+  border-radius: 6px;
+  margin-bottom: 10px;
+}
+
+.form-section:last-child {
+  margin-bottom: 0;
+}
+
+.form-section-title {
+  display: flex;
+  align-items: center;
+  padding-left: 8px;
+  border-left: 3px solid var(--el-color-primary);
+  margin-bottom: 12px;
+  font-size: 14px;
+  font-weight: 600;
+  line-height: 1;
+  color: #303133;
+}
+
+.form-section :deep(.el-form-item) {
+  margin-bottom: 12px;
+}
+</style>
diff --git a/src/views/CNAS/resourceDemand/device/component/equipmentVerificationPlan.vue b/src/views/CNAS/resourceDemand/device/component/equipmentVerificationPlan.vue
index 26aceb1..b79641d 100644
--- a/src/views/CNAS/resourceDemand/device/component/equipmentVerificationPlan.vue
+++ b/src/views/CNAS/resourceDemand/device/component/equipmentVerificationPlan.vue
@@ -4,14 +4,14 @@
     <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>
+          <span class="title" style="margin-bottom: 0;">{{ planInfo.planName || (planYear ? 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>
           <el-button size="small" type="primary" @click="handleAddRecord">鏂板鏍告煡璁板綍</el-button>
-          <el-button size="small" type="primary" @click="loadPlan">鍒锋柊</el-button>
+          <el-button size="small" type="primary" @click="loadYearOptions">鍒锋柊</el-button>
           <el-button size="small" type="primary" @click="downLoadPost">瀵煎嚭</el-button>
         </div>
       </div>
@@ -57,7 +57,7 @@
         <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">
+        <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>
@@ -65,18 +65,13 @@
             <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 label="闄勪欢" min-width="140">
           <template #default="scope">
-            <el-link v-if="scope.row.fileUrl" type="primary" @click="openAttachment(scope.row)">
+            <el-link v-if="scope.row.attachmentCount > 0" type="primary" @click="handleAttachment(scope.row)">
+              鏌ョ湅闄勪欢锛坽{ scope.row.attachmentCount }}锛�
+            </el-link>
+            <el-link v-else-if="scope.row.fileUrl" type="primary" @click="openAttachment(scope.row)">
               {{ scope.row.fileName || '鏌ョ湅闄勪欢' }}
             </el-link>
             <span v-else>鈥�</span>
@@ -86,17 +81,14 @@
         <el-table-column align="center" fixed="right" label="鎿嶄綔" min-width="320">
           <template #default="scope">
             <el-button size="small" link type="primary"
+              :disabled="scope.row.recordStatus === 2 || scope.row.recordStatus === 3"
               @click="handleForm('edit', scope.row)">缂栬緫</el-button>
             <el-button size="small" link type="primary" @click="handleForm('view', scope.row)">鏌ョ湅</el-button>
-            <el-button v-if="scope.row.recordStatus === 1" size="small" link type="primary"
+            <el-button v-if="scope.row.recordStatus === 0 || scope.row.recordStatus === 1"
+              size="small" link type="primary" :disabled="!scope.row.checkChargerUser"
               @click="handleRecord(scope.row)">瀹℃牳</el-button>
-            <el-upload class="row-upload" :action="javaApi + '/deviceScope/uploadFile'"
-              :headers="uploadHeader" :show-file-list="false" :before-upload="beforeAttachmentUpload"
-              :on-success="(res) => handleAttachmentSuccess(res, scope.row)"
-              :on-error="handleAttachmentError">
-              <el-button size="small" link type="primary">涓婁紶闄勪欢</el-button>
-            </el-upload>
-            <el-button size="small" link type="primary" @click="handleDown(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"
               size="small" link type="danger" @click="deleteFun1(scope.row.planDetailsId)">鍒犻櫎</el-button>
           </template>
@@ -108,44 +100,116 @@
         @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="50%" @close="resetForm">
-      <el-form ref="modelForm" :model="form" :rules="rules" label-width="110px">
-        <el-form-item label="璁惧缂栧彿锛�" prop="deviceNumber">
-          <el-input v-model="form.deviceNumber" :disabled="operationType === 'view'" clearable
-            size="small"></el-input>
-        </el-form-item>
-        <el-form-item label="璁惧鍚嶇О锛�" prop="deviceName">
-          <el-input v-model="form.deviceName" :disabled="operationType === 'view'" clearable
-            size="small"></el-input>
-        </el-form-item>
-        <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-form-item>
-        <el-form-item label="鏍告煡鎸囨爣锛�" prop="checkIndex">
-          <el-input v-model="form.checkIndex" :disabled="operationType === 'view'" clearable
-            size="small"></el-input>
-        </el-form-item>
-        <el-form-item label="鏍告煡鏂规硶锛�" prop="checkMethod">
-          <el-input v-model="form.checkMethod" :disabled="operationType === 'view'" clearable size="small"
-            type="textarea"></el-input>
-        </el-form-item>
-        <el-form-item label="缁撴灉濡備綍鍒ゅ畾锛�" prop="howResults">
-          <el-input v-model="form.howResults" :disabled="operationType === 'view'" clearable size="small"
-            type="textarea"></el-input>
-        </el-form-item>
-        <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 chargerOptions" :key="item.id" :label="item.name"
-              :value="item.id"></el-option>
-          </el-select>
-        </el-form-item>
-        <el-form-item label="澶囨敞锛�" prop="remark">
-          <el-input v-model="form.remark" :disabled="operationType === 'view'" clearable size="small"></el-input>
-        </el-form-item>
+    <el-dialog :close-on-click-modal="false" :close-on-press-escape="false" v-model="dialogVisible"
+      :title="operationType === 'view' ? '璁惧鏍告煡璁板綍' : '缂栬緫鏍告煡璁板綍'" top="5vh" width="960px" @close="resetForm">
+      <el-form ref="modelForm" :model="form" :rules="rules" label-width="104px">
+        <div class="form-section">
+          <div class="form-section-title">鍩烘湰淇℃伅</div>
+          <el-row :gutter="12">
+            <el-col :span="12">
+              <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-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item label="绠$悊缂栧彿锛�" prop="deviceNumber">
+                <el-input v-model="form.deviceNumber" disabled size="small"></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item label="璁惧鍨嬪彿锛�" prop="deviceModel">
+                <el-input v-model="form.deviceModel" disabled size="small"></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item label="鏍告煡浜猴細" prop="checkChargerUserId">
+                <el-select v-model="form.checkChargerUserId" @change="setCheckChargerUser" clearable filterable
+                  :disabled="operationType === 'view'" placeholder="璇烽�夋嫨" size="small" style="width: 100%">
+                  <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>
+          </el-row>
+        </div>
+        <div class="form-section">
+          <div class="form-section-title">鏍告煡鍐呭</div>
+          <el-row :gutter="12">
+            <el-col :span="8">
+              <el-form-item label="鐜娓╂箍搴︼細" prop="environment">
+                <el-input v-model="form.environment" :disabled="operationType === 'view'" clearable size="small"
+                  placeholder="濡傦細25鈩� / 50%RH"></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item label="鏍告煡渚濇嵁锛�" prop="checkBasis">
+                <el-input v-model="form.checkBasis" :disabled="operationType === 'view'" clearable
+                  size="small"></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item label="鏍告煡鎸囨爣锛�" prop="checkIndex">
+                <el-input v-model="form.checkIndex" :disabled="operationType === 'view'" clearable
+                  size="small"></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item label="鏍告煡鏂瑰紡锛�" prop="checkMethod">
+                <el-input v-model="form.checkMethod" :disabled="operationType === 'view'" clearable :rows="2"
+                  size="small" type="textarea"></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item label="缁撴灉濡備綍鍒ゅ畾锛�" prop="howResults">
+                <el-input v-model="form.howResults" :disabled="operationType === 'view'" clearable :rows="2"
+                  size="small" type="textarea"></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item label="澶栬鎯呭喌锛�">
+                <el-radio-group v-model="form.appearanceStatus" :disabled="operationType === 'view'">
+                  <el-radio value="鑹ソ">鑹ソ</el-radio>
+                  <el-radio value="涓�鑸�">涓�鑸�</el-radio>
+                  <el-radio value="鎹熷潖">鎹熷潖</el-radio>
+                </el-radio-group>
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item label="杩愯鐘舵�侊細">
+                <el-radio-group v-model="form.runningStatus" :disabled="operationType === 'view'">
+                  <el-radio value="姝e父">姝e父</el-radio>
+                  <el-radio value="寮傚父">寮傚父</el-radio>
+                  <el-radio value="鍋滄満">鍋滄満</el-radio>
+                </el-radio-group>
+              </el-form-item>
+            </el-col>
+            <el-col :span="24">
+              <el-form-item label="澶囨敞锛�" prop="remark">
+                <el-input v-model="form.remark" :disabled="operationType === 'view'" clearable size="small"></el-input>
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </div>
+        <div class="form-section">
+          <div class="form-section-title">闄勪欢璧勬枡</div>
+          <el-form-item label-width="0">
+            <lims-attachment inline upload-url="/deviceExaminePlan/uploadAttachment"
+              select-url="/deviceExaminePlan/selectAttachments" delete-url="/deviceExaminePlan/deleteAttachment"
+              id-param="planDetailsId" name-field="deviceName" title="鏍告煡璁板綍闄勪欢"
+              :main-id="form.planDetailsId" :readonly="operationType === 'view'"></lims-attachment>
+            <el-link v-if="form.fileUrl" type="primary" @click="openAttachment(form)">
+              {{ form.fileName || '鏌ョ湅鍘熼檮浠�' }}
+            </el-link>
+          </el-form-item>
+        </div>
       </el-form>
       <template #footer><span class="dialog-footer">
         <el-button @click="resetForm">鍙� 娑�</el-button>
@@ -153,23 +217,47 @@
           v-if="operationType !== 'view'">纭� 璁�</el-button>
       </span></template>
     </el-dialog>
-    <el-dialog v-model="downloadDialog" title="瀵煎嚭" width="600px">
-      <span>
-        <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>
+    <el-dialog v-model="downloadDialog" title="瀵煎嚭" width="480px">
+      <div class="export-panel">
+        <div class="export-panel-head">
+          <span class="export-panel-name">浠櫒璁惧鏈熼棿鏍告煡璁板綍琛�</span>
+          <el-tag v-if="downRow.recordStatus === 2" type="success" disable-transitions>閫氳繃</el-tag>
+          <el-tag v-else-if="downRow.recordStatus === 1" type="warning" disable-transitions>寰呮壒鍑�</el-tag>
+          <el-tag v-else-if="downRow.recordStatus === 3" type="danger" disable-transitions>涓嶉�氳繃</el-tag>
+          <el-tag v-else type="info" disable-transitions>鏈紑濮�</el-tag>
+        </div>
+        <div class="export-panel-meta">
+          <div class="export-panel-item">
+            <span class="export-panel-label">璁惧缂栧彿</span>{{ downRow.deviceNumber || '鈥�' }}
+          </div>
+          <div class="export-panel-item">
+            <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) || '鈥�' }}
+          </div>
+        </div>
+        <div v-if="!canExport" class="export-panel-tip">
+          {{ downRow.recordStatus === 1 ? '璇ヨ鍒掕灏氭湭瀹℃牳瀹屾垚锛屽鏍搁�氳繃鎴栦笉閫氳繃鍚庢墠鑳藉鍑恒��' : '璇ヨ鍒掕杩樻病鏈夋牳鏌ヨ褰曪紝褰曞叆骞舵彁浜ゅ鏍稿悗鎵嶈兘瀵煎嚭銆�' }}
+        </div>
+      </div>
       <template #footer><span class="dialog-footer">
         <el-button @click="downloadDialog = false">鍙� 娑�</el-button>
+        <el-button :loading="outLoading" type="primary" :disabled="!canExport"
+          @click="controlDown">瀵煎嚭璁板綍琛�</el-button>
       </span></template>
     </el-dialog>
     <check-record v-if="checkRecord" ref="checkRecord" @closeDialog1="closeDialog1"></check-record>
+    <lims-attachment ref="rowAttachment" upload-url="/deviceExaminePlan/uploadAttachment"
+      select-url="/deviceExaminePlan/selectAttachments" delete-url="/deviceExaminePlan/deleteAttachment"
+      id-param="planDetailsId" name-field="deviceName" title="鏍告煡璁板綍闄勪欢" :readonly="attachmentReadonly"
+      @closed="getYearTableDetailData"></lims-attachment>
   </div>
 </template>
 
 <script>
 import CheckRecord from "./checkRecord.vue";
+import LimsAttachment from '@/components/Attachment/lims-attachment.vue'
 import {
   pageDeviceExaminePlan,
   getExaminePlanByYear,
@@ -186,7 +274,7 @@
 export default {
   name: "equipment-verification-plan",
   // import 寮曞叆鐨勭粍浠堕渶瑕佹敞鍏ュ埌瀵硅薄涓墠鑳戒娇鐢�
-  components: { CheckRecord },
+  components: { CheckRecord, LimsAttachment },
   mixins: [draftSave],
   props: {
     clickNodeVal: {
@@ -216,24 +304,31 @@
       form: {
         deviceNumber: '',
         deviceName: '',
+        deviceModel: '',
         checkTime: '',
         checkIndex: '',
         checkMethod: '',
         howResults: '',
         checkChargerUserId: '',
         checkChargerUser: '',
+        environment: '',
+        checkBasis: '',
+        appearanceStatus: '',
+        runningStatus: '',
         remark: '',
+        fileName: '',
+        fileUrl: '',
         planId: '',
         planDetailsId: '',
       },
       operationType: '',
       rules: {
-        deviceNumber: [{ required: true, message: '璇峰~鍐欒澶囩紪鍙�', trigger: 'blur' }],
-        checkMethod: [{ required: true, message: '璇峰~鍐欐牳鏌ユ柟娉�', trigger: 'blur' }],
+        checkMethod: [{ required: true, message: '璇峰~鍐欐牳鏌ユ柟寮�', trigger: 'blur' }],
       },
       yearTableDetailDataLoading: false,
       submitFormLoading: false,
       userList: [],
+      attachmentReadonly: false,
       checkRecord: false,
       downloadDialog: false,
       outLoading: false,
@@ -245,7 +340,7 @@
   },
   // 鏂规硶闆嗗悎
   methods: {
-    // 骞翠唤涓嬫媺閫夐」锛氬凡鏈夎鍒掑勾浠� + 褰撳墠骞翠唤
+    // 骞翠唤涓嬫媺鍙繚鐣欐湁璁″垝鏄庣粏鐨勫勾浠斤紝绌哄勾浠借嚜鍔ㄦ秷澶�
     loadYearOptions() {
       pageDeviceExaminePlan({
         current: 1,
@@ -255,12 +350,19 @@
         if (res.code == 200) {
           years = (res.data.records || []).map(r => r.planYear).filter(Boolean)
         }
-        const currentYear = String(new Date().getFullYear())
-        if (years.indexOf(currentYear) === -1) {
-          years.push(currentYear)
+        const options = [...new Set(years)].sort((a, b) => b.localeCompare(a))
+        this.yearOptions = options
+        if (options.length === 0) {
+          this.planYear = ''
+          this.planInfo = {}
+          this.yearTableDetailData = []
+          this.pagination1.total = 0
+          return
         }
-        this.yearOptions = [...new Set(years)].sort((a, b) => b.localeCompare(a))
-        this.planYear = currentYear
+        if (options.indexOf(this.planYear) === -1) {
+          const currentYear = String(new Date().getFullYear())
+          this.planYear = options.indexOf(currentYear) > -1 ? currentYear : options[0]
+        }
         this.loadPlan()
       })
     },
@@ -271,6 +373,12 @@
     },
     // 鏌ヨ骞翠唤璁″垝锛堜笉瀛樺湪鑷姩鍒涘缓骞惰ˉ鍏ㄥ埌鐐规槑缁嗭級锛岄殢鍚庡埛鏂版槑缁�
     loadPlan() {
+      if (!this.planYear) {
+        this.planInfo = {}
+        this.yearTableDetailData = []
+        this.pagination1.total = 0
+        return
+      }
       getExaminePlanByYear({ planYear: this.planYear }).then(res => {
         if (res.code == 200) {
           this.planInfo = res.data || {}
@@ -311,19 +419,27 @@
       })
     },
     // 鍒扮偣闇�鏍告煡鐨勮鏍囩孩
-    // 鏍告煡鏃堕棿鎸夋湀浠芥樉绀猴紙鍏煎鍘嗗彶鏁版嵁涓殑瀹屾暣鏃ユ湡锛�
+    // 鎵嬪姩褰曞叆鐨勬牳鏌ユ棩鏈熸樉绀哄埌鏃ワ紝绯荤粺鐧昏鐨勬湀浠芥暟鎹粛鎸夊勾鏈堟樉绀�
     formatCheckMonth(row, column, cellValue) {
       if (cellValue === null || cellValue === undefined || cellValue === '') {
         return cellValue
       }
       const str = String(cellValue).trim().replace(/[./]/g, '-')
+      const dateMatched = str.match(/^(\d{4})-(\d{1,2})-(\d{1,2})/)
+      if (dateMatched) {
+        return `${dateMatched[1]}-${dateMatched[2].padStart(2, '0')}-${dateMatched[3].padStart(2, '0')}`
+      }
       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
+      const fallback = String(formatted).match(/^(\d{4})-(\d{1,2})-(\d{1,2})/)
+      if (fallback) {
+        return `${fallback[1]}-${fallback[2].padStart(2, '0')}-${fallback[3].padStart(2, '0')}`
+      }
+      const monthFallback = String(formatted).match(/^(\d{4})-(\d{1,2})/)
+      return monthFallback ? `${monthFallback[1]}-${monthFallback[2].padStart(2, '0')}` : cellValue
     },
     tableRowClassName({ row }) {
       return row.redFlag === 1 ? 'red-row' : ''
@@ -380,14 +496,14 @@
     },
     // 鏄庣粏-鍒犻櫎
     deleteFun1(id) {
-      this.$confirm('姝ゆ搷浣滃皢姘镐箙鍒犻櫎璇ユ潯鏄庣粏, 鏄惁缁х画?', '鎻愮ず', {
+      this.$confirm('鍒犻櫎鍚庯紝鑻ヨ璁惧杩樻湁瀹℃牳閫氳繃鐨勬牳鏌ヨ褰曪紝妗f鐨勬渶杩戞牳鏌ユ棩鏈熷皢鍥為��鍒版渶杩戜竴娆″畬鎴愯褰曪紱鑻ユ病鏈夛紝鍒欐竻绌烘。妗堢殑鏍告煡鏃ユ湡鍜屾牳鏌ュ懆鏈熴�傛槸鍚︾户缁�?', '鎻愮ず', {
         confirmButtonText: '纭畾',
         cancelButtonText: '鍙栨秷',
         type: 'warning'
       }).then(() => {
         delDeviceExaminePlanDetail({ planDetailsId: id }).then(res => {
           this.$message.success('鍒犻櫎鎴愬姛锛�');
-          this.getYearTableDetailData()
+          this.loadYearOptions()
         });
       }).catch(() => {
         this.$message({
@@ -426,39 +542,15 @@
       const isImage = /\.(jpg|jpeg|png|gif)$/i.test(row.fileUrl)
       window.open(this.javaApi + (isImage ? '/img/' : '/word/') + row.fileUrl, '_blank')
     },
-    beforeAttachmentUpload(file) {
-      if (file.size > 1024 * 1024 * 10) {
-        this.$message.error('涓婁紶鏂囦欢涓嶈秴杩�10M')
-        return false
-      }
-      return true
-    },
-    // 闄勪欢涓婁紶鎴愬姛鍚庝繚瀛樺埌璁″垝鏄庣粏
-    handleAttachmentSuccess(response, row) {
-      if (response.code == 200) {
-        updateDeviceExaminePlanDetail({
-          planDetailsId: row.planDetailsId,
-          fileName: response.data.name,
-          fileUrl: response.data.url
-        }).then(res => {
-          if (res.code == 200) {
-            this.$message.success('闄勪欢涓婁紶鎴愬姛')
-            this.getYearTableDetailData()
-          } else {
-            this.$message.error(res.msg || '闄勪欢淇濆瓨澶辫触')
-          }
-        })
-      } else {
-        this.$message.error(response.msg || '闄勪欢涓婁紶澶辫触')
-      }
-    },
-    handleAttachmentError() {
-      this.$message.error('闄勪欢涓婁紶澶辫触')
+    // 鍒楄〃闄勪欢鍒楀彧璇绘煡鐪嬶紙涓婁紶/鍒犻櫎鍏ュ彛鍙湪缂栬緫銆佹柊澧炲脊绐楀唴锛�
+    handleAttachment(row) {
+      this.attachmentReadonly = true
+      this.$refs.rowAttachment.open(row)
     },
     // 鍏抽棴璁板綍寮规
     closeDialog1() {
       this.checkRecord = false
-      this.getYearTableDetailData()
+      this.loadYearOptions()
     },
     // 鎵撳紑瀵煎嚭寮规
     handleDown(row) {
@@ -519,6 +611,10 @@
     // 鏄惁宸插畬鎴愬鎵癸紙鎵瑰噯/涓嶆壒鍑嗭級
     isRatified() {
       return this.planInfo.ratifyStatus === 0 || this.planInfo.ratifyStatus === 1;
+    },
+    // 璁板綍鐘舵�佷负閫氳繃鎴栦笉閫氳繃锛堝鏍稿凡缁撴潫锛夋墠鍏佽瀵煎嚭
+    canExport() {
+      return this.downRow.recordStatus === 2 || this.downRow.recordStatus === 3;
     },
     // 璐d换浜轰笅鎷夛細宸蹭繚瀛樼殑璐d换浜轰笉鍦ㄥ�欓�夊垪琛ㄦ椂琛ヤ竴鏉★紝閬垮厤鍥炴樉鎴愮敤鎴稩D
     chargerOptions() {
@@ -589,9 +685,80 @@
   background: #ffcccc !important;
 }
 
-.row-upload {
-  display: inline-block;
-  margin-left: 10px;
-  vertical-align: middle;
+.form-section {
+  padding: 12px 14px 0;
+  border: 1px solid #ebeef5;
+  border-radius: 6px;
+  margin-bottom: 10px;
+}
+
+.form-section:last-child {
+  margin-bottom: 0;
+}
+
+.form-section-title {
+  display: flex;
+  align-items: center;
+  padding-left: 8px;
+  border-left: 3px solid var(--el-color-primary);
+  margin-bottom: 12px;
+  font-size: 14px;
+  font-weight: 600;
+  line-height: 1;
+  color: #303133;
+}
+
+.form-section :deep(.el-form-item) {
+  margin-bottom: 12px;
+}
+
+.export-panel {
+  border: 1px solid #e4e7ed;
+  border-radius: 6px;
+  padding: 18px 20px;
+  background: #fafbfc;
+}
+
+.export-panel-head {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  gap: 12px;
+  margin-bottom: 14px;
+}
+
+.export-panel-name {
+  font-size: 15px;
+  font-weight: 600;
+  color: var(--lims-text);
+}
+
+.export-panel-meta {
+  display: flex;
+  flex-direction: column;
+  gap: 8px;
+  font-size: 13px;
+  color: #606266;
+}
+
+.export-panel-item {
+  display: flex;
+  align-items: center;
+}
+
+.export-panel-label {
+  width: 72px;
+  flex-shrink: 0;
+  color: #909399;
+}
+
+.export-panel-tip {
+  margin-top: 14px;
+  padding: 8px 12px;
+  border-radius: 4px;
+  background: #fdf6ec;
+  color: #e6a23c;
+  font-size: 13px;
+  line-height: 1.5;
 }
 </style>
diff --git a/src/views/CNAS/resourceDemand/device/component/record.vue b/src/views/CNAS/resourceDemand/device/component/record.vue
index 9c45784..add40c3 100644
--- a/src/views/CNAS/resourceDemand/device/component/record.vue
+++ b/src/views/CNAS/resourceDemand/device/component/record.vue
@@ -5,51 +5,67 @@
       <el-form :model="search" ref="search" size="small" :inline="true">
         <el-form-item label="鏍峰搧缂栧彿">
           <el-input v-model="search.sampleCode" clearable placeholder="璇疯緭鍏�" size="small"
-                    @keyup.enter="getTableList(clickNodeVal.value)"></el-input>
+                    @keyup.enter="getTableList()"></el-input>
         </el-form-item>
-        <el-form-item label="绠$悊缂栧彿">
+        <el-form-item label="璁惧缂栧彿">
           <el-input v-model="search.managementNumber" clearable placeholder="璇疯緭鍏�" size="small"
-                    @keyup.enter="getTableList(clickNodeVal.value)"></el-input>
+                    @keyup.enter="getTableList()"></el-input>
         </el-form-item>
         <el-form-item>
-          <el-button size="small" type="primary" @click="getTableList(clickNodeVal.value)">鏌ヨ</el-button>
+          <el-button size="small" type="primary" @click="getTableList()">鏌ヨ</el-button>
           <el-button size="small" @click="resetSearch">閲嶇疆</el-button>
         </el-form-item>
       </el-form>
       <div>
-        <el-button v-if="isMenuList !== 1" size="small" type="primary" @click="dialogVisible = true, openAdd()">鏂� 寤�</el-button>
         <el-button :loading="outLoading" size="small" type="primary" @click="openHandleOut">瀵� 鍑�</el-button>
       </div>
     </div>
     <div>
-      <el-table ref="Recordtable" :data="formParamList" height="calc(100vh - 20em)"
-                v-loading="tableLoading"
- border>
-        <!-- 琛ㄦ牸鍒� -->
-        <el-table-column label="搴忓彿" type="index" width="70" align="center">
-          <template v-slot="scope">
+      <el-table ref="Recordtable" :data="formParamList" height="calc(100vh - 25em)"
+                v-loading="tableLoading" border>
+        <el-table-column label="搴忓彿" type="index" width="60" align="center">
+          <template #default="scope">
             <span>{{ (search.current - 1) * search.size + scope.$index + 1 }}</span>
           </template>
         </el-table-column>
-        <el-table-column label="鏍峰搧缂栧彿" min-width="180" prop="sampleCode" />
-        <el-table-column label="璁惧鍚嶇О" min-width="150" prop="deviceName" />
-        <el-table-column label="绠$悊缂栧彿" min-width="150" prop="managementNumber" />
-        <el-table-column label="浣跨敤鍓�" min-width="120" prop="useBefore">
-          <template v-slot="scope">
-            {{ scope.row.useBefore === 1 ? '鑹ソ' : '寮傚父' }}
+        <el-table-column label="璁惧鍚嶇О" min-width="140" prop="deviceName" show-overflow-tooltip />
+        <el-table-column label="璁惧鍨嬪彿" min-width="120" prop="specificationModel" show-overflow-tooltip />
+        <el-table-column label="璁惧缂栧彿" min-width="130" prop="managementNumber" />
+        <el-table-column label="浣跨敤鏃ユ湡" width="110" align="center">
+          <template #default="scope">
+            {{ formatDateCell(scope.row.useStartDate) }}
           </template>
         </el-table-column>
-        <el-table-column label="浣跨敤鍚�" min-width="120" prop="useAfter">
-          <template v-slot="scope">
-            {{ scope.row.useAfter === 1 ? '鑹ソ' : '寮傚父' }}
+        <el-table-column label="鏍峰搧缂栧彿" min-width="150" prop="sampleCode">
+          <template #default="scope">
+            <span>{{ scope.row.sampleCode }}</span>
+            <el-tooltip v-if="scope.row.orderCode" :content="'鍏宠仈鍘熷璁板綍锛�' + scope.row.orderCode" placement="top">
+              <lims-icon class="link-icon" name="el-icon-link"></lims-icon>
+            </el-tooltip>
           </template>
         </el-table-column>
-        <!--        <el-table-column label="寮傚父鎯呭喌" min-width="120" prop="abnormal" />-->
-        <el-table-column label="浣跨敤寮�濮嬫棩鏈�" min-width="170" prop="useStartDate" :formatter="formatDateCell" />
-        <el-table-column label="浣跨敤缁撴潫鏃ユ湡" min-width="170" prop="useEndDate" :formatter="formatDateCell" />
-        <el-table-column label="浣跨敤浜�" min-width="120" prop="usePerson" />
-        <el-table-column label="澶囨敞" min-width="120" prop="remark" />
-        <!-- 鎿嶄綔鎸夐挳 -->
+        <el-table-column label="鏃堕棿锛�24灏忔椂鍒讹級" align="center">
+          <el-table-column label="寮�濮�" width="90" align="center">
+            <template #default="scope">{{ formatTimeCell(scope.row.useStartDate) }}</template>
+          </el-table-column>
+          <el-table-column label="缁撴潫" width="90" align="center">
+            <template #default="scope">{{ formatTimeCell(scope.row.useEndDate) }}</template>
+          </el-table-column>
+        </el-table-column>
+        <el-table-column label="璁惧鐘跺喌" align="center">
+          <el-table-column label="浣跨敤鍓�" width="80" align="center">
+            <template #default="scope">{{ formatStatus(scope.row.useBefore) }}</template>
+          </el-table-column>
+          <el-table-column label="浣跨敤鍚�" width="80" align="center">
+            <template #default="scope">{{ formatStatus(scope.row.useAfter) }}</template>
+          </el-table-column>
+        </el-table-column>
+        <el-table-column label="鐜鏉′欢" align="center">
+          <el-table-column label="鈩�" width="80" align="center" prop="temperature" />
+          <el-table-column label="%RH" width="80" align="center" prop="humidity" />
+        </el-table-column>
+        <el-table-column label="浣跨敤浜�" width="100" prop="usePerson" />
+        <el-table-column label="澶囨敞" min-width="140" prop="remark" show-overflow-tooltip />
         <el-table-column fixed="right" label="鎿嶄綔" width="150" align="center">
           <template #default="scope">
             <el-button size="small" link type="primary" @click="showDetailsDialog('edit', scope.row)">缂栬緫</el-button>
@@ -63,30 +79,57 @@
         @current-change="handleCurrentChange" background>
       </el-pagination>
     </div>
-    <el-dialog v-model="dialogVisible" title="浠櫒璁惧浣跨敤璁板綍琛�" top="5vh" width="55%">
-      <el-form ref="form" :model="form" label-width="130px">
-        <el-row>
-          <el-col :span="24">
-            <el-form-item :rules="[{ required: true, message: '鏍峰搧缂栧彿', trigger: 'blur' }]" label="鏍峰搧缂栧彿:"
+    <el-dialog v-model="dialogVisible" title="浠櫒璁惧杩愯璁板綍" top="5vh" width="70%">
+      <el-form ref="form" :model="form" label-width="105px">
+        <el-row :gutter="16">
+          <el-col :span="8">
+            <el-form-item label="璁惧鍚嶇О:">
+              <el-input v-model="form.deviceName" disabled size="small"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="璁惧鍨嬪彿:">
+              <el-input v-model="form.specificationModel" disabled size="small"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="璁惧缂栧彿:">
+              <el-input v-model="form.managementNumber" disabled size="small"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item :rules="[{ required: true, message: '璇烽�夋嫨浣跨敤鏃ユ湡', trigger: 'change' }]" label="浣跨敤鏃ユ湡:"
+              prop="useDate">
+              <el-date-picker v-model="form.useDate" :disabled="operationType === 'view'" format="YYYY-MM-DD"
+                placeholder="閫夋嫨浣跨敤鏃ユ湡" size="small" style="width: 100%" type="date" value-format="YYYY-MM-DD"
+                :disabled-date="disabledDate">
+              </el-date-picker>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item :rules="[{ required: true, message: '璇疯緭鍏ユ牱鍝佺紪鍙�', trigger: 'blur' }]" label="鏍峰搧缂栧彿:"
               prop="sampleCode">
-              <el-input v-model="form.sampleCode" :disabled="operationType === 'view'" size="small"
-                style="width: 100%;"></el-input>
+              <el-input v-model="form.sampleCode" :disabled="operationType === 'view'" size="small"></el-input>
             </el-form-item>
           </el-col>
           <el-col :span="12">
-            <el-form-item label="璁惧鍚嶇О:" required>
-              <el-input v-model="form.deviceName" :disabled="operationType === 'view'" size="small"
-                style="width: 100%;"></el-input>
+            <el-form-item :rules="[{ required: true, message: '璇烽�夋嫨寮�濮嬫椂闂�', trigger: 'change' }]" label="寮�濮嬫椂闂�:"
+              prop="useStartTime">
+              <el-time-picker v-model="form.useStartTime" :disabled="operationType === 'view'" format="HH:mm"
+                placeholder="閫夋嫨寮�濮嬫椂闂�" size="small" style="width: 100%" value-format="HH:mm:ss">
+              </el-time-picker>
             </el-form-item>
           </el-col>
           <el-col :span="12">
-            <el-form-item label="绠$悊缂栧彿:" required>
-              <el-input v-model="form.managementNumber" :disabled="operationType === 'view'" size="small"
-                style="width: 100%;"></el-input>
+            <el-form-item :rules="[{ required: true, message: '璇烽�夋嫨缁撴潫鏃堕棿', trigger: 'change' }]" label="缁撴潫鏃堕棿:"
+              prop="useEndTime">
+              <el-time-picker v-model="form.useEndTime" :disabled="operationType === 'view'" format="HH:mm"
+                placeholder="閫夋嫨缁撴潫鏃堕棿" size="small" style="width: 100%" value-format="HH:mm:ss">
+              </el-time-picker>
             </el-form-item>
           </el-col>
           <el-col :span="12">
-            <el-form-item :rules="[{ required: true, message: '璇烽�夋嫨浣跨敤鍓�', trigger: 'change' }]" label="浣跨敤鍓�:"
+            <el-form-item :rules="[{ required: true, message: '璇烽�夋嫨浣跨敤鍓嶇姸鎬�', trigger: 'change' }]" label="浣跨敤鍓�:"
               prop="useBefore">
               <el-radio-group v-model="form.useBefore" :disabled="operationType === 'view'">
                 <el-radio :value="1">鑹ソ</el-radio>
@@ -95,7 +138,7 @@
             </el-form-item>
           </el-col>
           <el-col :span="12">
-            <el-form-item :rules="[{ required: true, message: '璇烽�夋嫨浣跨敤鍚�', trigger: 'change' }]" label="浣跨敤鍚�:"
+            <el-form-item :rules="[{ required: true, message: '璇烽�夋嫨浣跨敤鍚庣姸鎬�', trigger: 'change' }]" label="浣跨敤鍚�:"
               prop="useAfter">
               <el-radio-group v-model="form.useAfter" :disabled="operationType === 'view'">
                 <el-radio :value="1">鑹ソ</el-radio>
@@ -104,22 +147,31 @@
             </el-form-item>
           </el-col>
           <el-col :span="12">
-            <el-form-item :rules="[{ required: true, message: '璇疯緭鍏ヤ娇鐢ㄦ棩鏈�', trigger: 'blur' }]" label="浣跨敤鏃ユ湡:"
-              prop="useDateList">
-              <el-date-picker v-model="form.useDateList" :disabled="operationType === 'view'" end-placeholder="缁撴潫鏃ユ湡"
-                format="YYYY-MM-DD HH:mm:ss" size="small" start-placeholder="寮�濮嬫棩鏈�" style="width:100%"
-                type="datetimerange" value-format="YYYY-MM-DD HH:mm:ss"
-                              :disabled-date="disabledDate">
-              </el-date-picker>
+            <el-form-item label="鐜娓╁害:">
+              <el-input v-model="form.temperature" :disabled="operationType === 'view'" placeholder="璇疯緭鍏ユ俯搴�" size="small">
+                <template #append>鈩�</template>
+              </el-input>
             </el-form-item>
           </el-col>
           <el-col :span="12">
-            <el-form-item :rules="[{ required: true, message: '璇疯緭鍏ヤ娇鐢ㄤ汉', trigger: 'change' }]" label="浣跨敤浜�:"
+            <el-form-item label="鐜婀垮害:">
+              <el-input v-model="form.humidity" :disabled="operationType === 'view'" placeholder="璇疯緭鍏ユ箍搴�" size="small">
+                <template #append>%RH</template>
+              </el-input>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item :rules="[{ required: true, message: '璇烽�夋嫨浣跨敤浜�', trigger: 'change' }]" label="浣跨敤浜�:"
               prop="usePersonId">
               <el-select @change="usePersonName" v-model="form.usePersonId" :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-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12" v-if="form.orderCode">
+            <el-form-item label="鍏宠仈鍘熷璁板綍:">
+              <el-input v-model="form.orderCode" disabled size="small"></el-input>
             </el-form-item>
           </el-col>
           <el-col :span="24">
@@ -129,7 +181,7 @@
           </el-col>
         </el-row>
       </el-form>
-      <template #footer><span  class="dialog-footer">
+      <template #footer><span class="dialog-footer">
         <el-button @click="dialogVisible = false">鍙� 娑�</el-button>
         <el-button v-if="operationType !== 'view'" type="primary" @click="saveRecord">纭� 瀹�</el-button>
       </span></template>
@@ -140,7 +192,7 @@
           type="month" value-format="YYYY-MM">
         </el-date-picker>
       </span>
-      <template #footer><span  class="dialog-footer">
+      <template #footer><span class="dialog-footer">
         <el-button @click="ratifyDialog = false, exportDate = ''">鍙� 娑�</el-button>
         <el-button :loading="outLoading" type="primary" @click="handleDown">瀵� 鍑�</el-button>
       </span></template>
@@ -151,28 +203,41 @@
 import {
   deviceRecordPage,
   exportUseRecord,
-  selectDeviceByCode,
-  saveDeviceRecord,
   updateDeviceRecord,
   deleteDeviceRecord,
 } from '@/api/cnas/resourceDemand/device.js'
 import { selectUserCondition } from "@/api/business/inspectionTask";
-import { formatListDate } from './dateFormat';
+import { formatDateOnly as toDateOnly } from './dateFormat';
 import { saveBlobOrShowError } from '@/utils/saveBlob'
+import dayjs from 'dayjs'
+
+const today = () => {
+  const now = new Date()
+  return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`
+}
+
+const defaultForm = () => ({
+  id: null,
+  deviceId: '',
+  deviceName: '',
+  specificationModel: '',
+  managementNumber: '',
+  insOrderId: null,
+  orderCode: '',
+  sampleCode: '',
+  useDate: today(),
+  useStartTime: '',
+  useEndTime: '',
+  temperature: '',
+  humidity: '',
+  useBefore: 1,
+  useAfter: 1,
+  abnormal: '',
+  usePersonId: '',
+  usePerson: '',
+  remark: '',
+})
 export default {
-  props: {
-    clickNodeVal: {
-      type: Object,
-      default: () => {
-        return {};
-      }
-    },
-    // 鍒ゆ柇鏄惁鏄閮ㄥ垎绂�
-    isMenuList: {
-      type: Number,
-      default: 0
-    }
-  },
   data() {
     return {
       search: {
@@ -182,37 +247,11 @@
         sampleCode: '',
         managementNumber: ''
       },
-      responsiblePersonList: {},
-      isShow: false,
       outLoading: false,
       ratifyDialog: false,
       exportDate: '',
       userList: [],
-      form: {
-        // deviceId:'',
-        processNumber: '',
-        deviceName: '',
-        managementNumber: '',
-        //娓╁害
-        temperature: '',
-        //婀垮害
-        humidity: '',
-        //浣跨敤鍓�
-        useBefore: 1,
-        //浣跨敤鍚�
-        useAfter: 1,
-        //寮傚父鎯呭喌
-        abnormal: '',
-        useDateList: [],
-        //浣跨敤鏃ユ湡
-        useStartDate: null,
-        useEndDate: null,
-        //浣跨敤浜�
-        usePerson: '',
-        usePersonId: '',
-        //澶囨敞
-        remark: '',
-      },
+      form: defaultForm(),
       dialogVisible: false,
       operationType: '',
       formParamList: [],
@@ -220,11 +259,21 @@
     }
   },
   mounted() {
-    this.getTableList(this.clickNodeVal.value);
+    this.getTableList();
   },
   methods: {
-    formatDateCell(row, column, cellValue) {
-      return formatListDate(cellValue)
+    formatDateCell(value) {
+      return toDateOnly(value)
+    },
+    formatTimeCell(value) {
+      if (!value) return ''
+      const date = dayjs(String(value).replace('T', ' '))
+      return date.isValid() ? date.format('HH:mm') : ''
+    },
+    formatStatus(value) {
+      if (value === 1) return '鑹ソ'
+      if (value === 0) return '寮傚父'
+      return ''
     },
     // element-plus 鐨� el-date-picker 娌℃湁 picker-options锛屾敼鎴� :disabled-date
     disabledDate(time) {
@@ -232,11 +281,11 @@
     },
     handleSizeChange(val) {
       this.search.size = val
-      this.getTableList(this.clickNodeVal.value);
+      this.getTableList();
     },
     handleCurrentChange(val) {
       this.search.current = val
-      this.getTableList(this.clickNodeVal.value);
+      this.getTableList();
     },
     resetSearch() {
       this.search = {
@@ -246,15 +295,11 @@
         sampleCode: '',
         managementNumber: ''
       }
-      this.getTableList(this.clickNodeVal.value);
+      this.getTableList();
     },
-    async getTableList(deviceId) {
-      if (deviceId === undefined) {
-        deviceId = ''
-      }
+    async getTableList() {
       this.tableLoading = true
       await deviceRecordPage({
-        deviceId: deviceId,
         ...this.search
       }).then(res => {
         this.tableLoading = false
@@ -274,28 +319,18 @@
     handleDown() {
       this.outLoading = true
       exportUseRecord({
-        deviceId: this.clickNodeVal.value,
         sampleCode: this.search.sampleCode,
         managementNumber: this.search.managementNumber,
         exportDate: this.exportDate
       }).then(res => {
         this.outLoading = false
-        saveBlobOrShowError(res, '璁惧浣跨敤璁板綍.doc', 'application/msword')
+        saveBlobOrShowError(res, '浠櫒璁惧杩愯璁板綍.docx', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document')
       }).catch(() => {
         this.outLoading = false
       })
     },
-    //鏂板缓
-    openAdd() {
-      this.operationType = 'add'
-      this.getUserList()
-      selectDeviceByCode({ id: this.clickNodeVal.value }).then(res => {
-        this.form.deviceName = res.data.deviceName
-        this.form.managementNumber = res.data.managementNumber
-        this.$nextTick(() => {
-          this.$refs['form'].clearValidate()
-        })
-      });
+    resetForm() {
+      this.form = defaultForm()
     },
     usePersonName(value) {
       const index = this.userList.findIndex(item => item.id === value)
@@ -303,31 +338,39 @@
         this.form.usePerson = this.userList[index].name
       }
     },
-    //纭娣诲姞璁板綍
+    //淇濆瓨淇敼
     saveRecord() {
       this.$refs.form.validate((valid) => {
-        if (valid) {
-          this.form.useStartDate = this.form.useDateList[0]
-          this.form.useEndDate = this.form.useDateList[1]
-          this.form.deviceId = this.clickNodeVal.value
-          if (this.operationType === 'add') {
-            saveDeviceRecord(this.form).then(res => {
-              if (res.code == 200) {
-                this.$message.success('鏂板鎴愬姛')
-                this.getTableList(this.clickNodeVal.value)
-                this.dialogVisible = false
-              }
-            })
-          } else {
-            updateDeviceRecord(this.form).then(res => {
-              if (res.code == 200) {
-                this.$message.success('淇敼鎴愬姛')
-                this.getTableList(this.clickNodeVal.value)
-                this.dialogVisible = false
-              }
-            })
-          }
+        if (!valid) {
+          return
         }
+        if (this.form.useStartTime >= this.form.useEndTime) {
+          this.$message.error('缁撴潫鏃堕棿蹇呴』鏅氫簬寮�濮嬫椂闂�')
+          return
+        }
+        const payload = {
+          id: this.form.id || undefined,
+          deviceId: this.form.deviceId,
+          insOrderId: this.form.insOrderId || undefined,
+          sampleCode: this.form.sampleCode,
+          temperature: this.form.temperature,
+          humidity: this.form.humidity,
+          useBefore: this.form.useBefore,
+          useAfter: this.form.useAfter,
+          abnormal: this.form.abnormal,
+          usePersonId: this.form.usePersonId,
+          usePerson: this.form.usePerson,
+          remark: this.form.remark,
+          useStartDate: `${this.form.useDate} ${this.form.useStartTime}`,
+          useEndDate: `${this.form.useDate} ${this.form.useEndTime}`,
+        }
+        updateDeviceRecord(payload).then(res => {
+          if (res.code == 200) {
+            this.$message.success('淇敼鎴愬姛')
+            this.getTableList()
+            this.dialogVisible = false
+          }
+        })
       });
     },
     //鏌ョ湅璇︽儏
@@ -336,13 +379,23 @@
       this.dialogVisible = true;
       this.getUserList()
       // 澶嶅埗涓�浠藉啀缂栬緫锛岄伩鍏嶇洿鎺ユ敼鍔ㄨ〃鏍奸噷鐨勬暟鎹�
-      const useStartDate = row.useStartDate || ''
-      const useEndDate = row.useEndDate || ''
+      const start = row.useStartDate ? String(row.useStartDate).replace('T', ' ') : ''
+      const end = row.useEndDate ? String(row.useEndDate).replace('T', ' ') : ''
       this.form = {
+        ...defaultForm(),
         ...row,
-        useStartDate,
-        useEndDate,
-        useDateList: useStartDate && useEndDate ? [useStartDate, useEndDate] : []
+        deviceId: row.deviceId,
+        deviceName: row.deviceName || '',
+        specificationModel: row.specificationModel || '',
+        managementNumber: row.managementNumber || '',
+        orderCode: row.orderCode || '',
+        useDate: start ? start.slice(0, 10) : '',
+        useStartTime: start.length >= 19 ? start.slice(11, 19) : '',
+        useEndTime: end.length >= 19 ? end.slice(11, 19) : '',
+        temperature: row.temperature || '',
+        humidity: row.humidity || '',
+        usePersonId: row.usePersonId || '',
+        usePerson: row.usePerson || '',
       }
     },
     handleDeleteClick(index, row) {
@@ -372,37 +425,12 @@
     },
   },
   watch: {
-    // 鐩戝惉鐐瑰嚮el-tree鐨勬暟鎹紝杩涜鏁版嵁鍒锋柊
-    clickNodeVal(newVal) {
-      if (newVal.value) {
-        this.getTableList(newVal.value);
-      }
-    },
     dialogVisible(newVal) {
       if (newVal === false) {
-        this.form = {
-          // deviceId:'',
-          sampleCode: '',
-          deviceName: '',
-          managementNumber: '',
-          //娓╁害
-          temperature: '',
-          //婀垮害
-          humidity: '',
-          //浣跨敤鍓�
-          useBefore: 1,
-          //浣跨敤鍚�
-          useAfter: 1,
-          //寮傚父鎯呭喌
-          abnormal: '',
-          //浣跨敤鏃ユ湡
-          useDateList: [],
-          //浣跨敤浜�
-          usePersonId: '',
-          //澶囨敞
-          remark: '',
-        }
-        this.$refs.form.clearValidate()
+        this.resetForm()
+        this.$nextTick(() => {
+          this.$refs.form && this.$refs.form.clearValidate()
+        })
       }
     }
   }
@@ -414,6 +442,13 @@
   height: 46px;
   display: flex;
   justify-content: space-between;
-  margin-top: 10px;
+  margin-top: 4px;
+}
+
+.link-icon {
+  margin-left: 4px;
+  color: #409eff;
+  font-size: 14px;
+  vertical-align: middle;
 }
 </style>
diff --git a/src/views/CNAS/resourceDemand/device/index.vue b/src/views/CNAS/resourceDemand/device/index.vue
index fe4cbfd..665a277 100644
--- a/src/views/CNAS/resourceDemand/device/index.vue
+++ b/src/views/CNAS/resourceDemand/device/index.vue
@@ -62,7 +62,7 @@
             <using-external-instruments v-if="menuListActiveName == '鍒╃敤澶栭儴浠櫒璁惧'" :clickNodeVal="clickNodeVal"></using-external-instruments>
           </el-tab-pane>
           <el-tab-pane label="浣跨敤璁板綍" name="浣跨敤璁板綍">
-            <record v-if="menuListActiveName == '浣跨敤璁板綍'" :isMenuList="1" />
+            <record v-if="menuListActiveName == '浣跨敤璁板綍'" />
           </el-tab-pane>
         </el-tabs>
       </div>
@@ -83,9 +83,6 @@
           </el-tab-pane>
           <el-tab-pane label="璁惧鍊熺敤" name="璁惧鍊熺敤">
             <borrow v-if="tabListActiveName == '璁惧鍊熺敤'" :clickNodeVal="clickNodeVal" />
-          </el-tab-pane>
-          <el-tab-pane label="浣跨敤璁板綍" name="浣跨敤璁板綍">
-            <record v-if="tabListActiveName == '浣跨敤璁板綍'" :clickNodeVal="clickNodeVal" />
           </el-tab-pane>
           <el-tab-pane label="璁惧鍋滅敤/鍚敤" name="璁惧鍋滅敤/鍚敤">
             <state v-if="tabListActiveName == '璁惧鍋滅敤/鍚敤'" :clickNodeVal="clickNodeVal" />

--
Gitblit v1.9.3