liding
3 天以前 8f06fbf30772f2dd23a0ca7957d0f6d3db92c0e9
src/workers/InspectionWorker.worker.js
@@ -35,6 +35,11 @@
// 当前这次输入对应的原始检验项。计算过程中 pId 会切换到下游计算项,
// 保存时必须同时带回原始检验项,否则只会保存计算结果。
let sourceInsItemId = null;
// 当前消息版本。Worker 单线程串行处理消息,供递归公式计算完成后回传给主线程。
let currentRevision = null;
// 本次输入是否往单元格写入过计算结果。链式公式只有最外层会回传保存,
// 用它在最外层判断计算的中间值是否也需要落库。
let hasComputedWrite = false;
/**
 * 生成模板结构签名
@@ -68,6 +73,7 @@
self.onmessage = function (event) {
  // 保存主线程传过来的值
  const data = JSON.parse(event.data);
  currentRevision = data.revision;
  // 模板内容变了(不只是模板id变了)也要刷新表格,否则改完模版后 Worker 仍用旧模板计算并把旧版式回写页面
  const nextTemplateSig = buildTemplateSig(data.tableList);
  if (
@@ -138,7 +144,8 @@
  comparisonList = JSON.parse(JSON.stringify(data.comparisonList));
  currentSample = JSON.parse(JSON.stringify(data.currentSample));
  PROJECT = data.PROJECT;
  // 执行计算方法
  // 执行计算方法。每次输入重置标记,由本次调用栈的最外层决定是否回传保存
  hasComputedWrite = false;
  changeInput("", code);
};
@@ -169,6 +176,18 @@
}
/**
 * 获取纯单元格引用公式的坐标名,例如 =F4、=$F$4。
 * 纯引用应直接复制原值,避免把“外观”等中文文本送入数值计算。
 */
function getDirectReferenceName(f) {
  if (typeof f !== "string") {
    return null;
  }
  const matched = f.trim().match(/^=\s*\$?([A-Za-z]{1,3})\$?(\d{1,7})\s*$/);
  return matched ? `${matched[1].toUpperCase()}${matched[2]}` : null;
}
/**
 * 按检验项id取当前样品下的检验项信息,取不到时返回空对象,避免公式计算因缺项中断
 *
 * @param id 检验项id
@@ -194,7 +213,7 @@
  return !(typeof r === "number" && isNaN(r));
}
function changeInput(m, code) {
function changeInput(m, code, isComputed) {
  let str = code.split("-");
  let r = str[1]; //当前行
  let c = str[2]; //当前列
@@ -270,7 +289,11 @@
        // 如果是函数方法,则执行此方法
        let comResult = ""; //初始化计算结果
        try {
          if (
          const directReferenceName = getDirectReferenceName(item.v.f);
          if (directReferenceName && Object.prototype.hasOwnProperty.call(comValue, directReferenceName)) {
            // =F4 这类公式既可能引用数字,也可能引用中文文本,直接保留源值。
            comResult = comValue[directReferenceName];
          } else if (
            getInspectionValueType(item.i) == 1 ||
            isNumericFormula(item.v.f)
          ) {
@@ -448,6 +471,7 @@
                    a[b].v.v = comResult;
                    console.log("error---", error);
                  }
                  hasComputedWrite = true;
                  break;
                }
              }
@@ -456,7 +480,9 @@
          // 如果此计算结果所属单元格,同时也是另一个excel函数的参数,那么就需要递归进行计算
          // 只有算出有效结果才继续向下游公式传递,避免把空值/NaN 传染给其它单元格
          if (isValidComputedResult(comResult)) {
            changeInput(comResult, `${id}-${item.r}-${item.c}-${pId}`); //改变最终值
            // 标记为计算层:它可能是下游公式的参数(isSave 会被置成 false),但自身也是结果,
            // 保存交给最外层统一回传,中间值不会被漏掉,也不会每一级都发一次保存请求
            changeInput(comResult, `${id}-${item.r}-${item.c}-${pId}`, true); //改变最终值
          }
          currentInsItemId = item.i;
        } catch (error) {
@@ -464,10 +490,14 @@
        }
    }
  });
  if (index === -1 || (inputType === undefined && isSave === "true")) {
  if (
    !isComputed &&
    (hasComputedWrite || index === -1 || (inputType === undefined && isSave === "true"))
  ) {
    // 赋值传递到主线程的数据,method:saveInsContext表示此消息需要保存数据
    result = {
      method: "saveInsContext",
      revision: currentRevision,
      value: {
        tableList, // 表格数据
        param: getParam(), //传给后端的参数
@@ -483,6 +513,7 @@
  // 赋值多线程传输数据
  result = {
    method: "tableList",
    revision: currentRevision,
    value: tableList,
  };
  // 发送主线程数据
@@ -589,6 +620,13 @@
  const resultParam = {};
  tableList.forEach((t) => {
    resultParam[t.templateId] = {};
    const cells = (t.arr || []).reduce((all, row) => all.concat(row), []);
    const resultHeader = cells.find((cell) =>
      cell.v && String(cell.v.v || "").trim() === "检验结果"
    );
    const exportRows = new Set(cells.filter((cell) =>
      cell.v && cell.v.ps && cell.v.ps.value === "导出值"
    ).map((cell) => cell.r));
    (t.arr || []).forEach((a) => {
      a.forEach((b) => {
        const isEditable =
@@ -598,10 +636,12 @@
            b.v.ps.value === "计算值" ||
            b.v.ps.value === "最终值" ||
            b.v.ps.value === "设备名称");
        if (!isEditable) {
        const isExportResult = resultHeader && exportRows.has(b.r) && b.c === resultHeader.c;
        if (!isEditable && !isExportResult) {
          return;
        }
        if (
          isEditable &&
          b.v.ps.value.includes("检验值") &&
          (b.v.v === "" || b.v.v === null || b.v.v === undefined)
        ) {
@@ -1199,6 +1239,12 @@
          return "断裂脆化";
        }
      }
      // 参数代入后含中文时(如检验值填了"均匀"),不能再当公式 eval ——
      // eval("均匀") 会抛 ReferenceError,被外层 catch 吞掉后返回 undefined,
      // 该单元格的结果既不写回也不向下游公式传递,整条计算链断在这里
      if (/[一-龥]/.test(str)) {
        return str.trim();
      }
      // 计算常规的
      const value = eval(str);
      // 除零等非有限结果不写回单元格(与 Excel 的 #DIV/0! 一致:不出值)