Explorar el Código

附属工程量,界面调整

MaiXinRong hace 1 día
padre
commit
5aceeee7f5

+ 388 - 0
app/public/js/ledger.js

@@ -205,6 +205,7 @@ $(document).ready(function() {
                     for (let i = 1; i <= addCount; i++) {
                         data.add.push({ lid: node.lid, pid: node.id, pcd_order: detailRange.length + i });
                     }
+                    if (first) data.select = first.id;
                 } else if (type === 'delete') {
                     data.del = [];
                     for (let iRow = 0; iRow < count; iRow++) {
@@ -504,6 +505,376 @@ $(document).ready(function() {
 
         return { detail, spread, sheet, refresh, loadCurDetailData, reloadCurDetailData }
     })();
+    const ancGclDetail = (function() {
+        const detail = createAncGclDetail({ id: 'id', masterId: 'ag_id', firstId: 'lid', secondId: 'pid', sort: [['agd_order', 'asc']]});
+        const spread = SpreadJsObj.createNewSpread($('#anc-gcl-detail-spread')[0]);
+        const sheet = spread.getActiveSheet();
+        const emptySetting = {
+            cols: [],
+            emptyRows: 3,
+            headRows: 1,
+            headRowHeight: [32],
+            defaultRowHeight: 21,
+            headerFont: '12px 微软雅黑',
+            font: '12px 微软雅黑',
+            frozenLineColor: '#93b5e4',
+            readOnly: readOnly,
+        };
+        const refresh = function() {
+            if (spread) spread.refresh();
+        };
+        let template;
+        const reloadCurDetailData = function() {
+            const curAncGcl = SpreadJsObj.getSelectObject(ancGclSheet);
+            const detailData = curAncGcl ? detail.getPartData(curAncGcl.id) || [] : [];
+            SpreadJsObj.loadSheetData(sheet, SpreadJsObj.DataType.Data, detailData);
+        };
+        const loadCurDetailData = function() {
+            const curAncGcl = SpreadJsObj.getSelectObject(ancGclSheet);
+            template = node ? posCalcTemplate.find(x => { return x.id === node.calc_template }) : null;
+            if (template) {
+                const specCol = template.spread_cache.cols.find(x => { return x.field === 'spec'; });
+                if (specCol) {
+                    specCol.comboItems = template.specValue.map(x => { return x.spec; });
+                    specCol.cellType = 'customizeCombo';
+                    specCol.cellTypeKey = 'specSelect';
+                    specCol.maxDrop = 10;
+                }
+                template.spread_cache.forceLoadEmpty = true;
+                template.spread_cache.readOnly = readOnly;
+                SpreadJsObj.initSheet(sheet, template.spread_cache);
+            } else {
+                SpreadJsObj.initSheet(sheet, emptySetting);
+            }
+            reloadCurDetailData();
+        };
+        const ctrlObj = {
+            afterPostData: function(result) {
+                detail.updateDatas(result.detail);
+                reloadCurDetailData();
+                if (result.ancGcl) {
+                    ancGcl.updateDatas(result.ancGcl);
+                    // todo 刷新附属工程量
+                }
+            },
+            baseOpr: function (type, addCount = 1) {
+                const data = {};
+
+                const detailRange = sheet.zh_data;
+                if (type !== 'insert' && (!detailRange || detailRange.length === 0)) return;
+
+                const sel = sheet.getSelections();
+                if (!sel[0]) return;
+
+                const row = sel[0].row, count = sel[0].rowCount;
+                const first = detailRange[row];
+                if (type === 'insert') {
+                    const node = SpreadJsObj.getSelectObject(posSheet);
+                    data.add = [];
+                    for (let i = 1; i <= addCount; i++) {
+                        data.add.push({ lid: node.lid, pid: node.id, pcd_order: detailRange.length + i });
+                    }
+                    if (first) data.select = first.id;
+                } else if (type === 'delete') {
+                    data.del = [];
+                    for (let iRow = 0; iRow < count; iRow++) {
+                        const detailData = detailRange[row + iRow];
+                        if (!detailData) continue;
+                        data.del.push(detailData.id);
+                    }
+
+                    if (data.del.length === 0) return;
+                } else if (type === 'up-move') {
+                    data.update = [];
+                    const pre = detailRange[row - 1];
+                    if (!pre) return;
+
+                    const preUpdate = { id: pre.id };
+                    for (let iRow = 0; iRow < count; iRow++) {
+                        const detailData = detailRange[iRow + row];
+                        if (!detailData) continue;
+                        data.update.push({ id: detailData.id, pcd_order: detailRange[iRow + row - 1].pcd_order });
+                        preUpdate.pcd_order = detailData.pcd_order;
+                    }
+                    data.update.push(preUpdate);
+
+                    if (data.update <= 1) return;
+                } else if (type === 'down-move') {
+                    data.update = [];
+                    const next = detailRange[row + count];
+                    if (!next) return;
+
+                    const nextUpdate = { id: next.id };
+                    for (let iRow = count - 1; iRow >= 0; iRow--) {
+                        const detailData = detailRange[iRow + row];
+                        if (!detailData) continue;
+
+                        data.update.push({ id: detailData.id, pcd_order: detailRange[iRow + row + 1].pcd_order});
+                        nextUpdate.pcd_order = detailData.pcd_order;
+                    }
+                    data.update.push(nextUpdate);
+
+                    if (data.update <= 1) return;
+                }
+
+                postData('/tender/' + getTenderId() + '/anc-gcl-calc/update', data, function(result) {
+                    ctrlObj.afterPostData(result);
+                    if (type !== 'delete') SpreadJsObj.locateData(sheet, first);
+                });
+            },
+            editStarting: function (e, info) {
+                ctrlObj.ledgerTreeNode = SpreadJsObj.getSelectObject(ledgerSheet);
+                ctrlObj.posNode = SpreadJsObj.getSelectObject(posSheet);
+                ctrlObj.ancGclNode = SpreadJsObj.getSelectObject(ancGclSheet);
+            },
+            editEnded: function (e, info) {
+                const setting = info.sheet.zh_setting;
+                if (!setting) return;
+                const detailData = SpreadJsObj.getSelectObject(info.sheet);
+
+                const col = setting.cols[info.col];
+                const orgText = detailData ? detailData[col.field] : '', newText = trimInvalidChar(info.editingText);
+                if (orgText === newText || (!orgText && !newText)) return;
+
+                const pos = ctrlObj.posNode;
+                if (!pos) {
+                    toastr.error('数据错误,请选择计量单元后再试');
+                    SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                    return;
+                }
+
+                const data = {};
+                if (detailData) {
+                    const updateData = { id: detailData.id };
+                    if (col.type === 'Number') {
+                        const num = _.toNumber(newText);
+                        if (!_.isFinite(num)) {
+                            try {
+                                updateData[col.field] = ZhCalc.mathCalcExpr(transExpr(newText));
+                            } catch (err) {
+                                toastr.error('输入的表达式非法');
+                                SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                                return;
+                            }
+                        } else {
+                            updateData[col.field] = num;
+                        }
+                    } else {
+                        updateData[col.field] = newText;
+                    }
+                    data.update = [ updateData ];
+                } else {
+                    const sortData = info.sheet.zh_data;
+                    const order = (!sortData || sortData.length === 0) ? 1 : Math.max(sortData[sortData.length - 1].pcd_order + 1, sortData.length + 1);
+                    const addData = { lid: pos.lid, pid: pos.id, pcd_order: order };
+                    if (col.type === 'Number') {
+                        const num = _.toNumber(newText);
+                        if (!_.isFinite(num)) {
+                            try {
+                                addData[col.field] = ZhCalc.mathCalcExpr(transExpr(newText));
+                            } catch (err) {
+                                toastr.error('输入的表达式非法');
+                                SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                                return;
+                            }
+                        } else {
+                            addData[col.field] = num;
+                        }
+                    } else {
+                        addData[col.field] = newText;
+                    }
+                    data.add = [addData];
+                }
+                postData('/tender/' + getTenderId() + '/pos-calc/update', data, function (result) {
+                    ctrlObj.afterPostData(result);
+                }, function () {
+                    SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                });
+            },
+            deletePress: function (sheet) {
+                const setting = sheet.zh_setting;
+                if (!setting) return;
+
+                const sortData = sheet.zh_data;
+                if (!sortData || sortData.length === 0) return;
+
+                const sel = sheet.getSelections()[0];
+                const data = { update: [] };
+                for (let iRow = sel.row; iRow < sel.row + sel.rowCount; iRow++) {
+                    let bDel = false;
+                    const node = sortData[iRow];
+                    if (!node) continue;
+
+                    const updateData = { id: node.id };
+                    for (let iCol = sel.col; iCol < sel.col + sel.colCount; iCol++) {
+                        const style = sheet.getStyle(iRow, iCol);
+                        if (style.locked) continue;
+
+                        const col = setting.cols[iCol];
+                        updateData[col.field] = col.type === 'Number' ? 0 : '';
+                        bDel = true;
+                    }
+                    if (bDel) data.update.push(updateData);
+                }
+                if (data.update.length === 0) return;
+
+                postData('/tender/' + getTenderId() + '/pos-calc/update', data, function (result) {
+                    ctrlObj.afterPostData(result);
+                }, function () {
+                    SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                });
+            },
+            clipboardPasting: function(e, info) {
+                info.cancel = true;
+                const relaPos = SpreadJsObj.getSelectObject(posSheet);
+                if (!relaPos) {
+                    toastr.error('数据错误,请选择计量单元后再试');
+                    SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                    return;
+                }
+
+                const hint = {
+                    num: {type: 'warning', msg: '输入的 数字 非法,已过滤'},
+                };
+                const setting = info.sheet.zh_setting;
+                const sortData = info.sheet.zh_data || [];
+                const pasteData = SpreadJsObj.analysisPasteText(info.pasteData.text);
+                const data = {};
+                const analysisData = function(pasteRow, targetData) {
+                    pasteRow.forEach((value, iCol) => {
+                        const col = setting.cols[info.cellRange.col + iCol];
+                        if (col.type === 'Number') {
+                            const num = _.toNumber(value);
+                            if (!_.isFinite(num)) {
+                                try {
+                                    targetData[col.field] = ZhCalc.mathCalcExpr(transExpr(value));
+                                } catch (err) {
+                                    toastr.error('输入的表达式非法');
+                                    SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                                    return;
+                                }
+                            } else {
+                                targetData[col.field] = num;
+                            }
+                        } else {
+                            targetData[col.field] = value;
+                        }
+                    });
+                };
+                for (let iRow = 0; iRow < pasteData.length; iRow++) {
+                    const curRow = iRow + info.cellRange.row;
+                    const detailData = sortData[curRow];
+                    if (detailData) {
+                        if (!data.update) data.update = [];
+                        const updateData = { id: detailData.id };
+                        analysisData(pasteData[iRow], updateData);
+                        data.update.push(updateData);
+                    } else {
+                        if (!data.add) data.add = [];
+                        const addData = { lid: relaPos.lid, pid: relaPos.id, pcd_order: curRow + 1};
+                        analysisData(pasteData[iRow], addData);
+                        data.add.push(addData);
+                    }
+                }
+                if ((!data.update || data.update.length === 0) && (!data.add || data.add.length === 0)) return;
+
+                postData('/tender/' + getTenderId() + '/pos-calc/update', data, function (result) {
+                    ctrlObj.afterPostData(result);
+                }, function () {
+                    SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                });
+            },
+        };
+        if (!readOnly) {
+            SpreadJsObj.addDeleteBind(spread, ctrlObj.deletePress);
+            spread.bind(spreadNS.Events.EditStarting, ctrlObj.editStarting);
+            spread.bind(spreadNS.Events.EditEnded, ctrlObj.editEnded);
+            spread.bind(spreadNS.Events.ClipboardPasting, ctrlObj.clipboardPasting);
+            $.contextMenu({
+                selector: '#pos-detail-spread',
+                build: function ($trigger, e) {
+                    const target = SpreadJsObj.safeRightClickSelection($trigger, e, spread);
+                    return target.hitTestType === GC.Spread.Sheets.SheetArea.viewport || target.hitTestType === GC.Spread.Sheets.SheetArea.rowHeader;
+                },
+                items: {
+                    'insert': {
+                        name: '插入',
+                        icon: 'fa-plus',
+                        disabled: function (key, opt) {
+                            const pos = SpreadJsObj.getSelectObject(posSheet);
+                            return !pos;
+                        },
+                        callback: function (key, opt) {
+                            ctrlObj.baseOpr('insert');
+                        }
+                    },
+                    'batchInsert': {
+                        name: '批量插入',
+                        type: 'batchInsert',
+                        value: '2',
+                        icon: 'fa-plus',
+                        disabled: function (key, opt) {
+                            const pos = SpreadJsObj.getSelectObject(posSheet);
+                            return !pos;
+                        },
+                        batchInsert: function (obj, root) {
+                            if (_.toNumber(obj.value) > _.toNumber(obj.max)) {
+                                obj.value = obj.max;
+                                toastr.warning('批量插入不可多于' + obj.max);
+                            } else if(_.toNumber(obj.value) < _.toNumber(obj.min)) {
+                                obj.value = obj.min;
+                                toastr.warning('批量插入不可少于' + obj.min);
+                            } else {
+                                ctrlObj.baseOpr('insert', parseInt(obj.value));
+                                root.$menu.trigger('contextmenu:hide');
+                            }
+                        },
+                    },
+                    'delete': {
+                        name: '删除',
+                        icon: 'fa-remove',
+                        disabled: function (key, opt) {
+                            const detailData = SpreadJsObj.getSelectObject(sheet);
+                            return !detailData;
+                        },
+                        callback: function (key, opt) {
+                            ctrlObj.baseOpr('delete');
+                        }
+                    },
+                    'down-move': {
+                        name: '下移',
+                        icon: 'fa-arrow-down',
+                        disabled: function(key, opt) {
+                            const sel = sheet.getSelections()[0];
+                            const row = sel ? sel.row : -1;
+                            const first = sheet.zh_data[row];
+                            const next = sheet.zh_data[sel.row + sel.rowCount];
+                            return !first || !next;
+                        },
+                        callback: function(key, opt) {
+                            ctrlObj.baseOpr('down-move');
+                        }
+                    },
+                    'up-move': {
+                        name: '上移',
+                        icon: 'fa-arrow-up',
+                        disabled: function(key, opt) {
+                            const sel = sheet.getSelections()[0];
+                            const row = sel ? sel.row : -1;
+                            const first = sheet.zh_data[row];
+                            const preNode = sheet.zh_data[row - 1];
+                            return !first || !preNode;
+                        },
+                        callback: function(key, opt) {
+                            ctrlObj.baseOpr('up-move');
+                        }
+                    },
+                }
+            });
+        }
+
+        return { detail, spread, sheet, refresh, loadCurDetailData, reloadCurDetailData }
+    })();
 
     const billsTag = $.billsTag({
         relaTree: ledgerTree,
@@ -528,6 +899,7 @@ $(document).ready(function() {
             ledgerSpread.refresh();
             if (posSpread) posSpread.refresh();
             if (ancGclSpread) ancGclSpread.refresh();
+            if (ancGclDetail) ancGclDetail.refresh();
             if (posCalcDetail) posCalcDetail.refresh();
         },
     });
@@ -544,6 +916,7 @@ $(document).ready(function() {
             ledgerSpread.refresh();
             if (posSpread) posSpread.refresh();
             if (ancGclSpread) ancGclSpread.refresh();
+            if (ancGclDetail) ancGclDetail.refresh();
             if (posCalcDetail) posCalcDetail.refresh();
         },
     });
@@ -562,6 +935,7 @@ $(document).ready(function() {
             ledgerSpread.refresh();
             if (posSpread) posSpread.refresh();
             if (ancGclSpread) ancGclSpread.refresh();
+            if (ancGclDetail) ancGclDetail.refresh();
             if (posCalcDetail) posCalcDetail.refresh();
         },
     });
@@ -1604,6 +1978,7 @@ $(document).ready(function() {
             ledgerSpread.refresh();
             if (posSpread) posSpread.refresh();
             if (ancGclSpread) ancGclSpread.refresh();
+            if (ancGclDetail) ancGclDetail.refresh();
             if (posCalcDetail) posCalcDetail.refresh();
             if (stdXmj) stdXmj.spread.refresh();
             if (stdGcl) stdGcl.spread.refresh();
@@ -2450,6 +2825,7 @@ $(document).ready(function() {
                 $(".sp-wrap").height(bcontent-30);
                 posSpread.refresh();
                 if (ancGclSpread) ancGclSpread.refresh();
+                if (ancGclDetail) ancGclDetail.refresh();
                 if (posCalcDetail) posCalcDetail.refresh();
             }
         });
@@ -2465,6 +2841,7 @@ $(document).ready(function() {
             ledgerSpread.refresh();
             posSpread.refresh();
             if (ancGclSpread) ancGclSpread.refresh();
+            if (ancGclDetail) ancGclDetail.refresh();
             if (posCalcDetail) posCalcDetail.refresh();
         };
         const reloadPosDisplayCache = function () {
@@ -3643,6 +4020,7 @@ $(document).ready(function() {
             ledgerSpread.refresh();
             if (posSpread) posSpread.refresh();
             if (ancGclSpread) ancGclSpread.refresh();
+            if (ancGclDetail) ancGclDetail.refresh();
             if (posCalcDetail) posCalcDetail.refresh();
             if (stdXmj) stdXmj.spread.refresh();
             if (stdGcl) stdGcl.spread.refresh();
@@ -3894,6 +4272,7 @@ $(document).ready(function() {
             posSpread.refresh();
         }
         if (ancGclSpread) ancGclSpread.refresh();
+        if (ancGclDetail) ancGclDetail.refresh();
         if (posCalcDetail) posCalcDetail.refresh();
     });
     class DealBills {
@@ -4887,6 +5266,7 @@ $(document).ready(function() {
         }
         if (posSpread) posSpread.refresh();
         if (ancGclSpread) ancGclSpread.refresh();
+        if (ancGclDetail) ancGclDetail.refresh();
         if (posCalcDetail) posCalcDetail.refresh();
     });
     $.divResizer({
@@ -4894,9 +5274,17 @@ $(document).ready(function() {
         callback: function () {
             if (posSpread) posSpread.refresh();
             if (ancGclSpread) ancGclSpread.refresh();
+            if (ancGclDetail) ancGclDetail.refresh();
             if (posCalcDetail) posCalcDetail.refresh();
         }
     });
+    $.divResizer({
+        select: '#anc-gcl-spr',
+        callback: function () {
+            if (ancGclSpread) ancGclSpread.refresh();
+            if (ancGclDetail) ancGclDetail.refresh();
+        }
+    });
 
     // $('#searchAccount').click(() => {
     //     const data = {

+ 185 - 1
app/public/js/path_tree.js

@@ -2475,7 +2475,191 @@ const createPosCalcDetail = function (setting) {
             if (topRange) {
                 delete this.topIndex[topKey];
                 for (const tr of topRange) {
-                    this.removeDatasByTopId(tr);
+                    this.removeDatasByMasterId(tr);
+                }
+            }
+        }
+
+        getItem(id) {
+            return this.items[this.itemPre + id];
+        }
+
+        getPartData(mid) {
+            return this.masterIndex[this.itemPre + mid];
+        }
+
+        set sort(sort) {
+            this.setting.sort = sort;
+            for (const key in this.masterIndex) {
+                this.resortPart(this.masterIndex[key]);
+            }
+        }
+    }
+
+    return new PosCalcDetail(setting);
+};
+
+const createAncGclDetail = function (setting) {
+    class PosCalcDetail {
+        constructor(setting) {
+            this.itemPre = 'id_';
+            // 无索引
+            this.datas = [];
+            // 以key为索引
+            this.items = {};
+            // 以分类id为索引的有序
+            this.masterIndex = {}; // posCalcDetail ---ag_id---> ancGcl
+            this.secondIndex = {}; // ag_id --- pid ---> pos
+            this.firstIndex = {}; // ag_id --- pid --- lid ---> bills
+            // 设置
+            this.setting = setting;
+        }
+
+        resortPart(partData) {
+            const sortRule = this.setting.sort || [['agd_order', 'asc']];
+            if (partData instanceof Array) {
+                partData.sort(function (a, b) {
+                    for (const sr of sortRule) {
+                        const iSort = sr[1] === 'asc' ? a[sr[0]] - b[sr[0]] : b[sr[0]] - a[sr[0]];
+                        if (iSort) return iSort;
+                    }
+                })
+            }
+        }
+
+        /**
+         * 加载数据
+         * @param datas
+         */
+        loadDatas(datas) {
+            this.datas = datas;
+            this.items = {};
+            this.masterIndex = {};
+            this.secondIndex = {};
+            this.firstIndex = {};
+            for (const data of this.datas) {
+                const key = this.itemPre + data[this.setting.id];
+                this.items[key] = data;
+
+                const masterKey = this.itemPre + data[this.setting.masterId];
+                if (!this.masterIndex[masterKey]) {
+                    this.masterIndex[masterKey] = [];
+                }
+                this.masterIndex[masterKey].push(data);
+
+                const secondKey = this.itemPre + data[this.setting.secondId];
+                if (!this.secondIndex[secondKey]) this.secondIndex[secondKey] = [];
+                if (this.secondIndex[secondKey].indexOf(data[this.setting.masterId]) < 0) this.secondIndex[secondKey].push(data[this.setting.masterId]);
+
+                const firstKey = this.itemPre + data[this.setting.firstId];
+                if (!this.firstIndex[firstKey]) this.firstIndex[firstKey] = [];
+                if (this.firstIndex[firstKey].indexOf(data[this.setting.secondId]) < 0) this.firstIndex[firstKey].push(data[this.setting.secondId]);
+            }
+            for (const prop in this.masterIndex) {
+                this.resortPart(this.masterIndex[prop]);
+            }
+        }
+
+        _addDatas(data, resort) {
+            const datas = data instanceof Array ? data : [data];
+            for (const d of datas) {
+                const key = this.itemPre + d[this.setting.id];
+                this.items[key] = d;
+
+                const masterKey = this.itemPre + d[this.setting.masterId];
+                if (!this.masterIndex[masterKey]) this.masterIndex[masterKey] = [];
+                this.masterIndex[masterKey].push(d);
+                if (resort.indexOf(masterKey) < 0) resort.push(masterKey);
+
+                const secondKey = this.itemPre + data[this.setting.secondId];
+                if (!this.secondIndex[secondKey]) this.secondIndex[secondKey] = [];
+                if (this.secondIndex[secondKey].indexOf(data[this.setting.masterId]) < 0) this.secondIndex[secondKey].push(data[this.setting.masterId]);
+
+                const firstKey = this.itemPre + data[this.setting.firstId];
+                if (!this.firstIndex[firstKey]) this.firstIndex[firstKey] = [];
+                if (this.firstIndex[firstKey].indexOf(data[this.setting.secondId]) < 0) this.firstIndex[firstKey].push(data[this.setting.secondId]);
+            }
+        }
+
+        /**
+         * 更新数据
+         * @param datas
+         */
+        _updateDatas(data, resort) {
+            const datas = data instanceof Array ? data : [data];
+            for (const d of datas) {
+                const item = this.getItem(d[this.setting.id]);
+                if (!item) continue;
+                for (const prop in d) {
+                    item[prop] = d[prop];
+                }
+                const masterKey = this.itemPre + item[this.setting.masterId];
+                if (resort.indexOf(masterKey) < 0) resort.push(masterKey);
+            }
+
+        }
+
+        /**
+         * 移除数据
+         * @param datas
+         */
+        _removeDatas(data, resort) {
+            if (!data) { return; }
+            const datas = data instanceof Array ? data : [data];
+            for (let i = datas.length - 1; i >= 0; i--) {
+                const id = datas[i];
+                const d = this.getItem(id);
+                this.datas.splice(this.datas.indexOf(d), 1);
+                const key = this.itemPre + d[this.setting.id];
+                delete this.items[key];
+                const range = this.getPartData(d[this.setting.masterId]);
+                range.splice(range.indexOf(d), 1);
+            }
+        }
+
+        updateDatas(data) {
+            const resort = [];
+            if (data.add) this._addDatas(data.add, resort);
+            if (data.del) this._removeDatas(data.del, resort);
+            if (data.update) this._updateDatas(data.update, resort);
+            for (const s of resort) {
+                this.resortPart(this.masterIndex[s]);
+            }
+        }
+
+        /**
+         * 移除数据 - 根据分类id
+         * @param mid
+         */
+        removeDatasByMasterId(mid) {
+            const masterKey = this.itemPre + mid;
+            const range = this.masterIndex[masterKey];
+            if (range) {
+                delete this.masterIndex[masterKey];
+                for (const r of range) {
+                    this.datas.splice(this.datas.indexOf(r), 1);
+                    const key = this.itemPre + r[this.setting.id];
+                    delete this.items[key];
+                }
+            }
+        }
+        removeDatasBySecondId(secondId) {
+            const secondKey = this.itemPre + secondId;
+            const secondRange = this.secondIndex[secondKey];
+            if (secondRange) {
+                delete this.secondIndex[secondKey];
+                for (const tr of secondRange) {
+                    this.removeDatasByMasterId(tr);
+                }
+            }
+        }
+        removeDatasByFirstId(firstId) {
+            const firstKey = this.itemPre + firstId;
+            const firstRange = this.secondIndex[firstKey];
+            if (firstRange) {
+                delete this.secondIndex[firstKey];
+                for (const tr of firstRange) {
+                    this.removeDatasBySecondId(tr);
                 }
             }
         }

+ 4 - 2
app/service/calc_tmpl.js

@@ -35,9 +35,11 @@ const PosCalc = (function(){
     const ValidColInfo = [
         { key: 'str', name: '文本', fields: ['str1', 'str2', 'str3', 'str4'], valid: ['title', 'width'], def: { title: '文字', width: 80, type: 'str'} },
         {
-            key: 'num', name: '数值',
+            key: 'num', name: '数值/计算',
             fields: ['num_a', 'num_b', 'num_c', 'num_d', 'num_e', 'num_f', 'num_g', 'num_h', 'num_i', 'num_j', 'num_k', 'num_l', 'num_m', 'num_n', 'num_o', 'num_p', 'num_q', 'num_r', 'num_s', 'num_t', 'num_u'], // 'num_v', 'num_w', 'num_x', 'num_y', 'num_z'],
-            valid: ['title', 'width', 'calc_code', 'decimal', 'unit'], def: { title: '数值', width: 80, decimal: 2, type: 'num', unit: ''} },
+            valid: ['title', 'width', 'calc_code', 'decimal', 'unit', 'expr'],
+            def: { title: '数值', width: 80, decimal: 2, type: 'num', unit: ''}
+        },
         { key: 'spec', name: '规格', fields: ['spec'], valid: ['title', 'width', 'rela_col', 'spec_set'], def: { title: '规格', width: 80, rela_col: '', type: 'spec'} },
         { key: 'qty', name: '数量', fields: ['qty'], valid: ['title', 'width', 'expr', 'decimal'], def: { title: '数量', width: 80, decimal: 2, expr: '', type: 'qty' } },
     ];

+ 23 - 6
app/service/pos_calc_detail.js

@@ -136,7 +136,7 @@ module.exports = app => {
             }
         }
 
-        async _addDatas(data, calcMaster) {
+        async _addDatas(data, selectId) {
             const user_id = this.ctx.session.sessionUser.accountId;
 
             const datas = data instanceof Array ? data : [data];
@@ -144,24 +144,39 @@ module.exports = app => {
             if (!le.calc_template) throw '未定义计算模板,请先在清单处选择计算模板';
             const calcTemplate = await this.ctx.service.calcTmpl.getTemplate(le.calc_template);
             if (!calcTemplate) throw '计算模板不存在';
+            const posDetail = await this.getAllDataByCondition({ where: { tid: this.ctx.tender.id, pid: datas[0].pid }, orders: [['pcd_order', 'ASC']] });
+            const selectIndex = selectId ? posDetail.findIndex(x => { return x.id === selectId; }) : -1;
+            if (selectId && selectIndex < 0) throw '选择的数据不存在';
+            const startOrder = selectId
+                ? (selectIndex > 0 ? posDetail[selectIndex - 1].pcd_order : 0)
+                : (posDetail.length > 0 ? posDetail[posDetail.length - 1].pcd_order : 0);
 
-            const insertData = [];
+            const insertData = [], updateData = [];
             let isCalc = false;
-            for (const d of datas) {
+            for (const [i, d] of datas.entries()) {
                 if (!d.lid || !d.pid || !d.pcd_order) throw '新增其他数据,提交的数据错误';
                 const nd = {
                     id: this.uuid.v4(), tid: this.ctx.tender.id,
                     create_user_id: user_id, update_user_id: user_id,
-                    lid: d.lid, pid: d.pid, pcd_order: d.pcd_order,
+                    lid: d.lid, pid: d.pid, pcd_order: startOrder + i + 1,
                 };
                 if (this._loadDataAndCalc(nd, d, {}, calcTemplate)) isCalc = true;
                 insertData.push(nd);
             }
             const [posUpdate, billsUpdate] = await this._getBillsPosUpdateData(insertData, insertData[0].pid, insertData[0].lid, isCalc);
+            if (selectIndex >= 0) {
+                const maxOrder = insertData[insertData.length - 1].pcd_order;
+                for (const p of posDetail) {
+                    if (p.pcd_order > startOrder) {
+                        updateData.push({ id: p.id, pcd_order: maxOrder + updateData.length + 1 });
+                    }
+                }
+            }
 
             const conn = await this.db.beginTransaction();
             try {
                 await conn.insert(this.tableName, insertData);
+                if (updateData.length > 0) await conn.updateRows(this.tableName, updateData);
                 if (posUpdate) await conn.update(this.ctx.service.pos.tableName, posUpdate);
                 if (billsUpdate) await conn.update(this.ctx.service.ledger.tableName, billsUpdate);
                 await conn.commit();
@@ -174,7 +189,7 @@ module.exports = app => {
             });
             const posData = isCalc ? await this.ctx.service.pos.getDataById(addData[0].pid) : null;
             const ledgerData = isCalc ? await this.ctx.service.ledger.getDataById(addData[0].lid) : null;
-            return [addData, posData, ledgerData]
+            return [addData, updateData, posData, ledgerData]
         }
         async _delDatas (data) {
             if (!data || data.length === 0) throw '提交数据错误';
@@ -259,10 +274,12 @@ module.exports = app => {
             const result = { detail: {add: [], del: [], update: []}, pos: null, bills: null };
             try {
                 if (data.add) {
-                    [result.detail.add, result.pos, result.bills] = await this._addDatas(data.add);
+                    [result.detail.add, result.detail.update, result.pos, result.bills] = await this._addDatas(data.add, data.select);
                 }
                 if (data.update) {
+                    const orgUpdate = result.detail.update;
                     [result.detail.update, result.pos, result.bills] = await this._updateDatas(data.update);
+                    if (orgUpdate.length > 0) result.detail.update.push(...orgUpdate);
                 }
                 if (data.del) {
                     [result.detail.del, result.detail.update, result.pos, result.bills] = await this._delDatas(data.del);

+ 6 - 2
app/view/ledger/explode.ejs

@@ -103,7 +103,7 @@
             <div class="c-body" id="left-view" style="width: 100%">
                 <div id="ledger-spread" class="sjs-height-1"></div>
                 <% if (tender.measure_type === measureType.tz.value) { %>
-                <div class="bcontent-wrap" id="main-bottom">
+                <div class="bcontent-wrap" id="main-bottom" <% if (tenderInfo.display.ledger.ancillaryGcl) {%>style="height: 500px;"<% } %>>
                     <div id="main-resize" class="resize-y" id="top-spr" r-Type="height" div1=".sjs-height-1" div2=".bcontent-wrap" r-parent="div2" title="调整大小"><!--调整上下高度条--></div>
                     <div class="bc-bar mb-1 d-flex">
                         <div class="d-inline-block">
@@ -159,7 +159,11 @@
                             <div class="resize-x" id="pos-right-spr" r-Type="width" div1="#pos-spread" div2="#pos-right" title="调整大小" a-type="percent"><!--调整左右高度条--></div>
                             <div class="tab-content sp-wrap">
                                 <div id="anc-gcl" class="tab-pane table-select-show">
-                                    <div class="sp-wrap" id="anc-gcl-spread">
+                                    <div id="anc-gcl-spread" style="height: 235px;">
+                                    </div>
+                                    <div id="anc-gcl-detail" style="height: 235px;">
+                                        <div id="anc-gcl-spr" class="resize-y" r-Type="height" div1="#anc-gcl-spread" div2="#anc-gcl-detail" r-parent="div2" title="调整大小"><!--调整上下高度条--></div>
+                                        <div id="anc-gcl-detail-spread" class="w-100 h-100"></div>
                                     </div>
                                 </div>
                                 <div id="pos-detail" class="tab-pane table-select-show">