|  | @@ -0,0 +1,883 @@
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +function setAlign(sheet, headers) {
 | 
	
		
			
				|  |  | +    const fuc = () => {
 | 
	
		
			
				|  |  | +        headers.forEach(({ hAlign, vAlign }, index) => {
 | 
	
		
			
				|  |  | +            sheetCommonObj.setAreaAlign(sheet.getRange(-1, index, -1, 1), hAlign, vAlign)
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +    sheetCommonObj.renderSheetFunc(sheet, fuc);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +function setFormatter(sheet, headers) {
 | 
	
		
			
				|  |  | +    const fuc = () => {
 | 
	
		
			
				|  |  | +        headers.forEach(({ formatter }, index) => {
 | 
	
		
			
				|  |  | +            if (formatter) {
 | 
	
		
			
				|  |  | +                sheet.setFormatter(-1, index, formatter);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +    sheetCommonObj.renderSheetFunc(sheet, fuc);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +function initSheet(dom, setting) {
 | 
	
		
			
				|  |  | +    const workBook = sheetCommonObj.buildSheet(dom, setting);
 | 
	
		
			
				|  |  | +    const sheet = workBook.getSheet(0);
 | 
	
		
			
				|  |  | +    setAlign(sheet, setting.header);
 | 
	
		
			
				|  |  | +    setFormatter(sheet, setting.header);
 | 
	
		
			
				|  |  | +    return workBook;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +function showData(sheet, data, headers, emptyRows) {
 | 
	
		
			
				|  |  | +    const fuc = () => {
 | 
	
		
			
				|  |  | +        sheet.setRowCount(data.length);
 | 
	
		
			
				|  |  | +        data.forEach((item, row) => {
 | 
	
		
			
				|  |  | +            headers.forEach(({ dataCode }, col) => {
 | 
	
		
			
				|  |  | +                sheet.setValue(row, col, item[dataCode] || '');
 | 
	
		
			
				|  |  | +            });
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +        if (emptyRows) {
 | 
	
		
			
				|  |  | +            sheet.addRows(data.length, emptyRows);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +    sheetCommonObj.renderSheetFunc(sheet, fuc);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const TIME_OUT = 10000;
 | 
	
		
			
				|  |  | +const libID = window.location.search.match(/libID=([^&]+)/)[1];
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const UpdateType = {
 | 
	
		
			
				|  |  | +    UPDATE: 'update',
 | 
	
		
			
				|  |  | +    DELETE: 'delete',
 | 
	
		
			
				|  |  | +    CREATE: 'create',
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const DEBOUNCE_TIME = 200;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const locked = lockUtil.getLocked();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 地区表
 | 
	
		
			
				|  |  | +const AREA_BOOK = (() => {
 | 
	
		
			
				|  |  | +    const cache = areaList;
 | 
	
		
			
				|  |  | +    const setting = {
 | 
	
		
			
				|  |  | +        header: [{ headerName: '地区', headerWidth: $('#area-spread').width(), dataCode: 'name', dataType: 'String', hAlign: 'center', vAlign: 'center' }]
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +    // 初始化表格
 | 
	
		
			
				|  |  | +    const workBook = initSheet($('#area-spread')[0], setting);
 | 
	
		
			
				|  |  | +    lockUtil.lockSpreads([workBook], locked);
 | 
	
		
			
				|  |  | +    workBook.options.allowExtendPasteRange = false;
 | 
	
		
			
				|  |  | +    workBook.options.allowUserDragDrop = true;
 | 
	
		
			
				|  |  | +    workBook.options.allowUserDragFill = true;
 | 
	
		
			
				|  |  | +    const sheet = workBook.getSheet(0);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // 排序显示
 | 
	
		
			
				|  |  | +    cache.sort((a, b) => a.serialNo - b.serialNo);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // 显示数据
 | 
	
		
			
				|  |  | +    showData(sheet, cache, setting.header);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // 编辑处理
 | 
	
		
			
				|  |  | +    async function handleEdit(changedCells) {
 | 
	
		
			
				|  |  | +        const updateData = [];
 | 
	
		
			
				|  |  | +        changedCells.forEach(({ row, col }) => {
 | 
	
		
			
				|  |  | +            updateData.push({
 | 
	
		
			
				|  |  | +                row,
 | 
	
		
			
				|  |  | +                ID: cache[row].ID,
 | 
	
		
			
				|  |  | +                name: sheet.getValue(row, col)
 | 
	
		
			
				|  |  | +            });
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +        try {
 | 
	
		
			
				|  |  | +            await ajaxPost('/priceInfo/editArea', { updateData }, TIME_OUT);
 | 
	
		
			
				|  |  | +            updateData.forEach(({ row, name }) => cache[row].name = name);
 | 
	
		
			
				|  |  | +        } catch (err) {
 | 
	
		
			
				|  |  | +            // 恢复各单元格数据
 | 
	
		
			
				|  |  | +            sheetCommonObj.renderSheetFunc(sheet, () => {
 | 
	
		
			
				|  |  | +                changedCells.forEach(({ row }) => {
 | 
	
		
			
				|  |  | +                    sheet.setValue(cache[row].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 curArea = { ID: null };
 | 
	
		
			
				|  |  | +    // 焦点变更处理
 | 
	
		
			
				|  |  | +    const debounceSelectionChanged = _.debounce(function (e, info) {
 | 
	
		
			
				|  |  | +        const row = info.newSelections && info.newSelections[0] ? info.newSelections[0].row : 0;
 | 
	
		
			
				|  |  | +        handleSelectionChanged(row);
 | 
	
		
			
				|  |  | +    }, DEBOUNCE_TIME, { leading: true }); // leading = true : 先触发再延迟
 | 
	
		
			
				|  |  | +    function handleSelectionChanged(row) {
 | 
	
		
			
				|  |  | +        const areaItem = cache[row];
 | 
	
		
			
				|  |  | +        curArea.ID = areaItem && areaItem.ID || null;
 | 
	
		
			
				|  |  | +        CLASS_BOOK.initData(libID, curArea.ID);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    sheet.bind(GC.Spread.Sheets.Events.SelectionChanged, debounceSelectionChanged);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // 新增
 | 
	
		
			
				|  |  | +    async function insert() {
 | 
	
		
			
				|  |  | +        const data = {
 | 
	
		
			
				|  |  | +            compilationID,
 | 
	
		
			
				|  |  | +            ID: uuid.v1(),
 | 
	
		
			
				|  |  | +            name: '',
 | 
	
		
			
				|  |  | +        };
 | 
	
		
			
				|  |  | +        try {
 | 
	
		
			
				|  |  | +            $.bootstrapLoading.start();
 | 
	
		
			
				|  |  | +            await ajaxPost('/priceInfo/insertArea', { insertData: [data] });
 | 
	
		
			
				|  |  | +            // 新增的数据总是添加在最后
 | 
	
		
			
				|  |  | +            sheet.addRows(cache.length, 1);
 | 
	
		
			
				|  |  | +            cache.push(data);
 | 
	
		
			
				|  |  | +            const lastRow = cache.length - 1;
 | 
	
		
			
				|  |  | +            sheet.setSelection(lastRow, 0, 1, 1);
 | 
	
		
			
				|  |  | +            sheet.showRow(lastRow, GC.Spread.Sheets.VerticalPosition.top);
 | 
	
		
			
				|  |  | +            handleSelectionChanged(lastRow);
 | 
	
		
			
				|  |  | +        } catch (err) {
 | 
	
		
			
				|  |  | +            alert(err);
 | 
	
		
			
				|  |  | +        } finally {
 | 
	
		
			
				|  |  | +            $.bootstrapLoading.end();
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // 删除
 | 
	
		
			
				|  |  | +    async function del() {
 | 
	
		
			
				|  |  | +        try {
 | 
	
		
			
				|  |  | +            $.bootstrapLoading.start();
 | 
	
		
			
				|  |  | +            await ajaxPost('/priceInfo/deleteArea', { deleteData: [curArea.ID] });
 | 
	
		
			
				|  |  | +            const index = cache.findIndex(item => item.ID === curArea.ID);
 | 
	
		
			
				|  |  | +            sheet.deleteRows(index, 1);
 | 
	
		
			
				|  |  | +            cache.splice(index, 1);
 | 
	
		
			
				|  |  | +            const row = sheet.getActiveRowIndex();
 | 
	
		
			
				|  |  | +            handleSelectionChanged(row);
 | 
	
		
			
				|  |  | +        } catch (err) {
 | 
	
		
			
				|  |  | +            alert(err);
 | 
	
		
			
				|  |  | +        } finally {
 | 
	
		
			
				|  |  | +            $.bootstrapLoading.end();
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // 右键功能
 | 
	
		
			
				|  |  | +    function buildContextMenu() {
 | 
	
		
			
				|  |  | +        $.contextMenu({
 | 
	
		
			
				|  |  | +            selector: '#area-spread',
 | 
	
		
			
				|  |  | +            build: function ($triggerElement, e) {
 | 
	
		
			
				|  |  | +                // 控制允许右键菜单在哪个位置出现
 | 
	
		
			
				|  |  | +                const offset = $('#area-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();
 | 
	
		
			
				|  |  | +                        if (orgRow !== target.row) {
 | 
	
		
			
				|  |  | +                            sheet.setActiveCell(target.row, target.col);
 | 
	
		
			
				|  |  | +                            handleSelectionChanged(target.row);
 | 
	
		
			
				|  |  | +                        }
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                    return {
 | 
	
		
			
				|  |  | +                        items: {
 | 
	
		
			
				|  |  | +                            insert: {
 | 
	
		
			
				|  |  | +                                name: '新增',
 | 
	
		
			
				|  |  | +                                icon: "fa-arrow-left",
 | 
	
		
			
				|  |  | +                                disabled: function () {
 | 
	
		
			
				|  |  | +                                    return locked;
 | 
	
		
			
				|  |  | +                                },
 | 
	
		
			
				|  |  | +                                callback: function (key, opt) {
 | 
	
		
			
				|  |  | +                                    insert();
 | 
	
		
			
				|  |  | +                                }
 | 
	
		
			
				|  |  | +                            },
 | 
	
		
			
				|  |  | +                            del: {
 | 
	
		
			
				|  |  | +                                name: '删除',
 | 
	
		
			
				|  |  | +                                icon: "fa-arrow-left",
 | 
	
		
			
				|  |  | +                                disabled: function () {
 | 
	
		
			
				|  |  | +                                    return locked || !cache[target.row];
 | 
	
		
			
				|  |  | +                                },
 | 
	
		
			
				|  |  | +                                callback: function (key, opt) {
 | 
	
		
			
				|  |  | +                                    del();
 | 
	
		
			
				|  |  | +                                }
 | 
	
		
			
				|  |  | +                            },
 | 
	
		
			
				|  |  | +                        }
 | 
	
		
			
				|  |  | +                    };
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                else {
 | 
	
		
			
				|  |  | +                    return false;
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    buildContextMenu();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    return {
 | 
	
		
			
				|  |  | +        handleSelectionChanged,
 | 
	
		
			
				|  |  | +        curArea,
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +})();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 分类表
 | 
	
		
			
				|  |  | +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) {
 | 
	
		
			
				|  |  | +            console.log(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');
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // 插入
 | 
	
		
			
				|  |  | +    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) {
 | 
	
		
			
				|  |  | +            console.log(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) {
 | 
	
		
			
				|  |  | +        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);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    $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,'<br>'); //replaceAll('\n','<br>',data);
 | 
	
		
			
				|  |  | +              $("#result-info-body").html(htmlStr);
 | 
	
		
			
				|  |  | +              $("#result-info").modal('show');
 | 
	
		
			
				|  |  | +          }else{
 | 
	
		
			
				|  |  | +              alert('计算完成!')
 | 
	
		
			
				|  |  | +          }  
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        } catch (error) {
 | 
	
		
			
				|  |  | +            console.log(error);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        $.bootstrapLoading.end();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    }, DEBOUNCE_TIME, { leading: true }));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    return {
 | 
	
		
			
				|  |  | +        initData,
 | 
	
		
			
				|  |  | +        handleSelectionChanged,
 | 
	
		
			
				|  |  | +        curClass,
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +})();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 关键字表
 | 
	
		
			
				|  |  | +const KEYWORD_BOOK = (() => {
 | 
	
		
			
				|  |  | +    const setting = {
 | 
	
		
			
				|  |  | +        header: [
 | 
	
		
			
				|  |  | +            { headerName: '关键字', headerWidth: 200, dataCode: 'keyword', dataType: 'String', hAlign: 'left', vAlign: 'center' },
 | 
	
		
			
				|  |  | +            { headerName: '单位', headerWidth: 70, dataCode: 'unit', dataType: 'String', hAlign: 'center', vAlign: 'center' },
 | 
	
		
			
				|  |  | +            { headerName: '关键字效果', headerWidth: 100, dataCode: 'coe', dataType: 'String', hAlign: 'center', vAlign: 'center' },
 | 
	
		
			
				|  |  | +            { headerName: '组别', headerWidth: 50, dataCode: 'group', dataType: 'String', hAlign: 'center', vAlign: 'center' },
 | 
	
		
			
				|  |  | +            { headerName: '选项号', headerWidth: 70, dataCode: 'optionCode', dataType: 'String', hAlign: 'center', vAlign: 'center' },
 | 
	
		
			
				|  |  | +        ],
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +    // 初始化表格
 | 
	
		
			
				|  |  | +    const workBook = initSheet($('#keyword-spread')[0], setting);
 | 
	
		
			
				|  |  | +    workBook.options.allowUserDragDrop = false;
 | 
	
		
			
				|  |  | +    workBook.options.allowUserDragFill = false;
 | 
	
		
			
				|  |  | +    lockUtil.lockSpreads([workBook], true);
 | 
	
		
			
				|  |  | +    const sheet = workBook.getSheet(0);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // 显示关键字数据
 | 
	
		
			
				|  |  | +    const showKeywordData = (keywordList) => {
 | 
	
		
			
				|  |  | +        showData(sheet, keywordList, setting.header);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    return {
 | 
	
		
			
				|  |  | +        showKeywordData 
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +})();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 价格信息表
 | 
	
		
			
				|  |  | +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);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    // 初始化数据
 | 
	
		
			
				|  |  | +    async function initData(classIDList) {
 | 
	
		
			
				|  |  | +        if (!classIDList || !classIDList.length) {
 | 
	
		
			
				|  |  | +            return clear();
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        $.bootstrapLoading.start();
 | 
	
		
			
				|  |  | +        try {
 | 
	
		
			
				|  |  | +            cache = await ajaxPost('/priceInfo/getPriceData', { classIDList }, TIME_OUT);
 | 
	
		
			
				|  |  | +            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();
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // 获取当前表中行数据
 | 
	
		
			
				|  |  | +    function getRowData(sheet, row, headers) {
 | 
	
		
			
				|  |  | +        const item = {};
 | 
	
		
			
				|  |  | +        headers.forEach(({ dataCode }, index) => {
 | 
	
		
			
				|  |  | +            const value = sheet.getValue(row, index) || '';
 | 
	
		
			
				|  |  | +            if (value) {
 | 
	
		
			
				|  |  | +                item[dataCode] = value;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +        return item;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // 获取表数据和缓存数据的不同数据
 | 
	
		
			
				|  |  | +    function getRowDiffData(curRowData, cacheRowData, headers) {
 | 
	
		
			
				|  |  | +        let item = null;
 | 
	
		
			
				|  |  | +        headers.forEach(({ dataCode }) => {
 | 
	
		
			
				|  |  | +            const curValue = curRowData[dataCode];
 | 
	
		
			
				|  |  | +            const cacheValue = cacheRowData[dataCode];
 | 
	
		
			
				|  |  | +            if (!cacheValue && !curValue) {
 | 
	
		
			
				|  |  | +                return;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            if (cacheValue !== curValue) {
 | 
	
		
			
				|  |  | +                if (!item) {
 | 
	
		
			
				|  |  | +                    item = {};
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                item[dataCode] = curValue || '';
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +        return item;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // 编辑处理
 | 
	
		
			
				|  |  | +    async function handleEdit(changedCells) {
 | 
	
		
			
				|  |  | +        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, data: diffData });
 | 
	
		
			
				|  |  | +                            updateData.push({ row, data: diffData });
 | 
	
		
			
				|  |  | +                        }
 | 
	
		
			
				|  |  | +                    } else { // 该行无数据了,删除
 | 
	
		
			
				|  |  | +                        postData.push({ type: UpdateType.DELETE, ID: cache[row].ID });
 | 
	
		
			
				|  |  | +                        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, 5);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        } catch (err) {
 | 
	
		
			
				|  |  | +            // 恢复各单元格数据
 | 
	
		
			
				|  |  | +            showData(sheet, cache, setting.header, 5);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    sheet.bind(GC.Spread.Sheets.Events.ValueChanged, function (e, info) {
 | 
	
		
			
				|  |  | +        const changedCells = [{ row: info.row }];
 | 
	
		
			
				|  |  | +        handleEdit(changedCells);
 | 
	
		
			
				|  |  | +    });
 | 
	
		
			
				|  |  | +    sheet.bind(GC.Spread.Sheets.Events.SelectionChanged, function (e, info) {
 | 
	
		
			
				|  |  | +        const row = info.newSelections && info.newSelections[0] ? info.newSelections[0].row : 0;
 | 
	
		
			
				|  |  | +        // 显示关键字数据
 | 
	
		
			
				|  |  | +        const keywordList = cache[row] && cache[row].keywordList || [];
 | 
	
		
			
				|  |  | +        KEYWORD_BOOK.showKeywordData(keywordList);
 | 
	
		
			
				|  |  | +    });
 | 
	
		
			
				|  |  | +    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);
 | 
	
		
			
				|  |  | +    });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    return {
 | 
	
		
			
				|  |  | +        clear,
 | 
	
		
			
				|  |  | +        initData,
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +})();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +$(document).ready(() => {
 | 
	
		
			
				|  |  | +    console.log('进入信息价');
 | 
	
		
			
				|  |  | +    $('[data-toggle="tooltip"]').tooltip();
 | 
	
		
			
				|  |  | +    AREA_BOOK.handleSelectionChanged(0);
 | 
	
		
			
				|  |  | +    const $range = $(document.body);
 | 
	
		
			
				|  |  | +    lockUtil.lockTools($range, locked);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +});
 |