Browse Source

feat: 信息价AI填值增加报错断电续填功能

vian 7 months ago
parent
commit
b5f3ecf6ff
1 changed files with 183 additions and 146 deletions
  1. 183 146
      web/maintain/price_info_lib/js/priceEmpty.js

+ 183 - 146
web/maintain/price_info_lib/js/priceEmpty.js

@@ -84,10 +84,14 @@ const EMPTY_BOOK = (() => {
     }
   }
 
+  // ai填值缓存,用于ai填值报错时,可以从当前报错处开始匹配,而不用重头开始匹配
+  let aiMatchCache = null;
+
   // 清空
   function clear() {
     cache.length = 0;
     workBookObj.sheet.setRowCount(0);
+    aiMatchCache = null;
   }
 
   let curRow = 0;
@@ -334,43 +338,69 @@ const EMPTY_BOOK = (() => {
     return code.substring(0, 4);
   }
 
+
+  const getAIMatchData = (summaryGroupMap, noCodeSummary) => {
+    if (aiMatchCache && aiMatchCache.changedCells.length && aiMatchCache.curIndex > 0) {
+      return aiMatchCache;
+    }
+    const curPercent = 0;
+    const curIndex = 0;
+    const totalRows = workBookObj.sheet.getRowCount();
+    const changedCells = [];
+    const noMatchRows = []; // 没有匹配、ai没有命中的行,后续需要自动生成别名编码(最大的别名编码+1)
+    for (let i = 0; i < totalRows; i++) {
+      const rowData = getRowData(workBookObj.sheet, i, setting.header);
+      // const code = rowData.code || '';
+      const code = getFourCode(rowData.code);
+      const toMatchSummary = code ? summaryGroupMap[code] || [] : noCodeSummary;
+      if (toMatchSummary.length) {
+        changedCells.push({ row: i });
+      } else {
+        noMatchRows.push(i);
+      }
+    }
+    return {
+      curPercent,
+      curIndex,
+      changedCells,
+      noMatchRows,
+    }
+  }
+
   // ai填值
   const aiMatch = async () => {
+    let percent = 0;
+    let curIndex = 0;
+    let noMatchRows = [];
+    let changedCells = [];
     try {
       // 获取信息价总表
       const priceInfoSummary = await ajaxPost('/priceInfoSummary/getData', {}, 1000 * 60 * 5);
       const summaryGroupMap = _.groupBy(priceInfoSummary, item => getFourCode(item.code));
       const noCodeSummary = priceInfoSummary.filter(item => !item.code);
-      const totalRows = workBookObj.sheet.getRowCount();
-      const changedCells = [];
-      const noMatchRows = []; // 没有匹配、ai没有命中的行,后续需要自动生成别名编码(最大的别名编码+1)
-      for (let i = 0; i < totalRows; i++) {
-        const rowData = getRowData(workBookObj.sheet, i, setting.header);
-        // const code = rowData.code || '';
-        const code = getFourCode(rowData.code);
-        const toMatchSummary = code ? summaryGroupMap[code] || [] : noCodeSummary;
-        if (toMatchSummary.length) {
-          changedCells.push({ row: i });
-        } else {
-          noMatchRows.push(i);
-        }
-      }
+
+      const aiMatchData = getAIMatchData(summaryGroupMap, noCodeSummary);
+      percent = aiMatchData.curPercent;
+      curIndex = aiMatchData.curIndex;
+      changedCells = aiMatchData.changedCells;
+      noMatchRows = aiMatchData.noMatchRows;
+
       if (!changedCells.length) {
         return;
       }
       const classCodeCol = setting.header.findIndex(h => h.dataCode === 'classCode');
       const expStringCol = setting.header.findIndex(h => h.dataCode === 'expString');
       // const chunks = _.chunk(changedCells, 20);
-      const chunks = _.chunk(changedCells, 1); // 
-      let percent = 0;
+      const chunks = _.chunk(changedCells, 1); // 只能一条一条匹配改成,否则经常ai服务经常挂
       $.bootstrapLoading.progressStart('AI填值', false);
-      $("#progress_modal_body").text('正在进行AI填值,请稍后...');
+      $('#progress_modal_body').text(`正在进行AI填值,请稍后${curIndex + 1}/${chunks.length}...`);
       await setTimeoutSync(500);
       const matchResCache = {};
 
       // 分块进行ai匹配
       const step = 100 / (chunks.length || 1);
-      for (let i = 0; i < chunks.length; i++) {
+      for (let i = curIndex; i < chunks.length; i++) {
+        curIndex = i;
         const chunk = chunks[i];
         const listA = [];
         const listB = [];
@@ -378,7 +408,6 @@ const EMPTY_BOOK = (() => {
         chunk.forEach(item => {
           const rowData = getRowData(workBookObj.sheet, item.row, setting.header);
           listA.push(`${rowData.name || ''} ${rowData.specs}`);
-          // const code = rowData.code || '';
           const code = getFourCode(rowData.code);
           const toMatchSummary = code ? summaryGroupMap[code] || [] : noCodeSummary;
           summaryData.push(toMatchSummary);
@@ -387,7 +416,6 @@ const EMPTY_BOOK = (() => {
         });
         const test = listB.map(item => item.length);
         console.log(test);
-
         const matchRes = matchResCache[listA[0]] ? matchResCache[listA[0]] : await ajaxPost('/priceInfoSummary/aiMatch', { listA, listB }, 1000 * 60 * 5);
         matchResCache[listA[0]] = matchRes;
         // 填匹配值到表格,不实时保存,因为需要人工核查
@@ -430,7 +458,7 @@ const EMPTY_BOOK = (() => {
         workBookObj.sheet.resumeEvent();
         workBookObj.sheet.resumePaint();
         percent += step;
-        $('#progress_modal_body').text(`正在进行AI填值,请稍后${i + 1}/${chunks.length}...`)
+        $('#progress_modal_body').text(`正在进行AI填值,请稍后${i + 1}/${chunks.length}...`);
         $("#progress_modal_bar").css('width', `${percent}%`);
         await setTimeoutSync(100);
       }
@@ -451,139 +479,147 @@ const EMPTY_BOOK = (() => {
       }
       workBookObj.sheet.resumeEvent();
       workBookObj.sheet.resumePaint();
-
-
+      aiMatchCache = null;
+      $("#ai-match").text('AI填值');
     } catch (error) {
       console.log(error);
+      aiMatchCache = {
+        curPercent: percent,
+        curIndex,
+        noMatchRows,
+        changedCells,
+      }
+      $("#ai-match").text('继续AI填值');
       alert(error);
     }
     await setTimeoutSync(500);
     $.bootstrapLoading.progressEnd();
   }
 
-  /*  const aiMatch = async () => {
-     try {
-       // 获取信息价总表
-       const priceInfoSummary = await ajaxPost('/priceInfoSummary/getData', {}, 1000 * 60 * 5);
-       const summaryGroupMap = _.groupBy(priceInfoSummary, item => getFourCode(item.code));
-       const noCodeSummary = priceInfoSummary.filter(item => !item.code);
-       const totalRows = workBookObj.sheet.getRowCount();
-       const changedCells = [];
-       const noMatchRows = []; // 没有匹配、ai没有命中的行,后续需要自动生成别名编码(最大的别名编码+1)
-       for (let i = 0; i < totalRows; i++) {
-         const rowData = getRowData(workBookObj.sheet, i, setting.header);
-         // const code = rowData.code || '';
-         const code = getFourCode(rowData.code);
-         const toMatchSummary = code ? summaryGroupMap[code] || [] : noCodeSummary;
-         if (toMatchSummary.length) {
-           changedCells.push({ row: i });
-         } else {
-           noMatchRows.push(i);
-         }
-       }
-       if (!changedCells.length) {
-         return;
-       }
-       const classCodeCol = setting.header.findIndex(h => h.dataCode === 'classCode');
-       const expStringCol = setting.header.findIndex(h => h.dataCode === 'expString');
-       // const chunks = _.chunk(changedCells, 20);
-       const chunks = _.chunk(changedCells, 1);
-       let percent = 0;
-       $.bootstrapLoading.progressStart('AI填值', false);
-       $("#progress_modal_body").text('正在进行AI填值,请稍后...');
-       await setTimeoutSync(500);
-       debugger;
- 
-       // 分块进行ai匹配
-       const step = 100 / (chunks.length || 1);
-       for (const chunk of chunks) {
-         const listA = [];
-         const listB = [];
-         const summaryData = [];
-         chunk.forEach(item => {
-           const rowData = getRowData(workBookObj.sheet, item.row, setting.header);
-           listA.push(`${rowData.name || ''} ${rowData.specs}`);
-           // const code = rowData.code || '';
-           const code = getFourCode(rowData.code);
-           const toMatchSummary = code ? summaryGroupMap[code] || [] : noCodeSummary;
-           summaryData.push(toMatchSummary);
-           const summaryKeys = toMatchSummary.map(summary => `${summary.name || ''} ${summary.specs || ''}`);
-           listB.push(summaryKeys)
-         });
-         const test = listB.map(item => item.length);
-         console.log(test);
- 
-         const matchRes = await ajaxPost('/priceInfoSummary/aiMatch', { listA, listB }, 1000 * 60 * 5);
-         // 填匹配值到表格,不实时保存,因为需要人工核查
-         workBookObj.sheet.suspendEvent();
-         workBookObj.sheet.suspendPaint();
-         matchRes.forEach((item, index) => {
-           const firstMatch = item[0];
-           const chunkItem = chunk[index];
-           const summaryIndex = item[0].index;
-           const summaryItem = summaryData[index][summaryIndex];
-           const curUnit = cache[chunkItem.row]?.unit || '';
-           const summaryItemUnit = summaryItem?.unit || '';
-           // 相似度过低的、单位不一致的,不命中
-           if (firstMatch.similarity < 70 || curUnit !== summaryItemUnit) {
-             noMatchRows.push(chunkItem.row);
-             return;
-           };
-           if (chunkItem && summaryItem) {
-             workBookObj.sheet.setValue(chunkItem.row, classCodeCol, summaryItem.classCode);
-             cache[chunkItem.row].classCode = summaryItem.classCode;
-             const items = getItemsFromTableItem(cache[chunkItem.row]);
-             items.forEach(item => {
-               item.classCode = summaryItem.classCode;
-             });
-             // 如果实际行存在珠海地区的,才填计算式
-             const tableItems = getItemsFromTableItem(cache[chunkItem.row]);
-             const needExpString = tableItems.some(tItem => {
-               const area = AREA_BOOK.cache.find(areaItem => areaItem.ID === tItem.areaID)
-               return area && area.name && /珠海/.test(area.name);
-             });
-             if (needExpString) {
-               workBookObj.sheet.setValue(chunkItem.row, expStringCol, summaryItem.expString);
-               cache[chunkItem.row].expString = summaryItem.expString;
-               items.forEach(item => {
-                 item.expString = summaryItem.expString;
-               });
-             }
-           }
-         });
-         workBookObj.sheet.resumeEvent();
-         workBookObj.sheet.resumePaint();
-         percent += step;
-         $("#progress_modal_bar").css('width', `${percent}%`);
-         await setTimeoutSync(100);
-       }
- 
-       // 没匹配到的行,自动生成别名编码
-       workBookObj.sheet.suspendEvent();
-       workBookObj.sheet.suspendPaint();
-       let curMaxClassCode = getMaxClassCode(priceInfoSummary);
-       debugger;
-       for (const row of noMatchRows) {
-         const newClassCode = getNewMaxClassCode(curMaxClassCode);
-         workBookObj.sheet.setValue(row, classCodeCol, newClassCode);
-         cache[row].classCode = newClassCode;
-         const items = getItemsFromTableItem(cache[row]);
-         items.forEach(item => {
-           item.classCode = newClassCode;
-         });
-         curMaxClassCode = newClassCode;
-       }
-       workBookObj.sheet.resumeEvent();
-       workBookObj.sheet.resumePaint();
- 
- 
-     } catch (error) {
-       console.log(error);
-       alert(error);
-     }
-     await setTimeoutSync(500);
-     $.bootstrapLoading.progressEnd();
-   } */
+
+  /*   const aiMatch = async () => {
+      try {
+        // 获取信息价总表
+        const priceInfoSummary = await ajaxPost('/priceInfoSummary/getData', {}, 1000 * 60 * 5);
+        const summaryGroupMap = _.groupBy(priceInfoSummary, item => getFourCode(item.code));
+        const noCodeSummary = priceInfoSummary.filter(item => !item.code);
+        const totalRows = workBookObj.sheet.getRowCount();
+        const changedCells = [];
+        const noMatchRows = []; // 没有匹配、ai没有命中的行,后续需要自动生成别名编码(最大的别名编码+1)
+        for (let i = 0; i < totalRows; i++) {
+          const rowData = getRowData(workBookObj.sheet, i, setting.header);
+          // const code = rowData.code || '';
+          const code = getFourCode(rowData.code);
+          const toMatchSummary = code ? summaryGroupMap[code] || [] : noCodeSummary;
+          if (toMatchSummary.length) {
+            changedCells.push({ row: i });
+          } else {
+            noMatchRows.push(i);
+          }
+        }
+        if (!changedCells.length) {
+          return;
+        }
+        const classCodeCol = setting.header.findIndex(h => h.dataCode === 'classCode');
+        const expStringCol = setting.header.findIndex(h => h.dataCode === 'expString');
+        // const chunks = _.chunk(changedCells, 20);
+        const chunks = _.chunk(changedCells, 1); // 只能一条一条匹配改成,否则经常ai服务经常挂
+        let percent = 0;
+        $.bootstrapLoading.progressStart('AI填值', false);
+        $("#progress_modal_body").text('正在进行AI填值,请稍后...');
+        await setTimeoutSync(500);
+        const matchResCache = {};
+  
+        // 分块进行ai匹配
+        const step = 100 / (chunks.length || 1);
+        for (let i = 0; i < chunks.length; i++) {
+          const chunk = chunks[i];
+          const listA = [];
+          const listB = [];
+          const summaryData = [];
+          chunk.forEach(item => {
+            const rowData = getRowData(workBookObj.sheet, item.row, setting.header);
+            listA.push(`${rowData.name || ''} ${rowData.specs}`);
+            const code = getFourCode(rowData.code);
+            const toMatchSummary = code ? summaryGroupMap[code] || [] : noCodeSummary;
+            summaryData.push(toMatchSummary);
+            const summaryKeys = toMatchSummary.map(summary => `${summary.name || ''} ${summary.specs || ''}`);
+            listB.push([...new Set(summaryKeys)]);
+          });
+          const test = listB.map(item => item.length);
+          console.log(test);
+          const matchRes = matchResCache[listA[0]] ? matchResCache[listA[0]] : await ajaxPost('/priceInfoSummary/aiMatch', { listA, listB }, 1000 * 60 * 5);
+          matchResCache[listA[0]] = matchRes;
+          // 填匹配值到表格,不实时保存,因为需要人工核查
+          workBookObj.sheet.suspendEvent();
+          workBookObj.sheet.suspendPaint();
+          matchRes.forEach((item, index) => {
+            const firstMatch = item[0];
+            const chunkItem = chunk[index];
+            const summaryIndex = item[0].index;
+            const summaryItem = summaryData[index][summaryIndex];
+            const curUnit = cache[chunkItem.row]?.unit || '';
+            const summaryItemUnit = summaryItem?.unit || '';
+            // 相似度过低的、单位不一致的,不命中
+            if (firstMatch.similarity < 70 || curUnit !== summaryItemUnit) {
+              noMatchRows.push(chunkItem.row);
+              return;
+            };
+            if (chunkItem && summaryItem) {
+              workBookObj.sheet.setValue(chunkItem.row, classCodeCol, summaryItem.classCode);
+              cache[chunkItem.row].classCode = summaryItem.classCode;
+              const items = getItemsFromTableItem(cache[chunkItem.row]);
+              items.forEach(item => {
+                item.classCode = summaryItem.classCode;
+              });
+              // 如果实际行存在珠海地区的,才填计算式
+              const tableItems = getItemsFromTableItem(cache[chunkItem.row]);
+              const needExpString = tableItems.some(tItem => {
+                const area = AREA_BOOK.cache.find(areaItem => areaItem.ID === tItem.areaID)
+                return area && area.name && /珠海/.test(area.name);
+              });
+              if (needExpString) {
+                workBookObj.sheet.setValue(chunkItem.row, expStringCol, summaryItem.expString);
+                cache[chunkItem.row].expString = summaryItem.expString;
+                items.forEach(item => {
+                  item.expString = summaryItem.expString;
+                });
+              }
+            }
+          });
+          workBookObj.sheet.resumeEvent();
+          workBookObj.sheet.resumePaint();
+          percent += step;
+          $('#progress_modal_body').text(`正在进行AI填值,请稍后${i + 1}/${chunks.length}...`);
+          $("#progress_modal_bar").css('width', `${percent}%`);
+          await setTimeoutSync(100);
+        }
+  
+        // 没匹配到的行,自动生成别名编码
+        workBookObj.sheet.suspendEvent();
+        workBookObj.sheet.suspendPaint();
+        let curMaxClassCode = getMaxClassCode(priceInfoSummary);
+        for (const row of noMatchRows) {
+          const newClassCode = getNewMaxClassCode(curMaxClassCode);
+          workBookObj.sheet.setValue(row, classCodeCol, newClassCode);
+          cache[row].classCode = newClassCode;
+          const items = getItemsFromTableItem(cache[row]);
+          items.forEach(item => {
+            item.classCode = newClassCode;
+          });
+          curMaxClassCode = newClassCode;
+        }
+        workBookObj.sheet.resumeEvent();
+        workBookObj.sheet.resumePaint();
+  
+  
+      } catch (error) {
+        console.log(error);
+        alert(error);
+      }
+      await setTimeoutSync(500);
+      $.bootstrapLoading.progressEnd();
+    } */
 
   // 保存ai填值
   const saveData = async () => {
@@ -643,6 +679,7 @@ $(document).ready(() => {
 
   $('#empty-area').on('hidden.bs.modal', function () {
     EMPTY_BOOK.clear();
+    $("#ai-match").text('AI填值');
   });
 
   // 保存至总表