Selaa lähdekoodia

计量台账,按比例计量

MaiXinRong 4 vuotta sitten
vanhempi
commit
91b2e5c65d
3 muutettua tiedostoa jossa 290 lisäystä ja 47 poistoa
  1. 141 46
      app/public/js/stage.js
  2. 109 1
      app/service/stage_pos.js
  3. 40 0
      app/view/stage/modal.ejs

+ 141 - 46
app/public/js/stage.js

@@ -962,7 +962,7 @@ $(document).ready(() => {
             }
         },
         measureAllPosInNode(node, ratio = 1) {
-            const posterity = stageTree.getPosterity(node)
+            const posterity = stageTree.getPosterity(node);
             const data = {updateType: 'update', updateData: []};
             for (const p of posterity) {
                 if (p.children && p.children.length > 0) continue;
@@ -1089,6 +1089,46 @@ $(document).ready(() => {
                 }
             }
         },
+        measureByBatch: function (posNames, ratio, apply2sibling) {
+            if (posNames.length <= 0) return;
+            if (ratio <= 0) return;
+
+            const sheet = slSpread.getActiveSheet();
+            const node = SpreadJsObj.getSelectObject(sheet);
+            const parent = stageTree.getParent(node);
+            const nodes = apply2sibling === true ? (parent ? parent.children : stageTree.children) : [node];
+            const data = {updateType: 'batchUpdate', updateData: []};
+            for (const node of nodes) {
+                const posRange = stagePos.getLedgerPos(node.id);
+                if (!posRange || posRange <= 0) continue;
+
+                for (const p of posRange) {
+                    if (posNames.indexOf(p.name) < 0) continue;
+                    data.updateData.push({
+                        pid: p.id, lid: p.lid,
+                        contract_qty: ZhCalc.mul(p.quantity, ratio)
+                    });
+                }
+            }
+            postData(window.location.pathname + '/update', {pos: data}, function (result) {
+                if (result.pos) {
+                    stagePos.updateDatas(result.pos.pos);
+                    stagePos.loadCurStageData(result.pos.curStageData);
+                }
+                const nodes = stageTree.loadPostStageData(result.ledger);
+                stageTreeSpreadObj.refreshTreeNodes(slSpread.getActiveSheet(), nodes);
+                stagePosSpreadObj.loadCurPosData();
+                if (detail) {
+                    detail.loadStagePosUpdateData(result);
+                } else {
+                    stageIm.loadUpdatePosData(result);
+                }
+                $('#calc-by-ratio').modal('hide');
+            }, function () {
+                stagePosSpreadObj.loadCurPosData();
+                $('#calc-by-ratio').modal('hide');
+            });
+        }
     };
     slSpread.bind(spreadNS.Events.EditEnded, stageTreeSpreadObj.editEnded);
     slSpread.bind(spreadNS.Events.SelectionChanged, stageTreeSpreadObj.selectionChanged);
@@ -1673,63 +1713,89 @@ $(document).ready(() => {
             });
         });
     }
-    if (!checkTzMeasureType()) {
-        const mergePeg = NewMergePeg({ callback: stagePosSpreadObj.addPegs});
-        $.contextMenu({
-            selector: '#stage-pos',
-            build: function ($trigger, e) {
-                const target = SpreadJsObj.safeRightClickSelection($trigger, e, spSpread);
-                return target.hitTestType === spreadNS.SheetArea.viewport || target.hitTestType === spreadNS.SheetArea.rowHeader;
-            },
-            items: {
-                'del': {
-                    name: '删除',
-                    icon: 'fa-remove',
-                    disabled: function (key, opt) {
-                        const sheet = spSpread.getActiveSheet();
-                        if (sheet.zh_data && !readOnly) {
-                            const selection = sheet.getSelections();
-                            if (selection && selection[0]) {
-                                let valid = sheet.zh_data.length < selection[0].row + selection[0].rowCount;
-                                for (let iRow = 0; iRow < selection[0].rowCount; iRow++) {
-                                    const posData = sheet.zh_data[selection[0].row + iRow];
-                                    if (posData) {
-                                        if (posData.add_stage_order < stage.order || ZhCalc.isNonZero(posData.gather_qty) || ZhCalc.isNonZero(posData.end_gather_qty)) {
-                                            valid = true;
-                                            break;
-                                        }
-                                    } else {
+
+    const mergePeg = NewMergePeg({ callback: stagePosSpreadObj.addPegs});
+    $.contextMenu({
+        selector: '#stage-pos',
+        build: function ($trigger, e) {
+            const target = SpreadJsObj.safeRightClickSelection($trigger, e, spSpread);
+            return target.hitTestType === spreadNS.SheetArea.viewport || target.hitTestType === spreadNS.SheetArea.rowHeader;
+        },
+        items: {
+            'del': {
+                name: '删除',
+                icon: 'fa-remove',
+                visible: function (key, opt) {
+                    return !checkTzMeasureType();
+                },
+                disabled: function (key, opt) {
+                    const sheet = spSpread.getActiveSheet();
+                    if (sheet.zh_data && !readOnly) {
+                        const selection = sheet.getSelections();
+                        if (selection && selection[0]) {
+                            let valid = sheet.zh_data.length < selection[0].row + selection[0].rowCount;
+                            for (let iRow = 0; iRow < selection[0].rowCount; iRow++) {
+                                const posData = sheet.zh_data[selection[0].row + iRow];
+                                if (posData) {
+                                    if (posData.add_stage_order < stage.order || ZhCalc.isNonZero(posData.gather_qty) || ZhCalc.isNonZero(posData.end_gather_qty)) {
                                         valid = true;
                                         break;
                                     }
+                                } else {
+                                    valid = true;
+                                    break;
                                 }
-                                return valid;
-                            } else {
-                                return true;
                             }
+                            return valid;
                         } else {
                             return true;
                         }
-                    },
-                    callback: function (key, opt) {
-                        stagePosSpreadObj.deletePos(spSpread.getActiveSheet());
+                    } else {
+                        return true;
                     }
                 },
-                'merge-peg': {
-                    name: '合并起讫桩号',
-                    disabled: function (key, opt) {
-                        const node = SpreadJsObj.getSelectObject(slSpread.getActiveSheet());
-                        return _.isNil(node) || _.isNil(node.b_code) || node.b_code === '';
-                    },
-                    callback: function (key, opt) {
-                        mergePeg.show();
-                    }
+                callback: function (key, opt) {
+                    stagePosSpreadObj.deletePos(spSpread.getActiveSheet());
+                }
+            },
+            'merge-peg': {
+                name: '合并起讫桩号',
+                visible: function (key, opt) {
+                    return !checkTzMeasureType();
+                },
+                disabled: function (key, opt) {
+                    const node = SpreadJsObj.getSelectObject(slSpread.getActiveSheet());
+                    return _.isNil(node) || _.isNil(node.b_code) || node.b_code === '';
+                },
+                callback: function (key, opt) {
+                    mergePeg.show();
+                }
+            },
+            'calcByRatio': {
+                name: '按比例计量',
+                visible: function (key, opt) {
+                    const data = spSpread.getActiveSheet().zh_data;
+                    return data && data.length > 0;
+                },
+                callback: function (key, opt) {
+                    $('#cbr-ratio').val('');
+                    $('#apply2sibling')[0].checked = false;
+                    $('#cbr-check-all')[0].checked = false;
+                    const html = [];
+                    for (const [i, p] of spSpread.getActiveSheet().zh_data.entries()) {
+                        html.push('<tr>');
+                        html.push('<td>', i, '</td>');
+                        html.push('<td>', p.name, '</td>');
+                        html.push('<td>', p.quantity, '</td>');
+                        html.push('<td><input type="checkbox" pos-name="' + p.name + '"></td></td>');
+                        html.push('</tr>');
+                    }
+                    $('#cbr-pos-list').html(html.join(''));
+                    $('#calc-by-ratio').modal('show');
                 }
             }
-        })
-    } else {
-        SpreadJsObj.forbiddenSpreadContextMenu('#stage-pos', spSpread);
-    }
+        }
+    });
     $.subMenu({
         menu: '#sub-menu', miniMenu: '#sub-mini-menu', miniMenuList: '#mini-menu-list',
         toMenu: '#to-menu', toMiniMenu: '#to-mini-menu',
@@ -3622,4 +3688,33 @@ $(document).ready(() => {
 
         SpreadExcelObj.exportSimpleXlsxSheet(setting, data, $('.sidebar-title').attr('data-original-title') + "计量台账.xlsx");
     });
+
+    $('#cbr-check-all').click(function () {
+        if (this.checked) {
+            $('input', '#cbr-pos-list').attr('checked', 'checked');
+        } else {
+            $('input', '#cbr-pos-list').removeAttr('checked');
+        }
+    });
+    $('#cbr-ok').click(() => {
+        const ratio = parseInt($('#cbr-ratio').val());
+        if (!ratio) {
+            toastr.warning('请输入计量比例');
+            return;
+        } else if (ratio < 1) {
+            toastr.warning('计量比例不可小于1');
+            return;
+        } else if (ratio > 100) {
+            toastr.warning('计量比例不可大于100');
+            return;
+        }
+
+        const apply2sibling = $('#apply2sibling')[0].checked;
+        const posName = _.map($('input:checked', '#cbr-pos-list'), function (x) {return $(x).attr('pos-name')});
+        if (posName.length === 0) {
+            toastr.warning('请勾选需要按计量比例的计量单元');
+            return;
+        }
+        stageTreeSpreadObj.measureByBatch(posName, ZhCalc.div(ratio, 100), apply2sibling);
+    })
 });

+ 109 - 1
app/service/stage_pos.js

@@ -38,7 +38,7 @@ module.exports = app => {
             if (where.lid) {
                 if (where.lid instanceof Array) {
                     whereSql += ' And ' + asTable + 'lid in ('  + this.ctx.helper.getInArrStrSqlFilter(where.lid) + ')';
-                } else if (typeof where.pid === "string") {
+                } else if (typeof where.lid === "string") {
                     whereSql += ' And ' + asTable + 'lid = ' + this.db.escape(where.lid);
                 }
             }
@@ -379,6 +379,112 @@ module.exports = app => {
         }
 
         /**
+         * 更新部位明细数据(仅供updateStageData调用)
+         *
+         * @param transaction - 事务
+         * @param data - 更新数据(允许一次性提交多条)
+         * @returns {Promise<{ledger: Array, pos: Array}>}
+         * @private
+         */
+        async _batchUpdateStagePosData(data) {
+            const datas = data instanceof Array ? data : [data];
+            const result = {
+                ledger: this._.uniq(this._.map(datas, 'lid')),
+                pos: this._.map(datas, 'pid'),
+                stageUpdate: true
+            };
+
+            const orgStagePos = await this.getLastestStageData2(this.ctx.tender.id, this.ctx.stage.id,
+                {pid: this._.map(datas, 'pid')});
+
+            const bills = await this.ctx.service.ledger.getAllDataByCondition({where: {id: result.ledger}});
+            for (const b of bills) {
+                b.precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, b.unit);
+            }
+
+            const updatePosStage = [], insertPosStage = [];
+            for (const d of datas) {
+                const b = this._.find(bills, {id: d.lid});
+
+                const osp = this._.find(orgStagePos, function (p) { return p.pid === d.pid; });
+
+                if (osp && osp.times === this.ctx.stage.curTimes && osp.order === this.ctx.stage.curOrder) {
+                    const sp = {id: osp.id};
+                    if (d.contract_qty !== undefined) {
+                        sp.contract_qty = this.ctx.helper.round(d.contract_qty, b.precision.value);
+                    }
+                    if (osp.contract_expr) sp.contract_expr = null;
+                    updatePosStage.push(sp);
+                } else {
+                    const sp = {
+                        pid: d.pid, lid: d.lid,
+                        tid: this.ctx.tender.id, sid: this.ctx.stage.id,
+                        said: this.ctx.session.sessionUser.accountId,
+                        times: this.ctx.stage.curTimes, order: this.ctx.stage.curOrder
+                    };
+                    if (d.contract_qty !== undefined || osp) {
+                        sp.contract_qty = d.contract_qty === undefined && osp
+                            ? osp.contract_qty
+                            : this.ctx.helper.round(d.contract_qty, b.precision.value);
+                    }
+                    insertPosStage.push(sp);
+                }
+                result.pos.push(d.pid);
+            }
+            const updateBillsStage = [], insertBillsStage = [], info = this.ctx.tender.info;
+            for (const b of bills) {
+                const stageBills = await this.getLastestStageData(b.tender_id, this.ctx.stage.id, b.id);
+
+                const posStage = await this.getLastestStageData2(b.tender_id, this.ctx.stage.id, {lid: b.id});
+                let contract_qty = 0;
+                for (const ps of posStage) {
+                    const nps = this._.find(datas, {pid: ps.pid});
+                    contract_qty = this.ctx.helper.add(contract_qty, nps ? nps.contract_qty : ps.contract_qty);
+                }
+                if (stageBills && stageBills.times === this.ctx.stage.curTimes && stageBills.order === this.ctx.stage.curOrder) {
+                    if (contract_qty === stageBills.contract_qty) continue;
+                    updateBillsStage.push({
+                        id: stageBills.id,
+                        contract_qty: contract_qty,
+                        contract_tp: this.ctx.helper.mul(contract_qty, b.unit_price, info.decimal.tp),
+                    });
+                } else {
+                    insertBillsStage.push({
+                        tid: this.ctx.tender.id,
+                        lid: b.id,
+                        sid: this.ctx.stage.id,
+                        times: this.ctx.stage.curTimes,
+                        order: this.ctx.stage.curOrder,
+                        said: this.ctx.session.sessionUser.accountId,
+                        contract_qty: contract_qty,
+                        contract_tp: this.ctx.helper.mul(contract_qty, b.unit_price, info.decimal.tp),
+                    })
+                }
+            }
+
+            const transaction = await this.db.beginTransaction();
+            try {
+                if (updatePosStage.length > 0) {
+                    await transaction.updateRows(this.tableName, updatePosStage);
+                }
+                if (insertPosStage.length > 0) {
+                    await transaction.insert(this.tableName, insertPosStage);
+                }
+                if (updateBillsStage.length > 0) {
+                    await transaction.updateRows(this.ctx.service.stageBills.tableName, updateBillsStage);
+                }
+                if (insertBillsStage.length > 0) {
+                    await transaction.insert(this.ctx.service.stageBills.tableName, insertBillsStage);
+                }
+                await transaction.commit();
+                return result;
+            } catch (err) {
+                await transaction.rollback();
+                throw err;
+            }
+        }
+
+        /**
          * 删除部位明细数据(仅供updateStageData调用)
          *
          * @param transaction - 事务
@@ -451,6 +557,8 @@ module.exports = app => {
                 refreshData = await this._addStagePosData(data.updateData);
             } else if (data.updateType === 'update') {
                 refreshData = await this._updateStagePosData(data.updateData);
+            } else if (data.updateType === 'batchUpdate') {
+                refreshData = await this._batchUpdateStagePosData(data.updateData);
             } else if (data.updateType === 'delete') {
                 if (!data.updateData || data.updateData.length === 0) {
                     throw '提交数据错误';

+ 40 - 0
app/view/stage/modal.ejs

@@ -410,6 +410,46 @@
         </div>
     </div>
 </div>
+
+<!--按比例计量-->
+<div class="modal fade" id="calc-by-ratio" 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">
+                <div class="input-group input-group-sm mb-1 col-5 p-0">
+                    <div class="input-group-prepend">
+                        <span class="input-group-text">计量比例</span>
+                    </div>
+                    <input class="form-control nospin" type="number" min="1" max="100" id="cbr-ratio">
+                    <div class="input-group-append">
+                        <span class="input-group-text">%</span>
+                    </div>
+                </div>
+                <div class="d-inline-block mb-1">
+                    <div class="form-check">
+                        <input class="form-check-input" type="checkbox" value="" id="apply2sibling">
+                        <label class="form-check-label" for="apply2sibling">
+                            当前细目下同名计量单元同步计量
+                        </label>
+                    </div>
+                </div>
+                <div class="modal-height-300">
+                    <table class="table table-bordered">
+                        <thead><tr><th>序号</th><th>计量单元</th><th>台帐数量</th><th><input id="cbr-check-all" type="checkbox"></th></tr></thead>
+                        <tbody id="cbr-pos-list"></tbody>
+                    </table>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">关闭</button>
+                <a href="javascript: void(0);" class="btn btn-sm btn-primary" id="cbr-ok">确定</a>
+            </div>
+        </div>
+    </div>
+</div>
 <% include ./audit_modal.ejs %>
 <% include ../shares/merge_peg_modal.ejs %>
 <% include ../shares/ledger_check_modal.ejs %>