// 分类表 function setTimeoutSync(handle, time) { return new Promise(function (resolve, reject) { setTimeout(function () { if (handle && typeof handle === 'function') { handle(); } resolve(); }, time); }); } const CLASS_BOOK = (() => { const setting = { header: [{ headerName: '分类', headerWidth: $('#area-spread').width(), dataCode: 'name', dataType: 'String', hAlign: 'left', vAlign: 'center' }], controller: { cols: [ { data: { field: 'name', vAlign: 1, hAlign: 0, font: 'Arial' }, } ], headRows: 1, headRowHeight: [30], emptyRows: 0, treeCol: 0 }, tree: { id: 'ID', pid: 'ParentID', nid: 'NextSiblingID', rootId: -1 } }; // 初始化表格 const workBook = initSheet($('#class-spread')[0], setting); workBook.options.allowExtendPasteRange = false; workBook.options.allowUserDragDrop = true; workBook.options.allowUserDragFill = true; const sheet = workBook.getSheet(0); let tree; let controller; // 初始化数据 async function initData(libID, areaID) { if (!areaID) { tree = null; controller = null; sheet.setRowCount(0); PRICE_BOOK.clear(); return; } $.bootstrapLoading.start(); try { const data = await ajaxPost('/priceInfo/getClassData', { libID, areaID }, TIME_OUT); tree = idTree.createNew(setting.tree); tree.loadDatas(data); tree.selected = tree.items.length > 0 ? tree.items[0] : null; controller = TREE_SHEET_CONTROLLER.createNew(tree, sheet, setting.controller, false); controller.showTreeData(); handleSelectionChanged(0); sheet.setSelection(0, 0, 1, 1); lockUtil.lockSpreads([workBook], locked); } catch (err) { tree = null; controller = null; sheet.setRowCount(0); alert(err); } finally { $.bootstrapLoading.end(); } } // 编辑处理 async function handleEdit(changedCells) { const updateData = []; changedCells.forEach(({ row, col }) => { updateData.push({ row, type: UpdateType.UPDATE, filter: { ID: tree.items[row].data.ID }, update: { name: sheet.getValue(row, col) } }); }); try { await ajaxPost('/priceInfo/editClassData', { updateData }, TIME_OUT); updateData.forEach(({ row, update: { name } }) => tree.items[row].data.name = name); } catch (err) { // 恢复各单元格数据 sheetCommonObj.renderSheetFunc(sheet, () => { changedCells.forEach(({ row }) => { sheet.setValue(tree.items[row].data.name); }); }); } } sheet.bind(GC.Spread.Sheets.Events.ValueChanged, function (e, info) { const changedCells = [{ row: info.row, col: info.col }]; handleEdit(changedCells); }); sheet.bind(GC.Spread.Sheets.Events.RangeChanged, function (e, info) { handleEdit(info.changedCells); }); // 树操作相关 const $insert = $('#tree-insert'); const $remove = $('#tree-remove'); const $upLevel = $('#tree-up-level'); const $downLevel = $('#tree-down-level'); const $downMove = $('#tree-down-move'); const $upMove = $('#tree-up-move'); const $calcPriceIndex = $('#calc-price-index'); const $matchSummary = $('#match-summary'); const $batchMatchSummary = $('#batch-match-summary'); const $showEmpty = $('#show-empty'); // 插入 let canInsert = true; async function insert() { try { if (!canInsert) { return false; } canInsert = false; $.bootstrapLoading.start(); const updateData = []; const selected = tree.selected; const newItem = { libID, areaID: AREA_BOOK.curArea.ID, ID: uuid.v1(), name: '', ParentID: '-1', NextSiblingID: '-1' }; if (selected) { newItem.ParentID = selected.data.ParentID; updateData.push({ type: UpdateType.UPDATE, filter: { ID: selected.data.ID }, update: { NextSiblingID: newItem.ID } }); if (selected.nextSibling) { newItem.NextSiblingID = selected.nextSibling.data.ID; } } updateData.push({ type: UpdateType.CREATE, document: newItem }); await ajaxPost('/priceInfo/editClassData', { updateData }); controller.insertByID(newItem.ID); handleSelectionChanged(sheet.getActiveRowIndex()); } catch (err) { alert(err); } finally { canInsert = true; $.bootstrapLoading.end(); } } $insert.click(_.debounce(insert, DEBOUNCE_TIME, { leading: true })); // 删除 let canRemove = true; async function remove() { try { if (!canRemove) { return false; } canRemove = false; $.bootstrapLoading.start(); const updateData = []; const selected = tree.selected; const children = selected.getPosterity(); [selected, ...children].forEach(node => updateData.push({ type: UpdateType.DELETE, filter: { ID: node.data.ID } })); if (selected.preSibling) { updateData.push({ type: UpdateType.UPDATE, filter: { ID: selected.preSibling.data.ID }, update: { NextSiblingID: selected.data.NextSiblingID } }); } await ajaxPost('/priceInfo/editClassData', { updateData }); controller.delete(); handleSelectionChanged(sheet.getActiveRowIndex()); } catch (err) { alert(err); } finally { canRemove = true; $.bootstrapLoading.end(); } } $remove.click(_.debounce(remove, DEBOUNCE_TIME, { leading: true })); // 升级 let canUpLevel = true; async function upLevel() { try { if (!canUpLevel) { return false; } canUpLevel = false; $.bootstrapLoading.start(); const updateData = []; const selected = tree.selected; if (selected.preSibling) { updateData.push({ type: UpdateType.UPDATE, filter: { ID: selected.preSibling.data.ID }, update: { NextSiblingID: -1 } }); } if (selected.parent) { updateData.push({ type: UpdateType.UPDATE, filter: { ID: selected.parent.data.ID }, update: { NextSiblingID: selected.data.ID } }); } updateData.push({ type: UpdateType.UPDATE, filter: { ID: selected.data.ID }, update: { ParentID: selected.parent.data.ParentID, NextSiblingID: selected.parent.data.NextSiblingID } }); let curNode = selected.nextSibling; while (curNode) { updateData.push({ type: UpdateType.UPDATE, filter: { ID: curNode.data.ID }, update: { ParentID: selected.data.ID } }); curNode = curNode.nextSibling; } await ajaxPost('/priceInfo/editClassData', { updateData }); controller.upLevel(); refreshTreeButton(tree.selected); } catch (err) { alert(err); } finally { canUpLevel = true; $.bootstrapLoading.end(); } } $upLevel.click(_.debounce(upLevel, DEBOUNCE_TIME, { leading: true })); // 降级 let canDownLevel = true; async function downLevel() { try { if (!canDownLevel) { return false; } canDownLevel = false; $.bootstrapLoading.start(); const updateData = []; const selected = tree.selected; if (selected.preSibling) { updateData.push({ type: UpdateType.UPDATE, filter: { ID: selected.preSibling.data.ID }, update: { NextSiblingID: selected.data.NextSiblingID } }); const preSiblingLastChild = selected.preSibling.children[selected.preSibling.children.length - 1]; if (preSiblingLastChild) { updateData.push({ type: UpdateType.UPDATE, filter: { ID: preSiblingLastChild.data.ID }, update: { NextSiblingID: selected.data.ID } }); } updateData.push({ type: UpdateType.UPDATE, filter: { ID: selected.data.ID }, update: { ParentID: selected.preSibling.data.ID, NextSiblingID: -1 } }); } await ajaxPost('/priceInfo/editClassData', { updateData }); controller.downLevel(); refreshTreeButton(tree.selected); } catch (err) { alert(err); } finally { canDownLevel = true; $.bootstrapLoading.end(); } } $downLevel.click(_.debounce(downLevel, DEBOUNCE_TIME, { leading: true })); // 下移 let canDownMove = true; async function downMove() { try { if (!canDownMove) { return false; } canDownMove = false; $.bootstrapLoading.start(); const updateData = []; const selected = tree.selected; if (selected.preSibling) { updateData.push({ type: UpdateType.UPDATE, filter: { ID: selected.preSibling.data.ID }, update: { NextSiblingID: selected.data.NextSiblingID } }); } updateData.push({ type: UpdateType.UPDATE, filter: { ID: selected.data.ID }, update: { NextSiblingID: selected.nextSibling.data.NextSiblingID } }); updateData.push({ type: UpdateType.UPDATE, filter: { ID: selected.nextSibling.data.ID }, update: { NextSiblingID: selected.data.ID } }); await ajaxPost('/priceInfo/editClassData', { updateData }); controller.downMove(); refreshTreeButton(tree.selected); } catch (err) { alert(err); } finally { canDownMove = true; $.bootstrapLoading.end(); } } $downMove.click(_.debounce(downMove, DEBOUNCE_TIME, { leading: true })); // 上移 let canUpMove = true; async function upMove() { try { if (!canUpMove) { return false; } canUpMove = false; $.bootstrapLoading.start(); const updateData = []; const selected = tree.selected; if (selected.preSibling) { updateData.push({ type: UpdateType.UPDATE, filter: { ID: selected.preSibling.data.ID }, update: { NextSiblingID: selected.data.NextSiblingID } }); } const prePreSibling = selected.preSibling.preSibling; if (prePreSibling) { updateData.push({ type: UpdateType.UPDATE, filter: { ID: prePreSibling.data.ID }, update: { NextSiblingID: selected.data.ID } }); } updateData.push({ type: UpdateType.UPDATE, filter: { ID: selected.data.ID }, update: { NextSiblingID: selected.preSibling.data.ID } }); await ajaxPost('/priceInfo/editClassData', { updateData }); controller.upMove(); refreshTreeButton(tree.selected); } catch (err) { alert(err); } finally { canUpMove = true; $.bootstrapLoading.end(); } } $upMove.click(_.debounce(upMove, DEBOUNCE_TIME, { leading: true })); // 刷新树操作按钮有效性 function refreshTreeButton(selected) { if (locked) { return; } $insert.removeClass('disabled'); $remove.removeClass('disabled'); $upLevel.removeClass('disabled'); $downLevel.removeClass('disabled'); $downMove.removeClass('disabled'); $upMove.removeClass('disabled'); if (!selected) { $remove.addClass('disabled'); $upLevel.addClass('disabled'); $downLevel.addClass('disabled'); $downMove.addClass('disabled'); $upMove.addClass('disabled'); } else { if (!selected.preSibling) { $downLevel.addClass('disabled'); $upMove.addClass('disabled'); } if (!selected.nextSibling) { $downMove.addClass('disabled'); } if (!selected.parent) { $upLevel.addClass('disabled'); } } } // 焦点变更处理 const curClass = { ID: null }; function handleSelectionChanged(row) { curRow = row; const classNode = tree.items[row] || null; tree.selected = classNode; refreshTreeButton(classNode); curClass.ID = classNode && classNode.data && classNode.data.ID || null; const classIDList = [] if (classNode) { classIDList.push(classNode.data.ID); const children = classNode.getPosterity(); children.forEach(child => classIDList.push(child.data.ID)); } PRICE_BOOK.initData(classIDList); } const debounceSelectionChanged = _.debounce(function (e, info) { const row = info.newSelections && info.newSelections[0] ? info.newSelections[0].row : 0; handleSelectionChanged(row); }, DEBOUNCE_TIME, { leading: true }); sheet.bind(GC.Spread.Sheets.Events.SelectionChanged, debounceSelectionChanged); const reload = () => { if (curClass.ID) { const node = tree.nodes[tree.prefix + curClass.ID]; if (node) { handleSelectionChanged(node.serialNo()) } } } $calcPriceIndex.click(_.debounce(async () => { $.bootstrapLoading.start(); try { const data = await ajaxPost('/priceInfo/calcPriceIndex', { libID, period: curLibPeriod, compilationID }, TIME_OUT); //alert(data); if (data) { const htmlStr = data.replace(/\n/gm, '
'); //replaceAll('\n','
',data); $("#result-info-body").html(htmlStr); $("#result-info").modal('show'); } else { alert('计算完成!') } } catch (error) { console.log(error); } $.bootstrapLoading.end(); }, DEBOUNCE_TIME, { leading: true })); const doMatchSummary = async (libID, compilationID, areaID) => { await ajaxPost('/priceInfo/matchSummary', { libID, compilationID, areaID }, 1000 * 60 * 10); } // 匹配总表 $matchSummary.click(_.debounce(async () => { $.bootstrapLoading.progressStart('匹配总表', true); $("#progress_modal_body").text('正在匹配总表,请稍后...'); try { const matchAll = $('#match-all-input')[0].checked; const areaID = matchAll ? '' : AREA_BOOK.curArea?.ID; await doMatchSummary(libID, compilationID, areaID); setTimeout(() => { $.bootstrapLoading.progressEnd(); window.location.reload() }, 1000) } catch (error) { alert(error) console.log(error); $.bootstrapLoading.progressEnd(); } }, DEBOUNCE_TIME, { leading: true })); // 批量匹配总表 $batchMatchSummary.click(_.debounce(async () => { $.bootstrapLoading.progressStart('批量匹配总表', true); try { const libs = await ajaxPost('/priceInfo/getAllLibs'); for (const lib of libs) { $("#progress_modal_body").text(`${lib.name},正在匹配总表,请稍后(${libs.indexOf(lib) + 1}/${libs.length})...`); await doMatchSummary(lib.ID, lib.compilationID, ''); await setTimeoutSync(() => { }, 100); } await setTimeoutSync(() => { $.bootstrapLoading.progressEnd(); window.location.reload() }, 1000); } catch (error) { alert(error) console.log(error); $.bootstrapLoading.progressEnd(); } }, DEBOUNCE_TIME, { leading: true })); // 显示空数据 $showEmpty.click(() => { $('#empty-area').modal('show'); }); return { initData, handleSelectionChanged, curClass, reload, } })();