feat(order): 新增订单编辑功能并完善表单验证
- 实现订单表单验证规则,包括送样日期必填验证
- 修复送样日期字段映射问题
- 完善文件上传组件的动态宽度计算
- 添加检验依据搜索过滤功能
已修改8个文件
248 ■■■■■ 文件已修改
src/api/business/add.js 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/business/inspectionTask.js 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Table/lims-table.vue 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/index.js 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/business/productOrder/components/addOrder.vue 168 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/business/productOrder/components/printDialog.vue 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/business/productOrder/index.vue 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/standard/model/index.vue 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
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({
src/api/business/inspectionTask.js
@@ -115,6 +115,7 @@
    url: "/insOrderPlan/uploadFile",
    method: "post",
    data: data,
    headers: { "Content-Type": "multipart/form-data" },
  });
}
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 === "查看") {
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: () =>
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() {
    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.getInfo();
      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
  },
  methods: {
    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
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')
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,9 +1015,8 @@
        inspectorList = row.userName.split(',')
      }
      inspectorList.push(this.nickName)
      if (this.checkPermi(['business:inspectionView'])) {
        this.$router.push({
          name: "InspectionView",
        path: "/productOrder/inspectionView",
          query: {
            sonLaboratory: null,
            state: 3,
@@ -1004,18 +1025,6 @@
            inspectorList: inspectorList,
          },
        })
      } else {
        this.$router.push({
          path: "/inspectionTask/inspection",
          query: {
            sonLaboratory: null,
            state: 3,
            typeSource: row.typeSource,
            orderId: row.id,
            inspectorList: inspectorList,
          },
        })
      }
    },
    goback() {
      this.state = 0
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: [