Browse Source

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

Tony Kang 3 năm trước cách đây
mục cha
commit
ce5924a087

+ 33 - 1
app/controller/dashboard_controller.js

@@ -11,6 +11,7 @@
 const auditConst = require('../const/audit');
 const officeList = require('../const/cld_office').list;
 const maintainConst = require('../const/maintain');
+const typeColMap = require('../const/advance').typeColMap;
 
 module.exports = app => {
 
@@ -45,9 +46,36 @@ module.exports = app => {
             const userPermission = pa !== undefined && pa.permission !== '' ? JSON.parse(pa.permission) : null;
             const userMsgPermission = userPermission !== null && userPermission.project_msg !== undefined && parseInt(userPermission.project_msg) === 1;
             // 获取系统通知
-            const sysMsgList = await ctx.service.message.getMsgList(ctx.session.sessionProject.id, 2, 0, 2);
+            const sysMsgList = await ctx.service.message.getMsgList(ctx.session.sessionProject.id, 1, 0, 2);
             // 获取系统维护信息
             const maintainData = await ctx.service.maintain.getDataById(1);
+            // 获取各个审批的次数及最后的审批时间
+            const shenpi_count = [
+                { count: await ctx.service.advanceAudit.getCountByChecked(ctx.session.sessionUser.accountId), name: '预付款' },
+                { count: await ctx.service.ledgerAudit.getCountByChecked(ctx.session.sessionUser.accountId), name: '台账审批' },
+                { count: await ctx.service.reviseAudit.getCountByChecked(ctx.session.sessionUser.accountId), name: '台账修订' },
+                { count: await ctx.service.stageAudit.getCountByChecked(ctx.session.sessionUser.accountId), name: '计量审批' },
+                { count: await ctx.service.changeAudit.getCountByChecked(ctx.session.sessionUser.accountId), name: '变更审批' },
+            ];
+            if (ctx.session.sessionProject.page_show.openChangeProject) shenpi_count.push({ count: await ctx.service.changeProjectAudit.getCountByChecked(ctx.session.sessionUser.accountId), name: '变更立项' });
+            if (ctx.session.sessionProject.page_show.openChangeApply) shenpi_count.push({ count: await ctx.service.changeApplyAudit.getCountByChecked(ctx.session.sessionUser.accountId), name: '变更申请' });
+            if (ctx.session.sessionProject.page_show.openChangePlan) shenpi_count.push({ count: await ctx.service.changePlanAudit.getCountByChecked(ctx.session.sessionUser.accountId), name: '变更方案' });
+            shenpi_count.push({ count: await ctx.service.materialAudit.getCountByChecked(ctx.session.sessionUser.accountId), name: '材料调差' });
+            // shenpi_count.push({ count: await ctx.service.advanceAudit.getCountByChecked(ctx.session.sessionUser.accountId), name: '预付款' });
+            const total_count = ctx.app._.sumBy(shenpi_count, 'count');
+            const shenpi_lastime = [
+                await ctx.service.advanceAudit.getLastEndTimeByChecked(ctx.session.sessionUser.accountId),
+                await ctx.service.ledgerAudit.getLastEndTimeByChecked(ctx.session.sessionUser.accountId),
+                await ctx.service.reviseAudit.getLastEndTimeByChecked(ctx.session.sessionUser.accountId),
+                await ctx.service.stageAudit.getLastEndTimeByChecked(ctx.session.sessionUser.accountId),
+                await ctx.service.changeAudit.getLastEndTimeByChecked(ctx.session.sessionUser.accountId),
+                ctx.session.sessionProject.page_show.openChangeProject ? await ctx.service.changeProjectAudit.getLastEndTimeByChecked(ctx.session.sessionUser.accountId) : null,
+                ctx.session.sessionProject.page_show.openChangeApply ? await ctx.service.changeApplyAudit.getLastEndTimeByChecked(ctx.session.sessionUser.accountId) : null,
+                ctx.session.sessionProject.page_show.openChangePlan ? await ctx.service.changePlanAudit.getLastEndTimeByChecked(ctx.session.sessionUser.accountId) : null,
+                await ctx.service.materialAudit.getLastEndTimeByChecked(ctx.session.sessionUser.accountId),
+            ];
+            const last_time = ctx.app._.max(shenpi_lastime);
+            console.log(ctx.app._.max(shenpi_lastime), ctx.helper.calcDayNum(last_time));
             const renderData = {
                 auditTenders,
                 auditStages,
@@ -58,6 +86,9 @@ module.exports = app => {
                 auditChangeProject,
                 auditChangeApply,
                 auditChangePlan,
+                shenpi_count,
+                total_count,
+                last_day: ctx.helper.calcDayNum(last_time),
                 role: pa.role,
                 authMobile: pa.auth_mobile,
                 acLedger: auditConst.ledger,
@@ -81,6 +112,7 @@ module.exports = app => {
                 uid: ctx.session.sessionUser.accountId,
                 maintainData,
                 maintainConst,
+                typeColMap,
             };
             await this.layout('dashboard/index.ejs', renderData, 'dashboard/modal.ejs');
             await ctx.service.projectAccount.defaultUpdate({

+ 1 - 1
app/controller/material_controller.js

@@ -723,7 +723,7 @@ module.exports = app => {
                     msg: '',
                     data: {},
                 };
-                if (ctx.session.sessionProject.page_show.openMaterialChecklist && ctx.app._.findIndex(['join', 'notjoin', 'self', 'noself', 'useOther'], data.type) === -1) {
+                if (ctx.session.sessionProject.page_show.openMaterialChecklist && ctx.app._.indexOf(['join', 'notjoin', 'self', 'noself', 'useOther'], data.type) === -1) {
                     throw '清单设置功能已启动,请前往清单设置页操作清单内容';
                 }
                 switch (data.type) {

+ 4 - 0
app/extend/context.js

@@ -76,4 +76,8 @@ module.exports = {
         return this.app.hisOss;
     },
 
+    saveTempFile(filename, text) {
+        const filepath = path.join(this.app.config.logger.dir, this.app.config.version, filename);
+        this.helper.saveBufferFile(text, filepath);
+    }
 };

+ 6 - 0
app/extend/helper.js

@@ -969,6 +969,12 @@ module.exports = {
         return moment(time).format('YYYY-MM-DD HH:mm:ss');
     },
 
+    calcDayNum(startTime, endTime = '') {
+        const dateStart = new Date(startTime);
+        const dateEnd = endTime ? new Date(endTime) : new Date();
+        return parseInt((dateEnd.getTime() - dateStart.getTime()) / (1000 * 60 * 60 * 24));
+    },
+
     // 预付款详情页时间线所需格式
     formatDate(date) {
         if (!date) return '';

+ 17 - 0
app/lib/gcl_gather.js

@@ -334,6 +334,23 @@ const gclGatherModel = class {
         this.convertResultData();
         return [this.gclList, this.leafXmjs];
     }
+    gatherObj(bills, pos, deal) {
+        const helper = this.ctx.helper;
+        this.billsTree = bills;
+        this.pos = pos;
+
+        this.gclList = [];
+        this.leafXmjs = [];
+
+        this.recursiveGatherGclData(this.billsTree.children, null);
+        this.gatherDealBillsData(deal);
+        this.gclList.sort(function (a, b) {
+            return helper.compareCode(a.b_code, b.b_code);
+        });
+
+        this.convertResultData();
+        return [this.gclList, this.leafXmjs];
+    }
 };
 
 module.exports = {

+ 296 - 0
app/lib/rm/material.js

@@ -0,0 +1,296 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Mai
+ * @date
+ * @version
+ */
+
+const materialConst = require('../../const/material');
+
+const Ledger = require('../../lib/ledger');
+
+const billsFields = (function () {
+    const cur = ['contract_qty', 'contract_tp', 'contract_expr', 'qc_qty', 'qc_tp', 'gather_qty', 'gather_tp', 'postil'];
+    const pre = ['pre_contract_qty', 'pre_contract_tp', 'pre_qc_qty', 'pre_qc_tp', 'pre_gather_qty', 'pre_gather_tp'];
+    const end = ['end_contract_qty', 'end_contract_tp', 'end_qc_qty', 'end_qc_tp', 'end_gather_qty', 'end_gather_tp'];
+    const final = ['final_tp', 'final_ratio'];
+    const stageDgn = ['deal_dgn_qty1', 'deal_dgn_qty2', 'c_dgn_qty1', 'c_dgn_qty2'];
+
+    const stage = cur.concat(pre, end, final);
+    const stageEnd = pre.concat(end, final);
+    const bgl = ['qc_bgl_code'];
+    const leafXmj = ['leaf_xmj_id'];
+
+    return {cur, pre, end, final, stageDgn, stage, stageEnd, bgl, leafXmj};
+})();
+const posFields = (function () {
+    const cur = ['contract_qty', 'qc_qty', 'gather_qty', 'postil'];
+    const pre = ['pre_contract_qty', 'pre_qc_qty', 'pre_gather_qty'];
+    const end = ['end_contract_qty', 'end_qc_qty', 'end_gather_qty'];
+    const final = ['final_ratio'];
+
+    const stage = cur.concat(pre, end, final);
+    const stageEnd = pre.concat(end, final);
+    const bgl = ['qc_bgl_code'];
+
+    return {cur, pre, end, final, stage, stageEnd, bgl};
+})();
+
+class ReportMemoryMaterial {
+    constructor(ctx) {
+        this.ctx = ctx;
+    }
+
+    _getNewPos(updateFields) {
+        const helper = this.ctx.helper;
+        return new Ledger.pos({
+            id: 'id', ledgerId: 'lid',
+            updateFields: ['contract_qty', 'qc_qty', 'postil'],
+            calc: function (p) {
+                p.pre_gather_qty = helper.add(p.pre_contract_qty, p.pre_qc_qty);
+                p.gather_qty = helper.add(p.contract_qty, p.qc_qty);
+                p.end_contract_qty = helper.add(p.pre_contract_qty, p.contract_qty);
+                p.end_qc_qty = helper.add(p.pre_qc_qty, p.qc_qty);
+                p.end_gather_qty = helper.add(p.pre_gather_qty, p.gather_qty);
+            }
+        });
+    }
+
+    _getNewBillsTree(calcFields) {
+        return new Ledger.billsTree(this.ctx, {
+            id: 'ledger_id',
+            pid: 'ledger_pid',
+            order: 'order',
+            level: 'level',
+            rootId: -1,
+            keys: ['id', 'tender_id', 'ledger_id'],
+            stageId: 'id',
+            calcFields: calcFields || ['deal_tp', 'total_price', 'contract_tp', 'qc_tp', 'gather_tp', 'pre_contract_tp', 'pre_qc_tp', 'pre_gather_tp'],
+            calc: function (node, helper) {
+                if (node.children && node.children.length === 0) {
+                    node.pre_gather_qty = helper.add(node.pre_contract_qty, node.pre_qc_qty);
+                    node.gather_qty = helper.add(node.contract_qty, node.qc_qty);
+                    node.end_contract_qty = helper.add(node.pre_contract_qty, node.contract_qty);
+                    node.end_qc_qty = helper.add(node.pre_qc_qty, node.qc_qty);
+                    node.end_gather_qty = helper.add(node.pre_gather_qty, node.gather_qty);
+                }
+                node.pre_gather_tp = helper.add(node.pre_contract_tp, node.pre_qc_tp);
+                node.gather_tp = helper.add(node.contract_tp, node.qc_tp);
+                node.end_contract_tp = helper.add(node.pre_contract_tp, node.contract_tp);
+                node.end_qc_tp = helper.add(node.pre_qc_tp, node.qc_tp);
+                node.end_gather_tp = helper.add(node.pre_gather_tp, node.gather_tp);
+
+                node.final_tp = helper.add(node.total_price, node.end_qc_tp);
+                node.final_ratio = helper.mul(helper.div(node.end_gather_tp, node.final_tp, 4), 100);
+            }
+        });
+    }
+
+    _checkFieldsExist(source, check) {
+        for (const s of source) {
+            if (check.indexOf(s) >= 0) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    async getSelectMaterialAuditors(tid, material_order, fields) {
+        await this.ctx.service.material.checkMaterial(tid, material_order);
+        const auditors = await this.ctx.service.materialAudit.getFinalAuditGroup(this.ctx.material.id, this.ctx.material.curTimes);
+        const user = await this.ctx.service.projectAccount.getDataById(this.ctx.material.user_id);
+        const result = [{
+            aid: user.id,
+            name: user.name,
+            company: user.company,
+            role: user.role,
+            mobile: user.mobile,
+            telephone: user.telephone,
+            sign_path: user.sign_path,
+            opinion: user.opinion,
+            end_time: auditors && auditors.length > 0 ? auditors[0].begin_time : null,
+            sort: 0,
+        }, ...auditors];
+        return result;
+    }
+
+    async getMaterial(tender_id, material_order, fields) {
+        const result = await this.ctx.service.material.getValidMaterials(tender_id);
+        if (this._checkFieldsExist(fields, ['checked_time'])) {
+            for (const r of result) {
+                const auditors = await this.ctx.service.materialAudit.getFinalAuditGroup(r.id, r.curTimes || r.times);
+                r.checked_time = !r.curTimes ? auditors[auditors.length - 1].end_time : null;
+            }
+        }
+        return result;
+    }
+
+    _completeMaterialGl(materialGl) {
+        const tTypeStr = [], mTypeStr = [];
+        for (const t of materialConst.t_type) {
+            tTypeStr[t.value] = t.text;
+        }
+        for (const m of materialConst.m_type) {
+            mTypeStr[m.value] = m.text;
+        }
+        for (const gl of materialGl) {
+            gl.tp = this.ctx.helper.mul(gl.quantity, gl.m_spread, 2);
+            gl.t_type_str = tTypeStr[gl.t_type];
+            gl.m_type_str = mTypeStr[gl.m_type];
+            gl.end_tp = this.ctx.helper.add(gl.tp, gl.pre_tp);
+        }
+    }
+
+    async getMaterialGl(tender_id, material_order, fields) {
+        const materials = await this.ctx.service.material.getAllDataByCondition({
+            where: {tid: tender_id},
+            orders: [['order', 'desc']],
+        });
+        if (materials.length > 0) {
+            let result;
+            if (materials[0].order === material_order) {
+                result = await this.ctx.service.materialBills.getAllDataByCondition({
+                    where: {tid: tender_id}
+                });
+            } else {
+                const material = this.ctx.helper._.find(materials, {order: material_order});
+                if (!material) return [];
+
+                const sql = 'SELECT mb.id, mb.tid, mb.mid, mb.order, mb.order, mb.t_type, mb.code, mb.name, mb.unit, mb.spec, mb.m_type,' +
+                    '    mbh.quantity, mbh.expr,' +
+                    '    mb.basic_price, mb.basic_times, ' +
+                    '    mbh.msg_tp, mbh.msg_times, mbh.msg_spread, mbh.m_up_risk, mbh.m_down_risk, mbh.m_spread, mbh.m_tp, mbh.pre_tp, mbh.m_tax_tp, mbh.tax_pre_tp, mbh.origin, ' +
+                    '    mb.remark, mb.is_summary, mbh.m_tax, mb.in_time' +
+                    '  FROM ' + this.ctx.service.materialBillsHistory.tableName + ' mbh ' +
+                    '  LEFT JOIN ' + this.ctx.service.materialBills.tableName + ' mb ON mbh.mb_id = mb.id ' +
+                    '  WHERE mbh.tid = ? And mbh.mid = ?';
+                result = await this.ctx.app.mysql.query(sql, [tender_id, material.id]);
+            }
+            this._completeMaterialGl(result);
+            return result;
+        } else {
+            return [];
+        }
+    }
+
+    async getMaterialGlDetail(tender_id, material_order, fields) {
+        const material = await this.ctx.service.material.getDataByCondition({tid: tender_id, order: material_order});
+        return material ? await this.ctx.service.materialList.getMaterialData(tender_id, material.id) : [];
+    }
+
+    async getMaterialBills(tender_id, material_order, fields) {
+        const material = await this.ctx.service.material.getDataByCondition({tid: tender_id, order: material_order});
+        try {
+            const billsData = await this.ctx.service.ledger.getData(tender_id);
+            if (this._checkFieldsExist(fields, billsFields.stage)) {
+                const curStage = await this.ctx.service.stageBills.getStagesData(tender_id, material.stage_id);
+                this.ctx.helper.assignRelaData(billsData, [
+                    {data: curStage, fields: ['contract_qty', 'contract_tp', 'contract_expr', 'qc_qty', 'qc_tp', 'postil'], prefix: '', relaId: 'lid'}
+                ]);
+            }
+
+            const billsTree = this._getNewBillsTree();
+            billsTree.loadDatas(billsData);
+            billsTree.calculateAll();
+
+            return billsTree.getDatas([
+                'id', 'tender_id', 'ledger_id', 'ledger_pid', 'level', 'order', 'full_path', 'is_leaf',
+                'code', 'b_code', 'name', 'unit', 'unit_price',
+                'deal_qty', 'deal_tp',
+                'sgfh_qty', 'sgfh_tp', 'sjcl_qty', 'sjcl_tp', 'qtcl_qty', 'qtcl_tp', 'quantity', 'total_price',
+                'dgn_qty1', 'dgn_qty2',
+                'drawing_code', 'memo', 'node_type', 'is_tp',
+                'contract_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'gather_qty', 'gather_tp', 'postil',
+                'sgfh_expr', 'sjcl_expr', 'qtcl_expr', 'contract_expr',
+            ]);
+        } catch(err) {
+            this.ctx.helper.log(err);
+            return [];
+        }
+    }
+
+    async getMaterialPos(tender_id, material_order, fields) {
+        const material = await this.ctx.service.material.getDataByCondition({tid: tender_id, order: material_order});
+        try {
+            const posData = await this.ctx.service.pos.getAllDataByCondition({ where: {tid: tender_id }});
+            if (this._checkFieldsExist(fields, posFields.stage)) {
+                const curPosStage = await this.ctx.service.stagePos.getStagesData(tender_id, material.stage_id);
+                this.ctx.helper.assignRelaData(posData, [
+                    {data: curPosStage, fields: ['contract_qty', 'qc_qty', 'contract_expr', 'postil'], prefix: '', relaId: 'pid'}
+                ]);
+            }
+            const pos = this._getNewPos();
+            pos.loadDatas(posData);
+            pos.calculateAll();
+
+            return pos.getDatas();
+        } catch (err) {
+            this.ctx.helper.log(err);
+            return [];
+        }
+    }
+
+    async getMaterialGatherBills(tender_id, material_order) {
+        const materials = await this.ctx.service.material.getAllDataByCondition({
+            where: { tid: tender_id },
+            orders: [['order', 'desc']],
+        });
+        if (materials.length === 0) return {};
+
+        const material = await this.ctx.service.material.getDataByCondition({ tid: tender_id, order: material_order });
+        const decimal = material.decimal ? JSON.parse(material.decimal) : materialConst.decimal;
+        try {
+
+            const billsData = await this.ctx.service.ledger.getData(tender_id);
+            const billsTree = this._getNewBillsTree();
+            billsTree.loadDatas(billsData);
+            billsTree.calculateAll();
+
+            const posData = await this.ctx.service.pos.getPosData({ tid: tender_id });
+            const curStage = await this.ctx.service.stagePos.getStagesData(tender_id, material.stage_id);
+            this.ctx.helper.assignRelaData(posData, [
+                { data: curStage, fields: ['contract_qty', 'contract_tp', 'contract_expr', 'qc_qty', 'qc_tp', 'postil'], prefix: '', relaId: 'pid' },
+            ]);
+            const pos = this._getNewPos();
+            pos.loadDatas(posData);
+            pos.calculateAll();
+
+            const gclGatherModel = require('../gcl_gather').gclGather;
+            const gatherUtil = new gclGatherModel(this.ctx);
+            gatherUtil.gatherObj(billsTree, pos);
+            const materialGl = material_order === materials[0].order
+                ? await this.ctx.service.materialList.getMaterialData(tender_id, material.id)
+                : await this.ctx.service.materialList.getPreMaterialData(tender_id, material.id);
+            const materialNotJoin = await this.ctx.service.materialListNotjoin.getAllDataByCondition({ where: { mid: material.id } });
+
+            const helper = this.ctx.helper;
+            for (const g of gatherUtil.gclList) {
+                g.jiacha = 0;
+                for (const x of g.leafXmjs) {
+                    x.jiacha = 0;
+                    const mnj = materialNotJoin.find(m => {
+                        return m.gcl_id === x.org_gcl_id && m.xmj_id === x.id && (x.mx_id ? x.mx_id === m.mx_id : true);
+                    });
+                    if (mnj) continue;
+                    const list = materialGl.filter(g => {
+                        return g.gcl_id === x.org_gcl_id && g.xmj_id === x.id && (x.mx_id ? x.mx_id === g.mx_id : true);
+                    });
+                    for (const l of list) {
+                        x.jiacha = helper.add(x.jiacha, helper.mul(helper.mul(x.gather_qty, l.quantity), l.m_spread));
+                    }
+                    x.jiacha = helper.round(x.jiacha, decimal.tp);
+                    g.jiacha = helper.add(g.jiacha, x.jiacha);
+                }
+            }
+            return { mem_material_gather_bills: gatherUtil.gclList, mem_material_gather_xmj: gatherUtil.leafXmjs, mem_material_gather_gl: materialGl };
+        } catch (err) {
+            this.ctx.log(err);
+            return {};
+        }
+    }
+}
+
+module.exports = ReportMemoryMaterial;

BIN
app/public/css/about.png


BIN
app/public/css/bg_participate_blue.png


BIN
app/public/css/bg_participate_orange.png


+ 52 - 28
app/public/css/main.css

@@ -87,7 +87,7 @@ font-size: .875rem;
 }
 .custom-control-warning-input:checked ~ .custom-control-warning-label::before{
   border-color:#da9500 ;
-  background-color:#da9500 
+  background-color:#da9500
 }
 .custom-control-warning-label{
   color:#da9500;
@@ -195,23 +195,23 @@ input.nospin[type="number"]{-moz-appearance:textfield;}
 /*滚动条*/
 /* 滚动条 */
 /*水平滚动条的样式*/
-/*::-webkit-scrollbar-thumb:horizontal { 
+/*::-webkit-scrollbar-thumb:horizontal {
 	width: 5px;
 	background-color: #e9ecef;
 	-webkit-border-radius: 0;
 }*/
 /*滚动条的背景颜色,滚动条的圆角宽度*/
 /*::-webkit-scrollbar-track-piece {
-	background-color: #efefef; 
-	-webkit-border-radius: 0; 
+	background-color: #efefef;
+	-webkit-border-radius: 0;
 }*/
 /*滚动条的宽度,滚动条的高度*/
 /*::-webkit-scrollbar {
-	width: 14px; 
-	height: 14px; 
+	width: 14px;
+	height: 14px;
 }*/
 /*垂直滚动条的样式*/
-/*::-webkit-scrollbar-thumb:vertical { 
+/*::-webkit-scrollbar-thumb:vertical {
 	height: 50px;
 	background-color: #e9ecef;
 	-webkit-border-radius: 0;
@@ -220,7 +220,7 @@ input.nospin[type="number"]{-moz-appearance:textfield;}
 	border: 1px solid #ced4da;
 }*/
 /*滚动条的hover样式*/
-/*::-webkit-scrollbar-thumb:hover { 
+/*::-webkit-scrollbar-thumb:hover {
 	height: 50px;
 	background-color: #ced4da;
 	-webkit-border-radius: 0;
@@ -870,7 +870,7 @@ input.nospin[type="number"]{-moz-appearance:textfield;}
   font-size: 14px
 }
 .bd-toc {
-  
+
     position: sticky;
     top:3rem;
     height: calc(100vh - 10rem);
@@ -1028,7 +1028,7 @@ body{
   line-height: 30px;
 }
 .panel-title > .title-main .btn.pull-right {
-    margin: 5px 0 0 0 
+    margin: 5px 0 0 0
 }
 .panel-content{
   padding-top:35px;
@@ -1246,7 +1246,7 @@ a.maintain-icon .fa{
     }
 }
 
-a.maintain-icon:hover .fa{ 
+a.maintain-icon:hover .fa{
     animation-iteration-count:0
 }
 /*审批列表*/
@@ -1369,10 +1369,10 @@ overflow-y: auto;
   position: relative;
 }
 .circle{
-  width: 62px; 
+  width: 62px;
   height: 62px;
   border-radius: 50%;
-  background: none; 
+  background: none;
   border: 4px solid #D7B014;
 }
 .circle-num{
@@ -1822,36 +1822,60 @@ overflow-y: auto;
   width: 70px;
   text-align: center;
 }
-.bg-new-red{
+.bg-new-advance{
   background: rgba(241, 82, 91, 0.08) !important;
 }
-.bg-new-orange{
+.bg-new-ledger{
   background: rgba(250, 140, 22, 0.08) !important;
 }
-.bg-new-yellow{
+.bg-new-revise{
   background: rgba(251, 182, 45, 0.08) !important;
 }
-.bg-new-green{
+.bg-new-stage{
   background: rgba(82, 196, 26, 0.08) !important;
 }
-.bg-new-blue{
+.bg-new-changeProject{
   background: rgba(51, 119, 255, 0.08) !important;
 }
-.text-new-red{
+.bg-new-changePlan{
+    background: rgba(114, 46, 209, 0.08) !important;
+}
+.bg-new-change{
+    background: rgba(22, 208, 208, 0.08) !important;
+}
+.bg-new-changeApply{
+    background: rgba(41, 58, 210, 0.08) !important;
+}
+.bg-new-material{
+    background: rgba(187, 41, 210, 0.08) !important;
+}
+.text-new-advance{
   color: rgba(241, 82, 91, 1) !important;
 }
-.text-new-orange{
+.text-new-ledger{
   color: rgba(250, 140, 22, 1) !important;
 }
-.text-new-yellow{
+.text-new-revise{
   color: rgba(251, 182, 45, 1) !important;
 }
-.text-new-green{
+.text-new-stage{
   color: rgba(82, 196, 26, 1) !important;
 }
-.text-new-blue{
+.text-new-changeProject{
   color: rgba(51, 119, 255, 1) !important;
 }
+.text-new-changePlan{
+    color: rgba(114, 46, 209, 1) !important;
+}
+.text-new-change{
+    color: rgba(22, 208, 208, 1) !important;
+}
+.text-new-changeApply{
+    color: rgba(41, 58, 210, 1) !important;
+}
+.text-new-material{
+    color: rgba(187, 41, 210, 1); !important;
+}
 .text-width{
   width: 66px;
   text-align: center;
@@ -1889,8 +1913,8 @@ overflow-y: auto;
   font-size: 36px;
 }
 .list-text-vertical{
-  overflow:hidden; 
-  text-overflow:ellipsis; 
+  overflow:hidden;
+  text-overflow:ellipsis;
   white-space:nowrap;
 }
 .about-text i{
@@ -1914,12 +1938,12 @@ overflow-y: auto;
 }
 /*@media (min-width: 768px){
   .weixin-erweima img{
-    width:90%; 
+    width:90%;
     height:auto;
   }
 }*/
 .weixin-erweima img{
-  width:75%; 
+  width:75%;
   height:auto;
 }
 .weixin-erweima span{
@@ -1958,4 +1982,4 @@ animation:shake 1s .2s ease both;}
 }
 .margin-inputbox .height-inputbox{
   height: 30px !important;
-}
+}

+ 1 - 1
app/public/js/advance.js

@@ -79,7 +79,7 @@ $(document).ready(function () {
 
     $('a[data-target="#sp-list" ]').on('click', function () {
         const id = $(this).data('vid')
-        postData(`${window.location.pathname.replace('/material', '')}/${id}/auditors`, {}, (res) => {
+        postData(`${window.location.pathname}/${id}/auditors`, {}, (res) => {
             const { auditHistory, auditors, user } = res
             let auditorsHTML = ''
             let historyHTML = ''

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

@@ -136,6 +136,16 @@ class codeRuleSet {
 }
 
 $(document).ready(() => {
+
+    $("#change-table").colResizable({
+        liveDrag:true,
+        gripInnerHtml:"<div class='grip'></div>",
+        draggingClass:"dragging",
+        resizeMode:'fit',
+        postbackSafe:true,
+        partialRefresh:true
+    });
+    
     // 首次进入设置
     let showNoNeed = false;
     if (parseInt(cRuleFirst)) {

+ 18 - 0
app/public/js/change_information.js

@@ -295,6 +295,24 @@ $(document).ready(() => {
         }
     };
     SpreadJsObj.initSheet(xmjSpread.getActiveSheet(), xmjSpreadSetting);
+
+    $.divResizer({
+        select: '#right-spr',
+        callback: function () {
+            changeSpread.refresh();
+            xmjSpread.refresh();
+            const width = (($('#right-view').width()/$('#right-view').parent('div').width())*100).toFixed();
+            setLocalCache('change_information_width', width);
+        }
+    });
+
+    // 根据浏览器记录展开收起
+    if (getLocalCache('change_information_width')) {
+        $('#left-view').css('width', (100 - parseFloat(getLocalCache('change_information_width'))) + '%');
+        $('#right-view').css('width', getLocalCache('change_information_width') + '%');
+        changeSpread.refresh();
+        xmjSpread.refresh();
+    }
 });
 function findDecimal(unit) {
     let value = precision.other.value;

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 415 - 0
app/public/js/colResizable/colResizable-1.6.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 3 - 0
app/public/js/colResizable/colResizable-1.6.min.js


+ 26 - 2
app/service/advance_audit.js

@@ -494,7 +494,7 @@ module.exports = app => {
         async getNoticeContent(pid, tid, vid, uid, opinion = '') {
             const noticeSql =
                 'SELECT * FROM (SELECT ' +
-                '  t.`id` As `tid`, ad.`vid`, t.`name`, m.`order`, pa.`name` As `su_name`, pa.role As `su_role`' +
+                '  t.`id` As `tid`, ad.`vid`, ad.`type` As `ad_type`, t.`name`, m.`order`, pa.`name` As `su_name`, pa.role As `su_role`' +
                 '  FROM (SELECT * FROM ?? WHERE `id` = ? ) As t' +
                 '  LEFT JOIN ?? As m On t.`id` = m.`tid` AND m.`id` = ?' +
                 '  LEFT JOIN ?? As ad ON m.`id` = ad.`vid`' +
@@ -573,7 +573,7 @@ module.exports = app => {
          */
         async getAuditAdvance(auditorId) {
             const sql = 'SELECT ma.`audit_id`, ma.`times`, ma.`order`, ma.`create_time`, ma.`end_time`, ma.`tid`, ma.`vid`,' +
-                        '    m.`order` As `morder`, m.`status` As `mstatus`,' +
+                        '    m.`order` As `morder`, m.`status` As `mstatus`, m.`type` As `mtype`,' +
                         '    t.`name`, t.`project_id`, t.`type`, t.`user_id` ' +
                         '  FROM ?? AS ma, ?? AS m, ?? As t ' +
                         '  WHERE ((ma.`audit_id` = ? and ma.`status` = ?) OR (m.`uid` = ? and ma.`status` = ? and m.`status` = ? and ma.`times` = (m.`times`-1)))' +
@@ -582,6 +582,30 @@ module.exports = app => {
             return await this.db.query(sql, sqlParam);
         }
 
+        /**
+         * 获取审核人审核的次数
+         *
+         * @param auditorId
+         * @return {Promise<*>}
+         */
+        async getCountByChecked(auditorId) {
+            return await this.db.count(this.tableName, { audit_id: auditorId, status: [auditConst.status.checked, auditConst.status.checkNo, auditConst.status.checkNoPre] });
+        }
+
+        /**
+         * 获取最近一次审批结束时间
+         *
+         * @param auditorId
+         * @return {Promise<*>}
+         */
+        async getLastEndTimeByChecked(auditorId) {
+            const sql = 'SELECT `end_time` FROM ?? WHERE `audit_id` = ? ' +
+                'AND `status` in (' + this.ctx.helper.getInArrStrSqlFilter([auditConst.status.checked, auditConst.status.checkNo]) + ') ORDER BY `end_time` DESC';
+            const sqlParam = [this.tableName, auditorId];
+            const result = await this.db.queryOne(sql, sqlParam);
+            return result ? result.end_time : null;
+        }
+
         async updateNewAuditList(advance, newIdList) {
             const transaction = await this.db.beginTransaction();
             try {

+ 25 - 0
app/service/change_apply_audit.js

@@ -307,6 +307,31 @@ module.exports = app => {
         }
 
         /**
+         * 获取审核人审核的次数
+         *
+         * @param auditorId
+         * @return {Promise<*>}
+         */
+        async getCountByChecked(auditorId) {
+            return await this.db.count(this.tableName, { aid: auditorId, status: [auditConst.status.checked, auditConst.status.checkNo] });
+        }
+
+        /**
+         * 获取最近一次审批结束时间
+         *
+         * @param auditorId
+         * @return {Promise<*>}
+         */
+        async getLastEndTimeByChecked(auditorId) {
+            const sql = 'SELECT `end_time` FROM ?? WHERE `aid` = ? ' +
+                'AND `status` in (' + this.ctx.helper.getInArrStrSqlFilter([auditConst.status.checked, auditConst.status.checkNo]) + ') ORDER BY `end_time` DESC';
+            const sqlParam = [this.tableName, auditorId];
+            const result = await this.db.queryOne(sql, sqlParam);
+            return result ? result.end_time : null;
+        }
+
+
+        /**
          * 用于添加推送所需的content内容
          * @param {Number} pid 项目id
          * @param {Number} tid 台账id

+ 28 - 0
app/service/change_audit.js

@@ -312,6 +312,34 @@ module.exports = app => {
         }
 
         /**
+         * 获取审核人审核的次数
+         *
+         * @param auditorId
+         * @return {Promise<*>}
+         */
+        async getCountByChecked(auditorId) {
+            const sql = 'Select count(*) as count FROM ?? WHERE uid = ? AND usite != 0 AND status in (' + this.ctx.helper.getInArrStrSqlFilter([auditConst.status.checked, auditConst.status.back, auditConst.status.backnew]) +')';
+            const sqlParam = [this.tableName, auditorId];
+            const result = await this.db.queryOne(sql, sqlParam);
+            return result.count ? result.count : 0;
+            // return await this.db.count(this.tableName, { aid: auditorId, status: [auditConst.status.checked, auditConst.status.checkNo] });
+        }
+
+        /**
+         * 获取最近一次审批结束时间
+         *
+         * @param auditorId
+         * @return {Promise<*>}
+         */
+        async getLastEndTimeByChecked(auditorId) {
+            const sql = 'SELECT `sin_time` FROM ?? WHERE `uid` = ? AND usite != 0 ' +
+                'AND `status` in (' + this.ctx.helper.getInArrStrSqlFilter([auditConst.status.checked, auditConst.status.back, auditConst.status.backnew]) + ') ORDER BY `sin_time` DESC';
+            const sqlParam = [this.tableName, auditorId];
+            const result = await this.db.queryOne(sql, sqlParam);
+            return result ? result.sin_time : null;
+        }
+
+        /**
          * 获取 某时间后 审批进度更新的 变更令
          * @param {Number} pid - 查询标段
          * @param {Number} uid - 查询人

+ 24 - 0
app/service/change_plan_audit.js

@@ -311,6 +311,30 @@ module.exports = app => {
         }
 
         /**
+         * 获取审核人审核的次数
+         *
+         * @param auditorId
+         * @return {Promise<*>}
+         */
+        async getCountByChecked(auditorId) {
+            return await this.db.count(this.tableName, { aid: auditorId, status: [auditConst.status.checked, auditConst.status.checkNo] });
+        }
+
+        /**
+         * 获取最近一次审批结束时间
+         *
+         * @param auditorId
+         * @return {Promise<*>}
+         */
+        async getLastEndTimeByChecked(auditorId) {
+            const sql = 'SELECT `end_time` FROM ?? WHERE `aid` = ? ' +
+                'AND `status` in (' + this.ctx.helper.getInArrStrSqlFilter([auditConst.status.checked, auditConst.status.checkNo]) + ') ORDER BY `end_time` DESC';
+            const sqlParam = [this.tableName, auditorId];
+            const result = await this.db.queryOne(sql, sqlParam);
+            return result ? result.end_time : null;
+        }
+
+        /**
          * 用于添加推送所需的content内容
          * @param {Number} pid 项目id
          * @param {Number} tid 台账id

+ 24 - 0
app/service/change_project_audit.js

@@ -308,6 +308,30 @@ module.exports = app => {
         }
 
         /**
+         * 获取审核人审核的次数
+         *
+         * @param auditorId
+         * @return {Promise<*>}
+         */
+        async getCountByChecked(auditorId) {
+            return await this.db.count(this.tableName, { aid: auditorId, status: [auditConst.status.checked, auditConst.status.back, auditConst.status.checkNo] });
+        }
+
+        /**
+         * 获取最近一次审批结束时间
+         *
+         * @param auditorId
+         * @return {Promise<*>}
+         */
+        async getLastEndTimeByChecked(auditorId) {
+            const sql = 'SELECT `end_time` FROM ?? WHERE `aid` = ? ' +
+                'AND `status` in (' + this.ctx.helper.getInArrStrSqlFilter([auditConst.status.checked, auditConst.status.back, auditConst.status.checkNo]) + ') ORDER BY `end_time` DESC';
+            const sqlParam = [this.tableName, auditorId];
+            const result = await this.db.queryOne(sql, sqlParam);
+            return result ? result.end_time : null;
+        }
+
+        /**
          * 用于添加推送所需的content内容
          * @param {Number} pid 项目id
          * @param {Number} tid 台账id

+ 24 - 0
app/service/ledger_audit.js

@@ -454,6 +454,30 @@ module.exports = app => {
         }
 
         /**
+         * 获取审核人审核的次数
+         *
+         * @param auditorId
+         * @return {Promise<*>}
+         */
+        async getCountByChecked(auditorId) {
+            return await this.db.count(this.tableName, { audit_id: auditorId, status: [auditConst.status.checked, auditConst.status.checkNo] });
+        }
+
+        /**
+         * 获取最近一次审批结束时间
+         *
+         * @param auditorId
+         * @return {Promise<*>}
+         */
+        async getLastEndTimeByChecked(auditorId) {
+            const sql = 'SELECT `end_time` FROM ?? WHERE `audit_id` = ? ' +
+                'AND `status` in (' + this.ctx.helper.getInArrStrSqlFilter([auditConst.status.checked, auditConst.status.checkNo]) + ') ORDER BY `end_time` DESC';
+            const sqlParam = [this.tableName, auditorId];
+            const result = await this.db.queryOne(sql, sqlParam);
+            return result ? result.end_time : null;
+        }
+
+        /**
          * 获取 某时间后 审批进度 更新的台账
          * @param {Integer} pid - 项目id
          * @param {Integer} uid - 查询人id

+ 24 - 0
app/service/material_audit.js

@@ -753,6 +753,30 @@ module.exports = app => {
         }
 
         /**
+         * 获取审核人审核的次数
+         *
+         * @param auditorId
+         * @return {Promise<*>}
+         */
+        async getCountByChecked(auditorId) {
+            return await this.db.count(this.tableName, { aid: auditorId, status: [auditConst.status.checked, auditConst.status.checkNo, auditConst.status.checkNoPre] });
+        }
+
+        /**
+         * 获取最近一次审批结束时间
+         *
+         * @param auditorId
+         * @return {Promise<*>}
+         */
+        async getLastEndTimeByChecked(auditorId) {
+            const sql = 'SELECT `end_time` FROM ?? WHERE `aid` = ? ' +
+                'AND `status` in (' + this.ctx.helper.getInArrStrSqlFilter([auditConst.status.checked, auditConst.status.checkNo]) + ') ORDER BY `end_time` DESC';
+            const sqlParam = [this.tableName, auditorId];
+            const result = await this.db.queryOne(sql, sqlParam);
+            return result ? result.end_time : null;
+        }
+
+        /**
          * 获取 某时间后 审批进度 更新的期
          * @param {Number} pid - 查询标段
          * @param {Number} uid - 查询人

+ 11 - 1
app/service/material_list.js

@@ -248,7 +248,7 @@ module.exports = app => {
          * @return {void}
          */
         async getMaterialData(tid, mid) {
-            const sql = 'SELECT ml.`id`, mb.`code`, mb.`name`, mb.`unit`, ml.`order`, ml.`quantity`, ml.`expr`, ml.`mb_id`, ml.`gcl_id`, ml.`xmj_id`, ml.`mx_id`, ml.`tid`, ml.`mid`' +
+            const sql = 'SELECT ml.`id`, mb.`code`, mb.`name`, mb.`unit`, ml.`order`, ml.`quantity`, ml.`expr`, ml.`mb_id`, ml.`gcl_id`, ml.`xmj_id`, ml.`mx_id`, ml.`tid`, ml.`mid`, mb.m_spread' +
                 ' FROM ' + this.tableName + ' as ml' +
                 ' LEFT JOIN ' + this.ctx.service.materialBills.tableName + ' as mb' +
                 ' ON ml.`mb_id` = mb.`id`' +
@@ -257,6 +257,16 @@ module.exports = app => {
             return await this.db.query(sql, sqlParam);
         }
 
+        async getPreMaterialData(tid, mid) {
+            const sql = 'SELECT ml.`id`, mb.`code`, mb.`name`, mb.`unit`, ml.`order`, ml.`quantity`, ml.`expr`, ml.`mb_id`, ml.`gcl_id`, ml.`xmj_id`, ml.`mx_id`, ml.`tid`, ml.`mid`, mbh.m_spread' +
+                ' FROM ' + this.tableName + ' as ml' +
+                ' LEFT JOIN ' + this.ctx.service.materialBills.tableName + ' as mb ON ml.`mb_id` = mb.`id`' +
+                ' LEFT JOIN ' + this.ctx.service.materialBillsHistory.tableName + ' as mbh ON ml.`mb_id` = mbh.`mb_id` and mbh.mid = ?' +
+                ' WHERE ml.`tid` = ? AND ml.`mid` = ?';
+            const sqlParam = [mid, tid, mid];
+            return await this.db.query(sql, sqlParam);
+        }
+
         /**
          * 复制上一期并生成新一期清单工料关联,计算新一期小计值
          * @param transaction

+ 2 - 2
app/service/notice_push.js

@@ -42,8 +42,8 @@ module.exports = app => {
             let notice = await this.db.select(this.tableName, {
                 where: wheres,
                 orders: [['create_time', 'desc']],
-                limit: 10,
-                offset: 0
+                // limit: 10,
+                // offset: 0
             })
             notice = notice.map(v => {
                 const extra = JSON.parse(v.content)

+ 47 - 7
app/service/report.js

@@ -9,7 +9,13 @@
  */
 
 const BudgetSource = require('../lib/rm/budget');
+const MaterialSource = require('../lib/rm/material');
+
 const rptCustomData = require('../lib/rptCustomData');
+const bindData = {
+    materialGather: ['mem_material_gather_bills', 'mem_material_gather_xmj', 'mem_material_gather_gl'],
+};
+
 
 module.exports = app => {
     class Report extends app.BaseService {
@@ -33,9 +39,31 @@ module.exports = app => {
             }
         }
 
-        async getReportData(params, filters, memFieldKeys, customDefine, customSelect) {
+
+        getFilter(sourceFilters) {
+            const common = [], spec = [];
+            for (const sf of sourceFilters) {
+                let bSpec = false;
+                for (const key in bindData) {
+                    const b = bindData[key];
+                    if (b.indexOf(sf) >= 0) {
+                        bSpec = true;
+                        if (spec.indexOf(key) === -1) {
+                            spec.push(key);
+                            break;
+                        }
+                    }
+                }
+                if (!bSpec) common.push(sf);
+            }
+            return [common, spec];
+        }
+
+        async getReportData(params, sourceFilters, memFieldKeys, customDefine, customSelect) {
+            const [filters, specFilters] = this.getFilter(sourceFilters);
             const service = this.ctx.service;
             await service.tender.checkTender(params.tender_id);
+            const materialSource = new MaterialSource(this.ctx);
             const rst = {};
             const runnableRst = [];
             const runnableKey = []; // 这个配合runnableRst用,未来考虑并行查询优化
@@ -166,27 +194,27 @@ module.exports = app => {
                             runnableKey.push(filter);
                             break;
                         case 'mem_select_material_audit':
-                            runnableRst.push(service.reportMemory.getSelectMaterialAuditors(params.tender_id, params.material_order));
+                            runnableRst.push(materialSource.getSelectMaterialAuditors(params.tender_id, params.material_order));
                             runnableKey.push(filter);
                             break;
                         case 'mem_material':
-                            runnableRst.push(service.reportMemory.getMaterial(params.tender_id, params.material_order, memFieldKeys[filter]));
+                            runnableRst.push(materialSource.getMaterial(params.tender_id, params.material_order, memFieldKeys[filter]));
                             runnableKey.push(filter);
                             break;
                         case 'mem_material_gl':
-                            runnableRst.push(service.reportMemory.getMaterialGl(params.tender_id, params.material_order, memFieldKeys[filter]));
+                            runnableRst.push(materialSource.getMaterialGl(params.tender_id, params.material_order, memFieldKeys[filter]));
                             runnableKey.push(filter);
                             break;
                         case 'mem_material_gl_detail':
-                            runnableRst.push(service.reportMemory.getMaterialGlDetail(params.tender_id, params.material_order, memFieldKeys[filter]));
+                            runnableRst.push(materialSource.getMaterialGlDetail(params.tender_id, params.material_order, memFieldKeys[filter]));
                             runnableKey.push(filter);
                             break;
                         case 'mem_material_bills':
-                            runnableRst.push(service.reportMemory.getMaterialBills(params.tender_id, params.material_order, memFieldKeys[filter]));
+                            runnableRst.push(materialSource.getMaterialBills(params.tender_id, params.material_order, memFieldKeys[filter]));
                             runnableKey.push(filter);
                             break;
                         case 'mem_material_pos':
-                            runnableRst.push(service.reportMemory.getMaterialPos(params.tender_id, params.material_order, memFieldKeys[filter]));
+                            runnableRst.push(materialSource.getMaterialPos(params.tender_id, params.material_order, memFieldKeys[filter]));
                             runnableKey.push(filter);
                             break;
                         case 'mem_stage_sum_bills':
@@ -348,6 +376,18 @@ module.exports = app => {
                         break;
                 }
             }
+            for (const s of specFilters) {
+                switch (s) {
+                    case 'materialGather':
+                        const mgResult = await materialSource.getMaterialGatherBills(params.tender_id, params.material_order);
+                        for (const d in mgResult) {
+                            rst[d] = mgResult[d];
+                        }
+                        break;
+                    default:
+                        break;
+                }
+            }
             return rst;
         }
     }

+ 0 - 135
app/service/report_memory.js

@@ -14,7 +14,6 @@ const StageIm = require('../lib/stage_im');
 const imType = require('../const/tender').imType;
 const audit = require('../const/audit');
 const changeConst = require('../const/change');
-const materialConst = require('../const/material');
 // const path = require('path');
 // const fs = require('fs');
 
@@ -1197,140 +1196,6 @@ module.exports = app => {
             }
         }
 
-        async getSelectMaterialAuditors(tid, material_order, fields) {
-            await this.ctx.service.material.checkMaterial(tid, material_order);
-            const auditors = await this.ctx.service.materialAudit.getFinalAuditGroup(this.ctx.material.id, this.ctx.material.curTimes);
-            const user = await this.ctx.service.projectAccount.getDataById(this.ctx.material.user_id);
-            const result = [{
-                aid: user.id,
-                name: user.name,
-                company: user.company,
-                role: user.role,
-                mobile: user.mobile,
-                telephone: user.telephone,
-                sign_path: user.sign_path,
-                opinion: user.opinion,
-                end_time: auditors && auditors.length > 0 ? auditors[0].begin_time : null,
-                sort: 0,
-            }, ...auditors];
-            return result;
-        }
-
-        async getMaterial(tender_id, material_order, fields) {
-            const result = await this.ctx.service.material.getValidMaterials(tender_id);
-            if (this._checkFieldsExist(fields, ['checked_time'])) {
-                for (const r of result) {
-                    const auditors = await this.ctx.service.materialAudit.getFinalAuditGroup(r.id, r.curTimes || r.times);
-                    r.checked_time = !r.curTimes ? auditors[auditors.length - 1].end_time : null;
-                }
-            }
-            return result;
-        }
-
-        _completeMaterialGl(materialGl) {
-            const tTypeStr = [], mTypeStr = [];
-            for (const t of materialConst.t_type) {
-                tTypeStr[t.value] = t.text;
-            }
-            for (const m of materialConst.m_type) {
-                mTypeStr[m.value] = m.text;
-            }
-            for (const gl of materialGl) {
-                gl.tp = this.ctx.helper.mul(gl.quantity, gl.m_spread, 2);
-                gl.t_type_str = tTypeStr[gl.t_type];
-                gl.m_type_str = mTypeStr[gl.m_type];
-                gl.end_tp = this.ctx.helper.add(gl.tp, gl.pre_tp);
-            }
-        }
-
-        async getMaterialGl(tender_id, material_order, fields) {
-            const materials = await this.ctx.service.material.getAllDataByCondition({
-                where: {tid: tender_id},
-                orders: [['order', 'desc']],
-            });
-            if (materials.length > 0) {
-                let result;
-                if (materials[0].order === material_order) {
-                    result = await this.ctx.service.materialBills.getAllDataByCondition({
-                        where: {tid: tender_id}
-                    });
-                } else {
-                    const material = this.ctx.helper._.find(materials, {order: material_order});
-                    if (!material) return [];
-
-                    const sql = 'SELECT mb.id, mb.tid, mb.mid, mb.order, mb.order, mb.t_type, mb.code, mb.name, mb.unit, mb.spec, mb.m_type,' +
-                        '    mbh.quantity, mbh.expr,' +
-                        '    mb.basic_price, mb.basic_times, ' +
-                        '    mbh.msg_tp, mbh.msg_times, mbh.msg_spread, mbh.m_up_risk, mbh.m_down_risk, mbh.m_spread, mbh.m_tp, mbh.pre_tp, mbh.m_tax_tp, mbh.tax_pre_tp, mbh.origin, ' +
-                        '    mb.remark, mb.is_summary, mbh.m_tax, mb.in_time' +
-                        '  FROM ' + this.ctx.service.materialBillsHistory.tableName + ' mbh ' +
-                        '  LEFT JOIN ' + this.ctx.service.materialBills.tableName + ' mb ON mbh.mb_id = mb.id ' +
-                        '  WHERE mbh.tid = ? And mbh.mid = ?';
-                    result = await this.ctx.app.mysql.query(sql, [tender_id, material.id]);
-                }
-                this._completeMaterialGl(result);
-                return result;
-            } else {
-                return [];
-            }
-        }
-
-        async getMaterialGlDetail(tender_id, material_order, fields) {
-            const material = await this.ctx.service.material.getDataByCondition({tid: tender_id, order: material_order});
-            return material ? await this.ctx.service.materialList.getMaterialData(tender_id, material.id) : [];
-        }
-
-        async getMaterialBills(tender_id, material_order, fields) {
-            const material = await this.ctx.service.material.getDataByCondition({tid: tender_id, order: material_order});
-            try {
-                const billsData = await this.ctx.service.ledger.getData(tender_id);
-                if (this._checkFieldsExist(fields, billsFields.stage)) {
-                    const curStage = await this.ctx.service.stageBills.getStagesData(tender_id, material.stage_id);
-                    this.ctx.helper.assignRelaData(billsData, [
-                        {data: curStage, fields: ['contract_qty', 'contract_tp', 'contract_expr', 'qc_qty', 'qc_tp', 'postil'], prefix: '', relaId: 'lid'}
-                    ]);
-                }
-
-                const billsTree = this._getNewBillsTree();
-                billsTree.loadDatas(billsData);
-                billsTree.calculateAll();
-
-                return billsTree.getDatas([
-                    'id', 'tender_id', 'ledger_id', 'ledger_pid', 'level', 'order', 'full_path', 'is_leaf',
-                    'code', 'b_code', 'name', 'unit', 'unit_price',
-                    'deal_qty', 'deal_tp',
-                    'sgfh_qty', 'sgfh_tp', 'sjcl_qty', 'sjcl_tp', 'qtcl_qty', 'qtcl_tp', 'quantity', 'total_price',
-                    'dgn_qty1', 'dgn_qty2',
-                    'drawing_code', 'memo', 'node_type', 'is_tp',
-                    'contract_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'gather_qty', 'gather_tp', 'postil',
-                    'sgfh_expr', 'sjcl_expr', 'qtcl_expr', 'contract_expr',
-                ]);
-            } catch(err) {
-                this.ctx.helper.log(err);
-                return [];
-            }
-        }
-
-        async getMaterialPos(tender_id, material_order, fields) {
-            const material = await this.ctx.service.material.getDataByCondition({tid: tender_id, order: material_order});
-            try {
-                const posData = await this.ctx.service.pos.getAllDataByCondition({ where: {tid: tender_id }});
-                if (this._checkFieldsExist(fields, posFields.stage)) {
-                    const curPosStage = await this.ctx.service.stagePos.getStagesData(tender_id, material.stage_id);
-                    this.ctx.helper.assignRelaData(posData, [
-                        {data: curPosStage, fields: ['contract_qty', 'qc_qty', 'contract_expr', 'postil'], prefix: '', relaId: 'pid'}
-                    ]);
-                }
-                this.pos.loadDatas(posData);
-                this.pos.calculateAll();
-
-                return this.pos.getDatas();
-            } catch (err) {
-                this.ctx.helper.log(err);
-                return [];
-            }
-        }
-
         async getSumStageBillsData(tid, sid, fields) {
             try {
                 await this.ctx.service.tender.checkTender(tid);

+ 24 - 0
app/service/revise_audit.js

@@ -609,6 +609,30 @@ module.exports = app => {
         }
 
         /**
+         * 获取审核人审核的次数
+         *
+         * @param auditorId
+         * @return {Promise<*>}
+         */
+        async getCountByChecked(auditorId) {
+            return await this.db.count(this.tableName, { audit_id: auditorId, status: [auditConst.status.checked, auditConst.status.checkNo] });
+        }
+
+        /**
+         * 获取最近一次审批结束时间
+         *
+         * @param auditorId
+         * @return {Promise<*>}
+         */
+        async getLastEndTimeByChecked(auditorId) {
+            const sql = 'SELECT `end_time` FROM ?? WHERE `audit_id` = ? ' +
+                'AND `status` in (' + this.ctx.helper.getInArrStrSqlFilter([auditConst.status.checked, auditConst.status.checkNo]) + ') ORDER BY `end_time` DESC';
+            const sqlParam = [this.tableName, auditorId];
+            const result = await this.db.queryOne(sql, sqlParam);
+            return result ? result.end_time : null;
+        }
+
+        /**
          * 获取 某时间后 审批进度 更新的台账
          * @param {Integer} pid - 项目id
          * @param {Integer} uid - 查询人id

+ 1 - 1
app/service/rpt_stage_sum_memory.js

@@ -181,7 +181,7 @@ module.exports = app => {
                     ? await this.ctx.service.stageBills.getAuditorStageData2(this.ctx.tender.id, stage.id, stage.curTimes, stage.curOrder)
                     : await this.ctx.service.stageBills.getLastestStageData2(this.ctx.tender.id, stage.id);
                 this.ctx.helper.assignRelaData(billsData, [
-                    {data: curStage, fields: ['contract_qty', 'contract_tp', 'contract_expr', 'qc_qty', 'qc_tp'], prefix: prefix, relaId: 'lid', defaultData: defaultData}
+                    {data: curStage, fields: ['contract_qty', 'contract_tp', 'contract_expr', 'qc_qty', 'qc_tp'], prefix: prefix, relaId: 'lid', defaultData}
                 ]);
             }
 

+ 24 - 0
app/service/stage_audit.js

@@ -1049,6 +1049,30 @@ module.exports = app => {
         }
 
         /**
+         * 获取审核人审核的次数
+         *
+         * @param auditorId
+         * @return {Promise<*>}
+         */
+        async getCountByChecked(auditorId) {
+            return await this.db.count(this.tableName, { aid: auditorId, status: [auditConst.status.checked, auditConst.status.checkNo, auditConst.status.checkNoPre] });
+        }
+
+        /**
+         * 获取最近一次审批结束时间
+         *
+         * @param auditorId
+         * @return {Promise<*>}
+         */
+        async getLastEndTimeByChecked(auditorId) {
+            const sql = 'SELECT `end_time` FROM ?? WHERE `aid` = ? ' +
+                'AND `status` in (' + this.ctx.helper.getInArrStrSqlFilter([auditConst.status.checked, auditConst.status.checkNo, auditConst.status.checkNoPre]) + ') ORDER BY `end_time` DESC';
+            const sqlParam = [this.tableName, auditorId];
+            const result = await this.db.queryOne(sql, sqlParam);
+            return result ? result.end_time : null;
+        }
+
+        /**
          * 获取 某时间后 审批进度 更新的期
          * @param {Number} pid - 查询标段
          * @param {Number} uid - 查询人

+ 2 - 1
app/view/change/index.ejs

@@ -69,7 +69,7 @@
             <input id="dealCode" value="<%= dealCode %>" type="hidden">
             <input id="tenderId" value="<%= tender.id %>" type="hidden">
             <div class="sjs-height-0">
-                <table class="table table-bordered">
+                <table class="table table-bordered" id="change-table">
                     <thead>
                     <tr>
                         <th width="20%" id="sort_change">申请编号/变更令号</th><th width="30%">变更工程名称</th>
@@ -134,6 +134,7 @@
     </div>
 </div>
 <script src="/public/js/sub_menu.js"></script>
+<script  src="/public/js/colResizable/colResizable-1.6.min.js"></script>
 <script>
     $.subMenu({
         menu: '#sub-menu', miniMenu: '#sub-mini-menu', miniMenuList: '#mini-menu-list',

+ 3 - 2
app/view/change/information.ejs

@@ -81,7 +81,7 @@
     <div class="content-wrap">
         <div class="c-header p-0"></div>
         <div class="w-100 sub-content row">
-            <div class="c-body col-4">
+            <div class="c-body" id="left-view" style="width: 33.33%">
                 <div class="sjs-bar-1">
                     <input type="hidden" id="tenderId" value="<%- ctx.tender.id %>">
                     <input type="hidden" id="changeId" value="<%- ctx.change.cid %>">
@@ -363,7 +363,8 @@
                     </div>
                 </div>
             </div>
-            <div class="c-body col-8">
+            <div class="c-body" id="right-view" style="width: 66.67%">
+                <div class="resize-x" id="right-spr" r-Type="width" div1="#left-view" div2="#right-view" title="调整大小" a-type="percent"><!--调整左右高度条--></div>
                 <div class="sjs-height-1" id="change-spread">
                 </div>
                 <!--下半部分-->

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 556 - 424
app/view/dashboard/index.ejs


+ 72 - 0
builder_report_index_define.js

@@ -1832,6 +1832,77 @@ const material_gl_detail = {
     ]
 };
 
+const materialGather = {
+    bills: {
+        name: '材差清单汇总 - 工程量清单',
+        remark: '',
+        key: 'mem_material_gather_bills',
+        id: 85,
+        prefix: '材差清单汇总-清单',
+        cols: [
+            { name: 'id', field: 'id', type: dataType.int },
+            { name: '清单编号', field: 'b_code', type: dataType.str },
+            { name: '名称', field: 'name', type: dataType.str },
+            { name: '单位', field: 'unit', type: dataType.str },
+            { name: '单价', field: 'unit_price', type: dataType.currency },
+            { name: '签约-数量', field: 'deal_qty', type: dataType.currency },
+            { name: '签约-金额', field: 'deal_tp', type: dataType.currency },
+            { name: '数量', field: 'quantity', type: dataType.currency },
+            { name: '金额', field: 'total_price', type: dataType.currency },
+            { name: '本期-合同-数量', field: 'contract_qty', type: dataType.currency },
+            { name: '本期-合同-金额', field: 'contract_tp', type: dataType.currency },
+            { name: '本期-变更-数量', field: 'qc_qty', type: dataType.currency },
+            { name: '本期-变更-金额', field: 'qc_tp', type: dataType.currency },
+            { name: '本期-完成-数量', field: 'gather_qty', type: dataType.currency },
+            { name: '本期-完成-金额', field: 'gather_tp', type: dataType.currency },
+            { name: '本期-价差', field: 'jiacha', type: dataType.currency },
+        ],
+    },
+    xmj: {
+        name: '材差清单汇总 - 相关项目节',
+        remark: '',
+        key: 'mem_material_gather_xmj',
+        id: 86,
+        prefix: '材差清单汇总-项目节',
+        cols: [
+            { name: 'id(项目节id)', field: 'id', type: dataType.int },
+            { name: '清单id(所属工程量清单id)', field: 'gcl_id', type: dataType.int },
+            { name: '明细id(在台账中的id)', field: 'mx_id', type: dataType.str },
+            { name: '编号', field: 'code', type: dataType.str },
+            { name: '计量单元', field: 'jldy', type: dataType.str },
+            { name: '分部工程', field: 'fbgc', type: dataType.str },
+            { name: '分项工程', field: 'fxgc', type: dataType.str },
+            { name: '单位工程', field: 'dwgc', type: dataType.str },
+            { name: '部位明细', field: 'bwmx', type: dataType.str },
+            { name: '图册号', field: 'drawing_code', type: dataType.str },
+            { name: '数量', field: 'quantity', type: dataType.currency },
+            { name: '本期-合同-数量', field: 'contract_qty', type: dataType.currency },
+            { name: '本期-变更-数量', field: 'qc_qty', type: dataType.currency },
+            { name: '本期-完成-数量', field: 'gather_qty', type: dataType.currency },
+            { name: '本期-价差', field: 'jiacha', type: dataType.currency },
+        ],
+    },
+    gl: {
+        name: '材差清单汇总 - 相关工料',
+        remark: '',
+        key: 'mem_material_gather_gl',
+        id: 87,
+        prefix: '材差清单汇总-工料',
+        cols: [
+            { name: 'id', field: 'id', type: dataType.int },
+            { name: '排序', field: 'order', type: dataType.int },
+            { name: '所属标段id', field: 'tid', type: dataType.int },
+            { name: '创建期id', field: 'mid', type: dataType.int },
+            { name: '所属工料id', field: 'mb_id', type: dataType.int },
+            { name: '清单id', field: 'gcl_id', type: dataType.int },
+            { name: '项目节id', field: 'xmj_id', type: dataType.int },
+            { name: '部位明细id', field: 'mx_id', type: dataType.int },
+            { name: '本期计量数量-小计', field: 'gather_qty', type: dataType.int },
+            { name: '数量', field: 'quantity', type: dataType.int },
+        ],
+    },
+};
+
 const stage_sum_bills = {
     name: '期汇总-清单-交叉数据表(mem_stage_sum_bills)',
     remark: '',
@@ -2737,6 +2808,7 @@ const defines = [
     custom_select,
     stage_change_info, stage_change_info_bills,
     budget.gu, budget.gai, budget.yu, budget.final,
+    materialGather.bills, materialGather.xmj, materialGather.gl,
 ];
 for (const d of defines) {
     exportTableDefine(d);