|
@@ -285,6 +285,174 @@ const EMPTY_BOOK = (() => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ // 获取最大别名编码
|
|
|
+ const getMaxClassCode = (priceInfoSummary) => {
|
|
|
+ let maxClassCode = '';
|
|
|
+ let maxClassNumber = 0;
|
|
|
+ priceInfoSummary.forEach(item => {
|
|
|
+ if (!item.classCode) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const numMatch = item.classCode.match(/\d+/);
|
|
|
+ if (numMatch && +numMatch[0] > maxClassNumber) {
|
|
|
+ maxClassNumber = +numMatch[0];
|
|
|
+ maxClassCode = item.classCode;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ // return { maxClassNumber, maxClassCode };
|
|
|
+ return maxClassCode;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 在最大别名编码基础上+1;
|
|
|
+ const getNewMaxClassCode = (maxClassCode) => {
|
|
|
+ const numMatch = maxClassCode.match(/\d+/);
|
|
|
+ if (!numMatch) {
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ const maxNumber = +numMatch[0];
|
|
|
+ let newMaxClassCode = String(maxNumber + 1);
|
|
|
+ // 补齐的位数
|
|
|
+ const pattern = numMatch[0].length - newMaxClassCode.length;
|
|
|
+ if (pattern > 0) {
|
|
|
+ for (let i = 0; i < pattern; i++) {
|
|
|
+ newMaxClassCode = `0${newMaxClassCode}`;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return newMaxClassCode;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ // ai填值
|
|
|
+ const aiMatch = async () => {
|
|
|
+ try {
|
|
|
+ // 获取信息价总表
|
|
|
+ const priceInfoSummary = await ajaxPost('/priceInfoSummary/getData', {}, 1000 * 60 * 5);
|
|
|
+ const summaryGroupMap = _.groupBy(priceInfoSummary, '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 toMatchSummary = code ? summaryGroupMap[code] || [] : noCodeSummary;
|
|
|
+ if (toMatchSummary.length) {
|
|
|
+ changedCells.push({ row: i });
|
|
|
+ } else {
|
|
|
+ noMatchRows.push(i);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ const classCodeCol = setting.header.findIndex(h => h.dataCode === 'classCode');
|
|
|
+ const expStringCol = setting.header.findIndex(h => h.dataCode === 'expString');
|
|
|
+ const chunks = _.chunk(changedCells, 20);
|
|
|
+ let percent = 0;
|
|
|
+ $.bootstrapLoading.progressStart('AI填值', false);
|
|
|
+ $("#progress_modal_body").text('正在进行AI填值,请稍后...');
|
|
|
+ await setTimeoutSync(500);
|
|
|
+
|
|
|
+ // 分块进行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 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];
|
|
|
+ // 相似度过低的不命中
|
|
|
+ if (firstMatch.similarity < 50) {
|
|
|
+ noMatchRows.push(chunkItem.row);
|
|
|
+ return;
|
|
|
+ };
|
|
|
+ const summaryIndex = item[0].index;
|
|
|
+ const summaryItem = summaryData[index][summaryIndex];
|
|
|
+ if (chunkItem && summaryItem) {
|
|
|
+ workBookObj.sheet.setValue(chunkItem.row, classCodeCol, 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);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ workBookObj.sheet.resumeEvent();
|
|
|
+ workBookObj.sheet.resumePaint();
|
|
|
+ percent += step;
|
|
|
+ $("#progress_modal_bar").css('width', `${percent}%`);
|
|
|
+ await setTimeoutSync(500);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 没匹配到的行,自动生成别名编码
|
|
|
+ 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);
|
|
|
+ curMaxClassCode = newClassCode;
|
|
|
+ }
|
|
|
+ workBookObj.sheet.resumeEvent();
|
|
|
+ workBookObj.sheet.resumePaint();
|
|
|
+
|
|
|
+
|
|
|
+ } catch (error) {
|
|
|
+ console.log(error);
|
|
|
+ alert(error);
|
|
|
+ }
|
|
|
+ await setTimeoutSync(500);
|
|
|
+ $.bootstrapLoading.progressEnd();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 保存ai填值
|
|
|
+ const saveData = async () => {
|
|
|
+ try {
|
|
|
+ $.bootstrapLoading.progressStart('保存AI填值', false);
|
|
|
+ $("#progress_modal_body").text('正在保存AI填值,请稍后...');
|
|
|
+ await setTimeoutSync(500);
|
|
|
+ // 分批保存数据,以免数据库压力过大
|
|
|
+ const totalRows = workBookObj.sheet.getRowCount();
|
|
|
+ const changedCells = [];
|
|
|
+ for (let i = 0; i < totalRows; i++) {
|
|
|
+ changedCells.push({ row: i });
|
|
|
+ }
|
|
|
+ const chunks = _.chunk(changedCells, 100);
|
|
|
+ let percent = 0;
|
|
|
+ const step = 100 / (chunks.length || 1);
|
|
|
+ for (const chunk of chunks) {
|
|
|
+ await handleEdit(chunk);
|
|
|
+ percent += parseInt(`${step}`);
|
|
|
+ $("#progress_modal_bar").css('width', `${percent}%`);
|
|
|
+ await setTimeoutSync(200);
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.log(error);
|
|
|
+ alert(error);
|
|
|
+ }
|
|
|
+ setTimeout(() => {
|
|
|
+ $.bootstrapLoading.progressEnd();
|
|
|
+ }, 500);
|
|
|
+ }
|
|
|
+
|
|
|
|
|
|
return {
|
|
|
buildWorkBook,
|
|
@@ -294,6 +462,8 @@ const EMPTY_BOOK = (() => {
|
|
|
workBookObj,
|
|
|
updateRowCode,
|
|
|
saveInSummary,
|
|
|
+ aiMatch,
|
|
|
+ saveData,
|
|
|
}
|
|
|
})();
|
|
|
|
|
@@ -314,4 +484,14 @@ $(document).ready(() => {
|
|
|
$('#save-in-summary').click(() => {
|
|
|
EMPTY_BOOK.saveInSummary();
|
|
|
});
|
|
|
+
|
|
|
+ // AI填值
|
|
|
+ $('#ai-match').click(() => {
|
|
|
+ EMPTY_BOOK.aiMatch();
|
|
|
+ })
|
|
|
+
|
|
|
+ // 保存AI填值
|
|
|
+ $('#save-data').click(() => {
|
|
|
+ EMPTY_BOOK.saveData();
|
|
|
+ })
|
|
|
});
|