新疆——新聚lims
1.检验任务详情逻辑重构,不需要判断结论逻辑,添加复杂运算逻辑
已修改6个文件
3129 ■■■■ 文件已修改
src/utils/excelFountion.js 100 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/business/inspectionTask/components/InspectionWord.vue 733 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/business/inspectionTask/inspection.vue 834 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/business/inspectionView/index.vue 831 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/workers/InspectionWorker.worker.js 624 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
vue.config.js 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/excelFountion.js
@@ -169,6 +169,7 @@
 */
function getIdFromColumnName(id, arr) {
  try {
    id = String(id).replace(/\$/g, "");
    // Get the letters
    var t = /^[a-zA-Z]+/.exec(id);
    if (t) {
@@ -245,9 +246,16 @@
 */
function getABCList(f) {
  try {
    if (typeof f !== "string") {
      return [];
    }
    let regex = /[=\+\-\*\%\(\)\/\^\s]/g;
    let fouList = ["SUM", "MAX", "MIN", "AVERAGE", "ABS"];
    let fouList = ["SUM", "MAX", "MIN", "AVERAGE", "ABS", "MEDIAN"];
    f = f
      .replace(/\$/g, "") // 去掉 Excel 绝对引用符号,$D$14 视为 D14
      // 区间写法里的空格(AVERAGE( D14 : D15 ))会被下面的空白替换吃掉冒号,
      // 导致区间被拆成两个独立单元格,先把区间规整成 D14:D15
      .replace(/\s*:\s*/g, ":")
      .replace(regex, ",")
      .replace(new RegExp('"&', "g"), "")
      .replace(new RegExp('&"', "g"), "");
@@ -280,6 +288,22 @@
}
/**
 * 把单元格值转成可参与 eval 的字面量,空白单元格按 0 处理(与 Excel 一致)
 *
 * @param value 单元格的值
 * @returns 数值/原始值,空值返回 0
 */
function toNumberLiteral(value) {
  if (value === null || value === undefined) {
    return 0;
  }
  if (typeof value === "string" && value.trim() === "") {
    return 0;
  }
  return value;
}
/**
 * 计算函数
 *
 * @param f 字符串类型,表示待计算的公式
@@ -288,9 +312,14 @@
 */
function compute(f, comValue) {
  try {
    let str = f;
    if (typeof f !== "string") {
      return undefined;
    }
    // 去掉 Excel 绝对引用符号,$D$14 与 D14 等价;
    // 区间里的空格也要一并去掉,否则区间 token 会因空格匹配不上而展开失败
    let str = f.replace(/\$/g, "").replace(/\s*:\s*/g, ":");
    // 获取单元格对应值
    let arr = getAllCell(f);
    let arr = getAllCell(str);
    for (var a in comValue) {
      if (
        comValue[a] !== "undefined" &&
@@ -310,43 +339,40 @@
        }
      }
    }
    // 解析公式参数,特别是带:的
    let arr0 = getABCList(f);
    let obj = {};
    arr0.forEach((item) => {
      if (item.includes(":")) {
        let arr1 = [];
        let r0 = getIdFromColumnName(item.split(":")[0]).r;
        let c0 = getIdFromColumnName(item.split(":")[0]).c;
        let r1 = getIdFromColumnName(item.split(":")[1]).r;
        let c1 = getIdFromColumnName(item.split(":")[1]).c;
        for (let i = Number(r0); i <= Number(r1); i++) {
          for (let u = Number(c0); u <= Number(c1); u++) {
            arr1.push({
              r: i,
              c: u,
    // 把区间参数(如 SUM(D14:D15) 中的 D14:D15)展开成单元格列表 D14,D15
    getABCList(str).forEach((token) => {
      if (!token.includes(":")) {
        return;
      }
      const parts = token.split(":");
      const start = getIdFromColumnName(parts[0]);
      const end = getIdFromColumnName(parts[1]);
      const cells = [];
      for (let i = Number(start.r); i <= Number(end.r); i++) {
        for (let u = Number(start.c); u <= Number(end.c); u++) {
          cells.push(getColumnNameFromId(`${u}` + "-" + `${i}`));
        }
      }
      str = str.replace(token, cells.join(","));
            });
    // 计算:一次性替换所有参数,避免 D1 与 D14 这类前缀互相污染
    const keys = Object.keys(arr);
    if (keys.length > 0) {
      const pattern = new RegExp(
        keys
          .sort((x, y) => y.length - x.length)
          .map((k) => k.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"))
          .join("|"),
        "g"
      );
      str = str.replace(pattern, (m) => String(toNumberLiteral(arr[m])));
          }
    const result = eval(str);
    // 除零等非有限结果不写回单元格
    if (typeof result === "number" && !isFinite(result)) {
      return undefined;
        }
        let arr2 = [];
        arr1.forEach((m) => {
          arr2.push(getColumnNameFromId(`${m.c}` + "-" + `${m.r}`));
        });
        obj[item.split(":").join("-")] = arr2.join(",");
      } else {
        obj[item] = item;
      }
    });
    str = str.replace(new RegExp(":", "g"), "");
    // 替换参数
    for (var a in obj) {
      str = str.replace(new RegExp(a, "g"), obj[a]);
    }
    // 计算
    for (var a in arr) {
      str = str.replace(new RegExp(a, "g"), arr[a]);
    }
    return eval(str);
    return result;
  } catch (error) {}
}
src/views/business/inspectionTask/components/InspectionWord.vue
@@ -41,7 +41,8 @@
                    class="content">
                    <template
                      v-if="n.v.ps != undefined && typeof n.v.ps.value === 'string' && n.v.ps.value.includes('检验值') && state == 1">
                      <el-input v-if="getInspectionValueType(n.i) == 1"
                      <el-input
                        v-if="getInspectionValueType(n.i) == 1 || (getInspectionValueType(n.i) != 2 && getInspectionValueType(n.i) != 4)"
                        :key="'abc-' + '000' + index + '000' + i + '000' + j" v-model="n.v.v"
                        :disabled="(getInspectionItemType(n.i) == 1 && !dataAcquisitionEidtAble) || (n.u != userId && n.u != undefined && n.u != '')"
                        class="table_input"
@@ -61,34 +62,6 @@
                      <span v-else-if="getInspectionValueType(n.i) == 4"
                        :style="`font-family:${n.v.ff} !important;`">/</span>
                    </template>
                    <template v-else-if="n.v.ps != undefined && n.v.ps.value === '结论'">
                      <el-select
                        v-if="(getInspectionValueType(n.i) == 2 || getInspectionValueType(n.i) == 5) && state == 1"
                        v-model="n.v.v" class="table_input"
                        @change="m => changeInput(m, `${item.templateId}-${n.r}-${n.c}-${n.i}`, n, 'getDataType')">
                        <el-option :value="1" label="合格"></el-option>
                        <el-option :value="0" label="不合格"></el-option>
                        <el-option :value="3" label="不判定"></el-option>
                        <el-option :value="2" label="待定"></el-option>
                      </el-select>
                      <template v-if="state > 1">
                        <span v-if="n.v.v === 1" :style="`font-family:${n.v.ff} !important;color: green;`">合格</span>
                        <span v-else-if="n.v.v === 0" :style="`font-family:${n.v.ff} !important;color: red;`">不合格</span>
                        <span v-else-if="n.v.v === 3"
                          :style="`font-family:${n.v.ff} !important;color: #3A7BFA;`">不判定</span>
                        <span v-else :style="`font-family:${n.v.ff} !important;`">待定</span>
                      </template>
                      <template v-if="getInspectionValueType(n.i) != 2 && state == 1">
                        <span v-if="n.v.v === 1" :style="`font-family:${n.v.ff} !important;color: green;`">合格</span>
                        <span v-else-if="n.v.v === 0" :style="`font-family:${n.v.ff} !important;color: red;`">不合格</span>
                        <span v-else-if="n.v.v === 3"
                          :style="`font-family:${n.v.ff} !important;color: #3A7BFA;`">不判定</span>
                        <span v-else :style="`font-family:${n.v.ff} !important;`">待定</span>
                      </template>
                    </template>
                    <template v-else-if="n.v.ps != undefined && n.v.ps.value === '设备编码' && state == 1">
                      <span>{{ n.v.v }}</span>
                    </template>
                    <template v-else-if="n.v.ps != undefined && n.v.ps.value === '设备名称'">
                      <el-select v-model="n.v.v" :disabled="state > 1" class="table_input" filterable multiple
                        placeholder="设备" remote @change="(val) => changeEquip(val, n)"
@@ -98,9 +71,6 @@
                          {{ item.label + '--' + item.value }}
                        </el-option>
                      </el-select>
                    </template>
                    <template v-else-if="n.v.ps != undefined && n.v.ps.value === '要求值' && state == 1">
                      <span :style="`font-family:${n.v.ff} !important;`">{{ getTell(n.i) }}</span>
                    </template>
                    <template v-else-if="n.v.ps != undefined && n.v.ps.value === '计算值' && state == 1"><span
                        :style="`font-family:${n.v.ff} !important;`">{{ toFixed(n.v.v, n.v.ct) }}</span></template>
@@ -510,22 +480,9 @@
          return
        }
        this.currentSample.insProduct = this.HaveJson(list)
        // 初始化传递到后端的参数
        // 初始化传递到后端的参数,按“模板id + 单元格坐标(r-c)”存
        this.param = {}
        this.changeType = 0;
        this.currentSample.insProduct.forEach(a => {
          // 是否为成品电缆下的松套管项目,不是则执行初始化
          if (this.handleCasing(a.inspectionItem)) {
            this.param[a.id] = {
              insValue: [],
              comValue: [],
              resValue: null,
              equipValue: [],
              equipName: [],
              insResult: null
            }
          }
        })
        // await this.determineWhetherToCollectData()//是否需要数采
        if (this.currentSample.index == undefined) this.currentSample['index'] = 1
        let bushing = this.currentSample.bushing
@@ -545,19 +502,7 @@
          if (m.templateId == val1) {
            let list = await this.getCurrentProduct(this.currentSample.id, 0)
            this.currentSample.insProduct = this.HaveJson(list)//赋值当前样品的检验项
            this.param = {}//初始化传到后端的参数
            this.currentSample.insProduct.forEach((a, j) => {
              if (this.handleCasing(a.inspectionItem)) {
                this.param[a.id] = {
                  insValue: [],
                  comValue: [],
                  resValue: null,
                  equipValue: [],
                  equipName: [],
                  insResult: null
                }
              }
            })
            this.param = {}//初始化传到后端的参数,按“模板id + 单元格坐标(r-c)”存
            // 去重模板,返回有几个模板
            const mySet1 = new Set();
            this.tableLists = this.currentSample.insProduct.filter(m => {
@@ -590,47 +535,7 @@
    // 特殊检验项--监听设备信息改变
    equipForm: {
      deep: true,
      handler(val) {
        if (this.tableLists.find(m => m.templateId == this.currentTable) && (this.tableLists.find(m => m.templateId == this.currentTable).templateName == '温度循环检验原始记录' || this.tableLists.find(m => m.templateId == this.currentTable).templateName.includes('热循环') || this.tableLists.find(m => m.templateId == this.currentTable).templateName.includes('温升试验')) && this.equipOptions && this.equipOptions.length > 0) {
          // 初始化设备信息
          this.param[this.currentSample.insProduct[0].id].equipValue = []
          this.param[this.currentSample.insProduct[0].id].equipName = []
          if (this.equipForm.code0) {
            // 赋值第一个设备的信息
            this.equipForm.value0 = this.equipOptions.find(m => m.value == this.equipForm.code0).label
            this.param[this.currentSample.insProduct[0].id].equipValue.push({
              i: this.currentSample.insProduct[0].id,
              v: {
                v: this.equipForm.code0
              }
            })
            this.param[this.currentSample.insProduct[0].id].equipName.push({
              i: this.currentSample.insProduct[0].id,
              v: {
                v: this.equipForm.value0
              }
            })
          }
          if (this.equipForm.code1) {
            // 赋值第二个设备的信息
            this.equipForm.value1 = this.equipOptions.find(m => m.value == this.equipForm.code1).label
            this.param[this.currentSample.insProduct[0].id].equipValue.push({
              i: this.currentSample.insProduct[0].id,
              v: {
                v: this.equipForm.code1
              }
            })
            this.param[this.currentSample.insProduct[0].id].equipName.push({
              i: this.currentSample.insProduct[0].id,
              v: {
                v: this.equipForm.value1
              }
            })
          }
          // 保存数据
          this.saveInsContext()
        }
      }
      handler(val) { },
    },
  },
  beforeDestroy() {
@@ -894,16 +799,6 @@
        let list = await this.getCurrentProduct(m, type, cableTag)
        if (list.length > 0) {
          this.param = {}
          list.forEach(a => {
            this.param[a.id] = {
              insValue: [],
              comValue: [],
              resValue: null,
              equipValue: [],
              equipName: [],
              insResult: null
            }
          })
          this.getTableLists0(list)
          this.worker.postMessage(JSON.stringify({
            type: 'saveData',
@@ -1084,129 +979,19 @@
          count++
        })
      })
      // 本次循环主要是控制合并,以及控制检验项信息是否展示出来,以便后续检验
      // 按后端下发的“模板ID + 模板行号”直接绑定检验项,不做名称比对,不隐藏任何行
      this.tableList.forEach(a => {
        let dels = new Set()//需要删除的行
        let ids = []//所有检验项的id
        let set3 = new Set()
        a.template.forEach(b => {
          let size1 = set3.size
          let size2 = set3.add(b.r).size
          if (size1 < size2) {
            let str = ''
            let str2 = ''
            let unit2 = ''
            let count4 = 0
            let isThree = 0
            a.template.forEach(c => {
              // 获取到 检验项分类+检验项+检验子项的拼接,如果模板里的信息跟接口返回的检验项信息能够匹配则展示出来
              if (b.r === c.r) {
                if (c.v.ps != undefined && c.v.ps.value === '检验项分类' && count4 === 0) {
                  // 三级分类
                  isThree = 1
                } else if (c.v.ps != undefined && c.v.ps.value === '检验项' && count4 === 0) {
                  // 二级分类
                  isThree = 0
        const directProducts = this.currentSample.insProduct.filter(
          (product) => product.templateId === a.templateId &&
            product.templateRowIndex !== null && product.templateRowIndex !== undefined
        );
        directProducts.forEach((product) => {
          a.template.forEach((cell) => {
            if (cell.r === product.templateRowIndex) {
              cell.i = product.id;
                }
                if (isThree == 0) {
                  if (c.v.ps != undefined && c.v.ps.value === '检验项') {
                    if (count4 === 0) {
                      str += c.v.v
                      count4 += 1
                    }
                  } else if (c.v.ps != undefined && c.v.ps.value === '检验子项') {
                    if (count4 === 1) {
                      str += c.v.v
                      count4 += 1
                    }
                  }
                } else if (isThree == 1) {
                  if (c.v.ps != undefined && c.v.ps.value === '检验项分类') {
                    if (count4 === 0) {
                      str += c.v.v
                      count4 += 1
                    }
                  } else if (c.v.ps != undefined && c.v.ps.value === '检验项') {
                    if (count4 === 1) {
                      str += c.v.v
                      count4 += 1
                    }
                  } else if (c.v.ps != undefined && c.v.ps.value === '检验子项') {
                    if (count4 === 2) {
                      str += c.v.v
                      count4 += 1
                    }
                  }
                }
                if (str === '机械性能干态拉伸强度(纵向)') {
                  if (c.v.ps != undefined && c.v.ps.value === '单位') {
                    str2 = str + c.v.v
                    unit2 = c.v.v
                  }
                }
              }
            })
            if (str != '') {
              let count2 = 0
              for (let i in this.currentSample.insProduct) {
                let inspectionItemClass = this.currentSample.insProduct[i].inspectionItemClass == null || this.currentSample.insProduct[i].inspectionItemClass == undefined ? '' : this.currentSample.insProduct[i].inspectionItemClass
                let inspectionItem = this.currentSample.insProduct[i].inspectionItem == null || this.currentSample.insProduct[i].inspectionItem == undefined ? '' : this.currentSample.insProduct[i].inspectionItem
                let inspectionItemSubclass = this.currentSample.insProduct[i].inspectionItemSubclass == null || this.currentSample.insProduct[i].inspectionItemSubclass == undefined ? '' : this.currentSample.insProduct[i].inspectionItemSubclass
                if (inspectionItemSubclass === '干态拉伸强度(纵向)') {
                  // 检验子项为'干态拉伸强度(纵向)'时,模版里是两个计算值对应相同的检验值并且计算方式不同,要根据相同的'单位'做特殊的渲染
                  const unit = this.currentSample.insProduct[i].unit
                  if ((this.currentSample.insProduct[i].templateId === a.templateId && inspectionItemClass + inspectionItem + inspectionItemSubclass + unit === str2) || (this.currentSample.insProduct[i].templateId === a.templateId && !unit2.includes('/') && inspectionItemClass + inspectionItem + inspectionItemSubclass === str)) {
                    ids.push({
                      r: b.r,
                      id: this.currentSample.insProduct[i].id,
                      product: this.currentSample.insProduct[i]
                    })
                    break
                  }
                } else {
                  // 如果相等,那么说明找到了,并且把id存起来,后续检验项也会在页面中显示出来
                  if (this.currentSample.insProduct[i].templateId === a.templateId && inspectionItemClass + inspectionItem + inspectionItemSubclass === str) {
                    ids.push({
                      r: b.r,
                      id: this.currentSample.insProduct[i].id,
                      product: this.currentSample.insProduct[i]
                    })
                    break
                  }
                }
                count2++
              }
              if (count2 == this.currentSample.insProduct.length) {
                dels.add(b.r)
              }
            }
          }
        })
        // 操作删除
        dels.forEach(del => {
          for (let b = 0; b < a.template.length; b++) {
            if (a.template[b].r === del) {
              a.template.splice(b, 1)
              b -= 1
            }
          }
        })
        // 操作赋值--主要赋值单位,试验方法等信息
        ids.forEach(id => {
          for (let b = 0; b < a.template.length; b++) {
            if (a.template[b].r === id.r) {
              a.template[b].i = id.id
              if (a.template[b].v.ps != undefined && a.template[b].v.ps.value === '单位') {
                a.template[b].v.v = id.product.unit
              }
              if (a.template[b].v.ps != undefined && (a.template[b].v.ps.value === '试验方法' || a.template[b].v
                .ps.value === '检测方法')) {
                a.template[b].v.v = id.product.methodS
              }
            }
          }
        })
          });
        });
        let set2 = new Set()
        // 合并的数据处理,cs  rs  代表合并的数量
        a.template.forEach(b => {
@@ -1233,60 +1018,24 @@
        let arrs = []
        let set = new Set()
        let count1 = 0
        let conclusionList = []; //结论列表
        let finalList = []; //最终值列表
        // 结论与最终值在这里一一对应,以下两个列表长度肯定是一样的,如果有不一样,那么多半是模板配置得问题
        conclusionList = a.template.filter(n => n.v.ps != undefined && n.v.ps.value === '结论')//结论列表
        finalList = a.template.filter(n => n.v.ps != undefined && n.v.ps.value === '最终值')//最终值列表
        a.template.forEach(b => {
          if (b.v.ps != undefined && b.v.ps.value === '序号' && (b.v.mc == undefined || Object.keys(b.v.mc).length === 4)) {
            // 对序号进行赋值
            count1++
            b.v.v = count1
          }
          if (b.v.ps != undefined && b.v.ps.value === '要求值') {
            // 对要求值进行赋值
            b.v.v = this.getAsk(b.i)
          }
          // 对页面的和给后端传参的检验值,计算值,设备编码,设备名称,最终值,结论进行初始化
          if (b.v.ps != undefined && typeof b.v.ps.value === 'string' && b.v.ps.value.includes('检验值')) {
          // 初始化可填写/可计算单元格,后续按坐标回显
          if (
            b.v.ps != undefined &&
            typeof b.v.ps.value === 'string' &&
            (b.v.ps.value.includes('检验值') ||
              b.v.ps.value === '计算值' ||
              b.v.ps.value === '最终值' ||
              b.v.ps.value === '设备名称')
          ) {
            this.$set(b.v, 'v', '')
            // b.v.v = ''
            if (b.v.ps.value.includes('检验值')) {
            b.u = ''
            b.i && this.param[b.i] && this.param[b.i].insValue.push(b)
          }
          if (b.v.ps != undefined && b.v.ps.value === '计算值') {
            this.$set(b.v, 'v', '')
            // b.v.v = ''
            b.i && this.param[b.i] && this.param[b.i].comValue.push(b)
          }
          if (b.v.ps != undefined && b.v.ps.value === '设备编码') {
            // b.v.v = ''
            this.$set(b.v, 'v', '')
            b.i && this.param[b.i] && this.param[b.i].equipValue.push(b)
          }
          if (b.v.ps != undefined && b.v.ps.value === '设备名称') {
            this.$set(b.v, 'v', '')
            // b.v.v = ''
            b.i && this.param[b.i] && this.param[b.i].equipName.push(b)
          }
          if (b.v.ps != undefined && b.v.ps.value === '最终值') {
            // b.v.v = ''
            this.$set(b.v, 'v', '')
            if (b.i !== undefined && this.param[b.i] && !this.param[b.i].resValue) {
              this.param[b.i].resValue = b
            }
          }
          if (b.v.ps != undefined && b.v.ps.value === '结论') {
            if (b.i !== undefined && this.param[b.i] && !this.param[b.i].insResult) {
              this.param[b.i].insResult = b
              conclusionList.forEach((n, i) => {
                if (n.r == b.r && n.c == b.c) {
                  b.v.f =
                    `(${this.comparisonList.find(j => j.value == (finalList[i].c)).label}${finalList[i].r + 1})`
                }
              })
            }
          }
          set.add(b.r)
@@ -1313,97 +1062,45 @@
          this.tableWidth += (a.style.columnlen[i] === undefined ? 100 : a.style.columnlen[i])
        }
      })
      // 本次循环主要是对页面及后端传参进行初始化赋值
      this.currentSample.insProduct.forEach(async a => {
        try {
          // 计算值赋值
          let comValue = JSON.parse(a.insProductResult.comValue)
          for (var i = 0; i < comValue.length; i++) {
            this.param[a.id].comValue[i].v.v = this.toFixed(comValue[i].v, this.param[a.id].comValue[i].v.ct)
          }
        } catch (e) { }
        try {
          // 检验值赋值
          let insValue = JSON.parse(a.insProductResult.insValue)
          for (let i = 0; i < insValue.length; i++) {
            if (this.param[a.id].insValue.find(m => m.c == insValue[i].c && m.r == insValue[i].r)) {
              this.param[a.id].insValue.find(m => m.c == insValue[i].c && m.r == insValue[i].r).v.v = this.toFixed(insValue[i].v, this.param[a.id].insValue.find(m => m.c == insValue[i].c && m.r == insValue[i].r).v.ct)
              this.param[a.id].insValue.find(m => m.c == insValue[i].c && m.r == insValue[i].r).u = insValue[i].u
              // this.param[a.id].insValue[i].v.v = insValue[i].v
              // this.param[a.id].insValue[i].u = insValue[i].u
            }
          }
        } catch (e) { }
        try {
          // 设备编号赋值
          let equipValue = JSON.parse(a.insProductResult.equipValue)
          if (this.tableLists.find(m => m.templateId == this.currentTable) && (this.tableLists.find(m => m.templateId == this.currentTable).templateName == '温度循环检验原始记录' || this.tableLists.find(m => m.templateId == this.currentTable).templateName.includes('热循环') || this.tableLists.find(m => m.templateId == this.currentTable).templateName.includes('温升试验'))) {
            // 特殊项目初始化
            this.param[a.id].equipValue = []
            for (let i = 0; i < equipValue.length; i++) {
              this.param[a.id].equipValue.push({
                v: {
                  v: ''
                }
              })
            }
          }
          for (let i = 0; i < equipValue.length; i++) {
            if (this.tableLists.find(m => m.templateId == this.currentTable) && (this.tableLists.find(m => m.templateId == this.currentTable).templateName == '温度循环检验原始记录' || this.tableLists.find(m => m.templateId == this.currentTable).templateName.includes('热循环') || this.tableLists.find(m => m.templateId == this.currentTable).templateName.includes('温升试验'))) {
              // 温度循环设备赋值
              this.$set(this.equipForm, `code` + i, equipValue[i].v)
              this.param[a.id].equipValue[i].v.v = equipValue[i].v
            } else {
              // 普通设备赋值
              this.param[a.id].equipValue[i].v.v = equipValue[i].v
            }
          }
        } catch (e) { }
        try {
          // 设备名称赋值
          let equipName = JSON.parse(a.insProductResult.equipName)
          for (let i = 0; i < equipName.length; i++) {
            equipName[i].v !== '' && equipName[i].v.map(val => {
              const index = this.equipOptions.findIndex(item => item.value === val)
              if (index > -1) {
                // 根据设备编码转换为相应的设备名称
                val = this.equipOptions[index].deviceName
              }
            })
          }
          if (this.tableLists.find(m => m.templateId == this.currentTable) && (this.tableLists.find(m => m.templateId == this.currentTable).templateName == '温度循环检验原始记录' || this.tableLists.find(m => m.templateId == this.currentTable).templateName.includes('热循环') || this.tableLists.find(m => m.templateId == this.currentTable).templateName.includes('温升试验'))) {
            // 设备名称初始化
            this.param[a.id].equipName = []
            for (let i = 0; i < equipName.length; i++) {
              this.param[a.id].equipName.push({
                v: {
                  v: ''
                }
              })
            }
          }
          for (let i = 0; i < equipName.length; i++) {
            if (this.tableLists.find(m => m.templateId == this.currentTable) && (this.tableLists.find(m => m.templateId == this.currentTable).templateName == '温度循环检验原始记录' || this.tableLists.find(m => m.templateId == this.currentTable).templateName.includes('热循环') || this.tableLists.find(m => m.templateId == this.currentTable).templateName.includes('温升试验'))) {
              // 温度循环赋值
              this.$set(this.equipForm, `value` + i, equipName[i].v)
              this.param[a.id].equipName[i].v.v = equipName[i].v
            } else {
              // 普通设备名称赋值
              this.param[a.id].equipName[i].v.v = equipName[i].v
            }
          }
        } catch (e) {
          console.log('设备名称赋值----', e)
        }
        try {
          // 最终值赋值
          this.param[a.id].resValue.v.v = this.toFixed(a.lastValue, this.param[a.id].resValue.v.ct)
          // 结论赋值
          this.param[a.id].insResult.v.v = a.insResult
        } catch (e) { }
      })
      // 按“模板id + 单元格坐标(r-c)”回显已保存的值
      this.initParamByCoordinate()
      // 对excel函数进行处理
      this.handleExcelMethod()
    },
    // 按“模板id + 单元格坐标(r-c)”回显已保存的值
    initParamByCoordinate() {
      this.param = {}
      this.tableList.forEach(a => {
        this.param[a.templateId] = {}
        const product = this.currentSample.insProduct.find(m => m.templateId === a.templateId)
        let saved = (product && (product.recordValues || product.insProductResult)) || {}
        if (typeof saved === 'string') {
          try {
            saved = JSON.parse(saved)
          } catch (e) {
            saved = {}
          }
        }
        a.template.forEach(cell => {
          const key = `${cell.r}-${cell.c}`
          const item = saved[key]
          if (item === undefined || item === null) {
            return
          }
          const value = typeof item === 'object' ? item.v : item
          if (value === undefined || value === null) {
            return
          }
          cell.v.v = value
          if (typeof item === 'object' && item.u) {
            cell.u = item.u
          }
          this.param[a.templateId][key] = {
            v: value,
            u: typeof item === 'object' ? item.u : cell.u
          }
        })
      })
    },
    // 检验值输入后触发的函数
    changeInput(m, code, n, getDataType) {
@@ -1411,9 +1108,7 @@
      if (getDataType == 'getDataType') {
        this.getDataType = 2;
      }
      let currentInsItemId = null//当前检验项id
      if (n) {
        currentInsItemId = JSON.parse(JSON.stringify(n.i))
        // 定义一个函数来验证分数是否有效
        if (typeof n.v.v == 'string') {
          function isValidFraction(fraction) {
@@ -1441,6 +1136,10 @@
          modelType: this.sampleProduct[0].model,
          currentInsItem: n
        }));
        // 先保存主线程中已经输入的原始值。Worker 完成计算后会再次入队保存计算结果。
        if (n) {
          this.saveInsContext()
        }
      } catch (error) {
        console.log(444, error);
      }
@@ -1450,24 +1149,11 @@
        this.result = JSON.parse(event.data);
        switch (this.result.method) {
          case 'saveInsContext':
            console.log(`output->`, 11111111111111)
            this.$nextTick(() => {
              // this.$delete(this.tableList[0],'arr')
              this.$set(this.tableList[0], 'arr', this.result.value.tableList[0].arr)
              this.param = this.result.value.param
              if (this.result.value.currentInsItem) {
                currentInsItemId = this.result.value.currentInsItem.i
              }
              // 特殊处理一下结论,会有这种特殊情况
              for (var i in this.param) {
                if (this.param[i].insResult && this.param[i].insResult.v && this.param[i].insResult.v.v) {
                  if (this.param[i].insResult.v.v == '合格') {
                    this.$set(this.param[i].insResult.v, 'v', 1)
                  } else if (this.param[i].insResult.v.v == '不合格') {
                    this.$set(this.param[i].insResult.v, 'v', 0)
                  }
                }
              }
              const resultValue = this.result.value
              this.$set(this.tableList[0], 'arr', resultValue.tableList[0].arr)
              this.param = resultValue.param
              this.saveInsContext()
            })
            break;
          case 'tableList':
@@ -1475,116 +1161,16 @@
              // 更新数据
              this.$delete(this.tableList[0], 'arr')
              this.$set(this.tableList[0], 'arr', this.result.value[0].arr)
              // this.param = this.result.value.param
              if (this.result.value.currentInsItem) {
                currentInsItemId = this.result.value.currentInsItem.i
              }
            })
            break;
          case 'getCurrentInsProduct':
            // 更新页面数据
            this.getCurrentInsProduct(this.result.value)
            break;
        }
      };
      // 保存数据
      setTimeout(() => {
        this.saveInsContext(currentInsItemId)
      }, 200)
    },
    // 是否需要数采
    // async determineWhetherToCollectData() {
    //   let res = determineWhetherToCollectData({ managementNumber: '' })
    //   this.isGet = res.data
    // },
    // 根据后端传参更新页面数据   param => this.tableList[0].insProductResult
    getCurrentInsProduct(pId) {
      if (!this.tableList[0].insProductResult) {
        this.tableList[0].insProductResult = {}
      }
      for (let m in this.param[pId]) {
        let value = this.param[pId][m]
        switch (m) {
          case 'comValue':
            // 赋值计算值
            if (value && value.length > 0) {
              this.tableList[0].insProductResult[m] = [];
              value.forEach((a, i) => {
                let obj = {
                  v: a.v.v,
                }
                this.tableList[0].insProductResult[m].push(obj);
              })
              try {
                this.tableList[0].insProductResult[m] = JSON.stringify(this.tableList[0].insProductResult[m])
              } catch (error) {
                console.log(555, error);
              }
            }
            break;
          // 赋值检验值
          case 'insValue':
            if (value && value.length > 0) {
              this.tableList[0].insProductResult[m] = [];
              value.forEach((a, i) => {
                let obj = {
                  v: a.v.v,
                  u: a.u,
                }
                this.tableList[0].insProductResult[m].push(obj);
              })
              try {
                this.tableList[0].insProductResult[m] = JSON.stringify(this.tableList[0].insProductResult[m])
              } catch (error) {
                console.log(666, error);
              }
            }
            break;
          // 赋值设备编号
          case 'equipValue':
            if (value && value.length > 0) {
              this.tableList[0].insProductResult[m] = [];
              value.forEach((a, i) => {
                let obj = {
                  v: a.v.v,
                }
                this.tableList[0].insProductResult[m].push(obj);
              })
              try {
                this.tableList[0].insProductResult[m] = JSON.stringify(this.tableList[0].insProductResult[m])
              } catch (error) {
                console.log(777, error);
              }
            }
            break;
          // 赋值设备名称
          case 'equipName':
            if (value && value.length > 0) {
              this.tableList[0].insProductResult[m] = [];
              value.forEach((a, i) => {
                let obj = {
                  v: a.v.v,
                }
                this.tableList[0].insProductResult[m].push(obj);
              })
              try {
                this.tableList[0].insProductResult[m] = JSON.stringify(this.tableList[0].insProductResult[m])
              } catch (error) {
                console.log(888, error);
              }
            }
            break;
          // 赋值最终值
          case 'resValue':
            this.tableList[0].lastValue = value ? value.v.v : ''
            break;
          // 赋值结论
          case 'insResult':
            this.tableList[0].insResult = value ? value.v.v : ''
            break;
        }
      }
    },
    // 对EXCEL函数进行处理
    handleExcelMethod() {
      if (this.excelMethodList.length > 0) {
@@ -1615,14 +1201,6 @@
      for (var a in this.currentSample.insProduct) {
        if (this.currentSample.insProduct[a].id == id) {
          return this.currentSample.insProduct[a].inspectionValueType
        }
      }
    },
    // 获取要求描述
    getTell(id) {
      for (var a in this.currentSample.insProduct) {
        if (this.currentSample.insProduct[a].id == id) {
          return this.currentSample.insProduct[a].tell
        }
      }
    },
@@ -1659,26 +1237,22 @@
        }
      }
    },
    // 获取要求值
    getAsk(id) {
      for (var a in this.currentSample.insProduct) {
        if (this.currentSample.insProduct[a].id == id) {
          return this.currentSample.insProduct[a].ask
        }
      }
    },
    getSystemValue(n) {
      let code = null
      try {
        this.param[n.i].equipValue.forEach(a => {
          if (a.r === n.r) {
            if (a.v.v == null || a.v.v == '') {
        this.tableList.forEach(table => {
          (table.arr || []).forEach(row => {
            row.forEach(cell => {
              if (cell.i == n.i && cell.r === n.r && cell.v.ps && cell.v.ps.value === '设备编码') {
                if (cell.v.v == null || cell.v.v == '') {
              this.$message.error('请先选择采集的设备')
              return
            } else {
              code = a.v.v
                  code = cell.v.v
            }
          }
            })
          })
        })
      } catch (e) {
        // console.log(e);
@@ -1857,20 +1431,62 @@
      })
      return
    },
    // 统一在这里保存数据
    saveInsContext(currentInsItemId) {
      try {
        if (this.param) {
          let param = null
          if (currentInsItemId) {
            param = { [currentInsItemId]: this.param[currentInsItemId] }
          } else {
            param = this.param
    // 按“模板id + 单元格坐标(r-c)”从当前模板快照出待保存参数
    buildParam() {
      const param = {}
      this.tableList.forEach(a => {
        param[a.templateId] = {}
        a.template.forEach(cell => {
          const isEditable =
            cell.v.ps != undefined &&
            typeof cell.v.ps.value === 'string' &&
            (cell.v.ps.value.includes('检验值') ||
              cell.v.ps.value === '计算值' ||
              cell.v.ps.value === '最终值' ||
              cell.v.ps.value === '设备名称')
          if (!isEditable) {
            return
          }
          if (
            cell.v.ps.value.includes('检验值') &&
            (cell.v.v === '' || cell.v.v === null || cell.v.v === undefined)
          ) {
            return
          }
          param[a.templateId][`${cell.r}-${cell.c}`] = {
            v: cell.v.v,
            u: cell.u
          }
        })
      })
      return param
    },
    // 统一在这里保存数据
    saveInsContext() {
      try {
        if (!this.param) {
          return
        }
        const param = this.buildParam()
        this.param = param
        let isNoTestValue = ''
        this.tableList.forEach(a => {
          a.template.forEach(cell => {
            if (
              cell.v.ps != undefined &&
              typeof cell.v.ps.value === 'string' &&
              cell.v.ps.value.includes('检验值') &&
              (cell.v.v === '' || cell.v.v === null || cell.v.v === undefined)
            ) {
              isNoTestValue = 1
            }
          })
        })
          saveUnqualifiedContext({
            param: JSON.stringify(param),
            currentTable: this.currentTable,
            sampleId: this.currentSample.id
          sampleId: this.currentSample.id,
          isNoTestValue: isNoTestValue
          }).then(res => {
            this.$message.success('已保存')
          })
@@ -1882,66 +1498,30 @@
            param: this.param,
            currentTable: this.currentTable
          }));
        }
      } catch (error) {
        console.log(999, error);
      }
    },
    // 设备改变
    changeEquip(val, n, v) {
      try {
        // this.$set(n.v,'v',val)
        this.tableList[0].arr.forEach((item, index) => {
          item.forEach((m, i) => {
            if (this.param[m.i]) {
              this.param[m.i].state = 1
    changeEquip(val, n) {
      const selectedDevices = Array.isArray(val) ? [...val] : []
      const deviceCodes = selectedDevices.join(',')
      this.$set(n.v, 'v', selectedDevices)
      this.tableList.forEach(table => {
        (table.arr || []).forEach(row => {
          row.forEach(cell => {
            if (cell.i == n.i && cell.v.ps) {
              if (cell.v.ps.value === '设备名称') {
                this.$set(cell.v, 'v', [...selectedDevices])
              } else if (cell.v.ps.value === '设备编码') {
                this.$set(cell.v, 'v', deviceCodes)
            }
            // if(m.i==n.i&&m.v.ps&&m.v.ps.value=='设备名称'&&v){
            //   this.$set(m.v,'v',v)
            // }
          })
        })
        for (let i in this.param) {
          if (this.param[i].state != 1) {
            delete this.param[i]
          }
        }
        // if(val&&v){
        //   for (let i1 in this.param[n.i].equipName) {
        //     if (this.param[n.i].equipName[i1].i === n.i && this.param[n.i].equipName[i1].r === n.r) {
        //       this.$delete(this.param[n.i].equipValue[i1].v,'v')
        //       this.$set(this.param[n.i].equipValue[i1].v,'v',val)
        //       this.$delete(this.param[n.i].equipName[i1].v,'v')
        //       this.$set(this.param[n.i].equipName[i1].v,'v',v)
        //     }
        //   }
        // }
        // this.equipOptions为设备名称下拉框选项数据
        for (let i1 in this.param[n.i].equipName) {
          if (this.param[n.i].equipName[i1].i === n.i && this.param[n.i].equipName[i1].r === n.r) {
            this.$delete(this.param[n.i].equipValue[i1].v, 'v')
            // 将数组赋值给设备编码
            this.$set(this.param[n.i].equipValue[i1].v, 'v', val.join(','))
            this.$delete(this.param[n.i].equipName[i1].v, 'v')
            // 将数组赋值给设备编码
            this.$set(this.param[n.i].equipName[i1].v, 'v', val)
            this.tableList[0].arr.forEach((item, index) => {
              item.forEach((m) => {
                if (m.i == n.i && m.v.ps && m.v.ps.value == '设备编码') {
                  this.$set(m.v, 'v', val.join(','))
                }
                if (m.i == n.i && m.v.ps && m.v.ps.value == '设备名称') {
                  this.$set(m.v, 'v', val)
                }
              })
            })
          }
        }
        // 保存数据
        this.saveInsContext(n.i)
      } catch (e) {
        console.log('changeEquip----', e)
      }
      })
      // 选择、移除、清空均由 change 事件触发,立即保存。
      this.saveInsContext()
    },
    getAuthorizedPerson() {
      selectUserCondition({ type: 1 }).then((res) => {
@@ -1996,16 +1576,6 @@
      this.param = {}
      this.fiberOptic = []
      this.currentFiberOptic = null;
      this.currentFiberOpticTape.productList.forEach(a => {
        this.param[a.id] = {
          insValue: [],
          comValue: [],
          resValue: null,
          equipValue: [],
          equipName: [],
          insResult: null
        }
      })
      this.fiberOpticTapeVisible = false;
      let list = await this.getCurrentProduct(this.currentFiberOpticTape.id, 1)
      this.getTableLists0(list)
@@ -2025,16 +1595,7 @@
      }
      this.currentKey2 = index
      this.currentFiberOptic = this.HaveJson(this.fiberOptic[index - 1])
      this.currentFiberOptic.productList.forEach(a => {
        this.param[a.id] = {
          insValue: [],
          comValue: [],
          resValue: null,
          equipValue: [],
          equipName: [],
          insResult: null
        }
      })
      this.param = {}
      let list = await this.getCurrentProduct(this.currentFiberOptic.id, 2)
      this.getTableLists0(list)
    },
src/views/business/inspectionTask/inspection.vue
@@ -219,7 +219,9 @@
                      n.v.ps.value.includes('检验值') &&
                      state == 1
                    ">
                      <el-input v-if="getInspectionValueType(n.i) == 1"
                      <el-input v-if="getInspectionValueType(n.i) == 1 ||
                        (getInspectionValueType(n.i) != 2 && getInspectionValueType(n.i) != 4)
                        "
                        :key="'abc-' + '000' + index + '000' + i + '000' + j" v-model="n.v.v" :disabled="(getInspectionItemType(n.i) == 1 &&
                          !dataAcquisitionEidtAble) ||
                          (n.u != userId && n.u != undefined && n.u != '')
@@ -249,63 +251,8 @@
                            'getDataType'
                          )
                          " />
                      <!-- <el-select v-else-if="getInspectionValueType(n.i) == 5" v-model="n.v.v" :disabled="state > 1 ||
                      getInspectionItemType(n.i) == 1 ||
                      (n.u != userId && n.u != undefined && n.u != '')
                      " class="table_input" @change="(m) =>
                        changeInput(
                          m,
                          `${item.templateId}-${n.r}-${n.c}-${n.i}`,
                          n,
                          'getDataType'
                        )
                        " @visible-change="(e) => getDic(e, n.i)">
                      <el-option v-for="(e, i) in enumList" :key="i" :label="e.label" :value="e.value"></el-option>
                    </el-select> -->
                      <span v-else-if="getInspectionValueType(n.i) == 4"
                        :style="`font-family:${n.v.ff} !important;`">/</span>
                    </template>
                    <template v-else-if="n.v.ps != undefined && n.v.ps.value === '结论'">
                      <el-select v-if="
                        (getInspectionValueType(n.i) == 2 ||
                          getInspectionValueType(n.i) == 5) &&
                        state == 1
                      " v-model="n.v.v" class="table_input" @change="(m) =>
                        changeInput(
                          m,
                          `${item.templateId}-${n.r}-${n.c}-${n.i}`,
                          n,
                          'getDataType',
                          'changeSelect'
                        )
                        ">
                        <el-option :value="1" label="合格"></el-option>
                        <el-option :value="0" label="不合格"></el-option>
                        <el-option :value="3" label="不判定"></el-option>
                        <el-option :value="2" label="待定"></el-option>
                      </el-select>
                      <template v-if="state > 1">
                        <span v-if="n.v.v === 1" :style="`font-family:${n.v.ff} !important;color: green;`">合格</span>
                        <span v-else-if="n.v.v === 0" :style="`font-family:${n.v.ff} !important;color: red;`">不合格</span>
                        <span v-else-if="n.v.v === 3"
                          :style="`font-family:${n.v.ff} !important;color: #3A7BFA;`">不判定</span>
                        <span v-else :style="`font-family:${n.v.ff} !important;`">待定</span>
                      </template>
                      <template v-if="getInspectionValueType(n.i) != 2 &&
                        state == 1">
                        <span v-if="n.v.v === 1" :style="`font-family:${n.v.ff} !important;color: green;`">合格</span>
                        <span v-else-if="n.v.v === 0" :style="`font-family:${n.v.ff} !important;color: red;`">不合格</span>
                        <span v-else-if="n.v.v === 3"
                          :style="`font-family:${n.v.ff} !important;color: #3A7BFA;`">不判定</span>
                        <span v-else :style="`font-family:${n.v.ff} !important;`">待定</span>
                      </template>
                    </template>
                    <template v-else-if="
                      n.v.ps != undefined &&
                      n.v.ps.value === '设备编码' &&
                      state == 1
                    ">
                      <span>{{ n.v.v }}</span>
                    </template>
                    <template v-else-if="
                      n.v.ps != undefined && n.v.ps.value === '设备名称'
@@ -318,15 +265,6 @@
                          {{ item.label + "--" + item.value }}
                        </el-option>
                      </el-select>
                    </template>
                    <template v-else-if="
                      n.v.ps != undefined &&
                      n.v.ps.value === '要求值' &&
                      state == 1
                    ">
                      <span :style="`font-family:${n.v.ff} !important;`">{{
                        getTell(n.i)
                      }}</span>
                    </template>
                    <template v-else-if="
                      n.v.ps != undefined &&
@@ -946,17 +884,7 @@
          if (m.templateId == val1) {
            let list = await this.getCurrentProduct(this.currentSample.id, 0);
            this.currentSample.insProduct = this.HaveJson(list); //赋值当前样品的检验项
            this.param = {}; //初始化传到后端的参数
            this.currentSample.insProduct.forEach((a, j) => {
              this.param[a.id] = {
                insValue: [],
                comValue: [],
                resValue: null,
                equipValue: [],
                equipName: [],
                insResult: null,
              };
            });
            this.param = {}; //初始化传到后端的参数,按“模板id + 单元格坐标”存
            // 去重模板,返回有几个模板
            const mySet1 = new Set();
            this.tableLists = this.currentSample.insProduct.filter((m) => {
@@ -1187,16 +1115,6 @@
        // 初始化传递到后端的参数
        this.param = {};
        this.changeType = 0;
        this.currentSample.insProduct.forEach((a) => {
          this.param[a.id] = {
            insValue: [],
            comValue: [],
            resValue: null,
            equipValue: [],
            equipName: [],
            insResult: null,
          };
        });
        if (this.currentSample.index == undefined)
          this.currentSample["index"] = 1;
        let bushing = this.currentSample.bushing;
@@ -1756,16 +1674,6 @@
      // 初始化后端传参
      this.param = {};
      this.changeType = 0;
      this.currentSample.insProduct.forEach((a, j) => {
        this.param[a.id] = {
          insValue: [],
          comValue: [],
          resValue: null,
          equipValue: [],
          equipName: [],
          insResult: null,
        };
      });
      // 处理页面列表数据
      this.getTableLists();
      this.currentKey = row.index;
@@ -1801,16 +1709,6 @@
        let list = await this.getCurrentProduct(m, type, cableTag);
        if (list && list.length > 0) {
          this.param = {};
          list.forEach((a) => {
            this.param[a.id] = {
              insValue: [],
              comValue: [],
              resValue: null,
              equipValue: [],
              equipName: [],
              insResult: null,
            };
          });
          this.getTableLists0(list);
          this.worker.postMessage(
            JSON.stringify({
@@ -1919,24 +1817,6 @@
    handleTableData() {
      this.excelMethodList = []; //excel函数列表
      this.widthList = this.tableList[0].style.columnlen; //页面宽度--根据模板来的
      // 对照接口返回的检验项模板 ID 与页面实际参与匹配的模板 ID。
      this.tableList.forEach((template) => {
        console.log("[templateId核对]", {
          sampleId: this.currentSample.id,
          currentTable: this.currentTable,
          templateName: template.templateName,
        });
        console.table(this.currentSample.insProduct.map((product) => ({
          检验项ID: product.id,
          检验项: product.inspectionItem,
          检验子项: product.inspectionItemSubclass,
          "检验项templateId(接口返回)": product.templateId,
          检验项ID类型: typeof product.templateId,
          "当前模板templateId": template.templateId,
          模板ID类型: typeof template.templateId,
          "是否一致(严格比较)": product.templateId === template.templateId,
        })));
      });
      // 本次循环主要做页面渲染层面的处理--单元格合并预处理
      this.tableList.forEach((a) => {
        let mcList = a.template.filter(
@@ -1972,255 +1852,18 @@
          count++;
        });
      });
      // 本次循环主要是控制合并,以及控制检验项信息是否展示出来,以便后续检验
      // 按后端下发的“模板ID + 模板行号”直接绑定检验项,不做名称比对,不隐藏任何行
      this.tableList.forEach((a) => {
        // 新聚订单直接按“模板ID + 模板行号”绑定检验记录,不再匹配分类和检验子项。
        const directProducts = this.currentSample.insProduct.filter(
          (product) => product.templateId === a.templateId &&
            product.templateRowIndex !== null && product.templateRowIndex !== undefined
        );
        if (directProducts.length > 0) {
          directProducts.forEach((product) => {
            a.template.forEach((cell) => {
              if (cell.r === product.templateRowIndex) {
                cell.i = product.id;
              }
            });
          });
          return;
        }
        let dels = new Set(); //需要删除的行
        let ids = []; //所有检验项的id
        let set3 = new Set();
        a.template.forEach((b) => {
          let size1 = set3.size;
          let size2 = set3.add(b.r).size;
          if (size1 < size2) {
            let str = "";
            let str2 = "";
            let unit2 = "";
            let count4 = 0;
            let isThree = 0;
            a.template.forEach((c) => {
              // 获取到 检验项分类+检验项+检验子项的拼接,如果模板里的信息跟接口返回的检验项信息能够匹配则展示出来
              if (b.r === c.r) {
                if (
                  c.v.ps != undefined &&
                  c.v.ps.value === "检验项分类" &&
                  count4 === 0
                ) {
                  // 三级分类
                  isThree = 1;
                } else if (
                  c.v.ps != undefined &&
                  c.v.ps.value === "检验项" &&
                  count4 === 0
                ) {
                  // 二级分类
                  isThree = 0;
                }
                if (isThree == 0) {
                  if (c.v.ps != undefined && c.v.ps.value === "检验项") {
                    if (count4 === 0) {
                      if (c.v.v) {
                        c.v.v = c.v.v.replace(/\s*/g, "");
                      }
                      str += c.v.v;
                      count4 += 1;
                    }
                  } else if (
                    c.v.ps != undefined &&
                    c.v.ps.value === "检验子项"
                  ) {
                    if (count4 === 1) {
                      if (c.v.v) {
                        c.v.v = c.v.v.replace(/\s*/g, "");
                      }
                      str += c.v.v;
                      count4 += 1;
                    }
                  }
                } else if (isThree == 1) {
                  if (c.v.ps != undefined && c.v.ps.value === "检验项分类") {
                    if (count4 === 0) {
                      if (c.v.v) {
                        c.v.v = c.v.v.replace(/\s*/g, "");
                      }
                      str += c.v.v;
                      count4 += 1;
                    }
                  } else if (c.v.ps != undefined && c.v.ps.value === "检验项") {
                    if (count4 === 1) {
                      if (c.v.v) {
                        c.v.v = c.v.v.replace(/\s*/g, "");
                      }
                      str += c.v.v;
                      count4 += 1;
                    }
                  } else if (
                    c.v.ps != undefined &&
                    c.v.ps.value === "检验子项"
                  ) {
                    if (count4 === 2) {
                      if (c.v.v) {
                        c.v.v = c.v.v.replace(/\s*/g, "");
                      }
                      str += c.v.v;
                      count4 += 1;
                    }
                  }
                }
                if (str === "机械性能干态拉伸强度(纵向)") {
                  if (c.v.ps != undefined && c.v.ps.value === "单位") {
                    if (c.v.v) {
                      c.v.v = c.v.v.replace(/\s*/g, "");
                    }
                    str2 = str + c.v.v;
                    unit2 = c.v.v;
                  }
                }
              }
            });
            if (str != "") {
              let count2 = 0;
              for (let i in this.currentSample.insProduct) {
                let inspectionItemClass =
                  this.currentSample.insProduct[i].inspectionItemClass ==
                    null ||
                    this.currentSample.insProduct[i].inspectionItemClass ==
                    undefined
                    ? ""
                    : this.currentSample.insProduct[i].inspectionItemClass;
                inspectionItemClass = inspectionItemClass.replace(/\s*/g, "");
                let inspectionItem =
                  this.currentSample.insProduct[i].inspectionItem == null ||
                    this.currentSample.insProduct[i].inspectionItem == undefined
                    ? ""
                    : this.currentSample.insProduct[i].inspectionItem;
                inspectionItem = inspectionItem.replace(/\s*/g, "");
                let inspectionItemSubclass =
                  this.currentSample.insProduct[i].inspectionItemSubclass ==
                    null ||
                    this.currentSample.insProduct[i].inspectionItemSubclass ==
                    undefined
                    ? ""
                    : this.currentSample.insProduct[i].inspectionItemSubclass;
                inspectionItemSubclass = inspectionItemSubclass.replace(
                  /\s*/g,
                  ""
                );
                if (inspectionItemSubclass === "干态拉伸强度(纵向)") {
                  // 检验子项为'干态拉伸强度(纵向)'时,模版里是两个计算值对应相同的检验值并且计算方式不同,要根据相同的'单位'做特殊的渲染
                  const unit = this.currentSample.insProduct[i].unit;
                  if (
                    (this.currentSample.insProduct[i].templateId ===
                      a.templateId &&
                      inspectionItemClass +
                      inspectionItem +
                      inspectionItemSubclass +
                      unit ===
                      str2) ||
                    (this.currentSample.insProduct[i].templateId ===
                      a.templateId &&
                      !unit2.includes("/") &&
                      inspectionItemClass +
                      inspectionItem +
                      inspectionItemSubclass ===
                      str)
                  ) {
                    ids.push({
                      r: b.r,
                      id: this.currentSample.insProduct[i].id,
                      product: this.currentSample.insProduct[i],
                    });
                    break;
                  }
                } else {
                  // 如果相等,那么说明找到了,并且把id存起来,后续检验项也会在页面中显示出来
                  if (
                    this.currentSample.insProduct[i].templateId ===
                    a.templateId &&
                    inspectionItemClass +
                    inspectionItem +
                    inspectionItemSubclass ===
                    str
                  ) {
                    ids.push({
                      r: b.r,
                      id: this.currentSample.insProduct[i].id,
                      product: this.currentSample.insProduct[i],
                    });
                    break;
                  }
                }
                count2++;
              }
              if (count2 == this.currentSample.insProduct.length) {
                console.warn("[模板行未匹配] 即将隐藏该行", {
                  sampleId: this.currentSample.id,
                  templateId: a.templateId,
                  templateName: a.templateName,
                  模板行号: b.r + 1,
                  模板拼接名称: str,
                  模板标记单元格: a.template
                    .filter((cell) => cell.r === b.r && cell.v.ps != undefined)
                    .map((cell) => ({
                      列号: cell.c + 1,
                      标记: cell.v.ps.value,
                      文字: cell.v.v,
                    })),
                });
                console.table(this.currentSample.insProduct
                  .filter((product) => product.templateId === a.templateId)
                  .map((product) => {
                    const name = [product.inspectionItemClass, product.inspectionItem,
                      product.inspectionItemSubclass]
                      .map((value) => value == null ? "" : value.replace(/\s*/g, ""))
                      .join("");
                    return {
                      检验项ID: product.id,
                      检验项分类: product.inspectionItemClass,
                      检验项: product.inspectionItem,
                      检验子项: product.inspectionItemSubclass,
                      接口拼接名称: name,
                      模板拼接名称: str,
                      名称是否一致: name === str,
                    };
                  }));
                dels.add(b.r);
              }
            }
          }
        });
        // 操作删除
        dels.forEach((del) => {
          for (let b = 0; b < a.template.length; b++) {
            if (a.template[b].r === del) {
              a.template.splice(b, 1);
              b -= 1;
            }
          }
        });
        // 操作赋值--主要赋值单位,试验方法等信息
        ids.forEach((id) => {
          for (let b = 0; b < a.template.length; b++) {
            if (a.template[b].r === id.r) {
              a.template[b].i = id.id;
              if (
                a.template[b].v.ps != undefined &&
                a.template[b].v.ps.value === "单位"
              ) {
                a.template[b].v.v = id.product.unit;
              }
              if (
                a.template[b].v.ps != undefined &&
                (a.template[b].v.ps.value === "试验方法" ||
                  a.template[b].v.ps.value === "检测方法")
              ) {
                a.template[b].v.v = id.product.methodS;
              }
            }
          }
        });
        let set2 = new Set();
        // 合并的数据处理,cs  rs  代表合并的数量
@@ -2243,20 +1886,11 @@
          }
        });
      });
      // 本次循环主要是对后端传参进行初始化,样式逻辑修改
      // 本次循环主要做样式逻辑处理,可编辑单元格初始化
      this.tableList.forEach((a) => {
        let arrs = [];
        let set = new Set();
        let count1 = 0;
        let conclusionList = []; //结论列表
        let finalList = []; //最终值列表
        // 结论与最终值在这里一一对应,以下两个列表长度肯定是一样的,如果有不一样,那么多半是模板配置得问题
        conclusionList = a.template.filter(
          (n) => n.v.ps != undefined && n.v.ps.value === "结论"
        ); //结论列表
        finalList = a.template.filter(
          (n) => n.v.ps != undefined && n.v.ps.value === "最终值"
        ); //最终值列表
        a.template.forEach((b) => {
          if (
            b.v.ps != undefined &&
@@ -2267,61 +1901,18 @@
            count1++;
            b.v.v = count1;
          }
          if (b.v.ps != undefined && b.v.ps.value === "要求值") {
            // 对要求值进行赋值
            b.v.v = this.getAsk(b.i);
          }
          // 对页面的和给后端传参的检验值,计算值,设备编码,设备名称,最终值,结论进行初始化
          // 初始化可填写/可计算单元格,后续按坐标回显
          if (
            b.v.ps != undefined &&
            typeof b.v.ps.value === "string" &&
            b.v.ps.value.includes("检验值")
            (b.v.ps.value.includes("检验值") ||
              b.v.ps.value === "计算值" ||
              b.v.ps.value === "最终值" ||
              b.v.ps.value === "设备名称")
          ) {
            this.$set(b.v, "v", "");
            // b.v.v = ''
            if (b.v.ps.value.includes("检验值")) {
            b.u = "";
            b.i && this.param[b.i] && this.param[b.i].insValue.push(b);
          }
          if (b.v.ps != undefined && b.v.ps.value === "计算值") {
            this.$set(b.v, "v", "");
            // b.v.v = ''
            b.i && this.param[b.i] && this.param[b.i].comValue.push(b);
          }
          if (b.v.ps != undefined && b.v.ps.value === "设备编码") {
            // b.v.v = ''
            this.$set(b.v, "v", "");
            b.i && this.param[b.i] && this.param[b.i].equipValue.push(b);
          }
          if (b.v.ps != undefined && b.v.ps.value === "设备名称") {
            this.$set(b.v, "v", "");
            // b.v.v = ''
            b.i && this.param[b.i] && this.param[b.i].equipName.push(b);
          }
          if (b.v.ps != undefined && b.v.ps.value === "最终值") {
            // b.v.v = ''
            this.$set(b.v, "v", "");
            if (
              b.i !== undefined &&
              this.param[b.i] &&
              !this.param[b.i].resValue
            ) {
              this.param[b.i].resValue = b;
            }
          }
          if (b.v.ps != undefined && b.v.ps.value === "结论") {
            if (
              b.i !== undefined &&
              this.param[b.i] &&
              !this.param[b.i].insResult
            ) {
              this.param[b.i].insResult = b;
              conclusionList.forEach((n, i) => {
                if (n.r == b.r && n.c == b.c) {
                  b.v.f = `(${this.comparisonList.find((j) => j.value == finalList[i].c)
                    .label
                    }${finalList[i].r + 1})`;
                }
              });
            }
          }
          set.add(b.r);
@@ -2349,112 +1940,56 @@
            a.style.columnlen[i] === undefined ? 100 : a.style.columnlen[i];
        }
      });
      // 本次循环主要是对页面及后端传参进行初始化赋值
      this.currentSample.insProduct.forEach(async (a) => {
        // 尚无检验结果时,保留前面初始化的空值。
        const savedResult = a.insProductResult || {};
        try {
          // 计算值赋值
          let comValue = JSON.parse(savedResult.comValue || "[]");
          for (var i = 0; i < comValue.length; i++) {
            if (
              this.param[a.id].comValue.find(
                (m) => m.c == comValue[i].c && m.r == comValue[i].r
              )
            ) {
              this.param[a.id].comValue.find(
                (m) => m.c == comValue[i].c && m.r == comValue[i].r
              ).v.v = this.toFixed(
                comValue[i].v,
                this.param[a.id].comValue.find(
                  (m) => m.c == comValue[i].c && m.r == comValue[i].r
                ).v.ct
              );
            } else if (!comValue[i].c || !comValue[i].r) {
              this.param[a.id].comValue[i].v.v = this.toFixed(
                comValue[i].v,
                this.param[a.id].comValue[i].v.ct
              );
            }
          }
        } catch (e) { }
        try {
          // 检验值赋值
          let insValue = JSON.parse(savedResult.insValue || "[]");
          for (let i = 0; i < insValue.length; i++) {
            if (
              this.param[a.id].insValue.find(
                (m) => m.c == insValue[i].c && m.r == insValue[i].r
              )
            ) {
              this.param[a.id].insValue.find(
                (m) => m.c == insValue[i].c && m.r == insValue[i].r
              ).v.v = this.toFixed(
                insValue[i].v,
                this.param[a.id].insValue.find(
                  (m) => m.c == insValue[i].c && m.r == insValue[i].r
                ).v.ct
              );
              this.param[a.id].insValue.find(
                (m) => m.c == insValue[i].c && m.r == insValue[i].r
              ).u = insValue[i].u;
              // this.param[a.id].insValue[i].v.v = insValue[i].v
              // this.param[a.id].insValue[i].u = insValue[i].u
            }
          }
        } catch (e) { }
        try {
          // 设备编号赋值
          let equipValue = JSON.parse(savedResult.equipValue || "[]");
          for (let i = 0; i < equipValue.length; i++) {
            // 普通设备赋值
            this.param[a.id].equipValue[i].v.v = equipValue[i].v;
          }
        } catch (e) { }
        try {
          // 设备名称赋值
          let equipName = JSON.parse(savedResult.equipName || "[]");
          for (let i = 0; i < equipName.length; i++) {
            equipName[i].v !== "" &&
              equipName[i].v.map((val) => {
                const index = this.equipOptions.findIndex(
                  (item) => item.value === val
                );
                if (index > -1) {
                  // 根据设备编码转换为相应的设备名称
                  val = this.equipOptions[index].deviceName;
                }
              });
          }
          for (let i = 0; i < equipName.length; i++) {
            // 普通设备名称赋值
            this.param[a.id].equipName[i].v.v = equipName[i].v;
          }
        } catch (e) {
          console.log("设备名称赋值----", e);
        }
        try {
          // 最终值赋值
          this.param[a.id].resValue.v.v = this.toFixed(
            a.lastValue,
            this.param[a.id].resValue.v.ct
          );
          // 结论赋值
          this.param[a.id].insResult.v.v = a.insResult;
        } catch (e) { }
      });
      // 按“模板id + 单元格坐标(r-c)”回显已保存的值
      this.initParamByCoordinate();
      // 对excel函数进行处理
      this.handleExcelMethod();
    },
    // 按“模板id + 单元格坐标(r-c)”回显已保存的值
    initParamByCoordinate() {
      this.param = {};
      this.tableList.forEach((a) => {
        this.param[a.templateId] = {};
        const product = this.currentSample.insProduct.find(
          (m) => m.templateId === a.templateId
        );
        let saved =
          (product && (product.recordValues || product.insProductResult)) || {};
        if (typeof saved === "string") {
          try {
            saved = JSON.parse(saved);
          } catch (e) {
            saved = {};
          }
        }
        a.template.forEach((cell) => {
          const key = `${cell.r}-${cell.c}`;
          const item = saved[key];
          if (item === undefined || item === null) {
            return;
          }
          const value = typeof item === "object" ? item.v : item;
          if (value === undefined || value === null) {
            return;
          }
          cell.v.v = value;
          if (typeof item === "object" && item.u) {
            cell.u = item.u;
          }
          this.param[a.templateId][key] = {
            v: value,
            u: typeof item === "object" ? item.u : cell.u,
          };
        });
      });
    },
    // 检验值输入后触发的函数
    changeInput(m, code, n, getDataType, changeSelect) {
    changeInput(m, code, n, getDataType) {
      // 为数采定义一个逻辑参数
      if (getDataType == "getDataType") {
        this.getDataType = 2;
      }
      let currentInsItemId = null; //当前检验项id
      if (n) {
        currentInsItemId = JSON.parse(JSON.stringify(n.i));
        // 定义一个函数来验证分数是否有效
        if (typeof n.v.v == "string") {
          function isValidFraction(fraction) {
@@ -2486,8 +2021,8 @@
        );
        // 先保存主线程中已经输入的原始值。Worker 完成计算后会再次入队保存计算结果。
        // 这样即使用户输入后立即刷新、切换或返回,最后编辑的单元格也不会丢失。
        if (currentInsItemId) {
          this.saveInsContext(currentInsItemId);
        if (n) {
          this.saveInsContext();
        }
      } catch (error) {
        console.log(444, error);
@@ -2501,36 +2036,13 @@
          case "saveInsContext":
            this.$nextTick(() => {
              const resultValue = workerResult.value;
              // this.$delete(this.tableList[0],'arr')
              this.$set(
                this.tableList[0],
                "arr",
                resultValue.tableList[0].arr
              );
              this.param = resultValue.param;
              // 特殊处理一下结论,会有这种特殊情况
              for (var i in this.param) {
                if (
                  this.param[i].insResult &&
                  this.param[i].insResult.v &&
                  this.param[i].insResult.v.v
                ) {
                  if (this.param[i].insResult.v.v == "合格") {
                    this.$set(this.param[i].insResult.v, "v", 1);
                  } else if (this.param[i].insResult.v.v == "不合格") {
                    this.$set(this.param[i].insResult.v, "v", 0);
                  }
                }
              }
              const sourceInsItemId =
                resultValue.sourceInsItemId != null &&
                  resultValue.sourceInsItemId !== ""
                  ? resultValue.sourceInsItemId
                  : currentInsItemId;
              this.saveInsContext([
                sourceInsItemId,
                resultValue.currentInsItemId,
              ]);
              this.saveInsContext();
            });
            break;
          case "tableList":
@@ -2538,117 +2050,10 @@
              // 更新数据
              this.$delete(this.tableList[0], "arr");
              this.$set(this.tableList[0], "arr", workerResult.value[0].arr);
              // this.param = this.result.value.param
            });
            break;
          case "getCurrentInsProduct":
            // 更新页面数据
            this.getCurrentInsProduct(workerResult.value);
            break;
        }
      };
      // 保存数据
      setTimeout(() => {
        if (changeSelect) {
          this.saveInsContext(currentInsItemId);
        }
      }, 200);
    },
    // 根据后端传参更新页面数据   param => this.tableList[0].insProductResult
    getCurrentInsProduct(pId) {
      if (!this.tableList[0].insProductResult) {
        this.tableList[0].insProductResult = {};
      }
      for (let m in this.param[pId]) {
        let value = this.param[pId][m];
        switch (m) {
          case "comValue":
            // 赋值计算值
            if (value && value.length > 0) {
              this.tableList[0].insProductResult[m] = [];
              value.forEach((a, i) => {
                let obj = {
                  v: a.v.v,
                };
                this.tableList[0].insProductResult[m].push(obj);
              });
              try {
                this.tableList[0].insProductResult[m] = JSON.stringify(
                  this.tableList[0].insProductResult[m]
                );
              } catch (error) {
                console.log(555, error);
              }
            }
            break;
          // 赋值检验值
          case "insValue":
            if (value && value.length > 0) {
              this.tableList[0].insProductResult[m] = [];
              value.forEach((a, i) => {
                let obj = {
                  v: a.v.v,
                  u: a.u,
                };
                this.tableList[0].insProductResult[m].push(obj);
              });
              try {
                this.tableList[0].insProductResult[m] = JSON.stringify(
                  this.tableList[0].insProductResult[m]
                );
              } catch (error) {
                console.log(666, error);
              }
            }
            break;
          // 赋值设备编号
          case "equipValue":
            if (value && value.length > 0) {
              this.tableList[0].insProductResult[m] = [];
              value.forEach((a, i) => {
                let obj = {
                  v: a.v.v,
                };
                this.tableList[0].insProductResult[m].push(obj);
              });
              try {
                this.tableList[0].insProductResult[m] = JSON.stringify(
                  this.tableList[0].insProductResult[m]
                );
              } catch (error) {
                console.log(777, error);
              }
            }
            break;
          // 赋值设备名称
          case "equipName":
            if (value && value.length > 0) {
              this.tableList[0].insProductResult[m] = [];
              value.forEach((a, i) => {
                let obj = {
                  v: a.v.v,
                };
                this.tableList[0].insProductResult[m].push(obj);
              });
              try {
                this.tableList[0].insProductResult[m] = JSON.stringify(
                  this.tableList[0].insProductResult[m]
                );
              } catch (error) {
                console.log(888, error);
              }
            }
            break;
          // 赋值最终值
          case "resValue":
            this.tableList[0].lastValue = value ? value.v.v : "";
            break;
          // 赋值结论
          case "insResult":
            this.tableList[0].insResult = value ? value.v.v : "";
            break;
        }
      }
    },
    // 对EXCEL函数进行处理
    handleExcelMethod() {
@@ -2692,14 +2097,6 @@
        }
      }
    },
    // 获取要求描述
    getTell(id) {
      for (var a in this.currentSample.insProduct) {
        if (this.currentSample.insProduct[a].id == id) {
          return this.currentSample.insProduct[a].tell;
        }
      }
    },
    // 动态获取单元格宽度
    handleWidth(n) {
      let sum = 0;
@@ -2740,14 +2137,6 @@
        }
      }
    },
    // 获取要求值
    getAsk(id) {
      for (var a in this.currentSample.insProduct) {
        if (this.currentSample.insProduct[a].id == id) {
          return this.currentSample.insProduct[a].ask;
        }
      }
    },
    // 获取所有设备
    getEquipOptions(e, id) {
      if (e) {
@@ -2766,17 +2155,6 @@
          });
      }
    },
    // getDic(e, id) {
    //   if (e) {
    //     for (var a in this.currentSample.insProduct) {
    //       if (this.currentSample.insProduct[a].id == id) {
    //         let str = this.currentSample.insProduct[a].dic;
    //         this.selectEnumByCategoryOfSelect(str);
    //         return str;
    //       }
    //     }
    //   }
    // },
    openAddCheck() {
      this.addCheck = true;
    },
@@ -2970,38 +2348,57 @@
        });
      return;
    },
    // 统一在这里保存数据
    saveInsContext(currentInsItemIds) {
      try {
        if (this.param) {
          const ids = (Array.isArray(currentInsItemIds)
            ? currentInsItemIds
            : [currentInsItemIds]
          )
            .filter((id) => id != null && id !== "")
            .map((id) => String(id));
          let param = this.param;
          if (ids.length > 0) {
            param = {};
            [...new Set(ids)].forEach((id) => {
              if (this.param[id]) {
                param[id] = this.param[id];
              }
            });
            if (Object.keys(param).length === 0) {
    // 按“模板id + 单元格坐标(r-c)”从当前模板快照出待保存参数
    buildParam() {
      const param = {};
      this.tableList.forEach((a) => {
        param[a.templateId] = {};
        a.template.forEach((cell) => {
          const isEditable =
            cell.v.ps != undefined &&
            typeof cell.v.ps.value === "string" &&
            (cell.v.ps.value.includes("检验值") ||
              cell.v.ps.value === "计算值" ||
              cell.v.ps.value === "最终值" ||
              cell.v.ps.value === "设备名称");
          if (!isEditable) {
              return;
            }
          if (
            cell.v.ps.value.includes("检验值") &&
            (cell.v.v === "" || cell.v.v === null || cell.v.v === undefined)
          ) {
            return;
          }
          let isNoTestValue = ''
          for (let key in param) {
            if (param[key]) {
              if (param[key].insValue?.length === 0) {
                isNoTestValue = 1
              } else {
                isNoTestValue = ''
          param[a.templateId][`${cell.r}-${cell.c}`] = {
            v: cell.v.v,
            u: cell.u,
          };
        });
      });
      return param;
    },
    // 统一在这里保存数据
    saveInsContext() {
      try {
        if (!this.param) {
          return;
              }
        const param = this.buildParam();
        this.param = param;
        let isNoTestValue = "";
        this.tableList.forEach((a) => {
          a.template.forEach((cell) => {
            if (
              cell.v.ps != undefined &&
              typeof cell.v.ps.value === "string" &&
              cell.v.ps.value.includes("检验值") &&
              (cell.v.v === "" || cell.v.v === null || cell.v.v === undefined)
            ) {
              isNoTestValue = 1;
            }
          }
          });
        });
          const payload = {
            param: JSON.stringify(param),
            currentTable: this.currentTable,
@@ -3031,7 +2428,6 @@
              currentTable: this.currentTable,
            })
          );
        }
      } catch (error) {
        console.log(999, error);
      }
@@ -3043,21 +2439,9 @@
    },
    // 设备改变
    changeEquip(val, n) {
      const itemParam = this.param[n.i];
      if (!itemParam) {
        this.$message.error("设备未关联检验项,请刷新页面后重试");
        return;
      }
      const selectedDevices = Array.isArray(val) ? [...val] : [];
      const deviceCodes = selectedDevices.join(",");
      this.$set(n.v, "v", selectedDevices);
      // 名称与编码单元格可能数量不同,分别更新,避免下标越界中断保存。
      (itemParam.equipName || []).forEach((cell) => {
        this.$set(cell.v, "v", [...selectedDevices]);
      });
      (itemParam.equipValue || []).forEach((cell) => {
        this.$set(cell.v, "v", deviceCodes);
      });
      this.tableList.forEach((table) => {
        (table.arr || []).forEach((row) => {
          row.forEach((cell) => {
@@ -3071,8 +2455,8 @@
          });
        });
      });
      // 选择、移除、清空均由 change 事件触发,立即保存当前检验项。
      this.saveInsContext(n.i);
      // 选择、移除、清空均由 change 事件触发,立即保存。
      this.saveInsContext();
    },
    getAuthorizedPerson() {
      selectUserCondition({ type: 1 }).then((res) => {
@@ -3132,16 +2516,6 @@
      // 初始化后端传参
      this.param = {};
      this.changeType = 0;
      this.currentSample.insProduct.forEach((a, j) => {
        this.param[a.id] = {
          insValue: [],
          comValue: [],
          resValue: null,
          equipValue: [],
          equipName: [],
          insResult: null,
        };
      });
      // 页面数据处理
      this.getTableLists();
      // 更新到多线程
src/views/business/inspectionView/index.vue
@@ -173,7 +173,7 @@
                      n.v.ps.value.includes('检验值') &&
                      state == 1
                    ">
                    <el-input v-if="getInspectionValueType(n.i) == 1"
                    <el-input v-if="getInspectionValueType(n.i) == 1 || (getInspectionValueType(n.i) != 2 && getInspectionValueType(n.i) != 4)"
                              :key="'abc-' + '000' + index + '000' + i + '000' + j" v-model="n.v.v" :disabled="(getInspectionItemType(n.i) == 1 &&
                          !dataAcquisitionEidtAble) ||
                          (n.u != userId && n.u != undefined && n.u != '')
@@ -203,63 +203,8 @@
                            'getDataType'
                          )
                          " />
                    <!-- <el-select v-else-if="getInspectionValueType(n.i) == 5" v-model="n.v.v" :disabled="state > 1 ||
                    getInspectionItemType(n.i) == 1 ||
                    (n.u != userId && n.u != undefined && n.u != '')
                    " class="table_input" @change="(m) =>
                      changeInput(
                        m,
                        `${item.templateId}-${n.r}-${n.c}-${n.i}`,
                        n,
                        'getDataType'
                      )
                      " @visible-change="(e) => getDic(e, n.i)">
                    <el-option v-for="(e, i) in enumList" :key="i" :label="e.label" :value="e.value"></el-option>
                  </el-select> -->
                    <span v-else-if="getInspectionValueType(n.i) == 4"
                          :style="`font-family:${n.v.ff} !important;`">/</span>
                  </template>
                  <template v-else-if="n.v.ps != undefined && n.v.ps.value === '结论'">
                    <el-select v-if="
                        (getInspectionValueType(n.i) == 2 ||
                          getInspectionValueType(n.i) == 5) &&
                        state == 1
                      " v-model="n.v.v" class="table_input" @change="(m) =>
                        changeInput(
                          m,
                          `${item.templateId}-${n.r}-${n.c}-${n.i}`,
                          n,
                          'getDataType',
                          'changeSelect'
                        )
                        ">
                      <el-option :value="1" label="合格"></el-option>
                      <el-option :value="0" label="不合格"></el-option>
                      <el-option :value="3" label="不判定"></el-option>
                      <el-option :value="2" label="待定"></el-option>
                    </el-select>
                    <template v-if="state > 1">
                      <span v-if="n.v.v === 1" :style="`font-family:${n.v.ff} !important;color: green;`">合格</span>
                      <span v-else-if="n.v.v === 0" :style="`font-family:${n.v.ff} !important;color: red;`">不合格</span>
                      <span v-else-if="n.v.v === 3"
                            :style="`font-family:${n.v.ff} !important;color: #3A7BFA;`">不判定</span>
                      <span v-else :style="`font-family:${n.v.ff} !important;`">待定</span>
                    </template>
                    <template v-if="getInspectionValueType(n.i) != 2 &&
                        state == 1">
                      <span v-if="n.v.v === 1" :style="`font-family:${n.v.ff} !important;color: green;`">合格</span>
                      <span v-else-if="n.v.v === 0" :style="`font-family:${n.v.ff} !important;color: red;`">不合格</span>
                      <span v-else-if="n.v.v === 3"
                            :style="`font-family:${n.v.ff} !important;color: #3A7BFA;`">不判定</span>
                      <span v-else :style="`font-family:${n.v.ff} !important;`">待定</span>
                    </template>
                  </template>
                  <template v-else-if="
                      n.v.ps != undefined &&
                      n.v.ps.value === '设备编码' &&
                      state == 1
                    ">
                    <span>{{ n.v.v }}</span>
                  </template>
                  <template v-else-if="
                      n.v.ps != undefined && n.v.ps.value === '设备名称'
@@ -272,15 +217,6 @@
                        {{ item.label + "--" + item.value }}
                      </el-option>
                    </el-select>
                  </template>
                  <template v-else-if="
                      n.v.ps != undefined &&
                      n.v.ps.value === '要求值' &&
                      state == 1
                    ">
                      <span :style="`font-family:${n.v.ff} !important;`">{{
                          getTell(n.i)
                        }}</span>
                  </template>
                  <template v-else-if="
                      n.v.ps != undefined &&
@@ -609,6 +545,7 @@
      loading: false,
      ps: {},
      param: {},
      saveQueue: null,
      currentKey: 1,
      currentKey0: 1,
      currentKey1: 1,
@@ -835,16 +772,6 @@
            let list = await this.getCurrentProduct(this.currentSample.id, 0);
            this.currentSample.insProduct = this.HaveJson(list); //赋值当前样品的检验项
            this.param = {}; //初始化传到后端的参数
            this.currentSample.insProduct.forEach((a, j) => {
              this.param[a.id] = {
                insValue: [],
                comValue: [],
                resValue: null,
                equipValue: [],
                equipName: [],
                insResult: null,
              };
            });
            // 去重模板,返回有几个模板
            const mySet1 = new Set();
            this.tableLists = this.currentSample.insProduct.filter((m) => {
@@ -989,16 +916,6 @@
        // 初始化传递到后端的参数
        this.param = {};
        this.changeType = 0;
        this.currentSample.insProduct.forEach((a) => {
          this.param[a.id] = {
            insValue: [],
            comValue: [],
            resValue: null,
            equipValue: [],
            equipName: [],
            insResult: null,
          };
        });
        if (this.currentSample.index == undefined)
          this.currentSample["index"] = 1;
        let bushing = this.currentSample.bushing;
@@ -1556,16 +1473,6 @@
      // 初始化后端传参
      this.param = {};
      this.changeType = 0;
      this.currentSample.insProduct.forEach((a, j) => {
        this.param[a.id] = {
          insValue: [],
          comValue: [],
          resValue: null,
          equipValue: [],
          equipName: [],
          insResult: null,
        };
      });
      // 处理页面列表数据
      this.getTableLists();
      this.currentKey = row.index;
@@ -1601,16 +1508,6 @@
        let list = await this.getCurrentProduct(m, type, cableTag);
        if (list && list.length > 0) {
          this.param = {};
          list.forEach((a) => {
            this.param[a.id] = {
              insValue: [],
              comValue: [],
              resValue: null,
              equipValue: [],
              equipName: [],
              insResult: null,
            };
          });
          this.getTableLists0(list);
          this.worker.postMessage(
            JSON.stringify({
@@ -1754,224 +1651,18 @@
          count++;
        });
      });
      // 本次循环主要是控制合并,以及控制检验项信息是否展示出来,以便后续检验
      // 按后端下发的“模板ID + 模板行号”直接绑定检验项,不做名称比对,不隐藏任何行
      this.tableList.forEach((a) => {
        // 新聚订单直接按“模板ID + 模板行号”绑定检验记录,不再匹配分类和检验子项。
        const directProducts = this.currentSample.insProduct.filter(
          (product) => product.templateId === a.templateId &&
            product.templateRowIndex !== null && product.templateRowIndex !== undefined
        );
        if (directProducts.length > 0) {
          directProducts.forEach((product) => {
            a.template.forEach((cell) => {
              if (cell.r === product.templateRowIndex) {
                cell.i = product.id;
              }
            });
          });
          return;
        }
        let dels = new Set(); //需要删除的行
        let ids = []; //所有检验项的id
        let set3 = new Set();
        a.template.forEach((b) => {
          let size1 = set3.size;
          let size2 = set3.add(b.r).size;
          if (size1 < size2) {
            let str = "";
            let str2 = "";
            let unit2 = "";
            let count4 = 0;
            let isThree = 0;
            a.template.forEach((c) => {
              // 获取到 检验项分类+检验项+检验子项的拼接,如果模板里的信息跟接口返回的检验项信息能够匹配则展示出来
              if (b.r === c.r) {
                if (
                  c.v.ps != undefined &&
                  c.v.ps.value === "检验项分类" &&
                  count4 === 0
                ) {
                  // 三级分类
                  isThree = 1;
                } else if (
                  c.v.ps != undefined &&
                  c.v.ps.value === "检验项" &&
                  count4 === 0
                ) {
                  // 二级分类
                  isThree = 0;
                }
                if (isThree == 0) {
                  if (c.v.ps != undefined && c.v.ps.value === "检验项") {
                    if (count4 === 0) {
                      if (c.v.v) {
                        c.v.v = c.v.v.replace(/\s*/g, "");
                      }
                      str += c.v.v;
                      count4 += 1;
                    }
                  } else if (
                    c.v.ps != undefined &&
                    c.v.ps.value === "检验子项"
                  ) {
                    if (count4 === 1) {
                      if (c.v.v) {
                        c.v.v = c.v.v.replace(/\s*/g, "");
                      }
                      str += c.v.v;
                      count4 += 1;
                    }
                  }
                } else if (isThree == 1) {
                  if (c.v.ps != undefined && c.v.ps.value === "检验项分类") {
                    if (count4 === 0) {
                      if (c.v.v) {
                        c.v.v = c.v.v.replace(/\s*/g, "");
                      }
                      str += c.v.v;
                      count4 += 1;
                    }
                  } else if (c.v.ps != undefined && c.v.ps.value === "检验项") {
                    if (count4 === 1) {
                      if (c.v.v) {
                        c.v.v = c.v.v.replace(/\s*/g, "");
                      }
                      str += c.v.v;
                      count4 += 1;
                    }
                  } else if (
                    c.v.ps != undefined &&
                    c.v.ps.value === "检验子项"
                  ) {
                    if (count4 === 2) {
                      if (c.v.v) {
                        c.v.v = c.v.v.replace(/\s*/g, "");
                      }
                      str += c.v.v;
                      count4 += 1;
                    }
                  }
                }
                if (str === "机械性能干态拉伸强度(纵向)") {
                  if (c.v.ps != undefined && c.v.ps.value === "单位") {
                    if (c.v.v) {
                      c.v.v = c.v.v.replace(/\s*/g, "");
                    }
                    str2 = str + c.v.v;
                    unit2 = c.v.v;
                  }
                }
              }
            });
            if (str != "") {
              let count2 = 0;
              for (let i in this.currentSample.insProduct) {
                let inspectionItemClass =
                  this.currentSample.insProduct[i].inspectionItemClass ==
                  null ||
                  this.currentSample.insProduct[i].inspectionItemClass ==
                  undefined
                    ? ""
                    : this.currentSample.insProduct[i].inspectionItemClass;
                inspectionItemClass = inspectionItemClass.replace(/\s*/g, "");
                let inspectionItem =
                  this.currentSample.insProduct[i].inspectionItem == null ||
                  this.currentSample.insProduct[i].inspectionItem == undefined
                    ? ""
                    : this.currentSample.insProduct[i].inspectionItem;
                inspectionItem = inspectionItem.replace(/\s*/g, "");
                let inspectionItemSubclass =
                  this.currentSample.insProduct[i].inspectionItemSubclass ==
                  null ||
                  this.currentSample.insProduct[i].inspectionItemSubclass ==
                  undefined
                    ? ""
                    : this.currentSample.insProduct[i].inspectionItemSubclass;
                inspectionItemSubclass = inspectionItemSubclass.replace(
                  /\s*/g,
                  ""
                );
                if (inspectionItemSubclass === "干态拉伸强度(纵向)") {
                  // 检验子项为'干态拉伸强度(纵向)'时,模版里是两个计算值对应相同的检验值并且计算方式不同,要根据相同的'单位'做特殊的渲染
                  const unit = this.currentSample.insProduct[i].unit;
                  if (
                    (this.currentSample.insProduct[i].templateId ===
                      a.templateId &&
                      inspectionItemClass +
                      inspectionItem +
                      inspectionItemSubclass +
                      unit ===
                      str2) ||
                    (this.currentSample.insProduct[i].templateId ===
                      a.templateId &&
                      !unit2.includes("/") &&
                      inspectionItemClass +
                      inspectionItem +
                      inspectionItemSubclass ===
                      str)
                  ) {
                    ids.push({
                      r: b.r,
                      id: this.currentSample.insProduct[i].id,
                      product: this.currentSample.insProduct[i],
                    });
                    break;
                  }
                } else {
                  // 如果相等,那么说明找到了,并且把id存起来,后续检验项也会在页面中显示出来
                  if (
                    this.currentSample.insProduct[i].templateId ===
                    a.templateId &&
                    inspectionItemClass +
                    inspectionItem +
                    inspectionItemSubclass ===
                    str
                  ) {
                    ids.push({
                      r: b.r,
                      id: this.currentSample.insProduct[i].id,
                      product: this.currentSample.insProduct[i],
                    });
                    break;
                  }
                }
                count2++;
              }
              if (count2 == this.currentSample.insProduct.length) {
                dels.add(b.r);
              }
            }
          }
        });
        // 操作删除
        dels.forEach((del) => {
          for (let b = 0; b < a.template.length; b++) {
            if (a.template[b].r === del) {
              a.template.splice(b, 1);
              b -= 1;
            }
          }
        });
        // 操作赋值--主要赋值单位,试验方法等信息
        ids.forEach((id) => {
          for (let b = 0; b < a.template.length; b++) {
            if (a.template[b].r === id.r) {
              a.template[b].i = id.id;
              if (
                a.template[b].v.ps != undefined &&
                a.template[b].v.ps.value === "单位"
              ) {
                a.template[b].v.v = id.product.unit;
              }
              if (
                a.template[b].v.ps != undefined &&
                (a.template[b].v.ps.value === "试验方法" ||
                  a.template[b].v.ps.value === "检测方法")
              ) {
                a.template[b].v.v = id.product.methodS;
              }
            }
          }
        });
        let set2 = new Set();
        // 合并的数据处理,cs  rs  代表合并的数量
@@ -1999,15 +1690,6 @@
        let arrs = [];
        let set = new Set();
        let count1 = 0;
        let conclusionList = []; //结论列表
        let finalList = []; //最终值列表
        // 结论与最终值在这里一一对应,以下两个列表长度肯定是一样的,如果有不一样,那么多半是模板配置得问题
        conclusionList = a.template.filter(
          (n) => n.v.ps != undefined && n.v.ps.value === "结论"
        ); //结论列表
        finalList = a.template.filter(
          (n) => n.v.ps != undefined && n.v.ps.value === "最终值"
        ); //最终值列表
        a.template.forEach((b) => {
          if (
            b.v.ps != undefined &&
@@ -2018,61 +1700,18 @@
            count1++;
            b.v.v = count1;
          }
          if (b.v.ps != undefined && b.v.ps.value === "要求值") {
            // 对要求值进行赋值
            b.v.v = this.getAsk(b.i);
          }
          // 对页面的和给后端传参的检验值,计算值,设备编码,设备名称,最终值,结论进行初始化
          // 初始化可填写/可计算单元格,后续按坐标回显
          if (
            b.v.ps != undefined &&
            typeof b.v.ps.value === "string" &&
            b.v.ps.value.includes("检验值")
            (b.v.ps.value.includes("检验值") ||
              b.v.ps.value === "计算值" ||
              b.v.ps.value === "最终值" ||
              b.v.ps.value === "设备名称")
          ) {
            this.$set(b.v, "v", "");
            // b.v.v = ''
            if (b.v.ps.value.includes("检验值")) {
            b.u = "";
            b.i && this.param[b.i] && this.param[b.i].insValue.push(b);
          }
          if (b.v.ps != undefined && b.v.ps.value === "计算值") {
            this.$set(b.v, "v", "");
            // b.v.v = ''
            b.i && this.param[b.i] && this.param[b.i].comValue.push(b);
          }
          if (b.v.ps != undefined && b.v.ps.value === "设备编码") {
            // b.v.v = ''
            this.$set(b.v, "v", "");
            b.i && this.param[b.i] && this.param[b.i].equipValue.push(b);
          }
          if (b.v.ps != undefined && b.v.ps.value === "设备名称") {
            this.$set(b.v, "v", "");
            // b.v.v = ''
            b.i && this.param[b.i] && this.param[b.i].equipName.push(b);
          }
          if (b.v.ps != undefined && b.v.ps.value === "最终值") {
            // b.v.v = ''
            this.$set(b.v, "v", "");
            if (
              b.i !== undefined &&
              this.param[b.i] &&
              !this.param[b.i].resValue
            ) {
              this.param[b.i].resValue = b;
            }
          }
          if (b.v.ps != undefined && b.v.ps.value === "结论") {
            if (
              b.i !== undefined &&
              this.param[b.i] &&
              !this.param[b.i].insResult
            ) {
              this.param[b.i].insResult = b;
              conclusionList.forEach((n, i) => {
                if (n.r == b.r && n.c == b.c) {
                  b.v.f = `(${this.comparisonList.find((j) => j.value == finalList[i].c)
                    .label
                  }${finalList[i].r + 1})`;
                }
              });
            }
          }
          set.add(b.r);
@@ -2100,110 +1739,56 @@
            a.style.columnlen[i] === undefined ? 100 : a.style.columnlen[i];
        }
      });
      // 本次循环主要是对页面及后端传参进行初始化赋值
      this.currentSample.insProduct.forEach(async (a) => {
        try {
          // 计算值赋值
          let comValue = JSON.parse(a.insProductResult.comValue);
          for (var i = 0; i < comValue.length; i++) {
            if (
              this.param[a.id].comValue.find(
                (m) => m.c == comValue[i].c && m.r == comValue[i].r
              )
            ) {
              this.param[a.id].comValue.find(
                (m) => m.c == comValue[i].c && m.r == comValue[i].r
              ).v.v = this.toFixed(
                comValue[i].v,
                this.param[a.id].comValue.find(
                  (m) => m.c == comValue[i].c && m.r == comValue[i].r
                ).v.ct
              );
            } else if (!comValue[i].c || !comValue[i].r) {
              this.param[a.id].comValue[i].v.v = this.toFixed(
                comValue[i].v,
                this.param[a.id].comValue[i].v.ct
              );
            }
          }
        } catch (e) { }
        try {
          // 检验值赋值
          let insValue = JSON.parse(a.insProductResult.insValue);
          for (let i = 0; i < insValue.length; i++) {
            if (
              this.param[a.id].insValue.find(
                (m) => m.c == insValue[i].c && m.r == insValue[i].r
              )
            ) {
              this.param[a.id].insValue.find(
                (m) => m.c == insValue[i].c && m.r == insValue[i].r
              ).v.v = this.toFixed(
                insValue[i].v,
                this.param[a.id].insValue.find(
                  (m) => m.c == insValue[i].c && m.r == insValue[i].r
                ).v.ct
              );
              this.param[a.id].insValue.find(
                (m) => m.c == insValue[i].c && m.r == insValue[i].r
              ).u = insValue[i].u;
              // this.param[a.id].insValue[i].v.v = insValue[i].v
              // this.param[a.id].insValue[i].u = insValue[i].u
            }
          }
        } catch (e) { }
        try {
          // 设备编号赋值
          let equipValue = JSON.parse(a.insProductResult.equipValue);
          for (let i = 0; i < equipValue.length; i++) {
            // 普通设备赋值
            this.param[a.id].equipValue[i].v.v = equipValue[i].v;
          }
        } catch (e) { }
        try {
          // 设备名称赋值
          let equipName = JSON.parse(a.insProductResult.equipName);
          for (let i = 0; i < equipName.length; i++) {
            equipName[i].v !== "" &&
            equipName[i].v.map((val) => {
              const index = this.equipOptions.findIndex(
                (item) => item.value === val
              );
              if (index > -1) {
                // 根据设备编码转换为相应的设备名称
                val = this.equipOptions[index].deviceName;
              }
            });
          }
          for (let i = 0; i < equipName.length; i++) {
            // 普通设备名称赋值
            this.param[a.id].equipName[i].v.v = equipName[i].v;
          }
        } catch (e) {
          console.log("设备名称赋值----", e);
        }
        try {
          // 最终值赋值
          this.param[a.id].resValue.v.v = this.toFixed(
            a.lastValue,
            this.param[a.id].resValue.v.ct
          );
          // 结论赋值
          this.param[a.id].insResult.v.v = a.insResult;
        } catch (e) { }
      });
      // 按“模板id + 单元格坐标(r-c)”回显已保存的值
      this.initParamByCoordinate();
      // 对excel函数进行处理
      this.handleExcelMethod();
    },
    // 按“模板id + 单元格坐标(r-c)”回显已保存的值
    initParamByCoordinate() {
      this.param = {};
      this.tableList.forEach((a) => {
        this.param[a.templateId] = {};
        const product = this.currentSample.insProduct.find(
          (m) => m.templateId === a.templateId
        );
        let saved =
          (product && (product.recordValues || product.insProductResult)) || {};
        if (typeof saved === "string") {
          try {
            saved = JSON.parse(saved);
          } catch (e) {
            saved = {};
          }
        }
        a.template.forEach((cell) => {
          const key = `${cell.r}-${cell.c}`;
          const item = saved[key];
          if (item === undefined || item === null) {
            return;
          }
          const value = typeof item === "object" ? item.v : item;
          if (value === undefined || value === null) {
            return;
          }
          cell.v.v = value;
          if (typeof item === "object" && item.u) {
            cell.u = item.u;
          }
          this.param[a.templateId][key] = {
            v: value,
            u: typeof item === "object" ? item.u : cell.u,
          };
        });
      });
    },
    // 检验值输入后触发的函数
    changeInput(m, code, n, getDataType, changeSelect) {
    changeInput(m, code, n, getDataType) {
      // 为数采定义一个逻辑参数
      if (getDataType == "getDataType") {
        this.getDataType = 2;
      }
      let currentInsItemId = null; //当前检验项id
      if (n) {
        currentInsItemId = JSON.parse(JSON.stringify(n.i));
        // 定义一个函数来验证分数是否有效
        if (typeof n.v.v == "string") {
          function isValidFraction(fraction) {
@@ -2233,6 +1818,11 @@
            currentInsItem: n,
          })
        );
        // 先保存主线程中已经输入的原始值。Worker 完成计算后会再次入队保存计算结果。
        // 这样即使用户输入后立即刷新、切换或返回,最后编辑的单元格也不会丢失。
        if (n) {
          this.saveInsContext();
        }
      } catch (error) {
        console.log(444, error);
      }
@@ -2245,36 +1835,13 @@
          case "saveInsContext":
            this.$nextTick(() => {
              const resultValue = workerResult.value;
              // this.$delete(this.tableList[0],'arr')
              this.$set(
                this.tableList[0],
                "arr",
                resultValue.tableList[0].arr
              );
              this.param = resultValue.param;
              // 特殊处理一下结论,会有这种特殊情况
              for (var i in this.param) {
                if (
                  this.param[i].insResult &&
                  this.param[i].insResult.v &&
                  this.param[i].insResult.v.v
                ) {
                  if (this.param[i].insResult.v.v == "合格") {
                    this.$set(this.param[i].insResult.v, "v", 1);
                  } else if (this.param[i].insResult.v.v == "不合格") {
                    this.$set(this.param[i].insResult.v, "v", 0);
                  }
                }
              }
              const sourceInsItemId =
                resultValue.sourceInsItemId != null &&
                  resultValue.sourceInsItemId !== ""
                  ? resultValue.sourceInsItemId
                  : currentInsItemId;
              this.saveInsContext([
                sourceInsItemId,
                resultValue.currentInsItemId,
              ]);
              this.saveInsContext();
            });
            break;
          case "tableList":
@@ -2282,117 +1849,10 @@
              // 更新数据
              this.$delete(this.tableList[0], "arr");
              this.$set(this.tableList[0], "arr", workerResult.value[0].arr);
              // this.param = this.result.value.param
            });
            break;
          case "getCurrentInsProduct":
            // 更新页面数据
            this.getCurrentInsProduct(workerResult.value);
            break;
        }
      };
      // 保存数据
      setTimeout(() => {
        if (changeSelect) {
          this.saveInsContext(currentInsItemId);
        }
      }, 200);
    },
    // 根据后端传参更新页面数据   param => this.tableList[0].insProductResult
    getCurrentInsProduct(pId) {
      if (!this.tableList[0].insProductResult) {
        this.tableList[0].insProductResult = {};
      }
      for (let m in this.param[pId]) {
        let value = this.param[pId][m];
        switch (m) {
          case "comValue":
            // 赋值计算值
            if (value && value.length > 0) {
              this.tableList[0].insProductResult[m] = [];
              value.forEach((a, i) => {
                let obj = {
                  v: a.v.v,
                };
                this.tableList[0].insProductResult[m].push(obj);
              });
              try {
                this.tableList[0].insProductResult[m] = JSON.stringify(
                  this.tableList[0].insProductResult[m]
                );
              } catch (error) {
                console.log(555, error);
              }
            }
            break;
          // 赋值检验值
          case "insValue":
            if (value && value.length > 0) {
              this.tableList[0].insProductResult[m] = [];
              value.forEach((a, i) => {
                let obj = {
                  v: a.v.v,
                  u: a.u,
                };
                this.tableList[0].insProductResult[m].push(obj);
              });
              try {
                this.tableList[0].insProductResult[m] = JSON.stringify(
                  this.tableList[0].insProductResult[m]
                );
              } catch (error) {
                console.log(666, error);
              }
            }
            break;
          // 赋值设备编号
          case "equipValue":
            if (value && value.length > 0) {
              this.tableList[0].insProductResult[m] = [];
              value.forEach((a, i) => {
                let obj = {
                  v: a.v.v,
                };
                this.tableList[0].insProductResult[m].push(obj);
              });
              try {
                this.tableList[0].insProductResult[m] = JSON.stringify(
                  this.tableList[0].insProductResult[m]
                );
              } catch (error) {
                console.log(777, error);
              }
            }
            break;
          // 赋值设备名称
          case "equipName":
            if (value && value.length > 0) {
              this.tableList[0].insProductResult[m] = [];
              value.forEach((a, i) => {
                let obj = {
                  v: a.v.v,
                };
                this.tableList[0].insProductResult[m].push(obj);
              });
              try {
                this.tableList[0].insProductResult[m] = JSON.stringify(
                  this.tableList[0].insProductResult[m]
                );
              } catch (error) {
                console.log(888, error);
              }
            }
            break;
          // 赋值最终值
          case "resValue":
            this.tableList[0].lastValue = value ? value.v.v : "";
            break;
          // 赋值结论
          case "insResult":
            this.tableList[0].insResult = value ? value.v.v : "";
            break;
        }
      }
    },
    // 对EXCEL函数进行处理
    handleExcelMethod() {
@@ -2436,14 +1896,6 @@
        }
      }
    },
    // 获取要求描述
    getTell(id) {
      for (var a in this.currentSample.insProduct) {
        if (this.currentSample.insProduct[a].id == id) {
          return this.currentSample.insProduct[a].tell;
        }
      }
    },
    // 动态获取单元格宽度
    handleWidth(n) {
      let sum = 0;
@@ -2484,14 +1936,6 @@
        }
      }
    },
    // 获取要求值
    getAsk(id) {
      for (var a in this.currentSample.insProduct) {
        if (this.currentSample.insProduct[a].id == id) {
          return this.currentSample.insProduct[a].ask;
        }
      }
    },
    // 获取所有设备
    getEquipOptions(e, id) {
      if (e) {
@@ -2510,17 +1954,6 @@
          });
      }
    },
    // getDic(e, id) {
    //   if (e) {
    //     for (var a in this.currentSample.insProduct) {
    //       if (this.currentSample.insProduct[a].id == id) {
    //         let str = this.currentSample.insProduct[a].dic;
    //         this.selectEnumByCategoryOfSelect(str);
    //         return str;
    //       }
    //     }
    //   }
    // },
    openAddCheck() {
      this.addCheck = true;
    },
@@ -2692,36 +2125,75 @@
        });
      return;
    },
    // 统一在这里保存数据
    saveInsContext(currentInsItemIds) {
      try {
        if (this.param) {
          const ids = (Array.isArray(currentInsItemIds)
            ? currentInsItemIds
            : [currentInsItemIds]
          )
            .filter((id) => id != null && id !== "")
            .map((id) => String(id));
          let param = this.param;
          if (ids.length > 0) {
            param = {};
            [...new Set(ids)].forEach((id) => {
              if (this.param[id]) {
                param[id] = this.param[id];
              }
            });
            if (Object.keys(param).length === 0) {
    // 按“模板id + 单元格坐标(r-c)”从当前模板快照出待保存参数
    buildParam() {
      const param = {};
      this.tableList.forEach((a) => {
        param[a.templateId] = {};
        a.template.forEach((cell) => {
          const isEditable =
            cell.v.ps != undefined &&
            typeof cell.v.ps.value === "string" &&
            (cell.v.ps.value.includes("检验值") ||
              cell.v.ps.value === "计算值" ||
              cell.v.ps.value === "最终值" ||
              cell.v.ps.value === "设备名称");
          if (!isEditable) {
              return;
            }
          if (
            cell.v.ps.value.includes("检验值") &&
            (cell.v.v === "" || cell.v.v === null || cell.v.v === undefined)
          ) {
            return;
          }
          saveInsContext({
          param[a.templateId][`${cell.r}-${cell.c}`] = {
            v: cell.v.v,
            u: cell.u,
          };
        });
      });
      return param;
    },
    // 统一在这里保存数据
    saveInsContext() {
      try {
        if (!this.param) {
          return;
        }
        const param = this.buildParam();
        this.param = param;
        let isNoTestValue = "";
        this.tableList.forEach((a) => {
          a.template.forEach((cell) => {
            if (
              cell.v.ps != undefined &&
              typeof cell.v.ps.value === "string" &&
              cell.v.ps.value.includes("检验值") &&
              (cell.v.v === "" || cell.v.v === null || cell.v.v === undefined)
            ) {
              isNoTestValue = 1;
            }
          });
        });
        const payload = {
            param: JSON.stringify(param),
            currentTable: this.currentTable,
            sampleId: this.currentSample.id,
            orderId: this.orderId,
            sonLaboratory: this.sonLaboratory
          }).then((res) => {
          sonLaboratory: this.sonLaboratory,
          isNoTestValue: isNoTestValue
        };
        const previousSave = this.saveQueue || Promise.resolve();
        this.saveQueue = previousSave
          .catch(() => undefined)
          .then(() => saveInsContext(payload))
          .then(() => {
            this.$message.success("已保存");
          })
          .catch((error) => {
            console.error("检验数据保存失败", error);
            this.$message.error("检验数据保存失败,请重试");
          });
          // 向 Worker 发送消息,开始处理逻辑
          this.worker.postMessage(
@@ -2733,59 +2205,30 @@
              currentTable: this.currentTable,
            })
          );
        }
      } catch (error) {
        console.log(999, error);
      }
    },
    // 设备改变
    changeEquip(val, n, v) {
      try {
        // this.$set(n.v,'v',val)
        this.tableList[0].arr.forEach((item, index) => {
          item.forEach((m, i) => {
            if (this.param[m.i]) {
              this.param[m.i].state = 1;
    changeEquip(val, n) {
      const selectedDevices = Array.isArray(val) ? [...val] : [];
      const deviceCodes = selectedDevices.join(",");
      this.$set(n.v, "v", selectedDevices);
      this.tableList.forEach((table) => {
        (table.arr || []).forEach((row) => {
          row.forEach((cell) => {
            if (cell.i == n.i && cell.v.ps) {
              if (cell.v.ps.value === "设备名称") {
                this.$set(cell.v, "v", [...selectedDevices]);
              } else if (cell.v.ps.value === "设备编码") {
                this.$set(cell.v, "v", deviceCodes);
            }
            // if(m.i==n.i&&m.v.ps&&m.v.ps.value=='设备名称'&&v){
            //   this.$set(m.v,'v',v)
            // }
          });
        });
        for (let i in this.param) {
          if (this.param[i].state != 1) {
            delete this.param[i];
          }
        }
        // this.equipOptions为设备名称下拉框选项数据
        for (let i1 in this.param[n.i].equipName) {
          if (
            this.param[n.i].equipName[i1].i === n.i &&
            this.param[n.i].equipName[i1].r === n.r
          ) {
            this.$delete(this.param[n.i].equipValue[i1].v, "v");
            // 将数组赋值给设备编码
            this.$set(this.param[n.i].equipValue[i1].v, "v", val.join(","));
            this.$delete(this.param[n.i].equipName[i1].v, "v");
            // 将数组赋值给设备编码
            this.$set(this.param[n.i].equipName[i1].v, "v", val);
            this.tableList[0].arr.forEach((item, index) => {
              item.forEach((m) => {
                if (m.i == n.i && m.v.ps && m.v.ps.value == "设备编码") {
                  this.$set(m.v, "v", val.join(","));
                }
                if (m.i == n.i && m.v.ps && m.v.ps.value == "设备名称") {
                  this.$set(m.v, "v", val);
                }
              });
            });
          }
        }
        // 保存数据
        this.saveInsContext(n.i);
      } catch (e) {
        console.log("changeEquip----", e);
      }
      });
      // 选择、移除、清空均由 change 事件触发,立即保存。
      this.saveInsContext();
    },
    getAuthorizedPerson() {
      selectUserCondition({ type: 1 }).then((res) => {
@@ -2845,16 +2288,6 @@
      // 初始化后端传参
      this.param = {};
      this.changeType = 0;
      this.currentSample.insProduct.forEach((a, j) => {
        this.param[a.id] = {
          insValue: [],
          comValue: [],
          resValue: null,
          equipValue: [],
          equipName: [],
          insResult: null,
        };
      });
      // 页面数据处理
      this.getTableLists();
      // 更新到多线程
src/workers/InspectionWorker.worker.js
@@ -26,6 +26,8 @@
let param = null;
// 当前的模板
let currentTable = "";
// 当前模板的结构签名(行列坐标+占位符),用于判断模板内容是否被改过
let currentTemplateSig = "";
// 优化数采较多数据时-记录最后一个检验项的id
let getDataTypeId = null;
//当前检验项
@@ -33,15 +35,51 @@
// 当前这次输入对应的原始检验项。计算过程中 pId 会切换到下游计算项,
// 保存时必须同时带回原始检验项,否则只会保存计算结果。
let sourceInsItemId = null;
/**
 * 生成模板结构签名
 * 只包含行列坐标与占位符,不含值,所以用户填值不会触发签名变化
 *
 * @param list 主线程传过来的表格数据
 * @returns 结构签名字符串
 */
function buildTemplateSig(list) {
  if (!list || !list.length) {
    return "";
  }
  return list
    .map((table) => {
      const tpl = table && table.template;
      if (!tpl || !tpl.length) {
        return `${table && table.templateId}:0`;
      }
      const cells = tpl
        .map((cell) => {
          const ps = cell.v && cell.v.ps ? cell.v.ps.value : "";
          return `${cell.r}-${cell.c}-${ps}`;
        })
        .join("|");
      return `${table.templateId}:${tpl.length}:${cells}`;
    })
    .join(";");
}
// 接收到主线程处理逻辑的消息
self.onmessage = function (event) {
  // 保存主线程传过来的值
  const data = JSON.parse(event.data);
  if (currentTable != data.currentTable) {
    // 检验模板改变后需要刷新表格
  // 模板内容变了(不只是模板id变了)也要刷新表格,否则改完模版后 Worker 仍用旧模板计算并把旧版式回写页面
  const nextTemplateSig = buildTemplateSig(data.tableList);
  if (
    currentTable != data.currentTable ||
    (nextTemplateSig && nextTemplateSig != currentTemplateSig)
  ) {
    tableList = data.tableList;
  }
  currentTable = data.currentTable;
  if (nextTemplateSig) {
    currentTemplateSig = nextTemplateSig;
  }
  if (data.type && data.type == "saveData") {
    // 更新表格数据和传递到后端的参数
    tableList = data.tableList;
@@ -85,10 +123,9 @@
    tableList = data.tableList;
  }
  if (param) {
    // 如果传递到后端的参数存在,则更新当前修改检验项的传递到后端的参数
    // 参数按“模板id + 单元格坐标”存,模板id即 code 的第一段
    let str = code.split("-");
    let pId = str[3];
    param[pId] = data.param[pId];
    param[str[0]] = data.param[str[0]];
  } else {
    // 初始化传递到后端的参数
    param = data.param;
@@ -105,12 +142,64 @@
  changeInput("", code);
};
/**
 * 判断公式是否为数值公式(含算术运算或 Excel 函数)
 * 这类公式必须走数值计算分支,否则只会把算式当文本原样显示
 *
 * @param f 公式字符串
 * @returns 是否按数值计算
 */
function isNumericFormula(f) {
  if (typeof f !== "string") {
    return false;
  }
  // 去掉双引号内的文本,避免把 "A-B" 这类文本字面量误判为算术
  const probe = f.replace(/"[^"]*"/g, "");
  // 只认支持的算术运算符和 Excel 函数,括号单独出现不视为数值公式,
  // 以免 IF 等不支持的函数被误判
  if (
    /[+\-*/^%]/.test(probe) ||
    /SUM|MAX|MIN|AVERAGE|ABS|MEDIAN/.test(probe)
  ) {
    return true;
  }
  // 纯单元格引用也是数值公式。模版里"最终值"常写成 =F4 这种形式,
  // 不认的话会掉进文本分支,把最终值变成带空格的字符串
  return /^[A-Za-z]{1,3}\d{1,7}$/.test(f.replace(/[=\s]/g, ""));
}
/**
 * 按检验项id取当前样品下的检验项信息,取不到时返回空对象,避免公式计算因缺项中断
 *
 * @param id 检验项id
 * @returns 检验项信息
 */
function findInsItem(id) {
  if (!currentSample || !currentSample.insProduct) {
    return {};
  }
  return currentSample.insProduct.find((m) => m.id == id) || {};
}
/**
 * 判断计算结果是否可以写回单元格
 *
 * @param r 计算结果
 * @returns 结果有效返回 true
 */
function isValidComputedResult(r) {
  if (r === "" || r === null || r === undefined) {
    return false;
  }
  return !(typeof r === "number" && isNaN(r));
}
function changeInput(m, code) {
  let str = code.split("-");
  let r = str[1]; //当前行
  let c = str[2]; //当前列
  let id = str[0];
  let pId = str[3]; //当前检验项id,param[pId]为当前检验项的所有值,包含:过程值insValue、计算值comValue、设备编码equipValue、设备名称equipName、最终值resValue、结论insResult
  let pId = str[3]; //当前检验项id,用于计算完成后把结果写回该检验项所在行
  var list = []; //一个双层数组,里面保存有当前页面渲染的所有数据
  // 赋值当前模板的表格数据
  for (let a in tableList) {
@@ -157,7 +246,8 @@
                list2.push(c.v.v);
                // 组装参数的对象集合并赋值,列如{A3:12,B4:15}
                if (
                  getInspectionValueType(item.i) == 1 &&
                  (getInspectionValueType(item.i) == 1 ||
                    isNumericFormula(item.v.f)) &&
                  !isNaN(parseFloat(c.v.v))
                ) {
                  // 如果是数字输入框
@@ -177,362 +267,26 @@
          }
        });
      });
      // 如果此excel方法是结论判断方法,则执行此方法
      // console.log('item.v.ps.value---', item.v.ps.value)
      if (item.v.ps != undefined && item.v.ps.value == "结论") {
        try {
          if (currentSample.insProduct.find((m) => m.id == item.i)) {
            // 如果当前检验项是产品检验项,则执行此方法,找到此检验项的要求值
            let ask = currentSample.insProduct.find((m) => m.id == item.i).ask
              ? currentSample.insProduct
                  .find((m) => m.id == item.i)
                  .ask.split("&")
              : null;
            // 获取当前结论的参数,也就是当前检验项的最终值
            let res = Object.values(comValue)[0];
            if (typeof res == "string" && res.includes(">")) {
              res = res.replace(">", "");
            }
            if (typeof res == "string" && res.includes("≤")) {
              res = res.replace("≤", "");
            }
            if (typeof res == "string" && res.includes("≥")) {
              res = res.replace("≥", "");
            }
            if (typeof res == "string" && res.includes("<")) {
              res = res.replace("<", "");
            }
            if (typeof res == "string" && res.includes(">")) {
              res = res.replace(">", "");
            }
            if (typeof res == "string" && res.includes("<")) {
              res = res.replace("<", "");
            }
            if (
              typeof res == "string" &&
              (res === "断裂" || res === "脆化" || res === "断裂脆化")
            ) {
              item.v.v = 0;
              list.forEach((a) => {
                if (a[0].r == item.r) {
                  for (let b = 0; b < a.length; b++) {
                    if (a[b].c == item.c) {
                      a[b].v.v = 0;
                      break;
                    }
                  }
                }
              });
            }
            let comp = [];
            // 判断当前结论的参数(当前检验项的最终值)是否为空,如果为空,则直接赋值
            if (
              res === "" ||
              res === null ||
              res === undefined ||
              res === "Infinity"
            ) {
              item.v.v = null;
              list.forEach((a) => {
                if (a[0].r == item.r) {
                  for (let b = 0; b < a.length; b++) {
                    if (a[b].c == item.c) {
                      a[b].v.v = null;
                      break;
                    }
                  }
                }
              });
            } else {
              // 如果不为空,则判断当前结论就需要进行判断
              //要求值为-,/,—,则结论设置为不判定,结论赋值为3
              if (
                ask == null ||
                ask[0] == "-" ||
                ask[0] == "/" ||
                ask[0] == "—"
              ) {
                item.v.v = 3;
                list.forEach((a) => {
                  if (a[0].r == item.r) {
                    for (let b = 0; b < a.length; b++) {
                      if (a[b].c == item.c) {
                        a[b].v.v = 3;
                        break;
                      }
                    }
                  }
                });
              } else {
                // 要求值不为-,/,—,则进行判断
                if (ask) {
                  // 循环要求值列表,判断当前结论的参数是否符合要求
                  comp = ask.map((m, i) => {
                    // 如果要求值包含=,则判断当前结论的参数是否等于要求值,
                    // 以下判断基本一致,只是判断类型不一样,就不做注释了
                    if (m.includes("=")) {
                      // 处理要求值
                      let str = handleFraction(m.split("=")[1]);
                      if (typeof res == "string" && typeof str == "string") {
                        // 如果要求值和当前结论的参数都是字符串,则执行
                        if (res.includes("/")) {
                          // 如果结论的参数是分数,则判断
                          if (m.includes("/")) {
                            // 如果要求值是分数,则判断
                            return eval(res) == eval(str);
                          } else {
                            // 如果要求值不是分数,则判断
                            return handleMoreParam(res, m.split("=")[1], "=");
                          }
                        } else {
                          // 如果结论的参数不是分数,则判断
                          return (
                            res.trim().replace(/[.,。、;:'";??“,]/g, "") ==
                            str.trim().replace(/[.,。、;:'";??“,]/g, "")
                          );
                        }
                      } else {
                        // 如果要求值和当前结论的参数有一个是数字,则执行
                        return eval(res) == eval(str);
                      }
                    } else if (m.includes("≥")) {
                      if (typeof res == "string" && res.includes("/")) {
                        if (m.includes("/")) {
                          let str = handleFraction(m.split("≥")[1]);
                          return eval(res) >= eval(str);
                        } else {
                          return handleMoreParam(res, m.split("≥")[1], "≥");
                        }
                      } else {
                        let str = handleFraction(m.split("≥")[1]);
                        return eval(res) >= eval(str);
                      }
                    } else if (m.includes("≤")) {
                      if (typeof res == "string" && res.includes("/")) {
                        if (m.includes("/")) {
                          let str = handleFraction(m.split("≤")[1]);
                          return eval(res) <= eval(str);
                        } else {
                          return handleMoreParam(res, m.split("≤")[1], "≤");
                        }
                      } else {
                        let str = handleFraction(m.split("≤")[1]);
                        if (typeof str == "string" && str.includes("A")) {
                          str = str.replace("A", "");
                        }
                        if (typeof str == "string" && str.includes("D")) {
                          str = str.replace("D", "");
                        }
                        if (typeof res == "string" && res.includes("A")) {
                          res = res.replace("A", "");
                        }
                        if (typeof res == "string" && res.includes("D")) {
                          res = res.replace("D", "");
                        }
                        return eval(res) <= eval(str);
                      }
                    } else if (m.includes("<")) {
                      if (typeof res == "string" && res.includes("/")) {
                        if (m.includes("/")) {
                          let str = handleFraction(m.split("<")[1]);
                          return eval(res) < eval(str);
                        } else {
                          return handleMoreParam(res, m.split("<")[1], "<");
                        }
                      } else {
                        let str = handleFraction(m.split("<")[1]);
                        return eval(res) < eval(str);
                      }
                    } else if (m.includes(">")) {
                      if (typeof res == "string" && res.includes("/")) {
                        if (m.includes("/")) {
                          let str = handleFraction(m.split(">")[1]);
                          return eval(res) > eval(str);
                        } else {
                          return handleMoreParam(res, m.split(">")[1], ">");
                        }
                      } else {
                        let str = handleFraction(m.split(">")[1]);
                        return eval(res) > eval(str);
                      }
                    } else if (m.includes("~")) {
                      if (typeof res == "string" && res.includes("/")) {
                        if (m.includes("/")) {
                          let k = m.split("~");
                          return (
                            eval(res) >= eval(handleFraction(k[0])) &&
                            eval(res) <= eval(handleFraction(k[1]))
                          );
                        } else {
                          return handleMoreParam(res, m, "~");
                        }
                      } else {
                        let k = m.split("~");
                        return (
                          eval(res) >= eval(handleFraction(k[0])) &&
                          eval(res) <= eval(handleFraction(k[1]))
                        );
                      }
                    } else if (m.includes("-")) {
                      if (typeof res == "string" && res.includes("/")) {
                        if (m.includes("/")) {
                          let k = m.split("-");
                          return (
                            eval(res) >= eval(handleFraction(k[0])) &&
                            eval(res) <= eval(handleFraction(k[1]))
                          );
                        } else {
                          return handleMoreParam(res, m, "-");
                        }
                      } else {
                        let k = m.split("-");
                        return (
                          eval(res) >= eval(handleFraction(k[0])) &&
                          eval(res) <= eval(handleFraction(k[1]))
                        );
                      }
                    } else if (m.includes("±")) {
                      if (modelType.includes("φ-")) {
                        if (m.indexOf("±") == 0) {
                          m =
                            modelType.substring(modelType.indexOf("-") + 1) + m;
                        }
                      }
                      if (typeof res == "string" && res.includes("/")) {
                        if (m.includes("/")) {
                          let k = m.split("±");
                          return (
                            eval(res) >=
                              eval(
                                handleFraction(k[0]) - handleFraction(k[1])
                              ) &&
                            eval(res) <=
                              eval(
                                Number(handleFraction(k[0])) +
                                  Number(handleFraction(k[1]))
                              )
                          );
                        } else {
                          return handleMoreParam(res, m, "±");
                        }
                      } else {
                        let k = m.split("±");
                        return (
                          eval(res) >=
                            eval(handleFraction(k[0]) - handleFraction(k[1])) &&
                          eval(res) <=
                            eval(
                              Number(handleFraction(k[0])) +
                                Number(handleFraction(k[1]))
                            )
                        );
                      }
                    } else if (m.includes(">")) {
                      if (typeof res == "string" && res.includes("/")) {
                        if (m.includes("/")) {
                          let str = handleFraction(m.split(">")[1]);
                          return eval(res) > eval(str);
                        } else {
                          return handleMoreParam(res, m.split(">")[1], ">");
                        }
                      } else {
                        let str = handleFraction(m.split(">")[1]);
                        return eval(res) > eval(str);
                      }
                    } else if (m.includes("<")) {
                      if (typeof res == "string" && res.includes("/")) {
                        if (m.includes("/")) {
                          let str = handleFraction(m.split("<")[1]);
                          return eval(res) < eval(str);
                        } else {
                          return handleMoreParam(res, m.split("<")[1], "<");
                        }
                      } else {
                        let str = handleFraction(m.split("<")[1]);
                        return eval(res) < eval(str);
                      }
                    }
                  });
                }
                // 如果要求值的每个条件都符合,则给结论赋值为1,合格
                if (comp.every((m) => m)) {
                  item.v.v = 1;
                  list.forEach((a) => {
                    if (a[0].r == item.r) {
                      for (let b = 0; b < a.length; b++) {
                        if (a[b].c == item.c) {
                          a[b].v.v = 1;
                          break;
                        }
                      }
                    }
                  });
                } else {
                  // 否则给结论赋值为0,不合格
                  item.v.v = 0;
                  list.forEach((a) => {
                    if (a[0].r == item.r) {
                      for (let b = 0; b < a.length; b++) {
                        if (a[b].c == item.c) {
                          a[b].v.v = 0;
                          break;
                        }
                      }
                    }
                  });
                }
              }
            }
            let getDataType0 = false;
            // 优化数采较多数据时-记录最后一个检验项的id,如果当前检验项的id与记录的id相同,则多传一个参数到主线程,进行数据保存,否则数采就不进行保存
            if (item.i == getDataTypeId) {
              getDataType0 = true;
            }
            // 赋值传递到主线程的数据,method:saveInsContext表示此消息需要保存数据
            currentInsItemId = item.i;
            // 赋值传递到主线程的数据,method:saveInsContext表示此消息需要保存数据
            result = {
              method: "saveInsContext",
              value: {
                tableList, // 表格数据
                param: getParam(), //传给后端的参数
                getDataTypeId: getDataTypeId,
                currentInsItemId: item.i,
                sourceInsItemId: sourceInsItemId,
              },
            };
            // 发消息给主线程
            self.postMessage(JSON.stringify(result));
          }
        } catch (error) {
          console.log("error---", error);
        }
      } else {
        // 如果是函数方法,则执行此方法
        let comResult = ""; //初始化计算结果
        try {
          if (getInspectionValueType(item.i) == 1) {
            // 如果检验值类型是数字输入框
            let tell = currentSample.insProduct.find((m) => m.id == item.i).tell
              ? currentSample.insProduct
                  .find((m) => m.id == item.i)
                  .tell.split("&")
              : null;
          if (
            getInspectionValueType(item.i) == 1 ||
            isNumericFormula(item.v.f)
          ) {
            // 如果检验值类型是数字输入框,或公式本身含算术运算/Excel函数
            const itemInfo = findInsItem(item.i);
            let tell =
              typeof itemInfo.tell == "string" ? itemInfo.tell.split("&") : null;
            isPoint =
              tell &&
              tell.length > 0 &&
              typeof tell[0] == "string" &&
              tell[0].includes("/") &&
              tell[0] !== "/"; // 判断要求值是否为分数
            const inspectionItemClass = currentSample.insProduct.find(
              (m) => m.id == item.i
            ).inspectionItemClass; // 检验项分类
            const inspectionItem = currentSample.insProduct.find(
              (m) => m.id == item.i
            ).inspectionItem; // 检验项
            const inspectionItemSubclass = currentSample.insProduct.find(
              (m) => m.id == item.i
            ).inspectionItemSubclass; // 检验子项
            const inspectionItemClass = itemInfo.inspectionItemClass; // 检验项分类
            const inspectionItem = itemInfo.inspectionItem; // 检验项
            const inspectionItemSubclass = itemInfo.inspectionItemSubclass; // 检验子项
            let isHaveSymbol = false;
            let symbol = "";
            for (var a in comValue) {
@@ -585,7 +339,12 @@
            ) {
              comResult = comResult + "";
            }
            if (inspectionItem === "邵氏硬度" && tell[0].includes("A")) {
            if (
              inspectionItem === "邵氏硬度" &&
              tell &&
              tell[0] &&
              tell[0].includes("A")
            ) {
              // 要求值如果有包含字母,最终结果要展示出字母
              comResult = comResult + "A";
            }
@@ -593,6 +352,8 @@
              inspectionItemClass === "绝缘机械物理性能" &&
              inspectionItem === "弯曲性能" &&
              inspectionItemSubclass === "最小弯曲半径" &&
              tell &&
              tell[0] &&
              tell[0].includes("D")
            ) {
              // 要求值如果有包含字母,最终结果要展示出字母
@@ -644,7 +405,7 @@
        try {
          // 循环表格数据,给表格数据进行赋值
          list.forEach((a) => {
            if (a[0].r == item.r && comResult !== "") {
            if (a[0].r == item.r && isValidComputedResult(comResult)) {
              // 判断当前行是否为当前检验项所在行,如果为当前行,则给表格数据赋值
              for (var b in a) {
                if (a[b].c == item.c) {
@@ -672,9 +433,7 @@
                      // 判断计算结果是否为科学计数法,如果为科学计数法,则给表格数据赋值为科学计数法
                      a[b].v.v = comResult;
                    } else {
                      const inspectionItem = currentSample.insProduct.find(
                        (m) => m.id == item.i
                      ).inspectionItem;
                      const inspectionItem = findInsItem(item.i).inspectionItem;
                      // 判断计算结果是否为数字,如果为数字,则给表格数据赋值为数字
                      if (inspectionItem == "铜线电阻率ρ20最大值") {
                        let val = parseFloat(Number(comResult).toFixed(5));
@@ -695,11 +454,13 @@
            }
          });
          // 如果此计算结果所属单元格,同时也是另一个excel函数的参数,那么就需要递归进行计算
          // 只有算出有效结果才继续向下游公式传递,避免把空值/NaN 传染给其它单元格
          if (isValidComputedResult(comResult)) {
          changeInput(comResult, `${id}-${item.r}-${item.c}-${pId}`); //改变最终值
          }
          currentInsItemId = item.i;
        } catch (error) {
          console.log("error---", error);
        }
      }
    }
  });
@@ -726,17 +487,6 @@
  };
  // 发送主线程数据
  self.postMessage(JSON.stringify(result));
  try {
    // 赋值多线程传输数据
    result = {
      method: "getCurrentInsProduct",
      value: pId,
    };
    // 发送主线程数据
    self.postMessage(JSON.stringify(result));
  } catch (error) {
    console.log("error---", error);
  }
}
/**
 * 获取检测值类型
@@ -835,68 +585,33 @@
 * @returns 返回处理后的参数对象
 */
function getParam() {
  tableList[0].arr.forEach((a) => {
  // 按“模板id + 单元格坐标(r-c)”从当前模板快照出待保存参数
  const resultParam = {};
  tableList.forEach((t) => {
    resultParam[t.templateId] = {};
    (t.arr || []).forEach((a) => {
    a.forEach((b) => {
      // 初始化传递到后端的参数
      if (param[b.i]) {
        param[b.i].insValue = [];
        param[b.i].comValue = [];
        param[b.i].equipValue = [];
        param[b.i].equipName = [];
        param[b.i].resValue = null;
        param[b.i].insResult = null;
      }
    });
  });
  tableList[0].arr.forEach((a) => {
    a.forEach((b) => {
      // 根据表格数据,赋值传递到后端的参数
      if (
        const isEditable =
        b.v.ps != undefined &&
        typeof b.v.ps.value == "string" &&
        b.v.ps.value.includes("检验值")
          (b.v.ps.value.includes("检验值") ||
            b.v.ps.value === "计算值" ||
            b.v.ps.value === "最终值" ||
            b.v.ps.value === "设备名称");
        if (!isEditable) {
          return;
        }
        if (
          b.v.ps.value.includes("检验值") &&
          (b.v.v === "" || b.v.v === null || b.v.v === undefined)
      ) {
        // 赋值检验值
        b.i &&
          b.v.v !== "" &&
          b.v.v !== null &&
          b.v.v !== undefined &&
          param[b.i].insValue.push(b);
          return;
      }
      if (b.v.ps != undefined && b.v.ps.value === "计算值") {
        // 赋值计算值
        b.i &&
          b.v.v &&
          b.valueList &&
          b.valueList.length > 0 &&
          param[b.i].comValue.push(b);
      }
      if (b.v.ps != undefined && b.v.ps.value === "设备编码") {
        // 赋值设备编码
        b.i && b.v && param[b.i].equipValue.push(b);
      }
      if (b.v.ps != undefined && b.v.ps.value === "设备名称") {
        // 赋值设备名称
        b.i && b.v && param[b.i].equipName.push(b);
      }
      if (b.v.ps != undefined && b.v.ps.value === "最终值") {
        // 赋值最终值
        b.i &&
          b.v &&
          b.valueList &&
          b.valueList.length > 0 &&
          (param[b.i].resValue = b);
      }
      if (b.v.ps != undefined && b.v.ps.value === "结论") {
        if (b.i && (b.v.v || b.v.v === 0 || b.v.v === "0")) {
          if (b.v.v != "合格" && b.v.v != "不合格") {
            // 赋值结论
            param[b.i].insResult = b;
          }
        }
      }
        resultParam[t.templateId][`${b.r}-${b.c}`] = { v: b.v.v, u: b.u };
    });
  });
  });
  param = resultParam;
  return param;
}
@@ -1191,6 +906,7 @@
 */
function getIdFromColumnName(id, arr) {
  try {
    id = String(id).replace(/\$/g, "");
    // Get the letters
    var t = /^[a-zA-Z]+/.exec(id);
    if (t) {
@@ -1271,6 +987,9 @@
 */
function getABCList(f) {
  try {
    if (typeof f !== "string") {
      return [];
    }
    let regex = /[=\+\-\*\%\(\)\/\^\s]/g;
    // 上面计算函数新增后,这里也要同步增加
    let fouList = [
@@ -1284,8 +1003,12 @@
      "IF",
      "LOG",
    ];
    // 替换特殊字符
    // 替换特殊字符,去掉 Excel 绝对引用符号($D$14 与 D14 等价)
    f = f
      .replace(/\$/g, "")
      // 区间写法里的空格(AVERAGE( D14 : D15 ))会被下面的空白替换吃掉冒号,
      // 导致区间被拆成两个独立单元格,先把区间规整成 D14:D15
      .replace(/\s*:\s*/g, ":")
      .replace(regex, ",")
      .replace(new RegExp('"&', "g"), "")
      .replace(new RegExp('&"', "g"), "");
@@ -1322,6 +1045,22 @@
}
/**
 * 把单元格值转成可参与 eval 的字面量,空白单元格按 0 处理(与 Excel 一致)
 *
 * @param value 单元格的值
 * @returns 数值/原始值,空值返回 0
 */
function toNumberLiteral(value) {
  if (value === null || value === undefined) {
    return 0;
  }
  if (typeof value === "string" && value.trim() === "") {
    return 0;
  }
  return value;
}
/**
 * 计算函数
 *
 * @param f 字符串类型,表示待计算的公式
@@ -1330,7 +1069,9 @@
 */
function compute(f, comValue, isPoint) {
  try {
    let str = f;
    // 去掉 Excel 绝对引用符号,$D$14 与 D14 等价;
    // 区间里的空格也要一并去掉,否则下面把 ":" 换成 "-" 后 D14-D15 会因空格匹配不上而展开失败
    let str = f.replace(/\$/g, "").replace(/\s*:\s*/g, ":");
    // 获取单元格对应值
    let arr = getAllCell(f);
    for (var a in comValue) {
@@ -1397,9 +1138,18 @@
    for (var a in obj) {
      str = str.replace(new RegExp(a, "g"), obj[a]);
    }
    // 计算
    for (var a in arr) {
      str = str.replace(new RegExp(a, "g"), arr[a]);
    // 计算:一次性替换所有参数,避免 D1 与 D14 这类前缀互相污染;
    // 空白单元格按 0 处理,避免把 null/undefined 带进表达式导致整条公式算不出来
    const cellKeys = Object.keys(arr);
    if (cellKeys.length > 0) {
      const pattern = new RegExp(
        cellKeys
          .sort((x, y) => y.length - x.length)
          .map((k) => k.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"))
          .join("|"),
        "g"
      );
      str = str.replace(pattern, (m) => String(toNumberLiteral(arr[m])));
    }
    if (str.includes(",,")) {
      str = str.replace(new RegExp(",,", "g"), ",");
@@ -1421,8 +1171,9 @@
      return str
        .replace(new RegExp('&"/"&', "g"), "/")
        .replace(new RegExp("//", "g"), "");
    } else if (isPoint) {
      // 计算带小数点的
    } else if (isPoint && !/SUM|MAX|MIN|AVERAGE|ABS|MEDIAN/.test(str)) {
      // 分数形式的输入(如 3/4)按原文返回展示;
      // 但含 Excel 函数名的公式不能走这里,否则会把 "AVERAGE(...)" 这种算式文本当成结果写回单元格
      return str.replace("ABS", "").replace(/\(|\)/g, "");
    } else {
      if (str.includes("IF")) {
@@ -1449,7 +1200,12 @@
        }
      }
      // 计算常规的
      return eval(str);
      const value = eval(str);
      // 除零等非有限结果不写回单元格(与 Excel 的 #DIV/0! 一致:不出值)
      if (typeof value === "number" && !isFinite(value)) {
        return undefined;
      }
      return value;
    }
  } catch (error) {
    console.log("error", error);
vue.config.js
@@ -106,6 +106,13 @@
    config.plugins.delete("preload"); // TODO: need test
    config.plugins.delete("prefetch"); // TODO: need test
    // 让改 src/workers/*.worker.js 也能触发 dev server 重建。
    // *.worker.js 已由 worker-loader 处理,但 vue-cli 内置的 js 规则(/\\.m?jsx?$/,
    // 含 cache-loader + babel-loader)同样会命中它。cache-loader 会缓存 worker 模块的
    // 产物,worker 源文件改动后即使模块被判失效并重建,cache-loader 仍直接返回旧缓存,
    // 于是 dev server 一直发旧包(改了 worker 不生效)。把它排除掉即可。
    config.module.rule("js").exclude.add(/\.worker\.js$/);
    // set svg-sprite-loader
    config.module.rule("svg").exclude.add(resolve("src/assets/icons")).end();
    config.module