Jelajahi Sumber

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

laiguoran 3 tahun lalu
induk
melakukan
d8c48d5bc1

+ 18 - 0
app/const/tourist_permission.js

@@ -0,0 +1,18 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Mai
+ * @date
+ * @version
+ */
+
+const defaultPermission = {
+    file: 0,
+    tag: 0,
+};
+
+module.exports = {
+    defaultPermission,
+};

+ 2 - 2
app/controller/advance_controller.js

@@ -126,7 +126,7 @@ module.exports = app => {
             if (ctx.advance.status === auditConst.status.uncheck) {
                 if (ctx.session.sessionUser.accountId !== ctx.advance.uid && !ctx.tender.isTourist) {
                     throw '无权访问';
-                } else if (ctx.session.sessionUser.accountId === ctx.advance.uid) {
+                } else if (ctx.session.sessionUser.accountId === ctx.advance.uid || ctx.tender.touristPermission.file) {
                     ctx.advance.filePermission = true;
                 }
             } else {
@@ -134,7 +134,7 @@ module.exports = app => {
                 const cur_uid = ctx.session.sessionUser.accountId;
                 if (auditors.findIndex(item => item.audit_id === cur_uid) === -1 && !ctx.tender.isTourist) {
                     throw '无权访问';
-                } else if (auditors.findIndex(item => item.audit_id === cur_uid) !== -1 || ctx.session.sessionUser.accountId === ctx.advance.uid) {
+                } else if (auditors.findIndex(item => item.audit_id === cur_uid) !== -1 || ctx.session.sessionUser.accountId === ctx.advance.uid || ctx.tender.touristPermission.file) {
                     ctx.advance.filePermission = true;
                 }
             }

+ 1 - 1
app/controller/material_controller.js

@@ -883,7 +883,7 @@ module.exports = app => {
             const auditors = await ctx.service.materialAudit.getAuditorsWithOwner(ctx.material.id, ctx.material.times);
             // console.log(auditors);
 
-            if (auditors.findIndex(item => item.aid === accountId) === -1) {
+            if (auditors.findIndex(item => item.aid === accountId) === -1 && !ctx.tender.touristPermission.file) {
                 throw '该调差期当前您无权操作';
             }
             // if (!ctx.material.curAuditor) {

+ 7 - 4
app/controller/stage_controller.js

@@ -774,9 +774,10 @@ module.exports = app => {
                 }
 
                 // 用户有无权限上传和删除附件
-                renderData.uploadPermission = ((ctx.stage.status === auditConst.status.uncheck || ctx.stage.status === auditConst.status.checkNo) && ctx.session.sessionUser.accountId === ctx.stage.user_id) ||
+                renderData.uploadPermission = (!(ctx.stage.readOnly || ctx.stage.revising) && ((ctx.stage.status === auditConst.status.uncheck || ctx.stage.status === auditConst.status.checkNo) && ctx.session.sessionUser.accountId === ctx.stage.user_id) ||
                     (ctx.stage.status === auditConst.status.checkNoPre && ctx.session.sessionUser.accountId === ctx.stage.curAuditor.aid) ||
-                    (ctx.stage.status === auditConst.status.checking && ctx.stage.curAuditor && ctx.stage.curAuditor.aid === ctx.session.sessionUser.accountId);
+                    (ctx.stage.status === auditConst.status.checking && ctx.stage.curAuditor && ctx.stage.curAuditor.aid === ctx.session.sessionUser.accountId)) ||
+                    (ctx.tender.isTourist && ctx.tender.touristPermission.file);
 
                 if (!ctx.stage.readOnly || ctx.tender.isTourist) {
                     // 计算 本期金额
@@ -1619,7 +1620,8 @@ module.exports = app => {
             };
             let stream;
             try {
-                this._checkStageCanModify(ctx);
+                // this._checkStageCanModify(ctx);
+                this._checkStageCanModifyRe(ctx);
 
                 const parts = ctx.multipart({ autoFields: true });
                 const files = [];
@@ -1726,7 +1728,8 @@ module.exports = app => {
                 data: '',
             };
             try {
-                this._checkStageCanModify(ctx);
+                // this._checkStageCanModify(ctx);
+                this._checkStageCanModifyRe(ctx);
 
                 const data = JSON.parse(ctx.request.body.data);
                 const payInfo = await ctx.service.stagePay.getDataById(data.id);

+ 4 - 3
app/controller/stage_extra_controller.js

@@ -28,7 +28,7 @@ module.exports = app => {
 
         /**
          * 甲供材料(Get)
-         * 
+         *
          * @param {Object} ctx - egg全局变量
          */
         async jgcl (ctx) {
@@ -85,14 +85,15 @@ module.exports = app => {
 
         /**
          * 奖罚金(Get)
-         * 
+         *
          * @param {Object} ctx - egg全局变量
          */
         async bonus (ctx) {
             try {
                 const renderData = {
                     jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.stageExtra.bonus),
-                    auditConst: auditConst,
+                    auditConst,
+                    stage: ctx.stage,
                 };
                 await this.layout('stage_extra/bonus.ejs', renderData, 'stage_extra/bonus_modal.ejs');
             } catch (err) {

+ 11 - 4
app/controller/tender_controller.js

@@ -502,6 +502,9 @@ module.exports = app => {
                 };
                 if (ctx.session.sessionUser.is_admin) {
                     renderData.tourists = await ctx.service.tenderTourist.getTourists(tender.id);
+                    for (const t of renderData.tourists) {
+                        t.permission = await ctx.service.tenderTourist.getTouristPermission(t);
+                    }
                     // 获取所有项目参与者
                     const accountList = await ctx.service.projectAccount.getAllDataByCondition({
                         where: { project_id: ctx.session.sessionProject.id, enable: 1 },
@@ -1036,6 +1039,9 @@ module.exports = app => {
                     case 'del':
                         await ctx.service.tenderTourist.removeAudit(data);
                         break;
+                    case 'permission':
+                        await ctx.service.tenderTourist.setPermission(data);
+                        break;
                     default:break;
                 }
                 ctx.body = { err: 0, msg: '', data: info };
@@ -1069,12 +1075,13 @@ module.exports = app => {
 
         async billsTag(ctx) {
             try {
+                const isValidTourist = ctx.tender.isTourist && ctx.tender.touristPermission.tag;
                 if (ctx.stage) {
-                    if (ctx.stage.users.indexOf(this.ctx.session.sessionUser.accountId) < 0)
-                        throw '您无权进行该操作';
+                    const isAuditor = ctx.stage.users.indexOf(this.ctx.session.sessionUser.accountId) >= 0;
+                    if (!isAuditor && !isValidTourist) throw '您无权进行该操作';
                 } else {
-                    if (ctx.tender.ledgerUsers.indexOf(this.ctx.session.sessionUser.accountId) < 0)
-                        throw '您无权进行该操作';
+                    const isAuditor = ctx.tender.ledgerUsers.indexOf(this.ctx.session.sessionUser.accountId) >= 0;
+                    if (!isAuditor && !isValidTourist) throw '您无权进行该操作';
                 }
                 const data = JSON.parse(ctx.request.body.data);
                 const result = await ctx.service.ledgerTag.update(data);

+ 159 - 7
app/lib/sum_load.js

@@ -33,13 +33,16 @@ class loadGclBaseTree {
      * @param {String} code - 子项编号
      * @returns {*}
      */
-    findNode(node, parent) {
+    findNode(node, parent, check) {
         parent = parent || this.parent;
         if (!parent.children) return null;
 
         for (const child of parent.children) {
             const checkLeaf = (child.is_leaf && node.is_leaf) || (!child.is_leaf && !node.is_leaf);
-            if (child.b_code === node.b_code && child.name === node.name && child.unit === node.unit && checkLeaf) return child;
+            if (child.b_code === node.b_code && child.name === node.name && child.unit === node.unit
+                && checkLeaf && (!check || check(child, node))) {
+                return child;
+            }
         }
         return null;
     }
@@ -50,11 +53,9 @@ class loadGclBaseTree {
      * @param {Object} parent - 父项
      * @returns {*}
      */
-    addNode(source, parent) {
-        if (source.b_code === '101') console.log('101 parent', parent);
+    addNode(source, parent, check) {
         parent = parent ? parent : this.parent;
-        let node = this.findNode(source, parent);
-        if (source.b_code === '101') console.log('101 cur', node);
+        let node = this.findNode(source, parent, check);
         if (!node) {
             if (!parent.children) parent.children = [];
             node = {
@@ -114,6 +115,7 @@ class updateReviseGclTree extends loadGclBaseTree {
     constructor (ctx, setting) {
         super(ctx, setting);
         this.baseNodes = [];
+        this.errors = [];
     }
     loadBase(datas) {
         datas.sort((x, y) => { return x.level === y.level ? x.order - y.order : x.level - y.level; });
@@ -151,7 +153,6 @@ class updateReviseGclTree extends loadGclBaseTree {
     }
     gather(source, parent) {
         const node = this.addNode(source, parent);
-        if (source.b_code === '207-2-1') console.log('207-2-1', node, source);
         node.sgfh_qty = this.ctx.helper.add(node.sgfh_qty, source.sgfh_qty);
         node.qtcl_qty = this.ctx.helper.add(node.qtcl_qty, source.qtcl_qty);
         node.sjcl_qty = this.ctx.helper.add(node.sjcl_qty, source.sjcl_qty);
@@ -187,6 +188,99 @@ class updateReviseGclTree extends loadGclBaseTree {
     }
 }
 
+class gatherStageGclTree extends loadGclBaseTree {
+    constructor (ctx, setting) {
+        super(ctx, setting);
+        this.baseNodes = [];
+    }
+    loadBase(datas) {
+        datas.sort((x, y) => { return x.level === y.level ? x.order - y.order : x.level - y.level; });
+        const Index = {};
+        for (const d of datas) {
+            const parent = this.parent.ledger_id === d.ledger_pid ? this.parent : Index[d.ledger_pid];
+            if (!parent) continue;
+
+            if (!parent.children) parent.children = [];
+            const baseNode = {
+                id: d.id,
+                ledger_id: d.ledger_id,
+                ledger_pid: d.ledger_pid,
+                level: d.level,
+                is_leaf: d.is_leaf,
+                full_path: d.full_path,
+                b_code: d.b_code,
+                name: d.name,
+                unit: d.unit,
+                unit_price: d.unit_price,
+                org_contract_qty: d.contract_qty || 0,
+                org_contract_tp: d.contract_tp || 0,
+                org_order: d.order,
+                contract_qty: 0,
+                contract_tp: 0,
+            };
+            parent.children.push(baseNode);
+            Index[baseNode.ledger_id] = baseNode;
+            this.baseNodes.push(baseNode);
+        }
+    }
+    _gatherChange(node, source) {
+        if (!source.change_detail || source.change_detail.length === 0) return;
+
+        if (!node.change_detail) node.change_detail = [];
+        for (const cd of source.change_detail) {
+            if (!cd.qty) continue;
+            let ncd = node.change_detail.find(x => { return x.cid === cd.cid; });
+            if (!ncd) {
+                ncd = { cid: cd.cid, c_code: cd.c_code };
+                node.change_detail.push(ncd);
+            }
+            ncd.qty = this.ctx.helper.add(ncd.qty, cd.qty);
+        }
+    }
+    gather(source, parent) {
+        parent = parent ? parent : this.parent;
+        const node = this.addNode(source, parent, function (node, source) {
+            return (source.is_tp && node.is_tp) || (!source.is_tp && !node.is_tp);
+        });
+        if (node.is_tp) {
+            node.contract_tp = this.ctx.helper.add(node.contract_tp, source.contract_tp);
+        } else {
+            node.contract_qty = this.ctx.helper.add(node.contract_qty, source.contract_qty);
+            node.contract_tp = this.ctx.helper.mul(node.unit_price, node.contract_qty, this.ctx.tender.info.decimal.tp);
+        }
+        this._gatherChange(node, source);
+        return node;
+    }
+    getUpdateData() {
+        const result = {update: [], errors: []};
+        for (const bn of this.baseNodes) {
+            if (bn.contract_qty !== bn.org_contract_qty || bn.contract_tp !== bn.org_contract_tp) {
+                result.update.push({lid: bn.id, contract_qty: bn.contract_qty, contract_tp: bn.contract_tp });
+            }
+            if (bn.change_detail && bn.change_detail.length > 0) {
+                for (const cd of bn.change_detail) {
+                    result.errors.push({
+                        b_code: bn.b_code, name: bn.name, unit: bn.unit,
+                        c_code: cd.c_code, qty: cd.qty
+                    });
+                }
+            }
+        }
+        for (const i of this.items) {
+            result.errors.push({ b_code: i.b_code, name: i.name, unit: i.unit, qty: i.qty });
+            if (i.change_detail && i.change_detail.length > 0) {
+                for (const cd of i.change_detail) {
+                    result.errors.push({
+                        b_code: i.b_code, name: i.name, unit: i.unit,
+                        c_code: cd.c_code, qty: cd.qty
+                    });
+                }
+            }
+        }
+        return result;
+    }
+}
+
 class sumLoad {
     constructor (ctx) {
         this.ctx = ctx;
@@ -250,6 +344,64 @@ class sumLoad {
         }
         return this.loadTree;
     }
+
+    _loadCurStageAndChange(billsData, curStageBills, curStageChange) {
+        const billsIndex = {};
+        for (const b of billsData) {
+            billsIndex[b.id] = b;
+        }
+        for (const csb of curStageBills) {
+            const b = billsIndex[csb.lid];
+            if (!b) continue;
+            b.contract_qty = csb.contract_qty;
+            b.contract_tp = csb.contract_tp;
+        }
+        for (const csc of curStageChange) {
+            if (!csc.qty) continue;
+
+            const b = billsIndex[csc.lid];
+            if (!b) continue;
+            if (!b.change_detail) b.change_detail = [];
+            let c = b.change_detail.find(x => { return x.cid === csc.cid });
+            if (!c) {
+                c = { cid: csc.cid };
+                b.change_detail.push(c);
+            }
+            c.qty = this.ctx.helper.add(c.qty, csc.qty);
+        }
+    }
+
+    async stageGatherGcl(select, maxId, tenders, defaultData) {
+        this.loadTree = new gatherStageGclTree(this.ctx, {
+            parent: select, maxId, type: 'ledger', defaultData,
+        });
+        const posterity = await this.ctx.service.ledger.getPosterityByParentId(this.ctx.tender.id, select.ledger_id);
+        this.loadTree.loadBase(posterity);
+
+        for (const tender of tenders) {
+            const billsData = await this.ctx.service.ledger.getData(tender.tid);
+            const stage = await this.ctx.service.stage.getDataByCondition({tid: tender.tid, order: tender.stage});
+            if (!stage) throw '选择的期不存在';
+            const curStageData = await this.ctx.service.stageBills.getLastestStageData(tender.tid, stage.id);
+            const curStageChange = await this.ctx.service.stageChangeFinal.getSumLoadFinalData({tid: tender.tid, sid: stage.id});
+            this._loadCurStageAndChange(billsData, curStageData, curStageChange);
+            const billsTree = 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',
+            });
+            billsTree.loadDatas(billsData);
+            for (const top of billsTree.children) {
+                if ([1].indexOf(top.node_type) < 0) continue;
+                this.recusiveLoadGatherGcl(top, null);
+            }
+        }
+        return this.loadTree;
+    }
 }
 
 module.exports = sumLoad;

+ 1 - 0
app/middleware/material_check.js

@@ -80,6 +80,7 @@ module.exports = options => {
                 } else {
                     material.curOrder = material.curAuditor.order;
                 }
+                material.filePermission = this.tender.touristPermission.file || auditorIds.indexOf(accountId) !== -1;
             } else if (auditorIds.indexOf(accountId) !== -1) { // 审批人
                 if (material.status === status.uncheck) {
                     throw '您无权查看该数据';

+ 1 - 0
app/middleware/stage_check.js

@@ -94,6 +94,7 @@ module.exports = options => {
                 } else {
                     stage.curOrder = stage.curAuditor.order;
                 }
+                stage.filePermission = this.tender.touristPermission.file || auditorIds.indexOf(accountId) !== -1;
             } else if (auditorIds.indexOf(accountId) !== -1) { // 审批人
                 if (stage.status === status.uncheck) {
                     throw '您无权查看该数据';

+ 2 - 0
app/middleware/tender_check.js

@@ -64,6 +64,8 @@ module.exports = options => {
             const isTenderTourist = yield this.service.tenderTourist.getDataByCondition({ tid: tender.id, user_id: accountId });
             // 判断访问人是否具有游客身份
             tender.isTourist = isTenderTourist !== null;
+            // 游客权限
+            tender.touristPermission = yield this.service.tenderTourist.getTouristPermission(isTenderTourist);
             if (auditorsId.indexOf(accountId) === -1 && tender.data.user_id !== accountId &&
                 (tenderPermission === null || tenderPermission === undefined || tenderPermission.indexOf('2') === -1) &&
                 stageAuditorsId.indexOf(accountId) === -1 && changeAuditorsId.indexOf(accountId) === -1 &&

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

@@ -81,7 +81,7 @@ $(document).ready(() => {
             formData.append('size', filesize);
             formData.append('file[]', file);
         }
-        if (auditList.findIndex(item => item.uid === parseInt(accountId)) === -1) {
+        if (auditList.findIndex(item => item.uid === parseInt(accountId)) === -1 && !touristPermission) {
             return toastr.error('暂无权限上传!');
         }
         postDataWithFile(window.location.pathname + '/file/upload', formData, function (data) {

+ 3 - 4
app/public/js/ledger.js

@@ -1603,7 +1603,7 @@ $(document).ready(function() {
         };
         billsContextMenuOptions.items.importGclBills2Xmj = {
             name: '导入(其他标段)工程量清单至项目节',
-            icon: 'fa-file-excel-o',
+            icon: 'fa-link',
             disabled: function (key, opt) {
                 const node = SpreadJsObj.getSelectObject(ledgerSpread.getActiveSheet());
                 return readOnly || !node
@@ -2359,7 +2359,7 @@ $(document).ready(function() {
         if (!tab.hasClass('active')) {
             // const close = $('.active', '#side-menu').length === 0;
             $('a', '#side-menu').removeClass('active');
-            $('.tab-content .tab-pane.active').removeClass('active');
+            $('.tab-content .tab-select-show.tab-pane.active').removeClass('active');
             tab.addClass('active');
             tabPanel.addClass('active');
             // $('.tab-content .tab-pane').removeClass('active');
@@ -2436,10 +2436,10 @@ $(document).ready(function() {
             } else if (tab.attr('content') === '#check-list') {
                 checkList.spread.refresh();
             } else if (tab.attr('content') === '#fujian') {
-              $('#dqjiedian').addClass('active')
               $('#showAttachment').hide()
               const node = SpreadJsObj.getSelectObject(ledgerSpread.getActiveSheet());
               getNodeList(node.id);
+              getAllList();
             }
         } else { // 收起工具栏
             tab.removeClass('active');
@@ -3722,7 +3722,6 @@ function getAllList(currPageNum = 1) {
       </div>
       </td><td>${att.username}</td></tr>`
   }
-  console.log(attData);
   $('#alllist-table').html(html);
   $('#alllist-table').on('click', 'tr', function() {
       $('#alllist-table tr').removeClass('bg-light')

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

@@ -1268,7 +1268,7 @@ $(document).ready(() => {
         });
         billsContextMenuOptions.items.importGclBills2Xmj = {
             name: '更新(其他标段)工程量清单至项目节',
-            icon: 'fa-file-excel-o',
+            icon: 'fa-link',
             disabled: function (key, opt) {
                 const node = SpreadJsObj.getSelectObject(billsSheet);
                 return readOnly || !node || (!_.isNil(node.b_code) && node.b_code !== '');

+ 21 - 1
app/public/js/shares/tender_select.js

@@ -20,6 +20,8 @@ const TenderSelect = function (setting) {
                     return items;
                 };
                 for (let i = 0; i < tsObj.resultSheet.getRowCount(); i++) {
+                    const items = getItems(tsObj.trArray[i]);
+                    console.log(items);
                     const cellType2 = new spreadNS.CellTypes.ComboBox().itemHeight(10).editorValueType(spreadNS.CellTypes.EditorValueType.value).items(getItems(tsObj.trArray[i]));
                     tsObj.resultSheet.getCell(i, 1).cellType(cellType2);
                 }
@@ -144,6 +146,13 @@ const TenderSelect = function (setting) {
                 headerFont: '12px 微软雅黑',
                 font: '12px 微软雅黑',
                 headColWidth: [],
+                getColor: function (sheet, data, row, col, defaultColor) {
+                    if (data) {
+                        return data.invalid ? '#ddd' : defaultColor;
+                    } else {
+                        return defaultColor;
+                    }
+                }
             };
             if (this.setting.type === 'ledger' || this.setting.type === 'revise') {
                 resultSpreadSetting.cols.push(
@@ -173,10 +182,21 @@ const TenderSelect = function (setting) {
         },
         resetSelect: function () {
             tsObj.trArray.length = 0;
-            if (tsObj.trHistory.tenders) tsObj.trArray.push(...tsObj.trHistory.tenders);
+            if (tsObj.trHistory.tenders) {
+                for (const trh of tsObj.trHistory.tenders) {
+                    const source = tsObj.tenderSourceTree.nodes.find(x => { return x.tid === trh.tid; });
+                    if (source) {
+                        trh.stageCount = source.stageCount;
+                    } else {
+                        trh.invalid = true;
+                    }
+                    tsObj.trArray.push(trh);
+                }
+            }
             tsObj._initSelected();
             SpreadJsObj.loadSheetData(tsObj.tenderSheet, SpreadJsObj.DataType.Tree, tsObj.tenderSourceTree);
             SpreadJsObj.loadSheetData(tsObj.resultSheet, SpreadJsObj.DataType.Data, tsObj.trArray);
+            tsObj._rebuildStageSelect();
             $('#tender-select-hint').hide();
         }
     };

+ 13 - 5
app/public/js/stage.js

@@ -181,7 +181,6 @@ function getHintMsg () {
 
 
 $(document).ready(() => {
-    const tenderSelect = TenderSelect({type: 'stage'});
     const exportExcelSetting = {
         cols: [
             {title: '项目节编号', colSpan: '1', rowSpan: '2', field: 'code', hAlign: 0, width: 145, formatter: '@', cellType: 'tree'},
@@ -1440,6 +1439,18 @@ $(document).ready(() => {
     }
     stageTreeSpreadObj.loadExprToInput(slSpread.getActiveSheet());
     const addTag = newTag({ledgerSheet: slSpread.getActiveSheet(), billsTag});
+    const tenderSelect = TenderSelect({
+        type: 'stage',
+        afterLoad: function (result) {
+            const nodes = stageTree.loadPostStageData(result);
+            stageTreeSpreadObj.refreshTreeNodes(slSpread.getActiveSheet(), nodes);
+            if (detail) {
+                detail.loadStageLedgerUpdateData(result, nodes);
+            } else {
+                stageIm.loadUpdateLedgerData(result, nodes);
+            }
+        }
+    });
     $.contextMenu({
         selector: '#stage-ledger',
         build: function ($trigger, e) {
@@ -1521,16 +1532,13 @@ $(document).ready(() => {
             importSpr: '---',
             importStageGcl: {
                 name: '导入(其他标段)工程量清单计量数据',
-                icon: 'fa-file-excel-o',
+                icon: 'fa-link',
                 disabled: function (key, opt) {
                     const node = SpreadJsObj.getSelectObject(slSpread.getActiveSheet());
                     return readOnly || !node || (!_.isNil(node.b_code) && node.b_code !== '');
                 },
                 callback: function (key, opt) {
                     tenderSelect.showSelect(SpreadJsObj.getSelectObject(slSpread.getActiveSheet()));
-                },
-                visible: function (key, opt) {
-                    return !readOnly;
                 }
             },
         }

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

@@ -34,7 +34,7 @@ function makeAttTable(payNode) {
     let html = '';
     if (attachment !== null) {
         for (const [index, att] of attachment.entries()) {
-            const delhtml = !readOnly && uploadPermission && (parseInt(att.uid) === userID || payNode.uid === userID || (payNode.uid === -1 && userID === stage.user_id))
+            const delhtml = uploadPermission && (parseInt(att.uid) === userID || payNode.uid === userID || (payNode.uid === -1 && userID === stage.user_id))
                 ? '<a class="delete-att text-danger" href="javascript:void(0);" data-payid="'+ id +'" data-attindex="'+ index +'" title="删除"><i class="fa fa-remove "></i></a>'
                 : '';
             html += '<tr><td style="width: 200px">' + att.filename + att.fileext + '</td><td>' + att.username + '</td><td>' + att.in_time + '</td>' +

+ 16 - 8
app/public/report/js/rpt_custom.js

@@ -269,13 +269,16 @@ const rptCustomObj = (function () {
 
         // 初始化
         if (resolve) {
-            setTimeout(() => { $("#gather-select").modal('show'); }, 500);
+            setTimeout(() => { $("#gather-select").modal('show'); }, 1000);
         } else {
             $("#gather-select").modal('show');
         }
 
         $('#gather-select-ok').unbind('click');
-        $('#gather-select-ok').bind('click', () => {rptCustomObj.resetGatherSelect(resolve);});
+        $('#gather-select-ok').bind('click', () => {
+            rptCustomObj.resetGatherSelect(resolve);
+            // $("#gather-select").modal('hide');
+        });
     };
     const initStageSelect = function (gsSetting, gsSelect, rptName, resolve = null) {
         const setting = JSON.parse(gsSetting);
@@ -292,13 +295,16 @@ const rptCustomObj = (function () {
             }
         }
         if (resolve) {
-            setTimeout(() => { $("#stage-select").modal('show'); }, 500);
+            setTimeout(() => { $("#stage-select").modal('show'); }, 1000);
         } else {
             $("#stage-select").modal('show');
         }
 
         $('#stage-select-ok').unbind('click');
-        $('#stage-select-ok').bind('click', () => {rptCustomObj.resetStageSelect(resolve);});
+        $('#stage-select-ok').bind('click', () => {
+            rptCustomObj.resetStageSelect(resolve);
+            // $("#stage-select").modal('hide');
+        });
     };
     const init = function (cDefine, sfData, cSelect, rptName, resolve = null) {
         stageFlow = sfData;
@@ -721,9 +727,10 @@ const rptCustomObj = (function () {
                     params.customSelect.push(data);
                 } else {
                     const chkNode = chkNodes.find(function (x) { return x.refId === rptId});
-                    params.customSelect.push(await comfirmSelectPromise(chkNode ? chkNode.name : '', gather_select));
+                    const select = await comfirmSelectPromise(chkNode ? chkNode.name : '', gather_select)
+                    params.customSelect.push(select);
+                    $('#gather-select').modal('hide');
                 }
-                $('#gather-select').modal('hide');
             } else if (stage_select && stage_select.custom_define && stage_select.custom_define[sStageSelect].enable) {
                 if (rptId === currentRptId) {
                     const data = {};
@@ -731,9 +738,10 @@ const rptCustomObj = (function () {
                     params.customSelect.push(data);
                 } else {
                     const chkNode = chkNodes.find(function (x) { return x.refId === rptId});
-                    params.customSelect.push(await comfirmSelectPromise(chkNode ? chkNode.name : '', stage_select));
+                    const select = await comfirmSelectPromise(chkNode ? chkNode.name : '', stage_select);
+                    params.customSelect.push(select);
+                    $('#stage-select').modal('hide');
                 }
-                $('#stage-select').modal('hide');
             } else {
                 params.customSelect.push(null);
             }

+ 22 - 0
app/service/stage_bills.js

@@ -10,6 +10,7 @@
 const calcFields = ['contract_qty', 'qc_qty'];
 const auditConst = require('../const/audit');
 const timesLen = auditConst.stage.timesLen;
+const SumLoad = require('../lib/sum_load');
 
 module.exports = app => {
     class StageBills extends app.BaseService {
@@ -475,6 +476,27 @@ module.exports = app => {
             }
             return { contract_tp, qc_tp };
         }
+
+        async sumLoad(lid, tender) {
+            const conn = await this.db.beginTransaction();
+            try {
+                const maxId = await this._getMaxLid(this.ctx.tender.id);
+                const select = await this.getDataById(lid);
+                const sumLoad = new SumLoad(this.ctx);
+                const loadTree = await sumLoad.stageGatherGcl(select, maxId, tenders);
+                const result = loadTree.getUpdateData();
+
+                this._cacheMaxLid(this.ctx.tender.id, loadTree.keyNodeId);
+                await this.ctx.service.sumLoadHistory.saveReviseHistory(this.ctx.tender.id, rid, lid, tenders, result.errors);
+                if (result.update.length > 0) await conn.updateRows(this.tableName, result.update);
+                if (result.create.length > 0)await conn.insert(this.tableName, result.create);
+                await conn.commit();
+                return result;
+            } catch (err) {
+                await conn.rollback();
+                throw (err.stack ? err : '导入工程量数据出错');
+            }
+        }
     }
 
     return StageBills;

+ 9 - 0
app/service/stage_change_final.js

@@ -82,6 +82,15 @@ module.exports = app => {
             }
             await transaction.delete(this.tableName, { tid: tender.id, sid: stage.id });
         }
+
+        async getSumLoadFinalData(sid) {
+            const sql = 'Select cf.lid, cf.cid, sum(cf.qty) as qty, c.code As c_code' +
+                '  FROM ' + this.tableName + ' cf' +
+                '  Left Join ' + this.ctx.service.change.tableName + ' c ON cf.cid = c.cid' +
+                '  Where cf.sid = ?' +
+                '  Group By cf.lid, cf.cid';
+            return await this.db.query(sql, [sid]);
+        }
     }
 
     return StageChangeFinal;

+ 20 - 1
app/service/tender_tourist.js

@@ -7,7 +7,7 @@
  * @date 2021/4/8
  * @version
  */
-
+const touristPermissionConst = require('../const/tourist_permission').defaultPermission;
 module.exports = app => {
 
     class TenderTourist extends app.BaseService {
@@ -60,6 +60,25 @@ module.exports = app => {
                 throw err;
             }
         }
+
+        async getTouristPermission(info) {
+            if (info && info.permission) {
+                return JSON.parse(info.permission);
+            }
+            return touristPermissionConst;
+        }
+
+        async setPermission(data) {
+            const transaction = await this.db.beginTransaction();
+            try {
+                await transaction.update(this.tableName, { id: data.id, permission: JSON.stringify(data.permission) });
+                await transaction.commit();
+                return true;
+            } catch (err) {
+                await transaction.rollback();
+                throw err;
+            }
+        }
     }
 
     return TenderTourist;

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

@@ -96,7 +96,7 @@
                             <!--所有附件 翻页-->
                             <a href="javascript: void(0);" data-toggle="modal" class="btn btn-sm btn-primary" id="bach-download"><i class="fa fa-download "></i> 批量下载</a>
                             <a href="javascript:void(0);" class="page-select ml-3" content="pre"><i class="fa fa-chevron-left"></i></a> <span id="currentPage">1</span>/<span id="totalPage">10</span> <a href="javascript:void(0);" class="page-select mr-3" content="next"><i class="fa fa-chevron-right"></i></a>
-                            <% if (auditStatus !== 8) { %>
+                            <% if (auditStatus !== 8 || (auditStatus === 8 && ctx.tender.touristPermission.file)) { %>
                             <a href="#addfujian" data-toggle="modal" class="btn btn-sm btn-light text-primary" data-placement="bottom" title="" data-original-title="上传附件"><i class="fa fa-cloud-upload" aria-hidden="true"></i> 上传附件</a>
                             <% } %>
                             <a href="" id="downloadZip" style="display: none;" download></a>
@@ -388,6 +388,7 @@
     const ledgeStatus = '<%- tender.ledger_status %>';
     const ledgerConsts = JSON.parse('<%- JSON.stringify(ledgerConsts) %>');
     const auditStatus = parseInt('<%- auditStatus %>');
+    const touristPermission = parseInt('<%- ctx.tender.touristPermission.file %>');
     const auditList = JSON.parse(unescape('<%- escape(JSON.stringify(auditList)) %>'));
     const precision = JSON.parse('<%- JSON.stringify(precision) %>');
     const whiteList = JSON.parse('<%- JSON.stringify(whiteList) %>');

+ 8 - 8
app/view/ledger/explode.ejs

@@ -108,9 +108,9 @@
             <div class="c-body" id="right-view" style="display: none; width: 33%;">
                 <div class="resize-x" id="right-spr" r-Type="width" div1="#left-view" div2="#right-view" title="调整大小" a-type="percent"><!--调整左右高度条--></div>
                 <div class="tab-content">
-                    <div id="search" class="tab-pane">
+                    <div id="search" class="tab-pane tab-select-show">
                     </div>
-                    <div id="std-xmj" class="tab-pane">
+                    <div id="std-xmj" class="tab-pane tab-select-show">
                         <div class="sjs-bar-2">
                             <div class="pb-1">
                                 <select class="form-control form-control-sm">
@@ -123,7 +123,7 @@
                         <div id="std-xmj-spread" class="sjs-sh-2">
                         </div>
                     </div>
-                    <div id="std-gcl" class="tab-pane">
+                    <div id="std-gcl" class="tab-pane tab-select-show">
                         <div class="sjs-bar-3">
                             <div class="pb-1">
                                 <select class="form-control form-control-sm">
@@ -136,7 +136,7 @@
                         <div id="std-gcl-spread" class="sjs-sh-3">
                         </div>
                     </div>
-                    <div id="deal-bills" class="tab-pane">
+                    <div id="deal-bills" class="tab-pane tab-select-show">
                         <div class="sjs-bar-4">
                             <div class="pb-1">
                                 <% if (dealBillsPermission) { %>
@@ -150,13 +150,13 @@
                         <div id="deal-bills-spread" class="sjs-sh-4">
                         </div>
                     </div>
-                    <div id="bills-tag" class="tab-pane">
+                    <div id="bills-tag" class="tab-pane tab-select-show">
                     </div>
-                    <div id="error-list" class="tab-pane">
+                    <div id="error-list" class="tab-pane tab-select-show">
                     </div>
-                    <div id="check-list" class="tab-pane">
+                    <div id="check-list" class="tab-pane tab-select-show">
                     </div>
-                    <div id="fujian" class="tab-pane">
+                    <div id="fujian" class="tab-pane tab-select-show">
                       <div class="sjs-bar">
                           <ul class="nav nav-tabs">
                               <li class="nav-item">

+ 1 - 1
app/view/material/file.ejs

@@ -13,7 +13,7 @@
           </div>
         </div>
         <div class="d-inline-block">
-          <% if (!ctx.tender.isTourist && material.filePermission) { %>
+          <% if (material.filePermission) { %>
           <a href="#addfujian" data-toggle="modal" class="btn btn-sm btn-light text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="添加清单"><i class="fa fa-cloud-upload" aria-hidden="true"></i> 上传附件</a>
           <% } %>
           <a href="javascript: void(0);" data-toggle="modal" class="btn btn-sm btn-light text-primary" id="bach-download"><i class="fa fa-download "></i> 批量下载</a>

+ 1 - 1
app/view/stage/index.ejs

@@ -276,7 +276,7 @@
                                     <!-- <% if (!ctx.tender.isTourist && stage.filePermission) { %>
                                     <a href="#upload" data-toggle="modal" data-target="#upload"  class="btn btn-sm btn-outline-primary ml-3">上传</a>
                                     <% } %> -->
-                                    <% if (!ctx.tender.isTourist) { %>
+                                    <% if (!ctx.tender.isTourist || (ctx.tender.isTourist && ctx.tender.touristPermission.file) || stage.filePermission) { %>
                                     <a href="#upload" data-toggle="modal" data-target="#upload"  class="btn btn-sm btn-outline-primary ml-3">上传</a>
                                     <% } %>
                                 </li>

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

@@ -521,3 +521,4 @@
 <% include ../shares/merge_peg_modal.ejs %>
 <% include ../shares/check_modal2.ejs %>
 <% include ../shares/new_tag_modal.ejs %>
+<% include ../shares/tender_select_modal.ejs %>

+ 3 - 1
app/view/stage_extra/bonus_modal.ejs

@@ -6,10 +6,12 @@
                 <h5 class="modal-title">附件</h5>
             </div>
             <div class="modal-body">
+                <% if (ctx.stage.filePermission) { %>
                 <div class="form-group" id="upload-file-panel">
                     <label for="formGroupExampleInput">大小限制:30MB,支持<span data-toggle="tooltip" data-placement="bottom" title="doc,docx,xls,xlsx,ppt,pptx,pdf">office等文档格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="jpg,png,bmp">图片格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="rar,zip">压缩包格式</span></label>
                     <input type="file" class="" id="upload-file" multiple>
                 </div>
+                <% } %>
                 <div class="modal-height-500" style="overflow:auto;">
                     <table class="table table-sm table-bordered" style="word-break:break-all; table-layout: fixed">
                         <thead>
@@ -31,4 +33,4 @@
             </div>
         </div>
     </div>
-</div>
+</div>

+ 67 - 17
app/view/tender/detail_modal.ejs

@@ -1708,17 +1708,34 @@
                         </dl>
                     </div>
                 </div>
-                <div class="card mt-3">
-                    <div class="card-header">
-                        游客列表
-                    </div>
-                    <div class="modal-height-300">
-                        <ul class="list-group list-group-flush" id="tourist-users">
+                <div class="mt-3">
+                    <!-- <div class="card-header">
+                      游客列表
+                    </div> -->
+                    <div class="">
+                        <table class="table table-bordered">
+                            <tr><th>用户</th><th>附件</th><th >书签</th><th>设置</th></tr>
+                            <tbody id="tourist-users">
                             <% for (const t of tourists) { %>
-                                <li class="list-group-item"  data-id="<%- t.user_id %>">
-                                    <a href="javascript:void(0);" class="text-danger pull-right remove-tourist-user" data-id="<%- t.id %>">移除</a><%- t.user_name %>  <small class="text-muted"><%- t.user_role %></small><p class="m-0 ml-2"><small class="text-muted"><%- t.user_company %></small></p></li>
+                                <tr data-id="<%- t.user_id %>">
+                                    <td><b class="col-3 pl-0"><%- t.user_name %></b></td>
+                                    <td>
+                                        <div class="custom-control custom-checkbox mb-2">
+                                            <input type="checkbox" id="<%- t.id %>_file" data-id="<%- t.id %>" name="file" class="custom-control-input set-tourist-permission" <% if(t.permission.file) { %>checked<% } %>>
+                                            <label class="custom-control-label" for="<%- t.id %>_file"></label>
+                                        </div>
+                                    </td>
+                                    <td>
+                                        <div class="custom-control custom-checkbox mb-2">
+                                            <input type="checkbox" id="<%- t.id %>_tag" data-id="<%- t.id %>" name="tag" class="custom-control-input set-tourist-permission" <% if(t.permission.tag) { %>checked<% } %>>
+                                            <label class="custom-control-label" for="<%- t.id %>_tag"></label>
+                                        </div>
+                                    </td>
+                                    <td><a href="javascript:void(0);" data-id="<%- t.id %>" class="text-danger remove-tourist-user">移除</a></td>
+                                </tr>
                             <% } %>
-                        </ul>
+                            </tbody>
+                        </table>
                     </div>
                 </div>
             </div>
@@ -1857,8 +1874,8 @@
                     return item.id === id;
                 });
                 const saIdList = [];
-                for (let i = 0; i < $('#tourist-users li').length; i++) {
-                    saIdList.push(parseInt($('#tourist-users li').eq(i).data('id')));
+                for (let i = 0; i < $('#tourist-users tr').length; i++) {
+                    saIdList.push(parseInt($('#tourist-users tr').eq(i).data('id')));
                 }
                 if (_.includes(saIdList, id)) {
                     toastr.error('该用户已存在列表中,无需重复添加');
@@ -1870,12 +1887,28 @@
                     type: 'add',
                 };
                 postData('/tender/' + cur_tenderid + '/tourist/audit/save', prop, function (data) {
-                    const html = '<li class="list-group-item"  data-id="' + user.id + '">\n' +
-                        '<a href="javascript:void(0);" class="text-danger pull-right remove-tourist-user" data-id="' + data.id + '">移除</a>' + user.name + '  ' +
-                        '<small class="text-muted">' + user.role + '</small><p class="m-0 ml-2"><small class="text-muted">' + user.company + '</small></p></li>';
+                    // const html = '<li class="list-group-item"  data-id="' + user.id + '">\n' +
+                    //     '<a href="javascript:void(0);" class="text-danger pull-right remove-tourist-user" data-id="' + data.id + '">移除</a>' + user.name + '  ' +
+                    //     '<small class="text-muted">' + user.role + '</small><p class="m-0 ml-2"><small class="text-muted">' + user.company + '</small></p></li>';
+                    const html = '<tr data-id="' + user.id + '">\n' +
+                        '                                    <td><b class="col-3 pl-0">' + user.name + '</b></td>\n' +
+                        '                                    <td>\n' +
+                        '                                        <div class="custom-control custom-checkbox mb-2">\n' +
+                        '                                            <input type="checkbox" id="'+ data.id +'_file" data-id="'+ data.id +'" name="file" class="custom-control-input set-tourist-permission">\n' +
+                        '                                            <label class="custom-control-label" for="'+ data.id +'_file"></label>\n' +
+                        '                                        </div>\n' +
+                        '                                    </td>\n' +
+                        '                                    <td>\n' +
+                        '                                        <div class="custom-control custom-checkbox mb-2">\n' +
+                        '                                            <input type="checkbox" id="'+ data.id +'_tag" data-id="'+ data.id +'" name="tag" class="custom-control-input set-tourist-permission">\n' +
+                        '                                            <label class="custom-control-label" for="'+ data.id +'_tag"></label>\n' +
+                        '                                        </div>\n' +
+                        '                                    </td>\n' +
+                        '                                    <td><a href="javascript:void(0);" data-id="' + data.id + '" class="text-danger remove-tourist-user">移除</a></td>\n' +
+                        '                                </tr>';
                     $('#tourist-users').append(html);
                     // 外面显示游客数量
-                    const num = $('#tourist-users li').length;
+                    const num = $('#tourist-users tr').length;
                     if (!$('#tourist-num').hasClass('badge')) {
                         $('#tourist-num').addClass('badge badge-secondary').text(num);
                     } else {
@@ -1895,9 +1928,9 @@
                 };
                 const _self = $(this);
                 postData('/tender/' + cur_tenderid + '/tourist/audit/save', prop, function (data) {
-                    _self.parents('li').remove();
+                    _self.parents('tr').remove();
                     // 外面显示游客数量
-                    const num = $('#tourist-users li').length;
+                    const num = $('#tourist-users tr').length;
                     if (num == 0) {
                         $('#tourist-num').removeClass('badge badge-secondary').text('');
                     } else {
@@ -1906,6 +1939,23 @@
                 });
             }
         });
+
+        // 权限设置
+        $('body').on('click', '#tourist-users .set-tourist-permission', function () {
+            const id = parseInt($(this).data('id'));
+            const permission = {
+                file: ($(this).attr('name') === 'file' ? $(this).is(':checked') : $('#' + id + '_file').is(':checked')) ? 1 : 0,
+                tag: ($(this).attr('name') === 'tag' ? $(this).is(':checked') : $('#' + id + '_tag').is(':checked')) ? 1 : 0,
+            }
+            const prop = {
+                id,
+                type: 'permission',
+                permission,
+            }
+            console.log(prop);
+            postData('/tender/' + cur_tenderid + '/tourist/audit/save', prop, function (data) {
+            });
+        });
     });
 </script>
 <% } %>

+ 1 - 1
build_min.js

@@ -43,7 +43,7 @@ fs.writeFileSync(needMinFileName, Uglyfy.minify(needMinCode, { mangle: true }).c
 
 const needVersionCss = ['/public/css/main'];
 for (const nvc of needVersionCss) {
-    fs.copyFileSync(nvc + '.css', nvc + '.' + version + '.css');
+    fs.copyFileSync(__dirname + '/app' + nvc + '.css', __dirname + '/app' + nvc + '.' + version + '.css');
 }
 
 

+ 3 - 3
config/config.uat.js

@@ -17,9 +17,9 @@ module.exports = appInfo => {
             // 端口号
             port: '3306',
             // 用户名
-            user: 'smartcost',
+            user: 'zh_calc',
             // 密码
-            password: 'zongheng_@)!(_jlzf',
+            password: 'zh@)!(3850calc',
             // 数据库名
             database: 'calculation',
             multipleStatements: true,
@@ -37,7 +37,7 @@ module.exports = appInfo => {
         client: {
             host: '127.0.0.1',
             port: '6379',
-            password: 'zongheng_@)!(_jlzf',
+            password: 'zh@)!(3850calc',
             db: '0',
         },
         agent: true,

+ 15 - 0
dev4qadx.js

@@ -0,0 +1,15 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Mai
+ * @date
+ * @version
+ */
+
+const fs = require('fs');
+const packageJSON = JSON.parse(fs.readFileSync(__dirname + '/package.json', 'utf8'));
+packageJSON.name = 'calc_dx' ;
+packageJSON.scripts['start-qadx'] = "egg-scripts start --daemon --port 7006";
+fs.writeFileSync(__dirname + '/package.json', JSON.stringify(packageJSON, '', '\t'));

+ 3 - 0
sql/update.sql

@@ -27,3 +27,6 @@ CREATE TABLE `zh_ledger_attachment` (
   `in_time` VARCHAR(15) NOT NULL COMMENT '创建时间',
   `extra_upload` TINYINT(1) NOT NULL DEFAULT '0' COMMENT '是否为审核通过后再次上传的文件,0为否',
   PRIMARY KEY (`id`));
+
+
+ALTER TABLE `zh_tender_tourist` ADD `permission` VARCHAR(1000) NULL DEFAULT NULL COMMENT '游客权限JSON格式' AFTER `user_id`;

+ 14 - 0
sql/update20210715.sql

@@ -0,0 +1,14 @@
+CREATE TABLE `calculation`.`zh_rpt_archive_encryption` (
+  `id` INT NOT NULL AUTO_INCREMENT,
+  `prj_id` INT NULL,
+  `stage_id` INT NULL,
+  `content` JSON NULL,
+  PRIMARY KEY (`id`),
+  INDEX `PRJ_STG` (`prj_id` ASC, `stage_id` ASC))
+COMMENT = '归档文档的需要加密签名的坐标及其他key信息(如签名角色id,签名角色名称等)';
+
+ALTER TABLE `zh_material_list` ADD `expr` VARCHAR(500) NULL DEFAULT '' COMMENT '公式' AFTER `quantity`;
+
+ALTER TABLE `zh_s2b_proj`
+ADD COLUMN `gxby_ratio_valid`  tinyint(1) NULL DEFAULT 0 COMMENT '工序报验,ratio是否生效' AFTER `gxby_status`,
+ADD COLUMN `dagl_ratio_valid`  tinyint(1) NOT NULL DEFAULT 1 COMMENT '工序报验,ratio是否生效' AFTER `dagl_status`;