Bladeren bron

feat: 新增台账修订详细数据接口

MaiXinRong 2 weken geleden
bovenliggende
commit
ebfe171630
5 gewijzigde bestanden met toevoegingen van 451 en 0 verwijderingen
  1. 8 0
      app/controller/spss_controller.js
  2. 39 0
      app/controller/weapp_tender_controller.js
  3. 326 0
      app/lib/gcl_gather.js
  4. 2 0
      app/router.js
  5. 76 0
      app/view/spss/dev_test2.ejs

+ 8 - 0
app/controller/spss_controller.js

@@ -964,6 +964,14 @@ module.exports = app => {
                 ctx.ajaxErrorBody(err, '查询数据错误');
             }
         }
+
+        async test2(ctx) {
+            try {
+                await this.layout('spss/dev_test2.ejs');
+            } catch (err) {
+                ctx.helper.log(err);
+            }
+        }
     }
 
     return SpssController;

+ 39 - 0
app/controller/weapp_tender_controller.js

@@ -4,6 +4,7 @@ const measureType = require('../const/tender').measureType;
 const advanceConst = require('../const/advance');
 const status = require('../const/audit').advance.status;
 const shenpiConst = require('../const/shenpi');
+const stdConst = require('../const/standard');
 const _ = require('lodash');
 
 module.exports = app => {
@@ -207,6 +208,44 @@ module.exports = app => {
                 ctx.body = { code: -1, msg: error.toString(), data: null };
             }
         }
+
+        async reviseDetail(ctx) {
+            try {
+                const { rid } = ctx.query;
+                const revise = rid
+                    ? await ctx.service.ledgerRevise.getRevise(ctx.tender.id, rid)
+                    : ctx.service.ledgerRevise.getLastestRevise(ctx.tender.id);
+                revise.preHis = revise.pre_his_id ? await ctx.service.ledgerHistory.getDataById(revise.pre_his_id) : null;
+                revise.curHis = revise.his_id ? await ctx.service.ledgerHistory.getDataById(revise.his_id) : null;
+                await ctx.service.reviseAudit.loadReviseUser(revise);
+                await ctx.service.reviseAudit.loadReviseAuditViewData(revise);
+
+                const GclGather = require('../lib/gcl_gather');
+                const gclGatherModal = new GclGather.gclCompareGather(this.ctx);
+                const spec = {zlj: stdConst.zlj, jrg: stdConst.jrg};
+                spec.zlj.deal_bills_tp = ctx.tender.info.deal_param.zanLiePrice;
+                gclGatherModal.init(ctx.tender.info.chapter, spec);
+                const reviseBillsData = revise.readOnly && revise.curHis
+                    ? await ctx.helper.loadLedgerDataFromOss(revise.curHis.bills_file)
+                    : await ctx.service.reviseBills.getAllDataByCondition({ where: { tender_id: ctx.tender.id } });
+                const revisePosData = revise.readOnly && revise.curHis
+                    ? await this.ctx.helper.loadLedgerDataFromOss(revise.curHis.pos_file)
+                    : await ctx.service.revisePos.getAllDataByCondition({ where: { tid: ctx.tender.id } });
+                const price = await this.ctx.service.revisePrice.getAllDataByCondition({ where: { rid: revise.id } });
+                gclGatherModal.gatherReviseLedgerData(reviseBillsData, revisePosData, { prefix: 'new_' }, price, ctx.tender.info.decimal);
+                const billsData = revise.preHis ? await this.ctx.helper.loadLedgerDataFromOss(revise.preHis.bills_file) : [];
+                const posData = revise.preHis ? await this.ctx.helper.loadLedgerDataFromOss(revise.preHis.pos_file) : [];
+                gclGatherModal.gatherLedgerData(billsData, posData, { prefix: 'org_' });
+                revise.chapterList = gclGatherModal.chapterData();
+                revise.new_tp = gclGatherModal.otherChapter.hj.new_total_price || 0;
+                revise.org_tp = gclGatherModal.otherChapter.hj.org_total_price || 0;
+
+                ctx.body = { code: 0, msg: '', data: { revise } };
+            } catch(error) {
+                ctx.log(error);
+                ctx.body = { code: -1, msg: error.toString(), data: null };
+            }
+        }
     }
 
     return WeappTenderController;

+ 326 - 0
app/lib/gcl_gather.js

@@ -350,7 +350,333 @@ const gclGatherModel = class {
         return [this.gclList, this.leafXmjs];
     }
 };
+const gclCompareGatherModal = class {
+    /**
+     * 构造函数
+     *
+     * @param {Object} ctx - egg 全局变量
+     */
+    constructor(ctx) {
+        this.ctx = ctx;
+        this._ = ctx.helper._;
+        this.defaultSetting = {
+            tree: {
+                id: 'ledger_id',
+                pid: 'ledger_pid',
+                order: 'order',
+                level: 'level',
+                rootId: -1,
+                isLeaf: 'is_leaf',
+                keys: ['id', 'tender_id', 'ledger_id'],
+                stageId: 'id',
+            },
+            pos: { id: 'id', ledgerId: 'lid' },
+            billsFields: ['quantity', 'total_price'],
+            posFields: ['quantity'],
+            chapterFields: ['total_price'],
+        };
+        this.leafXmjs = [];
+        this.gsTree = null;
+        this.gsPos = null;
+    }
+
+    _getCalcChapter(chapter, option) {
+        this.gclChapter = [];
+        this.otherChapter = [];
+        this.gclChapterFilter = [];
+
+        let serialNo = 1;
+        for (const c of chapter) {
+            const cc = { code: c.code, name: c.name, cType: 1 };
+            cc.serialNo = serialNo++;
+            cc.filter = '^[^0-9]*([0-9]{0,2}-)?' + c.code.substr(0, c.code.length - 2) + '[0-9]{2}(-|$)';
+            this.gclChapter.push(cc);
+        }
+        this.gclChapter.push({ name: '未计入章节清单合计', cType: 21, serialNo: serialNo+1 });
+
+        this.otherChapter.hj = { name: '合计(C=A+B+Z)', cType: 41, serialNo: serialNo+5, deal_bills_tp: option.zlj.deal_bills_tp };
+        this.gclChapterFilter.push({node_type: option.jrg.value});
+        this.gclChapterFilter.push({field: 'name', part: option.jrg.text});
+        const zlChapter = {
+            name: '暂列金额(Z)', cType: 32, serialNo: serialNo+4,
+            deal_bills_tp: option.zlj.deal_bills_tp, match: [], matchPath: []
+        };
+        zlChapter.match.push({node_type: option.zlj.value});
+        zlChapter.match.push({field: 'name', part: option.zlj.text});
+        this.otherChapter.zlj = zlChapter;
+
+        this.otherChapter.qd = { name: '清单小计(A)', cType: 11, serialNo: serialNo+2 };
+        this.otherChapter.fqd = { name: '非清单项费用(B)', cType: 31, serialNo: serialNo+3 };
+    }
+    init (chapter, option) {
+        this.gclList = [];
+        this._getCalcChapter(chapter, option);
+    }
+
+    newGclNode(node) {
+        const gcl = {
+            b_code: node.b_code,
+            name: node.name,
+            unit: node.unit,
+            unit_price: node.unit_price,
+            leafXmjs: [],
+        };
+        this.gclList.push(gcl);
+        return gcl;
+    }
+    getGclNode(node) {
+        const gcl = this.gclList.find(function (g) {
+            return g.b_code === node.b_code &&
+                (g.name || node.name ? g.name === node.name : true) &&
+                (g.unit || node.unit ? g.unit === node.unit : true) &&
+                checkZero(this.ctx.helper.sub(g.unit_price, node.unit_price));
+        });
+        if (gcl) {
+            return gcl
+        } else {
+            return this.newGclNode(node);
+        }
+    }
+    gatherfields(obj, src, fields, prefix = '') {
+        if (obj && src) {
+            for (const f of fields) {
+                obj[prefix + f] = this.ctx.helper.add(obj[prefix + f], src[f]);
+            }
+        }
+    }
+    CheckPeg(text) {
+        const pegReg = /[a-zA-Z]*[kK][0-9]+[++][0-9]{3}([.][0-9]+)?/;
+        return pegReg.test(text);
+    }
+    getPegNode (node) {
+        if (node) {
+            if (this.CheckPeg(node.name)) {
+                return node;
+            } else {
+                const parent = this.gsTree.getParent(node);
+                return parent ? this.getPegNode(parent) : null;
+            }
+        }
+    }
+    getPegNode (node) {
+        if (node) {
+            if (this.CheckPeg(node.name)) {
+                return node;
+            } else {
+                const parent = this.gsTree.getParent(node);
+                return parent ? this.getPegNode(parent) : null;
+            }
+        }
+    }
+    getNodeByLevel(node, level) {
+        let cur = node;
+        while (cur && cur.level > level) {
+            cur = this.gsTree.getParent(cur);
+        }
+        return cur;
+    }
+    getDwgc(peg, xmj) {
+        if (peg) {
+            return peg.name;
+        } else {
+            const node = this.getNodeByLevel(xmj, 2);
+            return node ? node.name : '';
+        }
+    }
+    getFbgc(peg, xmj) {
+        if (peg && peg.id !== xmj.id) {
+            const node = this.getNodeByLevel(xmj, peg.level + 1);
+            return node ? node.name : '';
+        } else {
+            const node = this.getNodeByLevel(xmj, 3);
+            return node ? node.name : '';
+        }
+    }
+    getFxgc(peg, xmj) {
+        if (!peg) {
+            const node = this.getNodeByLevel(xmj, 4);
+            return node ? node.name : '';
+        } else if (peg.id === xmj.id) {
+            if (xmj.level > 4) {
+                let value = '';
+                for (let level = 4; level < xmj.level; level++) {
+                    const node = this.getNodeByLevel(xmj, level);
+                    value = value === '' ? node.name : value + mergeChar + node.name;
+                }
+                return value;
+            } else {
+                return '';
+            }
+        } else {
+            if (peg.level + 2 < xmj.level) {
+                let value = '';
+                for (let level = peg.level + 2; level < xmj.level; level++) {
+                    const node = this.getNodeByLevel(xmj, level);
+                    value = value === '' ? node.name : value + mergeChar + node.name;
+                }
+                return value;
+            } else {
+                return '';
+            }
+        }
+    }
+    newCacheLeafXmj(leafXmj) {
+        const peg = this.getPegNode(leafXmj);
+        const cacheLX = {
+            id: leafXmj.id,
+            code: leafXmj.code,
+            jldy: leafXmj.name,
+            fbgc: this.getFbgc(peg, leafXmj),
+            fxgc: this.getFxgc(peg, leafXmj),
+            dwgc: this.getDwgc(peg, leafXmj),
+            drawing_code: leafXmj.drawing_code,
+        };
+        this.leafXmjs.push(cacheLX);
+        return cacheLX;
+    }
+    getCacheLeafXmj(leafXmj) {
+        const cacheLX = this.leafXmjs.find(function (lx) {
+            return lx.id === leafXmj.id;
+        });
+        if (!cacheLX) {
+            return this.newCacheLeafXmj(leafXmj);
+        } else {
+            return cacheLX;
+        }
+    }
+    loadGatherGclNode(node, leafXmj, gsPos) {
+        const gcl = this.getGclNode(node);
+        this.gatherfields(gcl, node, this.ledgerSetting.billsFields, this.ledgerSetting.prefix);
+        const cacheLeafXmj = this.getCacheLeafXmj(leafXmj);
+        const posRange = gsPos.getLedgerPos(node.id);
+        const detail = posRange && posRange.length > 0 ? posRange : [node];
+        for (const d of detail) {
+            const lx = gcl.leafXmjs.find(x => {return x.id === leafXmj.id && (x.mx_id === d.id || x.gcl_id === d.id)});
+            if (lx) {
+                this.gatherfields(lx, d, this.ledgerSetting.posFields, this.ledgerSetting.prefix);
+            } else {
+                const dx = this._.assign({}, cacheLeafXmj);
+                this.gatherfields(dx, d, this.ledgerSetting.posFields, this.ledgerSetting.prefix);
+                dx.gcl_id = node.id;
+                if (d.name !== node.name) {
+                    dx.bwmx = d.name;
+                    dx.mx_id = d.id;
+                }
+                if (d.drawing_code) {
+                    dx.drawing_code = d.drawing_code;
+                }
+                gcl.leafXmjs.push(dx);
+            }
+        }
+    }
+    recursiveGatherGclData(nodes, leafXmj, gsPos) {
+        for (const node of nodes) {
+            if (node.b_code) {
+                if (node.children.length > 0) {
+                    this.recursiveGatherGclData(node.children, leafXmj, gsPos);
+                } else {
+                    this.loadGatherGclNode(node, leafXmj, gsPos);
+                }
+            } else if (node.children.length > 0) {
+                this.recursiveGatherGclData(node.children, node, gsPos);
+            }
+        }
+    }
+
+    _getGclChapter(chapter, data) {
+        for (const c of chapter) {
+            if (c.filter) {
+                const reg = new RegExp(c.filter);
+                if (reg.test(data.b_code)) {
+                    return c;
+                }
+            } else {
+                return c;
+            }
+        }
+    }
+    _checkFilter(d, filter) {
+        for (const f of filter) {
+            if (f.node_type && f.node_type === d.node_type) return true;
+            if (f.field) {
+                if (f.part && d[f.field] && d[f.field].indexOf(f.part) >= 0) return true;
+                if (f.all && d[f.all] && d[f.all] === f.all) return true;
+            }
+        }
+        return false;
+    }
+    _gatherChapter() {
+        const chapterFilterPath = [];
+        const checkFilterPath = function (data, filterPath) {
+            for (const fp of filterPath) {
+                if (data.full_path.indexOf(fp + '-') === 0 || data.full_path === fp) return true;
+            }
+            return false;
+        };
+
+        for (const d of this.gsTree.nodes) {
+            if (this._checkFilter(d, this.gclChapterFilter)) chapterFilterPath.push(d.full_path);
+            if (this._checkFilter(d, this.otherChapter.zlj.match)) this.otherChapter.zlj.matchPath.push(d.full_path);
+            if (d.children && d.children.length > 0) continue;
+
+            if (checkFilterPath(d, this.otherChapter.zlj.matchPath)) {
+                this.gatherfields(this.otherChapter.zlj, d, this.ledgerSetting.chapterFields, this.ledgerSetting.prefix);
+                this.gatherfields(this.otherChapter.hj, d, this.ledgerSetting.chapterFields, this.ledgerSetting.prefix);
+            } else {
+                this.gatherfields(this.otherChapter.hj, d, this.ledgerSetting.chapterFields, this.ledgerSetting.prefix);
+                if (d.b_code) {
+                    this.gatherfields(this.otherChapter.qd, d, this.ledgerSetting.chapterFields, this.ledgerSetting.prefix);
+                }
+                if (!d.b_code || d.b_code === '') {
+                    this.gatherfields(this.otherChapter.fqd, d, this.ledgerSetting.chapterFields, this.ledgerSetting.prefix);
+                }
+
+                if (d.b_code) {
+                    const c = checkFilterPath(d, chapterFilterPath)
+                        ? this.gclChapter.find(x => { return x.cType === 21})
+                        : this._getGclChapter(this.gclChapter, d);
+                    this.gatherfields(c, d, this.ledgerSetting.chapterFields, this.ledgerSetting.prefix);
+                }
+            }
+        }
+    }
+    gatherLedgerData (bills, pos, setting) {
+        this.ledgerSetting = this._.assign(setting, this.defaultSetting);
+        try {
+            if (this.leafXmjs.length > 0) this.leafXmjs.length = 0;
+            this.gsTree = new Ledger.billsTree(this.ctx, this.ledgerSetting.tree);
+            this.gsTree.loadDatas(bills);
+            this.gsPos = new Ledger.pos(this.ledgerSetting.pos);
+            this.gsPos.loadDatas(pos);
+            this.recursiveGatherGclData(this.gsTree.children, null, this.gsPos);
+            this._gatherChapter();
+        } catch(err) {
+            this.ctx.log(err);
+        }
+        this.ledgerSetting = null;
+    }
+    gatherReviseLedgerData(bills, pos, setting, price, decimal) {
+        this.ledgerSetting = this._.assign(setting, this.defaultSetting);
+        try {
+            if (this.leafXmjs.length > 0) this.leafXmjs.length = 0;
+            this.gsTree = new Ledger.reviseTree(this.ctx, this.ledgerSetting.tree);
+            this.gsTree.loadRevisePrice(price, decimal);
+            this.gsTree.loadDatas(bills);
+            this.gsPos = new Ledger.pos(this.ledgerSetting.pos);
+            this.gsPos.loadDatas(pos);
+            this.recursiveGatherGclData(this.gsTree.children, null, this.gsPos);
+            this._gatherChapter();
+        } catch(err) {
+            this.ctx.log(err);
+        }
+        this.ledgerSetting = null;
+    }
+    chapterData () {
+        return this.gclChapter.concat([this.otherChapter.qd, this.otherChapter.fqd, this.otherChapter.zlj, this.otherChapter.hj]);
+    }
+};
 
 module.exports = {
     gclGather: gclGatherModel,
+    gclCompareGather: gclCompareGatherModal,
 };

+ 2 - 0
app/router.js

@@ -316,6 +316,7 @@ module.exports = app => {
     if (app.config.env === 'qa' || app.config.env === 'local') {
         app.get('/sp/:id/devTest', sessionAuth, projectManagerCheck, subProjectCheck, 'spssController.test');
         app.post('/sp/:id/devTest/load', sessionAuth, projectManagerCheck, subProjectCheck, 'spssController.testLoad');
+        app.get('/sp/:id/devTest2', sessionAuth, projectManagerCheck, subProjectCheck, 'spssController.test2');
     }
 
     // **标段合同管理 todo 接入项目内部
@@ -1252,4 +1253,5 @@ module.exports = app => {
     app.get('/wx/weapp/tender/list/manage', weappAuth, 'weappTenderController.listManage');
     app.get('/wx/weapp/advance/list', weappAuth, weappTenderCheck, 'weappTenderController.advanceList');
     app.get('/wx/weapp/advance/detail', weappAuth, weappTenderCheck, 'weappTenderController.advanceDetail');
+    app.get('/wx/weapp/revise/detail', weappAuth, weappTenderCheck, 'weappTenderController.reviseDetail');
 };

+ 76 - 0
app/view/spss/dev_test2.ejs

@@ -0,0 +1,76 @@
+<div class="panel-content">
+    <div class="panel-title">
+        <div class="title-main d-flex">
+            <div class="title-main d-flex justify-content-between">
+                测试用模块
+            </div>
+        </div>
+    </div>
+    <div class="content-wrap">
+        <div class="c-body">
+            <div class="row mt-2 ml-2">
+                <div class="col-5">
+                    <div class="form-group">
+                        <h6>测试App-api</h6>
+                        <div class="card p-2">
+                            <div class="mt-1 d-flex">
+                                <div class="form-group form-inline">
+                                    <label for="inputPassword2" class="mr-1">请求方式:</label>
+                                    <select class="form-control form-control-sm" id="apiType"><option value="GET">GET</option><option value="POST">POST</option></select>
+                                </div>
+                                <div class="ml-auto">
+                                    <button class="btn btn-sm btn-primary" id="st-rpt-check">查询</button>
+                                </div>
+                            </div>
+                            <div class="mt-1">
+                                <div class="input-group input-group-sm">
+                                    <div class="input-group-prepend">
+                                        <span class="input-group-text">url</span>
+                                    </div>
+                                    <input class="form-control m-0" id="st-url">
+                                </div>
+                            </div>
+                            <div class="mt-1">
+                                <div class="d-flex">
+                                    <span>传参<span class="text-danger">JSON</span>:</span>
+                                </div>
+                                <textarea class="form-control form-control-sm mt-1" rows="6" id="st-query"></textarea>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+<script>
+    const testApi = function(type, url, data, dataType) {
+        $.ajax({
+            type,
+            url,
+            data,
+            dataType,
+            cache: false,
+            timeout: postDefaultTime,
+            beforeSend: function(xhr) {
+                let csrfToken = Cookies.get('csrfToken_j');
+                xhr.setRequestHeader('x-csrf-token', csrfToken);
+            },
+            success: function(result){
+                console.log(result);
+            },
+            error: function(jqXHR, textStatus, errorThrown){
+                toastr.error('error: ' + textStatus + " " + errorThrown);
+                if (errorCallBack) {
+                    errorCallBack();
+                }
+                if (showWaiting) closeWaitingView();
+            }
+        });
+    }
+    $('#st-rpt-check').click(function() {
+        const url = $('#st-url').val();
+        const type = $('#apiType').val();
+        testApi(type, url);
+    });
+</script>