Browse Source

添加台账清单功能no.1 up

ellisran 10 months ago
parent
commit
343c5cbe9e

+ 91 - 1
app/controller/change_controller.js

@@ -648,6 +648,16 @@ module.exports = app => {
                         // 取所有工料表
                         responseData.data = await ctx.service.changeAuditList.getList(ctx.change.cid);
                         break;
+                        // 从新增部位页新增清单
+                    case 'add-change-list':
+                        await ctx.service.changeAuditList.adds(data.postData);
+                        responseData.data = { changeList: await ctx.service.changeAuditList.getList(ctx.change.cid) };
+                        break;
+                    // 从新增部位页删除清单
+                    case 'del-change-list':
+                        await ctx.service.changeAuditList.dels(data);
+                        responseData.data = { changeList: await ctx.service.changeAuditList.getList(ctx.change.cid) };
+                        break;
                     default: throw '参数有误';
                 }
 
@@ -838,6 +848,7 @@ module.exports = app => {
                 const settlePos = readySettle ? await this.ctx.service.settlePos.getAllDataByCondition({ where: { settle_id: readySettle.id } }) : [];
                 this.ctx.helper.assignRelaData(posData, [
                     { data: settlePos, fields: ['settle_status'], prefix: '', relaId: 'pid' },
+                    { data: settlePos, fields: ['settle_status'], prefix: '', relaId: 'pid' },
                 ]);
                 // 标记ledger,搜索需求
                 if (changePosData.length > 0) {
@@ -1515,7 +1526,7 @@ module.exports = app => {
         }
 
         /**
-         * 修订 详细页面(Get)
+         * 修订 详细页面(添加台账清单-台账模式)(Get)
          * @param ctx
          * @return {Promise<void>}
          */
@@ -1543,6 +1554,26 @@ module.exports = app => {
                 const renderData = await this._getDefaultReviseInfoData(ctx, change, !edit);
                 // 获取原报dsk数据
                 const accountInfo = await ctx.service.projectAccount.getDataById(change.uid);
+                renderData.changeList = await ctx.service.changeAuditList.getList(change.cid);
+                let changeUsedData = await ctx.service.stageChange.getAllFinalUsedData(ctx.tender.id, change.cid);
+                changeUsedData = ctx.helper._.orderBy(ctx.helper._.filter(changeUsedData, function(item) {
+                    return item.qty !== null;
+                }), ['sorder'], ['desc']);
+                const useChangeUsedData = [];
+                if (changeUsedData.length > 0) { // 防止未创建期时调用
+                    for (const cu of changeUsedData) {
+                        const index = ctx.helper._.findIndex(useChangeUsedData, { cbid: cu.cbid });
+                        if (index !== -1) {
+                            useChangeUsedData[index].qty = ctx.helper.add(useChangeUsedData[index].qty, cu.qty);
+                        } else {
+                            useChangeUsedData.push(cu);
+                        }
+                    }
+                }
+                renderData.changeUsedData = useChangeUsedData;
+                const readySettle = await ctx.service.settle.getReadySettle(ctx.tender.id);
+                renderData.settleBills = readySettle ? await this.ctx.service.settleBills.getAllDataByCondition({ where: { settle_id: readySettle.id } }) : [];
+                renderData.settlePos = readySettle ? await this.ctx.service.settlePos.getAllDataByCondition({ where: { settle_id: readySettle.id } }) : [];
                 renderData.dskAccountData = accountInfo && accountInfo.dsk_account ? JSON.parse(accountInfo.dsk_account) : {};
                 renderData.dskProjects = accountInfo && accountInfo.dsk_account && accountInfo.dsk_projects ? JSON.parse(accountInfo.dsk_projects) : [];
                 // 台账只读、使用数据
@@ -1557,6 +1588,65 @@ module.exports = app => {
             }
         }
 
+        /**
+         * 修订 详细页面(添加台账清单-清单模式)(Get)
+         * @param ctx
+         * @return {Promise<void>}
+         */
+        async addListInfo(ctx) {
+            try {
+                const change = ctx.change;
+                let edit = true;
+                let changing = false;
+                if (change.status !== audit.change.status.uncheck && change.status !== audit.change.status.checkNo && change.status !== audit.change.status.revise) {
+                    // throw '本条变更审批中或已完成,无法操作台账数据';
+                    edit = false;
+                    changing = true;
+                }
+                const renderData = {
+                    change,
+                    tpUnit: change.tp_decimal ? change.tp_decimal : ctx.tender.info.decimal.tp,
+                    upUnit: change.up_decimal ? change.up_decimal : ctx.tender.info.decimal.up,
+                    precision: ctx.tender.info.precision,
+                    tender: ctx.tender.data,
+                    preUrl: '/tender/' + ctx.tender.id + '/change/' + ctx.change.cid + '/information',
+                    jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.change.addList),
+                    auditConst: audit.change,
+                    settleStatus: ctx.service.settle.settleStatus,
+                };
+                // 获取原报dsk数据
+                const accountInfo = await ctx.service.projectAccount.getDataById(change.uid);
+                renderData.changeList = await ctx.service.changeAuditList.getList(change.cid);
+                let changeUsedData = await ctx.service.stageChange.getAllFinalUsedData(ctx.tender.id, change.cid);
+                changeUsedData = ctx.helper._.orderBy(ctx.helper._.filter(changeUsedData, function(item) {
+                    return item.qty !== null;
+                }), ['sorder'], ['desc']);
+                const useChangeUsedData = [];
+                if (changeUsedData.length > 0) { // 防止未创建期时调用
+                    for (const cu of changeUsedData) {
+                        const index = ctx.helper._.findIndex(useChangeUsedData, { cbid: cu.cbid });
+                        if (index !== -1) {
+                            useChangeUsedData[index].qty = ctx.helper.add(useChangeUsedData[index].qty, cu.qty);
+                        } else {
+                            useChangeUsedData.push(cu);
+                        }
+                    }
+                }
+                renderData.changeUsedData = useChangeUsedData;
+                const readySettle = await ctx.service.settle.getReadySettle(ctx.tender.id);
+                renderData.settleBills = readySettle ? await this.ctx.service.settleBills.getAllDataByCondition({ where: { settle_id: readySettle.id } }) : [];
+                renderData.settlePos = readySettle ? await this.ctx.service.settlePos.getAllDataByCondition({ where: { settle_id: readySettle.id } }) : [];
+                // 台账只读、使用数据
+                renderData.readOnly = !edit;
+                renderData.changing = changing;
+                renderData.isYb = change.uid === ctx.session.sessionUser.accountId;
+                await this.layout('change/addlist.ejs', renderData, 'change/addlist_modal.ejs');
+            } catch (err) {
+                this.log(err);
+                ctx.redirect(ctx.request.header.referer);
+            }
+        }
+
         async _getDefaultReviseInfoData(ctx, change, edit) {
             const [ledgerSpread, posSpread] = await spreadSetting.getLedgerSpreadSetting(ctx, change.tid, edit);
             const [stdBills, stdChapters] = await this.ctx.service.valuation.getValuationStdList(

+ 677 - 0
app/public/js/change_information_add_list.js

@@ -0,0 +1,677 @@
+'use strict';
+
+/**
+ * 变更令详细页js
+ *
+ * @author EllisRan.
+ * @date 2018/11/22
+ * @version
+ */
+// 编号排序,多重判断
+function sortByCode(a, b) {
+    let code1 = a.code.split('-');
+    let code2 = b.code.split('-');
+    let code1length = code1.length;
+    let code2length = code2.length;
+    for (let i = 0; i < code1length; i ++) {
+        if (i+1 <= code2length) {
+            if (code1[i] != code2[i]) {
+                if (/^\d+$/.test(code1[i]) && /^\d+$/.test(code2[i])) {
+                    return parseInt(code1[i]) - parseInt(code2[i]);
+                } else if (!/^\d+$/.test(code1[i]) && /^\d+$/.test(code2[i])) {
+                    return 1;
+                } else if (/^\d+$/.test(code1[i]) && !/^\d+$/.test(code2[i])) {
+                    return -1;
+                } else {
+                    const str1length = code1[i].length;
+                    const str2length = code2[i].length;
+                    for (let j = 0; j < str1length; j++) {
+                        if (j+1 <= str2length) {
+                            if (code1[i].charAt(j) != code2[i].charAt(j)) {
+                                return code1[i].charAt(j).charCodeAt() - code2[i].charAt(j).charCodeAt();
+                            }  else if (j+1 == str1length && code1[i].charAt(j) == code2[i].charAt(j)) {
+                                if (str1length == str2length) {
+                                    return 0;
+                                } else {
+                                    return str1length - str2length;
+                                }
+                            }
+                        } else {
+                            if (j+1 >= str1length) {
+                                return 1;
+                            } else {
+                                return -1;
+                            }
+                        }
+                    }
+                }
+            } else if (i+1 == code1length && code1[i] == code2[i]) {
+                if (code1length == code2length) {
+                    return 0;
+                } else {
+                    return code1length - code2length;
+                }
+            }
+        } else {
+            if (i+1 >= code1length) {
+                return 1;
+            } else {
+                return -1;
+            }
+        }
+    }
+}
+let searchCodeList = [];
+$(document).ready(() => {
+    let searchGcl;
+    autoFlashHeight();
+    const gclSpreadSetting = {
+        cols: [
+            {title: '清单编号', colSpan: '1', rowSpan: '2', field: 'code', hAlign: 0, width: 120, formatter: '@'},
+            {title: '名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 300, formatter: '@'},
+            {title: '单位', colSpan: '1', rowSpan: '2', field: 'unit', hAlign: 1, width: 100, formatter: '@'},
+            {title: '单价', colSpan: '1', rowSpan: '2', field: 'unit_price', hAlign: 2, width: 100},
+            {title: '数量', colSpan: '1', rowSpan: '2', field: 'quantity', hAlign: 2, width: 100},
+        ],
+        emptyRows: 0,
+        headRows: 2,
+        headRowHeight: [25, 25],
+        defaultRowHeight: 21,
+        headerFont: '12px 微软雅黑',
+        font: '12px 微软雅黑',
+        readOnly: true,
+        rowHeader:[
+            {
+                rowHeaderType: 'circle',
+                setting: {
+                    size: 5,
+                    indent: 16,
+                    getColor: function (index, data) {
+                        if (!data) return;
+                        if (data.cid) {
+                            return '#dc3545';
+                        }
+                    }
+                },
+            },
+        ],
+        localCache: {
+            key: 'change-add-list-gcl-spread',
+            colWidth: true,
+        }
+    };
+
+    gclSpreadSetting.getColor = function (sheet, data, row, col, defaultColor) {
+        if (data && data.settle_status && data.settle_status === settleStatus.finish) {
+            return spreadColor.stage.settle;
+        }
+        if (data && data.is_change) {
+            return '#c3e6cb';
+        }
+        return defaultColor;
+    }
+
+    const gclSpreadObj = {
+        resetXmjSpread: function(data = null) {
+            const xmjs = [];
+            if (data && data.id) {
+                xmjs.push({
+                    cid: '',
+                    is_change: _.findIndex(changeList, { lid: data.id }) !== -1 ? 1 : 0,
+                    code: '',
+                    jldy: '',
+                    dwgc: '',
+                    fbgc: '',
+                    fxgc: '',
+                    bwmx: '',
+                    quantity: '',
+                })
+            } else if (data && data.leafXmjs) {
+                for (const leaf of data.leafXmjs) {
+                    xmjs.push({
+                        is_change: _.findIndex(changeList, { gcl_id: leaf.gcl_id, mx_id: leaf.mx_id || '' }) !== -1 ? 1 : 0,
+                        cid: leaf.cid || '',
+                        code: leaf.code,
+                        jldy: leaf.jldy || '',
+                        dwgc: leaf.dwgc || '',
+                        fbgc: leaf.fbgc || '',
+                        fxgc: leaf.fxgc || '',
+                        bwmx: leaf.bwmx || '',
+                        quantity: leaf.quantity ? ZhCalc.round(leaf.quantity, findDecimal(data.unit)).toString() : '0',
+                    });
+                }
+            }
+            SpreadJsObj.loadSheetData(xmjSpreadSheet, SpreadJsObj.DataType.Data, xmjs);
+            checkSelectAll();
+        },
+        selectionChanged: function (e, info) {
+            const data = SpreadJsObj.getSelectObject(info.sheet);
+            gclSpreadObj.resetXmjSpread(data);
+        }
+    };
+
+    const xmjSpreadSetting = {
+        cols: [
+            { title: '变更清单', colSpan: '1', rowSpan: '2', field: 'is_change', hAlign: 1, width: 60, cellType: 'checkbox', readOnly: 'readOnly.isChangeList'},
+            {title: '项目节编号', colSpan: '1', rowSpan: '2', field: 'code', hAlign: 0, width: 120, formatter: '@', readOnly: true},
+            {title: '细目', colSpan: '1', rowSpan: '2', field: 'jldy', hAlign: 0, width: 150, formatter: '@', readOnly: true},
+            {title: '单位工程', colSpan: '1', rowSpan: '2', field: 'dwgc', hAlign: 0, width: 150, formatter: '@', readOnly: true},
+            {title: '分部工程', colSpan: '1', rowSpan: '2', field: 'fbgc', hAlign: 0, width: 150, readOnly: true},
+            {title: '分项工程', colSpan: '1', rowSpan: '2', field: 'fxgc', hAlign: 0, width: 150, readOnly: true},
+            {title: '计量单元', colSpan: '1', rowSpan: '2', field: 'bwmx', hAlign: 0, width: 150, readOnly: true},
+            {title: '数量', colSpan: '1', rowSpan: '2', field: 'quantity', hAlign: 2, width: 100, readOnly: true},
+        ],
+        emptyRows: 0,
+        headRows: 2,
+        headRowHeight: [25, 25],
+        defaultRowHeight: 21,
+        headerFont: '12px 微软雅黑',
+        font: '12px 微软雅黑',
+        rowHeader:[
+            {
+                rowHeaderType: 'circle',
+                setting: {
+                    size: 5,
+                    indent: 16,
+                    getColor: function (index, data) {
+                        if (!data) return;
+                        if (data.cid) {
+                            return '#dc3545';
+                        }
+                    }
+                },
+            },
+        ],
+    };
+
+    const xmjCol = {
+        readOnly: {
+            isChangeList: function (data) {
+                if (!data) return true;
+                return !readOnly;
+            }
+        }
+    };
+
+    const preUrl = window.location.pathname.split('/').slice(0, 4).join('/');
+    let changeListData;
+    let gclGatherData;
+    const gclSpread = SpreadJsObj.createNewSpread($('#gcl-spread')[0]);
+    const gclSpreadSheet = gclSpread.getActiveSheet();
+    const xmjSpread = SpreadJsObj.createNewSpread($('#xmj-spread')[0]);
+    const xmjSpreadSheet = xmjSpread.getActiveSheet();
+    sjsSettingObj.setGridSelectStyle(gclSpreadSetting);
+    SpreadJsObj.initSheet(gclSpreadSheet, gclSpreadSetting);
+    SpreadJsObj.initSpreadSettingEvents(xmjSpreadSetting, xmjCol);
+    SpreadJsObj.initSheet(xmjSpreadSheet, xmjSpreadSetting);
+    postData(preUrl + '/defaultBills', { from: 'batch' }, function (result) {
+        gclGatherModel.loadLedgerData(result.bills);
+        gclGatherModel.loadPosData(result.pos);
+
+        gclGatherData = gclGatherModel.gatherGclData();
+        gclGatherData = _.filter(gclGatherData, function (item) {
+            return item.leafXmjs && item.leafXmjs.length !== 0;
+        });
+        for (const ggd in gclGatherData) {
+            if (gclGatherData[ggd].leafXmjs && gclGatherData[ggd].leafXmjs.length === 0) {
+                gclGatherData.splice(ggd, 1);
+            }
+            gclGatherData[ggd].code = gclGatherData[ggd].b_code;
+            let hadcid = 0;
+            for (const xmj of gclGatherData[ggd].leafXmjs) {
+                const changeLedger = _.find(result.changeLedgerList, { id: xmj.gcl_id });
+                const changePos = _.find(result.changePosList, { id: xmj.mx_id, lid: xmj.gcl_id });
+                if (changeLedger || changePos) {
+                    xmj.cid = 1;
+                    xmj.ccid = changeLedger ? changeLedger.ccid : changePos.ccid;
+                    hadcid = 1;
+                }
+            }
+
+            if (hadcid !== 0) gclGatherData[ggd].cid = 1;
+        }
+        // 数组去重
+        const dealBillList = result.dealBills;
+        for (const db of gclGatherData) {
+            const exist_index = dealBillList.findIndex(function (item) {
+                return item.code === db.code && item.name === db.name && item.unit === db.unit && item.unit_price === db.unit_price;
+            });
+            if (exist_index !== -1) {
+                dealBillList.splice(exist_index, 1);
+            }
+        }
+        changeListData = gclGatherData.concat(dealBillList).sort(sortByCode);
+        for (const gcl of changeListData) {
+            gcl.unit = gcl.unit !== undefined && gcl.unit !== null ? gcl.unit : '';
+            gcl.quantity = gcl.quantity !== 0 && gcl.quantity !== null && gcl.quantity !== undefined ? (gcl.unit !== '' ? ZhCalc.round(gcl.quantity, findDecimal(gcl.unit)) : gcl.quantity).toString() : '0';
+            gcl.unit_price = gcl.unit_price !== null && gcl.unit_price !== undefined ? ZhCalc.round(gcl.unit_price, unitPriceUnit) : 0;
+            // 用id值区分签约清单和台账
+            if (gcl.id) {
+                const cInfo = gcl.id ? _.find(changeList, { lid: gcl.id }) : null;
+                gcl.is_change = cInfo ? 1 : 0;
+            } else {
+                const index = gcl.leafXmjs && gcl.leafXmjs.length !== 0 ? _.findIndex(gcl.leafXmjs, function (item) {
+                    return _.findIndex(changeList, { gcl_id: item.gcl_id }) !== -1;
+                }) : -1;
+                gcl.is_change = index !== -1 ? 1 : 0;
+            }
+        }
+        console.log(changeListData);
+        SpreadJsObj.loadSheetData(gclSpreadSheet, SpreadJsObj.DataType.Data, changeListData);
+        gclSpreadObj.resetXmjSpread(SpreadJsObj.getSelectObject(gclSpreadSheet));
+    });
+    gclSpread.bind(spreadNS.Events.SelectionChanged, gclSpreadObj.selectionChanged);
+
+    $.divResizer({
+        select: '#revise-right-spr',
+        callback: function () {
+            gclSpread.refresh();
+            xmjSpread.refresh();
+            if (searchGcl) searchGcl.spread.refresh();
+        }
+    });
+    $.subMenu({
+        menu: '#sub-menu', miniMenu: '#sub-mini-menu', miniMenuList: '#mini-menu-list',
+        toMenu: '#to-menu', toMiniMenu: '#to-mini-menu',
+        key: 'menu.1.0.0',
+        miniHint: '#sub-mini-hint', hintKey: 'menu.hint.1.0.1',
+        callback: function (info) {
+            if (info.mini) {
+                $('.panel-title').addClass('fluid');
+                $('#sub-menu').removeClass('panel-sidebar');
+            } else {
+                $('.panel-title').removeClass('fluid');
+                $('#sub-menu').addClass('panel-sidebar');
+            }
+            autoFlashHeight();
+            gclSpread.refresh();
+            xmjSpread.refresh();
+            if (searchGcl) searchGcl.spread.refresh();
+        }
+    });
+    gclSpread.refresh();
+    xmjSpread.refresh();
+
+    // 展开收起标准节点
+    $('a', '#side-menu').bind('click', function (e) {
+        e.preventDefault();
+        const tab = $(this), tabPanel = $(tab.attr('content'));
+        // 展开工具栏、切换标签
+        if (!tab.hasClass('active')) {
+            const close = $('.active', '#side-menu').length === 0;
+            $('a', '#side-menu').removeClass('active');
+            tab.addClass('active');
+            $('.tab-content .tab-pane').removeClass('active');
+            tabPanel.addClass('active');
+            showSideTools(tab.hasClass('active'));
+            if (tab.attr('content') === '#search') {
+                if (!searchGcl) {
+                    searchGcl = $.listSearch({
+                        selector: '#search',
+                        searchSpread: gclSpread,
+                        searchOver: true,
+                        searchEmpty: true,
+                        resultSpreadSetting: {
+                            cols: [
+                                {title: '清单编号', field: 'code', hAlign: 0, width: 80, formatter: '@'},
+                                {title: '名称', field: 'name', width: 150, hAlign: 0, formatter: '@'},
+                                {title: '单位', field: 'unit', width: 50, hAlign: 1, formatter: '@'},
+                                {title: '单价', field: 'unit_price', hAlign: 2, width: 50},
+                                {title: '数量', field: 'quantity', hAlign: 2, width: 50},
+                            ],
+                            emptyRows: 0,
+                            headRows: 1,
+                            headRowHeight: [32],
+                            headColWidth: [30],
+                            defaultRowHeight: 21,
+                            headerFont: '12px 微软雅黑',
+                            font: '12px 微软雅黑',
+                            selectedBackColor: '#fffacd',
+                            readOnly: true,
+                        },
+                        afterLocated: function () {
+                            gclSpreadObj.resetXmjSpread(SpreadJsObj.getSelectObject(gclSpreadSheet));
+                        },
+                        check: function(data, keyword) {
+                            return !keyword ||
+                                (data.code && data.code.indexOf(keyword) > -1) ||
+                                (data.name && data.name.indexOf(keyword) > -1);
+                        },
+                        customSearch: [
+                            {
+                                key: 'revise', title: '新增部位', valid: true, parent: true,
+                                check: function (node) {
+                                    if (node.formc || node.cid) {
+                                        return true;
+                                    } else {
+                                        return false;
+                                    }
+                                }
+                            }
+                        ],
+                    });
+                }
+                searchGcl.spread.refresh();
+            }
+        }
+        else {// 收起工具栏
+            tab.removeClass('active');
+            tabPanel.removeClass('active');
+            showSideTools(tab.hasClass('active'));
+        }
+        gclSpread.refresh();
+        xmjSpread.refresh();
+    });
+
+    // 回车提交
+    $('#list-input').on('keypress', function () {
+        if(window.event.keyCode === 13) {
+            $(this).blur();
+        }
+    });
+    $('#list-input').on('blur', function () {
+        const select = parseInt($('#select-list').val());
+        const value = _.trim($(this).val());
+        const valueList = _.slice(_.without(_.uniq(_.replace(_.replace(value, /\'|\"/g, ''), /\t/g, ' ').split(' ')), ''), 0, 10);
+        // console.log(valueList);
+        // 判断是否存在多个分词,以换行或空格分隔,多个则显示左侧菜单
+        if (value !== '' && valueList.length > 1) {
+            if (_.without(_.uniq(value.split(' ')), '').length > 10) {
+                toastr.warning('最多筛选以空格分割的前10个不重复关键词');
+            }
+            $('#table-list').addClass('col-9').removeClass('col-12');
+            $('#table-list').siblings('.col-3').show();
+            $('#list-search-keyword').html('<tr data-keyword="" class="text-white bg-primary"><td class="border-primary">全部</td></tr>');
+            for (const v of valueList) {
+                $('#list-search-keyword').append(`<tr data-keyword="${v}" class=""><td>${v}</td></tr>`);
+            }
+            $('#list-input').val(valueList.join(' '));
+        } else {
+            $('#table-list').addClass('col-12').removeClass('col-9');
+            $('#table-list').siblings('.col-3').hide();
+            $('#list-search-keyword').html('<tr data-keyword="" class="text-white bg-primary border-primary"><td class="border-primary">全部</td></tr>');
+        }
+        let showListData = changeListData;
+        if (select === 1 && value !== '') {
+            $(this).siblings('a').show();
+            showListData = _.filter(changeListData, function (c) {
+                let flag = false;
+                if (c.cid) {
+                    for(const v of valueList) {
+                        if ((c.code && c.code.indexOf(v) !== -1) || (c.name && c.name.indexOf(v) !== -1)) {
+                            flag = true;
+                            break;
+                        }
+                    }
+                }
+                return flag;
+                // return ((c.code && c.code.indexOf(value) !== -1) || (c.name && c.name.indexOf(value) !== -1)) && c.cid;
+            });
+        } else if (select === 1 && value === '') {
+            $(this).siblings('a').hide();
+            showListData = _.filter(changeListData, function (c) {
+                return c.cid;
+            });
+        } else if (value !== '') {
+            $(this).siblings('a').show();
+            showListData = _.filter(changeListData, function (c) {
+                let flag = false;
+                for(const v of valueList) {
+                    if ((c.code && c.code.indexOf(v) !== -1) || (c.name && c.name.indexOf(v) !== -1)) {
+                        flag = true;
+                        break;
+                    }
+                }
+                return flag;
+                // return (c.code && c.code.indexOf(value) !== -1) || (c.name && c.name.indexOf(value) !== -1);
+            });
+        } else {
+            $(this).siblings('a').hide();
+        }
+        makeListTable(changeListData, showListData);
+        $('#table-list-select tr').removeClass('table-warning');
+        $('#code-input').val('');
+        $('#code-input').siblings('a').hide();
+        $('#code-list').html('');
+        $('#code-select-all').prop('checked', false);
+    });
+    // 双击编辑搜索值
+    $('body').on('dblclick', '#list-search-keyword tr', function () {
+        if ($(this).attr('data-keyword') !== '') {
+            $(this).children('td').html(`<input class="form-control form-control-sm" value="">`);
+            $(this).find('input').focus();
+            $(this).find('input').val($(this).attr('data-keyword'));
+        }
+    });
+    // 光标离开
+    $('body').on('blur', '#list-search-keyword tr td input', function () {
+        let val = $(this).val();
+        const oldVal = $(this).parents('tr').attr('data-keyword');
+        if (_.trim(val) === '') {
+            toastr.warning('不能为空');
+            val = oldVal;
+        } else if (_.trim(val) === oldVal) {
+            val = oldVal;
+        } else {
+            const value = _.trim($('#list-input').val());
+            const valueList = _.slice(_.without(_.uniq(_.replace(value, /\t/g, ' ').split(' ')), ''), 0, 10);
+            // console.log(_.indexOf(valueList, oldVal), valueList, val, oldVal);
+            if (_.indexOf(valueList, val) !== -1) {
+                toastr.warning('已存在相同的检索词');
+                val = oldVal;
+            }
+            valueList.splice(_.indexOf(valueList, oldVal), 1, val);
+            $('#list-input').val(valueList.join(' '));
+            const select = parseInt($('#select-list').val());
+            const showListData = _.filter(changeListData, function (c) {
+                return ((c.code && c.code.indexOf(val) !== -1) || (c.name && c.name.indexOf(val) !== -1)) && (select === 1 ? c.cid : 1);
+            });
+            makeListTable(changeListData, showListData);
+            $('#table-list-select tr').removeClass('table-warning');
+            $('#code-input').val('');
+            $('#code-input').siblings('a').hide();
+            $('#code-list').html('');
+            $('#code-select-all').prop('checked', false);
+        }
+        $(this).parents('tr').attr('data-keyword', val);
+        $(this).parents('td').html(`${val}`);
+    });
+    $('body').on('keypress', '#list-search-keyword tr td input', function () {
+        if(window.event.keyCode === 13) {
+            $(this).blur();
+        }
+    });
+    $("#addlist").draggable({ handle: '.modal-header, .modal-footer'});
+    // 检索关键字切换
+    $('body').on('click', '#list-search-keyword tr', function () {
+        if (!$(this).hasClass('bg-primary')) {
+            const keyword = $(this).attr('data-keyword');
+            $(this).siblings().removeClass('text-white bg-primary');
+            $(this).siblings().children('td').removeClass('border-primary');
+            $(this).addClass('text-white bg-primary');
+            $(this).children('td').addClass('border-primary');
+            if (keyword === '') {
+                $('#list-input').blur();
+            } else {
+                const select = parseInt($('#select-list').val());
+                const showListData = _.filter(changeListData, function (c) {
+                    return ((c.code && c.code.indexOf(keyword) !== -1) || (c.name && c.name.indexOf(keyword) !== -1)) && (select === 1 ? c.cid : 1);
+                });
+                makeListTable(changeListData, showListData);
+                $('#table-list-select tr').removeClass('table-warning');
+                $('#code-input').val('');
+                $('#code-input').siblings('a').hide();
+                $('#code-list').html('');
+                $('#code-select-all').prop('checked', false);
+            }
+        }
+    });
+    // 回车提交
+    $('#code-input').on('keypress', function () {
+        if(window.event.keyCode === 13) {
+            $(this).blur();
+        }
+    });
+    $('#code-input').on('blur', function () {
+        const value = $(this).val();
+        if (value !== '') {
+            $(this).siblings('a').show();
+        } else {
+            $(this).siblings('a').hide();
+        }
+        makeCodeTable($(this).val());
+        checkSelectAll();
+    });
+
+    $('.remove-btn').on('click', function () {
+        $(this).hide();
+        $(this).siblings('input').val('');
+        if ($(this).data('btn') === 'list') {
+            const select = parseInt($('#select-list').val());
+            let showListData = changeListData;
+            if (select === 1) {
+                showListData = _.filter(changeListData, function (c) {
+                    return c.cid;
+                });
+            }
+            makeListTable(changeListData, showListData);
+            $('#table-list-select tr').removeClass('table-warning');
+            $('#code-list').html('');
+            $('#table-list').addClass('col-12').removeClass('col-9');
+            $('#table-list').siblings('.col-3').hide();
+            $('#list-search-keyword').html('');
+            $('#list-search-keyword').siblings('a').addClass('active');
+        } else {
+            makeCodeTable();
+        }
+        checkSelectAll();
+    });
+    // 全选及取消
+    $('#code-select-all').click(function () {
+        // 全选checkbox
+        let index = $('#code-list').attr('data-index');
+        if (index) {
+            if ($(this).is(':checked')){
+                $('#code-list tr').each(function () {
+                    if ($(this).css('display') !== 'none' && $(this).find('input').prop('disabled') !== true) {
+                        $(this).find('input').prop('checked', true);
+                    }
+                })
+            } else {
+                $('#code-list tr').each(function () {
+                    if ($(this).css('display') !== 'none' && $(this).find('input').prop('disabled') !== true) {
+                        $(this).find('input').prop('checked', false);
+                    }
+                });
+            }
+            // 判断还有无选中项目节编号
+            if ($('#code-list input').is(':checked')) {
+                // 去除部分data-detail值
+                let data_bwmx = [];
+                let data_charu = [];
+                $('#code-list input:checked').each(function () {
+                    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 === 9 ?
+                        tr.children('td').eq(1).text() + '!_!' +
+                        tr.children('td').eq(2).text() + '!_!' +
+                        tr.children('td').eq(3).text() + '!_!' +
+                        tr.children('td').eq(4).text() + '!_!' +
+                        tr.children('td').eq(5).text() + '!_!' + gcl_id + '!_!' + mx_id + '!_!' +
+                        (tr.children('td').eq(6).text() !== '' ? tr.children('td').eq(6).text() : tr.children('td').eq(2).text()) : '0';
+                    const quantity = tr.attr('quantity');
+                    const de_qu = bwmx + '*;*' + quantity;
+                    data_bwmx.push(de_qu);
+                    if (changeOrder && $(this).prop('disabled') !== true) {
+                        data_charu.push(de_qu);
+                    }
+                });
+                data_bwmx = data_bwmx.join('$#$');
+                $('#table-list-select tr[data-index="' + index + '"]').attr('data-bwmx', data_bwmx);
+                if (changeOrder) {
+                    data_charu = data_charu.join('$#$');
+                    $('#table-list-select tr[data-index="' + index + '"]').attr('data-charu', data_charu);
+                }
+                $('#table-list-select tr[data-index="' + index + '"]').addClass('table-success');
+            } else {
+                $('#table-list-select tr[data-index="' + index + '"]').removeClass('table-success');
+                $('#table-list-select tr[data-index="' + index + '"]').attr('data-bwmx', '');
+                if (changeOrder) {
+                    $('#table-list-select tr[data-index="' + index + '"]').attr('data-charu', '');
+                }
+            }
+        }
+    });
+    // 选中所有新增部位/清单
+    $('#select-all-revise').click(function() {
+        const qtySpr = '*;*', infoSpr = '!_!', recSpr = '$#$';
+        const gclTr = $('#table-list-select tr');
+        for (const tr of gclTr) {
+            const lid = $(tr).data('lid');
+            let gcl = _.find(gclGatherData, function (item) {
+                return item.leafXmjs && item.leafXmjs[0].gcl_id === lid;
+            });
+            if (!gcl) gcl = gclGatherData[$(this).data('gcl')];
+            if (!gcl || !gcl.cid) continue;
+
+            let data_bwmx = [];
+            if ($(tr).attr('data-bwmx') !== '') {
+                data_bwmx = $(tr).attr('data-bwmx').split(recSpr);
+                data_bwmx = data_bwmx.filter(x => {
+                    const rec = x.split(qtySpr);
+                    const info = rec[0].split(infoSpr);
+                    if (info.length < 8) return true;
+
+                    const leaf = gcl.leafXmjs.find(lx => { return lx.mx_id === info[6]});
+                    return !leaf || !leaf.cid || leaf.ccid !== window.location.pathname.split('/')[4];
+                });
+            }
+            let hasNew = false;
+            for (const [index, leaf] of gcl.leafXmjs.entries()) {
+                if (!leaf.cid || leaf.ccid !== window.location.pathname.split('/')[4]) continue;
+                const bwmx = [leaf.code, leaf.jldy || '', leaf.dwgc || '', leaf.fbgc || '', leaf.fxgc || '', leaf.gcl_id, leaf.mx_id, leaf.bwmx || leaf.jldy || ''];
+                const de_qu = bwmx.join(infoSpr) + qtySpr + (leaf.quantity || 0);
+                if (data_bwmx.indexOf(de_qu) < 0) data_bwmx.push(de_qu);
+                hasNew = true;
+            }
+            if (hasNew) $(tr).attr('data-bwmx', data_bwmx.join(recSpr)).addClass('table-success');
+        }
+
+        // 触发点击当前清单,重载当前全部部位
+        const dataIndex = $('#code-list').attr('data-index');
+        if (dataIndex) {
+            $(`tr[data-index=${dataIndex}]`).trigger('click');
+        }
+    });
+});
+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);
+}
+function findDecimal(unit) {
+    let value = precision.other.value;
+    const changeUnits = precision;
+    for (const d in changeUnits) {
+        if (changeUnits[d].unit !== undefined && changeUnits[d].unit === unit) {
+            value = changeUnits[d].value;
+            break;
+        }
+    }
+    return value;
+}

+ 42 - 1
app/public/js/change_information_set.js

@@ -959,11 +959,13 @@ $(document).ready(() => {
             }
         }
         changeListData = gclGatherData.concat(dealBillList).sort(sortByCode);
+        tableDataRemake(changeListData);
         console.log(changeListData);
         // 先加载台账数据
         let listHtml = '';
         let list_index = 1;
         let gcl_index = 0;
+        const newChangeList = [];
         for (const gcl of changeListData) {
             const unit = gcl.unit !== undefined && gcl.unit !== null ? gcl.unit : '';
             const quantity = gcl.quantity !== 0 && gcl.quantity !== null && gcl.quantity !== undefined ? (unit !== '' ? ZhCalc.round(gcl.quantity, findDecimal(gcl.unit)) : gcl.quantity) : 0;
@@ -982,9 +984,48 @@ $(document).ready(() => {
                     '</tr>';
                 list_index++;
             }
+            if (!changeOrder) {
+                if (gcl.leafXmjs !== undefined && gcl.leafXmjs !== null) {
+                    const cl = _.filter(changeList, function (item) {
+                        return _.findIndex(gcl.leafXmjs, { gcl_id: item.gcl_id }) !== -1;
+                    });
+                    if (cl.length > 0) {
+                        if (gcl.leafXmjs.length === 1 && !gcl.leafXmjs[0].bwmx) {
+                            newChangeList.push(cl[0]);
+                        } else {
+                            for (const l of gcl.leafXmjs) {
+                                const c = _.find(cl, { mx_id: l.mx_id });
+                                if (c) newChangeList.push(c);
+                            }
+                        }
+                    }
+                } else {
+                    // 签约清单
+                    const c = _.find(changeList, { lid: gcl.id });
+                    if (c) newChangeList.push(c);
+                }
+            }
+        }
+        // 按台账去重新排序changeList,空白清单居后
+        if (!changeOrder) {
+            const sycList = _.difference(changeList, newChangeList);
+            console.log(sycList);
+            changeList = newChangeList.concat(sycList);
+            console.log(changeList);
+            // order如果不同,则修改并提交
+            const updateOrderList = [];
+            for (let i = 0; i < changeList.length; i++) {
+                if (changeList[i].order !== i + 1) {
+                    changeList[i].order = i + 1;
+                    updateOrderList.push({ id: changeList[i].id, order: i + 1 });
+                }
+            }
+            if (updateOrderList.length > 0) {
+                postData(window.location.pathname + '/save', { type:'changeOrder', postData: updateOrderList }, function (result) {
+                });
+            }
         }
         $('#table-list-select').html(listHtml);
-        tableDataRemake(changeListData);
 
         SpreadJsObj.initSpreadSettingEvents(changeSpreadSetting, changeCol);
         SpreadJsObj.initSheet(changeSpreadSheet, changeSpreadSetting);

+ 235 - 1
app/public/js/change_revise.js

@@ -54,12 +54,14 @@ const checkOption = {
 $(document).ready(() => {
     let stdXmj, stdGcl, searchLedger;
     autoFlashHeight();
+    billsSpreadSetting.cols.unshift({ title: '变更清单', colSpan: '1', rowSpan: '2', field: 'is_change', hAlign: 1, width: 60, cellType: 'checkbox', readOnly: 'readOnly.isChangeList', });
     if (!billsSpreadSetting.readOnly) {
         for (const col of billsSpreadSetting.cols) {
             if (!col.readOnly || col.readOnly === false)
                 col.readOnly = 'readOnly.isChangeAdd';
         }
     }
+    posSpreadSetting.cols.unshift({ title: '变更清单', colSpan: '1', rowSpan: '2', field: 'is_change', hAlign: 1, width: 60, cellType: 'checkbox', readOnly: 'readOnly.isChangeList', getValue: 'getValue.isChange' });
     if (!posSpreadSetting.readOnly) {
         for (const col of posSpreadSetting.cols) {
             if (!col.readOnly || col.readOnly === false)
@@ -70,16 +72,48 @@ $(document).ready(() => {
         readOnly: {
             isChangeAdd: function (data) {
                 return !readOnly && !data.formc;
+            },
+            isChangeList: function (data) {
+                if (!data) return true;
+                let edit = !readOnly && !(data.is_leaf && data.b_code);
+                if (!edit && data.id) {
+                    const lPos = pos.getLedgerPos(data.id);
+                    if (lPos && lPos.length > 0) {
+                        edit = true;
+                    }
+                }
+                return edit;
             }
         }
     };
     const posCol = {
+        getValue: {
+            isChange: function (data) {
+                if (!data) return 0;
+                if (!data.name) return 0;
+                const cInfo = _.find(changeList, { gcl_id: data.lid, mx_id: data.id });
+                return cInfo ? 1 : 0;
+            }
+        },
         readOnly: {
             isChangeAdd: function (data) {
                 return !readOnly && !data.formc && (data.settle_status && data.settle_status === settleStatus.finish);
+            },
+            isChangeList: function (data) {
+                if (!data) return true;
+                // console.log(data.name);
+                return !readOnly && !data.name;
             }
         }
     };
+    // 判断是否是已结算清单
+    function checkIsSettle(data) {
+        const info = data.mx_id ? _.find(settlePos, { lid: data.gcl_id, pid: data.mx_id }) : _.find(settleBills, { lid: data.gcl_id });
+        if (info && info.settle_status && info.settle_status === settleStatus.finish) {
+            return true;
+        }
+        return false;
+    }
     // 初始化spread
     const billsSpread = SpreadJsObj.createNewSpread($('#bills-spread')[0]);
     const billsSheet = billsSpread.getActiveSheet();
@@ -101,6 +135,9 @@ $(document).ready(() => {
         if (data && data.settle_status && data.settle_status === settleStatus.finish) {
             return spreadColor.stage.settle;
         }
+        if (data && data.is_change) {
+            return '#c3e6cb';
+        }
         return defaultColor;
     };
     billsSpreadSetting.localCache = {
@@ -566,6 +603,80 @@ $(document).ready(() => {
                 });
             }
         },
+        buttonClicked: function (e, info, v) {
+            if (info.sheet.zh_setting) {
+                const select = SpreadJsObj.getSelectObject(info.sheet);
+                const col = info.sheet.zh_setting.cols[info.col];
+                if (col.field === 'is_change') {
+                    if (billsCol.readOnly.isChangeList(select)) {
+                        return
+                    }
+                    if (info.sheet.isEditing()) {
+                        info.sheet.endEdit(true);
+                    }
+                    const is_change = info.sheet.getValue(info.row, info.col) ? 1 : 0;
+                    console.log(select, is_change);
+                    if (is_change) {
+                        makeGclGatherData();
+                        const gclInfo = _.find(gclGatherData, function (item) {
+                            return item.leafXmjs && _.find(item.leafXmjs, {gcl_id: select.id });
+                        });
+                        const xmjInfo = gclInfo.leafXmjs[0];
+                        const oldCInfo = _.find(oldChangeList, { gcl_id: select.id, mx_id: '' });
+                        const data = {
+                            lid: select.id,
+                            code: gclInfo.b_code,
+                            name: gclInfo.name,
+                            unit: gclInfo.unit,
+                            unit_price: gclInfo.unit_price,
+                            oamount: xmjInfo.quantity,
+                            oamount2: oldCInfo ? oldCInfo.oamount2 : xmjInfo.quantity,
+                            bwmx: xmjInfo.bwmx || xmjInfo.jldy,
+                            xmj_code: xmjInfo.code || '',
+                            xmj_jldy: xmjInfo.jldy || '',
+                            xmj_dwgc: xmjInfo.dwgc || '',
+                            xmj_fbgc: xmjInfo.fbgc || '',
+                            xmj_fxgc: xmjInfo.fxgc || '',
+                            gcl_id: select.id,
+                            mx_id: '',
+                        };
+                        if (oldCInfo) {
+                            data.detail = oldCInfo.detail;
+                            data.camount = oldCInfo.camount;
+                            data.spamount = oldCInfo.spamount;
+                            data.is_valuation = oldCInfo.is_valuation;
+                            data.delimit = oldCInfo.delimit;
+                        }
+                        // 更新至服务器
+                        postData('/tender/' + window.location.pathname.split('/')[2] + '/change/' + window.location.pathname.split('/')[4] + '/information/save', {type: 'add-change-list', postData: [data]}, function (result) {
+                            changeList = result.changeList;
+                            select.is_change = 1;
+                        }, function () {
+                            info.sheet.setValue(info.row, info.col, 0);
+                        });
+                        console.log(data);
+                    } else {
+                        const cInfo = _.find(changeList, { gcl_id: select.id });
+                        if (_.find(changeUsedData, { cbid: cInfo.id })) {
+                            toastr.warning('该清单计量单元已被使用,无法取消勾选');
+                            info.sheet.setValue(info.row, info.col, 1);
+                            return
+                        } else if (checkIsSettle(cInfo)) {
+                            toastr.warning('该清单计量单元已结算,无法取消勾选');
+                            info.sheet.setValue(info.row, info.col, 1);
+                            return
+                        } else {
+                            postData('/tender/' + window.location.pathname.split('/')[2] + '/change/' + window.location.pathname.split('/')[4] + '/information/save', {type: 'del-change-list', ids: [cInfo.id], postData: null }, function (result) {
+                                changeList = result.changeList;
+                                select.is_change = 0;
+                            }, function () {
+                                info.sheet.setValue(info.row, info.col, 1);
+                            });
+                        }
+                    }
+                }
+            }
+        },
         /**
          * 编辑单元格响应事件
          * @param {Object} e
@@ -574,6 +685,9 @@ $(document).ready(() => {
         editEnded: function (e, info) {
             if (info.sheet.zh_setting) {
                 const col = info.sheet.zh_setting.cols[info.col];
+                if (col.field === 'is_change') {
+                    return;
+                }
                 const sortData = info.sheet.zh_dataType === 'tree' ? info.sheet.zh_tree.nodes : info.sheet.zh_data;
                 const node = sortData[info.row];
                 const data = {
@@ -1162,6 +1276,7 @@ $(document).ready(() => {
 
         billsSpread.bind(spreadNS.Events.EditStarting, billsTreeSpreadObj.editStarting);
         billsSpread.bind(spreadNS.Events.EditEnded, billsTreeSpreadObj.editEnded);
+        billsSpread.bind(spreadNS.Events.ButtonClicked, billsTreeSpreadObj.buttonClicked);
         billsSpread.bind(spreadNS.Events.ClipboardPasting, billsTreeSpreadObj.clipboardPasting);
         billsSpread.bind(spreadNS.Events.ClipboardChanging, function (e, info) {
             const copyText = SpreadJsObj.getFilterCopyText(info.sheet);
@@ -1521,6 +1636,7 @@ $(document).ready(() => {
             // SpreadJsObj.initSheet(posSheet, posSpreadSetting);
             if (node) {
                 const posData = pos.getLedgerPos(node.id) || [];
+                console.log(posData);
                 SpreadJsObj.loadSheetData(posSheet, 'data', posData);
                 posSheet.zh_setting.readOnly = readOnly || (node.used && posData.length === 0) || (node.settle_status && node.settle_status === settleStatus.finish);
             } else {
@@ -1531,7 +1647,15 @@ $(document).ready(() => {
                 if (posSheet.zh_setting) {
                     posSheet.zh_setting.cols.forEach(function (col, i) {
                         for (let iRow = 0; iRow < posSheet.getRowCount(); iRow++) {
-                            posSheet.getCell(iRow, i).locked((posSheet.zh_data[iRow] && !posSheet.zh_data[iRow].formc) || posSheet.zh_setting.readOnly || false);
+                            if (i !== 0) {
+                                posSheet.getCell(iRow, i).locked((posSheet.zh_data[iRow] && !posSheet.zh_data[iRow].formc) || posSheet.zh_setting.readOnly || false);
+                            } else {
+                                let lock = false;
+                                if (!posSheet.zh_data[iRow]) {
+                                    lock = true;
+                                }
+                                posSheet.getCell(iRow, i).locked(lock || (posSheet.zh_data[iRow] && !posSheet.zh_data[iRow].name) || posSheet.zh_setting.readOnly || false);
+                            }
                         }
                     });
                 }
@@ -1628,6 +1752,92 @@ $(document).ready(() => {
                 info.cancel = true;
             }
         },
+        buttonClicked: function (e, info) {
+            if (info.sheet.zh_setting) {
+                const select = SpreadJsObj.getSelectObject(info.sheet);
+                const col = info.sheet.zh_setting.cols[info.col];
+                if (col.field === 'is_change') {
+                    if (posCol.readOnly.isChangeList(select)) {
+                        info.sheet.setValue(info.row, info.col, !select || !select.is_change ? 0 : 1);
+                        return
+                    }
+                    if (info.sheet.isEditing()) {
+                        info.sheet.endEdit(true);
+                    }
+                    const is_change = info.sheet.getValue(info.row, info.col) ? 1 : 0;
+                    if (is_change) {
+                        makeGclGatherData();
+                        const gclInfo = _.find(gclGatherData, function (item) {
+                            return item.leafXmjs && _.find(item.leafXmjs, {gcl_id: select.lid, mx_id: select.id });
+                        });
+                        const xmjInfo = _.find(gclInfo.leafXmjs, { mx_id: select.id });
+                        const oldCInfo = _.find(oldChangeList, { gcl_id: select.lid, mx_id: select.id });
+                        const data = {
+                            lid: select.lid,
+                            code: gclInfo.b_code,
+                            name: gclInfo.name,
+                            unit: gclInfo.unit,
+                            unit_price: gclInfo.unit_price,
+                            oamount: xmjInfo.quantity,
+                            oamount2: oldCInfo ? oldCInfo.oamount2 : xmjInfo.quantity,
+                            bwmx: xmjInfo.bwmx || xmjInfo.jldy,
+                            xmj_code: xmjInfo.code || '',
+                            xmj_jldy: xmjInfo.jldy || '',
+                            xmj_dwgc: xmjInfo.dwgc || '',
+                            xmj_fbgc: xmjInfo.fbgc || '',
+                            xmj_fxgc: xmjInfo.fxgc || '',
+                            gcl_id: select.lid,
+                            mx_id: select.id,
+                        }
+                        if (oldCInfo) {
+                            data.detail = oldCInfo.detail;
+                            data.camount = oldCInfo.camount;
+                            data.spamount = oldCInfo.spamount;
+                            data.is_valuation = oldCInfo.is_valuation;
+                            data.delimit = oldCInfo.delimit;
+                        }
+                        // 更新至服务器
+                        postData('/tender/' + window.location.pathname.split('/')[2] + '/change/' + window.location.pathname.split('/')[4] + '/information/save', {type: 'add-change-list', postData: [data]}, function (result) {
+                            changeList = result.changeList;
+                            select.is_change = 1;
+                            if (_.findIndex(changeList, { gcl_id: select.lid }) !== -1) {
+                                const billsNode = SpreadJsObj.getSelectObject(billsSheet);
+                                billsNode.is_change = 1;
+                                const loadResult = { update: [billsNode] };
+                                billsTreeSpreadObj.refreshTree(billsSheet, loadResult);
+                            }
+                        }, function () {
+                            info.sheet.setValue(info.row, info.col, 0);
+                        });
+                    } else {
+                        const cInfo = _.find(changeList, { gcl_id: select.lid, mx_id: select.id });
+                        if (_.find(changeUsedData, { cbid: cInfo.id })) {
+                            toastr.warning('该计量单元已被使用,无法取消变更');
+                            info.sheet.setValue(info.row, info.col, 1);
+                            return
+                        } else if (checkIsSettle(cInfo)) {
+                            toastr.warning('该计量单元已结算,无法取消变更');
+                            info.sheet.setValue(info.row, info.col, 1);
+                            return
+                        } else {
+                            postData('/tender/' + window.location.pathname.split('/')[2] + '/change/' + window.location.pathname.split('/')[4] + '/information/save', {type: 'del-change-list', ids: [cInfo.id], postData: null }, function (result) {
+                                changeList = result.changeList;
+                                select.is_change = 0;
+                                // 判断是否只剩一个,并同步去勾
+                                if (_.findIndex(changeList, { gcl_id: select.lid }) === -1) {
+                                    const billsNode = SpreadJsObj.getSelectObject(billsSheet);
+                                    billsNode.is_change = 0;
+                                    const loadResult = { update: [billsNode] };
+                                    billsTreeSpreadObj.refreshTree(billsSheet, loadResult);
+                                }
+                            }, function () {
+                                info.sheet.setValue(info.row, info.col, 1);
+                            });
+                        }
+                    }
+                }
+            }
+        },
         /**
          * 编辑单元格响应事件
          * @param {Object} e
@@ -1641,6 +1851,9 @@ $(document).ready(() => {
 
             const posData = info.sheet.zh_data ? info.sheet.zh_data[info.row] : null;
             const col = info.sheet.zh_setting.cols[info.col];
+            if (col.field === 'is_change') {
+                return;
+            }
             const orgText = posData ? posData[col.field] : null;
             const newText = trimInvalidChar(info.editingText);
             if (orgText === newText || ((!orgText || orgText === '') && (newText === ''))) return;
@@ -1994,6 +2207,7 @@ $(document).ready(() => {
 
         posSpread.bind(spreadNS.Events.EditStarting, posSpreadObj.editStarting);
         posSpread.bind(spreadNS.Events.EditEnded, posSpreadObj.editEnded);
+        posSpread.bind(spreadNS.Events.ButtonClicked, posSpreadObj.buttonClicked);
         posSpread.bind(spreadNS.Events.ClipboardPasted, posSpreadObj.clipboardPasted);
         SpreadJsObj.addDeleteBind(posSpread, posSpreadObj.deletePress);
 
@@ -2034,7 +2248,16 @@ $(document).ready(() => {
 
     // 加载清单&计量单元数据
     const preUrl = window.location.pathname.split('/').slice(0, 4).join('/');
+    let gclGatherData;
     postData(preUrl + '/defaultBills', { from: 'revise' }, function (result) {
+        for (const b of result.bills) {
+            if (!(b.is_leaf && b.b_code)) {
+                b.is_change = 0;
+            } else {
+                const cInfo = _.find(changeList, { gcl_id: b.id });
+                b.is_change = cInfo ? 1 : 0;
+            }
+        }
         billsTree.loadDatas(result.bills);
         pos.loadDatas(result.pos);
         treeCalc.calculateAll(billsTree);
@@ -2060,6 +2283,17 @@ $(document).ready(() => {
         }
     });
 
+    function makeGclGatherData() {
+        gclGatherModel.loadLedgerData(billsTree.datas);
+        gclGatherModel.loadPosData(pos.datas);
+        gclGatherData = gclGatherModel.gatherGclData();
+        gclGatherData = _.filter(gclGatherData, function (item) {
+            return item.leafXmjs && item.leafXmjs.length !== 0;
+        });
+        gclGatherData = gclGatherData.sort(sortByCode);
+        console.log(gclGatherData);
+    }
+
     class DealBills {
         constructor (selector, spreadSetting) {
             const self = this;

+ 4 - 1
app/router.js

@@ -565,9 +565,12 @@ module.exports = app => {
     app.post('/tender/:id/change/:cid/information/audit/spgroup', sessionAuth, tenderCheck, uncheckTenderCheck, changeCheck, 'changeController.changeSpGroup');
     app.post('/tender/:id/change/cancel/audit', sessionAuth, tenderCheck, uncheckTenderCheck, changeCheck, 'changeController.checkAuditCancel');
     app.post('/tender/:id/change/:cid/information/audit/save', sessionAuth, tenderCheck, uncheckTenderCheck, changeCheck, changeAuditCheck, 'changeController.saveAudit');
-    // 变更新增部位页
+    // 变更新增部位页(添加台账清单-台账模式)
     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/change/:cid/information/list', sessionAuth, tenderCheck, uncheckTenderCheck, changeCheck, 'changeController.addListInfo');
+    // app.post('/tender/:id/change/:cid/information/list/update', sessionAuth, tenderCheck, uncheckTenderCheck, changeCheck, 'changeController.updateRevise');
     // 变更立项
     app.get('/tender/:id/change/project', sessionAuth, tenderCheck, uncheckTenderCheck, 'changeController.project');
     app.get('/tender/:id/change/project/status/:status', sessionAuth, tenderCheck, uncheckTenderCheck, 'changeController.projectStatus');

+ 76 - 1
app/service/change_audit_list.js

@@ -33,7 +33,8 @@ module.exports = app => {
             }
             const sql = 'SELECT * FROM ?? WHERE `cid` = ? ORDER BY `lid` = "0", `id` asc';
             const sqlParam = [this.tableName, cid];
-            return await this.db.query(sql, sqlParam);
+            const result = await this.db.query(sql, sqlParam);
+            return this._.orderBy(result, ['order'], ['asc']);
         }
 
         /**
@@ -124,6 +125,51 @@ module.exports = app => {
         }
 
         /**
+         * 添加台账清单(从新增部位页新增)
+         * @return {void}
+         */
+        async adds(datas, data = null) {
+            if (!this.ctx.tender || !this.ctx.change) {
+                throw '数据错误';
+            }
+            const transaction = await this.db.beginTransaction();
+            try {
+                let order = null;
+                if (this.ctx.change.order_by) {
+                    if (data) {
+                        order = parseInt(data) + 1;
+                        // order以下的清单+1
+                        await this._syncOrder(transaction, this.ctx.change.cid, order, '+');
+                    } else {
+                        order = await this.count({ cid: this.ctx.change.cid });
+                        order = order ? order + 1 : 1;
+                    }
+                }
+                const insertData = [];
+                for (const d of datas) {
+                    d.tid = this.ctx.tender.id;
+                    d.cid = this.ctx.change.cid;
+                    d.spamount = d.spamount || null;
+                    d.detail = d.detail || '';
+                    d.samount = d.samount || '';
+                    d.order = order ? order : null;
+                    order = order ? order + 1 : null;
+                    insertData.push(d);
+                }
+                // 新增工料
+                const result = await transaction.insert(this.tableName, insertData);
+                if (result.affectedRows === 0) {
+                    throw '添加清单数据失败';
+                }
+                await transaction.commit();
+                return true;
+            } catch (err) {
+                await transaction.rollback();
+                throw err;
+            }
+        }
+
+        /**
          * 批量添加空白变更清单
          * @return {void}
          */
@@ -223,6 +269,35 @@ module.exports = app => {
             }
         }
 
+        async dels(data) {
+            if (!this.ctx.tender || !this.ctx.change) {
+                throw '数据错误';
+            }
+            const transaction = await this.db.beginTransaction();
+            try {
+                // 判断是否存在调用,存在则报错
+                const delList = await this.getAllDataByCondition({ where: { id: data.ids } });
+                const sql1 = 'SELECT a.* FROM ?? as b LEFT JOIN ?? as a ON b.cbid = a.id WHERE b.cid = ? AND b.id in (' + this.ctx.helper.getInArrStrSqlFilter(data.ids) + ') GROUP BY b.cbid';
+                const sqlParam1 = [this.ctx.service.stageChange.tableName, this.tableName, this.ctx.change.cid];
+                const usedList = await transaction.query(sql1, sqlParam1);
+                if (usedList.length > 0) {
+                    throw '清单已被调用,不可删除';
+                }
+                await transaction.delete(this.tableName, { id: data.ids });
+                // // order以下的清单-1
+                if (this.ctx.change.order_by) {
+                    await this._syncOrder(transaction, this.ctx.change.cid, data.postData, '-', data.ids.length);
+                }
+                // 重新算变更令总额
+                await this.calcCamountSum(transaction);
+                await transaction.commit();
+                return true;
+            } catch (err) {
+                await transaction.rollback();
+                throw err;
+            }
+        }
+
         /**
          * 修改变更清单
          * @param {Object} data 工料内容

+ 69 - 0
app/view/change/addlist.ejs

@@ -0,0 +1,69 @@
+<% include ./sub_menu.ejs %>
+<div class="panel-content">
+    <div class="panel-title">
+        <div class="title-main  d-flex">
+            <% include ./sub_mini_menu.ejs %>
+            <div class="ml-auto">
+                <a class="btn btn-sm btn-primary mr-1" id="select-all-revise" 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="gcl-spread">
+                </div>
+                <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="nav-item" id="xmj-search">
+                            </li>
+                        </ul>
+                    </div>
+                    <div class="sp-wrap" id="xmj-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>
+            </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>
+            </ul>
+        </div>
+    </div>
+</div>
+<script>
+    const readOnly = <%- readOnly %>;
+    const isYb = <%- isYb %>;
+    const totalPriceUnit = '<%- tpUnit %>';
+    const unitPriceUnit = '<%- upUnit %>';
+    const thousandth = <%- ctx.tender.info.display.thousandth %>;
+    const decimal = JSON.parse('<%- JSON.stringify(ctx.tender.info.decimal) %>');
+    const settleStatus = JSON.parse('<%- JSON.stringify(settleStatus) %>');
+    const changeUsedData = JSON.parse(unescape('<%- escape(JSON.stringify(changeUsedData)) %>'));
+    let changeList = JSON.parse(unescape('<%- escape(JSON.stringify(changeList)) %>'));
+    const oldChangeList = _.cloneDeep(changeList);
+    const settleBills = JSON.parse(unescape('<%- escape(JSON.stringify(settleBills)) %>'));
+    const settlePos = JSON.parse(unescape('<%- escape(JSON.stringify(settlePos)) %>'));
+    const precision = JSON.parse('<%- JSON.stringify(precision) %>');
+</script>

+ 19 - 0
app/view/change/addlist_modal.ejs

@@ -0,0 +1,19 @@
+<% if (changing) { %>
+    <!--正在修订提示-->
+    <div class="modal fade" id="unedit2" data-backdrop="static">
+        <div class="modal-dialog " role="document" >
+            <div class="modal-content">
+                <div class="modal-header">
+                    <h5 class="modal-title">提示</h5>
+                </div>
+                <div class="modal-body">
+                    <h5>该变更令正在审批中或已完成,添加台账清单页无法进行任何操作。</h5>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">好的</button>
+                </div>
+            </div>
+        </div>
+    </div>
+    <script type="text/javascript">$('#unedit2').modal('show');</script>
+<% } %>

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

@@ -176,4 +176,9 @@
     const settleStatus = JSON.parse('<%- JSON.stringify(settleStatus) %>');
     let dskAccountData = JSON.parse(unescape('<%- escape(JSON.stringify(dskAccountData)) %>'));
     let dskProjects = JSON.parse(unescape('<%- escape(JSON.stringify(dskProjects)) %>'));
+    const changeUsedData = JSON.parse(unescape('<%- escape(JSON.stringify(changeUsedData)) %>'));
+    let changeList = JSON.parse(unescape('<%- escape(JSON.stringify(changeList)) %>'));
+    const oldChangeList = _.cloneDeep(changeList);
+    const settleBills = JSON.parse(unescape('<%- escape(JSON.stringify(settleBills)) %>'));
+    const settlePos = JSON.parse(unescape('<%- escape(JSON.stringify(settlePos)) %>'));
 </script>

+ 4 - 4
app/view/change/revise_modal.ejs

@@ -44,10 +44,10 @@
                     <h5 class="modal-title">提示</h5>
                 </div>
                 <div class="modal-body">
-                    <h5>台账正在进行修订,新增部位页无法进行任何操作。</h5>
+                    <h5>台账正在进行修订,添加台账清单页无法进行任何操作。</h5>
                 </div>
                 <div class="modal-footer">
-                    <button type="button" class="btn btn-secondary" data-dismiss="modal">好的</button>
+                    <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">好的</button>
                 </div>
             </div>
         </div>
@@ -62,10 +62,10 @@
                     <h5 class="modal-title">提示</h5>
                 </div>
                 <div class="modal-body">
-                    <h5>该变更令正在审批中或已完成,新增部位页无法进行任何操作。</h5>
+                    <h5>该变更令正在审批中或已完成,添加台账清单页无法进行任何操作。</h5>
                 </div>
                 <div class="modal-footer">
-                    <button type="button" class="btn btn-secondary" data-dismiss="modal">好的</button>
+                    <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">好的</button>
                 </div>
             </div>
         </div>

+ 1 - 1
app/view/change/sub_menu.ejs

@@ -1,5 +1,5 @@
 <div class="panel-sidebar" id="sub-menu">
-    <div class="sidebar-title" data-toggle="tooltip" data-placement="right" data-original-title="变更台账新增部位">变更台账新增部位</div>
+    <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-show"></div>

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

@@ -1 +1,15 @@
 <nav-menu title="返回" url="<%- preUrl %>" tclass="text-primary" ml="1" icon="fa-chevron-left"></nav-menu>
+<div class="nav-box">
+    <ul class="nav-list list-unstyled">
+        <li class="<% if (ctx.url === '/tender/' + ctx.tender.id + '/change/' + ctx.change.cid + '/information/revise') { %>active<% } %>">
+            <a href="/tender/<%- ctx.tender.id %>/change/<%- ctx.change.cid %>/information/revise"><span class="ml-3">台账模式</span></a>
+        </li>
+    </ul>
+</div>
+<div class="nav-box">
+    <ul class="nav-list list-unstyled">
+        <li class="<% if (ctx.url === '/tender/' + ctx.tender.id + '/change/' + ctx.change.cid + '/information/list') { %>active<% } %>">
+            <a href="/tender/<%- ctx.tender.id %>/change/<%- ctx.change.cid %>/information/list"><span class="ml-3">清单模式</span></a>
+        </li>
+    </ul>
+</div>

+ 21 - 0
config/web.js

@@ -983,6 +983,7 @@ const JsFiles = {
                     '/public/js/shares/cs_tools.js',
                     '/public/js/zh_calc.js',
                     '/public/js/path_tree.js',
+                    '/public/js/gcl_gather.js',
                     '/public/js/std_lib.js',
                     '/public/js/shares/tenders2tree.js',
                     '/public/js/ledger_check.js',
@@ -990,6 +991,26 @@ const JsFiles = {
                 ],
                 mergeFile: 'change_revise',
             },
+            addList: {
+                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',
+                    '/public/js/component/menu.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/gcl_gather.js',
+                    '/public/js/change_information_add_list.js',
+                ],
+                mergeFile: 'change_add_list',
+            },
             project: {
                 files: ['/public/js/moment/moment.min.js'],
                 mergeFiles: [