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/files.vue |  635 ++++++++++++++++++++++++++++++++++++---------------------
 1 files changed, 396 insertions(+), 239 deletions(-)

diff --git a/src/views/CNAS/resourceDemand/device/component/files.vue b/src/views/CNAS/resourceDemand/device/component/files.vue
index 4904357..ec28e92 100644
--- a/src/views/CNAS/resourceDemand/device/component/files.vue
+++ b/src/views/CNAS/resourceDemand/device/component/files.vue
@@ -15,12 +15,16 @@
       <el-row :gutter="20">
         <el-col :span="6">
           <!-- 鍔犳椂闂存埑閬垮厤娴忚鍣ㄧ紦瀛橀棶棰� -->
-          <el-image :src="`${javaApi}/img/${Mdata.imageUpload}`" fit="fill" :key="'personalPicture' + timeStamp"
+          <el-image v-if="Mdata.imageUpload" :src="`${javaApi}/img/${Mdata.imageUpload}`" fit="fill" :key="'personalPicture' + timeStamp"
             style="width: 200px;height: 300px;border: 1px solid #000;border-radius: 10px;margin-left: 30px;margin-top: 20px;">
             <template #error><div  class="image-slot">
               <lims-icon name="el-icon-picture-outline" style="font-size: 40px;"></lims-icon>
             </div></template>
           </el-image>
+          <div v-else class="image-slot"
+            style="width: 198px;height: 298px;border: 1px solid #000;border-radius: 10px;margin-left: 30px;margin-top: 20px;display: flex;align-items: center;justify-content: center;">
+            <lims-icon name="el-icon-picture-outline" style="font-size: 40px;"></lims-icon>
+          </div>
         </el-col>
         <el-col :span="8">
           <div class="form-item">
@@ -40,10 +44,6 @@
             <p>{{ Mdata.managementNumber }}</p>
           </div>
           <div class="form-item">
-            <label>鎵�灞為儴闂�</label>
-            <p>{{ Mdata.laboratoryName }}</p>
-          </div>
-          <div class="form-item">
             <label>鐢熶骇鍘傚</label>
             <!-- <p>{{ Mdata.manufacturer }}</p> -->
             <el-tooltip class="item" :content="Mdata.manufacturer">
@@ -56,10 +56,6 @@
           </div>
 
           <div class="form-item">
-            <label>鍑哄巶鏃ユ湡</label>
-            <p>{{ formaterDateTime(Mdata.acquisitionDate) }}</p>
-          </div>
-          <div class="form-item">
             <label>鏍″噯鏈夋晥鏈�</label>
             <p>{{ formaterDateTime(Mdata.activationDate) }}</p>
           </div>
@@ -69,19 +65,11 @@
           </div>
 
           <div class="form-item">
-            <label>鎶ュ簾鏃堕棿</label>
-            <p>{{ handleData() }}</p>
-          </div>
-          <div class="form-item">
             <label>鍑嗙‘搴﹂噺鍊�</label>
             <el-tooltip class="item" :content="Mdata.technicalIndicators">
               <span class="text-ellipsis">{{ Mdata.technicalIndicators }}</span>
             </el-tooltip>
             <!-- <p>{{ Mdata.technicalIndicators }}</p> -->
-          </div>
-          <div class="form-item">
-            <label>缁翠慨璁板綍</label>
-            <p>{{ handleData() }}</p>
           </div>
           <div class="form-item">
             <label>琚巿鏉冧汉</label>
@@ -140,15 +128,11 @@
           </div>
           <div class="form-item">
             <label>閲囪喘璐圭敤(鍏�)</label>
-            <p>{{ Mdata.unitPrice }}</p>
+            <p>{{ formatPurchasePrice(Mdata.unitPrice) }}</p>
           </div>
           <div class="form-item">
             <label>璁惧璐熻矗浜�</label>
             <p>{{ Mdata.equipmentManagerName }}</p>
-          </div>
-          <div class="form-item">
-            <label>楠屾敹璁板綍</label>
-            <p>{{ handleData() }}</p>
           </div>
           <div class="form-item">
             <label>鏍稿噯璇佷功</label>
@@ -170,7 +154,7 @@
         <el-table-column prop="quantity" label="浠芥暟" min-width="80" />
         <el-table-column prop="pageCount" label="椤电爜" min-width="80" />
         <el-table-column prop="provider" label="鎻愪緵鑰�" min-width="150" />
-        <el-table-column prop="provideDate" label="褰掓。鏃ユ湡" min-width="170" />
+        <el-table-column prop="provideDate" label="褰掓。鏃ユ湡" min-width="170" :formatter="formatDateCell" />
         <el-table-column prop="comments" label="澶囨敞" min-width="150" />
         <el-table-column fixed="right" label="鎿嶄綔" min-width="180" align="center">
           <template #default="scope">
@@ -184,156 +168,203 @@
     <!-- 淇 -->
     <el-dialog title="妗f淇" top="5vh" v-model="dialogVisible" width="70%" @open="openFileRevisionDialog"
       :before-close="handleClose">
-      <el-row style="display:flex;justify-content: space-around;max-height: 75vh;overflow-y: auto;">
-        <!-- 宸﹁竟甯冨眬 -->
-        <el-col :span="7">
-          <el-col>
-            <!-- 鍥剧墖 -->
-            <el-image class="img" style="width:100%;height: 320px;margin-bottom:16px"
-              :src="javaApi + '/img/' + editData.imageUpload">
-              <template #error><div  class="image-error" style="width: calc(100% - 2px);
+      <div style="max-height: 75vh;overflow-y: auto;">
+      <!-- 椤堕儴锛氬浘鐗� + 鍩烘湰淇℃伅 -->
+      <el-row>
+        <el-col :span="7" style="padding-right: 20px;">
+          <!-- 鍥剧墖 -->
+          <el-image v-if="editData.imageUpload" class="img" style="width:100%;height: 320px;"
+            :src="javaApi + '/img/' + editData.imageUpload">
+            <template #error><div  class="image-error" style="width: calc(100% - 2px);
             height: 318px;
             border-radius: 16px;
             display: flex;
             align-items: center;
             justify-content: center;
-            border: 1px solid #EEEEEE;">
-                <lims-icon name="el-icon-picture-outline" style="font-size:60px;color:#666666;"></lims-icon>
-              </div></template>
-            </el-image>
-            <!-- 琛ㄥ崟 -->
-            <el-form :model="editData" label-width="120px" ref="rules1" :rules="rules1">
+            border: 1px solid var(--lims-divider);">
+              <lims-icon name="el-icon-picture-outline" style="font-size:60px;color:var(--lims-text-2);"></lims-icon>
+            </div></template>
+          </el-image>
+          <div v-else class="image-error"
+            style="width: calc(100% - 2px);height: 320px;border-radius: 16px;display: flex;align-items: center;justify-content: center;border: 1px solid var(--lims-divider);">
+            <lims-icon name="el-icon-picture-outline" style="font-size:60px;color:var(--lims-text-2);"></lims-icon>
+          </div>
+          <!-- 鍥剧墖涓婁紶 -->
+          <div style="margin-top: 12px;text-align: center;">
+            <div v-show="editData.imageName" class="picName">{{ editData.imageName }}</div>
+            <el-upload :action="action" :on-success="handleSuccessUpImg2" :show-file-list="false"
+              accept='image/jpg,image/jpeg,image/png' :headers="uploadHeader" :before-upload="beforeUpload"
+              :on-error="onError" ref='upload' class="avatar-uploader">
+              <img v-if="editData.imageUpload" :src="javaApi + '/img/' + editData.imageUpload" class="avatar">
+              <lims-icon name="el-icon-plus" v-else class="avatar-uploader-icon"></lims-icon>
+            </el-upload>
+          </div>
+        </el-col>
+        <el-col :span="17">
+          <!-- 鍩烘湰淇℃伅 -->
+          <div class="section-title" style="margin-top: 0;">鍩烘湰淇℃伅</div>
+          <el-form :model="editData" label-width="120px" ref="rules1" :rules="rules1">
+            <div class="form-row">
               <el-form-item label="浠櫒鍚嶇О:" prop="deviceName">
                 <el-input v-model="editData.deviceName" size="small"></el-input>
               </el-form-item>
               <el-form-item label="浠櫒鍚嶇ОEN:" prop="enDeviceName">
                 <el-input v-model="editData.enDeviceName" size="small"></el-input>
               </el-form-item>
+            </div>
+            <div class="form-row">
               <el-form-item label="瑙勬牸鍨嬪彿:" prop="specificationModel">
                 <el-input v-model="editData.specificationModel" size="small"></el-input>
               </el-form-item>
               <el-form-item label="鐢熶骇鍘傚:">
                 <el-input v-model="editData.manufacturer" size="small"></el-input>
               </el-form-item>
-            </el-form>
-          </el-col>
-        </el-col>
-        <!-- 涓棿甯冨眬 -->
-        <el-col :span="7">
-          <el-form :model="editData" label-width="116px" ref="rules2" :rules="rules1">
-            <el-form-item label="鏍″噯鏈嶅姟鏈烘瀯:">
-              <el-input v-model="editData.calibrationServices" size="small"></el-input>
-            </el-form-item>
-            <el-form-item label="璧勪骇缂栫爜:">
-              <el-input v-model="editData.assetCode" size="small"></el-input>
-            </el-form-item>
-            <el-form-item label="浜у湴:">
-              <el-input v-model="editData.origin" size="small"></el-input>
-            </el-form-item>
-            <el-form-item label="鍑哄巶缂栧彿:">
-              <el-input v-model="editData.factoryNo" size="small"></el-input>
-            </el-form-item>
-            <el-form-item label="绠$悊缂栧彿:" prop="managementNumber">
-              <el-input v-model="editData.managementNumber" size="small"></el-input>
-            </el-form-item>
-            <el-form-item label="璐疆鏃ユ湡:">
-              <el-date-picker style="width:100%" v-model="editData.acquisitionDate" type="date" format="YYYY-MM-DD"
-                value-format="YYYY-MM-DD HH:mm:ss" size="small" placeholder="閫夋嫨鏃ユ湡">
-              </el-date-picker>
-            </el-form-item>
-            <el-form-item label="鏍″噯鏈夋晥鏈�:" prop="activationDate">
-              <el-date-picker style="width:100%" v-model="editData.activationDate" type="date" format="YYYY-MM-DD"
-                value-format="YYYY-MM-DD HH:mm:ss" size="small" placeholder="閫夋嫨鏃ユ湡">
-              </el-date-picker>
-            </el-form-item>
-            <el-form-item label="璐熻矗浜�:">
-              <el-select v-model="editData.equipmentManager" placeholder="璇烽�夋嫨" size="small" style="width:100%">
-                <el-option v-for="item in responsiblePersonList" :key="item.name" :label="item.name" :value="item.id">
-                </el-option>
-              </el-select>
-            </el-form-item>
-            <el-form-item label="瀛樻斁鐐�:">
-              <el-input v-model="editData.storagePoint" size="small"></el-input>
-            </el-form-item>
-            <el-form-item label="鎶�鏈寚鏍�:">
-              <el-input v-model="editData.technicalIndicators" :rows="7" type="textarea" size="small"></el-input>
-            </el-form-item>
-          </el-form>
-        </el-col>
-        <!-- 鍙宠竟甯冨眬 -->
-        <el-col :span="7">
-          <el-form :model="editData" label-width="140px" ref="ruleForm" :rules="rules1">
-            <!-- 瀹為獙瀹ゅ垪琛� -->
-            <el-form-item label="鎵�灞為儴闂�:" prop="subordinateDepartmentsId">
-              <el-select v-model="editData.subordinateDepartmentsId" placeholder="璇烽�夋嫨" size="small" style="width:100%">
-                <el-option v-for="item in subordinateDepartmentsList" :key="item.value" :label="item.label"
-                  :value="item.value">
-                </el-option>
-              </el-select>
-            </el-form-item>
-            <el-form-item label="妫�娴嬮」鐩�:">
-              <el-cascader v-model="editData.insProductIds" :options="options" :show-all-levels="false" :props="props"
-                placeholder="璇烽�夋嫨" size="small" style="width:100%;" :collapse-tags="true" separator="," filterable
-                clearable></el-cascader>
-            </el-form-item>
-            <el-form-item label="鏈�杩戞牎鍑嗘棩鏈�:">
-              <el-date-picker style="width:100%" v-model="editData.lastCalibrationDate" format="YYYY-MM-DD"
-                value-format="YYYY-MM-DD HH:mm:ss" type="date" size="small" placeholder="閫夋嫨鏃ユ湡">
-              </el-date-picker>
-            </el-form-item>
-            <el-form-item label="涓嬫鏍″噯鏃ユ湡:">
-              <el-date-picker style="width:100%" v-model="editData.nextCalibrationDate" format="YYYY-MM-DD"
-                value-format="YYYY-MM-DD HH:mm:ss" type="date" size="small" placeholder="閫夋嫨鏃ユ湡">
-              </el-date-picker>
-            </el-form-item>
-            <el-form-item label="璁惧绫诲瀷:">
-              <el-select v-model="editData.largeCategory" placeholder="璇烽�夋嫨" size="small" style="width:100%">
-                <el-option v-for="item in equipmentList" :key="item.value" :label="item.label" :value="item.value">
-                </el-option>
-              </el-select>
-            </el-form-item>
-            <el-form-item label="鍗曚环(涓囧厓):">
-              <el-input v-model="editData.unitPrice" size="small"></el-input>
-            </el-form-item>
-            <el-form-item label="褰撳墠鐘舵��:" prop="deviceStatus">
-              <el-select v-model="editData.deviceStatus" placeholder="璇烽�夋嫨" size="small" style="width:100%">
-                <el-option v-for="item in deviceStatusList" :key="item.value" :label="item.label" :value="item.value">
-                </el-option>
-              </el-select>
-            </el-form-item>
-            <el-form-item label="鏍″噯鍛ㄦ湡锛堟湀锛�:" prop="calibrationDate">
-              <el-input v-model="editData.calibrationDate" size="small"></el-input>
-            </el-form-item>
-            <el-form-item label="琚巿鏉冧汉:">
-              <el-select v-model="editData.authorizedPerson" multiple placeholder="璇烽�夋嫨" size="small" style="width:100%">
-                <el-option v-for="item in responsiblePersonList" :key="item.name" :label="item.name" :value="item.id">
-                </el-option>
-              </el-select>
-            </el-form-item>
-            <el-form-item label="鍥剧墖:">
-              <!-- <div
-                style="border: 1px solid #DCDFE6;border-radius:4px;height:32px;lineHeight:32px;display:flex;justify-content: space-around;font-size: 13px;">
-                <div v-show="Mdata.imageName" class="picName">{{ Mdata.imageName }}</div>
-                <el-upload :action="action" :on-success="handleSuccessUpImg2" :show-file-list="false"
-                  accept='image/jpg,image/jpeg,image/png' :headers="headers" :on-change="beforeUpload"
-                  :on-error="onError" ref='upload'>
-                  <el-button type="text" style="height:30px;padding-top:8px"><span v-if="Mdata.imageName"></span></el-button>
-                </el-upload>
-              </div> -->
-
-              <div>
-                <div v-show="editData.imageName" class="picName">{{ editData.imageName }}</div>
-                <el-upload :action="action" :on-success="handleSuccessUpImg2" :show-file-list="false"
-                  accept='image/jpg,image/jpeg,image/png' :headers="uploadHeader" :on-change="beforeUpload"
-                  :on-error="onError" ref='upload' class="avatar-uploader">
-                  <img v-if="editData.imageUpload" :src="javaApi + '/img/' + editData.imageUpload" class="avatar">
-                  <lims-icon name="el-icon-plus" v-else class="avatar-uploader-icon"></lims-icon>
-                </el-upload>
-              </div>
-            </el-form-item>
+            </div>
+            <div class="form-row">
+              <el-form-item label="浜у湴:">
+                <el-input v-model="editData.origin" size="small"></el-input>
+              </el-form-item>
+              <el-form-item label="鍑哄巶缂栧彿:">
+                <el-input v-model="editData.factoryNo" size="small"></el-input>
+              </el-form-item>
+            </div>
+            <div class="form-row">
+              <el-form-item label="璧勪骇缂栫爜:">
+                <el-input v-model="editData.assetCode" size="small"></el-input>
+              </el-form-item>
+              <el-form-item label="绠$悊缂栧彿:" prop="managementNumber">
+                <el-input v-model="editData.managementNumber" size="small"></el-input>
+              </el-form-item>
+            </div>
+            <div class="form-row">
+              <el-form-item label="璐疆鏃ユ湡:">
+                <el-date-picker style="width:100%" v-model="editData.acquisitionDate" type="date" format="YYYY-MM-DD"
+                  value-format="YYYY-MM-DD HH:mm:ss" size="small" placeholder="閫夋嫨鏃ユ湡">
+                </el-date-picker>
+              </el-form-item>
+              <el-form-item label="鏍″噯鏈夋晥鏈�:" prop="activationDate">
+                <el-date-picker style="width:100%" v-model="editData.activationDate" type="date" format="YYYY-MM-DD"
+                  value-format="YYYY-MM-DD HH:mm:ss" size="small" placeholder="閫夋嫨鏃ユ湡">
+                </el-date-picker>
+              </el-form-item>
+            </div>
+            <div class="form-row">
+              <el-form-item label="鏍″噯鏈嶅姟鏈烘瀯:">
+                <el-select v-model="editData.calibrationServices" clearable filterable size="small" style="width: 100%">
+                  <el-option v-for="name in calibrationServiceOptions" :key="name" :label="name" :value="name"></el-option>
+                </el-select>
+              </el-form-item>
+              <div style="flex: 1;"></div>
+            </div>
           </el-form>
         </el-col>
       </el-row>
+      <!-- 璁惧绠$悊 -->
+      <div class="section-title">璁惧绠$悊</div>
+      <el-form :model="editData" label-width="120px" ref="rules2" :rules="rules1">
+        <div class="form-row">
+          <el-form-item label="妫�娴嬮」鐩�:">
+            <el-cascader v-model="editData.insProductIds" :options="options" :show-all-levels="false" :props="props"
+              placeholder="璇烽�夋嫨" size="small" style="width:100%;" :collapse-tags="true" separator="," filterable
+              clearable></el-cascader>
+          </el-form-item>
+          <el-form-item label="璁惧/璁¢噺鍣ㄥ叿:">
+            <el-select v-model="editData.largeCategory" placeholder="璇烽�夋嫨" size="small" style="width:100%">
+              <el-option v-for="item in equipmentList" :key="item.value" :label="item.label" :value="item.value">
+              </el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="鍗曚环(涓囧厓):">
+            <el-input v-model="editData.unitPrice" size="small"></el-input>
+          </el-form-item>
+        </div>
+        <div class="form-row">
+          <el-form-item label="褰撳墠鐘舵��:" prop="deviceStatus">
+            <el-select v-model="editData.deviceStatus" placeholder="璇烽�夋嫨" size="small" style="width:100%">
+              <el-option v-for="item in deviceStatusList" :key="item.value" :label="item.label" :value="item.value">
+              </el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="璐熻矗浜�:">
+            <el-select v-model="editData.equipmentManager" placeholder="璇烽�夋嫨" size="small" style="width:100%">
+              <el-option v-for="item in responsiblePersonList" :key="item.name" :label="item.name" :value="item.id">
+              </el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="琚巿鏉冧汉:">
+            <el-select v-model="editData.authorizedPerson" multiple placeholder="璇烽�夋嫨" size="small" style="width:100%">
+              <el-option v-for="item in inspectorList" :key="item.name" :label="item.name" :value="item.id">
+              </el-option>
+            </el-select>
+          </el-form-item>
+        </div>
+        <div class="form-row">
+          <el-form-item label="瀛樻斁鐐�:">
+            <el-input v-model="editData.storagePoint" size="small"></el-input>
+          </el-form-item>
+          <div style="flex: 1;"></div>
+        </div>
+      </el-form>
+      <!-- 鏍″噯/淇濆吇/鏍告煡 鍛ㄦ湡淇℃伅 -->
+      <el-form :model="editData" :rules="rules1" ref="cycleForm" label-width="140px"
+        style="margin-top: 12px;border-top: 1px solid var(--lims-divider);padding-top: 4px;">
+        <div class="cycle-row">
+          <span class="cycle-title">鏍″噯淇℃伅</span>
+          <el-form-item label="鏈�杩戞牎鍑嗘棩鏈�:" class="cycle-item">
+            <el-date-picker style="width:100%" v-model="editData.lastCalibrationDate" @change="calcNextDate(editData)"
+              format="YYYY-MM-DD" value-format="YYYY-MM-DD HH:mm:ss" type="date" size="small" placeholder="閫夋嫨鏃ユ湡">
+            </el-date-picker>
+          </el-form-item>
+          <el-form-item label="涓嬫鏍″噯鏃ユ湡:" class="cycle-item">
+            <el-date-picker :disabled="true" style="width:100%" v-model="editData.nextCalibrationDate"
+              format="YYYY-MM-DD" value-format="YYYY-MM-DD HH:mm:ss" type="date" size="small" placeholder="閫夋嫨鏃ユ湡">
+            </el-date-picker>
+          </el-form-item>
+          <el-form-item label="鏍″噯鍛ㄦ湡锛堟湀锛�:" prop="calibrationDate" class="cycle-item">
+            <el-input v-model="editData.calibrationDate" size="small" @change="calcNextDate(editData)"></el-input>
+          </el-form-item>
+        </div>
+        <div class="cycle-row">
+          <span class="cycle-title">淇濆吇淇℃伅</span>
+          <el-form-item label="鏈�杩戜繚鍏绘棩鏈�:" class="cycle-item">
+            <el-date-picker style="width:100%" v-model="editData.lastMaintenanceDate" @change="calcNextDate(editData)"
+              format="YYYY-MM-DD" value-format="YYYY-MM-DD HH:mm:ss" type="date" size="small" placeholder="閫夋嫨鏃ユ湡">
+            </el-date-picker>
+          </el-form-item>
+          <el-form-item label="涓嬫淇濆吇鏃ユ湡:" class="cycle-item">
+            <el-date-picker :disabled="true" style="width:100%" v-model="editData.nextMaintenanceDate"
+              format="YYYY-MM-DD" value-format="YYYY-MM-DD HH:mm:ss" type="date" size="small" placeholder="閫夋嫨鏃ユ湡">
+            </el-date-picker>
+          </el-form-item>
+          <el-form-item label="淇濆吇鍛ㄦ湡锛堟湀锛�:" class="cycle-item">
+            <el-input v-model="editData.maintenanceCycle" size="small" @change="calcNextDate(editData)"></el-input>
+          </el-form-item>
+        </div>
+        <div class="cycle-row">
+          <span class="cycle-title">鏍告煡淇℃伅</span>
+          <el-form-item label="鏈�杩戞牳鏌ユ棩鏈�:" class="cycle-item">
+            <el-date-picker style="width:100%" v-model="editData.lastExamineDate" @change="calcNextDate(editData)"
+              format="YYYY-MM-DD" value-format="YYYY-MM-DD HH:mm:ss" type="date" size="small" placeholder="閫夋嫨鏃ユ湡">
+            </el-date-picker>
+          </el-form-item>
+          <el-form-item label="涓嬫鏍告煡鏃ユ湡:" class="cycle-item">
+            <el-date-picker :disabled="true" style="width:100%" v-model="editData.nextExamineDate"
+              format="YYYY-MM-DD" value-format="YYYY-MM-DD HH:mm:ss" type="date" size="small" placeholder="閫夋嫨鏃ユ湡">
+            </el-date-picker>
+          </el-form-item>
+          <el-form-item label="鏍告煡鍛ㄦ湡锛堟湀锛�:" class="cycle-item">
+            <el-input v-model="editData.examineCycle" size="small" @change="calcNextDate(editData)"></el-input>
+          </el-form-item>
+        </div>
+      </el-form>
+      <!-- 鎶�鏈寚鏍� -->
+      <div class="section-title">鎶�鏈寚鏍�</div>
+      <el-form :model="editData" ref="ruleForm" :rules="rules1">
+        <el-form-item>
+          <el-input v-model="editData.technicalIndicators" :rows="7" type="textarea" size="small"></el-input>
+        </el-form-item>
+      </el-form>
+      </div>
       <template #footer><span  class="dialog-footer">
         <el-row>
           <el-button @click="handleClose">鍙� 娑�</el-button>
@@ -446,6 +477,7 @@
 
 <script>
 import { ElMessageBox } from 'element-plus'
+import dayjs from 'dayjs'
 import fileDownload from '@/utils/file'
 // vue-qr 鍙敮鎸� Vue2锛屾崲鎴愬悓 props 鐨勬湰鍦扮粍浠讹紙鍐呴儴鐢� Vue3 鐨� qrcode.vue锛�
 import vueQr from '@/components/QrCode'
@@ -463,9 +495,9 @@
   getInsProduction,
 } from '@/api/cnas/resourceDemand/device.js'
 import { selectUserCondition } from "@/api/business/inspectionTask";
-import {
-  obtainItemParameterList,
-} from '@/api/cnas/resourceDemand/device.js'
+import { selectQualifiedSupplierManagementPage } from '@/api/cnas/externalService/supplierManage/supplierManage'
+import { formatListDate } from './dateFormat'
+import { saveBlobOrShowError } from '@/utils/saveBlob'
 export default {
   props: {
     clickNodeVal: {
@@ -499,9 +531,6 @@
         ],
         calibrationDate: [
           { required: true, message: '璇疯緭鍏ユ牎鍑嗗懆鏈�(鏈�)', trigger: 'blur' },
-        ],
-        subordinateDepartmentsId: [
-          { required: true, message: '璇烽�夋嫨鎵�灞為儴闂�', trigger: 'change' },
         ]
       },
       // dateForm: {
@@ -509,7 +538,6 @@
       // },
       fileList: [], // 娣诲姞闄勪欢涓婁紶鏂囦欢鍒楄〃
       timeStamp: '', // 缁欏浘鐗囨坊鍔爇ey锛屽湪姣忔鍔犺浇椤甸潰鐨勬椂鍊欐柊寤烘椂闂存埑
-      equipmentManager: [],
       formLabelWidth: '100px',
       dialogVisible1: false,
       recordNumber: '',
@@ -520,7 +548,7 @@
       num: 1,
       //娣诲姞闄勪欢鏁版嵁鏀堕泦
       addFile: {
-        documentType: '', // 缁存姢绫诲瀷
+        documentType: 0, // 缁存姢绫诲瀷
         provideDate: null, // 褰掓。鏃ユ湡
         name: '', // 妗f鍚嶇О
         number: '', // 搴撳彿/璧勪骇缂栧彿
@@ -540,9 +568,13 @@
       dialogVisible: false,
       upLoad: false,
       responsiblePersonList: [],
-      subordinateDepartmentsList: [],
+      inspectorList: [],
       options: [],
-      equipmentList: [],
+      // 璁惧绫诲瀷锛氫笌宸︿晶鏍戔�滆澶�/璁¢噺鍣ㄥ叿鈥濆垎绫讳繚鎸佷竴鑷�
+      equipmentList: [
+        { label: '璁惧', value: '璁惧' },
+        { label: '璁¢噺鍣ㄥ叿', value: '璁¢噺鍣ㄥ叿' }
+      ],
       deviceStatusList: [],
       props: { multiple: true, emitPath: false, value: 'id', label: 'name' },
       // 鏀堕泦璁惧妗f鏁版嵁
@@ -553,9 +585,17 @@
       editData: {
         authorizedPerson: [],
       },
+      qualifiedSupplierNames: [],
     }
   },
   computed: {
+    // 鏍″噯鏈嶅姟鏈烘瀯涓嬫媺閫夐」锛堝悎鏍间緵搴斿晢 + 褰撳墠鍊煎厹搴曪級
+    calibrationServiceOptions() {
+      const list = this.qualifiedSupplierNames.slice();
+      const value = this.editData.calibrationServices;
+      if (value && list.indexOf(value) === -1) list.push(value);
+      return list;
+    },
     action() {
       return this.javaApi + '/deviceScope/uploadFile'
     }
@@ -566,8 +606,21 @@
     // 鑾峰彇鐩稿叧鏂囨。鐨勬暟鎹�
     this.getPage()
     this.timeStamp = Date.now()
+    this.obtainQualifiedSupplierList()
   },
   methods: {
+    formatDateCell(row, column, cellValue) {
+      return formatListDate(cellValue)
+    },
+    // 鎷夊彇鍚堟牸渚涘簲鍟嗗垪琛紙鏍″噯鏈嶅姟鏈烘瀯涓嬫媺閫夐」锛�
+    obtainQualifiedSupplierList() {
+      selectQualifiedSupplierManagementPage({ current: 1, size: 999 }).then(res => {
+        if (res.code === 200) {
+          const rows = (res.data && res.data.records) || [];
+          this.qualifiedSupplierNames = [...new Set(rows.map(r => r.supplierName).filter(Boolean))];
+        }
+      });
+    },
     // 鍘熷厛鐨� Vue2 filter锛孷ue3 宸茬Щ闄� filters 閫夐」锛屾敼涓烘柟娉曡皟鐢�
     formaterDateTime(dateTime) {
       if (dateTime === undefined || dateTime === null || dateTime === '') {
@@ -602,8 +655,6 @@
     openFileRevisionDialog() {
       // 鑾峰彇妗f淇璐熻矗浜轰笅鎷夋鏁版嵁
       this.selectDevicePrincipal()
-      // 鑾峰彇妗f淇鎵�灞為儴闂ㄤ笅鎷夋鏁版嵁
-      this.obtainItemParameterList()
       // 鑾峰彇妗f淇璁惧鐘舵�佷笅鎷夋鏁版嵁
       this.selectEnumByCategory()
       // 鑾峰彇妗f淇妫�楠岄」鐩骇鑱斿脊妗嗘暟鎹�
@@ -611,12 +662,14 @@
     },
     //闄勪欢鍜岀浉鍏虫枃妗d簨浠�
     handleAttachmentClick(row) {
-      console.log(row)
-      if (row.fileName) {
-        this.$download.saveAs(row.fileName)
-      } else {
+      if (!row.systemFileName) {
         this.$message.warning('鏈笂浼犳枃浠讹紒')
+        return
       }
+      // 鍥剧墖瀛� /img/锛屽叾浠栨枃妗e瓨 /word/
+      const isImage = /\.(jpg|jpeg|png|gif|bmp|webp)$/i.test(row.systemFileName)
+      const url = this.javaApi + (isImage ? '/img/' : '/word/') + row.systemFileName
+      this.$download.saveAs(url, row.fileName || row.systemFileName)
     },
     handleViewClick(row) {
       this.isAddFileUpdate = true
@@ -650,11 +703,23 @@
       })
     },
     saveRecord() {
+      if (!this.addFile.name) {
+        this.$message.warning('璇疯緭鍏ユ。妗堝悕绉�')
+        return
+      }
+      if (this.addFile.documentType !== 0 && this.addFile.documentType !== '0' &&
+        this.addFile.documentType !== 1 && this.addFile.documentType !== '1') {
+        this.$message.warning('璇烽�夋嫨缁存姢绫诲瀷')
+        return
+      }
       //杞崲鏁版嵁
       this.addFile.deviceId = this.clickNodeVal.value
+      // 鏂颁笂浼犳椂 systemFileName 鏄� {name: 鍘熷鏂囦欢鍚�, url: 瀛樺偍鏂囦欢鍚峿锛涚紪杈戞棫璁板綍鏃跺凡鏄瓧绗︿覆
       let obj = this.addFile.systemFileName
-      this.addFile.systemFileName = obj.name
-      this.addFile.fileName = obj.url
+      if (obj && typeof obj === 'object') {
+        this.addFile.systemFileName = obj.url
+        this.addFile.fileName = obj.name
+      }
 
       // 鏇存柊
       if (this.isAddFileUpdate) {
@@ -686,11 +751,17 @@
       }
     },
     handleRemove(file, fileList) {
-      this.deleteFile(this.addFile.systemFileName)
+      const obj = this.addFile.systemFileName
+      const fileName = obj && typeof obj === 'object' ? obj.url : obj
+      if (fileName) this.deleteFile(fileName)
+      this.addFile.systemFileName = ''
+      this.addFile.fileName = ''
     },
     deleteFile(fileName) {
       deleteCNASFile({ fileName }).then(res => {
-        this.$message.success('鍒犻櫎鎴愬姛锛�')
+        if (res.code == 200) {
+          this.$message.success('鍒犻櫎鎴愬姛锛�')
+        }
       })
     },
     handleExceed(files, fileList) {
@@ -706,16 +777,37 @@
           this.tableDataA = res.data
       })
     },
+    // 琚巿鏉冧汉鍘嗗彶鍊煎彲鑳芥槸琚弽澶嶈浆涔夌殑澶氬眰 JSON 瀛楃涓诧紝閫愬眰瑙f瀽杩樺師鎴愭暟缁�
+    normalizeAuthorizedPerson(val) {
+      let v = val
+      for (let i = 0; i < 10; i++) {
+        if (typeof v !== 'string') break
+        if (v === '') {
+          v = []
+          break
+        }
+        try {
+          v = JSON.parse(v)
+        } catch (e) {
+          v = []
+          break
+        }
+      }
+      if (!Array.isArray(v)) {
+        v = v === '' || v === null || v === undefined ? [] : [v]
+      }
+      return v.filter(x => x !== '' && x !== null && x !== undefined)
+    },
     // 鏀堕泦鏁版嵁
     getList(id) {
       selectDeviceByCode({ id }).then(res => {
         // 灏嗗垎绫诲垪琛ㄧ殑淇℃伅瀛樿捣鏉�
         if (res.code == 200) {
           this.Mdata = res.data;
-          this.Mdata.insProductIds = this.Mdata.insProductIds.split(',')
-          if (this.Mdata.authorizedPerson) {
-            this.Mdata.authorizedPerson = JSON.parse(this.Mdata.authorizedPerson)
-          }
+          this.Mdata.insProductIds = this.Mdata.insProductIds
+              ? String(this.Mdata.insProductIds).split(',')
+              : []
+          this.Mdata.authorizedPerson = this.normalizeAuthorizedPerson(this.Mdata.authorizedPerson)
         }
       });
     },
@@ -732,57 +824,74 @@
     //鎵撳紑淇妗f寮规
     openEditForm() {
       this.editData = JSON.parse(JSON.stringify(this.Mdata))
+      // 璁惧绫诲瀷涓虹┖鏃讹紝榛樿鍙栧乏渚ф爲褰撳墠鎵�鍦ㄥ垎绫�
+      const treeCategory = this.clickNodeVal && this.clickNodeVal.parent ? this.clickNodeVal.parent.label : ''
+      if (!this.editData.largeCategory && (treeCategory === '璁惧' || treeCategory === '璁¢噺鍣ㄥ叿')) {
+        this.editData.largeCategory = treeCategory
+      }
       this.$nextTick(() => {
         this.dialogVisible = true
       })
     },
+    // 涓嬫鏃ユ湡 = 鏈�杩戞棩鏈� + 鍛ㄦ湡锛堟湀锛夛紝鑷姩璁$畻
+    calcNextDate(data) {
+      const calc = (lastDate, cycle) => {
+        const period = parseInt(cycle)
+        if (!lastDate || !period || period <= 0) {
+          return null
+        }
+        return dayjs(String(lastDate).replace(' ', 'T'))
+          .add(period, 'month')
+          .format('YYYY-MM-DD HH:mm:ss')
+      }
+      const nextCalibrationDate = calc(data.lastCalibrationDate, data.calibrationDate)
+      if (nextCalibrationDate) {
+        data.nextCalibrationDate = nextCalibrationDate
+      }
+      const nextMaintenanceDate = calc(data.lastMaintenanceDate, data.maintenanceCycle)
+      if (nextMaintenanceDate) {
+        data.nextMaintenanceDate = nextMaintenanceDate
+      }
+      const nextExamineDate = calc(data.lastExamineDate, data.examineCycle)
+      if (nextExamineDate) {
+        data.nextExamineDate = nextExamineDate
+      }
+    },
     //淇妗f
     submitForm() {
-      let flag = true
-      this.$refs['rules1'].validate((valid) => {
-        if (!valid) {
-          flag = false;
-          return false;
+      // validate() 杩斿洖 Promise锛岀粺涓�绛夊洓涓〃鍗曞叏閮ㄦ牎楠屽畬鍐嶅垽鏂�
+      const formRefs = ['rules1', 'rules2', 'ruleForm', 'cycleForm']
+      Promise.all(formRefs.map(ref => this.$refs[ref].validate().catch(() => false))).then(results => {
+        if (results.some(valid => !valid)) {
+          return
         }
-      });
-      this.$refs['rules2'].validate((valid) => {
-        if (!valid) {
-          flag = false;
-          return false;
-        }
-      });
-      this.$refs['ruleForm'].validate((valid) => {
-        if (!valid) {
-          flag = false;
-          return false;
-        }
-      });
-      if (!flag) {
-        return;
-      }
-      delete this.editData.createTime
-      delete this.editData.updateTime
-      delete this.editData.createUser
-      delete this.editData.updateUser
-      delete this.editData.orderBy
-      const formData = this.HaveJson(this.editData)
-      formData.userAllow = this.equipmentManager.toString();
-      formData.insProductIds = Array.isArray(formData.insProductIds) ? formData.insProductIds.join(',') : '';
-      if (formData.authorizedPerson.length === 0) {
-        formData.authorizedPerson = ''
-      } else {
-        formData.authorizedPerson = JSON.stringify(formData.authorizedPerson)
-      }
-      this.upLoad = true;
-      upDeviceParameter(formData).then(res => {
-        this.$message.success('淇敼鎴愬姛')
-        this.upLoad = false
-        this.getList(this.clickNodeVal.value)
-        this.dialogVisible = false
-      }).catch(e => {
-        this.$message.error('淇敼澶辫触')
-        this.dialogVisible = false
-        this.upLoad = false
+        delete this.editData.createTime
+        delete this.editData.updateTime
+        delete this.editData.createUser
+        delete this.editData.updateUser
+        delete this.editData.orderBy
+        const formData = this.HaveJson(this.editData)
+        formData.insProductIds = Array.isArray(formData.insProductIds) ? formData.insProductIds.join(',') : '';
+        formData.authorizedPerson = Array.isArray(formData.authorizedPerson) && formData.authorizedPerson.length
+          ? JSON.stringify(formData.authorizedPerson)
+          : ''
+        this.upLoad = true;
+        upDeviceParameter(formData).then(res => {
+          this.upLoad = false
+          if (res.code == 200) {
+            this.$message.success('淇敼鎴愬姛')
+            this.getList(this.clickNodeVal.value)
+            // 绫诲瀷鍙兘鍙樻洿锛屽埛鏂板乏渚ф爲璁╄澶囧綊鍒版柊鐨勫垎绫讳笅
+            this.$emit('refresh-tree')
+            this.dialogVisible = false
+          } else {
+            this.$message.error(res.message || res.msg || '淇敼澶辫触')
+          }
+        }).catch(e => {
+          // 澶辫触淇濈暀寮圭獥锛岄伩鍏嶅凡缂栬緫鍐呭涓㈠け
+          this.$message.error('淇敼澶辫触')
+          this.upLoad = false
+        })
       })
     },
     // 瀵煎嚭
@@ -790,9 +899,18 @@
       this.outLoading = true
       exportDeviceFile({ deviceId: this.clickNodeVal.value }).then(res => {
         this.outLoading = false
-        const blob = new Blob([res], { type: 'application/octet-stream' });
-        this.$download.saveAs(blob, '璁惧妗f鍗�.doc')
+        saveBlobOrShowError(res, '璁惧妗f鍗�.doc', 'application/msword')
+      }).catch(() => {
+        this.outLoading = false
       })
+    },
+    // 淇寮圭獥鎸変竾鍏冨綍鍏ワ紝妗f璇︽儏鎸夊厓灞曠ず
+    formatPurchasePrice(val) {
+      if (val === null || val === undefined || val === '') {
+        return '-'
+      }
+      const num = Number(val)
+      return isNaN(num) ? val : num * 10000
     },
     handleSuccessUpImg2(response) {
       if (response.code == 200) {
@@ -822,17 +940,9 @@
       selectUserCondition().then(res => {
         this.responsiblePersonList = res.data;
       })
-    },
-    obtainItemParameterList() {
-      obtainItemParameterList().then(res => {
-        let data = []
-        res.data.forEach(a => {
-          data.push({
-            label: a.laboratoryName,
-            value: a.id
-          })
-        })
-        this.subordinateDepartmentsList = data
+      // 琚巿鏉冧汉涓嬫媺鍙彇妫�娴嬪憳瑙掕壊浜哄憳
+      selectUserCondition({ type: 3 }).then(res => {
+        this.inspectorList = res.data;
       })
     },
     getInsProductIds() {
@@ -870,10 +980,6 @@
             a.value = parseInt(a.value)
           }
         })
-      });
-      // 璁惧鍒嗙被
-      this.getDicts("device_type").then((response) => {
-        this.equipmentList = this.dictToValue(response.data);
       });
     },
   },
@@ -930,6 +1036,57 @@
   width: 100%;
 }
 
+.cycle-row {
+  display: flex;
+  align-items: center;
+}
+
+.cycle-title {
+  width: 68px;
+  flex-shrink: 0;
+  font-size: 13px;
+  color: var(--lims-text-2, #909399);
+}
+
+.cycle-item {
+  flex: 1;
+  margin-bottom: 6px;
+  margin-right: 10px;
+}
+
+.cycle-item:last-child {
+  margin-right: 0;
+}
+
+.form-row {
+  display: flex;
+  gap: 16px;
+}
+
+.form-row > .el-form-item {
+  flex: 1;
+}
+
+.section-title {
+  position: relative;
+  padding-left: 10px;
+  margin: 14px 0 12px;
+  font-size: 13px;
+  font-weight: 600;
+  color: var(--lims-text-1, #303133);
+}
+
+.section-title::before {
+  content: "";
+  position: absolute;
+  left: 0;
+  top: 3px;
+  bottom: 3px;
+  width: 3px;
+  border-radius: 2px;
+  background: var(--el-color-primary, #409eff);
+}
+
 .el-image {
   position: relative;
 }
@@ -976,7 +1133,7 @@
   display: inline-block;
   text-align: right;
   margin-right: 20px;
-  color: #999;
+  color: var(--lims-text-3);
 }
 
 .form-item p {

--
Gitblit v1.9.3