浏览代码

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

Tony Kang 2 年之前
父节点
当前提交
0d0b67d3d3

+ 4 - 4
app/controller/stage_controller.js

@@ -247,9 +247,6 @@ module.exports = app => {
 
         async _getStageLedgerData(ctx, ledgerColumn) {
             // const ledgerData = ctx.stage.ledgerHis
-            //     ? await ctx.helper.loadLedgerDataFromOss(ctx.stage.ledgerHis.bills_file)
-            //     : await ctx.service.ledger.getAllDataByCondition({ where: { tender_id: ctx.tender.id } });
-            // const ledgerData = ctx.stage.ledgerHis
             //     ? await ctx.service.ledger.loadDataFromOss(ctx.tender.id, ctx.stage.ledgerHis.bills_file)
             //     : await ctx.service.ledger.getAllDataByCondition({ columns: ledgerColumn, where: { tender_id: ctx.tender.id } });
             const ledgerData = await ctx.service.ledger.getAllDataByCondition({ columns: ledgerColumn, where: { tender_id: ctx.tender.id } });
@@ -2103,11 +2100,14 @@ module.exports = app => {
 
         async importStageSheet(ctx) {
             try {
+                if (!ctx.stage.status === auditConst.status.uncheck) throw '仅新增期且未上报时,可从暂存计量中导入数据';
+
                 const compressData = ctx.request.body.data;
                 const data = JSON.parse(LzString.decompressFromUTF16(compressData));
-
+                await ctx.service.stageStash.loadExcelSheet(ctx.stage, data.sheet);
                 await ctx.service.stage.updateCheckCalcFlag(ctx.stage, true);
                 await ctx.service.stage.updateCacheTime(ctx.stage.id);
+                ctx.body = { err: 0, msg: '', data: null };
             } catch (err) {
                 ctx.log(err);
                 ctx.ajaxErrorBody(err, '导入计量台账数据错误');

+ 40 - 1
app/controller/tender_controller.js

@@ -532,7 +532,7 @@ module.exports = app => {
                 ];
                 // 地图
                 const tenderALLInfo = await ctx.service.tender.getDataById(tender.id);
-                const hadMap = tenderALLInfo.had_map === 1 ? 0 : 1;
+                const hadMap = tenderALLInfo.had_map === 0 ? 1 : tenderALLInfo.had_map;// 0为初始值,因为默认可能会变化,所以暂时把0都默认为1。共三种模式坐标模式1,图片模式2,无图模式3。
                 const tenderMapList = await ctx.service.tenderMap.getAllDataByCondition({ where: { tid: tender.id } });
                 // 默认坐标,否则则取办事处坐标
                 const projectData = await ctx.service.project.getDataById(ctx.session.sessionProject.id);
@@ -571,10 +571,12 @@ module.exports = app => {
                     // reviseNum,
                     stage_total,
                     hadMap,
+                    map_pic: tenderALLInfo.map_pic,
                     jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.tender.tenderInfo),
                     gclChapter,
                     tenderMapList,
                     map_json,
+                    fujianOssPath: ctx.app.config.fujianOssPath,
                 };
                 if (ctx.session.sessionUser.is_admin) {
                     renderData.tourists = await ctx.service.tenderTourist.getTourists(tender.id);
@@ -1367,6 +1369,43 @@ module.exports = app => {
             }
         }
 
+        /**
+         * 上传静态图
+         *
+         * @param {object} ctx - egg全局变量
+         * @return {void}
+         */
+        async uploadMap(ctx) {
+            const responseData = {
+                err: 0, msg: '', data: null,
+            };
+            try {
+                const stream = await ctx.getFileStream();
+                const create_time = Date.parse(new Date()) / 1000;
+                const fileInfo = path.parse(stream.filename);
+                const filepath = `app/public/upload/${ctx.tender.id}/map/${create_time}${fileInfo.ext}`;
+                await ctx.app.fujianOss.put(ctx.app.config.fujianOssFolder + filepath, stream);
+                await sendToWormhole(stream);
+                const tenderInfo = await ctx.service.tender.getDataById(ctx.tender.id);
+                const oldMapPic = tenderInfo && tenderInfo.map_pic ? tenderInfo.map_pic : null;
+                const result = await ctx.service.tender.update({ map_pic: filepath }, { id: ctx.tender.id });
+                if (result) {
+                    // 移除旧的map_pic oss
+                    if (oldMapPic) {
+                        await ctx.app.fujianOss.delete(ctx.app.config.fujianOssFolder + oldMapPic);
+                    }
+                    responseData.data = { map_pic: filepath };
+                } else {
+                    throw '添加数据库失败';
+                }
+            } catch (err) {
+                this.log(err);
+                responseData.err = 1;
+                responseData.msg = err;
+            }
+            ctx.body = responseData;
+        }
+
         async loadData(ctx) {
             try {
                 const data = JSON.parse(ctx.request.body.data);

+ 8 - 0
app/extend/context.js

@@ -76,6 +76,14 @@ module.exports = {
         return this.app.hisOss;
     },
 
+    get stashOssPath() {
+        return this.app.config.stashOssPath;
+    },
+
+    print(str) {
+        this.getLogger('out').info(str);
+    },
+
     saveTempFile(filename, text) {
         const filepath = path.join(this.app.config.logger.dir, this.app.config.version, filename);
         this.helper.saveBufferFile(text, filepath);

+ 90 - 30
app/lib/analysis_excel.js

@@ -296,8 +296,12 @@ class ImportBaseTree {
      * @param {object} pos - 部位明细
      * @returns {*}
      */
-    addPos (pos){
+    addPos (pos, strict = false){
         if (this.finalNode && this.finalNode.pos) {
+            if (strict) {
+                const exist = this.finalNode.pos.find(x => { return x.name === pos.name; });
+                if (exist) return;
+            }
             pos.id = this.ctx.app.uuid.v4();
             pos.lid = this.finalNode.id;
             pos.tid = this.ctx.tender.id;
@@ -876,17 +880,12 @@ class AnalysisGclExcelTree {
     }
 }
 
-class ImportStageBaseTree {
-
-}
-
-class AnalysisStageTree {
+class AnalysisStageExcelTree extends AnalysisExcelTree {
     /**
      * 构造函数
      */
     constructor(ctx, setting) {
-        this.ctx = ctx;
-        this.setting = setting;
+        super(ctx, setting);
         this.mid = ctx.tender.id;
         this.decimal = ctx.tender.info.decimal;
         this.precision = ctx.tender.info.precision;
@@ -897,23 +896,15 @@ class AnalysisStageTree {
             pos: {value: ['计量单元'], type: colDefineType.match},
             name: {value: ['名称'], type: colDefineType.match},
             unit: {value: ['单位'], type: colDefineType.match},
+            unit_price: {value: ['单价'], type: colDefineType.match},
             contract_qty: {value: ['本期合同计量|数量'], type: colDefineType.match},
             contract_tp: {value: ['本期合同计量|金额'], type: colDefineType.match},
+            deal_dgn_qty1: {value: ['合同|项目节数量1'], type: colDefineType.match},
+            deal_dgn_qty2: {value: ['合同|项目节数量2'], type: colDefineType.match},
+            qc_dgn_qty1: {value: ['变更|项目节数量1'], type: colDefineType.match},
+            qc_dgn_qty2: {value: ['变更|项目节数量2'], type: colDefineType.match},
         };
-        this.needCols = ['code', 'b_code', 'pos', 'name', 'unit', 'contract_qty', 'contract_tp'];
-    }
-
-    /**
-     * 读取表头并检查
-     * @param {Number} row - Excel数据行
-     */
-    checkColHeader(row) {
-        const colsDef = aeUtils.checkColHeader(row, this.colHeaderMatch);
-        let check = true;
-        for (const col of this.needCols) {
-            if (!colsDef[col]) check = false;
-        }
-        if (check) this.colsDef = colsDef;
+        this.needCols = ['code', 'b_code', 'pos', 'name', 'unit', 'unit_price', 'contract_qty', 'contract_tp'];
     }
 
     mergeHeaderRow(iRow, row, subRow, merge) {
@@ -934,8 +925,76 @@ class AnalysisStageTree {
         return result;
     }
 
-    loadRowData(row, iRow) {
-
+    /**
+     * 读取项目节节点
+     * @param {Array} row - excel行数据
+     * @returns {*}
+     * @private
+     */
+    _loadXmjNode(row) {
+        try {
+            const node = {};
+            node.code = this.ctx.helper.replaceReturn(this.ctx.helper._.trimEnd(row[this.colsDef.code]));
+            node.name = this.ctx.helper.replaceReturn(this.ctx.helper._.trimEnd(row[this.colsDef.name]));
+            node.unit = this.ctx.helper.replaceReturn(this.ctx.helper._.trimEnd(row[this.colsDef.unit]));
+            const xmj = this.cacheTree.addXmjNode(node);
+            xmj.deal_dgn_qty1 = aeUtils.toNumber(row[this.colsDef.deal_dgn_qty1]);
+            xmj.deal_dgn_qty2 = aeUtils.toNumber(row[this.colsDef.deal_dgn_qty2]);
+            xmj.c_dgn_qty1 = aeUtils.toNumber(row[this.colsDef.c_dgn_qty1]);
+            xmj.c_dgn_qty2 = aeUtils.toNumber(row[this.colsDef.c_dgn_qty2]);
+            this.ctx.helper.checkDgnQtyPrecision(xmj);
+            return xmj;
+        } catch (error) {
+            if (error.stack) {
+                this.ctx.logger.error(error);
+            } else {
+                this.ctx.getLogger('fail').info(JSON.stringify({
+                    error,
+                    project: this.ctx.session.sessionProject,
+                    user: this.ctx.session.sessionUser,
+                    body: row,
+                }));
+            }
+            return null;
+        }
+    }
+    /**
+     * 读取工程量清单数据
+     * @param {Array} row - excel行数据
+     * @returns {*}
+     * @private
+     */
+    _loadGclNode(row) {
+        if (this.filter.filterGcl) return true;
+        const node = {};
+        node.b_code = this.ctx.helper.replaceReturn(this.ctx.helper._.trimEnd(row[this.colsDef.b_code]));
+        node.name = this.ctx.helper.replaceReturn(this.ctx.helper._.trimEnd(row[this.colsDef.name]));
+        node.unit = this.ctx.helper.replaceReturn(this.ctx.helper._.trimEnd(row[this.colsDef.unit]));
+        node.unit_price = this.ctx.helper.round(aeUtils.toNumber(row[this.colsDef.unit_price]), this.decimal.up);
+        const precision = this.ctx.helper.findPrecision(this.precision, node.unit);
+        node.contract_qty = this.ctx.helper.round(aeUtils.toNumber(row[this.colsDef.contract_qty]), precision.value);
+        if (node.quantity && node.unit_price) {
+            node.contract_tp = this.ctx.helper.mul(node.quantity, node.unit_price, this.decimal.tp);
+        } else {
+            node.contract_tp = null;
+        }
+        if (this.filter.filterZeroGcl && !node.quantity && !node.total_price) return true;
+        return this.cacheTree.addGclNode(node);
+    }
+    /**
+     * 读取部位明细数据
+     * @param {Array} row - excel行数据
+     * @returns {*}
+     * @private
+     */
+    _loadPos(row) {
+        if (this.filter.filterPos) return true;
+        let pos = {};
+        pos.name = this.ctx.helper.replaceReturn(row[this.colsDef.name]);
+        pos.quantity = aeUtils.toNumber(row[this.colsDef.contract_qty]);
+        pos = this.cacheTree.addPos(pos, true);
+        pos.contract_qty = pos.quantity;
+        return pos;
     }
 
     /**
@@ -944,20 +1003,21 @@ class AnalysisStageTree {
      * @param {Array} tempData - 新建项目使用的清单模板
      * @returns {ImportBaseTree}
      */
-    analysisData(ledger, pos, sheet) {
+    analysisData(sheet, tempData, filter) {
         this.filter = filter ? filter : {};
         this.colsDef = null;
-        this.cacheTree = this._getNewLedger();
+        this.cacheTree = this._getNewCacheTree(tempData);
         this.errorData = [];
         this.loadEnd = false;
         this.loadBegin = sheet.rows.length;
 
-        for (const iRow in sheet.rows) {
+        for (const [iRow, row] of sheet.rows.entries()) {
             if (this.colsDef && !this.loadEnd) {
                 if (iRow < this.loadBegin) continue;
-                this.loadRowData(sheet.rows[iRow], iRow);
+                this.loadRowData(row, iRow);
             } else {
-                const mergeRow = this.mergeHeaderRow(iRow, sheet.rows[iRow], sheet.rows[iRow + 1], sheet.merge);
+                if (iRow === sheet.rows.length - 1) continue;
+                const mergeRow = this.mergeHeaderRow(iRow, row, sheet.rows[iRow + 1], sheet.merge);
                 this.checkColHeader(mergeRow);
                 if (this.colsDef) this.loadBegin = iRow + 2;
             }
@@ -967,4 +1027,4 @@ class AnalysisStageTree {
     }
 }
 
-module.exports = { AnalysisExcelTree, AnalysisGclExcelTree, AnalysisStageTree };
+module.exports = { AnalysisExcelTree, AnalysisGclExcelTree, AnalysisStageExcelTree };

+ 1 - 1
app/lib/ledger.js

@@ -508,7 +508,7 @@ class gatherTree extends baseTree {
     resortChildrenDefault() {
         const helper = this.ctx.helper;
         this.resortChildrenByCustom((x, y) => {
-            const iCode = helper.compareCode(x.code, y.code);
+            const iCode = (x.code || y.code) ? helper.compareCode(x.code, y.code) : helper.compareCode(x.b_code, y.b_code);
             if (iCode) return iCode;
             if (!x.name) return -1;
             if (!y.name) return 1;

+ 16 - 15
app/middleware/stage_check.js

@@ -85,21 +85,6 @@ module.exports = options => {
                     stage.curOrder = stage.curAuditor.aid === accountId ? stage.curAuditor.order : stage.curAuditor.order - 1;
                 }
                 stage.filePermission = true;
-            } else if (this.tender.isTourist) {
-                if (auditorIds.indexOf(accountId) !== -1) {
-                    stage.readOnly = (stage.status !== status.checking && stage.status !== status.checkNoPre) || accountId !== stage.curAuditor.aid;
-                } else {
-                    stage.readOnly = true;
-                }
-                stage.curTimes = stage.times;
-                if (stage.status === status.uncheck || stage.status === status.checkNo) {
-                    stage.curOrder = 0;
-                } else if (stage.status === status.checked) {
-                    stage.curOrder = _.max(_.map(stage.auditors, 'order'));
-                } 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 '您无权查看该数据';
@@ -132,6 +117,21 @@ module.exports = options => {
                     stage.curOrder = stage.status === status.checked ? _.max(_.map(stage.auditors, 'order')) : stage.curAuditor.order - 1;
                 }
                 stage.filePermission = false;
+            } else if (this.tender.isTourist || this.session.sessionUser.is_admin) {
+                if (auditorIds.indexOf(accountId) !== -1) {
+                    stage.readOnly = (stage.status !== status.checking && stage.status !== status.checkNoPre) || accountId !== stage.curAuditor.aid;
+                } else {
+                    stage.readOnly = true;
+                }
+                stage.curTimes = stage.times;
+                if (stage.status === status.uncheck || stage.status === status.checkNo) {
+                    stage.curOrder = 0;
+                } else if (stage.status === status.checked) {
+                    stage.curOrder = _.max(_.map(stage.auditors, 'order'));
+                } else {
+                    stage.curOrder = stage.curAuditor.order;
+                }
+                stage.filePermission = this.tender.touristPermission.file || auditorIds.indexOf(accountId) !== -1;
             } else { // 其他不可见
                 throw '您无权查看该数据';
             }
@@ -165,6 +165,7 @@ module.exports = options => {
             }
             yield next;
         } catch (err) {
+            console.log(err);
             this.helper.log(err);
             // 输出错误到日志
             if (err.stack) {

+ 52 - 19
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;
@@ -830,6 +830,10 @@ input.nospin[type="number"]{-moz-appearance:textfield;}
   height:450px;
   overflow: hidden
 }
+.modal-height-400{
+  height:400px;
+  overflow: hidden
+}
 .modal-height-300{
   height:300px;
   overflow:auto
@@ -870,7 +874,7 @@ input.nospin[type="number"]{-moz-appearance:textfield;}
   font-size: 14px
 }
 .bd-toc {
-
+  
     position: sticky;
     top:3rem;
     height: calc(100vh - 10rem);
@@ -1028,7 +1032,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;
@@ -1055,8 +1059,7 @@ label{
   font-size:100%;
 }
 .modal-header{
-  padding:.5rem 1rem;
-  cursor: move;
+  padding:.5rem 1rem
 }
 .modal-title{
   font-size:16px;
@@ -1247,7 +1250,7 @@ a.maintain-icon .fa{
     }
 }
 
-a.maintain-icon:hover .fa{
+a.maintain-icon:hover .fa{ 
     animation-iteration-count:0
 }
 /*审批列表*/
@@ -1370,10 +1373,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{
@@ -1914,8 +1917,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{
@@ -1939,12 +1942,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{
@@ -1984,3 +1987,33 @@ animation:shake 1s .2s ease both;}
 .margin-inputbox .height-inputbox{
   height: 30px !important;
 }
+.card-gk-width{
+  width: 352px;
+  border: none;
+  cursor: pointer;
+}
+.card-gk-width:hover{
+  background: #f7f7f7;
+}
+.modal-body .card-gk-title{
+  font-size: 16px;
+}
+.card-gk-active{
+  border: 1px solid #3377FF;
+}
+.sel-width{
+  width: 20px;
+  height: 20px;
+}
+.sel-blue{
+  background: url(sel_blue.png);
+}
+.card-gk-width:hover .sel-gary{
+  background: url(sel_gary.png);
+}
+.card-gk-bottom{
+  display:none ;
+}
+.card-gk-active .card-gk-bottom{
+  display: inline-block;
+}

二进制
app/public/css/sel_blue.png


二进制
app/public/css/sel_gary.png


二进制
app/public/images/dongtai.png


二进制
app/public/images/jingtai.png


二进制
app/public/images/tubiaoban.png


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

@@ -166,7 +166,8 @@ $(document).ready(() => {
             },
         },
     };
-
+    // 数字只判断几个值(unit_price, oamount, camount)
+    const numField = ['unit_price', 'oamount', 'camount'];
     const changeSpreadObj = {
         makeSjsFooter: function () {
             // 增加汇总行并设为锁定禁止编辑状态
@@ -430,7 +431,7 @@ $(document).ready(() => {
                     return;
                 }
                 // 未改变值则不提交
-                let validText = is_numeric(info.editingText) ? parseFloat(info.editingText) : (info.editingText ? trimInvalidChar(info.editingText) : '');
+                let validText = is_numeric(info.editingText) && _.indexOf(numField, col.field) !== -1 ? parseFloat(info.editingText) : (info.editingText ? trimInvalidChar(info.editingText) : '');
                 const orgValue = select[col.field];
                 if (orgValue == validText || ((!orgValue || orgValue === '') && (validText === ''))) {
                     SpreadJsObj.reLoadRowData(info.sheet, info.row);
@@ -529,7 +530,7 @@ $(document).ready(() => {
                     if (!colSetting) continue;
 
                     let validText = info.sheet.getText(curRow, curCol);
-                    validText = is_numeric(validText) ? parseFloat(validText) : (validText ? trimInvalidChar(validText) : '');
+                    validText = is_numeric(validText) && _.indexOf(numField, colSetting.field) !== -1 ? parseFloat(validText) : (validText ? trimInvalidChar(validText) : '');
                     const orgValue = sortData[curRow][colSetting.field];
                     if (orgValue == validText || ((!orgValue || orgValue === '') && (validText === ''))) {
                         sameCol++;

+ 1 - 2
app/public/js/stage.js

@@ -4726,8 +4726,7 @@ $(document).ready(() => {
             },
             callback: function (sheet) {
                 postDataCompress(window.location.pathname + '/importStageSheet', {sheet}, function (result) {
-                    // todo 刷新界面
-                    console.log(result);
+                    window.location.reload();
                 }, null);
             }
         });

+ 2 - 0
app/router.js

@@ -162,6 +162,7 @@ module.exports = app => {
     app.post('/tender/:id/copy-setting', sessionAuth, tenderCheck, 'tenderController.copyTender');
     app.post('/tender/:id/tourist/audit/save', sessionAuth, tenderCheck, uncheckTenderCheck, 'tenderController.saveTourist');
     app.post('/tender/:id/map/save', sessionAuth, tenderCheck, uncheckTenderCheck, 'tenderController.saveMap');
+    app.post('/tender/:id/map/upload', sessionAuth, tenderCheck, uncheckTenderCheck, 'tenderController.uploadMap');
     app.post('/tender/:id/load', sessionAuth, tenderCheck, 'tenderController.loadData');
     app.post('/tender/:id/saveRela', sessionAuth, tenderCheck, 'tenderController.saveRelaData');
 
@@ -291,6 +292,7 @@ module.exports = app => {
     app.post('/tender/:id/measure/stage/:order/stash/add', sessionAuth, tenderCheck, stageCheck, 'stageController.addStash');
     app.post('/tender/:id/measure/stage/:order/stash/del', sessionAuth, tenderCheck, stageCheck, 'stageController.delStash');
     app.post('/tender/:id/measure/stage/:order/stash/recover', sessionAuth, tenderCheck, stageCheck, 'stageController.recoverStash');
+    app.post('/tender/:id/measure/stage/:order/importStageSheet', sessionAuth, tenderCheck, stageCheck, 'stageController.importStageSheet');
 
     // 计量附件
     app.post('/tender/:id/measure/stage/:order/upload/file', sessionAuth, tenderCheck, uncheckTenderCheck, stageCheck, 'stageController.uploadFile');

+ 1 - 1
app/service/change_audit_list.js

@@ -942,7 +942,7 @@ module.exports = app => {
                     insertLedgerArr.push('(' + this.ctx.helper.getInArrStrSqlFilter(insertL) + ')');
                     await transaction.delete(this.ctx.service.changeLedger.tableName, { id: l.id });
                     // 日志添加
-                    await transaction.insert(this.ctx.service.changeReviseLog.tableName, { tid, cid, lid: l.id, name: l.name, create_time: new Date() });
+                    await transaction.insert(this.ctx.service.changeReviseLog.tableName, { tid, cid, lid: l.id, name: l.name ? l.name : (l.code ? l.code : ''), create_time: new Date() });
                 }
                 const bSql = 'Insert Into ' +
                     this.ctx.service.ledger.tableName +

+ 1 - 1
app/service/ledger.js

@@ -716,7 +716,7 @@ module.exports = app => {
                     // todo 最底层项目节其实应该导入,但是由于目前项目节不能输入金额,也不能计量,导入金额就会有矛盾,故暂时不导入
                     if (this.ctx.tender.data.measure_type === measureType.tz.value) {
                         data.sgfh_qty = node.quantity;
-                        data.sgfh_tp = node.total_price;
+                        data.sgfh_tp = node.b_code ? node.total_price : 0;
                         data.quantity = node.quantity;
                         data.total_price = node.b_code ? node.total_price : 0;
                     } else if (this.ctx.tender.data.measure_type === measureType.gcl.value) {

+ 4 - 0
app/service/rpt_gather_memory.js

@@ -581,6 +581,10 @@ module.exports = app => {
                 info.yf_tp = stage.yf_tp;
                 info.pre_yf_tp = stage.pre_yf_tp;
                 info.end_yf_tp = helper.add(stage.yf_tp, stage.pre_yf_tp);
+
+                info.sf_tp = stage.sf_tp;
+                info.pre_sf_tp = stage.pre_sf_tp;
+                info.end_sf_tp = helper.add(stage.sf_tp, stage.pre_sf_tp);
             }
         }
 

+ 2 - 1
app/service/stage.js

@@ -267,7 +267,7 @@ module.exports = app => {
                 s.end_tp = this.ctx.helper.add(s.pre_tp, s.tp);
                 s.tp_history = s.tp_history ? JSON.parse(s.tp_history) : [];
             }
-            if (stages.length !== 0) {
+            if (stages.length !== 0 && !this.ctx.session.sessionUser.is_admin) {
                 const lastStage = stages[0];
                 if (lastStage.status === auditConst.status.uncheck && lastStage.user_id !== this.ctx.session.sessionUser.accountId && !this.ctx.tender.isTourist) {
                     stages.splice(0, 1);
@@ -725,6 +725,7 @@ module.exports = app => {
             const lastStage = await this.ctx.service.stage.getLastestStage(tid, true);
             return lastStage ? lastStage.id === sid : false;
         }
+
     }
 
     return Stage;

+ 5 - 18
app/service/stage_bills_dgn.js

@@ -77,11 +77,8 @@ module.exports = app => {
          * @private
          */
         async _saveDgnDatas(datas) {
-            const orgDatas = await this.db.select(this.tableName, {
-                where: {
-                    id: this._.map(datas, 'id'),
-                }
-            });
+            const ids = this._.map(datas, 'id');
+            const orgDatas = await this.db.select(this.tableName, { where: { id: ids } });
             const updateDatas = [], newDatas = [];
             for(const d of datas) {
                 this._filterInvalidField(d);
@@ -95,24 +92,14 @@ module.exports = app => {
             }
             const transaction = await this.db.beginTransaction();
             try {
-                if (newDatas.length > 0) {
-                    await transaction.insert(this.tableName, newDatas);
-                }
-                if (updateDatas.length > 0) {
-                    for (const u of updateDatas) {
-                        await transaction.update(this.tableName, u);
-                    }
-                }
+                if (newDatas.length > 0) await transaction.insert(this.tableName, newDatas);
+                if (updateDatas.length > 0) await transaction.update(this.tableName, updateDatas);
                 await transaction.commit();
             } catch (err) {
                 await transaction.rollback();
                 throw err;
             }
-            await this.db.select(this.tableName, {
-                where: {
-                    id: this._.map(datas, 'id')
-                }
-            });
+            await this.db.select(this.tableName, {where: { id: ids } });
         }
 
         /**

+ 182 - 1
app/service/stage_stash.js

@@ -8,6 +8,135 @@
  * @version
  */
 
+class loadStageExcelTree {
+    constructor(ctx) {
+        this.ctx = ctx;
+
+        this.decimal = ctx.tender.info.decimal;
+
+        this.insertBills = [];
+        this.insertPos = [];
+        this.updateBills = [];
+        this.updatePos = [];
+        this.insertDgn = [];
+        this.updateDgn = [];
+    }
+    init(source) {
+        this.default = source.default;
+
+        const LedgerModel = require('../lib/ledger');
+        this.ledgerTree = new LedgerModel.billsTree(this.ctx, {
+            id: 'ledger_id', pid: 'ledger_pid', order: 'order', level: 'level', rootId: -1, calcFields: [],
+        });
+        this.pos = new LedgerModel.pos({ id: 'id', ledgerId: 'lid' });
+        this.ledgerTree.loadDatas(source.ledgerData);
+        this.pos.loadDatas(source.posData);
+
+        this.stageBills = source.stageBills;
+        this.stagePos = source.stagePos;
+
+        this.stageBillsDgn = source.stageBillsDgn;
+    }
+    findNode(node, parent) {
+        const _ = this.ctx.helper._;
+        const sibling = parent ? parent.children : this.ledgerTree.children;
+        const self = this;
+        return sibling.find(x => {
+            if (node.is_leaf !== x.is_leaf) return false;
+
+            if (node.b_code) {
+                if (x.has_pos === undefined) {
+                    const relaPos = self.pos.getLedgerPos(x.id);
+                    x.has_pos = !!relaPos && relaPos.length > 0;
+                }
+                return node.b_code === _.trimEnd(x.b_code) && node.name === _.trimEnd(x.name) && node.unit === _.trimEnd(x.unit)
+                    && node.unit_price === x.unit_price && node.has_pos === x.has_pos;
+            } else {
+                return node.code === _.trimEnd(x.code) && node.name === _.trimEnd(x.name);
+            }
+        });
+    }
+    loadLeaf(node, source) {
+        const curStageBills = this.stageBills.find(csb => { return csb.lid === source.id; });
+        if (node.has_pos) {
+            const sourcePos = this.pos.getLedgerPos(source.id);
+            const sourceStagePos = this.stagePos.filter(sp => { return sp.lid === source.id; });
+
+            let contract_qty = 0;
+            for (const p of node.pos) {
+                if (!p.contract_qty) continue;
+                const sp = sourcePos.find(x => { return x.name === p.name; });
+                if (!sp) continue;
+
+                contract_qty = this.ctx.helper.add(contract_qty, p.contract_qty);
+                let ssp = sourceStagePos.find(x => { return x.pid === sp.id; });
+                sourceStagePos.splice(sourceStagePos.indexOf(ssp), 1);
+                if (ssp) {
+                    this.updatePos.push({ id: ssp.id, contract_qty: p.contract_qty });
+                } else {
+                    this.insertPos.push({ tid: this.default.tid, sid: this.default.sid, said: this.default.said, times: 1, order: 0, lid: source.id, pid:sp.id, contract_qty: p.contract_qty });
+                }
+            }
+            for (const ssp of sourceStagePos) {
+                contract_qty = this.ctx.helper.add(contract_qty, ssp.contract_qty);
+            }
+            const contract_tp = this.ctx.helper.mul(contract_qty, source.unit_price, this.decimal.tp);
+            if (curStageBills) {
+                this.updateBills.push({ id: curStageBills.id, contract_qty, contract_tp });
+            } else {
+                if (contract_qty) this.insertBills.push({ tid: this.default.tid, sid: this.default.sid, said: this.default.said, times: 1, order: 0, lid: source.id, contract_qty, contract_tp });
+            }
+        } else {
+            if (!node.contract_qty && !node.contract_tp) return;
+            const contract_qty = node.contract_qty;
+            const contract_tp = contract_qty
+                ? this.ctx.helper.mul(contract_qty, source.unit_price, this.decimal.tp)
+                : this.ctx.helper.round(contract_tp, this.decimal.tp);
+
+            if (curStageBills) {
+                this.updateBills.push({ id: curStageBills.id, contract_qty: contract_qty, contract_tp: contract_tp });
+            } else {
+                this.insertBills.push({ tid: this.default.tid, sid: this.default.sid, said: this.default.said, times: 1, order: 0, lid: source.id, contract_qty: contract_qty, contract_tp: contract_tp });
+            }
+        }
+    }
+    loadDgn(node, cur) {
+        if (!node.deal_dgn_qty1 && !node.deal_dgn_qty2 && !node.c_dgn_qty1 && !node.c_dgn_qty2) return;
+
+        const dgn = this.stageBillsDgn.find(x => { return x.id === cur.id; });
+        if (dgn) {
+            this.updateDgn.push({ id: cur.id, deal_dgn_qty1: node.deal_dgn_qty1, deal_dgn_qty2: node.deal_dgn_qty2, c_dgn_qty1: node.c_dgn_qty1, c_dgn_qty2: node.c_dgn_qty2 });
+        } else {
+            this.insertDgn.push({ id: cur.id, tid: this.default.tid, deal_dgn_qty1: node.deal_dgn_qty1, deal_dgn_qty2: node.deal_dgn_qty2, c_dgn_qty1: node.c_dgn_qty1, c_dgn_qty2: node.c_dgn_qty2 });
+        }
+    }
+    loadNode(node, parent) {
+        node.is_leaf = !node.children || node.children.length === 0 ? 1 : 0;
+        node.has_pos = node.pos && node.pos.length > 0;
+        const cur = this.findNode(node, parent);
+        if (!cur) return;
+
+        if (cur) {
+            if (!node.b_code) this.loadDgn(node, cur);
+            if (node.is_leaf) {
+                this.loadLeaf(node, cur);
+            } else {
+                for (const c of node.children) {
+                    this.loadNode(c, cur);
+                }
+            }
+        }
+    }
+    load(excelTree, source) {
+        this.init(source);
+
+        for (const node of excelTree.roots) {
+            this.loadNode(node, null);
+        }
+    }
+}
+
+
 module.exports = app => {
     class StageStash extends app.BaseService {
         /**
@@ -38,7 +167,7 @@ module.exports = app => {
             const result = await this.db.insert(this.tableName, {
                 pid: this.ctx.session.sessionProject.id, tid: stage.tid, sid: stage.id, sorder: stage.order,
                 uid: this.ctx.session.sessionUser.accountId, uname: this.ctx.session.sessionUser.name,
-                filepath, info: {status: stage.status, flow: stage.curAuditor ? stage.curAuditor.user_id : stage.uid}, remark
+                filepath, info: JSON.stringify({ status: stage.status, flow: stage.curAuditor ? stage.curAuditor.user_id : stage.uid }), remark
             });
             return result.insertId;
         }
@@ -174,6 +303,58 @@ module.exports = app => {
                 throw err;
             }
         };
+
+        /**
+         * 导入Excel期计量(仅导入合同计量)
+         * 该方法本应该独立或者在stage下,但是跟stage_stash业务非常类似,暂归类于此
+         * @param stage
+         * @param sheet
+         * @returns {Promise<void>}
+         */
+        async loadExcelSheet(stage, excelData) {
+            const AnalysisExcel = require('../lib/analysis_excel').AnalysisStageExcelTree;
+            const analysisExcel = new AnalysisExcel(this.ctx, this.ctx.service.ledger.setting);
+
+            try {
+                const templateId = await this.ctx.service.valuation.getValuationTemplate(
+                    this.ctx.tender.data.valuation, this.ctx.tender.data.measure_type);
+                const tempData = await this.ctx.service.tenderNodeTemplate.getData(templateId, true);
+                const cacheTree = analysisExcel.analysisData(excelData, tempData, { filterZeroGcl: false });
+
+                const ledgerData = await this.ctx.service.ledger.getAllDataByCondition({
+                    columns: ['id', 'ledger_id', 'ledger_pid', 'level', 'order', 'full_path', 'is_leaf', 'code', 'b_code', 'name', 'unit', 'unit_price', 'is_tp'],
+                    where: { tender_id: stage.tid},
+                });
+                const posData = await this.ctx.service.pos.getAllDataByCondition({
+                    columns: ['id', 'lid', 'name', 'porder'],
+                    where: { tid: stage.tid },
+                });
+                const stageBills = await this.ctx.service.stageBills.getAllDataByCondition({ where: { sid: stage.id }});
+                const stagePos = await this.ctx.service.stagePos.getAllDataByCondition({ where: { sid: stage.id }});
+                const stageBillsDgn = await this.ctx.service.stageBillsDgn.getAllDataByCondition({ where: { tid: stage.tid } });
+
+                const loadModal = new loadStageExcelTree(this.ctx);
+                loadModal.load(cacheTree, {ledgerData, posData, stageBills, stagePos, stageBillsDgn, default: { tid: stage.tid, sid: stage.id, said: this.ctx.session.sessionUser.accountId } });
+
+                const conn = await this.db.beginTransaction();
+                try {
+                    if (loadModal.insertBills.length > 0) conn.insert(this.ctx.service.stageBills.tableName, loadModal.insertBills);
+                    if (loadModal.updateBills.length > 0) conn.updateRows(this.ctx.service.stageBills.tableName, loadModal.updateBills);
+                    if (loadModal.insertPos.length > 0) conn.insert(this.ctx.service.stagePos.tableName, loadModal.insertPos);
+                    if (loadModal.updatePos.length > 0) conn.updateRows(this.ctx.service.stagePos.tableName, loadModal.updatePos);
+                    if (loadModal.insertDgn.length > 0) conn.insert(this.ctx.service.stageBillsDgn.tableName, loadModal.insertDgn);
+                    if (loadModal.updateDgn.length > 0) conn.updateRows(this.ctx.service.stageBillsDgn.tableName, loadModal.updateDgn);
+                    await conn.commit();
+                } catch (err) {
+                    await conn.rollback();
+                    this.ctx.log(err);
+                    throw '保存导入数据失败';
+                }
+            } catch (err) {
+                this.ctx.log(err);
+                throw '解析Excel错误';
+            }
+        }
     }
 
     return StageStash;

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

@@ -44,7 +44,7 @@
                 </div>
             </div>
             <div class="ml-auto">
-                <% if (ctx.session.sessionUser.is_admin) { %>
+                <% if (ctx.session.sessionUser.is_admin && ctx.tender.data.measure_type === measureType.tz.value) { %>
                 <a class="btn btn-primary btn-sm" href="#stage-stash" data-toggle="modal" data-target="#stage-stash" href="javascript: void(0)">暂存计量</a>
                 <% } %>
             </div>

+ 19 - 6
app/view/tender/detail.ejs

@@ -183,8 +183,21 @@
                             <!--章节计量情况图-->
                             <div class="col-6 pl-0">
                                 <div class="card mb-3 <% if (!ctx.tender.info.display.dayMode) { %>bg-dark text-white<% } %>">
-                                    <% if (hadMap) { %>
-                                        <div class="card-body" id="map" style="height: 388px; width: 100%;">
+                                    <% if (hadMap === 1) { %>
+                                        <div class="card-body" id="map" style="height: 388px; width: 100%;"></div>
+                                    <% } else if (hadMap === 2) { %>
+                                        <div style="position:relative;height: 388px; width: 100%;">
+                                            <% if (map_pic) { %>
+                                            <% if (!ctx.tender.info.display.dayMode) { %>
+                                            <div style="position:absolute;top:0;left:0;width:100%;height: 388px;background-color: rgba(44, 50, 55, 0.2);z-index: 10"></div>
+                                            <% } %>
+                                            <img style="display:block;width:100%;height: 388px;margin:0 auto;" src="<%- fujianOssPath + map_pic %>">
+                                            <% } else { %>
+                                            <div class="p-5 text-center text-muted">
+                                                <img src="/public/images/nulllogo.png" />
+                                                <div class="pt-3">请上传你的静态图片</div>
+                                            </div>
+                                            <% } %>
                                         </div>
                                     <% } else  { %>
                                         <div class="card-header"><h6 class="mb-0">章节计量情况图</h6></div>
@@ -342,7 +355,7 @@
                             <!--期进度表-->
                             <div class="col-6">
                                 <div class="card mb-3 <% if (!ctx.tender.info.display.dayMode) { %>bg-dark text-white<% } %> bottom-height">
-                                    <% if (hadMap) { %>
+                                    <% if (hadMap === 1 || hadMap === 2) { %>
                                         <div class="card-header"><h6 class="mb-0">章节计量情况表</h6></div>
                                         <div class="card-body">
                                             <div id="jlchart3" style="height: 300px; width: 100%;"></div>
@@ -358,7 +371,7 @@
                             <!--月进度表-->
                             <div class="col-6 pl-0">
                                 <div class="card mb-3 bottom-height <% if (!ctx.tender.info.display.dayMode) { %>bg-dark text-white<% } %>">
-                                    <% if (hadMap) { %>
+                                    <% if (hadMap === 1 || hadMap === 2) { %>
                                         <div class="card-header">
                                             <ul class="nav nav-tabs card-header-tabs panel-card-tabs <% if (ctx.tender.info.display.dayMode) { %>nav-white-tabs<% } %>" id="change-echarts">
                                                 <li class="nav-item">
@@ -1341,14 +1354,14 @@
         };
     })
 </script>
-<% if (hadMap || ctx.session.sessionUser.is_admin) { %>
+<% if (hadMap === 1 || ctx.session.sessionUser.is_admin) { %>
     <script src="/public/js/map/turf.min.js"></script>
     <script src="/public/js/map/gcoord.js"></script>
     <script>
         const tenderMapList = JSON.parse(unescape('<%- escape(JSON.stringify(tenderMapList)) %>'));
     </script>
 <% } %>
-<% if (hadMap) { %>
+<% if (hadMap === 1) { %>
     <!--<script src="//bj.bcebos.com/v1/mapopen/api-demos/js/mapStyle.js"></script>-->
     <script type="text/javascript" src="https://api.map.baidu.com/api?v=1.0&type=webgl&ak=C3hLZAjuWTaCdwnwoYY83APrwlPEj4v7"></script>
     <script type="text/javascript">

+ 153 - 42
app/view/tender/detail_modal.ejs

@@ -2039,49 +2039,97 @@
 </script>
 <!--概况设置-->
 <div class="modal fade" id="bd-set-11" data-backdrop="static">
-    <div class="modal-dialog" role="document">
+    <div class="modal-dialog modal-lg" role="document">
         <div class="modal-content">
             <div class="modal-header">
                 <h5 class="modal-title">概况设置</h5>
             </div>
-            <div class="modal-body">
-                <div class="row">
-                    <div class="col-6">
-                        <div class="card <% if (!hadMap) { %>border-dark<% } %>">
-                            <div class="card-body">
-                                <h5 class="card-title"><i class="fa fa-bookmark"></i> 无地图版</h5>
-                                <p class="card-text">概况中间展示图表</p>
-                                <% if (hadMap) { %>
-                                <a href="javascript:void(0);" data-value="1" class="btn select-map btn-primary btn-sm">选择</a>
-                                <% } else { %>
-                                <a href="javascript:void(0);" data-value="1" class="btn btn-primary btn-sm disabled">当前</a>
-                                <% } %>
+            <div class="modal-body modal-height-400">
+                <div class="container-fluid">
+                    <div class="d-flex justify-content-between">
+                        <div class="map-set">
+                            <div class="card card-gk-width p-3 select-map <% if (hadMap === 3) { %>card-gk-active<% } %>" data-value="3">
+                                <div class="card-body p-0">
+                                    <h5 class="card-title card-gk-title">
+                                        <div class="d-flex justify-content-between align-items-center">
+                                            <div>图表版</div>
+                                            <div class="sel-width <% if (hadMap === 3) { %>sel-blue<% } else { %>sel-gary<% } %>"></div>
+                                        </div>
+                                    </h5>
+                                    <div class="card-text">
+                                        <div class="my-4"><img src="/public/images/tubiaoban.png"></div>
+                                    </div>
+                                </div>
                             </div>
                         </div>
-                    </div>
-                    <div class="col-6">
-                        <div class="card <% if (hadMap) { %>border-dark<% } %>">
-                            <div class="card-body">
-                                <h5 class="card-title"><i class="fa fa-bookmark"></i> 地图版</h5>
-                                <p class="card-text">概况中间展示地图</p>
-                                <% if (!hadMap) { %>
-                                    <a href="javascript:void(0);" data-value="0" class="btn select-map btn-primary btn-sm">选择</a>
-                                <% } else { %>
-                                    <a href="javascript:void(0);" data-value="0" class="btn btn-primary btn-sm disabled">当前</a>
-                                <% } %>
-                                <a href="#bd-set-11-1" data-toggle="modal" data-target="#bd-set-11-1" data-dismiss="modal">编辑地图</a>
+                        <div class="map-set">
+                            <div class="card card-gk-width p-3 select-map <% if (hadMap === 1 || hadMap === 2) { %>card-gk-active<% } %>" data-value="<%- hadMap === 3 ? 1 : hadMap %>">
+                                <div class="card-body p-0">
+                                    <h5 class="card-title card-gk-title">
+                                        <div class="d-flex justify-content-between align-items-center">
+                                            <div>地图版</div>
+                                            <div class="sel-width <% if (hadMap === 1 || hadMap === 2) { %>sel-blue<% } else { %>sel-gary<% } %>"></div>
+                                        </div>
+                                    </h5>
+                                    <div class="card-text">
+                                        <div class="my-4"><img src="<% if (hadMap === 1 || hadMap === 3) { %>/public/images/dongtai.png<% } else { %>/public/images/jingtai.png<% } %>"></div>
+                                    </div>
+                                </div>
+                                <div class="card-gk-bottom">
+                                    <div class="d-flex justify-content-between align-items-center">
+                                        <div class="btn-group btn-group-sm" role="group" aria-label="Basic example">
+                                            <button type="button" data-value="1" class="btn change-map btn-secondary">动态坐标</button>
+                                            <button type="button" data-value="2" class="btn change-map btn-outline-primary">静态图片</button>
+                                        </div>
+                                        <div>
+                                            <a href="#bd-set-11-1" class="show-map-edit" data-toggle="modal" data-target="#bd-set-11-1" data-dismiss="modal">编辑坐标</a>
+                                            <a href="#bd-set-11-5" class="show-map-edit" data-toggle="modal" data-target="#bd-set-11-5" data-dismiss="modal" style="display:none;">上传图片</a>
+                                        </div>
+                                    </div>
+                                </div>
                             </div>
                         </div>
                     </div>
                 </div>
             </div>
             <div class="modal-footer">
+                <input type="hidden" id="map-value" value="<%- hadMap %>">
                 <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">取消</button>
                 <button type="button" class="btn btn-sm btn-primary" id="save-select-map" >确认修改</button>
             </div>
         </div>
     </div>
 </div>
+<!--上传图片-->
+<div class="modal fade" id="bd-set-11-5" data-backdrop="static">
+    <div class="modal-dialog modal-lg" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">上传静态图片</h5>
+            </div>
+            <div class="modal-body">
+                <p><input value="选择图片" type="file" id="upload-map-pic" /></p>
+                <p>预览</p>
+                <div id="show-map-pic" style="border: 1px solid rgba(0,0,0,.125);height: 388px; width: 100%;">
+                    <% if (map_pic) { %>
+                        <img style="display:block;width:100%;height: 387px;margin:0 auto;" src="<%- fujianOssPath + map_pic %>">
+                    <% } else { %>
+                        <div class="p-5 text-center text-muted">
+                            <img src="/public/images/nulllogo.png" />
+                            <div class="pt-3">暂无静态图片</div>
+                        </div>
+                    <% } %>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <a href="#bd-set-11" class="btn btn-sm btn-secondary show-map-edit" data-toggle="modal" data-target="#bd-set-11" onclick="back=true" data-dismiss="modal">关闭</a>
+                <% if (hadMap === 2) { %>
+                    <button type="button" class="btn btn-sm btn-success" onclick="window.location.reload()" >刷新显示</button>
+                <% } %>
+            </div>
+        </div>
+    </div>
+</div>
 <!--地图路线-->
 <div class="modal fade" id="bd-set-11-1" data-backdrop="static">
     <div class="modal-dialog" role="document">
@@ -2104,7 +2152,7 @@
             </div>
             <div class="modal-footer">
                 <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">关闭</button>
-                <% if (hadMap) { %>
+                <% if (hadMap === 1) { %>
                 <button type="button" class="btn btn-sm btn-success" onclick="window.location.reload()" >刷新显示</button>
                 <% } %>
             </div>
@@ -2174,32 +2222,95 @@
 
 <script>
     const hadMap = parseInt(<%- hadMap %>);
+    const fujianOssPath = JSON.parse(unescape('<%- escape(JSON.stringify(fujianOssPath)) %>'));
+    let back = false;
     $(function () {
-        $('#bd-set-11').on('show.bs.modal', function () {
-            if (parseInt(hadMap) == 0) {
-                $('#bd-set-11').find('.card').eq(0).addClass('border-dark');
-                $('#bd-set-11').find('.card').eq(0).find('.btn').removeClass('select-map').addClass('disabled').text('当前');
-                $('#bd-set-11').find('.card').eq(1).removeClass('border-dark');
-                $('#bd-set-11').find('.card').eq(1).find('.btn').removeClass('disabled').addClass('select-map').text('选择');
+        $('#bd-set-11').on('shown.bs.modal', function () {
+            if (!back) {
+                if (hadMap === 1 || hadMap === 2) {
+                    $('#bd-set-11').find('.card').eq(1).addClass('card-gk-active');
+                    $('#bd-set-11').find('.card').eq(1).find('.sel-width').removeClass('sel-gary').addClass('sel-blue');
+                    $('#bd-set-11').find('.card').eq(0).removeClass('card-gk-active');
+                    $('#bd-set-11').find('.card').eq(0).find('.sel-width').removeClass('sel-blue').addClass('sel-gary');
+                    $('#bd-set-11').find('.card').eq(1).attr('data-value', hadMap);
+                    if (hadMap === 1) {
+                        $('.change-map').eq(0).removeClass('btn-outline-primary').addClass('btn-secondary');
+                        $('.change-map').eq(1).removeClass('btn-secondary').addClass('btn-outline-primary');
+                        $('.show-map-edit').eq(0).show();
+                        $('.show-map-edit').eq(1).hide();
+                        $('#bd-set-11').find('.card').eq(1).find('img').attr('src', '/public/images/dongtai.png');
+                    } else {
+                        $('.change-map').eq(1).removeClass('btn-outline-primary').addClass('btn-secondary');
+                        $('.change-map').eq(0).removeClass('btn-secondary').addClass('btn-outline-primary');
+                        $('.show-map-edit').eq(1).show();
+                        $('.show-map-edit').eq(0).hide();
+                        $('#bd-set-11').find('.card').eq(1).find('img').attr('src', '/public/images/jingtai.png');
+                    }
+                } else if (hadMap === 3) {
+                    $('#bd-set-11').find('.card').eq(0).addClass('card-gk-active');
+                    $('#bd-set-11').find('.card').eq(0).find('.sel-width').removeClass('sel-gary').addClass('sel-blue');
+                    $('#bd-set-11').find('.card').eq(1).removeClass('card-gk-active');
+                    $('#bd-set-11').find('.card').eq(1).find('.sel-width').removeClass('sel-blue').addClass('sel-gary');
+                }
+                $('#map-value').val(hadMap);
             } else {
-                $('#bd-set-11').find('.card').eq(1).addClass('border-dark');
-                $('#bd-set-11').find('.card').eq(1).find('.btn').removeClass('select-map').addClass('disabled').text('当前');
-                $('#bd-set-11').find('.card').eq(0).removeClass('border-dark');
-                $('#bd-set-11').find('.card').eq(0).find('.btn').removeClass('disabled').addClass('select-map').text('选择');
+                back = false;
             }
         })
         $('body').on('click', '#bd-set-11 .select-map', function () {
             // const val = parseInt($(this).data('value'));
-            $(this).parents('.card').addClass('border-dark');
-            $(this).removeClass('select-map').addClass('disabled').text('当前');
-            $(this).parents('.col-6').siblings('.col-6').children('.card').removeClass('border-dark');
-            $(this).parents('.col-6').siblings('.col-6').find('.btn').removeClass('disabled').addClass('select-map').text('选择');
+            $(this).addClass('card-gk-active');
+            $(this).find('.sel-width').removeClass('sel-gary').addClass('sel-blue');
+            $(this).parents('.map-set').siblings('.map-set').children('.card').removeClass('card-gk-active');
+            $(this).parents('.map-set').siblings('.map-set').find('.sel-width').removeClass('sel-blue').addClass('sel-gary');
+            $('#map-value').val($(this).attr('data-value'));
         });
+        // 切换坐标和图片选择
+        $('.change-map').on('click', function (e) {
+            e.preventDefault();
+            event.stopPropagation();
+            if ($(this).hasClass('btn-outline-primary')) {
+                $(this).addClass('btn-secondary').removeClass('btn-outline-primary');
+                $(this).siblings('button').removeClass('btn-secondary').addClass('btn-outline-primary');
+                const value = $(this).attr('data-value');
+                $(this).parents('.card').attr('data-value', value);
+                $('#map-value').val(value);
+                if (parseInt(value) === 2) {
+                    $(this).parents('.card').find('img').attr('src', '/public/images/jingtai.png');
+                    $('.show-map-edit').eq(0).hide();
+                    $('.show-map-edit').eq(1).show();
+                } else {
+                    $(this).parents('.card').find('img').attr('src', '/public/images/dongtai.png');
+                    $('.show-map-edit').eq(1).hide();
+                    $('.show-map-edit').eq(0).show();
+                }
+            }
+        });
+
+        $('#upload-map-pic').change(function () {
+            const file = this.files[0];
+            const ext = file.name.toLowerCase().split('.').splice(-1)[0];
+            const imgStr = /(jpg|jpeg|png|bmp|BMP|JPG|PNG|JPEG)$/;
+            if (!imgStr.test(ext)) {
+                toastr.error('请上传正确的图片格式文件');
+                $('#upload-map-pic').val('');
+                return
+            }
+            if ($(this).val()) {
+                const formData = new FormData();
+                formData.append('file', this.files[0]);
+                postDataWithFile('/tender/' + tenderId + '/map/upload', formData, function (result) {
+                    const html = '<img style="display:block;width:100%;height: 387px;margin:0 auto;" src="'+ fujianOssPath + result.map_pic +'">';
+                    $('#show-map-pic').html(html);
+                    $('#upload-map-pic').val('');
+                });
+            }
+        })
 
         $('#save-select-map').click(function () {
             $(this).attr('disabled', true);
-            const val = parseInt($('#bd-set-11').find('.disabled').data('value'));
-            if (hadMap === val) {
+            const val = parseInt($('#map-value').val());
+            if (hadMap !== val) {
                 postData('/tender/' + tenderId + '/map/save', { type: 'select-map', value: val }, function () {
                     toastr.success('修改成功,重新加载中...');
                     setTimeout(function () {

+ 6 - 0
builder_report_index_define.js

@@ -1520,6 +1520,12 @@ const gather_tender_info = {
         { name: '中标信息-业主控制价', field: 'bid_info.controlPrice', type: dataType.currency },
         { name: '中标信息-中标价', field: 'bid_info.bidPrice', type: dataType.currency },
         { name: '中标信息-开标日期', field: 'bid_info.bidStartDate', type: dataType.str },
+        { name: '中标信息-招标方式', field: 'bid_info.bidType', type: dataType.str },
+        { name: '中标信息-合同计价方式', field: 'bid_info.dealCalcType', type: dataType.str },
+
+        { name: '截止上期-实付', field: 'pre_sf_tp', type: dataType.currency },
+        { name: '本期-实付', field: 'sf_tp', type: dataType.currency },
+        { name: '截止本期-实付', field: 'end_sf_tp', type: dataType.currency },
     ],
 };
 const gather_stage_pay = {

+ 3 - 0
config/config.default.js

@@ -170,6 +170,9 @@ module.exports = appInfo => {
         },
         warning: {
             file: path.join(appInfo.root, 'logs', appInfo.name, config.version, 'warning.log'),
+        },
+        out: {
+            file: path.join(appInfo.root, 'logs', appInfo.name, config.version, 'out.log'),
         }
     };
 

+ 8 - 1
db_script/ledger_his_count.js

@@ -54,7 +54,13 @@ const querySql = async function(sql, sqlParam) {
 };
 
 const loadLedgerDataFromOss = async function(url) {
-  const File = await ossClient.get(options.hisOssPath + url);
+  let File;
+  try {
+    File = await ossClient.get(options.hisOssPath + url);
+  } catch(err) {
+    if (err.status === 404) return 0;
+    throw err;
+  }
   if (File.res.status !== 200) return '获取修订台账有误';
   const result = JSON.parse(File.content);
   return result.length;
@@ -69,6 +75,7 @@ const doCompleteLedgerHis = async function(l) {
 
 const doComplete = async function() {
     try {
+      //const ledgerHis = await querySql('Select * From zh_ledger_history where bills_count = 0 order by id asc');
       const ledgerHis = await querySql('Select * From zh_ledger_history');
       for (const l of ledgerHis) {
         await doCompleteLedgerHis(l);

+ 80 - 0
db_script/stage_stash.js

@@ -0,0 +1,80 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Mai
+ * @date
+ * @version
+ */
+
+const fs = require('fs');
+const path = require('path');
+var util = require('util');
+var logPath = path.join(__dirname, 'update_ledger_his.log');
+var logFile = fs.createWriteStream(logPath, { flags: 'a' });
+console.log = function() {
+    logFile.write(util.format.apply(null, arguments) + '\n');
+    process.stdout.write(util.format.apply(null, arguments) + '\n');
+};
+
+const mysql = require('mysql');
+const oss = require('ali-oss');
+const config = process.argv.splice(2)[0];
+if (['local', 'uat', 'default'].indexOf(config) < 0) throw `参数错误: ${config}`;
+const options = require(`../config/config.${config}`)({ baseDir: __dirname + '/app', root: __dirname, name: 'calc' });
+
+const pool = mysql.createPool(options.mysql.client);
+const ossOption = {
+    bucket: options.oss.clients.his.bucket,
+    accessKeyId: options.oss.default.accessKeyId,
+    accessKeySecret: options.oss.default.accessKeySecret,
+    endpoint: options.oss.default.endpoint,
+    timeout: options.oss.default.timeout,
+};
+const ossClient = new oss(ossOption);
+
+const querySql = async function(sql, sqlParam) {
+    return new Promise(function(resolve, reject) {
+        pool.getConnection(function(err, conn) {
+            if (err) {
+                if (err) console.log(err);
+                reject(err);
+            } else {
+                conn.query(sql, sqlParam, function(err, rows, fields) {
+                    if (err) console.log(err);
+                    // 释放连接
+                    conn.release();
+                    // 传递Promise回调对象
+                    resolve(rows);
+                });
+            }
+        });
+    });
+};
+
+const loadDataFromOss = async function(url) {
+    const File = await ossClient.get('undefined' + url);
+    if (File.res.status !== 200) return '获取修订台账有误';
+    return File.content;
+};
+
+const doCompleteStashStash = async function(stash) {
+    const data = await loadDataFromOss(stash.filepath);
+    await ossClient.put(options.stashOssPath + stash.filepath, data);
+};
+
+const doComplete = async function() {
+    try {
+        const stash = await querySql('Select * From zh_stage_stash');
+        for (const s of stash) {
+            console.log(s);
+            await doCompleteStashStash(s);
+        }
+    } catch (err) {
+        console.log(err);
+    }
+    pool.end();
+};
+doComplete();
+

+ 4 - 0
sql/update.sql

@@ -1,3 +1,7 @@
 ALTER TABLE `zh_ledger_history`
 ADD COLUMN `bills_count`  int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '清单条数' AFTER `valid`,
 ADD COLUMN `pos_count`  int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '计量单元数量' AFTER `bills_count`;
+
+UPDATE `zh_tender` SET `had_map`=3 WHERE `had_map`=1;
+
+ALTER TABLE `zh_tender` ADD `map_pic` VARCHAR(255) NULL DEFAULT NULL COMMENT '静态图片地址' AFTER `had_map`;