| | |
| | | let param = null; |
| | | // 当前的模板 |
| | | let currentTable = ""; |
| | | // 当前模板的结构签名(行列坐标+占位符),用于判断模板内容是否被改过 |
| | | let currentTemplateSig = ""; |
| | | // 优化数采较多数据时-记录最后一个检验项的id |
| | | let getDataTypeId = null; |
| | | //当前检验项 |
| | |
| | | // 当前这次输入对应的原始检验项。计算过程中 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; |
| | |
| | | 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; |
| | |
| | | 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) { |
| | |
| | | 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)) |
| | | ) { |
| | | // 如果是数字输入框 |
| | |
| | | } |
| | | }); |
| | | }); |
| | | // 如果此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) { |
| | |
| | | ) { |
| | | comResult = comResult + ""; |
| | | } |
| | | if (inspectionItem === "邵氏硬度" && tell[0].includes("A")) { |
| | | if ( |
| | | inspectionItem === "邵氏硬度" && |
| | | tell && |
| | | tell[0] && |
| | | tell[0].includes("A") |
| | | ) { |
| | | // 要求值如果有包含字母,最终结果要展示出字母 |
| | | comResult = comResult + "A"; |
| | | } |
| | |
| | | inspectionItemClass === "绝缘机械物理性能" && |
| | | inspectionItem === "弯曲性能" && |
| | | inspectionItemSubclass === "最小弯曲半径" && |
| | | tell && |
| | | tell[0] && |
| | | tell[0].includes("D") |
| | | ) { |
| | | // 要求值如果有包含字母,最终结果要展示出字母 |
| | |
| | | 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) { |
| | |
| | | // 判断计算结果是否为科学计数法,如果为科学计数法,则给表格数据赋值为科学计数法 |
| | | 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)); |
| | |
| | | } |
| | | }); |
| | | // 如果此计算结果所属单元格,同时也是另一个excel函数的参数,那么就需要递归进行计算 |
| | | // 只有算出有效结果才继续向下游公式传递,避免把空值/NaN 传染给其它单元格 |
| | | if (isValidComputedResult(comResult)) { |
| | | changeInput(comResult, `${id}-${item.r}-${item.c}-${pId}`); //改变最终值 |
| | | } |
| | | currentInsItemId = item.i; |
| | | } catch (error) { |
| | | console.log("error---", error); |
| | | } |
| | | } |
| | | } |
| | | }); |
| | |
| | | }; |
| | | // 发送主线程数据 |
| | | self.postMessage(JSON.stringify(result)); |
| | | try { |
| | | // 赋值多线程传输数据 |
| | | result = { |
| | | method: "getCurrentInsProduct", |
| | | value: pId, |
| | | }; |
| | | // 发送主线程数据 |
| | | self.postMessage(JSON.stringify(result)); |
| | | } catch (error) { |
| | | console.log("error---", error); |
| | | } |
| | | } |
| | | /** |
| | | * 获取检测值类型 |
| | |
| | | * @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; |
| | | } |
| | | |
| | |
| | | */ |
| | | function getIdFromColumnName(id, arr) { |
| | | try { |
| | | id = String(id).replace(/\$/g, ""); |
| | | // Get the letters |
| | | var t = /^[a-zA-Z]+/.exec(id); |
| | | if (t) { |
| | |
| | | */ |
| | | function getABCList(f) { |
| | | try { |
| | | if (typeof f !== "string") { |
| | | return []; |
| | | } |
| | | let regex = /[=\+\-\*\%\(\)\/\^\s]/g; |
| | | // 上面计算函数新增后,这里也要同步增加 |
| | | let fouList = [ |
| | |
| | | "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"), ""); |
| | |
| | | } |
| | | |
| | | /** |
| | | * 把单元格值转成可参与 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 字符串类型,表示待计算的公式 |
| | |
| | | */ |
| | | 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) { |
| | |
| | | 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"), ","); |
| | |
| | | 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")) { |
| | |
| | | } |
| | | } |
| | | // 计算常规的 |
| | | 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); |