From 57973d2a25401a8137de116f4e200ab14610e7d6 Mon Sep 17 00:00:00 2001
From: liding <756868258@qq.com>
Date: 星期四, 08 十月 2026 13:32:48 +0800
Subject: [PATCH] feat(order): 新增订单编辑功能并完善表单验证 - 实现订单表单验证规则,包括送样日期必填验证 - 修复送样日期字段映射问题 - 完善文件上传组件的动态宽度计算 - 添加检验依据搜索过滤功能

---
 src/components/Table/lims-table.vue                        |   16 ++
 src/views/standard/model/index.vue                         |    6 +
 src/api/business/inspectionTask.js                         |    1 
 src/views/business/productOrder/components/addOrder.vue    |  172 +++++++++++++++++++++++++++++-----
 src/views/business/productOrder/components/printDialog.vue |    6 
 src/views/business/productOrder/index.vue                  |   55 ++++++----
 src/router/index.js                                        |    6 +
 src/api/business/add.js                                    |    8 +
 8 files changed, 216 insertions(+), 54 deletions(-)

diff --git a/src/api/business/add.js b/src/api/business/add.js
index 053a9cf..82e45f3 100644
--- a/src/api/business/add.js
+++ b/src/api/business/add.js
@@ -16,6 +16,14 @@
     data: query
   })
 }
+// 淇敼鏂拌仛妫�楠屼笅鍗曞唴瀹�
+export function updateNewJuInsOrder(query) {
+  return request({
+    url: '/insOrder/updateNewJuInsOrder',
+    method: 'post',
+    data: query
+  })
+}
 // 妫�楠岀被鍒负鎶芥鏃舵帀鎺ュ彛
 export function judgeNotSpotCheckOrder(query) {
   return request({
diff --git a/src/api/business/inspectionTask.js b/src/api/business/inspectionTask.js
index d331635..2308b9d 100644
--- a/src/api/business/inspectionTask.js
+++ b/src/api/business/inspectionTask.js
@@ -115,6 +115,7 @@
     url: "/insOrderPlan/uploadFile",
     method: "post",
     data: data,
+    headers: { "Content-Type": "multipart/form-data" },
   });
 }
 
diff --git a/src/components/Table/lims-table.vue b/src/components/Table/lims-table.vue
index 2c36721..d8e09e0 100644
--- a/src/components/Table/lims-table.vue
+++ b/src/components/Table/lims-table.vue
@@ -264,11 +264,21 @@
   data() {
     return {
       spanList: [],
-      btnWidth: "120px",
       uploadRefs: [],
       currentFiles: {}, // 鐢ㄤ簬瀛樺偍姣忚鐨勫綋鍓嶆枃浠�
       uploadKeys: {} // 鐢ㄤ簬鍔ㄦ�侀噸缃粍浠�
     };
+  },
+  computed: {
+    btnWidth() {
+      let width = 120;
+      this.column.filter(item => item.dataType === 'action').forEach(item => {
+        this.tableData.forEach(row => {
+          width = Math.max(width, parseInt(this.getWidth(item.operation, row), 10));
+        });
+      });
+      return `${width}px`;
+    }
   },
   mounted() {
     this.calculateSpanInfo();
@@ -302,7 +312,6 @@
           count += a.name.length;
         }
       });
-      this.btnWidth = count * 15 + 60 + "px";
       return count * 15 + 60 + "px";
     },
     getTitleWidth(row) {
@@ -321,6 +330,9 @@
       }
     },
     iconFn(row) {
+      if (Object.prototype.hasOwnProperty.call(row, 'icon')) {
+        return row.icon;
+      }
       if (row.name === "缂栬緫" || row.name === "淇敼") {
         return "el-icon-edit";
       } else if (row.name === "鏌ョ湅") {
diff --git a/src/router/index.js b/src/router/index.js
index fb1442b..9a4be26 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -155,6 +155,12 @@
         meta: { title: "鏌ョ湅鎴愬搧涓嬪崟璇︽儏", activeMenu: "/business/productOrder",keepAlive: true },
       },
       {
+        path: "inspectionView",
+        component: () => import("@/views/business/inspectionView/index.vue"),
+        name: "ProductOrderInspectionView",
+        meta: { title: "鍘熷璁板綍", activeMenu: "/business/productOrder", keepAlive: false },
+      },
+      {
         // 杩涜涓嬪崟-鎴愬搧涓嬪崟
         path: "addOrder",
         component: () =>
diff --git a/src/views/business/productOrder/components/addOrder.vue b/src/views/business/productOrder/components/addOrder.vue
index 6b3bcf9..5bcc3f1 100644
--- a/src/views/business/productOrder/components/addOrder.vue
+++ b/src/views/business/productOrder/components/addOrder.vue
@@ -47,7 +47,7 @@
     </div>
     <div v-show="!cableConfigShow&&!auxiliaryShow" class="order-body">
       <el-card shadow="never" class="order-card">
-        <el-form ref="newJuOrder" class="newju-order-form" :model="addObj" size="small" label-width="108px"
+        <el-form ref="newJuOrder" class="newju-order-form" :model="addObj" :rules="newJuOrderRules" size="small" label-width="108px"
                  label-position="right">
           <el-row :gutter="16">
             <el-col :span="6">
@@ -135,7 +135,7 @@
               </el-form-item>
             </el-col>
             <el-col :span="6">
-              <el-form-item label="閫佹牱鏃ユ湡">
+              <el-form-item label="閫佹牱鏃ユ湡" prop="sampleDate">
                 <el-date-picker v-model="addObj.sampleDate" type="date" value-format="yyyy-MM-dd" :disabled="active>1"
                                 size="small"/>
               </el-form-item>
@@ -208,6 +208,17 @@
               <el-form-item label="澶囨敞">
                 <el-input v-model="addObj.remark" :disabled="active>1" size="small"
                           placeholder="鍙�夛紝琛ュ厖璇存槑濮旀墭浜嬮」"/>
+              </el-form-item>
+            </el-col>
+          </el-row>
+          <el-row :gutter="16">
+            <el-col :span="24">
+              <el-form-item label="闄勪欢">
+                <el-upload ref="orderFileUpload" action="#" :auto-upload="false" multiple :file-list="fileList"
+                           :disabled="active>1" :on-change="handleFileChange" :on-remove="handleFileRemove">
+                  <el-button :disabled="active>1" size="small" type="primary">閫夋嫨闄勪欢</el-button>
+                  <div slot="tip" class="el-upload__tip">鏀寔澶氭枃浠朵笂浼狅紝鍗曚釜鏂囦欢涓嶈秴杩�200MB</div>
+                </el-upload>
               </el-form-item>
             </el-col>
           </el-row>
@@ -821,16 +832,18 @@
   getInsOrder,
   getUserNow, selectInsOrderTemplate,
   selectStandardMethodEnum, selectStandardProductList,
-  selectStandardTreeList2
+  selectStandardTreeList2, getFileList, delFile
 } from "@/api/business/rawMaterialOrder";
 import {
   addInsOrder, addInsOrderTemplate, delInsOrderTemplate,
   getQuarterOnOrder, judgeNotSpotCheckOrder, selectInsOrderTemplateById,
   updateInsOrder,
+  updateNewJuInsOrder,
   upInsOrder,
   upInsOrderOfState
 } from "@/api/business/add";
 import {selectUserCondition} from "@/api/performance/class";
+import {uploadFile} from "@/api/business/inspectionTask";
 import {selectTemplateBindings, selectsStandardMethodByFLSSM} from "@/api/standard/standardLibrary";
 import limsTable from "@/components/Table/lims-table.vue";
 import {selectCustomPageList} from "@/api/system/customer";
@@ -868,7 +881,12 @@
       active: '',
       tabIndex: '',
       currentId: '',
+      isEdit: false,
+      hasActivated: false,
+      orderLoadVersion: 0,
       sampleCode: '',
+      fileList: [],
+      deleteFileIds: [],
       boundTemplateList: [],
       templateBindingLoading: false,
       sampleSelectionList: [],//鏍峰搧琛ㄦ牸閫変腑鏁版嵁
@@ -919,6 +937,9 @@
         reportDelivery: 1,
         reportAddress: '',
         reportReceiver: '',
+      },
+      newJuOrderRules: {
+        sampleDate: [{required: true, message: '璇烽�夋嫨閫佹牱鏃ユ湡', trigger: 'change'}],
       },
       addObjRules: { // 琛ㄥ崟鏍¢獙瑙勫垯
         orderType: [
@@ -1056,6 +1077,11 @@
     }
   },
   watch: {
+    '$route'(to, from) {
+      if (to.path === from.path && to.fullPath !== from.fullPath && to.name === 'AddOrder') {
+        this.loadRouteOrder(true)
+      }
+    },
     // sampleList() {
     //   this.addObj.method = null
     //   this.productList = []
@@ -1100,24 +1126,41 @@
     }
   },
   mounted() {
-    this.active = this.$route.query.active
-    this.tabIndex = this.$route.query.tabIndex
-    this.currentId = this.$route.query.currentId
-    this.getUserNowData()
-    this.getInfo()
-    if (this.tabIndex == 4 && this.active == 2) {
-      this.isSpecial = true
-    } else {
-      this.isSpecial = false
-    }
+    this.loadRouteOrder(false)
   },
   activated() {
-    this.active = this.$route.query.active
-    this.tabIndex = this.$route.query.tabIndex
-    this.currentId = this.$route.query.currentId
-    this.getInfo();
+    if (!this.hasActivated) {
+      this.hasActivated = true
+      return
+    }
+    this.loadRouteOrder(true)
   },
   methods: {
+    loadRouteOrder(reset) {
+      if (reset) this.resetOrderPage()
+      this.active = this.$route.query.active
+      this.tabIndex = this.$route.query.tabIndex
+      this.currentId = this.$route.query.currentId
+      this.isEdit = this.$route.query.edit == 1
+      if (this.active == 1 && !this.isEdit) this.getUserNowData()
+      this.getInfo()
+      this.isSpecial = this.tabIndex == 4 && this.active == 2
+    },
+    resetOrderPage() {
+      this.orderLoadVersion++
+      const defaults = this.$options.data.call(this)
+      const fields = ['addObj', 'sample', 'sampleCode', 'fileList', 'deleteFileIds',
+        'boundTemplateList', 'sampleSelectionList', 'editTable', 'sampleList',
+        'productList', 'productList0', 'productIds', 'sampleIds', 'selectTree',
+        'selectTreeNode', 'selectiveEcho', 'specialStandardMethod', 'model',
+        'standardMethodListId', 'template', 'templates', 'addObj1', 'totalArr',
+        'methodS', 'inspectionItem', 'inspectionItemSubclass', 'currentMethod',
+        'filters', 'selectStandardTree', 'search', 'expandedKeys', 'sampleViewEn'
+      ]
+      fields.forEach(key => { this[key] = defaults[key] })
+      if (this.$refs.orderFileUpload) this.$refs.orderFileUpload.clearFiles()
+      if (this.$refs.newJuOrder) this.$refs.newJuOrder.clearValidate()
+    },
     /**
      * 鑾峰彇灏忔暟鐨勬渶澶т綅鏁�
      * @param number  鍨嬪彿鍙傛暟
@@ -1153,23 +1196,33 @@
       this.selectStandardTreeList()
       this.getAuthorizedPerson();
       this.selectStandardMethods()
-      if (this.active != 1) {
+      if (this.active != 1 || this.isEdit) {
+        const orderId = this.currentId
+        const loadVersion = this.orderLoadVersion
         // 鏌ョ湅/瀹℃牳娴佺▼
         // 璇锋眰鎺ュ彛锛屽洖鏄炬暟鎹�
         getInsOrder({
-          orderId: this.currentId
+          orderId
         }).then(res => {
+          if (loadVersion !== this.orderLoadVersion || orderId !== this.currentId) return
           this.addObj = {
             ...res.data.insOrder
           };
+          if (res.data.standardTreeId) {
+            this.$set(this.addObj, 'standardTreeId', res.data.standardTreeId)
+          } else if (this.isEdit) {
+            this.$message.warning('鍘熸爣鍑嗕笌璁㈠崟妯℃澘鏃犳硶鍞竴鍖归厤锛岃閲嶆柊閫夋嫨妫�娴嬩緷鎹�')
+          }
           this.addObj.type = String(this.addObj.type)
           const samples = this.HaveJson(res.data.sampleProduct)
           this.sampleCode = res.data.sampleCode || (samples.length ? samples[0].sampleCode || '' : '')
           this.boundTemplateList = this.sortTemplateList(res.data.templateList)
+          this.loadOrderFiles()
           const loadSamples = this.canSelectProduct
             ? Promise.all(samples.map(sample => this.loadSelectableProducts(sample)))
             : Promise.resolve(samples)
           loadSamples.then(sampleList => {
+            if (loadVersion !== this.orderLoadVersion || orderId !== this.currentId) return
             this.sampleList = sampleList
             this.specialStandardMethod = this.sampleList[0].specialStandardMethod
             this.getProNum()
@@ -1323,7 +1376,7 @@
       this.addObj.code = this.multipleSelection[0].code
       this.addObj.companyId = this.multipleSelection[0].id
       this.selectUserDia = false
-      if (this.active == 1) {
+      if (this.active === 1) {
         // TODO
         this.selectInsOrderTemplate()
       }
@@ -1407,6 +1460,14 @@
       return str.replaceAll(find, value);
     },
     save() {
+      if (this.isEdit && !this.addObj.standardTreeId) {
+        this.$message.error('璇烽噸鏂伴�夋嫨妫�娴嬩緷鎹強鍘熷璁板綍妯℃澘')
+        return;
+      }
+      if (!this.addObj.sampleDate) {
+        this.$refs.newJuOrder.validateField('sampleDate');
+        return;
+      }
       if (this.addObj.standardTreeId) {
         if (!this.addObj.sample || !this.addObj.company || !this.addObj.orderType || !this.addObj.testQuantity) {
           this.$message.error('璇峰~鍐欐娴嬩緷鎹�佸鎵樺崟浣嶃�佹楠岀被鍒拰鏍峰搧鏁伴噺');
@@ -1414,7 +1475,7 @@
         }
         if (this.addObj.subcontractType == null || this.addObj.sampleDisposal == null
           || this.addObj.resultEvaluation == null || this.addObj.reportDelivery == null) {
-          this.$message.error('璇烽�夋嫨鍒嗗寘鍐呭銆佹牱鍝佸缃�佸缁撴灉璇勪环鍜屾姤鍛婁氦浠樻柟寮�');
+          this.$message.error('璇烽�夋嫨濮旀墭鍗曚綅');
           return;
         }
         if (this.addObj.subcontractType === 1 && !this.addObj.subcontractCompany) {
@@ -1615,9 +1676,6 @@
       if (this.addObj.quarterItemId) {
         this.addObj.quarterItemId = this.addObj.quarterItemId[1]
       }
-      if (this.addObj.createTime) {
-        delete this.addObj.createTime
-      }
       if (this.addObj.orderType === '鎶芥') {
         judgeNotSpotCheckOrder({insOrder: this.addObj, sampleList: sampleList}).then(res => {
           if (res.data === true) {
@@ -1652,6 +1710,7 @@
           ? null : this.addObj.productionDate,
         typeSource: -1,
       }
+      delete insOrder.createTime
       if (this.tabIndex == 4 && this.active == 2) {
         // 閫�鍥炲悗鎻愪氦
         updateInsOrder({insOrder, sampleProduct: sampleList}).then(res => {
@@ -1675,14 +1734,73 @@
             templateList: this.boundTemplateList.map((item, index) => ({templateId: item.templateId, sort: index}))
           }
           : {insOrder, sampleList: sampleList}
-        addInsOrder(payload).then(res => {
+        const request = this.isEdit
+          ? updateNewJuInsOrder({...payload, orderId: this.currentId})
+          : addInsOrder(payload)
+        request.then(async res => {
+          const orderId = this.isEdit ? this.currentId : res.data
+          const fileSuccess = await this.saveOrderFiles(orderId)
           this.saveLoad = false
-          this.$message.success('宸叉彁浜�')
+          if (!fileSuccess) {
+            this.$message.warning('璁㈠崟宸蹭繚瀛橈紝閮ㄥ垎闄勪欢澶勭悊澶辫触锛岃閲嶈瘯')
+            this.currentId = orderId
+            this.isEdit = true
+            this.loadOrderFiles()
+            return
+          }
+          this.$message.success(this.isEdit ? '淇敼鎴愬姛' : '宸叉彁浜�')
           this.bsm3Dia = false;
           this.closeOpenPage()
         }).catch(e => {
           this.saveLoad = false
         })
+      }
+    },
+    handleFileChange(file, fileList) {
+      if (file.size > 200 * 1024 * 1024) {
+        this.$message.error('鍗曚釜闄勪欢涓嶈兘瓒呰繃200MB')
+        this.fileList = fileList.filter(item => item.uid !== file.uid)
+        return
+      }
+      this.fileList = fileList
+    },
+    handleFileRemove(file, fileList) {
+      if (file.id) {
+        this.deleteFileIds.push(file.id)
+      }
+      this.fileList = fileList
+    },
+    loadOrderFiles() {
+      if (!this.currentId) return
+      const orderId = this.currentId
+      const loadVersion = this.orderLoadVersion
+      getFileList({insOrderId: orderId, current: -1, size: -1}).then(res => {
+        if (loadVersion !== this.orderLoadVersion || orderId !== this.currentId) return
+        this.fileList = (res.data.records || []).map(item => ({
+          name: item.fileName,
+          id: item.id,
+          status: 'success'
+        }))
+      })
+    },
+    async saveOrderFiles(orderId) {
+      try {
+        for (const id of this.deleteFileIds) {
+          await delFile({id})
+        }
+        this.deleteFileIds = []
+        for (const file of this.fileList) {
+          if (file.id || !file.raw) continue
+          const formData = new FormData()
+          formData.append('orderId', orderId)
+          formData.append('file', file.raw)
+          const res = await uploadFile(formData)
+          if (res.code !== 200 || !res.data) return false
+          file.id = res.data
+        }
+        return true
+      } catch (e) {
+        return false
       }
     },
     upInsOrderOfState(state) {
@@ -1733,9 +1851,11 @@
       })
     },
     getUserNowData() {
+      const loadVersion = this.orderLoadVersion
       this.addObj.prepareUserEn = this.nameEn
       this.addObj.prepareCode = this.userName
       getUserNow().then(res => {
+        if (loadVersion !== this.orderLoadVersion || this.active != 1 || this.isEdit) return
         let selects = res.data
         if (selects == null) return
         this.addObj.userId = selects.id
diff --git a/src/views/business/productOrder/components/printDialog.vue b/src/views/business/productOrder/components/printDialog.vue
index 4125bdf..8ef6b6d 100644
--- a/src/views/business/productOrder/components/printDialog.vue
+++ b/src/views/business/productOrder/components/printDialog.vue
@@ -38,7 +38,7 @@
                     </span>
                     <span class="label-col">
                       <span class="full-title">閫佹牱鏃ユ湡</span>:
-                      <span class="value-wrap">{{ item.sendTime }}</span>
+                      <span class="value-wrap">{{ item.sampleDate || '-' }}</span>
                     </span>
                   </div>
                   <div class="item label-row">
@@ -107,7 +107,7 @@
                 </span>
                 <span class="label-col">
                   <span class="full-title4">閫佹牱鏃ユ湡:</span>
-                  <span class="value-wrap">{{ item.sendTime }}</span>
+                  <span class="value-wrap">{{ item.sampleDate || '-' }}</span>
                 </span>
               </div>
               <div class="item label-row">
@@ -179,7 +179,7 @@
         }).then(res => {
           if (res.code === 200 && res.data.length > 0) {
             res.data.forEach(item => {
-              item.sendTime = item.sendTime && item.sendTime.substring(0, 10)
+              item.sampleDate = item.sampleDate && item.sampleDate.substring(0, 10)
               item.sampleNumber = item.qtyArrived + item.buyUnitMeas
               this.$set(item, 'barcode', item.entrustCode)
               this.$set(item, 'isLeave', item.insState === '2')
diff --git a/src/views/business/productOrder/index.vue b/src/views/business/productOrder/index.vue
index 114f96d..f079beb 100644
--- a/src/views/business/productOrder/index.vue
+++ b/src/views/business/productOrder/index.vue
@@ -342,6 +342,17 @@
           label: '鎿嶄綔',
           operation: [
             {
+              name: '缂栬緫',
+              type: 'text',
+              icon: '',
+              clickFun: (row) => {
+                this.editOrder(row);
+              },
+              showHide: (row) => {
+                return row.editable === true || row.editable === 1
+              }
+            },
+            {
               name: '鏌ョ湅璇︽儏',
               type: 'text',
               clickFun: (row) => {
@@ -763,6 +774,17 @@
       this.upLoad = false;
     },
     // 鐐瑰嚮鏍峰搧鍚嶇О
+    editOrder(row) {
+      this.$router.push({
+        path: "/productOrder/addOrder", query: {
+          examine: 0,
+          active: 1,
+          edit: 1,
+          currentId: row.id,
+          tabIndex: this.tabIndex,
+        }
+      });
+    },
     selectAllByOne(row) {
       if (this.tabIndex === 4) {
         this.$router.push({
@@ -993,29 +1015,16 @@
         inspectorList = row.userName.split(',')
       }
       inspectorList.push(this.nickName)
-      if (this.checkPermi(['business:inspectionView'])) {
-        this.$router.push({
-          name: "InspectionView",
-          query: {
-            sonLaboratory: null,
-            state: 3,
-            typeSource: row.typeSource,
-            orderId: row.id,
-            inspectorList: inspectorList,
-          },
-        })
-      } else {
-        this.$router.push({
-          path: "/inspectionTask/inspection",
-          query: {
-            sonLaboratory: null,
-            state: 3,
-            typeSource: row.typeSource,
-            orderId: row.id,
-            inspectorList: inspectorList,
-          },
-        })
-      }
+      this.$router.push({
+        path: "/productOrder/inspectionView",
+        query: {
+          sonLaboratory: null,
+          state: 3,
+          typeSource: row.typeSource,
+          orderId: row.id,
+          inspectorList: inspectorList,
+        },
+      })
     },
     goback() {
       this.state = 0
diff --git a/src/views/standard/model/index.vue b/src/views/standard/model/index.vue
index dcdfef6..aee7717 100644
--- a/src/views/standard/model/index.vue
+++ b/src/views/standard/model/index.vue
@@ -7,6 +7,11 @@
           <el-input v-model="queryParams.name" clearable placeholder="璇疯緭鍏�" size="small"
                     @keyup.enter.native="refreshTable()"></el-input>
         </div>
+        <div class="search_item">
+          <span class="search_label">妫�楠屼緷鎹�</span>
+          <el-input v-model="queryParams.number" clearable placeholder="璇疯緭鍏�" size="small"
+                    @keyup.enter.native="refreshTable()"></el-input>
+        </div>
         <div class="search_button">
           <el-button type="primary" size="mini" @click="refreshTable">鏌ヨ</el-button>
           <el-button size="mini" @click="refresh">閲嶇疆</el-button>
@@ -90,6 +95,7 @@
       },
       queryParams: {
         name: null,
+        number: null,
       },
       tableData: [],
       column: [

--
Gitblit v1.9.3