Преглед на файлове

Merge branch 'price2' into dev

MaiXinRong преди 2 години
родител
ревизия
ac9568db4f

+ 22 - 1
app/controller/revise_controller.js

@@ -918,6 +918,25 @@ module.exports = app => {
             return curStageData;
         }
 
+        async _loadChange(ctx) {
+            const change = await ctx.service.change.getAllDataByCondition({
+                columns: [ 'cid', 'code', 'name', 'w_code' ],
+                where: { tid: ctx.tender.id }
+            });
+            const changeBills = await ctx.service.changeAuditList.getAllDataByCondition({
+                columns: [ 'cid', 'code', 'name', 'unit', 'unit_price' ],
+                where: { tid: ctx.tender.id }
+            });
+            const changeIndex = {};
+            change.forEach(x => { changeIndex[x.cid] = x; x.bills = [] });
+            changeBills.forEach(cb => {
+                const c = changeIndex[cb.cid];
+                if (!c) return;
+                c.bills.push(cb);
+            });
+            return change;
+        }
+
         async _loadDataByFilter(ctx, filter) {
             switch(filter) {
                 case 'bills':
@@ -952,6 +971,8 @@ module.exports = app => {
                     return await this.ctx.service.ledgerTag.getDatas(ctx.tender.id);
                 case 'price':
                     return await this.ctx.service.revisePrice.getAllDataByCondition({ where: { rid: ctx.revise.id } });
+                case 'change':
+                    return await this._loadChange(ctx);
                 default: throw '请求的数据不存在';
             }
         }
@@ -997,7 +1018,7 @@ module.exports = app => {
                 revise: ctx.revise,
                 jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.revise.price),
             };
-            await this.layout('revise/price.ejs', renderData);
+            await this.layout('revise/price.ejs', renderData, 'revise/price_modal.ejs');
         }
 
         async priceUpdate(ctx) {

+ 58 - 6
app/lib/ledger.js

@@ -54,6 +54,30 @@ class baseTree {
     getParent (node) {
         return this.getItems(node[this.setting.pid]);
     };
+    getTopParent(node) {
+        const parents = this.getAllParents(node);
+        return parents[0];
+    };
+    getAllParents(node) {
+        const parents = [];
+        if (!node) return parents;
+
+        if (node[this.setting.fullPath] && node[this.setting.fullPath] !== '') {
+            const parentIds = node[this.setting.fullPath].split('-');
+            for (const id of parentIds) {
+                if (id !== node[this.setting.id]) {
+                    parents.push(this.getItems(id));
+                }
+            }
+        } else {
+            let vP = this.getParent(node);
+            while (vP) {
+                parents.unshift(vP);
+                vP = this.getParent(vP);
+            }
+        }
+        return parents;
+    }
     /**
      * 查询node的已下载子节点
      * @param {Object} node
@@ -66,7 +90,7 @@ class baseTree {
             return x[setting.pid] === pid;
         });
         children.sort(function (a, b) {
-            return a.order - b.order;
+            return a[setting.order] - b[setting.order];
         });
         return children;
     };
@@ -84,6 +108,7 @@ class baseTree {
      */
     sortTreeNode (isResort) {
         const self = this;
+        const setting = this.setting;
         const addSortNodes = function (nodes) {
             if (!nodes) { return }
             for (let i = 0; i < nodes.length; i++) {
@@ -93,7 +118,7 @@ class baseTree {
                     nodes[i].children = self.getChildren(nodes[i]);
                 } else {
                     nodes[i].children.sort(function (a, b) {
-                        return a.order - b.order;
+                        return a[setting.order] - b[setting.order];
                     })
                 }
                 addSortNodes(nodes[i].children);
@@ -104,7 +129,7 @@ class baseTree {
             this.children = this.getChildren();
         } else {
             this.children.sort(function (a, b) {
-                return a.order - b.order;
+                return a[setting.order] - b[setting.order];
             })
         }
         addSortNodes(this.children);
@@ -119,9 +144,10 @@ class baseTree {
         this.nodes = [];
         this.datas = [];
         this.children = [];
+        const setting = this.setting;
         // 加载全部数据
         datas.sort(function (a, b) {
-            return a.level - b.level;
+            return a[setting.level] - b[setting.level];
         });
         for (const data of datas) {
             const keyName = itemsPre + data[this.setting.id];
@@ -143,7 +169,7 @@ class baseTree {
             }
         }
         this.children.sort(function (a, b) {
-            return a.order - b.order;
+            return a[setting.order] - b[setting.order];
         });
         this.sortTreeNode(true);
     }
@@ -1017,10 +1043,36 @@ class reviseTree extends billsTree {
     loadRevisePrice(price, decimal) {
         this.decimal = decimal;
         this.price = price || [];
+        this.rela_price = [];
+        this.common_price = [];
+        this.price.forEach(x => {
+            if (x.rela_lid) {
+                x.rela_lid = x.rela_lid.split(',');
+                this.rela_price.push(x);
+            } else {
+                this.common_price.push(x);
+            }
+        });
     }
     checkRevisePrice(d) {
         const helper = this.ctx.helper;
-        const p = this.price.find(x => {
+        const setting = this.setting;
+        const pid = this.getAllParents(d).map(x => { return x[setting.id] + ''; });
+        const checkRela = function(rela_lid) {
+            if (!rela_lid || rela_lid.length === 0) return false;
+            for (const lid of rela_lid) {
+                if (pid.indexOf(lid) >= 0) return true;
+            }
+            return false;
+        };
+        let p = this.rela_price.find(x => {
+            return x.b_code === d.b_code &&
+                ((!x.name && !d.name) || x.name === d.name) &&
+                ((!x.unit && !d.unit) || x.unit === d.unit) &&
+                helper.checkZero(x.org_price - d.unit_price) &&
+                checkRela(x.rela_lid);
+        });
+        if (!p) p = this.common_price.find(x => {
             return x.b_code === d.b_code &&
                 ((!x.name && !d.name) || x.name === d.name) &&
                 ((!x.unit && !d.unit) || x.unit === d.unit) &&

+ 29 - 6
app/lib/revise_price.js

@@ -22,9 +22,32 @@ class revisePriceCalc {
         this.ctx = ctx;
     }
 
-    findPrice(b_code, name, unit, unit_price) {
+    set price(price) {
+        this._price = price;
+        this.common_price_c = [];
+        this.rela_price_c = [];
+        price.forEach(x => {
+            x.rela_lid = x.rela_lid ? x.rela_lid.split(',') : [];
+            if (x.rela_cid) {
+                x.rela_cid = x.rela_cid.split(',');
+                this.rela_price_c.push(x);
+            } else {
+                this.common_price_c.push(x);
+            }
+        });
+    }
+    get price() {
+        return this._price;
+    }
+
+    findChangeBillsPrice(b_code, name, unit, unit_price, cid) {
         const helper = this.ctx.helper;
-        return this.price.find(x => {
+        const p = this.rela_price_c.find(x => {
+            return b_code === x.b_code && name === x.name && unit === x.unit && helper.numEqual(unit_price, x.org_price) && x.rela_cid.indexOf(cid) >= 0;
+        });
+        if (p) return p;
+
+        return this.common_price_c.find(x => {
             return b_code === x.b_code && name === x.name && unit === x.unit && helper.numEqual(unit_price, x.org_price);
         });
     }
@@ -37,8 +60,8 @@ class revisePriceCalc {
      */
     async newStagePriceChange(newStage, preStage, transaction) {
         // 获取未执行的单价变更,无单价变更不执行
-        const price = await this.ctx.service.revisePrice.getAllDataByCondition({ where: { tid: newStage.tid, valid: 1, use_stage: 0 } });
-        if (price.length === 0) return;
+        this.price = await this.ctx.service.revisePrice.getAllDataByCondition({ where: { tid: newStage.tid, valid: 1, use_stage: 0 } });
+        if (this.price.length === 0) return;
         // 无截止上期数据不执行
         const preBillsData = await this.ctx.service.stageBillsFinal.getAllDataByCondition({ where: { sid: preStage.id } });
         if (preBillsData.length === 0) return;
@@ -94,7 +117,7 @@ class revisePriceCalc {
      */
     async stageCheckAgainPriceChange(stage, auditOrder, transaction) {
         // 获取未执行的单价变更,无单价变更不执行
-        const price = await this.ctx.service.revisePrice.getAllDataByCondition({ where: { tid: stage.tid, valid: 1, use_stage: 0 } });
+        this.price = await this.ctx.service.revisePrice.getAllDataByCondition({ where: { tid: stage.tid, valid: 1, use_stage: 0 } });
         if (price.length === 0) return;
 
         const curBillsData = await this.ctx.service.stageBills.getLastestStageData2(stage.tid, stage.id);
@@ -181,7 +204,7 @@ class revisePriceCalc {
         const updateBills = [];
         let total_price = 0, positive_tp = 0, negative_tp = 0;
         for (const b of changeBills) {
-            const p = this.findPrice(b.code, b.name, b.unit, b.unit_price);
+            const p = this.findChangeBillsPrice(b.code, b.name, b.unit, b.unit_price, change.cid);
             let bills_tp;
             if (p) {
                 updateBills.push({ id: b.id, unit_price: p.new_price });

+ 6 - 2
app/lib/stage_im.js

@@ -70,7 +70,9 @@ class StageIm {
 
     // 加载数据
     async _loadMainData() {
-        const billsData = await this.ctx.service.ledger.getData(this.ctx.tender.id);
+        const billsData = this.ctx.stage.ledgerHis
+            ? await this.ctx.helper.loadLedgerDataFromOss(this.ctx.stage.ledgerHis.bills_file)
+            : await this.ctx.service.ledger.getData(this.ctx.tender.id);
         const curStage = this.ctx.stage.readOnly
             ? await this.ctx.service.stageBills.getAuditorStageData2(this.ctx.tender.id,
                 this.ctx.stage.id, this.ctx.stage.curTimes, this.ctx.stage.curOrder)
@@ -86,7 +88,9 @@ class StageIm {
         this.billsTree.loadDatas(billsData);
         this.billsTree.calculateAll();
 
-        const posData = await this.ctx.service.pos.getAllDataByCondition({ where: { tid: this.ctx.tender.id } });
+        const posData = this.ctx.stage.ledgerHis
+            ? await this.ctx.helper.loadLedgerDataFromOss(this.ctx.stage.ledgerHis.pos_file)
+            : await this.ctx.service.pos.getAllDataByCondition({ where: { tid: this.ctx.tender.id } });
         const curPosStage = this.ctx.stage.readOnly
             ? await this.ctx.service.stagePos.getAuditorStageData2(this.ctx.tender.id,
                 this.ctx.stage.id, this.ctx.stage.curTimes, this.ctx.stage.curOrder)

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

@@ -420,6 +420,7 @@ const createNewPathTree = function (type, setting) {
 
             if (node.full_path && node.full_path !== '') {
                 const parentIds = node.full_path.split('-');
+                parentIds.length = parentIds.length - 1;
                 for (const id of parentIds) {
                     if (id !== node[this.setting.id]) {
                         parents.push(this.getItems(id));
@@ -907,6 +908,23 @@ const createNewPathTree = function (type, setting) {
                 this._getDefaultNodeData(node);
             }
         }
+
+        checkParent(node, field = 'check') {
+            const parent = this.getParent(node);
+            return parent
+                ? (parent[field] ? parent[field] : this.checkParent(parent, field))
+                : false;
+        }
+        checkChildren(node, field = 'check') {
+            for (const child of node.children) {
+                if (child[field]) {
+                    return true;
+                } else if (this.checkChildren(child, field)) {
+                    return true;
+                }
+            }
+            return false;
+        }
     }
 
     class MeasureTree extends BaseTree {
@@ -1160,9 +1178,35 @@ const createNewPathTree = function (type, setting) {
         loadRevisePrice(price, decimal) {
             this.decimal = decimal;
             this.price = price || [];
+            this.rela_price = [];
+            this.common_price = [];
+            this.price.forEach(x => {
+                if (x.rela_lid) {
+                    x.rela_lid = x.rela_lid.split(',');
+                    this.rela_price.push(x);
+                } else {
+                    this.common_price.push(x);
+                }
+            });
         }
         checkRevisePrice(d) {
-            const p = this.price.find(x => {
+            const setting = this.setting;
+            const pid = this.getAllParents(d).map(x => { return x[setting.id] + ''; });
+            const checkRela = function(rela_lid) {
+                if (!rela_lid || rela_lid.length === 0) return false;
+                for (const lid of rela_lid) {
+                    if (pid.indexOf(lid) >= 0) return true;
+                }
+                return false;
+            };
+            let p = this.rela_price.find(x => {
+                return x.b_code === d.b_code &&
+                    ((!x.name && !d.name) || x.name === d.name) &&
+                    ((!x.unit && !d.unit) || x.unit === d.unit) &&
+                    checkZero(x.org_price - d.unit_price) &&
+                    checkRela(x.rela_lid);
+            });
+            if (!p) p = this.common_price.find(x => {
                 return x.b_code === d.b_code &&
                     ((!x.name && !d.name) || x.name === d.name) &&
                     ((!x.unit && !d.unit) || x.unit === d.unit) &&

+ 484 - 9
app/public/js/revise_price.js

@@ -79,25 +79,100 @@ $(document).ready(() => {
         headerFont: '12px 微软雅黑',
         font: '12px 微软雅黑',
         readOnly,
+        getColor: function (sheet, data, row, col, defaultColor) {
+            if (!data || (data.rela_lid && data.rela_cid)) return defaultColor;
+
+            const samePrice = sheet.zh_data.find(x => {
+                return x.b_code === data.b_code && x.name === data.name && x.unit === data.unit && x.org_price === data.org_price;
+            });
+            return samePrice ? '#f5deb3' : defaultColor;
+        }
+    };
+    const priceBwSpreadSetting = {
+        cols: [
+            {title: '项目节编号', colSpan: '1', rowSpan: '1', field: 'code', hAlign: 0, width: 150, formatter: '@', cellType: 'tree'},
+            {title: '清单编号', colSpan: '1', rowSpan: '1', field: 'b_code', hAlign: 0, width: 80, formatter: '@'},
+            {title: '名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 230, formatter: '@'},
+            {title: '单位', colSpan: '1', rowSpan: '1', field: 'unit', hAlign: 1, width: 60, formatter: '@'},
+        ],
+        headRows: 1,
+        emptyRows: 0,
+        headRowHeight: [25],
+        defaultRowHeight: 21,
+        headerFont: '12px 微软雅黑',
+        font: '12px 微软雅黑',
+        readOnly: true,
+        // getColor: function (sheet, data, row, col, defaultColor) {
+        //     return data && data.valid ? defaultColor : '#ddd';
+        // },
+        getForeColor: function (sheet, data, row, col, defaultColor) {
+            return data && data.valid ? defaultColor : '#ddd';
+        },
+    };
+    sjsSettingObj.setFxTreeStyle(priceBwSpreadSetting, sjsSettingObj.FxTreeStyle.jz);
+    const priceChangeSpreadSetting = {
+        cols: [
+            {title: '变更令', colSpan: '1', rowSpan: '1', field: 'code', hAlign: 0, width: 80, formatter: '@'},
+            {title: '名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 230, formatter: '@'},
+            {title: '批复文号', colSpan: '1', rowSpan: '1', field: 'w_code', hAlign: 1, width: 80, formatter: '@'},
+        ],
+        headRows: 1,
+        emptyRows: 0,
+        headRowHeight: [25],
+        defaultRowHeight: 21,
+        headerFont: '12px 微软雅黑',
+        font: '12px 微软雅黑',
+        readOnly: true,
+        getForeColor: function (sheet, data, row, col, defaultColor) {
+            return data && data.valid ? defaultColor : '#ddd';
+        },
     };
     autoFlashHeight();
+    const bcontent = $(".bcontent-wrap").length > 0 ? $(".bcontent-wrap").height() : 0;
+    $(".sp-wrap").height(bcontent-30);
     const priceSpread = SpreadJsObj.createNewSpread($('#price-spread')[0]);
     const priceSheet = priceSpread.getActiveSheet();
+    const priceBwSpread = SpreadJsObj.createNewSpread($('#price-bw-spread')[0]);
+    const priceBwSheet = priceBwSpread.getActiveSheet();
+    const priceChangeSpread = SpreadJsObj.createNewSpread($('#price-change-spread')[0]);
+    const priceChangeSheet = priceChangeSpread.getActiveSheet();
 
     SpreadJsObj.initSheet(priceSheet, priceSpreadSetting);
+    SpreadJsObj.initSheet(priceBwSheet, priceBwSpreadSetting);
+    SpreadJsObj.initSheet(priceChangeSheet, priceChangeSpreadSetting);
 
     class RevisePrice {
         constructor () {
             this.data = [];
+            this.tree = createNewPathTree('filter', {
+                id: 'ledger_id',
+                pid: 'ledger_pid',
+                order: 'order',
+                level: 'level',
+                rootId: -1,
+                fullPath: 'full_path',
+                keys: ['id', 'tender_id', 'ledger_id'],
+            });
         }
         resortData() {
             this.data.sort(function (a, b) {
                 return a.order - b.order;
             });
         }
-        loadDatas(datas) {
+        analysisRelaLid(price) {
+            const tree = this.tree;
+            const rela_lid = price.rela_lid ? price.rela_lid.split(',') : [];
+            price.rela_hint = rela_lid.map(x => {
+                const node = tree.getItems(parseInt(x));
+                return node ? node.code || node.name : '';
+            }).join(',');
+        }
+        loadDatas(datas, treeData, changeData) {
             this.data = datas;
+            this.tree.loadDatas(treeData);
             this.resortData();
+            this.change = changeData;
+            if (this.data.length > 0) this.refreshRela(this.data[0]);
         }
         loadUpdateData(updateData) {
             if (updateData.add) {
@@ -124,12 +199,72 @@ $(document).ready(() => {
             }
             this.resortData();
         }
+        getSamePrice(price) {
+            return this.data.filter(x => {
+                if (x.id === price.id) return false;
+                return x.b_code === price.b_code && x.name === price.name && x.unit === price.unit && x.org_price === price.org_price;
+            });
+        }
+        refreshTreeRela(price, samePrice) {
+            if (price.rela_lid) {
+                const choose = price.rela_lid.split(',');
+                for (const node of this.tree.nodes) {
+                    node.rela = choose.indexOf(node.ledger_id + '') >= 0;
+                }
+                for (const node of this.tree.nodes) {
+                    node.valid = node.rela || this.tree.checkParent(node, 'rela') || this.tree.checkChildren(node, 'rela');
+                }
+            } else {
+                const invalid = [];
+                for (const sp of samePrice) {
+                    const lid = sp.rela_lid ? sp.rela_lid.split(',') : [];
+                    invalid.push(...lid);
+                }
+                for (const node of this.tree.nodes) {
+                    node.rela = invalid.indexOf(node.ledger_id + '') >= 0;
+                }
+                for (const node of this.tree.nodes) {
+                    node.valid = !(node.rela || this.tree.checkParent(node, 'rela'));
+                }
+            }
+        }
+        refreshChangeRela(price, samePrice) {
+            if (price.rela_cid) {
+                const choose = price.rela_cid.split(',');
+                for (const c of this.change) {
+                    c.rela = choose.indexOf(c.cid + '') >= 0;
+                    c.valid = c.rela;
+                }
+            } else {
+                const invalid = [];
+                for (const sp of samePrice) {
+                    const cid = sp.rela_cid ? sp.rela_cid.split(',') : [];
+                    invalid.push(...cid);
+                }
+                for (const c of this.change) {
+                    c.rela = invalid.indexOf(c.cid + '') >= 0;
+                    if (c.rela) {
+                        c.valid = 0;
+                    } else {
+                        const exist = c.bills.find(x => {
+                            return x.code === price.b_code && x.name === price.name && x.unit === price.unit && x.unit_price === price.org_price;
+                        });
+                        c.valid = exist;
+                    }
+                }
+            }
+        }
+        refreshRela(price) {
+            const samePrice = this.getSamePrice(price);
+            this.refreshTreeRela(price, samePrice);
+            this.refreshChangeRela(price, samePrice);
+        }
     }
     const revisePrice = new RevisePrice();
     const priceOprObj = {
         addRevisePrice(data) {
             const op = revisePrice.data.find(x => {
-                return x.b_code === data.b_code && x.name === x.name && x.unit === x.unit && checkZero(ZhCalc.sub(x.org_price, data.unit_price));
+                return x.b_code === data.b_code && x.name === x.name && x.unit === x.unit && checkZero(ZhCalc.sub(x.org_price, data.unit_price)) && (!x.rela_lid || !x.rela_cid);
             });
             if (op) {
                 toastr.warning('已存在该单价调整');
@@ -307,7 +442,27 @@ $(document).ready(() => {
                 SpreadJsObj.reLoadRowsData(priceSheet, [sels[0].row, sels[0].row + 1]);
                 priceSheet.setSelection(sels[0].row + 1, sels[0].col, sels[0].rowCount, sels[0].colCount);
             });
-        }
+        },
+        updateRelaLid: function (price, rela_lid) {
+            const data = { update: { id: price.id, rela_lid } };
+            postData(window.location.pathname + '/update', data, function (result) {
+                revisePrice.loadUpdateData(result);
+            });
+        },
+        updateRelaCid: function (price, rela_cid) {
+            const data = { update: { id: price.id, rela_cid } };
+            postData(window.location.pathname + '/update', data, function (result) {
+                revisePrice.loadUpdateData(result);
+            });
+        },
+        selectionChanged: function () {
+            const price = SpreadJsObj.getSelectObject(priceSheet);
+            revisePrice.refreshRela(price);
+            // SpreadJsObj.reloadRowBackColor(priceBwSheet, 0, priceBwSheet.getRowCount());
+            // SpreadJsObj.reloadRowBackColor(priceChangeSheet, 0, priceChangeSheet.getRowCount());
+            SpreadJsObj.reloadRowForeColor(priceBwSheet, 0, priceBwSheet.getRowCount());
+            SpreadJsObj.reloadRowForeColor(priceChangeSheet, 0, priceChangeSheet.getRowCount());
+        },
     };
     if (!readOnly) {
         priceSheet.bind(spreadNS.Events.EditEnded, priceOprObj.editEnded);
@@ -334,7 +489,7 @@ $(document).ready(() => {
                         return !readOnly;
                     }
                 },
-                sprDel: '------------',
+                sprDel: '----',
                 upMove: {
                     name: '上移',
                     icon: 'fa-arrow-up',
@@ -370,10 +525,44 @@ $(document).ready(() => {
                     visible: function (key, opt) {
                         return !readOnly;
                     }
-                }
+                },
+                sprMove: '----',
+                chooseRelaBw: {
+                    name: '选择应用部位',
+                    icon: 'fa-tags',
+                    callback: function (key, opt) {
+                        const price = SpreadJsObj.getSelectObject(priceSheet);
+                        const samePrice = revisePrice.getSamePrice(price);
+                        chooseRelaBw.show(price, samePrice);
+                    },
+                    disabled: function (key, opt) {
+                        const node = SpreadJsObj.getSelectObject(priceSheet);
+                        return !node;
+                    },
+                    visible: function (key, opt) {
+                        return !readOnly;
+                    }
+                },
+                chooseRelaChange: {
+                    name: '选择应用变更令',
+                    icon: 'fa-tags',
+                    callback: function (key, opt) {
+                        const price = SpreadJsObj.getSelectObject(priceSheet);
+                        const samePrice = revisePrice.getSamePrice(price);
+                        chooseRelaChange.show(price, samePrice);
+                    },
+                    disabled: function (key, opt) {
+                        const node = SpreadJsObj.getSelectObject(priceSheet);
+                        return !node;
+                    },
+                    visible: function (key, opt) {
+                        return !readOnly;
+                    }
+                },
             },
         });
     }
+    priceSpread.bind(spreadNS.Events.SelectionChanged, priceOprObj.selectionChanged);
 
     class LedgerGcl {
         constructor(setting) {
@@ -435,6 +624,8 @@ $(document).ready(() => {
             autoFlashHeight();
             priceSpread.refresh();
             ledgerGcl.spread.refresh();
+            priceBwSpread.refresh();
+            priceChangeSpread.refresh();
         }
     });
 
@@ -442,22 +633,296 @@ $(document).ready(() => {
         select: '#revise-right-spr',
         callback: function () {
             priceSpread.refresh();
+            priceBwSpread.refresh();
+            priceChangeSpread.refresh();
             ledgerGcl.spread.refresh();
+            ledgerGcl.xmjSpread.refresh();
         }
     });
     $.divResizer({
         select: '#gcl-spr',
         callback: function () {
-            priceSpread.refresh();
             ledgerGcl.spread.refresh();
             ledgerGcl.xmjSpread.refresh();
         }
     });
+    $.divResizer({
+        select: '#price-resize',
+        callback: function () {
+            priceSpread.refresh();
+            let bcontent = $(".bcontent-wrap").length > 0 ? $(".bcontent-wrap").height() : 0;
+            $(".sp-wrap").height(bcontent-30);
+            priceBwSpread.refresh();
+            priceChangeSpread.refresh();
+        }
+    });
+
+    class ChooseRelaBw {
+        constructor() {
+            const self = this;
+            this.tree = createNewPathTree('base', {
+                id: 'ledger_id',
+                pid: 'ledger_pid',
+                order: 'order',
+                level: 'level',
+                rootId: -1,
+                fullPath: 'full_path',
+                keys: ['id', 'tender_id', 'ledger_id'],
+            });
+            $('#choose-rela-bw').on('shown.bs.modal', function() {
+                self.initSpread();
+                SpreadJsObj.reloadColData(self.sheet, 0, 1);
+                SpreadJsObj.reloadRowBackColor(self.sheet, 0, self.tree.nodes.length);
+            });
+            $('#choose-rela-bw-ok').click(function() {
+                const choose_lid = [];
+                self.tree.nodes.forEach(x => {
+                    if (x.check) choose_lid.push(x.ledger_id);
+                });
+                priceOprObj.updateRelaLid(self.price, choose_lid.join(','));
+                $('#choose-rela-bw').modal('hide');
+            });
+        }
+        initSpread() {
+            if (this.spread) return;
+
+            this.spread = SpreadJsObj.createNewSpread($('#rela-bw-spread')[0]);
+            this.sheet = this.spread.getActiveSheet();
+            const spreadSetting = {
+                cols: [
+                    {title: '选择', colSpan: '1', rowSpan: '1', field: 'check', hAlign: 1, width: 50, formatter: '@', cellType: 'checkbox'},
+                    {title: '项目节编号', colSpan: '1', rowSpan: '1', field: 'code', hAlign: 0, width: 150, formatter: '@', cellType: 'tree'},
+                    {title: '清单编号', colSpan: '1', rowSpan: '1', field: 'b_code', hAlign: 0, width: 80, formatter: '@'},
+                    {title: '名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 230, formatter: '@'},
+                    {title: '单位', colSpan: '1', rowSpan: '1', field: 'unit', hAlign: 1, width: 60, formatter: '@'},
+                ],
+                headRows: 1,
+                emptyRows: 0,
+                headRowHeight: [25],
+                defaultRowHeight: 21,
+                headerFont: '12px 微软雅黑',
+                font: '12px 微软雅黑',
+                readOnly: true,
+                getColor: function (sheet, data, row, col, defaultColor) {
+                    return data && data.invalid ? '#dddddd' : defaultColor;
+                }
+            };
+            sjsSettingObj.setFxTreeStyle(spreadSetting, sjsSettingObj.FxTreeStyle.jz);
+            SpreadJsObj.initSheet(this.sheet, spreadSetting);
+            const self = this;
+            this.spread.bind(spreadNS.Events.ButtonClicked, function (e, info) {
+                function checkInvalid(node) {
+                    if (node.invalid) return 1;
+                    if (self.tree.checkParent(node, 'invalid')) return 2;
+                    if (self.tree.checkChildren(node, 'invalid')) return 3;
+                    return 0;
+                }
+
+                const sheet = info.sheet, cellType = sheet.getCellType(info.row, info.col);
+                if (!sheet.zh_setting) return;
+
+                if (cellType instanceof spreadNS.CellTypes.CheckBox) {
+                    if (sheet.isEditing()) sheet.endEdit(true);
+                }
+
+                const col = sheet.zh_setting.cols[info.col];
+                if (col.field !== 'check') return;
+
+                const tree = sheet.zh_tree;
+                const node = SpreadJsObj.getSelectObject(sheet);
+                if (node.b_code) {
+                    toastr.warning('请选择部位');
+                    return;
+                }
+
+                if (!node.check) {
+                    const invalid = checkInvalid(node);
+                    const invalidHint = ['该部位已被选择,请勿重复选择', '该部位的父项已被选择,请勿选择', '该部位的子项已被选择,请勿在其子项中选择'];
+                    if (invalid) {
+                        toastr.warning(invalidHint[invalid-1]);
+                        return;
+                    }
+                    if (self.tree.checkParent(node)) {
+                        const rect = info.sheet.getCellRect(info.row, info.col);
+                        self.chooseConfirmPopover({
+                            x: rect.x + rect.width / 2 + 25,
+                            y: rect.y + rect.height / 2 + 3,
+                        }, '父项已勾选,继续将取消父项勾选。', function () {
+                            node.check = true;
+                            const parents = tree.getFullPathNodes(tree.getParent(node).full_path);
+                            const rows = [tree.nodes.indexOf(node)];
+                            for (const p of parents) {
+                                if (p.check) {
+                                    p.check = false;
+                                    rows.push(tree.nodes.indexOf(p));
+                                }
+                            }
+                            SpreadJsObj.reLoadRowsData(info.sheet, rows);
+                        });
+                    } else if (self.tree.checkChildren(node)) {
+                        const rect = info.sheet.getCellRect(info.row, info.col);
+                        self.chooseConfirmPopover({
+                            x: rect.x + rect.width / 2 + 25,
+                            y: rect.y + rect.height / 2 + 3,
+                        }, '子项已勾选,继续将取消子项勾选。', function () {
+                            node.check = true;
+                            const posterity = tree.getPosterity(node);
+                            const rows = [tree.nodes.indexOf(node)];
+                            for (const p of posterity) {
+                                if (p.check) {
+                                    rows.push(tree.nodes.indexOf(p));
+                                    p.check = false;
+                                }
+                            }
+                            SpreadJsObj.reLoadRowsData(info.sheet, rows);
+                        });
+                    } else {
+                        node.check = true;
+                        SpreadJsObj.reLoadRowsData(info.sheet, [info.row]);
+                    }
+                } else {
+                    node.check = false;
+                    SpreadJsObj.reLoadRowsData(info.sheet, [info.row]);
+                }
+            });
+            SpreadJsObj.loadSheetData(this.sheet, SpreadJsObj.DataType.Tree, this.tree);
+        }
+        reBind(obj, eventName, fun) {
+            obj.unbind(eventName);
+            obj.bind(eventName, fun);
+        }
+        chooseConfirmPopover(pos, hint, okCallback) {
+            const confirmObj = $('#choose-confirm'), hintObj = $('#choose-confirm-hint');
+            const okObj = $('#choose-confirm-ok'), cancelObj = $('#choose-confirm-cancel');
+            this.reBind(cancelObj, 'click', function () {
+                confirmObj.hide();
+            });
+            this.reBind(okObj, 'click', function () {
+                okCallback();
+                confirmObj.hide();
+            });
+            hintObj.text(hint);
+            confirmObj.css("top", pos.y).css("left", pos.x).show();
+        }
+        loadTree(data) {
+            this.tree.loadDatas(data);
+        }
+        show(price, samePrice){
+            this.price = price;
+            this.choose = price.rela_lid ? price.rela_lid.split(',') : [];
+            this.invalid = [];
+            for (const sp of samePrice) {
+                const lid = sp.rela_lid ? sp.rela_lid.split(',') : [];
+                this.invalid.push(...lid);
+            }
+            for (const node of this.tree.nodes) {
+                node.check = this.choose.indexOf(node.ledger_id + '') >= 0;
+                node.invalid = this.invalid.indexOf(node.ledger_id + '') >= 0;
+            }
+            $('#choose-rela-bw').modal('show');
+        }
+    }
+    const chooseRelaBw = new ChooseRelaBw();
+    class ChooseRelaChange {
+        constructor (){
+            const self = this;
+            $('#choose-rela-change').on('shown.bs.modal', function() {
+                self.initSpread();
+                SpreadJsObj.reloadColData(self.sheet, 0, 1);
+                SpreadJsObj.reloadRowBackColor(self.sheet, 0, self.change.length);
+            });
+            $('#choose-rela-change-ok').click(function() {
+                const choose_cid = [];
+                self.change.forEach(x => {
+                    if (x.check) choose_cid.push(x.cid);
+                });
+                priceOprObj.updateRelaCid(self.price, choose_cid.join(','));
+                $('#choose-rela-change').modal('hide');
+            });
+        }
+        initSpread() {
+            if (this.spread) return;
 
-    postData('load', { filter: 'bills;pos;price' }, result => {
-        revisePrice.loadDatas(result.price);
+            this.spread = SpreadJsObj.createNewSpread($('#rela-change-spread')[0]);
+            this.sheet = this.spread.getActiveSheet();
+            const spreadSetting = {
+                cols: [
+                    {title: '选择', colSpan: '1', rowSpan: '1', field: 'check', hAlign: 1, width: 50, formatter: '@',  cellType: 'checkbox'},
+                    {title: '变更令', colSpan: '1', rowSpan: '1', field: 'code', hAlign: 0, width: 150, formatter: '@'},
+                    {title: '名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 230, formatter: '@'},
+                    {title: '单位', colSpan: '1', rowSpan: '1', field: 'unit', hAlign: 1, width: 60, formatter: '@'},
+                ],
+                headRows: 1,
+                emptyRows: 0,
+                headRowHeight: [25],
+                defaultRowHeight: 21,
+                headerFont: '12px 微软雅黑',
+                font: '12px 微软雅黑',
+                readOnly: true,
+                getColor: function (sheet, data, row, col, defaultColor) {
+                    return data && data.invalid ? '#dddddd' : defaultColor;
+                }
+            };
+            SpreadJsObj.initSheet(this.sheet, spreadSetting);
+            const self = this;
+            this.spread.bind(spreadNS.Events.ButtonClicked, function (e, info) {
+                const sheet = info.sheet, cellType = sheet.getCellType(info.row, info.col);
+                if (!sheet.zh_setting) return;
+
+                if (cellType instanceof spreadNS.CellTypes.CheckBox) {
+                    if (sheet.isEditing()) sheet.endEdit(true);
+                }
+
+                const col = sheet.zh_setting.cols[info.col];
+                if (col.field !== 'check') return;
+
+                const node = SpreadJsObj.getSelectObject(sheet);
+
+                if (!node.check) {
+                    if (node.invalid) return;
+                    node.check = true;
+                    SpreadJsObj.reLoadRowsData(info.sheet, [info.row]);
+                } else {
+                    node.check = false;
+                    SpreadJsObj.reLoadRowsData(info.sheet, [info.row]);
+                }
+            });
+            SpreadJsObj.loadSheetData(this.sheet, SpreadJsObj.DataType.Data, this.change);
+        }
+        loadChange(data) {
+            this.change = data;
+        }
+        show(price, samePrice) {
+            this.price = price;
+            this.choose = price.rela_cid ? price.rela_cid.split(',') : [];
+            this.invalid = [];
+            for (const sp of samePrice) {
+                const cid = sp.rela_cid ? sp.rela_cid.split(',') : [];
+                this.invalid.push(...cid);
+            }
+            for (const c of this.change) {
+                c.check = this.choose.indexOf(c.cid + '') >= 0;
+                c.invalid = this.invalid.indexOf(c.cid + '') >= 0;
+                if (!c.check && c.invalid) {
+                    const exist = c.bills.find(x => {
+                        return x.code === price.b_code && x.name === price.name && x.unit === price.unit && x.unit_price === price.org_price;
+                    });
+                    c.invalid = !exist;
+                }
+            }
+            $('#choose-rela-change').modal('show');
+        }
+    }
+    const chooseRelaChange = new ChooseRelaChange();
+
+    postData('load', { filter: 'bills;pos;price;change' }, result => {
+        revisePrice.loadDatas(result.price, result.bills, result.change);
         SpreadJsObj.loadSheetData(priceSheet, SpreadJsObj.DataType.Data, revisePrice.data);
         ledgerGcl.loadData(result.bills, result.pos);
+        chooseRelaBw.loadTree(result.bills);
+        chooseRelaChange.loadChange(result.change);
+        SpreadJsObj.loadSheetData(priceBwSheet, SpreadJsObj.DataType.Tree, revisePrice.tree);
+        SpreadJsObj.loadSheetData(priceChangeSheet, SpreadJsObj.DataType.Data, revisePrice.change);
         $("[content='#ledgerGcl']").click();
     });
 
@@ -468,7 +933,7 @@ $(document).ready(() => {
         if (!tab.hasClass('active')) {
             $('a', '#side-menu').removeClass('active');
             tab.addClass('active');
-            $('.tab-content .tab-pane').removeClass('active');
+            $('#right-view .tab-pane').removeClass('active');
             tabPanel.addClass('active');
             showSideTools(tab.hasClass('active'));
             ledgerGcl.spread.refresh();
@@ -479,5 +944,15 @@ $(document).ready(() => {
             showSideTools(tab.hasClass('active'));
         }
         priceSpread.refresh();
+        priceBwSpread.refresh();
+        priceChangeSpread.refresh();
+    });
+    $('a', '.bcontent-wrap').click(function() {
+        $('[name=priceRela]').removeClass('active');
+        $(this).addClass('active');
+        $('#priceRelaTab').children().removeClass('active');
+        $(this.getAttribute('href')).addClass('active');
+        priceBwSpread.refresh();
+        priceChangeSpread.refresh();
     });
 });

+ 71 - 13
app/public/js/spreadjs_rela/spreadjs_zh.js

@@ -436,14 +436,6 @@ const SpreadJsObj = {
         }
         cell.font(font);
 
-        if (col.foreColor) {
-            if (Object.prototype.toString.apply(col.foreColor) === "[object Function]") {
-                cell.foreColor(col.foreColor(data, sheet.getDefaultStyle().foreColor));
-            } else {
-                cell.foreColor(col.foreColor);
-            }
-        }
-
         if (col.readOnly && Object.prototype.toString.apply(col.readOnly) === "[object Function]") {
             cell.locked(col.readOnly(data) || sheet.zh_setting.readOnly || false).vAlign(1).hAlign(col.hAlign);
         } else {
@@ -461,9 +453,20 @@ const SpreadJsObj = {
         }
 
         cell.backColor(SpreadJsObj._getBackColor(sheet, data, iRow, col));
+        cell.foreColor(SpreadJsObj._getForeColor(sheet, data, iRow, col));
 
         cell.setBorder(sheet.borderLine, {all: true});
     },
+    _getForeColor: function (sheet, data, row, col) {
+        let foreColor = sheet.getDefaultStyle().foreColor;
+        if (sheet.zh_setting.tree.getForeColor && Object.prototype.toString.apply(sheet.zh_setting.tree.getForeColor) === "[object Function]") {
+            foreColor = sheet.zh_setting.tree.getColor(sheet, data, row, col, foreColor);
+        }
+        if (sheet.zh_setting.getForeColor && Object.prototype.toString.apply(sheet.zh_setting.getForeColor) === "[object Function]") {
+            foreColor = sheet.zh_setting.getForeColor(sheet, data, row, col, foreColor);
+        }
+        return foreColor;
+    },
     _getBackColor: function (sheet, data, row, col) {
         let backColor = sheet.getDefaultStyle().backColor;
         let sels = sheet.getSelections();
@@ -487,10 +490,6 @@ const SpreadJsObj = {
                 cell.font(col.font);
             }
 
-            if (col.foreColor && Object.prototype.toString.apply(col.foreColor) !== "[object Function]") {
-                cell.foreColor(col.foreColor);
-            }
-
             const readOnly1 = (sheet.zh_setting.readOnly && Object.prototype.toString.apply(sheet.zh_setting.readOnly) === "[object Function]")
                 ? sheet.zh_setting.readOnly(data) : (sheet.zh_setting.readOnly || false);
             const readOnly2 = (col.readOnly && Object.prototype.toString.apply(col.readOnly) === "[object Function]")
@@ -559,6 +558,7 @@ const SpreadJsObj = {
             }
 
             cell.backColor(SpreadJsObj._getBackColor(sheet, data, row, col));
+            cell.foreColor(SpreadJsObj._getForeColor(sheet, data, row, col));
 
             cell.setBorder(sheet.borderLine, {all: true});
             data.waitingLoading = false;
@@ -823,6 +823,57 @@ const SpreadJsObj = {
             this.endMassOperation(sheet);
         }
     },
+    reloadRowForeColor: function (sheet, row, count) {
+        const sortData = sheet.zh_dataType === 'tree' ? sheet.zh_tree.nodes : sheet.zh_data;
+
+        this.beginMassOperation(sheet);
+        try {
+            for (let i = row; i < row + count; i++) {
+                if (i < 0) { continue; }
+                const data = sortData[i];
+                for (const [iCol, col] of sheet.zh_setting.cols.entries()) {
+                    sheet.getCell(i, iCol).foreColor(SpreadJsObj._getForeColor(sheet, data, i, col));
+                }
+            };
+            this.endMassOperation(sheet);
+        } catch (err) {
+            this.endMassOperation(sheet);
+        }
+    },
+    reloadRowsForeColor: function (sheet, rows) {
+        const sortData = sheet.zh_dataType === 'tree' ? sheet.zh_tree.nodes : sheet.zh_data;
+
+        this.beginMassOperation(sheet);
+        try {
+            for (const row of rows) {
+                if (row < 0) { continue; }
+                const data = sortData[row];
+                for (const [iCol, col] of sheet.zh_setting.cols.entries()) {
+                    sheet.getCell(row, iCol).foreColor(SpreadJsObj._getForeColor(sheet, data, row, col));
+                }
+            };
+            this.endMassOperation(sheet);
+        } catch (err) {
+            this.endMassOperation(sheet);
+        }
+    },
+    reloadRowBackColor: function (sheet, row, count) {
+        const sortData = sheet.zh_dataType === 'tree' ? sheet.zh_tree.nodes : sheet.zh_data;
+
+        this.beginMassOperation(sheet);
+        try {
+            for (let i = row; i < row + count; i++) {
+                if (i < 0) { continue; }
+                const data = sortData[i];
+                for (const [iCol, col] of sheet.zh_setting.cols.entries()) {
+                    sheet.getCell(i, iCol).backColor(SpreadJsObj._getBackColor(sheet, data, i, col));
+                }
+            };
+            this.endMassOperation(sheet);
+        } catch (err) {
+            this.endMassOperation(sheet);
+        }
+    },
     reloadRowsBackColor: function (sheet, rows) {
         const sortData = sheet.zh_dataType === 'tree' ? sheet.zh_tree.nodes : sheet.zh_data;
 
@@ -866,7 +917,6 @@ const SpreadJsObj = {
      * @param {Array} cols
      */
     reLoadColsData: function (sheet, cols) {
-        const self = this;
         const sortData = sheet.zh_dataType === 'tree' ? sheet.zh_tree.nodes : sheet.zh_data;
 
         this.beginMassOperation(sheet);
@@ -1349,8 +1399,10 @@ const SpreadJsObj = {
                                 const x1 = centerX + indent / 2;
                                 if (dotLine) {
                                     drawDotLine(canvas, centerX, centerY, Math.min(x1, x + w), centerY, lineColor);
+                                    // drawDotLine(canvas, centerX, centerY, Math.min(x1, x + w), centerY, style.foreColor);
                                 } else {
                                     drawLine(canvas, centerX, centerY, Math.min(x1, x + w), centerY, lineColor);
+                                    // drawLine(canvas, centerX, centerY, Math.min(x1, x + w), centerY, style.foreColor);
                                 }
                             }
                             // Draw Vertical Line
@@ -1361,14 +1413,18 @@ const SpreadJsObj = {
                                 if (node.order === 1 && !parent) {
                                     if (dotLine) {
                                         drawDotLine(canvas, centerX, centerY, centerX, y1, lineColor);
+                                        // drawDotLine(canvas, centerX, centerY, centerX, y1, style.foreColor);
                                     } else {
                                         drawLine(canvas, centerX, centerY, centerX, y1, lineColor);
+                                        // drawLine(canvas, centerX, centerY, centerX, y1, style.foreColor);
                                     }
                                 } else {
                                     if (dotLine) {
                                         drawDotLine(canvas, centerX, y, centerX, y1, lineColor);
+                                        // drawDotLine(canvas, centerX, y, centerX, y1, style.foreColor);
                                     } else {
                                         drawLine(canvas, centerX, y, centerX, y1, lineColor);
+                                        // drawLine(canvas, centerX, y, centerX, y1, style.foreColor);
                                     }
                                 }
                             }
@@ -1385,8 +1441,10 @@ const SpreadJsObj = {
                                     if (parentCenterX < x + w) {
                                         if (dotLine) {
                                             drawDotLine(canvas, parentCenterX, y, parentCenterX, y + h, lineColor);
+                                            // drawDotLine(canvas, parentCenterX, y, parentCenterX, y + h, style.foreColor);
                                         } else {
                                             drawLine(canvas, parentCenterX, y, parentCenterX, y + h, lineColor);
+                                            // drawLine(canvas, parentCenterX, y, parentCenterX, y + h, style.foreColor);
                                         }
                                     }
                                 }

+ 10 - 0
app/public/js/stage_compare.js

@@ -341,4 +341,14 @@ $(document).ready(function () {
 
         SpreadExcelObj.exportSimpleXlsxSheet(ledgerSpreadSetting, data, $('.sidebar-title').attr('data-original-title') + "-审核比较.xlsx");
     });
+    $('[name=compareType]').click(function () {
+        $('[name=compareType]').removeClass('active');
+        $(this).addClass('active');
+        $('#compareType').children().removeClass('active');
+        $(this.getAttribute('href')).addClass('active');
+        xmjSpread.refresh();
+        posSpread.refresh();
+        gclSpread.refresh();
+        leafXmjSpread.refresh();
+    });
 });

+ 2 - 0
app/service/revise_price.js

@@ -69,6 +69,8 @@ module.exports = app => {
                     nd.valid = !this.ctx.helper.checkZero(this.ctx.helper.sub(nd.new_price, d.org_price));
                 }
                 if (d.memo !== undefined) nd.memo = d.memo;
+                if (d.rela_lid !== undefined) nd.rela_lid = d.rela_lid;
+                if (d.rela_cid !== undefined) nd.rela_cid = d.rela_cid;
                 uDatas.push(nd);
             }
             if (uDatas.length > 0) {

+ 24 - 1
app/view/revise/price.ejs

@@ -13,7 +13,30 @@
             <!--左栏-->
             <div class="c-body" id="left-view" style="width: 100%">
                 <!--0号台账模式-->
-                <div class="sjs-height-0" style="overflow: hidden" id="price-spread">
+                <div class="sjs-height-1" style="overflow: hidden" id="price-spread">
+                </div>
+                <div class="bcontent-wrap" id="bottom-view">
+                    <div id="price-resize" class="resize-y" r-Type="height" div1="#price-spread" div2="#bottom-view" store-id="price" store-version="1.0.0" min="150"></div>
+                    <div class="bc-bar mb-1">
+                        <ul class="nav nav-tabs">
+                            <li class="nav-item">
+                                <a class="nav-link active" href="#price-bw" name="priceRela">应用部位</a>
+                            </li>
+                            <li class="nav-item">
+                                <a class="nav-link" href="#price-change" name="priceRela">应用变更令</a>
+                            </li>
+                        </ul>
+                    </div>
+                    <div class="tab-content" id="priceRelaTab">
+                        <div class="tab-pane active" id="price-bw">
+                            <div class="sp-wrap" id="price-bw-spread">
+                            </div>
+                        </div>
+                        <div class="tab-pane" id="price-change">
+                            <div class="sp-wrap" id="price-change-spread">
+                            </div>
+                        </div>
+                    </div>
                 </div>
             </div>
             <!--右栏-->

+ 47 - 0
app/view/revise/price_modal.ejs

@@ -0,0 +1,47 @@
+<div class="modal fade" id="choose-rela-bw" data-backdrop="static">
+    <div class="modal-dialog modal-lg" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">选择应用部位</h5>
+            </div>
+            <div class="modal-body">
+                <div class="modal-height-500" id="rela-bw-spread">
+                </div>
+                <div class="popover bs-popover-right" role="tooltip" id="choose-confirm" style="display: none">
+                    <div class="arrow" style="top:30px"></div>
+                    <div class="popover-body">
+                        <p id="choose-confirm-hint">父项已勾选,继续将取消父项勾选。</p>
+                        <p class="mb-0 d-flex justify-content-end">
+                            <button class="btn btn-sm btn-secondary" id="choose-confirm-cancel">取消</button>&nbsp;<button class="btn btn-sm btn-success" id="choose-confirm-ok">继续</button>
+                        </p>
+                    </div>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
+                <% if (!ctx.revise.readOnly) { %>
+                <button type="button" class="btn btn-primary btn-sm" id="choose-rela-bw-ok">确定</button>
+                <% } %>
+            </div>
+        </div>
+    </div>
+</div>
+<div class="modal fade" id="choose-rela-change" data-backdrop="static">
+    <div class="modal-dialog modal-lg" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">选择应用变更令</h5>
+            </div>
+            <div class="modal-body">
+                <div class="modal-height-500" id="rela-change-spread">
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
+                <% if (!ctx.revise.readOnly) { %>
+                <button type="button" class="btn btn-primary btn-sm" id="choose-rela-change-ok">确定</button>
+                <% } %>
+            </div>
+        </div>
+    </div>
+</div>

+ 6 - 0
sql/update.sql

@@ -1 +1,7 @@
 ALTER TABLE `zh_project_account` CHANGE `stamp_path` `stamp_path` VARCHAR(5000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户签章oss地址';
+
+ALTER TABLE `zh_revise_price`
+ADD COLUMN `rela_lid`  varchar(1000) NOT NULL DEFAULT '' COMMENT '关联台账id(zh_ledger.ledger_id)' AFTER `use_stage_order`;
+
+ALTER TABLE `zh_revise_price`
+ADD COLUMN `rela_cid`  varchar(5000) NOT NULL DEFAULT '' COMMENT '关联变更令id(zh_change.cid)' AFTER `rela_lid`;