浏览代码

Merge branch 'master' of http://192.168.1.41:3000/maixinrong/Calculation

Conflicts:
	app/lib/rpt_data_analysis.js
TonyKang 4 年之前
父节点
当前提交
559f451a8f

+ 4 - 2
.travis.yml

@@ -1,10 +1,12 @@
-sudo: false
+
 language: node_js
 node_js:
   - '6'
   - '8'
+before_install:
+  - npm i npminstall -g
 install:
-  - npm i npminstall && npminstall
+  - npminstall
 script:
   - npm run ci
 after_script:

+ 1 - 1
app/const/report.js

@@ -13,10 +13,10 @@ const rptCustomType = {};
 rptCustomType[JV.NODE_CUS_AUDIT_SELECT] = 1;
 rptCustomType[JV.NODE_CUS_GATHER_SELECT] = 2;
 rptCustomType[JV.NODE_CUS_COMPARE_SELECT] = 3;
+rptCustomType[JV.NODE_CUS_STAGE_SELECT] = 4;
 
 const rptDataType = {};
 rptDataType[JV.NODE_CUS_MATERIAL_SELECT] = 1;
-rptDataType[JV.NODE_CUS_STAGE_SELECT] = 2;
 
 module.exports = {
     rptCustomType,

+ 11 - 12
app/controller/material_controller.js

@@ -320,13 +320,15 @@ module.exports = app => {
             try {
                 await this._getMaterialAuditViewData(ctx);
                 const renderData = await this._getDefaultRenderData(ctx);
+                const whiteList = this.ctx.app.config.multipart.whitelist;
                 // 获取当前标段所有附件
                 // const searchsql = { tid: ctx.tender.id };
-                renderData.fileList = await ctx.service.materialFile.getAllMaterialFiles(ctx.tender.id, ctx.material.id);
+                renderData.fileList = await ctx.service.materialFile.getAllMaterialFiles(ctx.tender.id);
                 renderData.auditors = ctx.material.auditors.map(audit => audit.aid);
                 // renderData.auditors = ctx.material.auditors2.map(audit => audit.aid);
                 renderData.report_id = ctx.material.user_id;
                 renderData.auditConst = auditConst;
+                renderData.whiteList = whiteList;
                 renderData.jsFiles = this.app.jsFiles.common.concat(this.app.jsFiles.material.file);
                 await this.layout('material/file.ejs', renderData, 'material/file_modal.ejs');
             } catch (err) {
@@ -622,17 +624,19 @@ module.exports = app => {
                     autoFields: true,
                 });
                 const files = [];
-                const create_time = Date.parse(new Date()) / 1000;
+                let idx = 0;
                 while ((stream = await parts()) != null) {
                     if (!stream.filename) {
                         // 如果没有传入直接返回
                         return;
                     }
+                    const create_time = Date.parse(new Date()) / 1000;
                     const fileInfo = path.parse(stream.filename);
                     // const filepath = path.join('public/upload', this.ctx.tender.id.toString(), 'tc', 'fujian_' + create_time + fileInfo.ext);
-                    const filepath = `public/upload/${this.ctx.tender.id.toString()}/tc/fujian_${create_time + fileInfo.ext}`;
+                    const filepath = `public/upload/${this.ctx.tender.id.toString()}/tc/fujian_${create_time + idx + fileInfo.ext}`;
                     await ctx.helper.saveStreamFile(stream, path.join(this.app.baseDir, 'app', filepath));
                     files.push({ filepath, name: stream.filename });
+                    idx++;
                 }
                 const upload_time = this.ctx.helper.dateTran(new Date());
                 const payload = files.map(file => {
@@ -657,7 +661,7 @@ module.exports = app => {
                 // 执行文件信息写入数据库
                 await ctx.service.materialFile.saveFileMsgToDb(payload);
                 // 将最新的当前标段的所有文件信息返回
-                const data = await ctx.service.materialFile.getAllMaterialFiles(ctx.tender.id, ctx.material.id);
+                const data = await ctx.service.materialFile.getAllMaterialFiles(ctx.tender.id);
                 ctx.body = { err: 0, msg: '', data };
             } catch (err) {
                 stream && (await sendToWormhole(stream));
@@ -671,13 +675,8 @@ module.exports = app => {
          */
         async getCurMatericalFiles(ctx) {
             try {
-                const { isCheck } = JSON.parse(ctx.request.body.data);
-                let data;
-                if (isCheck) {
-                    data = await ctx.service.materialFile.getAllMaterialFiles(ctx.tender.id);
-                } else {
-                    data = await ctx.service.materialFile.getAllMaterialFiles(ctx.tender.id, ctx.material.id);
-                }
+                // const { isCheck } = JSON.parse(ctx.request.body.data);
+                const data = await ctx.service.materialFile.getAllMaterialFiles(ctx.tender.id);
                 ctx.body = { err: 0, msg: '', data };
             } catch (err) {
                 this.log(err);
@@ -696,7 +695,7 @@ module.exports = app => {
                 const fileInfo = await ctx.service.materialFile.getMaterialFileById(id);
                 if (fileInfo) {
                     // 先删除文件
-                    await fs.unlinkSync(path.join(this.app.baseDir, './app', fileInfo.filepath));
+                    await fs.unlinkSync(path.resolve(this.app.baseDir, './app', fileInfo.filepath));
                     // 再删除数据库
                     await ctx.service.materialFile.delete(id);
                 } else {

+ 1 - 5
app/controller/report_controller.js

@@ -19,6 +19,7 @@ const RPT_DEF_PROPERTIES = require('../const/report_defined_properties');
 const reportConst = require('../const/report');
 // const stringUtil = require('../public/js/string_util_light');
 const scheduleJob = require('node-schedule');
+const needCustomTables = ['mem_gather_stage_bills', 'mem_gather_deal_bills', 'mem_gather_stage_pay', 'mem_gather_tender_info', 'mem_stage_sum_bills', 'mem_stage_sum_pay'];
 
 module.exports = app => {
     class ReportController extends app.BaseController {
@@ -633,7 +634,6 @@ async function getAllPagesCommon(ctx, rptTpl, params, option, outputType, baseDi
     // console.log(filter.tables);
     const rawDataObj = await ctx.service.report.getReportData(params, filter.tables, filter.memFieldKeys,
         rptTpl[JV.NODE_CUSTOM_DEFINE], customSelect);
-    //await ctx.helper.saveBufferFile(JSON.stringify(rawDataObj, '', '\t'), ctx.app.baseDir + '/mem.json');
     // console.log(rawDataObj);
     try {
         const printCom = JpcEx.createNew();
@@ -679,8 +679,6 @@ async function getAllPagesCommon(ctx, rptTpl, params, option, outputType, baseDi
 }
 
 async function getMultiRptsCommon(ctx, params, outputType, baseDir) {
-    const needCustomTables = ['mem_gather_stage_bills', 'mem_gather_deal_bills', 'mem_gather_stage_pay', 'mem_gather_tender_info'];
-
     for (let idx = 0; idx < params.rpt_ids.length; idx++) {
         params.rpt_ids[idx] = parseInt(params.rpt_ids[idx]); // 转换一下,以防万一
     }
@@ -767,10 +765,8 @@ async function getMultiRptsCommon(ctx, params, outputType, baseDir) {
                         }
                     }
                 }
-                console.log(customSelect);
                 const customRawDataObj = await ctx.service.report.getReportData(params, cfTables, cmFieldKeys,
                     rptTpl[JV.NODE_CUSTOM_DEFINE], customSelect);
-                console.log(customRawDataObj);
                 for (const prop in customRawDataObj) {
                     curRawDataObj[prop] = customRawDataObj[prop];
                 }

+ 9 - 2
app/controller/stage_controller.js

@@ -990,7 +990,8 @@ 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);
+                console.log('stage-auditor:', auditor);
                 ctx.body = { err: 0, msg: '', data: [] };
             } catch (err) {
                 this.log(err);
@@ -1027,7 +1028,13 @@ 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);
+                console.log('stage-auditor:', auditor, 'status:', stage.status);
                 ctx.body = { err: 0, msg: '', data: [] };
                 // ctx.redirect(ctx.request.header.referer);
             } catch (err) {

+ 2 - 0
app/controller/wechat_controller.js

@@ -64,6 +64,8 @@ module.exports = app => {
             try {
                 const user = await app.wechat.oauth.getUser(ctx.session.wechatToken.openid);
                 const errorMessage = ctx.session.loginError;
+                // 显示完删除
+                ctx.session.loginError = null;
                 // 获取系统维护信息
                 const maintainData = await ctx.service.maintain.getDataById(1);
                 const renderData = {

+ 1 - 1
app/middleware/stage_check.js

@@ -55,7 +55,7 @@ module.exports = options => {
             });
             const materials = yield this.service.material.getAllDataByCondition({ columns: ['stage_id', 's_order'], where: { tid: this.tender.id } });
             stage.hadMaterial = materials.find(function(item) {
-                return item.s_order.indexOf(stage.highOrder.toString()) !== -1;
+                return item.s_order.split(',').indexOf(stage.highOrder.toString()) !== -1;
             });
             // 权限相关
             // todo 校验权限 (标段参与人、分享)

二进制
app/public/images/example/jiliangmoshi.png


+ 92 - 36
app/public/js/change_set.js

@@ -81,45 +81,14 @@ $(document).ready(() => {
                 '<td>' + unit + '</td>' +
                 '<td>' + roundnum(unit_price, unitPriceUnit) + '</td>' +
                 '<td>' + quantity + '</td>' +
-                // '<td>' + roundnum(parseFloat(gcl.unit_price).mul(parseFloat(gcl.quantity)), totalPriceUnit) + '</td>' +
                 '</tr>';
             list_index++;
         }
-        // // 再加载签约清单
-        // for (const db of dealBillList) {
-        //     const unit = db.unit !== undefined && db.unit !== null ? db.unit : '';
-        //     const quantity = db.quantity !== null && db.quantity !== undefined ? (unit !== '' ? roundnum(db.quantity, findDecimal(db.unit)) : db.quantity) : 0;
-        //     const unit_price = db.unit_price !== null && db.unit_price !== undefined ? db.unit_price : 0;
-        //     listHtml += '<tr data-lid="' + db.id + '" data-index="' + list_index + '" data-bwmx="">' +
-        //         '<td>' + list_index + '</td>' +
-        //         '<td>' + db.code + '</td>' +
-        //         '<td>' + db.name + '</td>' +
-        //         '<td>' + unit + '</td>' +
-        //         '<td>' + roundnum(unit_price, unitPriceUnit) + '</td>' +
-        //         '<td>' + quantity + '</td>' +
-        //         // '<td>' + roundnum(parseFloat(db.unit_price).mul(parseFloat(db.quantity)), totalPriceUnit) + '</td>' +
-        //         '</tr>';
-        //     list_index++;
-        // }
         $('#table-list-select').html(listHtml);
         tableDataRemake(changeListData);
         maketablelist();
     });
 
-    // 上报时按钮点击
-    $('a[data-target="#sub-ap"]').on('click', function () {
-        let category = $(this).attr('data-category');
-        if (category === 'save_change') {
-            // 保存修改modal
-            $('.up-change').hide();
-            $('.save-change').show();
-        } else {
-            // 上报审批modal
-            $('.up-change').show();
-            $('.save-change').hide();
-        }
-    });
-
     // 多层modal关闭后的滚动bug修复
     $('#sub-sp2').on('hidden.bs.modal', function (e) {
         $(document.body).addClass('modal-open');
@@ -386,13 +355,13 @@ $(document).ready(() => {
             for (const leaf of gcl.leafXmjs) {
                 const quantity = leaf.quantity !== undefined && leaf.quantity !== null ? leaf.quantity : 0;
                 const bwmx = leaf.bwmx !== undefined ? leaf.bwmx : '';
-                const isChecked = data_bwmx.indexOf(leaf.code + '_' + (bwmx !== '' ? bwmx : leaf.jldy !== '' ? leaf.jldy : '') + ';' + quantity) !== -1 && isCheck ? 'checked' : '';
+                const isChecked = data_bwmx.indexOf(leaf.code + '_' + (bwmx !== '' ? bwmx : leaf.jldy ? leaf.jldy : '') + ';' + quantity) !== -1 && isCheck ? 'checked' : '';
                 codeHtml += '<tr quantity="' + quantity + '"><td>' + leaf.code + '</td>' +
-                    '<td>' + leaf.jldy + '</td>' +
+                    '<td>' + (leaf.jldy ? leaf.jldy: '') + '</td>' +
                     '<td>' + bwmx + '</td>' +
-                    '<td>' + leaf.dwgc + '</td>' +
-                    '<td>' + leaf.fbgc + '</td>' +
-                    '<td>' + leaf.fxgc + '</td>' +
+                    '<td>' + (leaf.dwgc ? leaf.dwgc : '') + '</td>' +
+                    '<td>' + (leaf.fbgc ? leaf.fbgc : '') + '</td>' +
+                    '<td>' + (leaf.fxgc ? leaf.fxgc : '') + '</td>' +
                     '<td>' + roundnum(quantity, findDecimal(gcl.unit)) + '</td>' +
                     '<td><input type="checkbox"' + isChecked +
                     '></td></tr>';
@@ -401,6 +370,8 @@ $(document).ready(() => {
             codeHtml = '<tr quantity="'+ $(this).children('td').eq(5).text() +'"><td colspan="7" class="colspan_1">&nbsp;</td><td class="colspan_2"><input type="checkbox" checked></td></tr>';
         }
         $('#code-list').attr('data-index', $(this).children('td').eq(0).text());
+        $('#code-input').val('');
+        $('#code-input').siblings('a').hide();
         $('#code-list').html(codeHtml);
     });
 
@@ -605,6 +576,46 @@ $(document).ready(() => {
         judgeChange();
     });
 
+    $('#list-input').on('valuechange', function (e, previous) {
+        const value = $(this).val();
+        let showListData = changeListData;
+        if (value !== '') {
+            $(this).siblings('a').show();
+            showListData = _.filter(changeListData, function (c) {
+                return (c.code && c.code.indexOf(value) !== -1) || (c.name && c.name.indexOf(value) !== -1);
+            });
+        } else {
+            $(this).siblings('a').hide();
+        }
+        makeListTable(changeListData, showListData);
+        $('#table-list-select tr').removeClass('table-warning');
+        $('#code-input').val('');
+        $('#code-input').siblings('a').hide();
+        $('#code-list').html('');
+    });
+
+    $('#code-input').on('valuechange', function (e, previous) {
+        const value = $(this).val();
+        if (value !== '') {
+            $(this).siblings('a').show();
+        } else {
+            $(this).siblings('a').hide();
+        }
+        makeCodeTable($(this).val());
+    });
+
+    $('.remove-btn').on('click', function () {
+        $(this).hide();
+        $(this).siblings('input').val('');
+        if ($(this).data('btn') === 'list') {
+            makeListTable(changeListData);
+            $('#table-list-select tr').removeClass('table-warning');
+            $('#code-list').html('');
+        } else {
+            makeCodeTable();
+        }
+    })
+
 });
 
 function tableDataRemake(changeListData) {
@@ -737,6 +748,51 @@ function getAuditList() {
         $('#changeaudit').val(auditInfoArray.join(','));
     }
 }
+// 清单搜索隐藏清单table部分值
+function makeListTable(changeListData, showListData = changeListData) {
+    // 先加载台账数据
+    let listHtml = '';
+    let list_index = 1;
+    let gcl_index = 0;
+    for (const [index,gcl] of changeListData.entries()) {
+        const isShow = _.find(showListData, gcl);
+        $('#table-list-select tr').eq(index).css('display', (isShow ? 'table-row' : 'none'));
+    }
+}
+// 项目节搜索隐藏code-table部分值
+function makeCodeTable(search = '') {
+    if (search === '') {
+        $('#code-list tr').css('display', 'table-row');
+        return;
+    }
+    for(let i = 0; i < $('#code-list tr').length; i++) {
+        const length = $('#code-list tr').eq(i).children('td').length;
+        if (length === 8) {
+            const code = $('#code-list tr').eq(i).children('td').eq(0).text();
+            const name = $('#code-list tr').eq(i).children('td').eq(1).text();
+            const jldy = $('#code-list tr').eq(i).children('td').eq(2).text();
+            console.log(code, name, jldy, search, code.indexOf(search) !== -1 || name.indexOf(search) !== -1 || jldy.indexOf(search) !== -1);
+            const isShow = code.indexOf(search) !== -1 || name.indexOf(search) !== -1 || jldy.indexOf(search) !== -1;
+            $('#code-list tr').eq(i).css('display', (isShow ? 'table-row' : 'none'));
+        } else {
+            return;
+        }
+    }
+}
+
+// 上报时按钮点击
+$('a[data-target="#sub-ap"]').on('click', function () {
+    let category = $(this).attr('data-category');
+    if (category === 'save_change') {
+        // 保存修改modal
+        $('.up-change').hide();
+        $('.save-change').show();
+    } else {
+        // 上报审批modal
+        $('.up-change').show();
+        $('.save-change').hide();
+    }
+});
 
 // 重新生成清单
 function maketablelist(status){

+ 106 - 87
app/public/js/material_file.js

@@ -6,8 +6,11 @@
  * @date 2020/06/30
  * @version
  */
-
 $(document).ready(function () {
+    // 全局fileData初始化
+    let fileData = fileList || []
+    handleFileList(fileData)
+    getAllList()
     $('#upload-file-ok').click(function () {
         const files = Array.from($('#upload-fujian-file')[0].files)
         const valiData = files.map(v => {
@@ -26,101 +29,114 @@ $(document).ready(function () {
                     formData.append('size', file.size)
                 })
                 postDataWithFile(window.location.pathname + '/upload', formData, function (result) {
-                    const files = result.map(file => {
-                        let showDel = false
-                        // 只判断当前期,因为以往期都是只读的
-                        if (file.mid === parseInt(mid) && file.tid === parseInt(tid) && file.user_id === parseInt(cur_uid)) {
-                            if (!curAuditor) {
-                                material.status === auditConst.status.uncheck && parseInt(cur_uid) === material.user_id && (showDel = true)
-                                material.status === auditConst.status.checkNo && parseInt(cur_uid) === material.user_id && (showDel = true)
-                            } else {
-                                curAuditor.aid === parseInt(cur_uid) && (showDel = true)
-                            }
-                        }
-                        return showDel ? {...file, canDel: true} : file
-                    })
+                    handleFileList(result)
                     $('#addfujian').modal('hide');
-                    let html = '';
-                    files.forEach((fileInfo, idx) => {
-                        html += `<tr>
-                        <td>${idx + 1}</td>
-                        <td><a href="/${fileInfo.filepath}" target="_blank">${fileInfo.file_name}</a></td>
-                        <td>${fileInfo.file_size}</td>
-                        <td>第${fileInfo.s_order}期</td>
-                        <td>${fileInfo.upload_time}</td>`
-                        if (fileInfo.canDel ) {
-                            html += `<td>
-                            <a 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>`
-                        }
-                    })
-                    $('#file-list').empty();
-                    $('#file-list').append(html);
+                    if (!$('#file-list tr').length) {
+                        getAllList();
+                    } else {
+                        getAllList(parseInt($('#currentPage').text()));
+                    }
                 });
             }
         }
     })
+    // 选择/未选所有期列表
     $('#file-checkbox').click(function() {
-        let isCheck = false
-        if($(this).is(':checked')) {
-            isCheck = true
-        }
-        postData(window.location.pathname + '/find', {isCheck}, function(result) {
-            const files = result.map(file => {
-                let showDel = false
-                // 只判断当前期,因为以往期都是只读的
-                if (file.mid === parseInt(mid) && file.tid === parseInt(tid) && file.user_id === parseInt(cur_uid)) {
-                    if (!curAuditor) {
-                        material.status === auditConst.status.uncheck && parseInt(cur_uid) === material.user_id && (showDel = true)
-                        material.status === auditConst.status.checkNo && parseInt(cur_uid) === material.user_id && (showDel = true)
-                    } else {
-                        curAuditor.aid === parseInt(cur_uid) && (showDel = true)
-                    }
-                }
-                return showDel ? {...file, canDel: true} : file
-            })
-            let html = '';
-            files.forEach((fileInfo, idx) => {
-                html += `<tr>
-                <td>${idx + 1 }</td>
-                <td><a href="/${fileInfo.filepath}" target="_blank">${fileInfo.file_name}</a></td>
-                <td>${fileInfo.file_size}</td>
-                <td>第${fileInfo.s_order}期</td>
-                <td>${fileInfo.upload_time}</td>`
-                if (fileInfo.canDel ) {
-                    html += `<td>
-                    <a 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>`
-                }
-
-            })
-            $('#file-list').empty();
-            $('#file-list').append(html);
-        })
+        getAllList()
     })
+
     // 删除附件
     $('body').on('click', '.delete-file', function () {
         let attid = $(this).data('attid');
-        let self = $(this);
         const data = {id: attid};
-        postData('/tender/measure/material/file/delete', data, function (result) {
-            self.parents('tr').remove();
-            // 重新排序
-            let newsort = 1;
-            $('#file-list tr').each(function(){
-                $(this).children('td').eq(0).text(newsort);
-                newsort++;
-            });
+        postData('/tender/measure/material/file/delete', data, function () {
+            const idx = fileData.findIndex(file => file.id === parseInt(attid))
+            idx !== -1 && fileData.splice(idx, 1)
+            if ($('#file-list tr').length === 1) {
+                getAllList(parseInt($('#currentPage').text()) - 1);
+            } else {
+                getAllList(parseInt($('#currentPage').text()));
+            }
+            // self.parents('tr').remove();
+            // // 重新排序
+            // let newsort = 1;
+            // $('#file-list tr').each(function(){
+            //     $(this).children('td').eq(0).text(newsort);
+            //     newsort++;
+            // });
         });
     });
+    // 切换页数
+    $('.page-select').on('click', function () {
+        const totalPageNum = parseInt($('#totalPage').text());
+        const lastPageNum = parseInt($('#currentPage').text());
+        const status = $(this).attr('content');
+        if (status === 'pre' && lastPageNum > 1) {
+            getAllList(lastPageNum-1);
+        } else if (status === 'next' && lastPageNum < totalPageNum) {
+            getAllList(lastPageNum+1);
+        }
+    });
+    // 生成所有附件列表
+    function getAllList(currPageNum = 1) {
+        // 每页最多几个附件
+        const pageCount = 15;
+        // 附件总数
+        let total = fileData && fileData.length;
+        // 未选中checkbox,需要过滤出来当前期的数据
+        const filterFileData = fileData && fileData.filter(file => file.mid === parseInt(mid) && file.tid === parseInt(tid))
+        if(!$('#file-checkbox').is(':checked')) {
+            total = filterFileData.length
+        }
+        // 总页数
+        const pageNum = Math.ceil(total/pageCount);
+        $('#totalPage').text(pageNum);
+        // total为0,当前还没上传过附件
+        $('#currentPage').text(total ? currPageNum : 0);
+        // 当前页附件内容
+        const currPageAttData = fileData && $('#file-checkbox').is(':checked') ? fileData.slice((currPageNum-1)*pageCount, currPageNum*pageCount) : filterFileData.slice((currPageNum-1)*pageCount, currPageNum*pageCount);
+        renderHtml(currPageAttData)
+    }
+
+
+    function renderHtml(list) {
+        let html = '';
+        list.forEach((fileInfo, idx) => {
+            html += `<tr style="height: 31px;">
+            <td>${idx + 1}</td>
+            <td><a href="/${fileInfo.filepath}" target="_blank">${fileInfo.file_name}</a></td>
+            <td>${fileInfo.file_size}</td>
+            <td>第${fileInfo.s_order}期</td>
+            <td>${fileInfo.upload_time}</td>`
+            if (fileInfo.canDel ) {
+                html += `<td>
+                <a 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>`
+            }
+        })
+        $('#file-list').empty();
+        $('#file-list').append(html);
+    }
+
+    function handleFileList(fileList) {
+        fileData = fileList.map(file => {
+            let showDel = false
+            // 只判断当前期,因为以往期都是只读的
+            if (file.mid === parseInt(mid) && file.tid === parseInt(tid) && file.user_id === parseInt(cur_uid)) {
+                if (!curAuditor) {
+                    material.status === auditConst.status.uncheck && parseInt(cur_uid) === material.user_id && (showDel = true)
+                    material.status === auditConst.status.checkNo && parseInt(cur_uid) === material.user_id && (showDel = true)
+                } else {
+                    curAuditor.aid === parseInt(cur_uid) && (showDel = true)
+                }
+            }
+            return showDel ? {...file, canDel: true} : file
+        })
+    }
 });
 
 /**
@@ -128,13 +144,16 @@ $(document).ready(function () {
  * @param {Array} files 文件数组
  */
 function validateFiles(files) {
-    const reg = /(doc|docx|excel|pdf|xlsx|xls|txt|zip|jpg|jpeg|png|bmp|BMP|JPG|PNG|JPEG|gif)$/;
+    if (files.length > 10) {
+        toastr.error('至多同时上传10个文件');
+        return false
+    }
     return files.every(file => {
-        if (file.size > 1024 * 1024 * 10) {
-            toastr.error('文件大小限制为10MB');
+        if (file.size > 1024 * 1024 * 30) {
+            toastr.error('文件大小限制为30MB');
             return false
         }
-        if (!reg.test(file.ext)) {
+        if (whiteList.indexOf('.' + file.ext) === -1) {
             toastr.error('请上传正确的格式文件');
             return false
         }

+ 46 - 9
app/public/js/material_list.js

@@ -42,10 +42,10 @@ function calcOneBQJC(xmj) {
     if (notx === undefined) {
         const list = xmj.mx_id !== undefined ? getMaterialListByLeafXmj(xmj.gcl_id, xmj.id, xmj.mx_id) : getMaterialListByLeafXmj(xmj.gcl_id, xmj.id);
         for (const l of list) {
-            jiacha = ZhCalc.round(ZhCalc.add(jiacha, ZhCalc.mul(ZhCalc.mul(xmj.gather_qty, l.quantity), getMpSpreadByMBData(l.mb_id))), 2);
+            jiacha = ZhCalc.add(jiacha, ZhCalc.mul(ZhCalc.mul(xmj.gather_qty, l.quantity), getMpSpreadByMBData(l.mb_id)));
         }
     }
-    return jiacha;
+    return ZhCalc.round(jiacha, 2);
 }
 
 function getPasteHint (str, row = '') {
@@ -56,6 +56,31 @@ function getPasteHint (str, row = '') {
     return returnObj;
 }
 
+// 重新计算列表的价差
+function calculateJiaCha(data, index) {
+    // 计算单条的
+    if (index) {
+        const gcld = data[index]
+        let total_jiacha = 0;
+        for (const [index, xmj] of gcld.leafXmjs.entries()) {
+            const jiacha = calcOneBQJC(xmj);
+            gcld.leafXmjs[index].jiacha = jiacha !== 0 ? jiacha : null;
+            total_jiacha += jiacha;
+        }
+        gcld.total_jiacha = ZhCalc.round(total_jiacha, 2)
+    } else {
+        for(const gcld of data) {
+            let total_jiacha = 0;
+            for (const [index, xmj] of gcld.leafXmjs.entries()) {
+                const jiacha = calcOneBQJC(xmj);
+                gcld.leafXmjs[index].jiacha = jiacha !== 0 ? jiacha : null;
+                total_jiacha += jiacha;
+            }
+            gcld.total_jiacha = ZhCalc.round(total_jiacha, 2)
+        }
+    }
+}
+
 const is_numeric = (value) => {
     if (typeof(value) === 'object') {
         return false;
@@ -113,6 +138,7 @@ $(document).ready(() => {
             {title: '本期计量数量|合同', colSpan: '3|1', rowSpan: '1|1', field: 'contract_qty', hAlign: 2, width: 120, type: 'Number'},
             {title: '|数量变更', colSpan: '|1', rowSpan: '|1', field: 'qc_qty', hAlign: 2, width: 120, type: 'Number'},
             {title: '|小计', colSpan: '|1', rowSpan: '|1', field: 'gather_qty', hAlign: 2, width: 120, type: 'Number'},
+            {title: '本期价差', colSpan: '1', rowSpan: '2', field: 'total_jiacha', hAlign:3, width: 150, type: 'Number'}
         ],
         emptyRows: 0,
         headRows: 2,
@@ -127,9 +153,11 @@ $(document).ready(() => {
     gclGatherModel.loadPosData(pos, curPosData);
     let gclGatherData = gclGatherModel.gatherGclData().filter(item => {
         return item.qc_qty || item.contract_qty
-    });
+    })
+
+
+    calculateJiaCha(gclGatherData)
     // let gclGatherData = gclGatherModel.gatherGclData()
-    // console.log(gclGatherData);
     // 获取项目节数据
     function loadLeafXmjData(iGclRow) {
         const gcl = gclGatherData[iGclRow];
@@ -138,7 +166,6 @@ $(document).ready(() => {
                 const jiacha = calcOneBQJC(xmj);
                 gcl.leafXmjs[index].jiacha = jiacha !== 0 ? ZhCalc.round(jiacha, 2) : null;
             }
-            // console.log(gcl.leafXmjs);
             SpreadJsObj.loadSheetData(leafXmjSpread.getActiveSheet(), SpreadJsObj.DataType.Data, gcl.leafXmjs);
             // 对清单调差工料table的单位数量进行改变
             materialSpreadSetting.cols[materialSpreadSetting.cols.length - 1].title = '|' + gcl.unit + '数量 �';
@@ -214,7 +241,6 @@ $(document).ready(() => {
     const materialBase = {
         isEdit: function (data) {
             // 是否本期添加的工料
-            console.log(data);
             return data.order === stage_order;
         }
     };
@@ -230,7 +256,6 @@ $(document).ready(() => {
         },
     };
     SpreadJsObj.initSpreadSettingEvents(materialSpreadSetting, materialCol);
-
     // 获取项目节数据
     let materialList = [];
     function loadMaterialData(iGclRow, iLXmjRow) {
@@ -355,9 +380,11 @@ $(document).ready(() => {
                         notJoinList.push(result);
                     }
                     gclGatherData[iGclRow].leafXmjs[iRow].jiacha = calcOneBQJC(select);
+                    calculateJiaCha(gclGatherData, iGclRow)
                     SpreadJsObj.reLoadRowData(sheet, iRow);
                     sheet.getRange(iRow, -1, 1, -1).backColor(color);
                     loadMaterialData(iGclRow, iRow);
+                    SpreadJsObj.reLoadRowData(ledgerSpread.getActiveSheet(), iGclRow);
                 });
             },
         }
@@ -422,7 +449,9 @@ $(document).ready(() => {
                     materialListData.splice(materialListIndex, 1);
                     const [iGclRow, iRow, lsheet, lselect] = leafXmjSpreadObj.getSelect();
                     gclGatherData[iGclRow].leafXmjs[iRow].jiacha = calcOneBQJC(lselect);
+                    calculateJiaCha(gclGatherData, iGclRow)
                     SpreadJsObj.reLoadRowData(lsheet, iRow);
+                    SpreadJsObj.reLoadRowData(ledgerSpread.getActiveSheet(), iGclRow);
                 });
             },
             deletePress: function (sheet) {
@@ -463,7 +492,9 @@ $(document).ready(() => {
                         SpreadJsObj.reLoadRowData(info.sheet, info.row);
                         const [iGclRow, iRow, sheet, lselect] = leafXmjSpreadObj.getSelect();
                         gclGatherData[iGclRow].leafXmjs[iRow].jiacha = calcOneBQJC(lselect);
+                        calculateJiaCha(gclGatherData, iGclRow)
                         SpreadJsObj.reLoadRowData(sheet, iRow);
+                        SpreadJsObj.reLoadRowData(ledgerSpread.getActiveSheet(), iGclRow);
                     }, function () {
                         SpreadJsObj.reLoadRowData(info.sheet, info.row);
                     });
@@ -542,7 +573,9 @@ $(document).ready(() => {
                     materialListData = result;
                     const [iGclRow, iRow, sheet, lselect] = leafXmjSpreadObj.getSelect();
                     gclGatherData[iGclRow].leafXmjs[iRow].jiacha = calcOneBQJC(lselect);
+                    calculateJiaCha(gclGatherData, iGclRow)
                     SpreadJsObj.reLoadRowData(sheet, iRow);
+                    SpreadJsObj.reLoadRowData(ledgerSpread.getActiveSheet(), iGclRow);
                 }, function () {
                     SpreadJsObj.reLoadRowData(info.sheet, info.cellRange.row, info.cellRange.rowCount);
                 });
@@ -597,12 +630,14 @@ $(document).ready(() => {
             postData(window.location.pathname + '/save', { type:'useOther', postData: { addXmj: needAddList, select: select } }, function (result) {
                 materialListData = result;
                 toastr.success('成功添加了' + needAddList.length + '条调差工料到其他清单明细中');
+                calculateJiaCha(gclGatherData)
                 const index = gclGatherData.indexOf(ledgerSelect);
                 loadLeafXmjData(index);
                 const xmjSheet = leafXmjSpread.getActiveSheet();
                 const xmjSelect = SpreadJsObj.getSelectObject(xmjSheet);
                 const xmjIndex = gclGatherData[index].leafXmjs.indexOf(xmjSelect);
                 loadMaterialData(index, xmjIndex);
+                SpreadJsObj.reLoadRowData(ledgerSpread.getActiveSheet(), index);
             });
         });
         $.contextMenu({
@@ -701,8 +736,11 @@ $(document).ready(() => {
         } else {
             gclGatherModel.loadLedgerData(ledger, curLedgerData);
             gclGatherModel.loadPosData(pos, curPosData);
-            gclGatherData = gclGatherModel.gatherGclData();
+            gclGatherData = gclGatherModel.gatherGclData().filter(item => {
+                return item.qc_qty || item.contract_qty
+            });
         }
+        calculateJiaCha(gclGatherData);
         SpreadJsObj.loadSheetData(ledgerSpread.getActiveSheet(), SpreadJsObj.DataType.Data, gclGatherData);
         loadLeafXmjData(0);
         loadMaterialData(0, 0);
@@ -710,7 +748,6 @@ $(document).ready(() => {
         SpreadJsObj.resetTopAndSelect(leafXmjSpread.getActiveSheet());
         SpreadJsObj.resetTopAndSelect(materialSpread.getActiveSheet());
         checkNotJoinMaterialData();
-
     });
 
     $.subMenu({

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

@@ -9,7 +9,7 @@ $(document).ready(function() {
     autoFlashHeight();
     try {
         if (user !== '') {
-            $(".title-bar h2").text(user);
+            $(".sidebar-title").text(user);
         }
         $.validator.addMethod("isMobile", function(value, element) {
             var length = value.length;

+ 13 - 13
app/public/report/js/rpt_custom.js

@@ -468,7 +468,7 @@ const rptCustomObj = (function () {
                     return x.id === zTreeOprObj.currentNode.refId;
                 });
                 if (stage_select) {
-                    stage_select.gather_select = data[sStageSelect];
+                    stage_select.stage_select = data[sStageSelect];
                 }
                 $('#stage-select-count').html(data[sStageSelect].stages.length);
                 $('#stage-select').modal('hide');
@@ -533,33 +533,33 @@ const rptCustomObj = (function () {
             const gather_select = customSelects.gather_select.find(function (x) {
                 return x.id === rptId;
             });
+            const stage_select = customSelects.stage_select.find(function (x) {
+                return x.id === rptId;
+            });
             if (gather_select && gather_select.custom_define && gather_select.custom_define[sGatherSelect].enable) {
                 if (rptId === currentRptId) {
-                    params.customSelect.push(gather_select[sGatherSelect]);
+                    const data = {};
+                    data[sGatherSelect] = gather_select[sGatherSelect];
+                    params.customSelect.push(data);
                 } else {
                     const chkNode = chkNodes.find(function (x) { return x.refId === rptId});
                     params.customSelect.push(await comfirmSelectPromise(chkNode ? chkNode.name : '', gather_select));
                 }
-            } else {
-                params.customSelect.push(null);
-            }
-
-            const stage_select = customSelects.stage_select.find(function (x) {
-                return x.id === rptId;
-            });
-            if (stage_select && stage_select.custom_define && stage_select.custom_define[sStageSelect].enable) {
+                $('#gather-select').modal('hide');
+            } else if (stage_select && stage_select.custom_define && stage_select.custom_define[sStageSelect].enable) {
                 if (rptId === currentRptId) {
-                    params.customSelect.push(stage_select[sStageSelect]);
+                    const data = {};
+                    data[sStageSelect] = stage_select[sStageSelect];
+                    params.customSelect.push(data);
                 } else {
                     const chkNode = chkNodes.find(function (x) { return x.refId === rptId});
                     params.customSelect.push(await comfirmSelectPromise(chkNode ? chkNode.name : '', stage_select));
                 }
+                $('#stage-select').modal('hide');
             } else {
                 params.customSelect.push(null);
             }
         }
-        $('#gather-select').modal('hide');
-        $('#stage-select').modal('hide');
     };
 
     const showMaterialSelect = function () {

+ 0 - 1
app/reports/util/rpt_calculation_data_util.js

@@ -221,7 +221,6 @@ class Rpt_Data_Extractor {
 
         // console.log(rawDataObj);
         setupFunc($PROJECT.REPORT, rawDataObj, baseDir);
-
         if (tpl[JV.NODE_MAP_DATA_HANDLE_INFO]) {
             for (const preHandle of tpl[JV.NODE_MAP_DATA_HANDLE_INFO]) {
                 const srcData = getModuleDataByKey(rawDataObj.prjData, preHandle[JV.PROP_DATA_KEY]);

+ 1 - 0
app/service/material_file.js

@@ -31,6 +31,7 @@ module.exports = app => {
             if (mid) where.mid = mid;
             return await this.db.select(this.tableName, {
                 where,
+                orders: [['upload_time', 'desc']],
             });
         }
 

+ 53 - 18
app/service/stage_audit.js

@@ -12,6 +12,7 @@ const auditConst = require('../const/audit').stage;
 const smsTypeConst = require('../const/sms_type');
 const SMS = require('../lib/sms');
 const SmsAliConst = require('../const/sms_alitemplate');
+const payConst = require('../const/deal_pay');
 
 module.exports = app => {
     class StageAudit extends app.BaseService {
@@ -985,6 +986,30 @@ module.exports = app => {
         }
 
         /**
+         * 删除 某期 某次 全审批流程
+         * 私有,不做判断,不补全最新一轮审批人数据,不计算缓存
+         * @param {Number} sid - 标段id
+         * @param {Number} times - 第几次审批
+         * @param transaction - 删除事务
+         * @return {Promise<void>}
+         */
+        async _timesDelete(sid, times, transaction) {
+            // 审批流程
+            await transaction.delete(this.tableName, { sid: sid, times: times });
+            await transaction.delete(this.ctx.service.pos.tableName, {add_stage: sid, add_times: times});
+            await transaction.delete(this.ctx.service.stageBills.tableName, { sid: sid, times: times });
+            await transaction.delete(this.ctx.service.stagePos.tableName, { sid: sid, times: times });
+            await transaction.delete(this.ctx.service.stageDetail.tableName, { sid: sid, times: times });
+            await transaction.delete(this.ctx.service.stageChange.tableName, { sid: sid, stimes: times });
+            await transaction.delete(this.ctx.service.stagePay.tableName, { sid: sid, stimes: times });
+            await transaction.delete(this.ctx.service.pay.tableName, { csid: sid, cstimes: times });
+            // 其他台账
+            await this.ctx.service.stageJgcl.deleteStageTimesData(sid, times, transaction);
+            await this.ctx.service.stageOther.deleteStageTimesData(sid, times, transaction);
+            await this.ctx.service.stageBonus.deleteStageTimesData(sid, times, transaction);
+        }
+
+        /**
          * 删除本次审批流程
          * @param {Number} stageId - 标段id
          * @param {Number} times - 第几次审批
@@ -993,13 +1018,13 @@ module.exports = app => {
         async timesDelete() {
             const transaction = await this.db.beginTransaction();
             try {
-                // 当前审批人2次添加至流程中
-                // 判断当前期是否是重新上报状态,决定删除times数并获取times个数
-                await transaction.delete(this.tableName, { sid: this.ctx.stage.id, times: this.ctx.stage.times });
+                // 删除最新一次数据
+                await this._timesDelete(this.ctx.stage.id, this.ctx.stage.times, transaction);
+                // 审批退回,未重新上报时,需删除最新两次数据
                 const isCheckNo = this.ctx.stage.status === auditConst.status.checkNo;
                 const nowTimes = isCheckNo ? this.ctx.stage.times - 1 : this.ctx.stage.times;
                 if (isCheckNo) {
-                    await transaction.delete(this.tableName, { sid: this.ctx.stage.id, times: nowTimes });
+                    await this._timesDelete(this.ctx.stage.id, nowTimes, transaction);
                 }
                 // 添加上一次审批人
                 const sql = 'SELECT `tid`, `sid`, `aid`, `order` FROM ?? WHERE `sid` = ? and `times` = ? GROUP BY `aid` ORDER BY `id` ASC';
@@ -1016,24 +1041,34 @@ module.exports = app => {
                 // 拷贝新一次审核流程列表
                 await transaction.insert(this.tableName, auditors);
 
-                // const tpData = await this.ctx.service.stageBills.getSumTotalPrice(this.ctx.stage);
-                // // 计算并合同支付最终数据
-                // const [yfPay, sfPay] = await this.ctx.service.stagePay.calcAllStagePays(this.ctx.stage, transaction);
+                // 计算缓存
+                const tpData = await this.ctx.service.stageBills.getSumTotalPrice(this.ctx.stage);
+                // 计算并合同支付最终数据
+                const lastAudit = await this.getDataByCondition({sid: this.ctx.stage.id, times: nowTimes - 1, status: auditConst.status.checkNo});
+                if (!lastAudit) throw '审批数据错误';
+
+                await this.ctx.service.stagePay.copyStagePays4DeleteTimes(this.ctx.stage, nowTimes, 0, lastAudit.times, lastAudit.order, transaction);
+                const stagePay = await this.ctx.service.stagePay.getAuditorStageData(this.ctx.stage.id, lastAudit.times, lastAudit.order);
+                const yfPay = stagePay.find(function (x) {
+                    return x.ptype === payConst.payType.yf;
+                });
+                const sfPay = stagePay.find(function (x) {
+                    return x.ptype === payConst.payType.sf;
+                });
                 // 同步 期信息
+                const time = new Date();
                 await transaction.update(this.ctx.service.stage.tableName, {
-                    id: this.ctx.stage.id, status: auditConst.status.checkNo,
-                    // contract_tp: tpData.contract_tp,
-                    // qc_tp: tpData.qc_tp,
+                    id: this.ctx.stage.id,
+                    status: auditConst.status.checkNo,
+                    contract_tp: tpData.contract_tp,
+                    qc_tp: tpData.qc_tp,
                     times: nowTimes,
-                    // yf_tp: yfPay.tp,
-                    // sf_tp: sfPay.tp,
-                    // tp_history: JSON.stringify(this.ctx.stage.tp_history),
-                    cache_time_r: this.ctx.stage.cache_time_l,
+                    yf_tp: yfPay.tp,
+                    sf_tp: sfPay.tp,
+                    tp_history: JSON.stringify(this.ctx.stage.tp_history),
+                    cache_time_l: time,
+                    cache_time_r: time,
                 });
-                // 复制一份最新数据给原报
-                // await this.ctx.service.stagePay.copyAuditStagePays(this.ctx.stage, this.ctx.stage.times + 1, 0, transaction);
-                // await this.ctx.service.stageJgcl.updateHistory(this.ctx.stage, transaction);
-                // await this.ctx.service.stageBonus.updateHistory(this.ctx.stage, transaction);
                 await transaction.commit();
             } catch (err) {
                 await transaction.rollback();

+ 32 - 29
app/service/stage_bills.js

@@ -29,10 +29,11 @@ module.exports = app => {
          * @param {Number} tid - 标段id
          * @param {Number} sid - 期id
          * @param {Number|Array} lid - 台账节点id(可以为空)
-         * @returns {Promise<*>}
+         * @return {Promise<*>}
          */
         async getLastestStageData(tid, sid, lid) {
-            let lidSql = '', result;
+            let lidSql = '',
+                result;
             if (lid) {
                 if (lid instanceof Array) {
                     lidSql = lid.length > 0 ? ' And lid in (' + this.ctx.helper.getInArrStrSqlFilter(lid) + ')' : '';
@@ -52,9 +53,9 @@ module.exports = app => {
                 return await this.db.query(sql, sqlParam);
             } else if (lid instanceof Array) {
                 return await this.db.query(sql, sqlParam);
-            } else {
-                return await this.db.queryOne(sql, sqlParam);
             }
+            return await this.db.queryOne(sql, sqlParam);
+
         }
 
         /**
@@ -64,7 +65,7 @@ module.exports = app => {
          * @param {Number} times - 第几轮
          * @param {Number} order - 流程
          * @param {Number|Array} lid - 台账节点id(可以为空)
-         * @returns {Promise<*>}
+         * @return {Promise<*>}
          */
         async getAuditorStageData(tid, sid, times, order, lid) {
             const lidSql = lid ? ' And Bills.lid in (?)' : '';
@@ -82,14 +83,15 @@ module.exports = app => {
             } else if (lid instanceof Array) {
                 sqlParam.push(lid.join(', '));
                 return await this.db.query(sql, sqlParam);
-            } else {
-                sqlParam.push(lid);
-                return await this.db.queryOne(sql, sqlParam);
             }
+            sqlParam.push(lid);
+            return await this.db.queryOne(sql, sqlParam);
+
         }
 
         async getLastestStageData2(tid, sid, lid) {
-            let lidSql = '', result;
+            let lidSql = '',
+                result;
             if (lid) {
                 if (lid instanceof Array) {
                     lidSql = lid.length > 0 ? ' And lid in (' + this.ctx.helper.getInArrStrSqlFilter(lid) + ')' : '';
@@ -109,9 +111,9 @@ module.exports = app => {
                 return await this.db.query(sql, sqlParam);
             } else if (lid instanceof Array) {
                 return await this.db.query(sql, sqlParam);
-            } else {
-                return await this.db.queryOne(sql, sqlParam);
             }
+            return await this.db.queryOne(sql, sqlParam);
+
         }
 
         async getStageUsedBills(tid, sid) {
@@ -163,9 +165,9 @@ module.exports = app => {
                 return await this.db.query(sql, sqlParam);
             } else if (lid instanceof Array) {
                 return await this.db.query(sql, sqlParam);
-            } else {
-                return await this.db.queryOne(sql, sqlParam);
             }
+            return await this.db.queryOne(sql, sqlParam);
+
         }
 
         async getStageBills(tid, sid, lid) {
@@ -235,7 +237,7 @@ module.exports = app => {
         /**
          * 前端提交数据
          * @param {Object|Array} data - 提交的数据
-         * @returns {Promise<void>}
+         * @return {Promise<void>}
          */
         async updateStageData(data) {
             const datas = data instanceof Array ? data : [data];
@@ -267,7 +269,7 @@ module.exports = app => {
          * @param ledgerBills
          * @param stageBills
          * @param data
-         * @returns {Promise<void>}
+         * @return {Promise<void>}
          * @private
          */
         async updateStageBillsQty(transaction, ledgerBills, stageBills, data) {
@@ -285,14 +287,14 @@ module.exports = app => {
             } else {
                 await this._insertStageBillsData(transaction, data, stageBills, ledgerBills);
             }
-        };
+        }
         /**
          * 重算 本期计量 数量 (根据部位明细)
          * @param {Number} tid - 标段id
          * @param {Number} id - 需要计算的节点的id
          * @param {Number} lid - 台账id
          * @param {Object} transaction - 操作所属事务
-         * @returns {Promise<void>}
+         * @return {Promise<void>}
          */
         async calc(tid, sid, lid, transaction) {
             const info = this.ctx.tender.info;
@@ -317,14 +319,14 @@ module.exports = app => {
             if (stageBills) {
                 if (stageBills.contract_qty === posGather.contract_qty && stageBills.qc_qty === posGather.qc_qty) {
                     return;
+                }
+                if (stageBills.times === this.ctx.stage.curTimes && stageBills.order === this.ctx.stage.curOrder) {
+                    posGather.id = stageBills.id;
+                    await transaction.update(this.tableName, posGather);
                 } else {
-                    if (stageBills.times === this.ctx.stage.curTimes && stageBills.order === this.ctx.stage.curOrder) {
-                        posGather.id = stageBills.id;
-                        await transaction.update(this.tableName, posGather);
-                    } else {
-                        await this._insertStageBillsData(transaction, posGather, stageBills, ledgerBills);
-                    }
+                    await this._insertStageBillsData(transaction, posGather, stageBills, ledgerBills);
                 }
+
             } else {
                 await this._insertStageBillsData(transaction, posGather, stageBills, ledgerBills);
             }
@@ -332,7 +334,7 @@ module.exports = app => {
 
         async updateStageBillsCalcType(data) {
             const stageBills = await this.getLastestStageData(this.ctx.tender.id, this.ctx.stage.id, data.id);
-            const updateData = {contract_qty: null, contract_tp: null};
+            const updateData = { contract_qty: null, contract_tp: null };
 
             const transaction = await this.db.beginTransaction();
             try {
@@ -354,7 +356,7 @@ module.exports = app => {
 
             const bills = await this.ctx.service.ledger.getDataById(data.id);
             const curStageData = await this.getLastestStageData(this.ctx.tender.id, this.ctx.stage.id, [data.id]);
-            return {bills: [bills], curStageData: curStageData};
+            return { bills: [bills], curStageData };
         }
 
         async getSumTotalPrice(stage) {
@@ -389,9 +391,9 @@ module.exports = app => {
         async getSumTotalPriceGcl(stage, regText) {
             if (regText) {
                 return await this.getSumTotalPriceFilter(stage, 'REGEXP', regText);
-            } else {
-                return await this.getSumTotalPriceFilter(stage, '<>', this.db.escape(''));
             }
+            return await this.getSumTotalPriceFilter(stage, '<>', this.db.escape(''));
+
         }
 
         async getSumTotalPriceNotGcl(stage) {
@@ -402,7 +404,7 @@ module.exports = app => {
          * 多期清单数据整合 (材料调差调用)
          * @param {Number} tid - 标段id
          * @param {String} stage_id_list - 期id列表
-         * @returns {Promise<void>}
+         * @return {Promise<void>}
          */
         async getStagesData(tid, stage_id_list) {
             let stage_id_listSql = '';
@@ -419,6 +421,7 @@ module.exports = app => {
                 stage_id_listSql + ' GROUP BY `lid`';
             const sqlParam = [tid];
             const result = await this.db.query(sql, sqlParam);
+            console.log('result', result);
             return result;
         }
 
@@ -428,7 +431,7 @@ module.exports = app => {
          * @param {String} stage_id_list - 期id列表
          * @param {String} lid - 台账id
          * @param {String} xid - 项目节id
-         * @returns {Promise<void>}
+         * @return {Promise<void>}
          */
         async getGatherQtyByMaterial(tid, stage_id_list, lid) {
             stage_id_list = stage_id_list !== null ? stage_id_list.split(',') : [];

+ 27 - 3
app/service/stage_bonus.js

@@ -165,11 +165,12 @@ module.exports = app => {
             if (datas.length === 0) return;
 
             const updateDatas = [];
+            const times = this.ctx.stage.curTimes, order = this.ctx.stage.curOrder;
             for (const d of datas) {
                 const history = d.shistory && d.shistory !== '' ? JSON.parse(d.shistory) : [];
-                const his = datas.find(function (x) {
-                    return x.stimes && x.stimes === this.ctx.stage.curTimes
-                        && x.sorder && x.sorder === this.ctx.stage.curOrder;
+                const his = history.find(function (x) {
+                    return x.stimes && x.stimes === times
+                        && x.sorder && x.sorder === order;
                 });
                 if (his) {
                     his.tp = d.tp;
@@ -180,6 +181,29 @@ module.exports = app => {
             }
             await transaction.updateRows(this.tableName, updateDatas);
         }
+
+
+        async deleteStageTimesData(sid, times, transaction) {
+            const datas = await this.getAllDataByCondition({where: { sid: sid }});
+            if (datas.length === 0) return;
+
+            const updateDatas = [];
+            for (const d of datas) {
+                const history = d.shistory && d.shistory !== '' ? JSON.parse(d.shistory) : [];
+                const his = history.filter(function (x) {
+                    return x.stimes && x.stimes < times;
+                });
+                his.sort(function (x, y) {
+                    return (x.stimes * 1000 + x.sorder) - (y.stimes * 1000 + y.sorder);
+                });
+                updateDatas.push({
+                    id: d.id,
+                    shistory: JSON.stringify(his),
+                    tp: his.length > 0 ? his[his.length - 1].tp : null,
+                });
+            }
+            await transaction.updateRows(this.tableName, updateDatas);
+        }
     }
 
     return StageBonus;

+ 29 - 3
app/service/stage_jgcl.js

@@ -186,11 +186,12 @@ module.exports = app => {
             if (datas.length === 0) return;
 
             const updateDatas = [];
+            const times = this.ctx.stage.curTimes, order = this.ctx.stage.curOrder;
             for (const d of datas) {
                 const history = d.shistory && d.shistory !== '' ? JSON.parse(d.shistory) : [];
-                const his = datas.find(function (x) {
-                    return x.stimes && x.stimes === this.ctx.stage.curTimes
-                        && x.sorder && x.sorder === this.ctx.stage.curOrder;
+                const his = history.find(function (x) {
+                    return x.stimes && x.stimes === times
+                        && x.sorder && x.sorder === order;
                 });
                 if (his) {
                     his.arrive_qty = d.arrive_qty;
@@ -228,6 +229,31 @@ module.exports = app => {
                 return true;
             }
         }
+
+        async deleteStageTimesData(sid, times, transaction) {
+            const datas = await this.getAllDataByCondition({where: { sid: sid }});
+            if (datas.length === 0) return;
+
+            const updateDatas = [];
+            for (const d of datas) {
+                const history = d.shistory && d.shistory !== '' ? JSON.parse(d.shistory) : [];
+                const his = history.filter(function (x) {
+                    return x.stimes && x.stimes < times;
+                });
+                his.sort(function (x, y) {
+                    return (x.stimes * 1000 + x.sorder) - (y.stimes * 1000 + y.sorder);
+                });
+                updateDatas.push({
+                    id: d.id,
+                    shistory: JSON.stringify(his),
+                    arrive_qty: his.length > 0 ? his[his.length - 1].arrive_qty : null,
+                    arrive_tp: his.length > 0 ? his[his.length - 1].arrive_tp : null,
+                    deduct_qty: his.length > 0 ? his[his.length - 1].deduct_qty : null,
+                    deduct_tp: his.length > 0 ? his[his.length - 1].deduct_tp : null,
+                });
+            }
+            await transaction.updateRows(this.tableName, updateDatas);
+        }
     }
 
     return StageJgcl;

+ 26 - 3
app/service/stage_other.js

@@ -159,11 +159,12 @@ module.exports = app => {
             if (datas.length === 0) return;
 
             const updateDatas = [];
+            const times = this.ctx.stage.curTimes, order = this.ctx.stage.curOrder;
             for (const d of datas) {
                 const history = d.shistory && d.shistory !== '' ? JSON.parse(d.shistory) : [];
-                const his = datas.find(function (x) {
-                    return x.stimes && x.stimes === this.ctx.stage.curTimes
-                        && x.sorder && x.sorder === this.ctx.stage.curOrder;
+                const his = history.find(function (x) {
+                    return x.stimes && x.stimes === times
+                        && x.sorder && x.sorder === order;
                 });
                 if (his) {
                     his.tp = d.tp;
@@ -199,6 +200,28 @@ module.exports = app => {
             }
 
         }
+
+        async deleteStageTimesData(sid, times, transaction) {
+            const datas = await this.getAllDataByCondition({where: { sid: sid }});
+            if (datas.length === 0) return;
+
+            const updateDatas = [];
+            for (const d of datas) {
+                const history = d.shistory && d.shistory !== '' ? JSON.parse(d.shistory) : [];
+                const his = history.filter(function (x) {
+                    return x.stimes && x.stimes < times;
+                });
+                his.sort(function (x, y) {
+                    return (x.stimes * 1000 + x.sorder) - (y.stimes * 1000 + y.sorder);
+                });
+                updateDatas.push({
+                    id: d.id,
+                    shistory: JSON.stringify(his),
+                    tp: his.length > 0 ? his[his.length - 1].tp : null,
+                });
+            }
+            await transaction.updateRows(this.tableName, updateDatas);
+        }
     }
 
     return StageOther;

+ 20 - 0
app/service/stage_pay.js

@@ -295,6 +295,26 @@ module.exports = app => {
         }
 
         /**
+         * 拷贝上一操作人数据 为 下一操作人数据
+         * @param stage - 期数据
+         * @param times - 下一操作人 该期第几次
+         * @param order - 下一操作人顺序
+         * @param transaction - 事务
+         * @returns {Promise<*>}
+         */
+        async copyStagePays4DeleteTimes(stage, times, order, copyTimes, copyOrder, transaction) {
+            const sql = 'INSERT INTO ?? (`tid`, `sid`, `pid`, `stimes`, `sorder`, `name`, `tp`, `expr`, `pause`, `attachment`,' +
+                '    `pre_tp`, `end_tp`, `pre_used`, `pre_finish`, `start_stage_order`) ' +
+                '  SELECT SP.`tid`, SP.`sid`, SP.`pid`, ?, ?, SP.name, SP.`tp`, SP.`expr`, SP.`pause`, SP.`attachment`,' +
+                '     SP.`pre_tp`, SP.`end_tp`, SP.`pre_used`, SP.`pre_finish`, SP.`start_stage_order` ' +
+                '  FROM ?? As SP, ?? As P ' +
+                '  WHERE SP.`sid` = ? AND SP.`stimes` = ? AND SP.`sorder` = ? And SP.`pid` = P.`id` And P.`valid`';
+            const sqlParam = [this.tableName, times, order, this.tableName, this.ctx.service.pay.tableName,
+                stage.id, copyTimes, copyOrder];
+            return await transaction.query(sql, sqlParam);
+        }
+
+        /**
          * 保存附件
          * @param data
          * @returns {Promise<void>}

+ 8 - 2
app/view/change/info_modal.ejs

@@ -109,7 +109,10 @@
             <div class="modal-body">
                 <div class="row">
                     <div class="col-12">
-                        <div class="mb-2 col-6 p-0 search-group"><input class="form-control form-control-sm" placeholder="输入 清单编号、名称 检索" value="202-1-1"><a href="" class="text-danger remove-btn" title="移除关键词"><i class="fa fa-times-circle "></i></a></div>
+                        <div class="mb-2 col-6 p-0 search-group">
+                            <input class="form-control form-control-sm" id="list-input" placeholder="输入 清单编号、名称 检索" value="">
+                            <a href="javascript:void(0);" style="display: none" data-btn="list" class="text-danger remove-btn" title="移除关键词"><i class="fa fa-times-circle "></i></a>
+                        </div>
                         <div style="overflow-y:auto" class="sjs-biangeng-height">
                             <table class="table table-striped table-bordered table-hover table-sm fixed_headers">
                                 <thead><tr><th width="40">序号</th><th>清单编号</th><th>名称</th><th width="50">单位</th><th width="100">单价</th><th width="100">数量</th></tr></thead>
@@ -119,7 +122,10 @@
                         </div>
                     </div>
                     <div class="col-12">
-                        <div class="mb-2 col-6 p-0 search-group"><input class="form-control form-control-sm" placeholder="输入 项目节编号、名称、计量单元 检索"><!-- <a href="" class="text-danger remove-btn" title="移除关键词"><i class="fa fa-times-circle "></i></a> --></div>
+                        <div class="mb-2 col-6 p-0 search-group mt-2">
+                            <input class="form-control form-control-sm" id="code-input" placeholder="输入 项目节编号、名称、计量单元 检索">
+                            <a href="javascript:void(0);" style="display: none" data-btn="code" class="text-danger remove-btn" title="移除关键词"><i class="fa fa-times-circle "></i></a>
+                        </div>
                         <div style="overflow-y:auto" class="sjs-biangeng-height">
                             <table class="table table-striped table-bordered table-hover table-sm fixed_headers2">
                                 <thead>

+ 15 - 3
app/view/material/file.ejs

@@ -7,6 +7,10 @@
           <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>
+            <div style="margin-left: 20px;">
+              <!--所有附件 翻页-->
+              <span id="showPage"><a href="javascript:void(0);" class="page-select" content="pre"><i class="fa fa-chevron-left"></i></a> <span id="currentPage">1</span>/<span id="totalPage">10</span> <a href="javascript:void(0);" class="page-select" content="next"><i class="fa fa-chevron-right"></i></a></span>
+            </div>
           </span>
         </div>
     </div>
@@ -16,10 +20,17 @@
       <div class="sjs-height-0">
         <table class="table table-bordered">
           <thead>
-            <tr><th width="50">序号</th><th>名称</th><th width="90">大小</th><th width="90">调差期</th><th width="150">上传时间</th><th width="100">操作</th></tr>
+            <tr>
+              <th width="50">序号</th>
+              <th>名称</th>
+              <th width="90">大小</th>
+              <th width="90">调差期</th>
+              <th width="150">上传时间</th>
+              <th width="100">操作</th>
+            </tr>
           </thead>
           <tbody id="file-list">
-            <% fileList.forEach(function(file, idx){ %>
+            <!-- <% fileList.filter(file => file.mid === ctx.material.id).forEach(function(file, idx){ %>
               <tr>
                 <td><%=idx + 1%></td>
                 <td><a href="/<%- file.filepath %>" target="_blank"><%=file.file_name%></a></td>
@@ -49,7 +60,7 @@
                   <% } %>
                 </td>
               </tr>
-            <% }) %>
+            <% }) %> -->
           </tbody>
         </table>
       </div>
@@ -65,4 +76,5 @@
   const tid = '<%- ctx.tender.id %>';
   const mid = '<%- ctx.material.id %>';
   const fileList = JSON.parse('<%- JSON.stringify(fileList) %>');
+  const whiteList = JSON.parse('<%- JSON.stringify(whiteList) %>');
 </script>

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

@@ -9,7 +9,7 @@
       </button>
         </div>
         <div class="modal-body">
-          <p>大小限制:10MB,支持office等文档格式、图片格式、压缩包格式</p>
+          <p>大小限制:30MB,支持office等文档格式、图片格式、压缩包格式</p>
                   <p>
                       <input id="upload-fujian-file" type="file" multiple="multiple">
                       <!-- <a href="javascript: void(0);" id="upload-fujian" class="btn btn-primary">选择文件</a> -->

+ 4 - 4
app/view/profile/sub_menu.ejs

@@ -1,19 +1,19 @@
 <div class="panel-sidebar">
-    <div class="panel-title">
-        <div class="title-bar">
-            <h2>项目信息</h2>
-        </div>
+    <div class="sidebar-title">
+        项目信息
     </div>
     <div class="scrollbar-auto">
         <div class="nav-box">
             <ul class="nav-list list-unstyled">
                 <% for (const index in ctx.subMenu) { %>
+                <% if (ctx.subMenu[index].display === false) { %>
                 <li <% if (ctx.url === ctx.subMenu[index].url) { %>class="active"<% } %>>
                     <a href="<%- ctx.subMenu[index].url %>">
                         <span><%- ctx.subMenu[index].name %></span>
                     </a>
                 </li>
                 <% } %>
+                <% } %>
             </ul>
         </div>
     </div>

+ 2 - 4
app/view/setting/sub_menu.ejs

@@ -1,8 +1,6 @@
 <div class="panel-sidebar">
-    <div class="panel-title">
-        <div class="title-bar">
-            <h2>项目信息</h2>
-        </div>
+    <div class="sidebar-title">
+        项目信息
     </div>
     <div class="scrollbar-auto">
         <div class="nav-box">

+ 18 - 0
app/view/stage/audit_modal.ejs

@@ -1436,6 +1436,23 @@
     <% } %>
 <% } %>
 <% if (ctx.stage.auditors !== undefined && ctx.stage.auditors.length !== 0 && ctx.stage.auditors[ctx.stage.auditors.length-1].aid === ctx.session.sessionUser.accountId && ctx.stage.status === auditConst.status.checked && ctx.stage.order === ctx.stage.highOrder) { %>
+    <% if (ctx.stage.hadMaterial) { %>
+    <div class="modal fade" id="sp-down-back" 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">
+                    <h5>材料调差已使用当前期,如需重新审批,请先删除材料调差相关期</h5>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">取消</button>
+                </div>
+            </div>
+        </div>
+    </div>
+    <% } else { %>
     <div class="modal fade" id="sp-down-back" data-backdrop="static">
         <div class="modal-dialog" role="document">
             <div class="modal-content">
@@ -1452,6 +1469,7 @@
             </div>
         </div>
     </div>
+    <% } %>
 <% } %>
 <% if (ctx.stage.user_id === ctx.session.sessionUser.accountId && ctx.stage.order === ctx.stage.highOrder && (ctx.stage.status === auditConst.status.checkNo || ctx.stage.status === auditConst.status.uncheck)) { %>
     <!--删除期-->

+ 54 - 0
app/view/stage/manager_modal.ejs

@@ -1,4 +1,21 @@
 <% if (lastStage) { %>
+<% if (ctx.stage.hadMaterial) { %>
+    <div class="modal fade" id="del" 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">
+                    <h5>材料调差已使用当前期,如需删除,请先删除材料调差相关期</h5>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">取消</button>
+                </div>
+            </div>
+        </div>
+    </div>
+<% } else { %>
 <!--删除本次审批-->
 <div class="modal fade" id="del" data-backdrop="static">
     <div class="modal-dialog" role="document">
@@ -20,6 +37,24 @@
         </form>
     </div>
 </div>
+<% } %>
+<% if (ctx.stage.hadMaterial) { %>
+    <div class="modal fade" id="del-qi" 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">
+                    <h5>材料调差已使用当前期,如需删除,请先删除材料调差相关期</h5>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">取消</button>
+                </div>
+            </div>
+        </div>
+    </div>
+<% } else { %>
 <!--删除本期-->
 <div class="modal fade" id="del-qi" data-backdrop="static">
     <div class="modal-dialog" role="document">
@@ -43,8 +78,26 @@
         </form>
     </div>
 </div>
+<% } %>
 <% if (lastStage.status === auditConst.status.checked) { %>
 <!--设置终审-->
+<% if (ctx.stage.hadMaterial) { %>
+    <div class="modal fade" id="pass" 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">
+                    <h5>材料调差已使用当前期,如需重新审批,请先删除材料调差相关期</h5>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">取消</button>
+                </div>
+            </div>
+        </div>
+    </div>
+        <% } else { %>
 <div class="modal fade" id="pass" data-backdrop="static">
     <div class="modal-dialog" role="document">
         <form action="/tender/<%- ctx.tender.id %>/measure/stage/<%- lastStage.order %>/audit/check/again" method="get" class="modal-content">
@@ -63,6 +116,7 @@
         </form>
     </div>
 </div>
+    <% } %>
 <% } %>
 <% } %>
 <% include ./audit_modal.ejs %>

+ 1 - 1
config/config.default.js

@@ -129,7 +129,7 @@ module.exports = appInfo => {
 
     const file = appInfo.baseDir + '/config/version';
 
-    config.version = fs.existsSync(file) ? fs.readFileSync(file, 'utf8') : '1.0.4';
+    config.version = fs.existsSync(file) ? fs.readFileSync(file, 'utf8') : '1.0.5';
 
     // 压缩设置
     config.gzip = {

+ 1 - 1
config/menu.js

@@ -288,7 +288,7 @@ const profileMenu = {
     },
     wechat: {
         name: '微信通知',
-        display: false,
+        display: true,
         url: '/profile/wechat',
     },
     sign: {

+ 4 - 0
sql/update.sql

@@ -102,3 +102,7 @@ ADD COLUMN `stage_select`  text CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL
 
 ALTER TABLE `calculation`.`zh_material_file`
 ADD COLUMN `s_order` VARCHAR(255) NOT NULL  COMMENT '期数order' AFTER `file_name`;
+
+-- ----------------------------
+-- 以上于2020-7-23 15:00 因测试需求更新至uat,尚未更新prod,如需增加sql,请一定在其后添加
+-- ----------------------------