// 价格信息表 const PRICE_BOOK = (() => { const setting = { header: [ { headerName: '编码', headerWidth: 100, dataCode: 'code', dataType: 'String', hAlign: 'left', vAlign: 'center', formatter: "@" }, { headerName: '别名编码', headerWidth: 70, dataCode: 'classCode', dataType: 'String', hAlign: 'left', vAlign: 'center', formatter: "@" }, { headerName: '名称', headerWidth: 200, dataCode: 'name', dataType: 'String', hAlign: 'left', vAlign: 'center' }, { headerName: '规格型号', headerWidth: 120, dataCode: 'specs', dataType: 'String', hAlign: 'left', vAlign: 'center' }, { headerName: '单位', headerWidth: 80, dataCode: 'unit', dataType: 'String', hAlign: 'center', vAlign: 'center' }, { headerName: '不含税价', headerWidth: 80, dataCode: 'noTaxPrice', dataType: 'String', hAlign: 'right', vAlign: 'center' }, { headerName: '含税价', headerWidth: 80, dataCode: 'taxPrice', dataType: 'String', hAlign: 'right', vAlign: 'center' }, { headerName: '月份备注', headerWidth: 140, dataCode: 'dateRemark', dataType: 'String', hAlign: 'left', vAlign: 'center' }, { headerName: '计算式', headerWidth: 100, dataCode: 'expString', dataType: 'String', hAlign: 'left', vAlign: 'center' }, ], }; // 初始化表格 const workBook = initSheet($('#price-spread')[0], setting); workBook.options.allowUserDragDrop = true; workBook.options.allowUserDragFill = true; lockUtil.lockSpreads([workBook], locked); const sheet = workBook.getSheet(0); let cache = []; // 清空 function clear() { cache = []; sheet.setRowCount(0); } // 是否正在检测重复数据 let isCheckingRepeat = false; // 初始化数据 async function initData(classIDList) { isCheckingRepeat = false; $('#check-repeat').text('检测重复别名编码'); if (!classIDList || !classIDList.length) { return clear(); } $.bootstrapLoading.start(); try { cache = await ajaxPost('/priceInfo/getPriceData', { classIDList }, 1000 * 60 * 10); cache = _.sortBy(cache, 'classCode'); showData(sheet, cache, setting.header, 5); const row = sheet.getActiveRowIndex(); const keywordList = cache[row] && cache[row].keywordList || []; KEYWORD_BOOK.showKeywordData(keywordList); } catch (err) { cache = []; sheet.setRowCount(0); alert(err); } finally { $.bootstrapLoading.end(); } } // 编辑处理 async function handleEdit(changedCells, needLoading = true) { $.bootstrapLoading.start(); const areaID = AREA_BOOK.curArea.ID; const postData = []; // 请求用 // 更新缓存用 const updateData = []; const deleteData = []; const insertData = []; try { changedCells.forEach(({ row }) => { if (cache[row]) { const rowData = getRowData(sheet, row, setting.header); if (Object.keys(rowData).length) { // 还有数据,更新 const diffData = getRowDiffData(rowData, cache[row], setting.header); if (diffData) { postData.push({ type: UpdateType.UPDATE, ID: cache[row].ID, areaID, compilationID, period: curLibPeriod, data: diffData }); updateData.push({ row, data: diffData }); } } else { // 该行无数据了,删除 postData.push({ type: UpdateType.DELETE, ID: cache[row].ID, areaID, compilationID, period: curLibPeriod }); deleteData.push(cache[row]); } } else { // 新增 const rowData = getRowData(sheet, row, setting.header); if (Object.keys(rowData).length) { rowData.ID = uuid.v1(); rowData.libID = libID; rowData.compilationID = compilationID; rowData.areaID = AREA_BOOK.curArea.ID; rowData.classID = CLASS_BOOK.curClass.ID; rowData.period = curLibPeriod; postData.push({ type: UpdateType.CREATE, data: rowData }); insertData.push(rowData); } } }); if (postData.length) { await ajaxPost('/priceInfo/editPriceData', { postData }, TIME_OUT); // 更新缓存,先更新然后删除,最后再新增,防止先新增后缓存数据的下标与更新、删除数据的下标对应不上 updateData.forEach(item => { Object.assign(cache[item.row], item.data); }); deleteData.forEach(item => { const index = cache.indexOf(item); if (index >= 0) { cache.splice(index, 1); } }); insertData.forEach(item => cache.push(item)); if (deleteData.length || insertData.length) { showData(sheet, cache, setting.header, isCheckingRepeat ? 0 : 5); } } } catch (err) { // 恢复各单元格数据 showData(sheet, cache, setting.header, 5); } $.bootstrapLoading.end(); } sheet.bind(GC.Spread.Sheets.Events.ValueChanged, function (e, info) { const changedCells = [{ row: info.row }]; handleEdit(changedCells); }); const handleSelectionChange = (row) => { // 显示关键字数据 const keywordList = cache[row] && cache[row].keywordList || []; KEYWORD_BOOK.showKeywordData(keywordList); } sheet.bind(GC.Spread.Sheets.Events.SelectionChanged, function (e, info) { const row = info.newSelections && info.newSelections[0] ? info.newSelections[0].row : 0; handleSelectionChange(row); }); sheet.bind(GC.Spread.Sheets.Events.RangeChanged, function (e, info) { const changedRows = []; let preRow; info.changedCells.forEach(({ row }) => { if (row !== preRow) { changedRows.push({ row }); } preRow = row; }); handleEdit(changedRows); }); // 显示重复别名编码数据 let orgCache = [...cache]; const showRepeatData = () => { if (isCheckingRepeat) { $('#check-repeat').text('检测重复别名编码'); isCheckingRepeat = false; cache = orgCache; showData(sheet, cache, setting.header, 5); return; } $('#check-repeat').text('检测重复别名编码(检测中)'); isCheckingRepeat = true; const tableData = []; const classCodeMap = {}; cache.forEach(item => { const classCode = item.classCode || ''; if (!classCodeMap[classCode]) { classCodeMap[classCode] = 1; } else { classCodeMap[classCode] = classCodeMap[classCode] + 1; } }); cache.forEach(item => { const classCode = item.classCode || ''; if (classCodeMap[classCode] > 1) { tableData.push(item); } }); orgCache = [...cache]; cache = tableData; showData(sheet, cache, setting.header); } const getKey = (item) => { return `${item.code || ''}@${item.name || ''}@${item.specs || ''}@${item.unit || ''}`; } // 批量修改 const batchEdit = async () => { try { $.bootstrapLoading.start(); const row = sheet.getActiveRowIndex(); const col = sheet.getActiveColumnIndex(); const colHeader = setting.header[col]; const priceItem = cache[row]; if (!priceItem || !colHeader) { return; } const prop = colHeader.dataCode; const val = $('#edit-text').val(); if (['noTaxPrice', 'taxPrice'].includes(prop) && (!val || isNaN(val))) { throw new Error('请输入数值'); } await ajaxPost('/priceInfo/batchUpdate', { priceItem, prop, val }); const key = getKey(priceItem); cache.forEach(item => { if (key === getKey(item)) { item[prop] = val; } }); showData(sheet, cache, setting.header, 5); $('#batch-edit').modal('hide'); } catch (error) { alert(error.message); } $.bootstrapLoading.end(); } // 右键功能 function buildContextMenu() { $.contextMenu({ selector: '#price-spread', build: function ($triggerElement, e) { // 控制允许右键菜单在哪个位置出现 const offset = $('#price-spread').offset(); const x = e.pageX - offset.left; const y = e.pageY - offset.top; const target = sheet.hitTest(x, y); if (target.hitTestType === 3) { // 在表格内 const sel = sheet.getSelections()[0]; if (sel && sel.rowCount === 1 && typeof target.row !== 'undefined') { const orgRow = sheet.getActiveRowIndex(); sheet.setActiveCell(target.row, target.col); if (orgRow !== target.row) { handleSelectionChange(target.row); } } return { items: { batchUpdate: { name: '批量修改', icon: "fa-edit", disabled: function () { return locked || !cache[target.row]; }, callback: function (key, opt) { const colHeader = setting.header[target.col]; const item = cache[target.row]; if (item) { const info = `材料:${item.code || ''} ${item.name || ''} ${item.specs || ''} ${item.unit}`; $('#edit-item').text(info); $('#edit-label').text(colHeader.headerName); $('#edit-text').attr('placeholder', `请输入${colHeader.headerName}`); $('#edit-text').val(item[colHeader.dataCode] || ''); $('#batch-edit').modal('show'); } } }, } }; } else { return false; } } }); } buildContextMenu(); return { clear, initData, showRepeatData, batchEdit, } })(); $(document).ready(() => { // 检测重复别名编码 $('#check-repeat').click(() => { PRICE_BOOK.showRepeatData(); }); // 批量修改 $('#batch-edit-confirm').click(() => { PRICE_BOOK.batchEdit(); }); $('#batch-edit').on('shown.bs.modal', function () { $('#edit-text').focus(); }); });