Browse Source

Merge branch 'dev' of http://192.168.1.41:3000/maixinrong/Calculation into dev

laiguoran 4 years ago
parent
commit
8d0be66fef

+ 54 - 0
app/controller/setting_controller.js

@@ -14,6 +14,7 @@ const settingMenu = require('../../config/menu').settingMenu;
 const accountGroup = require('../const/account_group').group;
 const permission = require('../const/account_permission').permission;
 const projectLog = require('../const/project_log');
+const imType = require('../const/tender').imType;
 
 module.exports = app => {
 
@@ -679,6 +680,59 @@ module.exports = app => {
                 ctx.redirect('/dashboard');
             }
         }
+
+        async fun(ctx) {
+            try {
+                const projectId = ctx.session.sessionProject.id;
+                const projectData = await ctx.service.project.getDataById(projectId);
+                const funRela = await ctx.service.project.getFunRela(projectId);
+                if (projectData === null) {
+                    throw '没有对应的项目数据';
+                }
+                if (ctx.session.sessionUser.is_admin === 0) {
+                    throw '没有访问权限';
+                }
+                await this.layout('setting/fun.ejs', {
+                    projectData,
+                    funRela,
+                    imType,
+                })
+            } catch (error) {
+                ctx.helper.log(error);
+                ctx.redirect('/dashboard');
+            }
+        }
+
+        /**
+         * 保存功能设置相关
+         * @param ctx
+         * @returns {Promise<void>}
+         */
+        async updateFun(ctx) {
+            try {
+                const projectId = ctx.session.sessionProject.id;
+                const projectData = await ctx.service.project.getDataById(projectId);
+                if (projectData === null) {
+                    throw '没有对应的项目数据';
+                }
+                if (ctx.session.sessionUser.is_admin === 0) {
+                    throw '没有访问权限';
+                }
+
+                const data = JSON.parse(ctx.request.body.data);
+                if (data) ctx.request.body = data;
+                const rule = ctx.service.project.rule('fun');
+                ctx.validate(rule);
+
+                const result = await ctx.service.project.updateFunRela(projectId, ctx.request.body);
+                if (!result) throw '保存数据失败';
+
+                ctx.body = {err: 0, msg: '', data: null};
+            } catch(error) {
+                ctx.helper.log(error);
+                this.ajaxErrorBody(error, '保存数据失败');
+            }
+        }
     }
 
     return SettingController;

+ 7 - 4
app/controller/stage_controller.js

@@ -349,20 +349,23 @@ module.exports = app => {
 
         async check(ctx) {
             try {
+                const projRela = await this.ctx.service.project.getFunRela(this.ctx.session.sessionProject.id);
                 const ledgerData = await this._getStageLedgerData(ctx);
                 const posData = await this._getStagePosData(ctx);
 
-                const qtyData = ctx.helper.checkBillsWithPos(ledgerData, posData, ['contract_qty', 'qc_qty']);
+                const [qtyData, overData] = ctx.helper.checkBillsWithPos2(ledgerData, posData,
+                    ['contract_qty', 'qc_qty'], projRela.banOver, this.ctx.tender.data.measure_type === measureType.tz.value);
                 qtyData.error.forEach(x => { x.errorType = 'qty'; });
+                overData.error.forEach(x => {x.errorType = 'over'});
                 const tpData = ctx.helper.checkBillsTp(ledgerData.filter(x => {return !x.is_tp}), [
                     { qty: 'contract_qty', tp: 'contract_tp' }, { qty: 'qc_qty', tp: 'qc_tp' },
                 ], this.ctx.tender.info.decimal);
                 tpData.error.forEach(x => { x.errorType = 'tp'; });
                 ctx.body = { err: 0, msg: '', data: {
-                    error: [...qtyData.error, ...tpData.error],
+                    error: [...qtyData.error, ...tpData.error, ...overData.error],
                     source: {
-                        bills: [...qtyData.source.bills, ...tpData.source.bills],
-                        pos: [...qtyData.source.pos, ...tpData.source.pos],
+                        bills: [...qtyData.source.bills, ...tpData.source.bills, ...overData.source.bills],
+                        pos: [...qtyData.source.pos, ...tpData.source.pos, ...overData.source.pos],
                     },
                 } };
             } catch (err) {

+ 82 - 9
app/extend/helper.js

@@ -1148,14 +1148,18 @@ module.exports = {
         return request.url.indexOf('/wap/') !== -1;
     },
 
-    checkBillsWithPos(bills, pos, fields) {
-        const result = {
+    getDefaultCheckResult() {
+        return {
             error: [],
             source: {
                 bills: [],
                 pos: [],
             },
         };
+    },
+
+    checkBillsWithPos(bills, pos, fields) {
+        const result = this.getDefaultCheckResult();
         for (const b of bills) {
             const pr = _.remove(pos, { lid: b.id });
             const checkData = {},
@@ -1186,14 +1190,83 @@ module.exports = {
         return result;
     },
 
+    checkBillsOverRange(bills, posRange, isTz) {
+        if (isTz && posRange.length > 0) {
+            for (const p of posRange) {
+                const end_contract_qty = this.add(p.pre_contract_qty, p.contract_qty);
+                if (end_contract_qty > p.quantity) return true;
+            }
+            return false;
+        } else {
+            const end_qc_qty = this.add(bills.qc_qty, bills.pre_qc_qty);
+            const end_qc_tp = this.add(bills.qc_tp, bills.pre_qc_tp);
+            const end_gather_qty = this.sum([bills.contract_qty, bills.pre_contract_qty, end_qc_qty]);
+            const end_gather_tp = this.sum([bills.contract_tp, bills.pre_contract_tp, end_qc_tp]);
+            if (isTz) {
+                if (end_gather_qty) {
+                    return !bills.quantity || Math.abs(end_gather_qty) > Math.abs(this.add(bills.quantity, end_qc_qty));
+                } else if (end_gather_tp) {
+                    return !bills.total_price || Math.abs(end_gather_tp) > Math.abs(this.add(bills.total_price, end_qc_tp));
+                }
+            } else {
+                if (end_gather_qty) {
+                    return !bills.deal_qty || Math.abs(end_gather_qty) > Math.abs(this.add(bills.deal_qty, end_qc_qty));
+                } else if (end_gather_tp) {
+                    return !bills.deal_tp || Math.abs(end_gather_tp) > Math.abs(this.add(bills.deal_tp, end_qc_tp));
+                }
+            }
+        }
+    },
+
+    checkBillsWithPos2(bills, pos, fields, checkOver, isTz) {
+        const result = this.getDefaultCheckResult(), overResult = this.getDefaultCheckResult();
+        for (const b of bills) {
+            let hasSource = false;
+            const pr = _.remove(pos, { lid: b.id });
+            const checkData = {},
+                calcData = {};
+            if (pr && pr.length > 0) {
+                for (const field of fields) {
+                    checkData[field] = b[field] ? b[field] : 0;
+                }
+                for (const p of pr) {
+                    for (const field of fields) {
+                        calcData[field] = this.add(calcData[field], p[field]);
+                    }
+                }
+                if (!_.isMatch(checkData, calcData)) {
+                    hasSource = true;
+                    result.error.push({
+                        ledger_id: b.ledger_id,
+                        b_code: b.b_code,
+                        name: b.name,
+                        error: { checkData, calcData },
+                    });
+                    result.source.bills.push(b);
+                    for (const p of pr) {
+                        result.source.pos.push(p);
+                    }
+                }
+            }
+            if (checkOver && this.checkBillsOverRange(b, pr, isTz)) {
+                overResult.error.push({
+                    ledger_id: b.ledger_id,
+                    b_code: b.b_code,
+                    name: b.name,
+                });
+                if (!hasSource) {
+                    overResult.source.bills.push(b);
+                    for (const p of pr) {
+                        overResult.source.pos.push(p);
+                    }
+                }
+            }
+        }
+        return [result, overResult];
+    },
+
     checkBillsTp(bills, field, decimal) {
-        const result = {
-            error: [],
-            source: {
-                bills: [],
-                pos: [],
-            },
-        };
+        const result = this.getDefaultCheckResult();
         for (const b of bills) {
             if (!b.check_calc) continue;
 

+ 1 - 0
app/public/js/shares/cs_tools.js

@@ -75,6 +75,7 @@ const showSelectTab = function(select, spread, afterShow) {
                             switch (x.errorType) {
                                 case 'qty': return '数量';
                                 case 'tp': return '金额';
+                                case 'over': return '超计';
                                 default: return '';
                             }
                         }

+ 4 - 0
app/router.js

@@ -85,6 +85,10 @@ module.exports = app => {
     // 操作日志
     app.get('/setting/logs', sessionAuth, 'settingController.logs');
     app.get('/setting/logs/type/:type', sessionAuth, 'settingController.logs');
+    // 功能设置
+    app.get('/setting/fun', sessionAuth, 'settingController.fun');
+    app.post('/setting/fun/update', sessionAuth, 'settingController.updateFun');
+
 
     // 项目相关
     app.get('/project/info', sessionAuth, 'projectController.info');

+ 30 - 0
app/service/project.js

@@ -7,6 +7,11 @@
  * @date 2017/11/16
  * @version
  */
+const imType = require('../const/tender').imType;
+const defaultFunRela = {
+    banOver: false,
+    imType: imType.zl.value,
+};
 
 module.exports = app => {
 
@@ -43,6 +48,12 @@ module.exports = app => {
                         name: { type: 'string', required: true, min: 2 },
                     };
                     break;
+                case 'fun':
+                    rule = {
+                        imType: {type: 'enum', values: [imType.tz.value, imType.zl.value, imType.bb.value, imType.bw.value], required: true},
+                        banOver: {type: 'bool', required: true,}
+                    };
+                    break;
                 default:
                     break;
             }
@@ -135,6 +146,25 @@ module.exports = app => {
             return projectData.page_show ? JSON.parse(projectData.page_show) : null;
         }
 
+        /**
+         * 功能设置
+         * @param id
+         * @returns {Promise<null>}
+         */
+        async getFunRela(id) {
+            const projectData = await this.db.get(this.tableName, { id });
+            const result = projectData.fun_rela ? JSON.parse(projectData.fun_rela) : {};
+            this.ctx.helper._.defaults(result, defaultFunRela);
+            return result;
+        }
+
+        async updateFunRela(id, data) {
+            const result = await this.db.update(this.tableName, {
+                id: id, fun_rela: JSON.stringify({banOver: data.banOver, imType: data.imType}),
+            });
+            return result.affectedRows === 1;
+        }
+
     }
 
     return Project;

+ 3 - 0
app/service/stage.js

@@ -355,6 +355,9 @@ module.exports = app => {
                     const sumTp = await this._getSumTp({tid: preStage.tid}, 'sf_tp');
                     newStage.pre_sf_tp = sumTp.sf_tp || 0;
                 }
+            } else {
+                const projFunRela = await this.ctx.service.project.getFunRela(this.ctx.session.sessionProject.id);
+                newStage.im_type = projFunRela.imType;
             }
             const transaction = await this.db.beginTransaction();
             try {

+ 51 - 0
app/view/setting/fun.ejs

@@ -0,0 +1,51 @@
+<% include ./sub_menu.ejs %>
+<div class="panel-content">
+    <div class="panel-title">
+        <div class="title-main">
+            <h2>功能设置</h2>
+        </div>
+    </div>
+    <div class="content-wrap">
+        <div class="c-body">
+            <div class="sjs-height-0">
+                <div class="row m-0 mt-3">
+                    <div class="col-6">
+                        <div class="form-group">
+                            <label>超计控制</label>
+                            <div>
+                                <div class="form-check form-check-inline">
+                                    <input class="form-check-input" type="checkbox" name="ban_over" <% if (funRela.banOver) { %>checked<% } %> onchange="updateSetting();">
+                                    <label class="form-check-label" for="inlineCheckbox6">超计时限制上报审批/审批通过</label>
+                                </div>
+                            </div>
+                        </div>
+
+                        <div class="form-group">
+                            <label>中间计量模式设置</label>
+                            <div>
+                                <% for (const i in imType) { %>
+                                <div class="form-check form-check-inline">
+                                    <input class="form-check-input" type="radio" id="radio_<%- i %>" value="<%- imType[i].value %>" <% if (funRela.imType === imType[i].value) { %>checked<% } %> name="im_type" onchange="updateSetting();">
+                                    <label class="form-check-label" for="radio_<%- i %>" name="im_type"><%- imType[i].name %></label>
+                                </div>
+                                <% } %>
+                            </div>
+                            <div>
+                                <label class="form-text text-danger">切换模式,仅对未开始第一期计量的标段生效。</label>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+<script src="/public/js/setting.js"></script>
+<script>
+    $(() => {
+        autoFlashHeight();
+    });
+    const updateSetting = function () {
+        postData('/setting/fun/update', {imType: parseInt($('[name=im_type]:checked').val()), banOver: $('[name=ban_over]')[0].checked});
+    }
+</script>

+ 6 - 0
config/menu.js

@@ -261,6 +261,12 @@ const settingMenu = {
         url: '/setting/user',
         caption: '账号设置',
     },
+    fun: {
+        name: '功能设置',
+        display: true,
+        url: '/setting/fun',
+        caption: '功能设置',
+    },
     show: {
         name: '显示设置',
         display: true,

+ 5 - 1
sql/update.sql

@@ -10,4 +10,8 @@ CREATE TABLE `calculation`.`zh_rpt_archive` (
   `content` VARCHAR(4000) NULL,
   PRIMARY KEY (`archive_id`),
   INDEX `PRJ_STG` (`prj_id` ASC, `stage_id` ASC))
-COMMENT = '报表归档表;\n只考虑项目id及期id,其他信息全部归入content';
+COMMENT = '报表归档表;\n只考虑项目id及期id,其他信息全部归入content';
+
+-- 项目设置-功能设置
+ALTER TABLE `zh_project`
+ADD COLUMN `fun_rela`  varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '功能设置(json.stringify)' AFTER `rpt_nature`;