Bläddra i källkod

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

TonyKang 4 år sedan
förälder
incheckning
3bdd0dcc40
47 ändrade filer med 1373 tillägg och 989 borttagningar
  1. 6 6
      app/const/sms_alitemplate.js
  2. 3 3
      app/const/tender.js
  3. 44 0
      app/controller/material_controller.js
  4. 57 15
      app/controller/stage_controller.js
  5. 2 2
      app/lib/wechat.js
  6. 7 0
      app/public/css/main.css
  7. 60 12
      app/public/js/material_file.js
  8. 1 1
      app/public/js/shares/cs_tools.js
  9. 107 14
      app/public/js/stage.js
  10. 1 1
      app/public/js/stage_change.js
  11. 15 4
      app/public/js/stage_im.js
  12. 2 2
      app/public/js/stage_pay.js
  13. 1 1
      app/public/js/tender_list_info.js
  14. 2 0
      app/router.js
  15. 124 75
      app/service/material_file.js
  16. 2 2
      app/service/revise_audit.js
  17. 144 95
      app/service/stage_att.js
  18. 1 1
      app/view/change/info.ejs
  19. 7 7
      app/view/dashboard/index.ejs
  20. 1 1
      app/view/layout/modal.ejs
  21. 1 1
      app/view/ledger/explode_modal.ejs
  22. 1 1
      app/view/ledger/gather.ejs
  23. 1 1
      app/view/ledger/index.ejs
  24. 14 2
      app/view/material/file.ejs
  25. 2 2
      app/view/revise/history.ejs
  26. 1 1
      app/view/revise/info.ejs
  27. 1 1
      app/view/revise/modal.ejs
  28. 1 1
      app/view/setting/user_permission_modal.ejs
  29. 1 1
      app/view/shares/import_excel_modal.ejs
  30. 1 1
      app/view/shares/ledger_check_modal.ejs
  31. 1 1
      app/view/stage/detail.ejs
  32. 1 1
      app/view/stage/gather_modal.ejs
  33. 609 603
      app/view/stage/index.ejs
  34. 3 3
      app/view/stage/measure.ejs
  35. 1 1
      app/view/stage/measure_modal.ejs
  36. 21 1
      app/view/stage/modal.ejs
  37. 1 1
      app/view/stage/report.ejs
  38. 2 2
      app/view/stage/stage_sub_menu.ejs
  39. 2 2
      app/view/stage/stage_sub_mini_menu.ejs
  40. 1 1
      app/view/sum/index.ejs
  41. 1 1
      app/view/tender/detail.ejs
  42. 5 5
      app/view/tender/tender_sub_menu.ejs
  43. 5 5
      app/view/tender/tender_sub_mini_menu.ejs
  44. 1 1
      config/config.default.js
  45. 7 7
      config/menu.js
  46. 7 7
      config/permission.js
  47. 94 93
      package.json

+ 6 - 6
app/const/sms_alitemplate.js

@@ -15,16 +15,16 @@ const endpoint = 'https://dysmsapi.aliyuncs.com';
 const smsTemplate = {
     yzm: 'SMS_192820305', // 验证码:${code},15分钟内有效。
     mmcz: 'SMS_192825318', // 账号:${account},密码重置为:${password}
-    ledger_check: 'SMS_192825164', // 项目:${project},标段:${number},台需要您审批,请登录系统处理。
-    ledger_result: 'SMS_192830156', // 项目:${project},标段:${number},台审批${status},请登录系统处理。
+    ledger_check: 'SMS_192825164', // 项目:${project},标段:${number},台需要您审批,请登录系统处理。
+    ledger_result: 'SMS_192830156', // 项目:${project},标段:${number},台审批${status},请登录系统处理。
     stage_check: 'SMS_193244645', // 项目:${project},标段:${number},第${qi}期,需要您审批。在线审批https://scn.ink/${code}
     stage_result: 'SMS_192835176', // 项目:${project},标段:${number},第${qi}期,审批${status}。
     change_check: 'SMS_193239611', // 项目:${project},标段:${number},变更:${biangeng},需要您审批。在线审批https://scn.ink/${code}
     change_result: 'SMS_192830143', // 项目:${project},标段:${number},变更:${biangeng},审批${status}。
-    revise_check: 'SMS_193145529', // 项目:${project},标段:${number},台修订需要您审批,请登录系统处理。
-    revise_result: 'SMS_193140537', // 项目:${project},标段:${number},台修订审批${status},请登录系统处理。
-    revise_result2: 'SMS_192985611', // 项目:${project},标段:${number},台修订审批${status}。
-    revise_report: 'SMS_192985614', // 项目:${project},标段:${number},台修订已上报。
+    revise_check: 'SMS_193145529', // 项目:${project},标段:${number},台修订需要您审批,请登录系统处理。
+    revise_result: 'SMS_193140537', // 项目:${project},标段:${number},台修订审批${status},请登录系统处理。
+    revise_result2: 'SMS_192985611', // 项目:${project},标段:${number},台修订审批${status}。
+    revise_report: 'SMS_192985614', // 项目:${project},标段:${number},台修订已上报。
 };
 const smsStatus = {
     back: '退回',

+ 3 - 3
app/const/tender.js

@@ -27,7 +27,7 @@ const infoTableCol = [
     { title: '名称', field: 'name', folderCell: true, },
     { title: '计量期数', field: 'stageCount', },
     { title: '审批状态', field: '', },
-    { title: '0号台合同', field: '', },
+    { title: '0号台合同', field: '', },
     { title: '本期完成', field: '', },
     { title: '截止本期合同', field: '', },
     { title: '截止本期变更', field: '', },
@@ -49,10 +49,10 @@ const manageTableCol = [
 
 const measureType = {
     tz: {
-        value: 1, name: '0号台账模式', title: ' 0号台帐', hint: ' 要求以台帐为计量根本,必须先有完整台帐才能持续计量。',
+        value: 1, name: '0号台账模式', title: ' 0号台账', hint: ' 要求以台账为计量根本,必须先有完整台账才能持续计量。',
     },
     gcl: {
-        value: 2, name: '工程量清单模式', title: ' 工程量清单', hint: ' 仅需要工程量清单,详细台帐在计量过程中逐步添加,最终组成完整台帐。',
+        value: 2, name: '工程量清单模式', title: ' 工程量清单', hint: ' 仅需要工程量清单,详细台账在计量过程中逐步添加,最终组成完整台账。',
     },
 };
 

+ 44 - 0
app/controller/material_controller.js

@@ -990,6 +990,50 @@ module.exports = app => {
                 ctx.body = { err: 1, msg: err.toString(), data: null };
             }
         }
+
+        /**
+         * 批量下载 - 压缩成zip文件返回
+         * @param {Object} ctx - 全局上下文
+         */
+        async downloadZip(ctx) {
+            try {
+                const fileIds = JSON.parse(ctx.request.query.fileIds);
+                // const { fileIds } = JSON.parse(ctx.request.body.data);
+                // console.log('fileIds', fileIds);
+                const zipFilename = `${ctx.tender.data.name}-材料调差-${ctx.params.order}-附件.zip`;
+                const time = Date.now();
+                const zipPath = `app/public/upload/${ctx.tender.id}/tc/fu_jian_zip${time}.zip`;
+                const size = await ctx.service.stageAtt.compressedFile(fileIds, zipPath);
+
+                // 解决中文无法下载问题
+                const userAgent = (ctx.request.header['user-agent'] || '').toLowerCase();
+                let disposition = '';
+                if (userAgent.indexOf('msie') >= 0 || userAgent.indexOf('chrome') >= 0) {
+                    disposition = 'attachment; filename=' + encodeURIComponent(zipFilename);
+                } else if (userAgent.indexOf('firefox') >= 0) {
+                    disposition = 'attachment; filename*="utf8\'\'' + encodeURIComponent(zipFilename) + '"';
+                } else {
+                    /* safari等其他非主流浏览器只能自求多福了 */
+                    disposition = 'attachment; filename=' + new Buffer(zipFilename).toString('binary');
+                }
+                ctx.response.set({
+                    'Content-Type': 'application/octet-stream',
+                    'Content-Disposition': disposition,
+                    'Content-Length': size,
+                });
+                const readStream = fs.createReadStream(path.join(this.app.baseDir, zipPath));
+
+                ctx.body = readStream;
+                // ctx.body = fs.readFileSync(path.resolve(this.app.baseDir, zipPath));
+                readStream.on('close', () => {
+                    if (fs.existsSync(path.resolve(this.app.baseDir, zipPath))) {
+                        fs.unlinkSync(path.resolve(this.app.baseDir, zipPath));
+                    }
+                });
+            } catch (error) {
+                this.log(error);
+            }
+        }
     }
 
     return MaterialController;

+ 57 - 15
app/controller/stage_controller.js

@@ -150,7 +150,8 @@ module.exports = app => {
             }
             // 获取审批流程中左边列表
             ctx.stage.auditors2 = await ctx.service.stageAudit.getAuditGroupByListWithOwner(ctx.stage.id, times);
-            if (ctx.stage.status === auditConst.status.uncheck || ctx.stage.status === auditConst.status.checkNo) {
+            const { status } = ctx.stage;
+            if (status === auditConst.status.uncheck || status === auditConst.status.checkNo) {
                 ctx.stage.auditorList = await ctx.service.stageAudit.getAuditors(ctx.stage.id, ctx.stage.times);
             }
         }
@@ -1016,11 +1017,13 @@ module.exports = app => {
                 }
 
                 await ctx.service.stageAudit.start(ctx.stage.id, ctx.stage.times);
-                const auditor = await ctx.service.stageAudit.getCurAuditor(ctx.stage.id, ctx.stage.times);
-                ctx.body = { err: 0, msg: '', data: [] };
+                // const auditor = await ctx.service.stageAudit.getCurAuditor(ctx.stage.id, ctx.stage.times);
+                // ctx.body = { err: 0, msg: '', data: [] };
+                ctx.redirect(ctx.request.header.referer);
             } catch (err) {
                 this.log(err);
-                ctx.body = this.ajaxErrorBody(err, '上报失败');
+                ctx.redirect(ctx.request.header.referer);
+                // ctx.body = this.ajaxErrorBody(err, '上报失败');
             }
         }
         /**
@@ -1037,7 +1040,7 @@ module.exports = app => {
                 if (!this.ctx.stage.curAuditor || this.ctx.stage.curAuditor.aid !== ctx.session.sessionUser.accountId) {
                     throw '您无权进行该操作';
                 }
-                const data = JSON.parse(ctx.request.body.data);
+                const data = ctx.request.body;
                 data.checkType = parseInt(data.checkType);
                 // const data = {
                 //     checkType: parseInt(ctx.request.body.checkType),
@@ -1053,20 +1056,20 @@ module.exports = app => {
                 }
 
                 await ctx.service.stageAudit.check(ctx.stage.id, data, ctx.stage.times);
-                const stageOrder = parseInt(ctx.params.order);
-                const stage = await ctx.service.stage.getDataByCondition({
-                    tid: ctx.tender.id,
-                    order: stageOrder,
-                });
-                const auditor = await ctx.service.stageAudit.getCurAuditor(ctx.stage.id, ctx.stage.times);
-                ctx.body = { err: 0, msg: '', data: [] };
-                // ctx.redirect(ctx.request.header.referer);
+                // const stageOrder = parseInt(ctx.params.order);
+                // const stage = await ctx.service.stage.getDataByCondition({
+                //     tid: ctx.tender.id,
+                //     order: stageOrder,
+                // });
+                // const auditor = await ctx.service.stageAudit.getCurAuditor(ctx.stage.id, ctx.stage.times);
+                // ctx.body = { err: 0, msg: '', data: [] };
+                ctx.redirect(ctx.request.header.referer);
             } catch (err) {
                 // console.log(err);
                 this.log(err);
-                ctx.body = this.ajaxErrorBody(err, '提交失败');
+                // ctx.body = this.ajaxErrorBody(err, '提交失败');
                 // ctx.session.postError = err.toString();
-                // ctx.redirect(ctx.request.header.referer);
+                ctx.redirect(ctx.request.header.referer);
             }
         }
         /**
@@ -1390,6 +1393,7 @@ module.exports = app => {
                     }
                 } catch (err) {
                     this.log(err);
+                    console.log(err);
                     this.setMessage(err.toString(), this.messageType.ERROR);
                 }
             }
@@ -1519,6 +1523,44 @@ module.exports = app => {
         }
 
         /**
+         * 批量下载 - 压缩成zip文件返回
+         * @param {Object} ctx - 全局上下文
+         */
+        async downloadZip(ctx) {
+            try {
+                const fileIds = JSON.parse(ctx.request.query.fileIds);
+                const zipFilename = `${ctx.tender.data.name}-计量台账-${ctx.params.order}-附件.zip`;
+                const time = Date.now();
+                const zipPath = `app/public/upload/${ctx.tender.id}/stage/fu_jian_zip${time}.zip`;
+                const size = await ctx.service.stageAtt.compressedFile(fileIds, zipPath);
+
+                // 解决中文无法下载问题
+                const userAgent = (ctx.request.header['user-agent'] || '').toLowerCase();
+                let disposition = '';
+                if (userAgent.indexOf('msie') >= 0 || userAgent.indexOf('chrome') >= 0) {
+                    disposition = 'attachment; filename=' + encodeURIComponent(zipFilename);
+                } else if (userAgent.indexOf('firefox') >= 0) {
+                    disposition = 'attachment; filename*="utf8\'\'' + encodeURIComponent(zipFilename) + '"';
+                } else {
+                    /* safari等其他非主流浏览器只能自求多福了 */
+                    disposition = 'attachment; filename=' + new Buffer(zipFilename).toString('binary');
+                }
+                ctx.response.set({
+                    'Content-Type': 'application/octet-stream',
+                    'Content-Disposition': disposition,
+                    'Content-Length': size,
+                });
+                ctx.body = fs.createReadStream(path.join(this.app.baseDir, zipPath));
+                // ctx.body = fs.readFileSync(path.resolve(this.app.baseDir, zipPath));
+                if (fs.existsSync(path.resolve(this.app.baseDir, zipPath))) {
+                    fs.unlinkSync(path.resolve(this.app.baseDir, zipPath));
+                }
+            } catch (error) {
+                this.log(error);
+            }
+
+        }
+        /**
          * 合同支付上传附件
          * @param {Object} ctx - egg全局变量
          * @return {void}

+ 2 - 2
app/lib/wechat.js

@@ -95,7 +95,7 @@ class WX {
                             (data.status === wxConst.status.success ? '审批已通过,查看审批结果' : '审批被退回,查看退回结果');
                         msgData = {
                             first: {
-                                value: '您好,台' + data.tips,
+                                value: '您好,台' + data.tips,
                             },
                             keyword1: {
                                 value: data.projectName,
@@ -118,7 +118,7 @@ class WX {
                                 (data.status === wxConst.status.back ? '审批被退回,查看退回结果' : '审批已上报,查看审批结果'));
                         msgData = {
                             first: {
-                                value: '您好,台修订' + data.tips,
+                                value: '您好,台修订' + data.tips,
                             },
                             keyword1: {
                                 value: data.projectName,

+ 7 - 0
app/public/css/main.css

@@ -1146,3 +1146,10 @@ overflow-y: auto;
 .fold-card {
   display: none;
 }
+.att-file-btn {
+  display: none;
+}
+.list-table tr:hover .att-file-btn{
+  display: block;
+}
+

+ 60 - 12
app/public/js/material_file.js

@@ -46,9 +46,9 @@ $(document).ready(function () {
         }
     })
     // 选择/未选所有期列表
-    $('#file-checkbox').click(function() {
-        getAllList()
-    })
+    // $('#file-checkbox').click(function() {
+    //     getAllList()
+    // })
 
     // 删除附件
     $('body').on('click', '.delete-file', function () {
@@ -100,6 +100,20 @@ $(document).ready(function () {
 
             curPageNo !== $(this).text() && getAllList(parseInt($(this).text()))
         }
+    });
+
+    $('.dropdown-item').click(function() {
+        const type = $('#dropdownMenuButton').attr('btn-type')
+        if (type === 'curr') {
+            $(this).text('当前期')
+            $('#dropdownMenuButton').text('所有期')
+            $('#dropdownMenuButton').attr('btn-type', 'all')
+        } else {
+            $(this).text('所有期')
+            $('#dropdownMenuButton').text('当前期')
+            $('#dropdownMenuButton').attr('btn-type', 'curr')
+        }
+        getAllList()
     })
     // 生成所有附件列表
     function getAllList(currPageNum = 1) {
@@ -109,14 +123,14 @@ $(document).ready(function () {
         // 总页数
         const pageNum = Math.ceil(total/pageCount);
         // 当前页附件内容
-        const currPageAttData = fileData && $('#file-checkbox').is(':checked') ? fileData.slice((currPageNum-1)*pageCount, currPageNum*pageCount) : filterFileData.map((v, index) => {
+        const currPageAttData = fileData && $('#dropdownMenuButton').attr('type') === 'all' ? fileData.slice((currPageNum-1)*pageCount, currPageNum*pageCount) : filterFileData.map((v, index) => {
             return {...v, index }
         }).slice((currPageNum-1)*pageCount, currPageNum*pageCount);
 
         renderHtml(currPageAttData)
         // 渲染分页器
         renderPagination(currPageNum, pageNum)
-    }
+    };
 
 
     function renderPagination(pageNo, pageSize) {
@@ -185,12 +199,14 @@ $(document).ready(function () {
         }
 
         $('.page-next').before(html)
-    }
+    };
 
     function renderHtml(list) {
         let html = '';
+        $('#check-all-file').prop("checked", false)
         list.forEach(fileInfo => {
             html += `<tr style="height: 31px;">
+            <td width="25"><input type="checkbox" class="check-file" file-id=${fileInfo.id}></td>
             <td>${fileInfo.index + 1}</td>
             <td><a href="/${fileInfo.filepath}" target="_blank">${fileInfo.file_name}</a></td>
             <td>${fileInfo.file_size}</td>
@@ -198,18 +214,50 @@ $(document).ready(function () {
             <td>${fileInfo.upload_time}</td>`
             if (fileInfo.canDel ) {
                 html += `<td>
-                <a class="btn btn-light btn-sm delete-file" data-attid="${fileInfo.id}" title="删除附件">
+                <a href="/${fileInfo.filepath}" class="btn btn-light btn-sm" title="下载"><span class="fa fa-download text-primary"></span></a>
+                <a href="javascript:void(0);" class="btn btn-light btn-sm delete-file" data-attid="${fileInfo.id}" title="删除附件">
                 <span class="fa fa-trash text-danger"></span>
                 </a>
                 </td></tr>`
             } else {
-                html += `<td></td></tr>`
+                html += `<td><a href="/${fileInfo.filepath}" class="btn btn-light btn-sm" title="下载"><span class="fa fa-download text-primary"></span></a></td></tr>`
             }
         })
         $('#file-list').empty();
         $('#file-list').append(html);
-    }
+    };
+
+    $('#file-list').on('click', '.check-file', function() {
+        const checkedList = $('#file-list').find('input:checked')
+        const childs = $('#file-list').children().length
+        const checkBox = $('#check-all-file')
+        if (checkedList.length === childs) {
+            checkBox.prop("checked", true)
+        } else {
+            checkBox.prop("checked", false)
+        }
+    })
+    $('#check-all-file').click(function() {
+        const isCheck = $(this).is(':checked')
+        $('#file-list').children().each(function() {
+            $(this).find('input:checkbox').prop("checked", isCheck)
+        })
+    });
 
+    $('#bach-download').click(function() {
+        const fileIds = []
+        $( '#file-list .check-file:checked').each(function() {
+            const fileId = $(this).attr('file-id')
+            fileId && fileIds.push(fileId)
+        })
+        console.log('fileIds', fileIds)
+
+        if (fileIds.length) {
+            // postData( `/tender/${tid}/measure/material/${order}/file/download/compresse-file`, { fileIds })
+            $('#downloadZip').attr('href', `/tender/${tid}/measure/material/${order}/file/download/compresse-file?fileIds=${JSON.stringify(fileIds)}`);
+            $('#downloadZip')[0].click();
+        }
+    });
     function handleFileList(fileList) {
         fileData = fileList.map((file, index) => {
             let showDel = false
@@ -224,7 +272,7 @@ $(document).ready(function () {
             }
             return showDel ? {...file, canDel: true, index} : {...file, index}
         })
-    }
+    };
 
     function calcCount() {
         // 附件总数
@@ -233,7 +281,7 @@ $(document).ready(function () {
             total = fileData && fileData.filter(file => file.mid === parseInt(mid) && file.tid === parseInt(tid)).length
         }
         return total
-    }
+    };
 
     $.subMenu({
         menu: '#sub-menu', miniMenu: '#sub-mini-menu', miniMenuList: '#mini-menu-list',
@@ -273,4 +321,4 @@ function validateFiles(files) {
         }
         return true
     })
-}
+};

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

@@ -469,7 +469,7 @@ const showSideTools = function (show) {
             }
             filter.push('</select>');
             // filter.push('<div class="input-group-prepend">');
-            // filter.push('<button class="btn btn-outline-secondary dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">台</button>');
+            // filter.push('<button class="btn btn-outline-secondary dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">台</button>');
             // filter.push('<div class="dropdown-menu">');
             // filter.push('<a class="dropdown-item" href="javascripty: void(0)" id="search-bills">台账</a>');
             // filter.push('<a class="dropdown-item" href="javascripty: void(0)" id="search-over">超计</a>');

+ 107 - 14
app/public/js/stage.js

@@ -103,7 +103,7 @@ function initTreeColSettingEvents(setting) {
 // 生成所有附件列表
 function getAllList(currPageNum = 1) {
     // 每页最多几个附件
-    const pageCount = 11;
+    const pageCount = 15;
     // 附件总数
     const total = attData.length;
     // 总页数
@@ -113,8 +113,16 @@ function getAllList(currPageNum = 1) {
     // 当前页附件内容
     const currPageAttData = attData.slice((currPageNum-1)*pageCount, currPageNum*pageCount);
     let html = '';
+    // '/tender/' + tender.id + '/measure/stage/' + stage.order + '/download/file/' + att.id
     for(const att of currPageAttData) {
-        html += '<tr ><td><a href="javascript:void(0)" file-id="'+ att.id +'">'+ att.filename + att.fileext +'</a></td><td>'+ att.username +'</td></tr>';
+        html += `<tr>
+        <td width="25"><input type="checkbox" class="check-file" file-id=${att.id}></td>
+        <td>
+        <div class="d-flex">
+            <a href="javascript:void(0)" class="pl-0 col-11 att-file-name" file-id=${att.id}>${att.filename}${att.fileext}</a>
+            <a href="/tender/${tender.id}/measure/stage/${stage.order}/download/file/${att.id}" class="col-1 pl-0 att-file-btn"><i class="fa fa-download"></i></a>
+        </div>
+        </td><td>${att.username}</td></tr>`
     }
     $('#alllist-table').html(html);
     $('#alllist-table').on('click', 'tr', function() {
@@ -127,7 +135,15 @@ function getNodeList(node) {
     let html = '';
     for(const att of attData) {
         if (node === att.lid) {
-            html += '<tr><td><a href="javascript:void(0)" file-id="'+ att.id +'">'+ att.filename + att.fileext +'</a></td><td>'+ att.username +'</td></tr>';
+            // html += '<tr><td><a href="javascript:void(0)" file-id="'+ att.id +'">'+ att.filename + att.fileext +'</a></td><td>'+ att.username +'</td></tr>';
+            html += `<tr>
+            <td width="25"><input type="checkbox" class="check-file" file-id=${att.id}></td>
+            <td>
+            <div class="d-flex">
+                <a href="javascript:void(0)" class="pl-0 col-11 att-file-name" file-id=${att.id}>${att.filename}${att.fileext}</a>
+                <a href="/tender/${tender.id}/measure/stage/${stage.order}/download/file/${att.id}" class="col-1 pl-0 att-file-btn"><i class="fa fa-download"></i></a>
+            </div>
+            </td><td>${att.username}</td></tr>`
         }
     }
     $('#nodelist-table').html(html);
@@ -2484,6 +2500,29 @@ $(document).ready(() => {
         }
         _initModifyDetail() {
             const self = this;
+            // 重置
+            $('#reset-detail-ok').click(function () {
+                const data = SpreadJsObj.getSelectObject(self.spread.getActiveSheet());
+                if (!data.uuid) return;
+                const updateData = {
+                    lid: data.lid, pid: data.pid,
+                    uuid: data.uuid,
+                    custom_define: [],
+                };
+                for (const f of data.custom_define) {
+                    if (stageIm.resetFields.indexOf(f) >= 0) {
+                        updateData[f] = null;
+                    } else {
+                        updateData.custom_define.push(f);
+                    }
+                }
+                updateData.custom_define = updateData.custom_define.join(',');
+                $('#reset-detail-modal').modal('hide');
+                postData(window.location.pathname + '/detail/save', updateData, function (result) {
+                    stageIm.loadUpdateDetailData(result);
+                    self.reLoadDetailData();
+                });
+            });
             // 编辑
             $('#edit-detail').click(function () {
                 $(this).hide();
@@ -2688,11 +2727,7 @@ $(document).ready(() => {
                     if (data.uuid) {
                         updateData.uuid = data.uuid;
                     }
-                    if (data.custom_define.indexOf('calc_img') === -1) {
-                        updateData.custom_define = data.custom_define;
-                        updateData.custom_define.push('calc_img');
-                        updateData.custom_define = updateData.custom_define.join(',');
-                    }
+
                     updateData.img = canvas.toDataURL('image/png');
                     updateData.imgInfo = itemInfo;
                     updateData.calc_img_remark = img_remark;
@@ -2776,7 +2811,14 @@ $(document).ready(() => {
         }
         reLoadDetailData() {
             const data = SpreadJsObj.getSelectObject(this.spread.getActiveSheet());
+            $('#reset-detail').hide();
             if (data) {
+                for (const f of data.custom_define) {
+                    if (stageIm.resetFields.indexOf(f) >= 0) {
+                        $('#reset-detail').show();
+                        break;
+                    }
+                }
                 $('#edit-detail').show();
                 $('#modify-img').show();
             } else {
@@ -3145,7 +3187,7 @@ $(document).ready(() => {
     });
 
     // 获取附件信息
-    $('body').on('click', '.list-table a', function () {
+    $('.list-table').on('click', '.att-file-name', function () {
         const fid = $(this).attr('file-id');
         if ($('#showAttachment').attr('file-id') === fid && !$('#showAttachment').is(":hidden")) {
             return;
@@ -3161,11 +3203,11 @@ $(document).ready(() => {
             $('#show-att tr').eq(0).children('td').text(att.filename + att.fileext);
             const name = att.code !== null && att.code !== '' ? att.code : (att.b_code !== null ? att.b_code : '');
             $('#show-att tr').eq(1).children('td').text($.trim(name + ' ' + att.lname));
-            $('#show-att tr').eq(2).find('a').attr('href', '/tender/' + tender.id + '/measure/stage/' + stage.order + '/download/file/' + att.id);
+            // $('#show-att tr').eq(2).find('a').attr('href', '/tender/' + tender.id + '/measure/stage/' + stage.order + '/download/file/' + att.id);
             // $('#show-att tr').eq(2).find('a').attr('href', att.filepath);
-            $('#show-att tr').eq(3).children('td').eq(0).text(att.username);
-            $('#show-att tr').eq(3).children('td').eq(1).text(att.in_time);
-            $('#show-att tr').eq(4).children('td').text(att.remark);
+            $('#show-att tr').eq(2).children('td').eq(0).text(att.username);
+            $('#show-att tr').eq(2).children('td').eq(1).text(att.in_time);
+            $('#show-att tr').eq(3).children('td').text(att.remark);
             // 附件uid等于当前用户id, 附件上传本人
             if (parseInt(cur_uid) === att.uid) {
                 $('#btn-att').show();
@@ -3251,7 +3293,7 @@ $(document).ready(() => {
                 $('#show-att tr').eq(0).children('td').text(data.filename + data.fileext);
                 const name = data.code !== null && data.code !== '' ? data.code : (data.b_code !== null ? data.b_code : '');
                 $('#show-att tr').eq(1).children('td').text($.trim(name + ' ' + data.lname));
-                $('#show-att tr').eq(2).find('a').attr('href', '/tender/' + tender.id + '/measure/stage/' + stage.order + '/download/file/' + data.id);
+                // $('#show-att tr').eq(2).find('a').attr('href', '/tender/' + tender.id + '/measure/stage/' + stage.order + '/download/file/' + data.id);
                 $('#show-att tr').eq(3).children('td').eq(0).text(data.username);
                 $('#show-att tr').eq(3).children('td').eq(1).text(data.in_time);
                 $('#show-att tr').eq(4).children('td').text(data.remark);
@@ -3335,6 +3377,57 @@ $(document).ready(() => {
             $('#showAttachment').hide();
         }
     });
+
+    // 批量下载
+    $('#bach-download').click(function() {
+        const fileIds = []
+        $('.tab-pane.active .list-table .check-file:checked').each(function() {
+            const fileId = $(this).attr('file-id')
+            fileId && fileIds.push(fileId)
+        })
+        console.log('fileIds', fileIds)
+
+        if (fileIds.length) {
+            const url = `/tender/${tender.id}/measure/stage/${stage.order}/download/compresse-file?fileIds=${JSON.stringify(fileIds)}`
+            $('#zipDown').attr('href', url)
+            $("#zipDown")[0].click()
+            // 执行请求
+            // postData('/tender/' + tender.id + '/measure/stage/' + stage.order + '/download/compresse-file', { fileIds }, function(data) {
+            //     console.log(data)
+            // })
+            // $.ajax({
+            //     type:"get",
+            //     // url: '/tender/' + tender.id + '/measure/stage/' + stage.order + '/download/compresse-file',
+            //     url: `/tender/${tender.id}/measure/stage/${stage.order}/download/compresse-file?fileids=${JSON.stringify(fileids)}`,
+            //     dataType: 'json',
+            //     cache: false,
+            //     // 告诉jQuery不要去设置Content-Type请求头
+            //     contentType: false,
+            //     // 告诉jQuery不要去处理发送的数据
+            //     processData: false,
+            //     timeout: 60000,
+            // })
+        }
+    });
+
+    // 监听附件check是否选中
+    $('.list-table').on('click', '.check-file', function() {
+        const checkedList = $(this).parents('.list-table').children().find('input:checked')
+        const childs = $(this).parents('.list-table').children().length
+        const checkBox = $(this).parents('.list-table').parent().find('.check-all-file')
+        if (checkedList.length === childs) {
+            checkBox.prop("checked", true)
+        } else {
+            checkBox.prop("checked", false)
+        }
+    });
+    $('.check-all-file').click(function() {
+        const isCheck = $(this).is(':checked')
+        $(this).parents('table').find('.list-table').each(function() {
+            $(this).find('input:checkbox').prop("checked", isCheck)
+        })
+    });
+
     // 显示层次
     (function (select, sheet) {
         $(select).click(function () {

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

@@ -131,7 +131,7 @@ $(document).ready(() => {
             {title: '相关台账|项目节编号', colSpan: '5|1', rowSpan: '1|1', field: 'leaf_xmj_code', hAlign: 0, width: 120, formatter: '@', readOnly: true},
             {title: '|名称', colSpan: '|1', rowSpan: '1', field: 'leaf_xmj_name', hAlign: 0, width: 150, formatter: '@', readOnly: true},
             {title: '|计量单元', colSpan: '|1', rowSpan: '1', field: 'p_name', hAlign: 0, width: 150, type: 'Number', readOnly: true},
-            {title: '|0号台数量', colSpan: '|1', rowSpan: '1', field: 'f_qty', hAlign: 2, width: 80, formatter: '@', readOnly: true},
+            {title: '|0号台数量', colSpan: '|1', rowSpan: '1', field: 'f_qty', hAlign: 2, width: 80, formatter: '@', readOnly: true},
             {title: '|本期变更数量', colSpan: '|1', rowSpan: '1', field: 'qty', hAlign: 2, width: 80, type: 'Number', readOnly: true},
         ],
         emptyRows: 0,

+ 15 - 4
app/public/js/stage_im.js

@@ -9,7 +9,8 @@
  */
 
 const stageIm = (function () {
-    const imFields = ['uuid', 'doc_code', 'peg', 'bw', 'xm', 'drawing_code', 'calc_memo', 'calc_img', 'calc_img_org','calc_img_remark', 'position', 'jldy'];
+    const imFields = ['uuid', 'peg', 'bw', 'xm', 'drawing_code', 'calc_memo', 'position', 'jldy'];
+    const resetFields = ['peg', 'bw', 'xm', 'drawing_code', 'calc_memo', 'position', 'jldy'];
     const splitChar = '-';
     const mergeChar = ';';
     let stage, imType, decimal, details, changes, ImData, pre;
@@ -254,10 +255,19 @@ const stageIm = (function () {
     }
 
     function loadCustomDetail(im, detail) {
+        if (!im.org) {
+            im.org = {};
+            for (const f of resetFields) {
+                im.org[f] = im[f];
+            }
+        }
         im.custom_define = detail.custom_define ? detail.custom_define.split(',') : imFields;
         _.assignInWith(im, detail, function (oV, sV, key) {
-            return (im.custom_define.indexOf(key) > -1 && sV !== undefined && sV !== null) ? sV : oV;
+            return (im.custom_define.indexOf(key) > -1) ? sV : ((resetFields.indexOf(key) > -1) ? im.org[key] : oV);
         });
+        im.uuid = detail.uuid;
+        im.doc_code = detail.doc_code;
+        im.calc_img = detail.calc_img;
         im.calc_img_org = detail.calc_img_org;
         im.calc_img_remark = detail.calc_img_remark;
     }
@@ -867,8 +877,8 @@ const stageIm = (function () {
         for (const d of datas) {
             const detail = _.find(details, {uuid: d.uuid});
             if (detail) {
-                _.assignInWith(detail, d, function (oV, sV, key) {
-                    return imFields.indexOf(key) > -1 && !_.isUndefined(sV) && !_.isNull(sV) ? sV : oV;
+                _.assignInWith(detail, d, function (oV, sV) {
+                    return !_.isUndefined(sV) ? sV : oV;
                 });
                 detail.custom_define = d.custom_define;
             } else {
@@ -988,5 +998,6 @@ const stageIm = (function () {
         getFirstUsed: getFirstUsed,
         getRelaXmj: getRelaXmj,
         getRelaImData: getRelaImData,
+        resetFields,
     }
 })();

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

@@ -813,8 +813,8 @@ $(document).ready(() => {
                         if (col.field === 'tp') {
                             updateData.pid = node.pid;
                             const [valid, msg] = payBase.isSF(node)
-                                ? paySpreadObj._checkSfExpr(validText, data.updateData)
-                                : paySpreadObj._checkExpr(validText, data.updateData);
+                                ? paySpreadObj._checkSfExpr(validText, updateData)
+                                : paySpreadObj._checkExpr(validText, updateData);
                             if (!valid) {
                                 toastr.warning(msg);
                                 SpreadJsObj.reLoadSheetData(paySpread.getActiveSheet());

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

@@ -386,7 +386,7 @@ function getTenderTreeHtml () {
         html.push('<th class="text-center" style="width: 6%">', '计量进度', '</th>');
         html.push('<th class="text-center" style="width: 6%">', '当前流程', '</th>');
         html.push('<th class="text-center" style="width: 8%">', '上一流程审批时间', '</th>');
-        html.push('<th class="text-center" style="width: 6%">', '0号台', '</th>');
+        html.push('<th class="text-center" style="width: 6%">', '0号台', '</th>');
         html.push('<th class="text-center" style="width: 6%">', '本期完成', '</th>');
         html.push('<th class="text-center" style="width: 6%">', '截止本期合同', '</th>');
         html.push('<th class="text-center" style="width: 6%">', '截止本期变更', '</th>');

+ 2 - 0
app/router.js

@@ -217,6 +217,7 @@ module.exports = app => {
     app.post('/tender/:id/measure/stage/:order/delete/file', sessionAuth, tenderCheck, uncheckTenderCheck, stageCheck, 'stageController.deleteFile');
     app.post('/tender/:id/measure/stage/:order/save/file', sessionAuth, tenderCheck, uncheckTenderCheck, stageCheck, 'stageController.saveFile');
     app.post('/tender/:id/measure/stage/:order/check/file', sessionAuth, tenderCheck, uncheckTenderCheck, stageCheck, 'stageController.checkFile');
+    app.get('/tender/:id/measure/stage/:order/download/compresse-file', sessionAuth, tenderCheck, uncheckTenderCheck, stageCheck, 'stageController.downloadZip');
 
     // 中间计量
     app.get('/tender/:id/measure/stage/:order/detail', sessionAuth, tenderCheck, uncheckTenderCheck, stageCheck, 'stageController.detail');
@@ -345,6 +346,7 @@ module.exports = app => {
     app.get('/tender/:id/measure/material/:order/file/:fid/download', sessionAuth, tenderCheck, uncheckTenderCheck, 'materialController.downloadFile');
     app.post('/tender/:id/measure/material/:order/file/find', sessionAuth, tenderCheck, uncheckTenderCheck, materialCheck, 'materialController.getCurMatericalFiles');
     app.post('/tender/measure/material/file/delete', sessionAuth, 'materialController.deleteFile');
+    app.get('/tender/:id/measure/material/:order/file/download/compresse-file', sessionAuth, tenderCheck, uncheckTenderCheck, 'materialController.downloadZip');
 
     // 个人账号相关
     app.get('/profile/info', sessionAuth, 'profileController.info');

+ 124 - 75
app/service/material_file.js

@@ -1,75 +1,124 @@
-'use strict';
-const auditConst = require('../const/audit');
-/**
- * 附件表 数据模型
- * @author LanJianRong
- * @date 2020/6/30
- * @version
- */
-
-module.exports = app => {
-    class MaterialFile extends app.BaseService {
-        /**
-         * 构造函数
-         *
-         * @param {Object} ctx - egg全局变量
-         * @return {void}
-         */
-        constructor(ctx) {
-            super(ctx);
-            this.tableName = 'material_file';
-        }
-
-        /**
-         * 获取当前标段(期)所有上传的附件
-         * @param {Number} tid 标段id
-         * @param {Number?} mid 期id
-         * @return {Promise<void>} 数据库查询实例
-         */
-        async getAllMaterialFiles(tid, mid) {
-            const { ctx } = this;
-            const where = { tid };
-            if (mid) where.mid = mid;
-            const result = await this.db.select(this.tableName, {
-                where,
-                orders: [['upload_time', 'desc']],
-            });
-            return result.map(item => {
-                if (!ctx.helper.canPreview(item.fileext)) {
-                    item.filepath = `tender/${ctx.tender.id}/measure/material/${item.s_order}/file/${item.id}/download`;
-                }
-                return item;
-            });
-        }
-
-
-        /**
-         * 存储上传的文件信息至数据库
-         * @param {Array} payload 载荷
-         * @return {Promise<void>} 数据库插入执行实例
-         */
-        async saveFileMsgToDb(payload) {
-            return await this.db.insert(this.tableName, payload);
-        }
-
-        /**
-         * 获取单个文件信息
-         * @param {Number} id 文件id
-         * @return {Promise<void>} 数据库查询实例
-         */
-        async getMaterialFileById(id) {
-            return await this.getDataByCondition({ id });
-        }
-
-        /**
-         * 删除附件
-         * @param {Number} id - 附件id
-         * @return {void}
-         */
-        async delete(id) {
-            return await this.deleteById(id);
-        }
-    }
-    return MaterialFile;
-};
-
+'use strict';
+const archiver = require('archiver');
+const path = require('path');
+const fs = require('fs');
+/**
+ * 附件表 数据模型
+ * @author LanJianRong
+ * @date 2020/6/30
+ * @version
+ */
+
+module.exports = app => {
+    class MaterialFile extends app.BaseService {
+        /**
+         * 构造函数
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'material_file';
+        }
+
+        /**
+         * 获取当前标段(期)所有上传的附件
+         * @param {Number} tid 标段id
+         * @param {Number?} mid 期id
+         * @return {Promise<void>} 数据库查询实例
+         */
+        async getAllMaterialFiles(tid, mid) {
+            const { ctx } = this;
+            const where = { tid };
+            if (mid) where.mid = mid;
+            const result = await this.db.select(this.tableName, {
+                where,
+                orders: [['upload_time', 'desc']],
+            });
+            return result.map(item => {
+                if (!ctx.helper.canPreview(item.fileext)) {
+                    item.filepath = `tender/${ctx.tender.id}/measure/material/${item.s_order}/file/${item.id}/download`;
+                }
+                return item;
+            });
+        }
+
+
+        /**
+         * 存储上传的文件信息至数据库
+         * @param {Array} payload 载荷
+         * @return {Promise<void>} 数据库插入执行实例
+         */
+        async saveFileMsgToDb(payload) {
+            return await this.db.insert(this.tableName, payload);
+        }
+
+        /**
+         * 获取单个文件信息
+         * @param {Number} id 文件id
+         * @return {Promise<void>} 数据库查询实例
+         */
+        async getMaterialFileById(id) {
+            return await this.getDataByCondition({ id });
+        }
+
+        /**
+         * 删除附件
+         * @param {Number} id - 附件id
+         * @return {void}
+         */
+        async delete(id) {
+            return await this.deleteById(id);
+        }
+
+        /**
+         * 将文件压缩成zip,并返回zip文件的路径
+         * @param {array} fileIds - 文件数组id
+         * @param {string} zipPath - 压缩文件存储路径
+         * @return {string} 压缩后的zip文件路径
+         */
+        async compressedFile(fileIds, zipPath) {
+            this.initSqlBuilder();
+            this.sqlBuilder.setAndWhere('id', {
+                value: fileIds,
+                operate: 'in',
+            });
+            const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
+            const files = await this.db.query(sql, sqlParam);
+            // const paths = files.map(item => {
+            //     return { name: item.filename + item.fileext, path: item.filepath }
+            // })
+            return new Promise(resolve => {
+                // 每次开一个新的archiver
+                const ziparchiver = archiver('zip');
+                const outputPath = fs.createWriteStream(path.resolve(this.app.baseDir, zipPath));
+                ziparchiver.pipe(outputPath);
+                files.forEach(item => {
+                    ziparchiver.file(path.resolve(this.app.baseDir, 'app', item.filepath), { name: item.file_name });
+                });
+
+                // 存档警告
+                ziparchiver.on('warning', function(err) {
+                    if (err.code === 'ENOENT') {
+                        console.warn('stat故障和其他非阻塞错误');
+                    } else {
+                        throw err;
+                    }
+                });
+
+                // 存档出错
+                ziparchiver.on('error', function(err) {
+                    console.log(err);
+                    throw err;
+                });
+                ziparchiver.finalize();
+                outputPath.on('close', () => {
+                    resolve(ziparchiver.pointer());
+                });
+            });
+        }
+    }
+    return MaterialFile;
+};
+

+ 2 - 2
app/service/revise_audit.js

@@ -243,7 +243,7 @@ module.exports = app => {
                 // 添加短信通知-需要审批提醒功能
                 // 下一人
                 // await this.ctx.helper.sendUserSms(audit.audit_id, smsTypeConst.const.XD,
-                //     smsTypeConst.judge.approval.toString(), '台修订需要您审批,请登录系统处理。');
+                //     smsTypeConst.judge.approval.toString(), '台修订需要您审批,请登录系统处理。');
                 await this.ctx.helper.sendAliSms(audit.audit_id, smsTypeConst.const.XD, smsTypeConst.judge.approval.toString(), SmsAliConst.template.revise_check);
                 // 微信模板通知
                 const wechatData = {
@@ -375,7 +375,7 @@ module.exports = app => {
                         // 短信通知-需要审批提醒功能
                         // 下一人
                         // await this.ctx.helper.sendUserSms(nextAudit.user_id, smsTypeConst.const.XD,
-                        //     smsTypeConst.judge.approval.toString(), '台修订需要您审批,请登录系统处理。');
+                        //     smsTypeConst.judge.approval.toString(), '台修订需要您审批,请登录系统处理。');
                         await this.ctx.helper.sendAliSms(nextAudit.audit_id, smsTypeConst.const.XD, smsTypeConst.judge.approval.toString(), SmsAliConst.template.revise_check);
                         // 微信模板通知
                         const wechatData = {

+ 144 - 95
app/service/stage_att.js

@@ -1,95 +1,144 @@
-'use strict';
-
-/**
- *
- *  附件
- * @author Ellisran
- * @date 2019/1/11
- * @version
- */
-
-module.exports = app => {
-    class StageAtt extends app.BaseService {
-        /**
-         * 构造函数
-         *
-         * @param {Object} ctx - egg全局变量
-         * @return {void}
-         */
-        constructor(ctx) {
-            super(ctx);
-            this.tableName = 'stage_attachment';
-        }
-
-        /**
-         * 添加附件
-         * @param {Object} postData - 表单信息
-         * @param {Object} fileData - 文件信息
-         * @param {int} uid - 上传者id
-         * @return {void}
-         */
-        async save(postData, fileData, uid) {
-            const data = {
-                lid: postData.lid,
-                uid,
-                remark: '',
-            };
-            Object.assign(data, fileData);
-            const result = await this.db.insert(this.tableName, data);
-            return result;
-        }
-
-        /**
-         * 添加附件
-         * @param {Object} postData - 表单信息
-         * @param {Object} fileData - 文件信息
-         * @param {int} uid - 上传者id
-         * @return {void}
-         */
-        async updateByID(postData, fileData) {
-            delete postData.size;
-            const data = {};
-            Object.assign(data, fileData);
-            Object.assign(data, postData);
-            const result = await this.db.update(this.tableName, data);
-            return result.affectedRows === 1;
-        }
-
-        /**
-         * 获取所有附件
-         * @param {int} tid - 标段id
-         * @param {int} sid - 当前期数
-         * @return {void}
-         */
-        async getDataByTenderIdAndStageId(tid, sid) {
-            const { ctx } = this;
-            const sql = 'SELECT att.id, att.lid, att.uid, att.filename, att.fileext, att.filesize, att.re_upload, att.remark, att.in_time,' +
-                ' pa.name as `username`, leg.name as `lname`, leg.code as `code`, leg.ledger_id as `ledger_id`, leg.b_code as `b_code`' +
-                ' FROM ?? AS att,?? AS pa,?? AS leg' +
-                ' WHERE leg.id = att.lid AND pa.id = att.uid AND att.tid = ? AND att.sid = ? ORDER BY att.id DESC';
-            const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, this.ctx.service.ledger.tableName, tid, sid];
-            return await this.db.query(sql, sqlParam);
-        }
-
-        /**
-         * 获取单个附件
-         * @param {int} tid - 标段id
-         * @param {int} sid - 当前期数
-         * @return {void}
-         */
-        async getDataByFid(id) {
-            const { ctx } = this;
-            const sql = 'SELECT att.id, att.lid, att.uid, att.filepath, att.filename, att.re_upload, att.fileext, att.filesize, att.remark, att.in_time,' +
-                ' pa.name as `username`, leg.name as `lname`, leg.code as `code`, leg.ledger_id as `ledger_id`,leg.b_code as `b_code`' +
-                ' FROM ?? AS att,?? AS pa,?? AS leg' +
-                ' WHERE leg.id = att.lid AND pa.id = att.uid AND att.id = ? ORDER BY att.in_time DESC';
-            const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, this.ctx.service.ledger.tableName, id];
-            const result = await this.db.queryOne(sql, sqlParam);
-            if (!ctx.helper.canPreview(result.fileext)) result.filepath = `/tender/${ctx.tender.id}/measure/stage/${ctx.params.order}/download/file/${result.id}`;
-            else result.filepath = result.filepath.replace(/^app|\/app/, '');
-            return result;
-        }
-    }
-
-    return StageAtt;
-};
+'use strict';
+
+/**
+ *
+ *  附件
+ * @author Ellisran
+ * @date 2019/1/11
+ * @version
+ */
+
+const archiver = require('archiver');
+const path = require('path');
+const fs = require('fs');
+module.exports = app => {
+    class StageAtt extends app.BaseService {
+        /**
+         * 构造函数
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'stage_attachment';
+        }
+
+        /**
+         * 添加附件
+         * @param {Object} postData - 表单信息
+         * @param {Object} fileData - 文件信息
+         * @param {int} uid - 上传者id
+         * @return {void}
+         */
+        async save(postData, fileData, uid) {
+            const data = {
+                lid: postData.lid,
+                uid,
+                remark: '',
+            };
+            Object.assign(data, fileData);
+            const result = await this.db.insert(this.tableName, data);
+            return result;
+        }
+
+        /**
+         * 添加附件
+         * @param {Object} postData - 表单信息
+         * @param {Object} fileData - 文件信息
+         * @param {int} uid - 上传者id
+         * @return {void}
+         */
+        async updateByID(postData, fileData) {
+            delete postData.size;
+            const data = {};
+            Object.assign(data, fileData);
+            Object.assign(data, postData);
+            const result = await this.db.update(this.tableName, data);
+            return result.affectedRows === 1;
+        }
+
+        /**
+         * 获取所有附件
+         * @param {int} tid - 标段id
+         * @param {int} sid - 当前期数
+         * @return {void}
+         */
+        async getDataByTenderIdAndStageId(tid, sid) {
+            const { ctx } = this;
+            const sql = 'SELECT att.id, att.lid, att.uid, att.filename, att.fileext, att.filesize, att.re_upload, att.remark, att.in_time,' +
+                ' pa.name as `username`, leg.name as `lname`, leg.code as `code`, leg.ledger_id as `ledger_id`, leg.b_code as `b_code`' +
+                ' FROM ?? AS att,?? AS pa,?? AS leg' +
+                ' WHERE leg.id = att.lid AND pa.id = att.uid AND att.tid = ? AND att.sid = ? ORDER BY att.id DESC';
+            const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, this.ctx.service.ledger.tableName, tid, sid];
+            return await this.db.query(sql, sqlParam);
+        }
+
+        /**
+         * 获取单个附件
+         * @param {int} tid - 标段id
+         * @param {int} sid - 当前期数
+         * @return {void}
+         */
+        async getDataByFid(id) {
+            const { ctx } = this;
+            const sql = 'SELECT att.id, att.lid, att.uid, att.filepath, att.filename, att.re_upload, att.fileext, att.filesize, att.remark, att.in_time,' +
+                ' pa.name as `username`, leg.name as `lname`, leg.code as `code`, leg.ledger_id as `ledger_id`,leg.b_code as `b_code`' +
+                ' FROM ?? AS att,?? AS pa,?? AS leg' +
+                ' WHERE leg.id = att.lid AND pa.id = att.uid AND att.id = ? ORDER BY att.in_time DESC';
+            const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, this.ctx.service.ledger.tableName, id];
+            const result = await this.db.queryOne(sql, sqlParam);
+            if (!ctx.helper.canPreview(result.fileext)) result.filepath = `/tender/${ctx.tender.id}/measure/stage/${ctx.params.order}/download/file/${result.id}`;
+            else result.filepath = result.filepath.replace(/^app|\/app/, '');
+            return result;
+        }
+
+        /**
+         * 将文件压缩成zip,并返回zip文件的路径
+         * @param {array} fileIds - 文件数组id
+         * @param {string} zipPath - 压缩文件存储路径
+         * @return {string} 压缩后的zip文件路径
+         */
+        async compressedFile(fileIds, zipPath) {
+            this.initSqlBuilder();
+            this.sqlBuilder.setAndWhere('id', {
+                value: fileIds,
+                operate: 'in',
+            });
+            const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
+            const files = await this.db.query(sql, sqlParam);
+            // const paths = files.map(item => {
+            //     return { name: item.filename + item.fileext, path: item.filepath }
+            // })
+            return new Promise(resolve => {
+                // 每次开一个新的archiver
+                const ziparchiver = archiver('zip');
+                const outputPath = fs.createWriteStream(path.resolve(this.app.baseDir, zipPath));
+                ziparchiver.pipe(outputPath);
+                files.forEach(item => {
+                    ziparchiver.file(item.filepath, { name: item.filename + item.fileext });
+                });
+
+                // 存档警告
+                ziparchiver.on('warning', function(err) {
+                    if (err.code === 'ENOENT') {
+                        console.warn('stat故障和其他非阻塞错误');
+                    } else {
+                        throw err;
+                    }
+                });
+
+                // 存档出错
+                ziparchiver.on('error', function(err) {
+                    console.log(err);
+                    throw err;
+                });
+                ziparchiver.finalize();
+                outputPath.on('close', () => {
+                    resolve(ziparchiver.pointer());
+                });
+            });
+        }
+    }
+    return StageAtt;
+};

+ 1 - 1
app/view/change/info.ejs

@@ -129,7 +129,7 @@
                 <div>
                     <% if (auditStatus === 1 || auditStatus === 2) { %>
                     <div class="d-inline-block">
-                        <a href="#addlist" data-toggle="modal" class="btn btn-sm btn-light text-primary" id="open-list-modal" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="添加清单"><i class="fa fa-plus" aria-hidden="true"></i> 添加台清单</a>
+                        <a href="#addlist" data-toggle="modal" class="btn btn-sm btn-light text-primary" id="open-list-modal" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="添加清单"><i class="fa fa-plus" aria-hidden="true"></i> 添加台清单</a>
                     </div>
                     <div class="d-inline-block mr-3">
                         <a href="javascript:void(0);" class="btn btn-sm btn-light text-primary" id="add-white-btn" data-original-title="添加清单"><i class="fa fa-plus" aria-hidden="true"></i> 添加空白清单</a>

+ 7 - 7
app/view/dashboard/index.ejs

@@ -35,8 +35,8 @@
                                             <li class="media pb-3 mb-3 border-bottom-1">
                                                 <div class="media-body">
                                                     <div class="row">
-                                                        <div class="col-auto"><span class="badge badge-info">台审批</span></div>
-                                                        <div class="col-6"><a href="/tender/<%- t.id %>"><%- t.name %></a> 台</div>
+                                                        <div class="col-auto"><span class="badge badge-info">台审批</span></div>
+                                                        <div class="col-6"><a href="/tender/<%- t.id %>"><%- t.name %></a> 台</div>
                                                         <div class="col-3 ml-auto text-right pl-0"><a href="/tender/<%- t.id %>/ledger/audit" class="btn btn-sm btn-outline-primary">审批</a></div>
                                                     </div>
                                                     <p class="mt-1 mb-0"><%- ctx.session.sessionUser.name %><small class="ml-1 text-muted"><%- (role ? '- ' + role : '') %></small>
@@ -48,8 +48,8 @@
                                             <li class="media pb-3 mb-3 border-bottom-1">
                                                 <div class="media-body">
                                                     <div class="row">
-                                                        <div class="col-auto"><span class="badge badge-info">台审批</span></div>
-                                                        <div class="col-6"><a href="/tender/<%- t.id %>"><%- t.name %></a> 台</div>
+                                                        <div class="col-auto"><span class="badge badge-info">台审批</span></div>
+                                                        <div class="col-6"><a href="/tender/<%- t.id %>"><%- t.name %></a> 台</div>
                                                         <div class="col-3 ml-auto text-right pl-0"><a href="/tender/<%- t.id %>/ledger" class="btn btn-sm btn-outline-primary">重新上报</a></div>
                                                     </div>
                                                     <p class="mt-1 mb-0"><%- ctx.session.sessionUser.name %><small class="ml-1 text-muted"><%- (role ? '- ' + role : '') %></small>
@@ -63,8 +63,8 @@
                                         <li class="media pb-3 mb-3 border-bottom-1">
                                             <div class="media-body">
                                                 <div class="row">
-                                                    <div class="col-auto"><span class="badge badge-info">台修订</span></div>
-                                                    <div class="col-6"><a href="/tender/<%- revise.t_id %>"><%- revise.t_name %></a> 台修订(第<%- revise.corder %>次)</div>
+                                                    <div class="col-auto"><span class="badge badge-info">台修订</span></div>
+                                                    <div class="col-6"><a href="/tender/<%- revise.t_id %>"><%- revise.t_name %></a> 台修订(第<%- revise.corder %>次)</div>
                                                     <div class="col-3 ml-auto text-right pl-0"><a href="/tender/<%- revise.t_id %>/revise/info" class="btn btn-sm btn-outline-primary"><% if (revise.status === acRevise.status.checking) { %>审批<% } else if (revise.status === acRevise.status.checkNo) { %>重新上报<% } %></a></div>
                                                 </div>
                                                 <p class="mt-1 mb-0"><%- revise.audit_name %><small class="ml-1 text-muted"><%- (revise.audit_role ? '- ' + revise.audit_role: '') %></small>
@@ -225,7 +225,7 @@
                                             <li class="media pb-3 mb-3 border-bottom-1">
                                                 <div class="media-body">
                                                     <div class="row">
-                                                        <div class="col-auto"><span class="badge badge-info">台审批</span></div>
+                                                        <div class="col-auto"><span class="badge badge-info">台审批</span></div>
                                                         <div class="col-6">
                                                             <a data-id="<%- notice.id %>"href="/tender/<%- notice.tid %>/ledger"><%- notice.name %></a> <%- acLedger.statusString[notice.status]%>
                                                         </div>

+ 1 - 1
app/view/layout/modal.ejs

@@ -15,7 +15,7 @@
     </div>
 </div>
 
-<!--弹出新建台变更-->
+<!--弹出新建台变更-->
 <div class="modal fade" id="add-bg" data-backdrop="static">
     <div class="modal-dialog" role="document">
         <div class="modal-content">

+ 1 - 1
app/view/ledger/explode_modal.ejs

@@ -6,7 +6,7 @@
                 <h5 class="modal-title">导入</h5>
             </div>
             <div class="modal-body">
-                <p>请上传符合格式的 <b>0号台</b> 格式的 .xls和.xlsx 文件,<a id="downloadLedgerTemplate" href="/tender/<%- ctx.tender.id %>/ledger/download/导入分项清单EXCEL格式.xls">下载示例</a>。</p>
+                <p>请上传符合格式的 <b>0号台</b> 格式的 .xls和.xlsx 文件,<a id="downloadLedgerTemplate" href="/tender/<%- ctx.tender.id %>/ledger/download/导入分项清单EXCEL格式.xls">下载示例</a>。</p>
                 <div class="form-group">
                     <label for="exampleFormControlFile1">选择文件</label><i class="fa fa-spinner fa-pulse fa-lg fa-fw text-primary" id="select-excel-loading" style="display: none;"></i>
                     <input type="file" class="form-control-file" id="upload-ledger-file" accept="*.xls">

+ 1 - 1
app/view/ledger/gather.ejs

@@ -46,7 +46,7 @@
                         <div class="side-bar-1"></div>
                         <div class="sjs-sh-1">
                             <table class="table table-bordered">
-                                <tr><th>章节</th><th>章节名称</th><th>签约金额</th><th>台帐金额</th><th>签约-台帐</th></tr>
+                                <tr><th>章节</th><th>章节名称</th><th>签约金额</th><th>台账金额</th><th>签约-台账</th></tr>
                                 <tbody id="chapter-list"></tbody>
                             </table>
                         </div>

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

@@ -42,7 +42,7 @@
                     <th rowspan="2">名称</th>
                     <th rowspan="2">单位</th>
                     <th rowspan="2">单价</th>
-                    <th colspan="2">0号台合同</th>
+                    <th colspan="2">0号台合同</th>
                     <th colspan="2">本期合同计量</th>
                     <th colspan="3">本期数量变更计量</th>
                     <th colspan="2">本期完成计量</th>

+ 14 - 2
app/view/material/file.ejs

@@ -5,14 +5,24 @@
       <% include ./material_sub_mini_menu.ejs %>
       <div>
         <div class="d-inline-block">
-          <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>
+          <div class="dropdown">
+            <button class="btn btn-sm btn-light dropdown-toggle text-primary" type="button" id="dropdownMenuButton" btn-type="curr" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">当前期</button>
+            <div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
+              <a class="dropdown-item" href="#">所有期</a>
+            </div>
+          </div>
         </div>
         <div class="d-inline-block">
+          <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>
+          <a href="" id="downloadZip" style="display: none;" download></a>
+        </div>
+        <!-- <div class="d-inline-block">
           <span class="d-flex align-items-center" style="margin-left: 5px;">
             <input type="checkbox" id="file-checkbox">
             <span class="text-primary" style="margin-left: 5px;">所有期</span>
           </span>
-        </div>
+        </div> -->
       </div>
       <!--<div class="d-flex justify-content-start align-items-center">-->
           <!--<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>-->
@@ -29,6 +39,7 @@
         <table class="table table-bordered">
           <thead>
             <tr>
+              <td width="25" style="background-color: #e9ecef;"><input type="checkbox" id="check-all-file" ></td>
               <th width="50">序号</th>
               <th>名称</th>
               <th width="90">大小</th>
@@ -106,6 +117,7 @@
   const auditConst = JSON.parse('<%- JSON.stringify(auditConst) %>');
   const tid = '<%- ctx.tender.id %>';
   const mid = '<%- ctx.material.id %>';
+  const order = '<%- ctx.material.order %>';
   const fileList = JSON.parse('<%- JSON.stringify(fileList) %>');
   const whiteList = JSON.parse('<%- JSON.stringify(whiteList) %>');
 </script>

+ 2 - 2
app/view/revise/history.ejs

@@ -36,7 +36,7 @@
         <div class="row w-100 sub-content">
             <!--左栏-->
             <div class="c-body" id="left-view" style="width: 100%">
-                <!--0号台模式-->
+                <!--0号台模式-->
                 <div class="sjs-height-1" style="overflow: hidden" id="bills-spread">
                 </div>
                 <% if (ctx.tender.data.measure_type === measureType.tz.value) { %>
@@ -70,7 +70,7 @@
                                     <% } %>
                                 </select>
                             </div>
-                            <div class="alert alert-warning">历史修订暂不支持查看历史台。</div>
+                            <div class="alert alert-warning">历史修订暂不支持查看历史台。</div>
                             <div class="form-group mt-2">
                                 <label >提交人</label>
                                 <input id="user-name" type="" class="form-control form-control-sm" value="<%- revise.user_name %>" disabled>

+ 1 - 1
app/view/revise/info.ejs

@@ -75,7 +75,7 @@
         <div class="row w-100 sub-content">
             <!--左栏-->
             <div class="c-body" id="left-view" style="width: 100%">
-                <!--0号台模式-->
+                <!--0号台模式-->
                 <div class="sjs-height-1" style="overflow: hidden" id="bills-spread">
                 </div>
                 <% if (ctx.tender.data.measure_type === measureType.tz.value) { %>

+ 1 - 1
app/view/revise/modal.ejs

@@ -1,4 +1,4 @@
-<!--弹出新建台修订-->
+<!--弹出新建台修订-->
 <div class="modal fade" id="add-bg" data-backdrop="static">
     <form class="modal-dialog" role="document" action="<%- preUrl + '/revise/add' %>" method="post" onsubmit="return dbClick();">
         <div class="modal-content">

+ 1 - 1
app/view/setting/user_permission_modal.ejs

@@ -88,7 +88,7 @@
                 <% } %>
                 <!--需要勾选  创建标段 ,协作办公才能勾选-->
                 <div class="alert alert-secondary">
-                    <p>1.勾选「创建标段」该用户默认具有「新建标段」及标段内「台帐分解」「创建台帐修订」「创建计量期」「创建工程变更」的权限。</p>
+                    <p>1.勾选「创建标段」该用户默认具有「新建标段」及标段内「台账分解」「创建台账修订」「创建计量期」「创建工程变更」的权限。</p>
                     <!--2.启用「协作办公」,则该用户可以为他创建的标段添加其他用户进行协作办公。-->
                 </div>
             </div>

+ 1 - 1
app/view/shares/import_excel_modal.ejs

@@ -7,7 +7,7 @@
                 <h5 class="modal-title">导入</h5>
             </div>
             <div class="modal-body">
-                <p id="import-template">请上传符合 <b id="import-type-hint">0号台</b> 格式的 .xls和.xlsx 文件,<a id="download-template" href="/tender/<%- ctx.tender.id %>/ledger/download/导入分项清单EXCEL格式.xls">下载示例</a>。</p>
+                <p id="import-template">请上传符合 <b id="import-type-hint">0号台</b> 格式的 .xls和.xlsx 文件,<a id="download-template" href="/tender/<%- ctx.tender.id %>/ledger/download/导入分项清单EXCEL格式.xls">下载示例</a>。</p>
                 <div class="form-group">
                     <label for="exampleFormControlFile1">选择文件</label><i class="fa fa-spinner fa-pulse fa-lg fa-fw text-primary" id="select-excel-loading" style="display: none;"></i>
                     <input type="file" class="form-control-file" id="import-excel-file" accept="*.xls">

+ 1 - 1
app/view/shares/ledger_check_modal.ejs

@@ -21,7 +21,7 @@
                 <h5 class="modal-title">数据检查</h5>
             </div>
             <div class="modal-body">
-                <p>数据检查,将检查罗列台中以下内容:</p>
+                <p>数据检查,将检查罗列台中以下内容:</p>
                 <div class="card mb-2 p-2 border-success" id="check-sibling">
                     <div class="d-flex justify-content-between">
                         项目节、清单同层

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

@@ -113,7 +113,7 @@
                                         <div class="sjs-bottom-2">
                                             <table class="table table-sm table-bordered">
                                                 <thead>
-                                                <tr><th>名称</th><th>台数量</th><th>本期计量数量</th></tr>
+                                                <tr><th>名称</th><th>台数量</th><th>本期计量数量</th></tr>
                                                 </thead>
                                                 <tbody id="pos-list">
                                                 <tr><td>0#桥台1#桩</td><td>126</td><td>40</td></tr>

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

@@ -8,7 +8,7 @@
             </div>
             <div class="modal-body">
                 <table class="table table-bordered table-sm">
-                    <thead class="text-center"><tr><th>章节</th><th>章节名称</th><th>签约金额</th><th>台金额</th><th>本期合同计量金额</th><th>本期数量变更金额</th><th>本期完成计量金额</th><th>截止本期合同计量金额</th><th>截止本期数量变更金额</th><th>截止本期完成计量金额</th><th>完成率(%)</th></tr></thead>
+                    <thead class="text-center"><tr><th>章节</th><th>章节名称</th><th>签约金额</th><th>台金额</th><th>本期合同计量金额</th><th>本期数量变更金额</th><th>本期完成计量金额</th><th>截止本期合同计量金额</th><th>截止本期数量变更金额</th><th>截止本期完成计量金额</th><th>完成率(%)</th></tr></thead>
                     <tbody id="chapter-list"></tbody>
                 </table>
             </div>

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 609 - 603
app/view/stage/index.ejs


+ 3 - 3
app/view/stage/measure.ejs

@@ -5,7 +5,7 @@
                 <div class="d-inline-block">
                     <ul class="nav nav-pills m-0">
                         <li class="nav-item"><a class="nav-link" href="/stage">返回</a></li>
-                        <li class="nav-item"><a class="nav-link active" href="/stage/<%- stage.order %>/measure">本期计量台</a></li>
+                        <li class="nav-item"><a class="nav-link active" href="/stage/<%- stage.order %>/measure">本期计量台</a></li>
                         <li class="nav-item"><a class="nav-link" href="/stage/<%- stage.order %>/deal">合同支付</a></li>
                         <li class="nav-item"><a class="nav-link" href="/stage/<%- stage.order %>/report">报表</a></li>
                     </ul>
@@ -355,7 +355,7 @@
                                     </div>
                                     <div class="form-check form-check-inline">
                                         <input class="form-check-input" type="radio" name="inlineRadioOptions" id="inlineRadio2" value="option2">
-                                        <label class="form-check-label" for="inlineRadio2">0号台</label>
+                                        <label class="form-check-label" for="inlineRadio2">0号台</label>
                                     </div>
                                 </div>
                             </div>
@@ -385,7 +385,7 @@
                                             <label>本期计量数量:</label>
                                             <input class="form-control form-control-sm" type="number">
                                         </div>
-                                        <!--0号台-->
+                                        <!--0号台-->
                                         <div class="form-group">
                                             <label>本期计量金额:</label>
                                             <input class="form-control form-control-sm" type="number">

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

@@ -36,7 +36,7 @@
                         <div class="modal-height-250">
                             <table class="table table-bordered">
                                 <thead>
-                                <tr><th width="50" rowspan="2"></th><th rowspan="2">清单编号</th><th rowspan="2">名称</th><th rowspan="2">单位</th><th rowspan="2">单价</th><th colspan="2">0号台</th><th colspan="2">累计完成</th></tr>
+                                <tr><th width="50" rowspan="2"></th><th rowspan="2">清单编号</th><th rowspan="2">名称</th><th rowspan="2">单位</th><th rowspan="2">单价</th><th colspan="2">0号台</th><th colspan="2">累计完成</th></tr>
                                 <tr><th>数量</th><th>金额</th><th>数量</th><th>金额</th></tr>
                                 </thead>
                                 <tbody>

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

@@ -227,7 +227,7 @@
                 <h5 class="modal-title">提示</h5>
             </div>
             <div class="modal-body">
-                <h5>台正在进行修订,本期计量无法进行任何操作。</h5>
+                <h5>台正在进行修订,本期计量无法进行任何操作。</h5>
             </div>
             <div class="modal-footer">
                 <button type="button" class="btn btn-secondary" data-dismiss="modal">好的</button>
@@ -390,6 +390,26 @@
         </div>
     </div>
 </div>
+<!--中间计量重置操作-->
+<div class="modal fade" id="reset-detail-modal" data-backdrop="static">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">中间计量重置</h5>
+            </div>
+            <div class="modal-body">
+                <div class="alert alert-danger" role="alert">
+                    重置将会清空当前中间计量录入的数据(除草图),同时按照系统规则重新生成数据。
+                    请谨慎操作!
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">取消</button>
+                <button type="button" class="btn btn-sm btn-danger" id="reset-detail-ok">确定还原</button>
+            </div>
+        </div>
+    </div>
+</div>
 <% include ./audit_modal.ejs %>
 <% include ../shares/merge_peg_modal.ejs %>
 <% include ../shares/ledger_check_modal.ejs %>

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

@@ -5,7 +5,7 @@
                 <div class="d-inline-block">
                     <ul class="nav nav-pills m-0">
                         <li class="nav-item"><a class="nav-link" href="/stage">返回</a></li>
-                        <li class="nav-item"><a class="nav-link active" href="/stage/<%- stage.order %>/measure">本期计量台</a></li>
+                        <li class="nav-item"><a class="nav-link active" href="/stage/<%- stage.order %>/measure">本期计量台</a></li>
                         <li class="nav-item"><a class="nav-link" href="/stage/<%- stage.order %>/deal">合同支付</a></li>
                         <li class="nav-item"><a class="nav-link" href="/stage/<%- stage.order %>/report">报表</a></li>
                     </ul>

+ 2 - 2
app/view/stage/stage_sub_menu.ejs

@@ -11,7 +11,7 @@
         <div class="nav-box">
             <ul class="nav-list list-unstyled">
                 <li class="<% if (ctx.url === '/tender/' + ctx.tender.id + '/measure/stage/' + ctx.stage.order) { %>active<% } %>">
-                    <a href="/tender/<%- ctx.tender.id %>/measure/stage/<%- ctx.stage.order %>"><span class="ml-3">计量台</span></a>
+                    <a href="/tender/<%- ctx.tender.id %>/measure/stage/<%- ctx.stage.order %>"><span class="ml-3">计量台</span></a>
                 </li>
             </ul>
         </div>
@@ -33,7 +33,7 @@
         <div class="nav-box">
             <ul class="nav-list list-unstyled">
                 <li class="<% if (ctx.url === '/tender/' + ctx.tender.id + '/measure/stage/' + ctx.stage.order + '/bwtz') { %>active<% } %>">
-                    <a href="/tender/<%- ctx.tender.id %>/measure/stage/<%- ctx.stage.order %>/bwtz"><span class="ml-3">部位台</span></a>
+                    <a href="/tender/<%- ctx.tender.id %>/measure/stage/<%- ctx.stage.order %>/bwtz"><span class="ml-3">部位台</span></a>
                 </li>
             </ul>
         </div>

+ 2 - 2
app/view/stage/stage_sub_mini_menu.ejs

@@ -13,7 +13,7 @@
         <div class="nav-box">
             <ul class="nav-list list-unstyled">
                 <li class="<% if (ctx.url === '/tender/' + ctx.tender.id + '/measure/stage/' + ctx.stage.order) { %>active<% } %>">
-                    <a href="/tender/<%- ctx.tender.id %>/measure/stage/<%- ctx.stage.order %>"><span class="ml-3">计量台</span></a>
+                    <a href="/tender/<%- ctx.tender.id %>/measure/stage/<%- ctx.stage.order %>"><span class="ml-3">计量台</span></a>
                 </li>
             </ul>
         </div>
@@ -35,7 +35,7 @@
         <div class="nav-box">
             <ul class="nav-list list-unstyled">
                 <li class="<% if (ctx.url === '/tender/' + ctx.tender.id + '/measure/stage/' + ctx.stage.order + '/bwtz') { %>active<% } %>">
-                    <a href="/tender/<%- ctx.tender.id %>/measure/stage/<%- ctx.stage.order %>/bwtz"><span class="ml-3">部位台</span></a>
+                    <a href="/tender/<%- ctx.tender.id %>/measure/stage/<%- ctx.stage.order %>/bwtz"><span class="ml-3">部位台</span></a>
                 </li>
             </ul>
         </div>

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

@@ -2,7 +2,7 @@
     <div class="panel-title">
         <div class="title-main d-flex justify-content-between">
             <div>
-                计量台
+                计量台
             </div>
             <div>
                 <a href="#add-qi" data-toggle="modal" data-target="#add-qi" class="btn btn-primary btn-sm pull-right">开始新一期</a>

+ 1 - 1
app/view/tender/detail.ejs

@@ -29,7 +29,7 @@
                             <div class="card text-center">
                                 <div class="card-body">
                                     <h5 class="card-title"><%- ctx.helper.formatMoney(tender.total_price) %></h5>
-                                    <p class="card-text text-muted">0号台</p>
+                                    <p class="card-text text-muted">0号台</p>
                                 </div>
                             </div>
                         </div>

+ 5 - 5
app/view/tender/tender_sub_menu.ejs

@@ -15,15 +15,15 @@
             </ul>
         </div>
         <div class="nav-box">
-            <h3><i class="fa fa-list-alt"></i> 0号台</h3>
+            <h3><i class="fa fa-list-alt"></i> 0号台</h3>
             <ul class="nav-list list-unstyled sub-list">
-                <li <% if (ctx.url === '/tender/' + ctx.tender.id + '/ledger') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/ledger"><span>台分解</span></a></li>
+                <li <% if (ctx.url === '/tender/' + ctx.tender.id + '/ledger') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/ledger"><span>台分解</span></a></li>
                 <% if (ctx.tender.data.ledger_status !== ctx.tender.auditLedgerConst.status.uncheck) { %>
-                <li <% if (ctx.url === '/tender/' + ctx.tender.id + '/ledger/audit') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/ledger/audit"><span>台审批</span></a></li>
+                <li <% if (ctx.url === '/tender/' + ctx.tender.id + '/ledger/audit') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/ledger/audit"><span>台审批</span></a></li>
                 <% } %>
-                <% if (ctx.session.sessionProject.page_show !== null && parseInt(ctx.session.sessionProject.page_show.bwtz) === 1) { %><li <% if (ctx.url === '/tender/' + ctx.tender.id + '/ledger/bwtz') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/ledger/bwtz"><span>部位台</span></a></li><% } %>
+                <% if (ctx.session.sessionProject.page_show !== null && parseInt(ctx.session.sessionProject.page_show.bwtz) === 1) { %><li <% if (ctx.url === '/tender/' + ctx.tender.id + '/ledger/bwtz') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/ledger/bwtz"><span>部位台</span></a></li><% } %>
                 <li <% if (ctx.url === '/tender/' + ctx.tender.id + '/ledger/gather') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/ledger/gather"><span>清单对比</span></a></li>
-                <li <% if (ctx.url.indexOf('/tender/' + ctx.tender.id + '/revise') >= 0) { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/revise"><span>台修订</span></a></li>
+                <li <% if (ctx.url.indexOf('/tender/' + ctx.tender.id + '/revise') >= 0) { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/revise"><span>台修订</span></a></li>
             </ul>
         </div>
         <div class="nav-box">

+ 5 - 5
app/view/tender/tender_sub_mini_menu.ejs

@@ -11,17 +11,17 @@
             </ul>
         </div>
         <div class="nav-box">
-            <h3><i class="fa fa-list-alt"></i> 0号台</h3>
+            <h3><i class="fa fa-list-alt"></i> 0号台</h3>
             <ul class="nav-list list-unstyled sub-list">
-                <li <% if (ctx.url === '/tender/' + ctx.tender.id + '/ledger') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/ledger"><span>台分解</span></a></li>
+                <li <% if (ctx.url === '/tender/' + ctx.tender.id + '/ledger') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/ledger"><span>台分解</span></a></li>
                 <% if (ctx.tender.data.ledger_status !== ctx.tender.auditLedgerConst.status.uncheck) { %>
-                <li <% if (ctx.url === '/tender/' + ctx.tender.id + '/ledger/audit') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/ledger/audit"><span>台审批</span></a></li>
+                <li <% if (ctx.url === '/tender/' + ctx.tender.id + '/ledger/audit') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/ledger/audit"><span>台审批</span></a></li>
                 <% } %>
                 <% if (ctx.session.sessionProject.page_show !== null && parseInt(ctx.session.sessionProject.page_show.bwtz) === 1) { %>
-                <li <% if (ctx.url === '/tender/' + ctx.tender.id + '/ledger/bwtz') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/ledger/bwtz"><span>部位台</span></a></li>
+                <li <% if (ctx.url === '/tender/' + ctx.tender.id + '/ledger/bwtz') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/ledger/bwtz"><span>部位台</span></a></li>
                 <% } %>
                 <li <% if (ctx.url === '/tender/' + ctx.tender.id + '/ledger/gather') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/ledger/gather"><span>清单对比</span></a></li>
-                <li <% if (ctx.url === '/tender/' + ctx.tender.id + '/revise') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/revise"><span>台修订</span></a></li>
+                <li <% if (ctx.url === '/tender/' + ctx.tender.id + '/revise') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/revise"><span>台修订</span></a></li>
             </ul>
         </div>
         <div class="nav-box">

+ 1 - 1
config/config.default.js

@@ -135,7 +135,7 @@ module.exports = appInfo => {
     config.gzip = {
         threshold: 2048,
         // 下载的url要用正则忽略
-        ignore: /(\w*)(\/download\/file)|(\/profile\/qrCode)(\w*)/ig,
+        ignore: /(\w*)(\/download\/file)|(\/profile\/qrCode)|(\/download\/compresse-file)(\w*)/ig,
     };
 
     config.customLogger = {

+ 7 - 7
config/menu.js

@@ -49,27 +49,27 @@ const tenderMenu = {
         ],
     },
     ledger: {
-        name: '0号台',
+        name: '0号台',
         icon: '<i class="fa fa-list-alt"></i> ',
         display: true,
         children: [
             {
-                name: '台分解',
+                name: '台分解',
                 display: true,
                 url: '/ledger/explode',
             }, {
-                name: '台审批',
+                name: '台审批',
                 display: true,
                 url: '/ledger/audit',
             }, {
-                name: '台修订',
+                name: '台修订',
                 display: true,
                 url: '/revise',
             },
         ],
     },
     measure: {
-        name: '计量台',
+        name: '计量台',
         icon: '<i class="fa fa-calendar-check-o"></i> ',
         display: true,
         children: [
@@ -129,11 +129,11 @@ const stageMenu = {
         ],
     },
     ledger: {
-        name: '本期计量台',
+        name: '本期计量台',
         display: false,
         children: [
             {
-                name: '本期计量台',
+                name: '本期计量台',
                 icon: '',
                 display: true,
                 url: '',

+ 7 - 7
config/permission.js

@@ -49,15 +49,15 @@ const permissionList = {
         ],
     },
     ledgerExplode: {
-        name: '台帐分解(台帐管理)',
+        name: '台账分解(台账管理)',
         icon: 'fa-list-alt',
         permission: [
-            { name: '编制台', value: permission.EDIT_LEDGER },
-            { name: '审批台', value: permission.APPROVAL_LEDGER },
+            { name: '编制台', value: permission.EDIT_LEDGER },
+            { name: '审批台', value: permission.APPROVAL_LEDGER },
         ],
     },
     ledgerChange: {
-        name: '台帐变更(台帐管理)',
+        name: '台账变更(台账管理)',
         icon: 'fa-list-alt',
         permission: [
             { name: '编制变更', value: permission.EDIT_APPROVAL },
@@ -65,7 +65,7 @@ const permissionList = {
         ],
     },
     measureLedger: {
-        name: '计量台帐(台帐管理)',
+        name: '计量台账(台账管理)',
         icon: 'fa-list-alt',
         permission: [
             { name: '查看', value: permission.VIEW_LEDGER },
@@ -96,8 +96,8 @@ const permissionString = [];
 permissionString[permission.CREATE_TENDER] = '创建标段';
 permissionString[permission.VIEW_ALL_TENDER] = '查看项目下所有标段';
 permissionString[permission.VIEW_MY_TENDER] = '仅查看我参与的(创建、审批)';
-permissionString[permission.EDIT_LEDGER] = '编制台';
-permissionString[permission.APPROVAL_LEDGER] = '审批台';
+permissionString[permission.EDIT_LEDGER] = '编制台';
+permissionString[permission.APPROVAL_LEDGER] = '审批台';
 permissionString[permission.EDIT_APPROVAL] = '编制变更';
 permissionString[permission.CHANGE_APPROVAL] = '审批变更';
 permissionString[permission.VIEW_LEDGER] = '查看';

+ 94 - 93
package.json

@@ -1,95 +1,96 @@
 {
-  "name": "calculation",
-  "version": "1.0.0",
-  "description": "calculation paying frontend",
-  "private": true,
-  "dependencies": {
-    "@alicloud/pop-core": "^1.7.9",
-    "ali-rds": "^3.3.0",
-    "atob": "^2.1.2",
-    "bignumber.js": "^8.1.1",
-    "decimal.js": "^10.2.0",
-    "egg": "^1.13.0",
-    "egg-etag": "^1.1.0",
-    "egg-js-validator": "^1.0.2",
-    "egg-multipart": "^2.7.1",
-    "egg-mysql": "^3.0.0",
-    "egg-redis": "^1.0.2",
-    "egg-scripts": "^1.0.0",
-    "egg-session-redis": "^1.0.0",
-    "egg-validate": "^1.0.0",
-    "egg-view": "^1.1.2",
-    "egg-view-ejs": "^1.1.0",
-    "egg-wechat-all": "^0.1.4",
-    "gt3-sdk": "^2.0.0",
-    "gulp": "^4.0.0",
-    "js-xlsx": "^0.8.22",
-    "jszip": "^3.1.3",
-    "koa-is-json": "^1.0.0",
-    "lodash": "^4.17.11",
-    "lz-string": "^1.4.4",
-    "mathjs": "^5.9.0",
-    "moment": "^2.20.1",
-    "node-schedule": "^1.3.2",
-    "node-uuid": "^1.4.8",
-    "node-xlsx": "^0.12.0",
-    "number-precision": "^1.3.1",
-    "qr-image": "^3.2.0",
-    "stream-to-array": "^2.3.0",
-    "stream-wormhole": "^1.1.0",
-    "ua-parser-js": "^0.7.21",
-    "ueditor": "^1.2.3",
-    "uglify-es": "^3.3.9",
-    "uglify-js": "^3.3.27",
-    "xmlreader": "^0.2.3",
-    "zlib": "^1.0.5"
-  },
-  "devDependencies": {
-    "autod": "^2.9.0",
-    "autod-egg": "^1.1.0",
-    "egg-bin": "^4.10.0",
-    "egg-ci": "^1.8.0",
-    "egg-mock": "^3.14.0",
-    "eslint": "^4.17.0",
-    "eslint-config-egg": "^5.0.0",
-    "pdfkit": "^0.8.2",
-    "webstorm-disable-index": "^1.2.0"
-  },
-  "engines": {
-    "node": ">=6.0.0"
-  },
-  "scripts": {
-    "start": "egg-scripts start --daemon --port 7002",
-    "stop": "egg-scripts stop",
-    "start-qa": "set EGG_SERVER_ENV=qa&&egg-scripts start --daemon --port 7002",
-    "dev": "egg-bin dev --port 7002",
-    "dev-local": "set EGG_SERVER_ENV=local&&egg-bin dev --port 7002",
-    "dev-remoteqa": "set EGG_SERVER_ENV=remoteqa&&egg-bin dev --port 7002",
-    "dev-remoteuat": "set EGG_SERVER_ENV=remoteuat&&egg-bin dev --port 7002",
-    "dev-localpro": "set EGG_SERVER_ENV=localpro&&egg-bin dev --port 7002",
-    "dev-temp": "set EGG_SERVER_ENV=temp&&egg-bin dev --port 7002",
-    "dev-qa": "set EGG_SERVER_ENV=qa&&egg-bin dev --port 7002",
-    "dev-test": "set EGG_SERVER_ENV=test&&egg-bin dev --port 7002",
-    "test": "npm run lint -- --fix&&npm run test-local",
-    "test-sim": "egg-bin test",
-    "test-local": "set EGG_SERVER_ENV=local&& egg-bin test",
-    "test-qa": "set EGG_SERVER_ENV=qa&&egg-bin test",
-    "test-auto": "set EGG_SERVER_ENV=autotest&&egg-bin test",
-    "dev-docker": "egg-scripts start --port 7005",
-    "cov": "egg-bin cov",
-    "lint": "eslint .",
-    "ci": "npm run lint && npm run cov",
-    "autod": "autod",
-    "qa": "set EGG_SERVER_ENV=local&&egg-scripts start --deamon --port 7002",
-    "local": "set EGG_SERVER_ENV=local&npm run dev"
-  },
-  "ci": {
-    "version": "6, 8"
-  },
-  "repository": {
-    "type": "git",
-    "url": ""
-  },
-  "author": "olym",
-  "license": "MIT"
+    "name": "calculation",
+    "version": "1.0.0",
+    "description": "calculation paying frontend",
+    "private": true,
+    "dependencies": {
+        "@alicloud/pop-core": "^1.7.9",
+        "ali-rds": "^3.3.0",
+        "archiver": "^5.0.2",
+        "atob": "^2.1.2",
+        "bignumber.js": "^8.1.1",
+        "decimal.js": "^10.2.0",
+        "egg": "^1.13.0",
+        "egg-etag": "^1.1.0",
+        "egg-js-validator": "^1.0.2",
+        "egg-multipart": "^2.7.1",
+        "egg-mysql": "^3.0.0",
+        "egg-redis": "^1.0.2",
+        "egg-scripts": "^1.0.0",
+        "egg-session-redis": "^1.0.0",
+        "egg-validate": "^1.0.0",
+        "egg-view": "^1.1.2",
+        "egg-view-ejs": "^1.1.0",
+        "egg-wechat-all": "^0.1.4",
+        "gt3-sdk": "^2.0.0",
+        "gulp": "^4.0.0",
+        "js-xlsx": "^0.8.22",
+        "jszip": "^3.1.3",
+        "koa-is-json": "^1.0.0",
+        "lodash": "^4.17.11",
+        "lz-string": "^1.4.4",
+        "mathjs": "^5.9.0",
+        "moment": "^2.20.1",
+        "node-schedule": "^1.3.2",
+        "node-uuid": "^1.4.8",
+        "node-xlsx": "^0.12.0",
+        "number-precision": "^1.3.1",
+        "qr-image": "^3.2.0",
+        "stream-to-array": "^2.3.0",
+        "stream-wormhole": "^1.1.0",
+        "ua-parser-js": "^0.7.21",
+        "ueditor": "^1.2.3",
+        "uglify-es": "^3.3.9",
+        "uglify-js": "^3.3.27",
+        "xmlreader": "^0.2.3",
+        "zlib": "^1.0.5"
+    },
+    "devDependencies": {
+        "autod": "^2.9.0",
+        "autod-egg": "^1.1.0",
+        "egg-bin": "^4.10.0",
+        "egg-ci": "^1.8.0",
+        "egg-mock": "^3.14.0",
+        "eslint": "^4.17.0",
+        "eslint-config-egg": "^5.0.0",
+        "pdfkit": "^0.8.2",
+        "webstorm-disable-index": "^1.2.0"
+    },
+    "engines": {
+        "node": ">=6.0.0"
+    },
+    "scripts": {
+        "start": "egg-scripts start --daemon --port 7002",
+        "stop": "egg-scripts stop",
+        "start-qa": "set EGG_SERVER_ENV=qa&&egg-scripts start --daemon --port 7002",
+        "dev": "egg-bin dev --port 7002",
+        "dev-local": "set EGG_SERVER_ENV=local&&egg-bin dev --port 7002",
+        "dev-remoteqa": "set EGG_SERVER_ENV=remoteqa&&egg-bin dev --port 7002",
+        "dev-remoteuat": "set EGG_SERVER_ENV=remoteuat&&egg-bin dev --port 7002",
+        "dev-localpro": "set EGG_SERVER_ENV=localpro&&egg-bin dev --port 7002",
+        "dev-temp": "set EGG_SERVER_ENV=temp&&egg-bin dev --port 7002",
+        "dev-qa": "set EGG_SERVER_ENV=qa&&egg-bin dev --port 7002",
+        "dev-test": "set EGG_SERVER_ENV=test&&egg-bin dev --port 7002",
+        "test": "npm run lint -- --fix&&npm run test-local",
+        "test-sim": "egg-bin test",
+        "test-local": "set EGG_SERVER_ENV=local&& egg-bin test",
+        "test-qa": "set EGG_SERVER_ENV=qa&&egg-bin test",
+        "test-auto": "set EGG_SERVER_ENV=autotest&&egg-bin test",
+        "dev-docker": "egg-scripts start --port 7005",
+        "cov": "egg-bin cov",
+        "lint": "eslint .",
+        "ci": "npm run lint && npm run cov",
+        "autod": "autod",
+        "qa": "set EGG_SERVER_ENV=local&&egg-scripts start --deamon --port 7002",
+        "local": "set EGG_SERVER_ENV=local&npm run dev"
+    },
+    "ci": {
+        "version": "6, 8"
+    },
+    "repository": {
+        "type": "git",
+        "url": ""
+    },
+    "author": "olym",
+    "license": "MIT"
 }