Pārlūkot izejas kodu

变更部位功能提交

laiguoran 3 gadi atpakaļ
vecāks
revīzija
71db7f1b9c

+ 2 - 2
app/base/base_bills_service.js

@@ -563,7 +563,7 @@ class BaseBillsSerivce extends TreeService {
             });
             if (pd[0].ledger_pid !== pasteData[0][0].ledger_pid) throw '复制数据错误:仅可操作同层节点';
         }
-
+        this.newBills = false;
         const selectData = await this.getDataByKid(tid, sid);
         if (!selectData) throw '粘贴数据错误';
         const newParentPath = selectData.full_path.replace(selectData.ledger_id, '');
@@ -698,4 +698,4 @@ class BaseBillsSerivce extends TreeService {
 
 }
 
-module.exports = BaseBillsSerivce;
+module.exports = BaseBillsSerivce;

+ 1 - 1
app/base/base_tree_service.js

@@ -1112,4 +1112,4 @@ class TreeService extends Service {
 
 }
 
-module.exports = TreeService;
+module.exports = TreeService;

+ 278 - 2
app/controller/change_controller.js

@@ -7,7 +7,11 @@
  * @date 2018/8/14
  * @version
  */
-
+const stdDataAddType = {
+    withParent: 1,
+    child: 2,
+    next: 3,
+};
 const moment = require('moment');
 const sendToWormhole = require('stream-wormhole');
 const fs = require('fs');
@@ -17,6 +21,9 @@ const codeRuleConst = require('../const/code_rule');
 const changeConst = require('../const/change');
 const accountGroup = require('../const/account_group').group;
 const shenpiConst = require('../const/shenpi');
+const tenderMenu = require('../../config/menu').tenderMenu;
+const measureType = require('../const/tender').measureType;
+const spreadConst = require('../const/spread');
 // const tenderMenu = require('../../config/menu').tenderMenu;
 
 module.exports = app => {
@@ -774,6 +781,11 @@ module.exports = app => {
                         // 取所有工料表
                         responseData.data = await ctx.service.changeAuditList.getList(ctx.change.cid);
                         break;
+                    case 'update_list':
+                        await ctx.service.changeAuditList.saveDatas(data.updateData);
+                        // 取所有工料表
+                        // responseData.data = await ctx.service.changeAuditList.getList(ctx.change.cid);
+                        break;
                     case 'info':
                         await ctx.service.change.saveInfo(data.updateData);
                         // 取所有工料表
@@ -921,9 +933,11 @@ module.exports = app => {
         async defaultBills(ctx) {
             try {
                 const ledgerData = await ctx.service.ledger.getData(ctx.tender.id);
+                const changeLedgerData = await ctx.service.changeLedger.getData(ctx.tender.id);
                 const posData = await ctx.service.pos.getPosData({ tid: ctx.tender.id });
+                const changePosData = await ctx.service.changePos.getPosData({ tid: ctx.tender.id });
                 const dealBills = await ctx.service.dealBills.getAllDataByCondition({ where: { tender_id: ctx.tender.id } });
-                ctx.body = { err: 0, msg: '', data: { bills: ledgerData, pos: posData, dealBills } };
+                ctx.body = { err: 0, msg: '', data: { bills: ctx.helper._.concat(ledgerData, changeLedgerData), pos: ctx.helper._.concat(posData, changePosData), dealBills } };
             } catch (err) {
                 this.log(err);
                 ctx.body = { err: 1, msg: err.toString(), data: [] };
@@ -1477,6 +1491,268 @@ module.exports = app => {
             }
             ctx.body = responseData;
         }
+
+        /**
+         * 修订 详细页面(Get)
+         * @param ctx
+         * @return {Promise<void>}
+         */
+        async reviseInfo(ctx) {
+            try {
+                const change = ctx.change;
+                let edit = true;
+                if (change.status !== audit.flow.status.uncheck && change.status !== audit.flow.status.backnew) {
+                    // throw '本条变更审批中或已完成,无法操作台账数据';
+                    edit = false;
+                }
+                // 判断是否在修订中,是则无法操作本页
+                const lastRevise = await ctx.service.ledgerRevise.getLastestRevise(ctx.tender.id);
+                if (lastRevise && lastRevise.status !== audit.revise.status.checked) {
+                    // throw '台账修订中,无法操作台账数据';
+                    edit = false;
+                }
+                const renderData = await this._getDefaultReviseInfoData(ctx, change);
+                // 台账只读、使用数据
+                renderData.readOnly = edit;
+                // renderData.readOnly = false;
+                await this.layout('change/revise.ejs', renderData, 'change/revise_modal.ejs');
+            } catch (err) {
+                this.log(err);
+                ctx.redirect(ctx.request.header.referer);
+            }
+        }
+
+        async _getDefaultReviseInfoData(ctx, change) {
+            const [ledgerSpread, posSpread] = this._getSpreadSetting(change);
+            const sjsRela = await this.ctx.service.project.getSjsRela(ctx.session.sessionProject.id);
+            this.ctx.helper.refreshSpreadShow(sjsRela.ledgerCol, [ledgerSpread, posSpread]);
+            const [stdBills, stdChapters] = await this.ctx.service.valuation.getValuationStdList(
+                ctx.tender.data.valuation, ctx.tender.data.measure_type);
+            return {
+                change,
+                tender: ctx.tender.data,
+                ledgerSpread, posSpread, tenderMenu, measureType,
+                preUrl: '/tender/' + ctx.tender.id + '/change/' + ctx.change.cid + '/information',
+                jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.change.revise),
+                stdBills,
+                auditConst: audit.flow,
+                audit: audit.flow,
+                stdChapters,
+            };
+        }
+
+        /**
+         * 获取SpreadSetting
+         * @private
+         */
+        _getSpreadSetting(change) {
+            const _ = this.app._;
+            function removeFieldCols(setting, cols) {
+                _.remove(setting.cols, function(c) {
+                    return cols.indexOf(c.field) > -1;
+                });
+            }
+            const tender = this.ctx.tender;
+            const setting = tender.data.measure_type === measureType.tz.value
+                ? (tender.info.display.ledger.clQty ? spreadConst.withCl : spreadConst.withoutCl)
+                : (tender.info.display.ledger.clQty ? spreadConst.withClGcl : spreadConst.withoutClGcl);
+            const ledger = JSON.parse(JSON.stringify(setting.ledger));
+            const pos = setting.pos ? JSON.parse(JSON.stringify(setting.pos)) : spreadConst.blank;
+
+            if (change.status === audit.flow.status.checking || change.status === audit.flow.status.checked) {
+                ledger.readOnly = true;
+                pos.readOnly = true;
+            }
+            if (tender.data.measure_type === measureType.tz.value) {
+                removeFieldCols(ledger, spreadConst.filterCols.tzWithoutCols);
+            }
+            if (!tender.info.display.ledger.dgnQty) {
+                removeFieldCols(ledger, spreadConst.filterCols.dgnCols);
+            }
+            return [ledger, pos];
+        }
+
+        async updateRevise(ctx) {
+            try {
+                if (!ctx.tender.data) throw '标段数据错误';
+                const data = JSON.parse(ctx.request.body.data);
+                if (!data.postType || !data.postData) throw '数据错误';
+                const responseData = { err: 0, msg: '', data: {} };
+                console.log(data);
+
+                // const revise = await this.checkRevise(ctx);
+                //
+                switch (data.postType) {
+                    case 'add':
+                    case 'delete':
+                    case 'up-move':
+                    case 'down-move':
+                    case 'up-level':
+                    case 'down-level':
+                        responseData.data = await this._billsBase(ctx, data.postType, data.postData);
+                        break;
+                    case 'update':
+                        ctx.helper.checkDgnQtyPrecision(data.postData);
+                        responseData.data = await ctx.service.changeLedger.updateCalc(ctx.tender.id, data.postData);
+                        break;
+                    case 'paste-block':
+                        responseData.data = await this._pasteBlock(ctx, data.postData);
+                        break;
+                    case 'add-std':
+                        responseData.data = await this._addStd(ctx, data.postData);
+                        break;
+                    case 'add-deal':
+                        responseData.data = await this._addDeal(ctx, data.postData);
+                        break;
+                    // case 'batch-insert':
+                    //     responseData.data = await this._batchInsert(ctx, data.postData);
+                    //     break;
+                    case 'pos':
+                        responseData.data = await this._updatePos(ctx, data);
+                        break;
+                    default:
+                        throw '未知操作';
+                }
+                ctx.body = responseData;
+            } catch (err) {
+                this.log(err);
+                ctx.body = this.ajaxErrorBody(err, '数据错误');
+            }
+        }
+
+        async _billsBase(ctx, type, data) {
+            if (isNaN(data.id) || data.id <= 0) throw '数据错误';
+            if (type !== 'add') {
+                if (isNaN(data.count) || data.count <= 0) data.count = 1;
+            }
+            switch (type) {
+                case 'add':
+                    return await ctx.service.changeLedger.addNodeBatch(ctx.tender.id, data.id, { ccid: ctx.change.cid, check_calc: 1 }, data.count);
+                case 'delete':
+                    return await ctx.service.changeLedger.delete(ctx.tender.id, data.id, data.count);
+                case 'up-move':
+                    return await ctx.service.changeLedger.upMoveNode(ctx.tender.id, data.id, data.count);
+                case 'down-move':
+                    return await ctx.service.changeLedger.downMoveNode(ctx.tender.id, data.id, data.count);
+                case 'up-level':
+                    return await ctx.service.changeLedger.upLevelNode(ctx.tender.id, data.id, data.count);
+                case 'down-level':
+                    return await ctx.service.changeLedger.downLevelNode(ctx.tender.id, data.id, data.count);
+                default:
+                    throw '未知操作';
+            }
+        }
+        /**
+         * 复制粘贴整块
+         *
+         * @param ctx
+         * @return {Promise<void>}
+         */
+        async _pasteBlock(ctx, data) {
+            if ((isNaN(data.id) || data.id <= 0) ||
+                (!data.tid && data.tid <= 0) ||
+                (!data.block || data.block.length <= 0)) throw '参数错误';
+            return await ctx.service.changeLedger.pasteBlockData(ctx.tender.id, data.id, data.block);
+        }
+        /**
+         * 从标准项目表添加数据
+         * @param ctx
+         * @return {Promise<void>}
+         */
+        async _addStd(ctx, data) {
+            if ((isNaN(data.id) || data.id <= 0) || !data.stdType || !data.stdNode) throw '参数错误';
+            // todo 校验项目是否使用该库的权限
+
+            let stdLib,
+                addType;
+            switch (data.stdType) {
+                case 'xmj':
+                    stdLib = ctx.service.stdXmj;
+                    addType = stdDataAddType.withParent;
+                    break;
+                case 'gcl':
+                    stdLib = ctx.service.stdGcl;
+                    const selectNode = await ctx.service.changeLedger.getDataByNodeId(ctx.tender.id, data.id) || await ctx.service.ledger.getDataByNodeId(ctx.tender.id, data.id);
+                    if (selectNode.b_code) {
+                        addType = stdDataAddType.next;
+                    } else {
+                        addType = stdDataAddType.child;
+                    }
+                    break;
+                default:
+                    throw '未知标准库';
+            }
+            const stdData = await stdLib.getDataByDataId(data.stdLibId, data.stdNode);
+            switch (addType) {
+                case stdDataAddType.child:
+                    return await ctx.service.changeLedger.addStdNodeAsChild(ctx.tender.id, data.id, stdData, ctx.change.cid);
+                case stdDataAddType.next:
+                    return await ctx.service.changeLedger.addStdNode(ctx.tender.id, data.id, stdData, ctx.change.cid);
+                case stdDataAddType.withParent:
+                    return await ctx.service.changeLedger.addStdNodeWithParent(ctx.tender.id, stdData, stdLib, ctx.change.cid);
+                default:
+                    throw '未知添加方式';
+            }
+        }
+        /**
+         * 从签约清单添加节点
+         * @param ctx
+         * @return {Promise<void>}
+         */
+        async _addDeal(ctx, data) {
+            if (!data.type || !data.dealBills) throw '数据错误';
+            data.dealBills.unit_price = this.ctx.helper.round(data.dealBills.unit_price, ctx.tender.info.decimal.up);
+            if (data.type === 'child') {
+                return await ctx.service.changeLedger.addChild(ctx.tender.id, data.id, data.dealBills, ctx.change.cid);
+            } else if (data.type === 'next') {
+                data.dealBills.ccid = ctx.change.cid;
+                return await ctx.service.changeLedger.addNode(ctx.tender.id, data.id, data.dealBills);
+            }
+            throw '数据错误';
+
+        }
+        /**
+         * 批量插入数据
+         *
+         * data = {id, batchData, batchType}
+         * data.batchType = 'batchInsertChild'/'batchInsertNext'
+         * data.batchData = [{name, children}] -- 项目节列表
+         * data.batchData.children = [{code, name, unit, unit_price, quantity}] -- 工程量清单列表
+         *
+         * @param ctx
+         * @return {Promise<void>}
+         */
+        async _batchInsert(ctx, data) {
+            if ((isNaN(data.id) || data.id <= 0) || !data.batchType) throw '参数错误';
+
+            switch (data.batchType) {
+                case 'child':
+                    return await ctx.service.changeLedger.batchInsertChild(ctx.tender.id, data.id, data.batchData);
+                case 'next':
+                    return await ctx.service.changeLedger.batchInsertNext(ctx.tender.id, data.id, data.batchData);
+                default:
+                    throw '参数错误';
+            }
+        }
+        async _updatePos(ctx, data) {
+            await this.checkMeasureType(measureType.tz.value);
+            if (!data.posPostType) throw '数据错误';
+            switch (data.posPostType) {
+                case 'add':
+                    return await this.ctx.service.changePos.addPos(ctx.tender.id, ctx.change.cid, data.postData);
+                case 'update':
+                    if (data.postData instanceof Array) {
+                        return await this.ctx.service.changePos.updatePosArr(ctx.tender.id, data.postData);
+                    }
+                    return await this.ctx.service.changePos.updatePos(ctx.tender.id, data.postData);
+                case 'delete':
+                    return await this.ctx.service.changePos.deletePos(ctx.tender.id, data.postData);
+                case 'paste':
+                    return await this.ctx.service.changePos.pastePosData(ctx.tender.id, ctx.change.cid, data.postData);
+                default:
+                    throw '未知操作';
+            }
+        }
     }
 
     return ChangeController;

+ 50 - 14
app/public/js/change_information_set.js

@@ -625,7 +625,7 @@ $(document).ready(() => {
         const isCheck = $(this).hasClass('table-success') ? true : false;
         const data_bwmx = $(this).attr('data-bwmx').split('$#$');
         const isDeal = $(this).data('gcl') !== undefined ? true : false;
-        let codeHtml = '<tr quantity="'+ $(this).children('td').eq(5).text() +'" gcl_id=""><td colspan="7" class="colspan_1">&nbsp;</td><td class="colspan_2"><input type="checkbox"></td></tr>';
+        let codeHtml = '<tr quantity="'+ $(this).children('td').eq(5).text() +'" gcl_id="" mx_id=""><td colspan="7" class="colspan_1">&nbsp;</td><td class="colspan_2"><input type="checkbox"></td></tr>';
         if (isDeal) {
             const lid = $(this).data('lid');
             let gcl = _.find(gclGatherData, function (item) {
@@ -638,27 +638,28 @@ $(document).ready(() => {
             for (const leaf of gcl.leafXmjs) {
                 const quantity = leaf.quantity !== undefined && leaf.quantity !== null ? leaf.quantity : 0;
                 const gcl_id = leaf.gcl_id ? leaf.gcl_id : '';
-                const bwmx = leaf.bwmx !== undefined ? leaf.bwmx : (gcl.leafXmjs.length > 1 && gcl.name ? gcl.name : '');
+                const mx_id = leaf.mx_id ? leaf.mx_id : '';
+                const bwmx = leaf.bwmx !== undefined ? leaf.bwmx : (gcl.leafXmjs.length > 1 && gcl.name ? gcl.name : undefined);
                 const isChecked = data_bwmx.indexOf(
                     leaf.code + '!_!' + (leaf.jldy ? leaf.jldy : '') + '!_!' +
                     (leaf.dwgc ? leaf.dwgc : '') + '!_!' + (leaf.fbgc ? leaf.fbgc : '') + '!_!' + (leaf.fxgc ? leaf.fxgc : '')
-                    + '!_!' + (leaf.gcl_id ? leaf.gcl_id : '0') + '!_!' +
-                    (bwmx !== '' ? bwmx : leaf.jldy ? leaf.jldy : '') + '*;*' + quantity) !== -1 && isCheck ?
+                    + '!_!' + (leaf.gcl_id ? leaf.gcl_id : '0') + '!_!' + (leaf.mx_id ? leaf.mx_id : '') + '!_!' +
+                    (bwmx !== undefined ? bwmx : leaf.jldy ? leaf.jldy : '') + '*;*' + quantity) !== -1 && isCheck ?
                     'checked' : '';
                 const isUsed = _.find(changeUsedData, { gcl_id: leaf.gcl_id, bwmx: (bwmx ? bwmx : leaf.jldy ? leaf.jldy : ''), oamount: leaf.quantity });
                 const isDisabled = isUsed ? 'disabled ' : '';
-                codeHtml += '<tr quantity="' + quantity + '" gcl_id="' + gcl_id + '"><td>' + leaf.code + '</td>' +
+                codeHtml += '<tr quantity="' + quantity + '" gcl_id="' + gcl_id + '" mx_id="' + mx_id + '"><td>' + leaf.code + '</td>' +
                     '<td>' + (leaf.jldy ? leaf.jldy: '') + '</td>' +
                     '<td>' + (leaf.dwgc ? leaf.dwgc : '') + '</td>' +
                     '<td>' + (leaf.fbgc ? leaf.fbgc : '') + '</td>' +
                     '<td>' + (leaf.fxgc ? leaf.fxgc : '') + '</td>' +
-                    '<td>' + bwmx + '</td>' +
+                    '<td>' + (bwmx !== undefined ? bwmx : '') + '</td>' +
                     '<td class="text-right">' + (ZhCalc.round(quantity, findDecimal(gcl.unit)) ? ZhCalc.round(quantity, findDecimal(gcl.unit)) : 0) + '</td>' +
                     '<td class="text-center"><input type="checkbox" ' + isDisabled + isChecked +
                     '></td></tr>';
             }
         } else if (!isDeal && isCheck) {
-            codeHtml = '<tr quantity="'+ $(this).children('td').eq(5).text() +'" gcl_id=""><td colspan="7" class="colspan_1">&nbsp;</td><td class="colspan_2"><input type="checkbox" checked></td></tr>';
+            codeHtml = '<tr quantity="'+ $(this).children('td').eq(5).text() +'" gcl_id="" mx_id=""><td colspan="7" class="colspan_1">&nbsp;</td><td class="colspan_2"><input type="checkbox" checked></td></tr>';
         }
         $('#code-list').attr('data-index', $(this).children('td').eq(0).text());
         $('#code-input').val('');
@@ -682,12 +683,13 @@ $(document).ready(() => {
                 const tr = $(this).parents('tr');
                 const length = tr.children('td').length;
                 const gcl_id = tr.attr('gcl_id');
+                const mx_id = tr.attr('mx_id');
                 const bwmx = length === 8 ?
                     tr.children('td').eq(0).text() + '!_!' +
                     tr.children('td').eq(1).text() + '!_!' +
                     tr.children('td').eq(2).text() + '!_!' +
                     tr.children('td').eq(3).text() + '!_!' +
-                    tr.children('td').eq(4).text() + '!_!' + gcl_id + '!_!' +
+                    tr.children('td').eq(4).text() + '!_!' + gcl_id + '!_!' + mx_id + '!_!' +
                     (tr.children('td').eq(5).text() !== '' ? tr.children('td').eq(5).text() : tr.children('td').eq(1).text()) : '0';
                 const quantity = tr.attr('quantity');
                 const de_qu = bwmx + '*;*' + quantity;
@@ -704,12 +706,13 @@ $(document).ready(() => {
                     const tr = $(this).parents('tr');
                     const length = tr.children('td').length;
                     const gcl_id = tr.attr('gcl_id');
+                    const mx_id = tr.attr('mx_id');
                     const bwmx = length === 8 ?
                         tr.children('td').eq(0).text() + '!_!' +
                         tr.children('td').eq(1).text() + '!_!' +
                         tr.children('td').eq(2).text() + '!_!' +
                         tr.children('td').eq(3).text() + '!_!' +
-                        tr.children('td').eq(4).text() + '!_!' + gcl_id + '!_!' +
+                        tr.children('td').eq(4).text() + '!_!' + gcl_id + '!_!' + mx_id + '!_!' +
                         (tr.children('td').eq(5).text() !== '' ? tr.children('td').eq(5).text() : tr.children('td').eq(1).text()) : '0';
                     const quantity = tr.attr('quantity');
                     const de_qu = bwmx + '*;*' + quantity;
@@ -830,12 +833,13 @@ $(document).ready(() => {
                     const tr = $(this).parents('tr');
                     const length = tr.children('td').length;
                     const gcl_id = tr.attr('gcl_id');
+                    const mx_id = tr.attr('mx_id');
                     const bwmx = length === 8 ?
                         tr.children('td').eq(0).text() + '!_!' +
                         tr.children('td').eq(1).text() + '!_!' +
                         tr.children('td').eq(2).text() + '!_!' +
                         tr.children('td').eq(3).text() + '!_!' +
-                        tr.children('td').eq(4).text() + '!_!' + gcl_id + '!_!' +
+                        tr.children('td').eq(4).text() + '!_!' + gcl_id + '!_!' + mx_id + '!_!' +
                         (tr.children('td').eq(5).text() !== '' ? tr.children('td').eq(5).text() : tr.children('td').eq(1).text()) : '0';
                     const quantity = tr.attr('quantity');
                     const de_qu = bwmx + '*;*' + quantity;
@@ -922,11 +926,20 @@ $(document).ready(() => {
 });
 function checkSelectAll() {
     let check = $('#code-list tr').length > 0 ? true : false;
+    const codeNum = $('#code-list tr').length;
+    let i = 0;
     $('#code-list tr').each(function () {
         if ($(this).css('display') !== 'none' && !$(this).find('input').is(':checked')) {
             check = false;
+            return;
+        }
+        else if ($(this).css('display') === 'none') {
+            i++;
         }
     });
+    if (check && i === codeNum) {
+        check = false;
+    }
     $('#code-select-all').prop('checked', check);
 }
 
@@ -988,11 +1001,24 @@ function tableDataRemake(changeListData) {
     // 根据已添加的清单显示
     if (changeList.length > 0 && changeList[0]) {
         const removeList = [];
+        const updateList = [];
         for (const [index,clinfo] of changeList.entries()) {
             if (clinfo.lid != 0) {
                 let listinfo = changeListData.find(function (item) {
                     return (item.id !== undefined && item.id == clinfo.lid) || (item.id === undefined && item.leafXmjs !== undefined && item.leafXmjs.length !== 0 && item.leafXmjs[0].gcl_id == clinfo.lid);
                 });
+                if (listinfo === undefined || (clinfo.lid && clinfo.gcl_id && clinfo.lid !== clinfo.gcl_id)) {
+                    // 有可能这部分台账发生变化,此时要更新清单lid信息,防止数据丢失
+                    const newlistinfo = changeListData.find(function (item) {
+                        return (item.id !== undefined && item.id == clinfo.gcl_id) || (item.id === undefined && item.leafXmjs !== undefined && item.leafXmjs.length !== 0 && _.find(item.leafXmjs, {gcl_id: clinfo.gcl_id }));
+                    });
+                    if (listinfo === undefined && newlistinfo || (listinfo && newlistinfo && !isObjEqual(listinfo, newlistinfo))) {
+                        listinfo = newlistinfo;
+                        updateList.push({id: clinfo.id, lid: newlistinfo.leafXmjs[0].gcl_id});
+                        // 更新lid
+                        changeList[index].lid = newlistinfo.leafXmjs[0].gcl_id;
+                    }
+                }
                 if (listinfo === undefined) {
                     // 针对旧数据获取清单信息
                     listinfo = changeListData[clinfo.lid - 1];
@@ -1018,6 +1044,7 @@ function tableDataRemake(changeListData) {
                                 (leafInfo.fbgc ? leafInfo.fbgc : '') + '!_!' +
                                 (leafInfo.fxgc ? leafInfo.fxgc : '') + '!_!' +
                                 (leafInfo.gcl_id ? leafInfo.gcl_id : '') + '!_!' +
+                                (leafInfo.mx_id ? leafInfo.mx_id : '') + '!_!' +
                                 (leafInfo.bwmx !== undefined ? leafInfo.bwmx : (listinfo.leafXmjs.length > 1 && listinfo.name ? listinfo.name : (leafInfo.jldy !== undefined ? leafInfo.jldy : ''))) + '*;*' + (leafInfo.quantity !== null ? leafInfo.quantity : 0);
                         } else {
                             toastr.warning('台账清单列表已不存在'+ clinfo.code +',已更新变更清单列表');
@@ -1053,8 +1080,10 @@ function tableDataRemake(changeListData) {
                                 (leafInfo.fbgc ? leafInfo.fbgc : '') + '!_!' +
                                 (leafInfo.fxgc ? leafInfo.fxgc : '') + '!_!' +
                                 (leafInfo.gcl_id ? leafInfo.gcl_id : '') + '!_!' +
+                                (leafInfo.mx_id ? leafInfo.mx_id : '') + '!_!' +
                                 (leafInfo.bwmx !== undefined ? leafInfo.bwmx : (listinfo.leafXmjs.length > 1 && listinfo.name ? listinfo.name : (leafInfo.jldy !== undefined ? leafInfo.jldy : ''))) + '*;*' + (leafInfo.quantity !== null ? leafInfo.quantity : 0);
                         } else {
+                            console.log(clinfo, listinfo.leafXmjs);
                             toastr.warning('台账清单列表已不存在'+ clinfo.code +',已更新变更清单列表');
                             // changeList.splice(index, 1);
                             removeList.push(clinfo);
@@ -1074,12 +1103,17 @@ function tableDataRemake(changeListData) {
                 }
             }
         }
-        if(removeList.length > 0) {
-            _.pullAll(changeList, removeList);
-            postData(window.location.pathname + '/save', { type:'remove_list', updateData: removeList }, function (result) {
+        if(updateList.length > 0) {
+            postData(window.location.pathname + '/save', { type:'update_list', updateData: updateList }, function (result) {
             }, function () {
             });
         }
+        if(removeList.length > 0) {
+            _.pullAll(changeList, removeList);
+            // postData(window.location.pathname + '/save', { type:'remove_list', updateData: removeList }, function (result) {
+            // }, function () {
+            // });
+        }
     }
 }
 
@@ -1137,13 +1171,14 @@ function remakeChangeSpread() {
 
         for (const b of data_bwmx) {
             const oamount = b.split('*;*')[1] != '' ? b.split('*;*')[1] : 0;
-            let bwmx = b.split('*;*')[0] != 0 ? b.split('*;*')[0].split('!_!')[6] : '';
+            let bwmx = b.split('*;*')[0] != 0 ? b.split('*;*')[0].split('!_!')[7] : '';
             let xmj_code = b.split('*;*')[0] != 0 ? b.split('*;*')[0].split('!_!')[0] : '';
             let xmj_jldy = b.split('*;*')[0] != 0 ? b.split('*;*')[0].split('!_!')[1] : '';
             let xmj_dwgc = b.split('*;*')[0] != 0 ? b.split('*;*')[0].split('!_!')[2] : '';
             let xmj_fbgc = b.split('*;*')[0] != 0 ? b.split('*;*')[0].split('!_!')[3] : '';
             let xmj_fxgc = b.split('*;*')[0] != 0 ? b.split('*;*')[0].split('!_!')[4] : '';
             let gcl_id = b.split('*;*')[0] != 0 ? b.split('*;*')[0].split('!_!')[5] : '';
+            let mx_id = b.split('*;*')[0] != 0 ? b.split('*;*')[0].split('!_!')[6] : '';
             let trlist = {
                 code,
                 name,
@@ -1160,6 +1195,7 @@ function remakeChangeSpread() {
                 xmj_fbgc,
                 xmj_fxgc,
                 gcl_id,
+                mx_id,
             };
             const radionInfo = changeList.find(function (info) {
                 return info.code === code && (info.lid == lid || parseInt(info.lid) === parseInt(lindex)) && gcl_id == info.gcl_id && (info.bwmx === bwmx || info.bwmx === xmj_jldy) && parseInt(info.oamount) === parseInt(oamount);

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 2552 - 0
app/public/js/change_revise.js


+ 1 - 1
app/public/js/gcl_gather.js

@@ -534,4 +534,4 @@ const gclGatherModel = (function () {
         checkDiffer,
         gatherChapterData,
     };
-})();
+})();

+ 3 - 0
app/router.js

@@ -434,6 +434,9 @@ module.exports = app => {
     app.post('/tender/:id/change/:cid/information/copy', sessionAuth, tenderCheck, uncheckTenderCheck, 'changeController.copyChange');
     app.post('/tender/:id/change/:cid/information/audit/add', sessionAuth, tenderCheck, uncheckTenderCheck, changeCheck, 'changeController.addAudit');
     app.post('/tender/:id/change/:cid/information/audit/delete', sessionAuth, tenderCheck, uncheckTenderCheck, changeCheck, 'changeController.deleteAudit');
+    // 变更新增部位页
+    app.get('/tender/:id/change/:cid/information/revise', sessionAuth, tenderCheck, uncheckTenderCheck, changeCheck, 'changeController.reviseInfo');
+    app.post('/tender/:id/change/:cid/information/revise/update', sessionAuth, tenderCheck, uncheckTenderCheck, changeCheck, 'changeController.updateRevise');
     // 材料调差
     app.get('/tender/:id/measure/material', sessionAuth, tenderCheck, uncheckTenderCheck, 'materialController.index');
     app.post('/tender/:id/measure/material/add', sessionAuth, tenderCheck, uncheckTenderCheck, 'materialController.add');

+ 353 - 0
app/service/change_audit_list.js

@@ -374,6 +374,359 @@ module.exports = app => {
             const result = await this.db.query(sql, param);
             return result;
         }
+
+
+        /**
+         * 删除变更清单(form 变更新增部位页)
+         * Tony Kang
+         * @param {String} transaction - 队列
+         * @param {String} tid - 标段id
+         * @param {Array} ids - id列表
+         * @param {String} column - id所属字段
+         * @param {String} mx_id - mx_id为空列删除
+         * @return {void}
+         */
+        async deleteDataByRevise(transaction, tid, ids, column = 'gcl_id', mx_id = 'hello') {
+            if (ids.length > 0) {
+                const addSql = mx_id === '' ? ' AND (`mx_id` is NULL OR `mx_id` = "")' : '';
+                const sql = 'SELECT `cid` FROM ?? WHERE `tid` = ? AND ' + column + ' in (' + this.ctx.helper.getInArrStrSqlFilter(ids) + ')' + addSql + ' GROUP BY `cid`';
+                const params = [this.tableName, tid];
+                const changes = await transaction.query(sql, params);
+                if (changes.length > 0) {
+                    const delData = {
+                        tid,
+                    };
+                    delData[column] = ids;
+                    await transaction.delete(this.tableName, delData);
+                    for (const c of changes) {
+                        // 重算选了此清单的变更令已变更金额
+                        await this.reCalcTp(transaction, c.cid);
+                    }
+                }
+            }
+        }
+
+        /**
+         * 修改变更清单(form 变更新增部位页台账子节点清单编号编辑)
+         * Tony Kang
+         * @param {String} transaction - 队列
+         * @param {String} tid - 标段id
+         * @param {Array} datas - 更新列表
+         * @param {String} column - id所属字段
+         * @return {void}
+         */
+        async updateDataByReviseLedger(transaction, tid, datas, column = 'gcl_id') {
+            if (datas.length > 0) {
+                const ids = this._.map(datas, 'id');
+                const sql = 'SELECT ' + column + ' FROM ?? WHERE `tid` = ? AND ' + column + ' in (' + this.ctx.helper.getInArrStrSqlFilter(ids) + ') GROUP BY ' + column;
+                const params = [this.tableName, tid];
+                const changeAuditLists = await transaction.query(sql, params);
+                if (changeAuditLists.length > 0) {
+                    const updateArr = [];
+                    const cidList = [];
+                    for (const ca of changeAuditLists) {
+                        const d = this._.find(datas, { id: ca[column] });
+                        if (d.id) {
+                            const changePosNum = await transaction.count(this.ctx.service.changePos.tableName, { lid: d.id });
+                            const updateCol = {};
+                            if (column === 'gcl_id' && d.b_code !== undefined) updateCol.code = d.b_code;
+                            if (column === 'gcl_id' && d.sgfh_qty !== undefined && changePosNum === 0) updateCol.oamount = d.sgfh_qty ? d.sgfh_qty : 0;
+                            if (column === 'gcl_id' && d.unit_price !== undefined) updateCol.unit_price = d.unit_price ? d.unit_price : 0;
+                            if (column === 'gcl_id' && d.unit !== undefined) updateCol.unit = d.unit;
+                            if (column === 'gcl_id' && d.name !== undefined) updateCol.name = d.name;
+                            if (d.code !== undefined && d.b_code === null) {
+                                // 清单升级成了项目节,故删除变更已有的此清单,并找出需要重新计算的变更令
+                                const sql = 'SELECT `cid` FROM ?? WHERE `tid` = ? AND ' + column + ' = ? GROUP BY `cid`';
+                                const params = [this.tableName, tid, d.id];
+                                const changes = await transaction.query(sql, params);
+                                for (const c of changes) {
+                                    if (this._.indexOf(cidList, c.cid) === -1) {
+                                        cidList.push(c.cid);
+                                    }
+                                }
+                                const delData = {
+                                    tid,
+                                };
+                                delData[column] = d.id;
+                                console.log(delData);
+                                await transaction.delete(this.tableName, delData);
+                            } else {
+                                const options = {
+                                    row: {},
+                                    where: {},
+                                };
+                                options.row = updateCol;
+                                options.where[column] = d.id;
+                                if (!this._.isEmpty(options.row)) updateArr.push(options);
+                                if (updateCol.unit !== undefined || updateCol.unit_price !== undefined) {
+                                    const sql = 'SELECT `cid` FROM ?? WHERE `tid` = ? AND ' + column + ' = ? GROUP BY `cid`';
+                                    const params = [this.tableName, tid, d.id];
+                                    const changes = await transaction.query(sql, params);
+                                    for (const c of changes) {
+                                        if (this._.indexOf(cidList, c.cid) === -1) {
+                                            cidList.push(c.cid);
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    if (updateArr.length > 0) await transaction.updateRows(this.tableName, updateArr);
+                    if (cidList.length > 0) {
+                        for (const c of cidList) {
+                            await this.reCalcTp(transaction, c);
+                        }
+                    }
+                }
+                // 针对项目节更新可能对清单影响判断,修正变更清单项目节编号,细目,单位工程,分部分项工程数据
+                for (const data of datas) {
+                    const select = await transaction.get(this.ctx.service.changeLedger.tableName, { id: data.id });
+                    if (select && select.is_leaf === 0) {
+                        const lists = await this.ctx.service.changeLedger.getDataByFullPath(this.ctx.service.changeLedger.tableName, tid, select.full_path + '%', transaction);
+                        const childLists = this._.filter(lists, { level: select.level + 1 }); // 细目or项目节编号更新
+                        if (childLists.length > 0) {
+                            const d = { xmj_code: '', xmj_jldy: '' };
+                            if (select.code !== null) {
+                                d.xmj_code = select.code;
+                                d.xmj_jldy = select.name;
+                            } else {
+                                // 再找出上一个项目节节点并更新
+                                this.newBills = false;
+                                const parents = await this.ctx.service.changeLedger.getDataByKid(tid, select.ledger_pid);
+                                console.log('hello :', parents);
+                                d.xmj_code = parents.code;
+                                d.xmj_jldy = parents.name;
+                            }
+                            for (const cl of childLists) {
+                                await transaction.update(this.tableName, { xmj_code: d.xmj_code, xmj_jldy: d.xmj_jldy }, { where: { tid, gcl_id: cl.id } });
+                            }
+                        }
+                        if (select.code !== null && data.name !== undefined) { // 名称修改则可能影响几个数据
+                            const secondChildLists = this._.filter(lists, { level: select.level + 2 }); // 分项工程更新
+                            const thirdChildLists = this._.filter(lists, { level: select.level + 3 }); // 分部工程更新
+                            const fourthChildLists = this._.filter(lists, { level: select.level + 4 }); // 单位工程更新
+                            if (secondChildLists.length > 0) {
+                                for (const sl of secondChildLists) {
+                                    await transaction.update(this.tableName, { xmj_fxgc: select.name }, { where: { tid, gcl_id: sl.id } });
+                                }
+                            }
+                            if (thirdChildLists.length > 0) {
+                                for (const tl of thirdChildLists) {
+                                    await transaction.update(this.tableName, { xmj_fbgc: select.name }, { where: { tid, gcl_id: tl.id } });
+                                }
+                            }
+                            if (fourthChildLists.length > 0 && select.level === 2) {
+                                for (const fl of fourthChildLists) {
+                                    await transaction.update(this.tableName, { xmj_dwgc: select.name }, { where: { tid, gcl_id: fl.id } });
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        /**
+         * 修改变更清单(form 变更新增部位页台账节点清单编号升降级)
+         * Tony Kang
+         * @param {String} transaction - 队列
+         * @param {String} tid - 标段id
+         * @param {Array} datas - 更新列表
+         * @param {String} column - id所属字段
+         * @return {void}
+         */
+        async updateDataByReviseLedgerUpDownLevel(transaction, tid, datas, column = 'gcl_id') {
+            if (datas.length > 0) {
+                console.log(datas);
+                // const ids = this._.map(datas, 'id');
+                // const sql = 'SELECT ' + column + ' FROM ?? WHERE `tid` = ? AND ' + column + ' in (' + this.ctx.helper.getInArrStrSqlFilter(ids) + ') GROUP BY ' + column;
+                // const params = [this.tableName, tid];
+                // const changeAuditLists = await transaction.query(sql, params);
+                // if (changeAuditLists.length > 0) {
+                //     const updateArr = [];
+                //     const cidList = [];
+                //     for (const ca of changeAuditLists) {
+                //         const d = this._.find(datas, { id: ca[column] });
+                //         console.log(d);
+                //         if (d.id) {
+                //             const changePosNum = await transaction.count(this.ctx.service.changePos.tableName, { lid: d.id });
+                //             const updateCol = {};
+                //             if (column === 'gcl_id' && d.b_code !== undefined) updateCol.code = d.b_code;
+                //             if (column === 'gcl_id' && d.sgfh_qty !== undefined && changePosNum === 0) updateCol.oamount = d.sgfh_qty ? d.sgfh_qty : 0;
+                //             if (column === 'gcl_id' && d.unit_price !== undefined) updateCol.unit_price = d.unit_price ? d.unit_price : 0;
+                //             if (column === 'gcl_id' && d.unit !== undefined) updateCol.unit = d.unit;
+                //             if (column === 'gcl_id' && d.name !== undefined) updateCol.name = d.name;
+                //             if (d.code !== undefined && d.b_code === null) {
+                //                 // 清单升级成了项目节,故删除变更已有的此清单,并找出需要重新计算的变更令
+                //                 const sql = 'SELECT `cid` FROM ?? WHERE `tid` = ? AND ' + column + ' = ? GROUP BY `cid`';
+                //                 const params = [this.tableName, tid, d.id];
+                //                 const changes = await transaction.query(sql, params);
+                //                 for (const c of changes) {
+                //                     if (this._.indexOf(cidList, c.cid) === -1) {
+                //                         cidList.push(c.cid);
+                //                     }
+                //                 }
+                //                 const delData = {
+                //                     tid,
+                //                 };
+                //                 delData[column] = d.id;
+                //                 console.log(delData);
+                //                 await transaction.delete(this.tableName, delData);
+                //             } else {
+                //                 const options = {
+                //                     row: {},
+                //                     where: {},
+                //                 };
+                //                 options.row = updateCol;
+                //                 options.where[column] = d.id;
+                //                 if (!this._.isEmpty(options.row)) updateArr.push(options);
+                //                 if (updateCol.unit !== undefined || updateCol.unit_price !== undefined) {
+                //                     const sql = 'SELECT `cid` FROM ?? WHERE `tid` = ? AND ' + column + ' = ? GROUP BY `cid`';
+                //                     const params = [this.tableName, tid, d.id];
+                //                     const changes = await transaction.query(sql, params);
+                //                     for (const c of changes) {
+                //                         if (this._.indexOf(cidList, c.cid) === -1) {
+                //                             cidList.push(c.cid);
+                //                         }
+                //                     }
+                //                 }
+                //             }
+                //         }
+                //     }
+                //     console.log(updateArr, cidList);
+                //     if (updateArr.length > 0) await transaction.updateRows(this.tableName, updateArr);
+                //     if (cidList.length > 0) {
+                //         for (const c of cidList) {
+                //             await this.reCalcTp(transaction, c);
+                //         }
+                //     }
+                // }
+                // 针对项目节更新可能对清单影响判断,修正变更清单项目节编号,细目,单位工程,分部分项工程数据
+                // for (const data of datas) {
+                //     const select = await transaction.get(this.ctx.service.changeLedger.tableName, { id: data.id });
+                //     console.log(select);
+                //     if (select && select.is_leaf === 0) {
+                //         const lists = await this.ctx.service.changeLedger.getDataByFullPath(this.ctx.service.changeLedger.tableName, tid, select.full_path + '%', transaction);
+                //         const childLists = this._.filter(lists, { level: select.level + 1 }); // 细目or项目节编号更新
+                //         if (childLists.length > 0) {
+                //             const d = { xmj_code: '', xmj_jldy: '' };
+                //             if (select.code !== null) {
+                //                 d.xmj_code = select.code;
+                //                 d.xmj_jldy = select.name;
+                //             } else {
+                //                 // 再找出上一个项目节节点并更新
+                //                 this.newBills = false;
+                //                 const parents = await this.ctx.service.changeLedger.getDataByKid(tid, select.ledger_pid);
+                //                 console.log('hello :', parents);
+                //                 d.xmj_code = parents.code;
+                //                 d.xmj_jldy = parents.name;
+                //             }
+                //             for (const cl of childLists) {
+                //                 await transaction.update(this.tableName, { xmj_code: d.xmj_code, xmj_jldy: d.xmj_jldy }, { where: { tid, gcl_id: cl.id } });
+                //             }
+                //         }
+                //         if (select.code !== null && data.name !== undefined) { // 名称修改则可能影响几个数据
+                //             const secondChildLists = this._.filter(lists, { level: select.level + 2 }); // 分项工程更新
+                //             const thirdChildLists = this._.filter(lists, { level: select.level + 3 }); // 分部工程更新
+                //             const fourthChildLists = this._.filter(lists, { level: select.level + 4 }); // 单位工程更新
+                //             if (secondChildLists.length > 0) {
+                //                 for (const sl of secondChildLists) {
+                //                     await transaction.update(this.tableName, { xmj_fxgc: select.name }, { where: { tid, gcl_id: sl.id } });
+                //                 }
+                //             }
+                //             if (thirdChildLists.length > 0) {
+                //                 for (const tl of thirdChildLists) {
+                //                     await transaction.update(this.tableName, { xmj_fbgc: select.name }, { where: { tid, gcl_id: tl.id } });
+                //                 }
+                //             }
+                //             if (fourthChildLists.length > 0) {
+                //                 for (const fl of fourthChildLists) {
+                //                     await transaction.update(this.tableName, { xmj_dwgc: select.name }, { where: { tid, gcl_id: fl.id } });
+                //                 }
+                //             }
+                //         }
+                //     }
+                // }
+            }
+        }
+
+        /**
+         * 修改变更清单(form 变更新增部位页计量单元编辑)
+         * Tony Kang
+         * @param {String} transaction - 队列
+         * @param {String} tid - 标段id
+         * @param {Array} datas - 更新列表
+         * @param {String} column - id所属字段
+         * @return {void}
+         */
+        async updateDataByRevisePos(transaction, tid, datas, column = 'mx_id') {
+            if (datas.length > 0) {
+                const ids = this._.map(datas, 'id');
+                const sql = 'SELECT ' + column + ' FROM ?? WHERE `tid` = ? AND ' + column + ' in (' + this.ctx.helper.getInArrStrSqlFilter(ids) + ') GROUP BY ' + column;
+                const params = [this.tableName, tid];
+                const changeAuditLists = await transaction.query(sql, params);
+                if (changeAuditLists.length > 0) {
+                    const updateArr = [];
+                    for (const ca of changeAuditLists) {
+                        const d = this._.find(datas, { id: ca[column] });
+                        if (d.id) {
+                            const updateCol = {};
+                            if (column === 'mx_id' && d.name !== undefined) updateCol.bwmx = d.name;
+                            if (column === 'mx_id' && d.sgfh_qty !== undefined) updateCol.oamount = d.sgfh_qty ? d.sgfh_qty : 0;
+                            if (column === 'mx_id' && d.sgfh_qty === undefined && d.sgfh_expr === '') updateCol.oamount = 0;
+                            const options = {
+                                row: {},
+                                where: {},
+                            };
+                            options.row = updateCol;
+                            options.where[column] = d.id;
+                            // if (!this._.isEmpty(updateCol)) await transaction.update(this.tableName, updateCol, options);
+                            if (!this._.isEmpty(options.row)) updateArr.push(options);
+                        }
+                    }
+                    console.log(updateArr);
+                    if (updateArr.length > 0) await transaction.updateRows(this.tableName, updateArr);
+                }
+            }
+        }
+
+        /**
+         * 重算变更令总金额(变更新增部位设置时使用)
+         * @param {String} transaction - 队列
+         * @param {String} cid - 变更令id
+         */
+        async reCalcTp(transaction, cid) {
+            const change = await transaction.get(this.ctx.service.change.tableName, { cid });
+            let count = '';
+            if (change.status === audit.flow.status.uncheck || change.status === audit.flow.status.back || change.status === audit.flow.status.revise) {
+                count = '`camount`';
+            } else if (change.status === audit.flow.status.checking || change.status === audit.flow.status.backnew) {
+                count = '`spamount`';
+            }
+            if (count) {
+                const sql = 'SELECT `unit_price`, ' + count + ' as `count` FROM ?? WHERE `cid` = ?';
+                const params = [this.tableName, change.cid];
+                const caLists = await transaction.query(sql, params);
+                let tp = 0;
+                const tpUnit = change.tp_decimal ? change.tp_decimal : this.ctx.tender.info.decimal.tp;
+                for (const ca of caLists) {
+                    const catp = this.ctx.helper.round(this.ctx.helper.mul(ca.unit_price, ca.count), tpUnit);
+                    tp = this.ctx.helper.add(tp, catp);
+                }
+                console.log(tp);
+                if (tp !== change.total_price) {
+                    const options = {
+                        where: {
+                            cid: change.cid,
+                        },
+                    };
+                    const change_update = {
+                        total_price: tp,
+                    };
+                    await transaction.update(this.ctx.service.change.tableName, change_update, options);
+                }
+            }
+        }
     }
 
     return ChangeAuditList;

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 1710 - 0
app/service/change_ledger.js


+ 397 - 0
app/service/change_pos.js

@@ -0,0 +1,397 @@
+'use strict';
+
+/**
+ * 变更插入新增 - 部位明细
+ *
+ * @author Mai
+ * @date
+ * @version
+ */
+
+module.exports = app => {
+
+    class ChangePos extends app.BaseService {
+        /**
+         * 构造函数
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        constructor(ctx) {
+            super(ctx);
+            // this.depart = 20;
+            this.tableName = 'change_pos';
+        }
+
+        async getPosData(condition) {
+            if (!condition.tid) throw '查询计量单元缺少必要信息';
+            return await this.db.select(this.tableName, {
+                where: condition,
+                columns: ['id', 'tid', 'lid', 'name', 'quantity', 'position', 'drawing_code', 'sgfh_qty', 'sjcl_qty',
+                    'qtcl_qty', 'in_time', 'porder', 'add_stage', 'sgfh_expr', 'sjcl_expr', 'qtcl_expr', 'real_qty',
+                    'dagl_status', 'dagl_url', 'gxby_status', 'gxby_limit', 'dagl_limit', 'dagl_status',
+                    'ex_memo1', 'ex_memo2', 'ex_memo3', 'ccid'],
+                order: [['porder', 'ASC']],
+            });
+        }
+
+        async _completeInsertPosData(tid, cid, data) {
+            data.id = this.uuid.v4();
+            data.tid = tid;
+            // todo 新增期
+            data.add_stage = 0;
+            data.add_times = 0;
+            data.in_time = new Date();
+            data.add_user = this.ctx.session.sessionUser.accountId;
+            data.ccid = cid;
+        }
+
+        async addPos(tid, cid, data) {
+            if (data instanceof Array) {
+                for (const d of data) {
+                    this._completeInsertPosData(tid, cid, d);
+                }
+            } else {
+                this._completeInsertPosData(tid, cid, data);
+            }
+            const transaction = await this.db.beginTransaction();
+            try {
+                await this.ctx.service.changeAuditList.deleteDataByRevise(transaction, tid, [data.lid], 'gcl_id', '');
+                await transaction.insert(this.tableName, data);
+                await transaction.commit();
+                return { pos: data };
+            } catch (err) {
+                await transaction.rollback();
+                throw err;
+            }
+        }
+
+        async updatePos(tid, data) {
+            if (data.sgfh_qty !== undefined || data.sjcl_qty !== undefined || data.qtcl_qty !== undefined) {
+                const op = await this.getDataById(data.id);
+                let bills = await this.ctx.service.changeLedger.getDataById(op.lid);
+                let newBills = false;
+                let billsPos = await this.getAllDataByCondition({ where: { tid: tid, lid: op.lid } });
+                if (bills) {
+                    newBills = true;
+                } else {
+                    bills = await this.ctx.service.ledger.getDataById(op.lid);
+                    const posData = await this.ctx.service.pos.getAllDataByCondition({ where: { tid: tid, lid: op.lid } });
+                    billsPos = this._.concat(posData, billsPos);
+                }
+
+                const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, bills.unit);
+                if (data.sgfh_qty !== undefined) {
+                    data.sgfh_qty = this.round(data.sgfh_qty, precision.value);
+                } else if (op) {
+                    data.sgfh_qty = op.sgfh_qty;
+                }
+                if (data.sjcl_qty !== undefined) {
+                    data.sjcl_qty = this.round(data.sjcl_qty, precision.value);
+                } else if (op) {
+                    data.sjcl_qty = op.sjcl_qty;
+                }
+                if (data.qtcl_qty !== undefined) {
+                    data.qtcl_qty = this.round(data.qtcl_qty, precision.value);
+                } else if (op) {
+                    data.qtcl_qty = op.qtcl_qty;
+                }
+                data.quantity = this.ctx.helper.sum([data.sgfh_qty, data.qtcl_qty, data.sjcl_qty]);
+
+                const updateBills = { id: bills.id };
+                for (const bp of billsPos) {
+                    const calcData = bp.id === data.id ? data : bp;
+                    updateBills.sgfh_qty = this.ctx.helper.add(updateBills.sgfh_qty, calcData.sgfh_qty);
+                    updateBills.sjcl_qty = this.ctx.helper.add(updateBills.sjcl_qty, calcData.sjcl_qty);
+                    updateBills.qtcl_qty = this.ctx.helper.add(updateBills.qtcl_qty, calcData.qtcl_qty);
+                    updateBills.quantity = this.ctx.helper.add(updateBills.quantity, calcData.quantity);
+                }
+                const info = this.ctx.tender.info;
+                updateBills.sgfh_tp = this.ctx.helper.mul(updateBills.sgfh_qty, bills.unit_price, info.decimal.tp);
+                updateBills.sjcl_tp = this.ctx.helper.mul(updateBills.sjcl_qty, bills.unit_price, info.decimal.tp);
+                updateBills.qtcl_tp = this.ctx.helper.mul(updateBills.qtcl_qty, bills.unit_price, info.decimal.tp);
+                updateBills.total_price = this.ctx.helper.mul(updateBills.quantity, bills.unit_price, info.decimal.tp);
+                const transaction = await this.db.beginTransaction();
+                try {
+                    await transaction.update(this.tableName, data);
+                    if (newBills) await transaction.update(this.ctx.service.changeLedger.tableName, updateBills);
+                    await this.ctx.service.changeAuditList.updateDataByRevisePos(transaction, tid, [data]);
+                    await transaction.commit();
+                    updateBills.ledger_id = bills.ledger_id;
+                    return {
+                        ledger: { update: [updateBills] },
+                        pos: data,
+                    };
+                } catch (err) {
+                    await transaction.rollback();
+                    throw err;
+                }
+            } else {
+                const transaction = await this.db.beginTransaction();
+                try {
+                    await transaction.update(this.tableName, data, { tid, id: data.id });
+                    await this.ctx.service.changeAuditList.updateDataByRevisePos(transaction, tid, [data]);
+                    await transaction.commit();
+                    return { pos: data };
+                } catch (err) {
+                    await transaction.rollback();
+                    throw err;
+                }
+            }
+        }
+
+        async updatePosArr(tid, data) {
+            console.log(data);
+            if (data.length === 0) return;
+            const op = await this.getDataById(data[0].id) || await this.ctx.service.pos.getDataById(data[0].id);
+            let bills = await this.ctx.service.changeLedger.getDataById(op.lid);
+            let newBills = false;
+            let billsPos = await this.getAllDataByCondition({ where: { tid: tid, lid: op.lid } });
+            if (bills) {
+                newBills = true;
+            } else {
+                bills = await this.ctx.service.ledger.getDataById(op.lid);
+                const posData = await this.ctx.service.pos.getAllDataByCondition({ where: { tid: tid, lid: op.lid } });
+                billsPos = this._.concat(posData, billsPos);
+            }
+            const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, bills.unit);
+            let needUpdateBills;
+            for (const d of data) {
+                if (d.sgfh_qty !== undefined || d.sjcl_qty !== undefined || d.qtcl_qty !== undefined) {
+                    if (d.sgfh_qty !== undefined) {
+                        d.sgfh_qty = this.round(d.sgfh_qty, precision.value);
+                    } else if (op) {
+                        d.sgfh_qty = op.sgfh_qty;
+                    }
+                    if (d.sjcl_qty !== undefined) {
+                        d.sjcl_qty = this.round(d.sjcl_qty, precision.value);
+                    } else if (op) {
+                        d.sjcl_qty = op.sjcl_qty;
+                    }
+                    if (d.qtcl_qty !== undefined) {
+                        d.qtcl_qty = this.round(d.qtcl_qty, precision.value);
+                    } else if (op) {
+                        d.qtcl_qty = op.qtcl_qty;
+                    }
+                    d.quantity = this.ctx.helper.sum([d.sgfh_qty, d.qtcl_qty, d.sjcl_qty]);
+                    needUpdateBills = true;
+                }
+            }
+            const updateBills = { id: bills.id };
+            if (needUpdateBills) {
+                for (const bp of billsPos) {
+                    const newPos = data.find(function(x) { return x.id === bp.id; });
+                    updateBills.sgfh_qty = newPos && newPos.sgfh_qty !== undefined
+                        ? this.ctx.helper.add(updateBills.sgfh_qty, newPos.sgfh_qty)
+                        : this.ctx.helper.add(updateBills.sgfh_qty, bp.sgfh_qty);
+                    updateBills.sjcl_qty = newPos && newPos.sjcl_qty !== undefined
+                        ? this.ctx.helper.add(updateBills.sjcl_qty, newPos.sjcl_qty)
+                        : this.ctx.helper.add(updateBills.sjcl_qty, bp.sjcl_qty);
+                    updateBills.qtcl_qty = newPos && newPos.qtcl_qty !== undefined
+                        ? this.ctx.helper.add(updateBills.qtcl_qty, newPos.qtcl_qty)
+                        : this.ctx.helper.add(updateBills.qtcl_qty, bp.qtcl_qty);
+                    updateBills.quantity = newPos && newPos.quantity !== undefined
+                        ? this.ctx.helper.add(updateBills.quantity, newPos.quantity)
+                        : this.ctx.helper.add(updateBills.quantity, bp.quantity);
+                }
+                const info = this.ctx.tender.info;
+                updateBills.sgfh_tp = this.ctx.helper.mul(updateBills.sgfh_qty, bills.unit_price, info.decimal.tp);
+                updateBills.sjcl_tp = this.ctx.helper.mul(updateBills.sjcl_qty, bills.unit_price, info.decimal.tp);
+                updateBills.qtcl_tp = this.ctx.helper.mul(updateBills.qtcl_qty, bills.unit_price, info.decimal.tp);
+                updateBills.total_price = this.ctx.helper.mul(updateBills.quantity, bills.unit_price, info.decimal.tp);
+            }
+
+            const transaction = await this.db.beginTransaction();
+            try {
+                for (const d of data) {
+                    // 区分d属于pos还是changePos,分别更新对应的表
+                    const np = await this.getDataById(d.id);
+                    np ? await transaction.update(this.tableName, d) : await transaction.update(this.ctx.service.pos.tableName, d);
+                }
+                if (needUpdateBills && newBills) await transaction.update(this.ctx.service.changeLedger.tableName, updateBills);
+                await this.ctx.service.changeAuditList.updateDataByRevisePos(transaction, tid, data);
+                await transaction.commit();
+                updateBills.ledger_id = bills.ledger_id;
+                return {
+                    ledger: { update: needUpdateBills ? [updateBills] : [] },
+                    pos: data,
+                };
+            } catch (err) {
+                await transaction.rollback();
+                throw err;
+            }
+        }
+
+        async deletePos(tid, data) {
+            if (!data || data.length === 0) {
+                throw '提交数据错误';
+            }
+
+            const pos = await this.getPosData({tid: tid, id: data});
+            let bills = await this.ctx.service.changeLedger.getDataById(pos[0].lid);
+            let newBills = false;
+            let billsPos = await this.getAllDataByCondition({ where: { tid: tid, lid: pos[0].lid } });
+            if (bills) {
+                newBills = true;
+            } else {
+                bills = await this.ctx.service.ledger.getDataById(pos[0].lid);
+                const posData = await this.ctx.service.pos.getAllDataByCondition({ where: { tid: tid, lid: pos[0].lid } });
+                billsPos = this._.concat(posData, billsPos);
+            }
+            // const bills = await this.ctx.service.reviseBills.getDataById(pos[0].lid);
+            // const billsPos = await this.getAllDataByCondition({ where: {tid: tid, lid: bills.id} });
+            const updateBills = {id: bills.id, sgfh_qty: null, sjcl_qty: null, qtcl_qty: null, quantity: null};
+            for (const bp of billsPos) {
+                if (data.indexOf(bp.id) >= 0) continue;
+                updateBills.sgfh_qty = this.ctx.helper.add(updateBills.sgfh_qty, bp.sgfh_qty);
+                updateBills.sjcl_qty = this.ctx.helper.add(updateBills.sjcl_qty, bp.sjcl_qty);
+                updateBills.qtcl_qty = this.ctx.helper.add(updateBills.qtcl_qty, bp.qtcl_qty);
+                updateBills.quantity = this.ctx.helper.add(updateBills.quantity, bp.quantity);
+            }
+            const info = this.ctx.tender.info;
+            updateBills.sgfh_tp = this.ctx.helper.mul(updateBills.sgfh_qty, bills.unit_price, info.decimal.tp);
+            updateBills.sjcl_tp = this.ctx.helper.mul(updateBills.sjcl_qty, bills.unit_price, info.decimal.tp);
+            updateBills.qtcl_tp = this.ctx.helper.mul(updateBills.qtcl_qty, bills.unit_price, info.decimal.tp);
+            updateBills.total_price = this.ctx.helper.mul(updateBills.quantity, bills.unit_price, info.decimal.tp);
+
+            const transaction = await this.db.beginTransaction();
+            try {
+                await transaction.delete(this.tableName, {tid: tid, id: data});
+                if (newBills) await transaction.update(this.ctx.service.changeLedger.tableName, updateBills);
+                await this.ctx.service.changeAuditList.deleteDataByRevise(transaction, tid, data, 'mx_id');
+                await transaction.commit();
+                updateBills.ledger_id = bills.ledger_id;
+                return {
+                    ledger: { update: [updateBills] },
+                    pos: data,
+                };
+            } catch (err) {
+                await transaction.rollback();
+                throw err;
+            }
+        }
+        /**
+         * 复制粘贴 部位明细数据
+         * @param {Array} data - 复制粘贴的数据
+         * @param {Number} tid - 标段id
+         * @returns {Promise<{ledger: {}, pos: null}>}
+         */
+        async pastePosData(tid, cid, data) {
+            if (!(data instanceof Array)) throw '提交数据错误';
+
+            const transaction = await this.db.beginTransaction();
+            const result = { ledger: {}, pos: null };
+            const orgPos = await this.getPosData({ tid: tid, id: this._.map(data, 'id') });
+
+            // const bills = await this.ctx.service.reviseBills.getDataById(data[0].lid);
+            // const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, bills.unit);
+            // const updateBills = {id: bills.id};
+            // const billsPos = await this.getAllDataByCondition({where: {tid: tid, lid: bills.id} });
+            let bills = await this.ctx.service.changeLedger.getDataById(data[0].lid);
+            let newBills = false;
+            let billsPos = await this.getAllDataByCondition({ where: { tid: tid, lid: data[0].lid } });
+            if (bills) {
+                newBills = true;
+            } else {
+                bills = await this.ctx.service.ledger.getDataById(data[0].lid);
+                const posData = await this.ctx.service.pos.getAllDataByCondition({ where: { tid: tid, lid: data[0].lid } });
+                billsPos = this._.concat(posData, billsPos);
+            }
+            const updateBills = { id: bills.id };
+            const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, bills.unit);
+            let needUpdateBills;
+            for (const bp of billsPos) {
+                const d = data.find(function(x) {
+                    return bp.id ? x.id === bp.id : false;
+                });
+                if (d) continue;
+                updateBills.sgfh_qty = this.ctx.helper.add(updateBills.sgfh_qty, bp.sgfh_qty);
+                updateBills.sjcl_qty = this.ctx.helper.add(updateBills.sjcl_qty, bp.sjcl_qty);
+                updateBills.qtcl_qty = this.ctx.helper.add(updateBills.qtcl_qty, bp.qtcl_qty);
+                updateBills.quantity = this.ctx.helper.add(updateBills.quantity, bp.quantity);
+            }
+
+            try {
+                for (const d of data) {
+                    const op = d.id ? this._.find(orgPos, { id: d.id }) : null;
+                    if (d.sgfh_qty !== undefined || d.sjcl_qty !== undefined || d.qtcl_qty !== undefined) {
+                        if (d.sgfh_qty !== undefined) {
+                            d.sgfh_qty = this.round(d.sgfh_qty, precision.value);
+                        } else if (op) {
+                            d.sgfh_qty = op.sgfh_qty;
+                        }
+                        updateBills.sgfh_qty = this.ctx.helper.add(updateBills.sgfh_qty, d.sgfh_qty);
+                        if (d.sjcl_qty !== undefined) {
+                            d.sjcl_qty = this.round(d.sjcl_qty, precision.value);
+                        } else if (op) {
+                            d.sjcl_qty = op.sjcl_qty;
+                        }
+                        updateBills.sjcl_qty = this.ctx.helper.add(updateBills.sjcl_qty, d.sjcl_qty);
+                        if (d.qtcl_qty) {
+                            d.qtcl_qty = this.round(d.qtcl_qty, precision.value);
+                        } else if (op) {
+                            d.qtcl_qty = op.qtcl_qty;
+                        }
+                        updateBills.qtcl_qty = this.ctx.helper.add(updateBills.qtcl_qty, d.qtcl_qty);
+                        d.quantity = this.ctx.helper.sum([d.sgfh_qty, d.qtcl_qty, d.sjcl_qty]);
+                        updateBills.quantity = this.ctx.helper.add(updateBills.quantity, d.quantity);
+                        needUpdateBills = true;
+                    }
+                    if (d.id) {
+                        await transaction.update(this.tableName, d);
+                    } else {
+                        await this._insertPosData(transaction, d, tid, cid);
+                    }
+                }
+                const info = this.ctx.tender.info;
+                if (needUpdateBills) {
+                    updateBills.sgfh_tp = this.ctx.helper.mul(updateBills.sgfh_qty, bills.unit_price, info.decimal.tp);
+                    updateBills.sjcl_tp = this.ctx.helper.mul(updateBills.sjcl_qty, bills.unit_price, info.decimal.tp);
+                    updateBills.qtcl_tp = this.ctx.helper.mul(updateBills.qtcl_qty, bills.unit_price, info.decimal.tp);
+                    updateBills.total_price = this.ctx.helper.mul(updateBills.quantity, bills.unit_price, info.decimal.tp);
+                    if (newBills) await transaction.update(this.ctx.service.changeLedger.tableName, updateBills);
+                    updateBills.ledger_id = bills.ledger_id;
+                }
+                await this.ctx.service.changeAuditList.updateDataByRevisePos(transaction, tid, data);
+                await transaction.commit();
+            } catch (err) {
+                await transaction.rollback();
+                throw err;
+            }
+            result.pos = data;
+            result.ledger.update = needUpdateBills ? [updateBills] : [];
+            return result;
+        }
+
+        async _insertPosData(transaction, data, tid, cid) {
+            data.id = this.uuid.v4();
+            data.tid = tid;
+            // todo 新增期
+            data.add_stage = 0;
+            data.add_times = 0;
+            data.in_time = new Date();
+            data.add_user = this.ctx.session.sessionUser.accountId;
+            data.ccid = cid;
+            if (data.quantity) {
+                const bills = await this.ctx.service.changeLedger.getDataById(data.lid) || await this.ctx.service.ledger.getDataById(data.lid);
+                const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, bills.unit);
+                data.quantity = this.round(data.quantity, precision.value);
+            }
+            const addRst = await transaction.insert(this.tableName, data);
+        }
+
+        /**
+         * 删除清单下部位明细数据(删除清单时调用)
+         *
+         * @param transaction - 事务
+         * @param tid - 标段id
+         * @param lid - 清单id
+         * @returns {Promise<void>}
+         */
+        async deletePosData(transaction, tid, lid) {
+            await transaction.delete(this.tableName, {tid: tid, lid: lid});
+        }
+    }
+
+    return ChangePos;
+};

+ 6 - 3
app/view/change/information_modal.ejs

@@ -128,12 +128,15 @@
                         </div>
                     </div>
                     <div class="col-12">
-                        <div class="row mb-2 mt-2 mx-0 p-0">
-                            <div class="col-6 pl-0 p-0 search-group mt-2">
+                        <div class="row mb-2 mt-3 mx-0 p-0">
+                            <div class="col-6 p-0 search-group">
                                 <input class="form-control form-control-sm" id="code-input" placeholder="输入 项目节编号、名称、计量单元 检索">
                                 <a href="javascript:void(0);" style="display: none" data-btn="code" class="text-danger remove-btn" title="移除关键词"><i class="fa fa-times-circle "></i></a>
                             </div>
-                            <div class="ml-auto mt-2">
+                            <div class="col-3 pl-3 mt-1">
+                                <a href="/tender/<%- change.tid %>/change/<%- change.cid %>/information/revise" class="btn btn-primary btn-sm">新增部位</a>
+                            </div>
+                            <div class="ml-auto mt-1">
                                 <div class="custom-control custom-checkbox mt-1">
                                     <input type="checkbox" id="code-select-all" class="custom-control-input">
                                     <label class="custom-control-label" for="code-select-all">全选</label>

+ 173 - 0
app/view/change/revise.ejs

@@ -0,0 +1,173 @@
+<% include ./sub_menu.ejs %>
+<div class="panel-content">
+    <div class="panel-title">
+        <div class="title-main  d-flex">
+            <% include ./sub_mini_menu.ejs %>
+            <!--工具-->
+            <div>
+                <div class="d-inline-block">
+                    <div class="dropdown">
+                        <button class="btn btn-sm btn-light dropdown-toggle text-primary" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+                            <i class="fa fa-list-ol"></i> 显示层级
+                        </button>
+                        <div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
+                            <a class="dropdown-item" name="showLevel" tag="1" href="javascript: void(0);">第一层</a>
+                            <a class="dropdown-item" name="showLevel" tag="2" href="javascript: void(0);">第二层</a>
+                            <a class="dropdown-item" name="showLevel" tag="3" href="javascript: void(0);">第三层</a>
+                            <a class="dropdown-item" name="showLevel" tag="4" href="javascript: void(0);">第四层</a>
+                            <a class="dropdown-item" name="showLevel" tag="5" href="javascript: void(0);">第五层</a>
+                            <a class="dropdown-item" name="showLevel" tag="last" href="javascript: void(0);">最底层</a>
+                            <a class="dropdown-item" name="showLevel" tag="leafXmj" href="javascript: void(0);">只显示项目节</a>
+                        </div>
+                    </div>
+                </div>
+                <div class="d-inline-block">
+                    <a href="javascript: void(0);" name="base-opr" type="add" class="btn btn-sm btn-light text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="新增"><i class="fa fa-plus" aria-hidden="true"></i></a>
+                    <a href="javascript: void(0);" name="base-opr" type="delete" class="btn btn-sm btn-light text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="删除"><i class="fa fa-remove" aria-hidden="true"></i></a>
+                    <a href="javascript: void(0);" name="base-opr" type="up-level" class="btn btn-sm btn-light text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="升级"><i class="fa fa-arrow-left" aria-hidden="true"></i></a>
+                    <a href="javascript: void(0);" name="base-opr" type="down-level" class="btn btn-sm btn-light text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="降级"><i class="fa fa-arrow-right" aria-hidden="true"></i></a>
+                    <a href="javascript: void(0);" name="base-opr" type="down-move" class="btn btn-sm btn-light text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="下移"><i class="fa fa-arrow-down" aria-hidden="true"></i></a>
+                    <a href="javascript: void(0);" name="base-opr" type="up-move" class="btn btn-sm btn-light text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="上移"><i class="fa fa-arrow-up" aria-hidden="true"></i></a>
+                    <a href="javascript: void(0);" name="cpc" type="copy" class="btn btn-sm btn-light text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="复制"><i class="fa fa-files-o" aria-hidden="true"></i></a>
+                    <a href="javascript: void(0);" name="cpc" type="cut" class="btn btn-sm btn-light text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="剪切"><i class="fa fa-scissors" aria-hidden="true"></i></a>
+                    <a href="javascript: void(0);" name="cpc" type="paste" class="btn btn-sm btn-light text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="粘贴"><i class="fa fa-clipboard" aria-hidden="true"></i></a>
+                </div>
+                <div class="d-inline-block">
+                    <div class="input-group input-group-sm ml-2">
+                        <div class="input-group-prepend">
+                            <span class="input-group-text" id="basic-addon1">表达式</span>
+                        </div>
+                        <input type="text" class="form-control form-control-sm m-0" id="bills-expr" readonly="">
+                    </div>
+                </div>
+            </div>
+            <div class="ml-auto">
+                <a class="btn btn-sm btn-primary mr-1" id="ledger-check2" href="javascript: void(0);">数据检查</a>
+            </div>
+        </div>
+    </div>
+    <div class="content-wrap row pr-46">
+        <div class="c-header p-0 col-12"></div>
+        <!--核心内容(两栏)-->
+        <div class="row w-100 sub-content">
+            <!--左栏-->
+            <div class="c-body" id="left-view" style="width: 100%">
+                <!--0号台账模式-->
+                <div class="sjs-height-1" style="overflow: hidden" id="bills-spread">
+                </div>
+                <% if (ctx.tender.data.measure_type === measureType.tz.value) { %>
+                <div class="bcontent-wrap">
+                    <div id="revise-resize" class="resize-y" id="top-spr" r-Type="height" div1=".sjs-height-1" div2=".bcontent-wrap" title="调整大小"><!--调整上下高度条--></div>
+                    <div class="bc-bar mb-1">
+                        <ul class="nav nav-tabs">
+                            <li class="nav-item">
+                                <a class="nav-link active" href="javascript:void(0)">计量单元</a>
+                            </li>
+                            <li class="ml-2 nav-item">
+                                <div class="d-inline-flex">
+                                    <a href="javascript: void(0);" name="pos-opr" type="down-move" class="btn btn-sm btn-light text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="下移"><i class="fa fa-arrow-down" aria-hidden="true"></i></a>
+                                    <a href="javascript: void(0);" name="pos-opr" type="up-move" class="btn btn-sm btn-light text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="上移"><i class="fa fa-arrow-up" aria-hidden="true"></i></a>
+                                </div>
+                            </li>
+                            <li class="nav-item" id="pos-search">
+                            </li>
+                            <li class="nav-item">
+                                <div class="d-inline-block">
+                                    <div class="input-group input-group-sm ml-2">
+                                        <div class="input-group-prepend">
+                                            <span class="input-group-text" id="basic-addon1">表达式</span>
+                                        </div>
+                                        <input type="text" class="form-control form-control-sm m-0" id="pos-expr" readonly="">
+                                    </div>
+                                </div>
+                            </li>
+                        </ul>
+                    </div>
+                    <div class="sp-wrap" id="pos-spread">
+                    </div>
+                </div>
+                <% } %>
+            </div>
+            <!--右栏-->
+            <div class="c-body" id="right-view" style="display: none; width: 33%;">
+                <div class="resize-x" id="revise-right-spr" r-Type="width" div1="#left-view" div2="#right-view" title="调整大小" a-type="percent"><!--调整左右高度条--></div>
+                <div class="tab-content">
+                    <div id="search" class="tab-pane">
+                    </div>
+                    <div id="std-xmj" class="tab-pane">
+                        <div class="sjs-bar">
+                            <div class="pb-1">
+                                <select class="form-control form-control-sm">
+                                    <% for (const c of stdChapters) { %>
+                                    <option value="<%- c.id %>" <% if (stdChapters.indexOf(c) === 0) { %>selected<% } %>><%- c.name %></option>
+                                    <% } %>
+                                </select>
+                            </div>
+                        </div>
+                        <div id="std-xmj-spread" class="sjs-sh">
+                        </div>
+                    </div>
+                    <div id="std-gcl" class="tab-pane">
+                        <div class="sjs-bar">
+                            <div class="pb-1">
+                                <select class="form-control form-control-sm">
+                                    <% for (const b of stdBills) { %>
+                                    <option value="<%- b.id %>" <% if (stdBills.indexOf(b) === 0) { %>selected<% } %>><%- b.name %></option>
+                                    <% } %>
+                                </select>
+                            </div>
+                        </div>
+                        <div id="std-gcl-spread" class="sjs-sh">
+                        </div>
+                    </div>
+                    <div id="deal-bills" class="tab-pane">
+                        <div class="sjs-bar">
+                            签约清单
+                            <a href="/tender/<%- ctx.tender.id %>/deal/download/签约清单.xlsx" class="btn btn-sm btn-primary" style="display: none">下载签约清单</a>
+                        </div>
+                        <div id="deal-bills-spread" class="sjs-sh">
+                        </div>
+                    </div>
+                    <div id="error-list" class="tab-pane">
+                    </div>
+                    <div id="check-list" class="tab-pane">
+                    </div>
+                    <div id="sum-load-miss" class="tab-pane tab-select-show">
+                    </div>
+                </div>
+            </div>
+        </div>
+        <!--右侧菜单-->
+        <div class="side-menu">
+            <!--右侧菜单-->
+            <ul class="nav flex-column right-nav" id="side-menu">
+                <li class="nav-item">
+                    <a class="nav-link" content="#search" href="javascript: void(0);">查找定位</a>
+                </li>
+                <li class="nav-item">
+                    <a class="nav-link" content="#std-xmj" href="javascript: void(0);">项目节</a>
+                </li>
+                <li class="nav-item">
+                    <a class="nav-link" content="#std-gcl" href="javascript: void(0);">标准清单</a>
+                </li>
+                <li class="nav-item">
+                    <a class="nav-link" content="#deal-bills" href="javascript: void(0);">签约清单</a>
+                </li>
+                <li class="nav-item">
+                    <a class="nav-link" content="#error-list" id="error-list-tab" href="javascript: void(0);" style="display: none;">错误列表</a>
+                </li>
+                <li class="nav-item">
+                    <a class="nav-link" content="#check-list" id="check-list-tab" href="javascript: void(0);" style="display: none;">数据检查</a>
+                </li>
+            </ul>
+        </div>
+    </div>
+</div>
+<script>
+    const readOnly = <%- readOnly %>;
+    const isTz = <%- ctx.tender.data.measure_type === measureType.tz.value %>;
+    const billsSpreadSetting = JSON.parse('<%- JSON.stringify(ledgerSpread) %>');
+    const posSpreadSetting = JSON.parse('<%- JSON.stringify(posSpread) %>');
+    const thousandth = <%- ctx.tender.info.display.thousandth %>;
+    const decimal = JSON.parse('<%- JSON.stringify(ctx.tender.info.decimal) %>');
+</script>

+ 40 - 0
app/view/change/revise_modal.ejs

@@ -0,0 +1,40 @@
+<!--批量添加清单部位-->
+<div class="modal fade" id="batch" data-backdrop="static">
+    <div class="modal-dialog modal-xl" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">批量插入清单-计量单元</h5>
+            </div>
+            <div class="modal-body">
+                <div class="custom-control custom-checkbox mb-2">
+                    <label class="form-check-label">
+                        <input class="form-check-input" type="checkbox" name="batch-filter">
+                        过滤无计量单元的清单
+                    </label>
+                </div>
+                <div class="row">
+                    <div class="col-6">
+                        <h6>清单信息</h6>
+                        <div class="batch-l-t">
+                        </div>
+                        <h6>计量单元数量复核表</h6>
+                        <div class="batch-l-b">
+                        </div>
+                    </div>
+                    <div class="col-6">
+                        <h6>签约清单</h6>
+                        <div class="batch-r">
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">取消</button>
+                <button type="button" class="btn btn-primary btn-sm" id="batch-ok">确定</button>
+            </div>
+        </div>
+    </div>
+</div>
+<% include ../shares/delete_hint_modal.ejs %>
+<% include ../shares/check_data_modal.ejs %>
+<% include ../shares/check_modal2.ejs %>

+ 12 - 0
app/view/change/sub_menu.ejs

@@ -0,0 +1,12 @@
+<div class="panel-sidebar" id="sub-menu">
+    <div class="sidebar-title" data-toggle="tooltip" data-placement="right" data-original-title="变更台账新增部位">变更台账新增部位</div>
+    <div class="scrollbar-auto">
+        <% include ./sub_menu_list.ejs %>
+        <div class="side-fold"><a href="javascript: void(0)" data-toggle="tooltip" data-placement="top" data-original-title="折叠侧栏" id="to-mini-menu"><i class="fa fa-upload fa-rotate-270"></i></a></div>
+    </div>
+    <script>
+        new Vue({
+            el: '.scrollbar-auto',
+        });
+    </script>
+</div>

+ 1 - 0
app/view/change/sub_menu_list.ejs

@@ -0,0 +1 @@
+<nav-menu title="返回" url="<%- preUrl %>" tclass="text-primary" ml="1" icon="fa-chevron-left"></nav-menu>

+ 16 - 0
app/view/change/sub_mini_menu.ejs

@@ -0,0 +1,16 @@
+<!--折起的菜单-->
+<div class="min-side" id="sub-mini-menu" style="display: none;">
+    <div id="sub-mini-hint" class="side-switch" data-container="body" data-toggle="popover" data-placement="bottom" data-content="这里打开收起的菜单栏"></div>
+    <div class="side-switch">
+        <i class="fa fa-bars"></i>
+    </div>
+    <div class="side-menu" id="mini-menu-list" style="display: none">
+        <% include ./sub_menu_list.ejs %>
+        <div class="side-fold"><a href="javascript: void(0);" data-toggle="tooltip" data-placement="top" data-original-title="展开侧栏" id="to-menu"><i class="fa fa-upload fa-rotate-90"></i></a></div>
+    </div>
+</div>
+<script>
+    new Vue({
+        el: '.side-menu',
+    });
+</script>

+ 27 - 1
config/web.js

@@ -830,21 +830,47 @@ const JsFiles = {
                 files: [
                     '/public/js/spreadjs/sheets/v11/gc.spread.sheets.all.11.2.2.min.js',
                     '/public/js/decimal.min.js',
+                    '/public/js/moment/moment.min.js',
                 ],
                 mergeFiles: [
                     '/public/js/sub_menu.js',
                     '/public/js/div_resizer.js',
                     '/public/js/spreadjs_rela/spreadjs_zh.js',
+                    '/public/js/shares/sjs_setting.js',
                     '/public/js/zh_calc.js',
                     '/public/js/path_tree.js',
                     '/public/js/gcl_gather.js',
                     '/public/js/jquery/jquery.form.min.js',
-                    '/public/js/moment/moment.min.js',
                     // '/public/js/change_calculation.js',
                     '/public/js/change_information.js',
                 ],
                 mergeFile: 'information',
             },
+            revise: {
+                files: [
+                    '/public/js/js-xlsx/xlsx.full.min.js',
+                    '/public/js/js-xlsx/xlsx.utils.js',
+                    '/public/js/spreadjs/sheets/v11/gc.spread.sheets.all.11.2.2.min.js',
+                    '/public/js/decimal.min.js',
+                    '/public/js/math.min.js',
+                    '/public/js/component/menu.js',
+                    '/public/js/moment/moment.min.js',
+                ],
+                mergeFiles: [
+                    '/public/js/sub_menu.js',
+                    '/public/js/div_resizer.js',
+                    '/public/js/spreadjs_rela/spreadjs_zh.js',
+                    '/public/js/shares/sjs_setting.js',
+                    '/public/js/shares/cs_tools.js',
+                    '/public/js/zh_calc.js',
+                    '/public/js/path_tree.js',
+                    '/public/js/std_lib.js',
+                    '/public/js/shares/tenders2tree.js',
+                    '/public/js/ledger_check.js',
+                    '/public/js/change_revise.js',
+                ],
+                mergeFile: 'change_revise',
+            },
         },
         datacollect: {
             index: {

+ 3 - 1
sql/update.sql

@@ -15,4 +15,6 @@ CREATE TABLE `zh_pay_attachment` (
   `renew` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '是否审批通过后上传',
   `username` varchar(10) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '用户名',
   PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+
+ALTER TABLE `zh_change_audit_list` ADD `mx_id` VARCHAR(50) NULL DEFAULT NULL COMMENT '计量单元id' AFTER `gcl_id`;