瀏覽代碼

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

TonyKang 3 年之前
父節點
當前提交
f8621b689f
共有 47 個文件被更改,包括 663 次插入271 次删除
  1. 1 0
      app/const/page_show.js
  2. 2 2
      app/controller/advance_controller.js
  3. 6 1
      app/controller/budget_controller.js
  4. 2 2
      app/controller/change_controller.js
  5. 3 3
      app/controller/ledger_controller.js
  6. 25 3
      app/controller/material_controller.js
  7. 4 2
      app/controller/setting_controller.js
  8. 6 6
      app/controller/stage_controller.js
  9. 3 2
      app/controller/tender_controller.js
  10. 2 2
      app/controller/wap_controller.js
  11. 2 2
      app/extend/helper.js
  12. 5 0
      app/middleware/material_check.js
  13. 122 61
      app/public/js/budget_compare.js
  14. 89 31
      app/public/js/budget_list.js
  15. 91 46
      app/public/js/material.js
  16. 2 0
      app/public/js/material_list.js
  17. 1 0
      app/public/js/path_tree.js
  18. 5 1
      app/public/js/revise.js
  19. 4 3
      app/public/js/shares/tenders2tree.js
  20. 3 3
      app/public/js/tender_list_info.js
  21. 3 3
      app/public/js/tender_list_progress.js
  22. 36 6
      app/service/material.js
  23. 3 0
      app/service/material_audit.js
  24. 26 9
      app/service/material_bills.js
  25. 6 2
      app/service/material_list.js
  26. 12 4
      app/service/material_month.js
  27. 9 0
      app/service/project.js
  28. 6 0
      app/service/report_memory.js
  29. 1 1
      app/service/stage_detail_att.js
  30. 2 2
      app/service/stage_shoufang.js
  31. 5 1
      app/view/budget/compare.ejs
  32. 2 18
      app/view/budget/compare_modal.ejs
  33. 4 1
      app/view/budget/list.ejs
  34. 3 10
      app/view/budget/list_modal.ejs
  35. 54 22
      app/view/material/exponent.ejs
  36. 11 7
      app/view/material/index.ejs
  37. 39 3
      app/view/material/info.ejs
  38. 1 1
      app/view/measure/stage.ejs
  39. 30 0
      app/view/setting/fun.ejs
  40. 4 3
      config/config.default.js
  41. 2 1
      config/config.local.js
  42. 2 1
      config/config.qa.js
  43. 2 1
      config/config.remoteqa.js
  44. 2 1
      config/config.remoteuat.js
  45. 3 2
      config/config.uat.js
  46. 8 1
      config/web.js
  47. 9 1
      sql/update.sql

+ 1 - 0
app/const/page_show.js

@@ -34,6 +34,7 @@ const defaultSetting = {
     openSign: 0,
     openNetCaSign: 0,
     openChangeRevise: 0,
+    openMaterialTax: 0,
 };
 
 

+ 2 - 2
app/controller/advance_controller.js

@@ -425,7 +425,7 @@ module.exports = app => {
                     const fileInfo = path.parse(stream.filename);
                     const filepath = `app/public/upload/${this.ctx.tender.id.toString()}/yfk/fujian_${create_time + idx.toString() + fileInfo.ext}`;
                     // await ctx.helper.saveStreamFile(stream, path.resolve(this.app.baseDir, 'app', filepath));
-                    await ctx.app.fujianOss.put(filepath, stream);
+                    await ctx.app.fujianOss.put(ctx.app.config.fujianOssFolder + filepath, stream);
                     files.push({ filepath, name: stream.filename, ext: fileInfo.ext });
                     ++idx;
                     stream && (await sendToWormhole(stream));
@@ -474,7 +474,7 @@ module.exports = app => {
                 if (fileInfo || Object.keys(fileInfo).length) {
                     // 先删除文件
                     // await fs.unlinkSync(path.resolve(this.app.baseDir, './app', fileInfo.filepath));
-                    await ctx.app.fujianOss.delete(fileInfo.filepath);
+                    await ctx.app.fujianOss.delete(ctx.app.config.fujianOssFolder + fileInfo.filepath);
                     // 再删除数据库
                     await ctx.service.advanceFile.delete(id);
                 } else {

+ 6 - 1
app/controller/budget_controller.js

@@ -50,6 +50,7 @@ module.exports = app => {
                     return { groupName: item, groupList };
                 });
                 renderData.permissionConst = ctx.service.budgetPermission.PermissionConst;
+                renderData.categoryData = await this.ctx.service.category.getAllCategory(this.ctx.session.sessionProject.id);
                 await this.layout('budget/list.ejs', renderData, 'budget/list_modal.ejs');
             } catch (err) {
                 ctx.log(err);
@@ -111,7 +112,7 @@ module.exports = app => {
                     err: 0,
                     msg: '',
                     data: tenderList.filter(x => { return otherRela.indexOf(x.id) === -1})
-                        .map(y => { return {id: y.id, name: y.name, lastStageOrder: y.lastStage.order, lastStageStatus: auditConst.stage.statusString[y.lastStage.status]}}),
+                        .map(y => { return {id: y.id, name: y.name, lastStageOrder: y.lastStage.order, lastStageStatus: auditConst.stage.statusString[y.lastStage.status], category: y.category}}),
                 };
             } catch (err) {
                 ctx.log(err);
@@ -153,6 +154,10 @@ module.exports = app => {
                 renderData.tenderList = relaTenderId.length > 0 ? tenderList.filter(x => {
                     return relaTenderId.indexOf(x.id) >= 0;
                 }) : tenderList;
+                renderData.tenderList = renderData.tenderList.map(y => {
+                    return { id: y.id, name: y.name, lastStageOrder: y.lastStage.order, lastStageStatus: auditConst.stage.statusString[y.lastStage.status], category: y.category };
+                });
+                renderData.categoryData = await this.ctx.service.category.getAllCategory(this.ctx.session.sessionProject.id);
                 await this.layout('budget/compare.ejs', renderData, 'budget/compare_modal.ejs');
             } catch (err) {
                 ctx.log(err);

+ 2 - 2
app/controller/change_controller.js

@@ -1099,7 +1099,7 @@ module.exports = app => {
                     // const filepath = `app/public/upload/change/fujian_${create_time + index.toString() + fileInfo.ext}`;
                     const filepath = `app/public/upload/${parts.field.tid}/change/fujian_${create_time + index.toString() + fileInfo.ext}`;
                     // await ctx.helper.saveStreamFile(stream, path.resolve(this.app.baseDir, filepath));
-                    await ctx.app.fujianOss.put(filepath, stream);
+                    await ctx.app.fujianOss.put(ctx.app.config.fujianOssFolder + filepath, stream);
                     await sendToWormhole(stream);
                     // 保存数据到att表
                     const fileData = {
@@ -1263,7 +1263,7 @@ module.exports = app => {
                 if (fileInfo !== undefined && fileInfo !== '') {
                     // 先删除文件
                     // await fs.unlinkSync(path.join(this.app.baseDir, fileInfo.filepath));
-                    await ctx.app.fujianOss.delete(fileInfo.filepath);
+                    await ctx.app.fujianOss.delete(ctx.app.config.fujianOssFolder + fileInfo.filepath);
                     // 再删除数据库
                     await ctx.service.changeAtt.deleteById(data.id);
                     responseData.data = '';

+ 3 - 3
app/controller/ledger_controller.js

@@ -825,7 +825,7 @@ module.exports = app => {
                     const create_time = Date.parse(new Date()) / 1000;
                     const filepath = `app/public/upload/${this.ctx.tender.id}/ledger/fujian_${create_time + index.toString() + fileInfo.ext}`;
                     // await ctx.helper.saveStreamFile(stream, path.resolve(this.app.baseDir, filepath));
-                    await ctx.app.fujianOss.put(filepath, stream);
+                    await ctx.app.fujianOss.put(ctx.app.config.fujianOssFolder + filepath, stream);
                     if (stream) {
                         await sendToWormhole(stream);
                     }
@@ -957,7 +957,7 @@ module.exports = app => {
                 if (fileInfo !== undefined && fileInfo !== '') {
                     // 先删除文件
                     // await fs.unlinkSync(path.join(this.app.baseDir, fileInfo.filepath));
-                    await ctx.app.fujianOss.delete(fileInfo.filepath);
+                    await ctx.app.fujianOss.delete(ctx.app.config.fujianOssFolder + fileInfo.filepath);
                     // 再删除数据库
                     await ctx.service.ledgerAtt.deleteById(data.id);
                     responseData.data = '';
@@ -1000,7 +1000,7 @@ module.exports = app => {
                     // }
                     // 保存文件
                     // await ctx.helper.saveStreamFile(stream, path.join(this.app.baseDir, dirName, fileName));
-                    await ctx.app.fujianOss.put(path.join(dirName, fileName), stream);
+                    await ctx.app.fujianOss.put(ctx.app.config.fujianOssFolder + path.join(dirName, fileName), stream);
                     // 保存数据到att表
                     fileData = {
                         filesize: stream.fields.size,

+ 25 - 3
app/controller/material_controller.js

@@ -52,7 +52,14 @@ module.exports = app => {
                     auditConst,
                     auditConst2: JSON.stringify(auditConst),
                 };
+                let openMaterialTax = ctx.session.sessionProject.page_show.openMaterialTax;
+                let allMaterialTax = true;
                 renderData.materials = await ctx.service.material.getValidMaterials(ctx.tender.id);
+                const lastMaterial = renderData.materials.length > 0 ? renderData.materials[0] : null;
+                if (lastMaterial && (lastMaterial.status === auditConst.status.uncheck || lastMaterial.status === auditConst.status.checkNo) && lastMaterial.material_tax !== openMaterialTax) {
+                    await ctx.service.material.updateMaterialTax(lastMaterial.id, openMaterialTax);
+                    lastMaterial.material_tax = openMaterialTax;
+                }
                 // 获取未选中和已完成的计量期
                 const stages = await ctx.service.stage.getAllDataByCondition({ where: { tid: ctx.tender.id, status: auditStageConst.status.checked } });
                 for (const s of renderData.materials) {
@@ -66,8 +73,16 @@ module.exports = app => {
                         });
                         stages.splice(index, 1);
                     }
+                    if (allMaterialTax && s.material_tax === 0) {
+                        allMaterialTax = false;
+                    }
+                    if (!openMaterialTax && s.material_tax === 1) {
+                        openMaterialTax = 1;
+                    }
                 }
                 renderData.stages = stages;
+                renderData.openMaterialTax = openMaterialTax;
+                renderData.allMaterialTax = allMaterialTax;
                 await this.layout('material/index.ejs', renderData, 'material/modal.ejs');
             } catch (err) {
                 this.log(err);
@@ -342,8 +357,10 @@ module.exports = app => {
                 // }
 
                 // 取当前期截止上期含税金额
+                renderData.material.m_tax_tp = renderData.material.m_tax_tp ? renderData.material.m_tax_tp : renderData.material.m_tp;
                 renderData.pre_tp_hs = await ctx.service.material.getPreTpHs(ctx.tender.id, ctx.material.order);
                 renderData.ex_pre_tp_hs = await ctx.service.material.getExPreTpHs(ctx.tender.id, ctx.material.order);
+                // renderData.tax_pre_tp_hs = await ctx.service.material.getTaxPreTpHs(ctx.tender.id, ctx.material.order);
 
                 renderData.months = ctx.material.months ? ctx.material.months.split(',') : [];
                 renderData.monthsList = await this._getMaterialMonthsData(ctx, renderData.materialBillsData);
@@ -670,7 +687,9 @@ module.exports = app => {
                         break;
                     default: throw '参数有误';
                 }
-
+                if (this.ctx.material.material_tax) {
+                    responseData.data.m_tax_tp = await ctx.service.material.getMaterialTaxTp(ctx.material.id);
+                }
                 ctx.body = responseData;
             } catch (err) {
                 this.log(err);
@@ -732,6 +751,9 @@ module.exports = app => {
                         break;
                     default: throw '参数有误';
                 }
+                if (this.ctx.material.material_tax) {
+                    responseData.data.m_tax_tp = await ctx.service.material.getMaterialTaxTp(ctx.material.id);
+                }
                 responseData.data.materialBillsData = await this._getMaterialBillsData(ctx);
                 ctx.body = responseData;
             } catch (err) {
@@ -973,7 +995,7 @@ module.exports = app => {
                     // const filepath = path.join('public/upload', this.ctx.tender.id.toString(), 'tc', 'fujian_' + create_time + fileInfo.ext);
                     const filepath = `app/public/upload/${this.ctx.tender.id.toString()}/tc/fujian_${create_time + idx.toString() + fileInfo.ext}`;
                     // await ctx.helper.saveStreamFile(stream, path.resolve(this.app.baseDir, 'app', filepath));
-                    await ctx.app.fujianOss.put(filepath, stream);
+                    await ctx.app.fujianOss.put(ctx.app.config.fujianOssFolder + filepath, stream);
                     files.push({ filepath, name: stream.filename, ext: fileInfo.ext });
                     ++idx;
                 }
@@ -1085,7 +1107,7 @@ module.exports = app => {
                 if (fileInfo) {
                     // 先删除文件
                     // await fs.unlinkSync(path.resolve(this.app.baseDir, './app', fileInfo.filepath));
-                    await ctx.app.fujianOss.delete(fileInfo.filepath);
+                    await ctx.app.fujianOss.delete(ctx.app.config.fujianOssFolder + fileInfo.filepath);
                     // 再删除数据库
                     await ctx.service.materialFile.delete(id);
                 } else {

+ 4 - 2
app/controller/setting_controller.js

@@ -763,9 +763,11 @@ module.exports = app => {
 
                 const result = await ctx.service.project.updateFunRela(projectId, ctx.request.body);
                 if (!result) throw '保存数据失败';
+                const result2 = await ctx.service.project.updatePageshow(projectId, ctx.request.body);
+                if (!result2) throw '保存数据失败';
 
-                ctx.body = {err: 0, msg: '', data: null};
-            } catch(error) {
+                ctx.body = { err: 0, msg: '', data: null };
+            } catch (error) {
                 ctx.helper.log(error);
                 this.ajaxErrorBody(error, '保存数据失败');
             }

+ 6 - 6
app/controller/stage_controller.js

@@ -762,7 +762,7 @@ module.exports = app => {
 
                     // 保存文件
                     // await ctx.helper.saveStreamFile(stream, path.join(this.app.baseDir, dirName, fileName));
-                    await ctx.app.fujianOss.put(filepath, stream);
+                    await ctx.app.fujianOss.put(ctx.app.config.fujianOssFolder + filepath, stream);
                     await sendToWormhole(stream);
 
                     // 插入到stage_pay对应的附件列表中
@@ -1456,7 +1456,7 @@ module.exports = app => {
                     const create_time = Date.parse(new Date()) / 1000;
                     const filepath = `app/public/upload/${this.ctx.tender.id}/stage/fujian_${create_time + index.toString() + fileInfo.ext}`;
                     // await ctx.helper.saveStreamFile(stream, path.resolve(this.app.baseDir, filepath));
-                    await ctx.app.fujianOss.put(filepath, stream);
+                    await ctx.app.fujianOss.put(ctx.app.config.fujianOssFolder + filepath, stream);
                     // console.log(await fs.existsSync(path.resolve(this.app.baseDir, 'app', filepath)));
                     // const fileInfo = path.parse(stream.filename);
                     // const fileName = 'stage' + create_time + '_' + index + fileInfo.ext;
@@ -1600,7 +1600,7 @@ module.exports = app => {
                 if (fileInfo !== undefined && fileInfo !== '') {
                     // 先删除文件
                     // await fs.unlinkSync(path.join(this.app.baseDir, fileInfo.filepath));
-                    await ctx.app.fujianOss.delete(fileInfo.filepath);
+                    await ctx.app.fujianOss.delete(ctx.app.config.fujianOssFolder + fileInfo.filepath);
                     // 再删除数据库
                     await ctx.service.stageAtt.deleteById(data.id);
                     responseData.data = '';
@@ -1646,7 +1646,7 @@ module.exports = app => {
 
                     // 保存文件
                     // await ctx.helper.saveStreamFile(stream, path.join(this.app.baseDir, dirName, fileName));
-                    await ctx.app.fujianOss.put(path.join(dirName, fileName), stream);
+                    await ctx.app.fujianOss.put(ctx.app.config.fujianOssFolder + path.join(dirName, fileName), stream);
                     // 保存数据到att表
                     fileData = {
                         filesize: stream.fields.size,
@@ -1771,7 +1771,7 @@ module.exports = app => {
                     // }
                     // 保存文件
                     // await ctx.helper.saveStreamFile(stream, path.join(this.app.baseDir, dirName, fileName));
-                    await ctx.app.fujianOss.put(filepath, stream);
+                    await ctx.app.fujianOss.put(ctx.app.config.fujianOssFolder + filepath, stream);
                     await sendToWormhole(stream);
                     // 插入到stage_pay对应的附件列表中
                     const attData = {
@@ -1851,7 +1851,7 @@ module.exports = app => {
                 const data = JSON.parse(ctx.request.body.data);
                 const fileInfo = await ctx.service.payAtt.getDataById(data.id);
                 if (!fileInfo) throw '不存在该文件';
-                await ctx.app.fujianOss.delete(fileInfo.filepath);
+                await ctx.app.fujianOss.delete(ctx.app.config.fujianOssFolder + fileInfo.filepath);
                 const result = await ctx.service.payAtt.delFiles(data.id);
                 // if (fs.existsSync(path.join(ctx.app.baseDir, fileInfo.filepath))) {
                 //     await fs.unlinkSync(path.join(ctx.app.baseDir, fileInfo.filepath));

+ 3 - 2
app/controller/tender_controller.js

@@ -127,6 +127,9 @@ module.exports = app => {
                 const tenderList = await this.ctx.service.tender.getList('', userPermission, this.ctx.session.sessionUser.is_admin);
 
                 for (const t of tenderList) {
+                    const tenderInfo = await this.ctx.service.tenderInfo.getTenderInfo(t.id);
+                    t.contract_price = tenderInfo.deal_param.contractPrice;
+
                     if (t.user_id === this.ctx.session.sessionUser.accountId && (
                         t.ledger_status === auditConst.ledger.status.checkNo || t.ledger_status === auditConst.ledger.status.uncheck)) {
                         const sum = await this.ctx.service.ledger.addUp({ tender_id: t.id/* , is_leaf: true*/ });
@@ -178,8 +181,6 @@ module.exports = app => {
                 renderData.tenderList = await this.ctx.service.tender.getList(list_status, renderData.userPermission, this.ctx.session.sessionUser.is_admin);
 
                 for (const t of renderData.tenderList) {
-                    const tenderInfo = await this.ctx.service.tenderInfo.getTenderInfo(t.id);
-                    t.deal_tp = tenderInfo.deal_param.contractPrice;
                     if (t.ledger_status === auditConst.ledger.status.checked) {
                         t.lastStage = await this.ctx.service.stage.getLastestStage(t.id, true);
                         t.completeStage = await this.ctx.service.stage.getLastestCompleteStage(t.id);

+ 2 - 2
app/controller/wap_controller.js

@@ -594,7 +594,7 @@ module.exports = app => {
                     const create_time = Date.parse(now_time) / 1000;
                     const filepath = `app/public/upload/${sfInfo.tid}/stage/shoufang/fujian_${create_time + index.toString() + fileInfo.ext}`;
                     // await ctx.helper.saveStreamFile(stream, path.resolve(this.app.baseDir, filepath));
-                    await ctx.app.fujianOss.put(filepath, stream);
+                    await ctx.app.fujianOss.put(ctx.app.config.fujianOssFolder + filepath, stream);
                     // console.log(await fs.existsSync(path.resolve(this.app.baseDir, 'app', filepath)));
                     // const fileInfo = path.parse(stream.filename);
                     // const fileName = 'stage' + create_time + '_' + index + fileInfo.ext;
@@ -663,7 +663,7 @@ module.exports = app => {
                 if (fileInfo !== undefined && fileInfo !== '') {
                     // 先删除文件
                     // await fs.unlinkSync(path.join(this.app.baseDir, fileInfo.filepath));
-                    await ctx.app.fujianOss.delete(fileInfo.filepath);
+                    await ctx.app.fujianOss.delete(ctx.app.config.fujianOssFolder + fileInfo.filepath);
                     // 再删除数据库
                     await ctx.service.stageShoufangAtt.deleteById(data.id);
                     responseData.data = '';

+ 2 - 2
app/extend/helper.js

@@ -1218,7 +1218,7 @@ module.exports = {
                 if (att.filepath && fs.existsSync(path.join(this.app.baseDir, att.filepath))) {
                     await fs.unlinkSync(path.join(this.app.baseDir, att.filepath));
                 } else if (att.filepath) {
-                    await this.ctx.app.fujianOss.delete(att.filepath);
+                    await this.ctx.app.fujianOss.delete(this.ctx.app.config.fujianOssFolder + att.filepath);
                 }
             }
         }
@@ -1424,7 +1424,7 @@ module.exports = {
         if (!_.includes(path, 'app/')) {
             path = 'app/' + path;
         }
-        const result = await this.ctx.app.fujianOss.get(path);
+        const result = await this.ctx.app.fujianOss.get(this.ctx.app.config.fujianOssFolder + path);
         if (result.res.status !== 200) {
             throw '该文件不存在';
         }

+ 5 - 0
app/middleware/material_check.js

@@ -45,6 +45,11 @@ module.exports = options => {
             if (!material) {
                 throw '材料调差期数据错误';
             }
+            const openMaterialTax = this.session.sessionProject.page_show.openMaterialTax;
+            if ((material.status === status.uncheck || material.status === status.checkNo) && material.material_tax !== openMaterialTax) {
+                yield this.service.material.updateMaterialTax(material.id, openMaterialTax);
+                material.material_tax = openMaterialTax;
+            }
             // 读取原报、审核人数据
             material.auditors = yield this.service.materialAudit.getAuditors(material.id, material.times);
             // if (material.status > 1) {

+ 122 - 61
app/public/js/budget_compare.js

@@ -47,7 +47,6 @@ $(document).ready(() => {
         rootId: -1,
     });
 
-
     function compareCode(str1, str2, symbol = '-') {
         if (!str1) {
             return 1;
@@ -152,66 +151,6 @@ $(document).ready(() => {
             compareSpread.refresh();
         }
     });
-
-    $('#sf-select-all').click(function() {
-        $('[name=sf-tender]').prop("checked", this.checked);
-    });
-    $('#select-final-ok').click(() => {
-        const rela = [];
-        const select = $('[name=sf-tender]:checked');
-        for (const s of select) {
-            rela.push(parseInt(s.getAttribute('tid')));
-        }
-        if (rela.length === 0) return;
-        postData(window.location.pathname + '/final', {id: rela}, function(result) {
-            if (spreadSetting.cols.length < 13) {
-                spreadSetting.cols.push(...[
-                    {title: '台账|数量1/数量2', colSpan: '3|1', rowSpan: '1|1', field: 'dgn_qty', hAlign: 2, width: 80},
-                    {title: '|经济指标', colSpan: '|1', rowSpan: '|1', field: 'dgn_price', hAlign: 2, width: 80, type: 'Number'},
-                    {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'total_price', hAlign: 2, width: 80, type: 'Number'},
-                    {title: '决算|数量1/数量2', colSpan: '3|1', rowSpan: '1|1', field: 'final_dgn_qty', hAlign: 2, width: 80},
-                    {title: '|经济指标', colSpan: '|1', rowSpan: '|1', field: 'final_dgn_price', hAlign: 2, width: 80, type: 'Number'},
-                    {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'final_tp', hAlign: 2, width: 80, type: 'Number'},
-                    {title: '增幅%|数量1/数量2', colSpan: '2|1', rowSpan: '1|1', field: 'grow_dgn_qty', hAlign: 2, width: 80},
-                    {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'grow_tp', hAlign: 2, width: 80, type: 'Number'},
-                ]);
-            }
-            const setting = { id: 'ledger_id', pid: 'ledger_pid', order: 'order', level: 'level', rootId: -1, calcFields: ['total_price', 'end_gather_tp'] };
-            compareTree.clearFinal();
-            for (const r of result) {
-                const tree = createNewPathTree('ledger', setting);
-                tree.loadDatas(r);
-                treeCalc.calculateAll(tree);
-                compareTree.loadTree(tree, function (cur, source) {
-                    cur.total_price = ZhCalc.add(cur.total_price, source.total_price);
-                    cur.dgn_qty1 = ZhCalc.add(cur.dgn_qty1, source.dgn_qty1);
-                    cur.dgn_qty2 = ZhCalc.add(cur.dgn_qty2, source.dgn_qty2);
-                    cur.final_dgn_qty1 = ZhCalc.sum([cur.final_dgn_qty1, source.deal_dgn_qty1, source.c_dgn_qty1]);
-                    cur.final_dgn_qty2 = ZhCalc.sum([cur.final_dgn_qty2, source.deal_dgn_qty2, source.c_dgn_qty2]);
-                    cur.final_tp = ZhCalc.add(cur.final_tp, source.end_gather_tp);
-                });
-            }
-            compareTree.afterLoad(node => {
-                node.dgn_price = ZhCalc.div(node.total_price, node.dgn_qty1, 2);
-                node.dgn_qty = node.dgn_qty1
-                    ? (node.dgn_qty2 ? node.dgn_qty1 + '/' + node.dgn_qty2 : node.dgn_qty1)
-                    : (node.dgn_qty2 ? '/' + node.dgn_qty2 : '');
-                node.final_dgn_price = ZhCalc.div(node.final_tp, node.final_dgn_qty1, 2);
-                node.final_dgn_qty = node.final_dgn_qty1
-                    ? (node.final_dgn_qty2 ? node.final_dgn_qty1 + '/' + node.final_dgn_qty2 : node.final_dgn_qty1)
-                    : (node.final_dgn_qty2 ? '/' + node.final_dgn_qty2 : '');
-                node.grow_dgn_qty1 = ZhCalc.mul(ZhCalc.div(ZhCalc.sub(node.final_dgn_qty1, node.gai_dgn_qty1), node.gai_dgn_qty1, 4), 100);
-                node.grow_dgn_qty2 = ZhCalc.mul(ZhCalc.div(ZhCalc.sub(node.final_dgn_qty2, node.gai_dgn_qty2), node.gai_dgn_qty2, 4), 100);
-                node.grow_dgn_qty = node.grow_dgn_qty1
-                    ? (node.grow_dgn_qty2 ? node.grow_dgn_qty1 + '/' + node.grow_dgn_qty2 : node.grow_dgn_qty1)
-                    : (node.grow_dgn_qty2 ? '/' + node.grow_dgn_qty2 : '');
-                node.grow_tp = ZhCalc.mul(ZhCalc.div(ZhCalc.sub(node.final_tp, node.gai_tp), node.gai_tp, 4), 100);
-            });
-            SpreadJsObj.reLoadSheetHeader(compareSheet);
-            SpreadJsObj.reLoadSheetData(compareSheet);
-            $('#select-final').modal('hide');
-        });
-    });
     // 显示层次
     (function (select, sheet) {
         $(select).click(function () {
@@ -238,4 +177,126 @@ $(document).ready(() => {
             }, 100);
         });
     })('a[name=showLevel]', compareSheet);
+
+
+    class sfObject {
+        constructor() {
+            const self = this;
+            this.selectTree = Tender2Tree.convert(category, tenderList, null, null, function (node, source) {
+                node.lastStageOrder =`第${source.lastStageOrder}期`;
+                node.lastStageStatus = source.lastStageStatus;
+            });
+            const sfSpreadSetting = {
+                cols: [
+                    {title: '选择', field: 'selected', hAlign: 1, width: 40, formatter: '@', cellType: 'checkbox'},
+                    {title: '名称', field: 'name', hAlign: 0, width: 180, formatter: '@', cellType: 'tree'},
+                    {title: '期数', field: 'lastStageOrder', hAlign: 1, width: 60, formatter: '@'},
+                    {title: '审批状态', field: 'lastStageStatus', hAlign: 1, width: 60, formatter: '@'},
+                ],
+                emptyRows: 0,
+                headRows: 1,
+                headRowHeight: [32],
+                defaultRowHeight: 21,
+                headerFont: '12px 微软雅黑',
+                font: '12px 微软雅黑',
+                headColWidth: [30],
+                selectedBackColor: '#fffacd',
+                readOnly: true,
+            };
+            this.spread = SpreadJsObj.createNewSpread($('#sf-spread')[0]);
+            this.sheet = this.spread.getActiveSheet();
+            SpreadJsObj.initSheet(this.sheet, sfSpreadSetting);
+            SpreadJsObj.loadSheetData(this.sheet, SpreadJsObj.DataType.Tree, this.selectTree);
+
+            this.spread.bind(spreadNS.Events.ButtonClicked, function (e, info) {
+                if (!info.sheet.zh_setting) return;
+
+                const col = info.sheet.zh_setting.cols[info.col];
+                if (col.field !== 'selected') return;
+
+                const node = SpreadJsObj.getSelectObject(info.sheet);
+                self.selectNode(node, !node[col.field]);
+                SpreadJsObj.reloadColData(info.sheet, 0);
+            });
+
+
+            $('#sf-select-all').click(function() {
+                for (const n of self.selectTree.nodes) {
+                    n.selected = this.checked;
+                }
+                SpreadJsObj.reloadColData(self.sheet, 0);
+            });
+            $('#select-final-ok').click(() => {
+                const rela = self.getSelects();
+                if (rela.length === 0) return;
+                postData(window.location.pathname + '/final', {id: rela}, function(result) {
+                    if (spreadSetting.cols.length < 13) {
+                        spreadSetting.cols.push(...[
+                            {title: '台账|数量1/数量2', colSpan: '3|1', rowSpan: '1|1', field: 'dgn_qty', hAlign: 2, width: 80},
+                            {title: '|经济指标', colSpan: '|1', rowSpan: '|1', field: 'dgn_price', hAlign: 2, width: 80, type: 'Number'},
+                            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'total_price', hAlign: 2, width: 80, type: 'Number'},
+                            {title: '决算|数量1/数量2', colSpan: '3|1', rowSpan: '1|1', field: 'final_dgn_qty', hAlign: 2, width: 80},
+                            {title: '|经济指标', colSpan: '|1', rowSpan: '|1', field: 'final_dgn_price', hAlign: 2, width: 80, type: 'Number'},
+                            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'final_tp', hAlign: 2, width: 80, type: 'Number'},
+                            {title: '增幅%|数量1/数量2', colSpan: '2|1', rowSpan: '1|1', field: 'grow_dgn_qty', hAlign: 2, width: 80},
+                            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'grow_tp', hAlign: 2, width: 80, type: 'Number'},
+                        ]);
+                    }
+                    const setting = { id: 'ledger_id', pid: 'ledger_pid', order: 'order', level: 'level', rootId: -1, calcFields: ['total_price', 'end_gather_tp'] };
+                    compareTree.clearFinal();
+                    for (const r of result) {
+                        const tree = createNewPathTree('ledger', setting);
+                        tree.loadDatas(r);
+                        treeCalc.calculateAll(tree);
+                        compareTree.loadTree(tree, function (cur, source) {
+                            cur.total_price = ZhCalc.add(cur.total_price, source.total_price);
+                            cur.dgn_qty1 = ZhCalc.add(cur.dgn_qty1, source.dgn_qty1);
+                            cur.dgn_qty2 = ZhCalc.add(cur.dgn_qty2, source.dgn_qty2);
+                            cur.final_dgn_qty1 = ZhCalc.sum([cur.final_dgn_qty1, source.deal_dgn_qty1, source.c_dgn_qty1]);
+                            cur.final_dgn_qty2 = ZhCalc.sum([cur.final_dgn_qty2, source.deal_dgn_qty2, source.c_dgn_qty2]);
+                            cur.final_tp = ZhCalc.add(cur.final_tp, source.end_gather_tp);
+                        });
+                    }
+                    compareTree.afterLoad(node => {
+                        node.dgn_price = ZhCalc.div(node.total_price, node.dgn_qty1, 2);
+                        node.dgn_qty = node.dgn_qty1
+                            ? (node.dgn_qty2 ? node.dgn_qty1 + '/' + node.dgn_qty2 : node.dgn_qty1)
+                            : (node.dgn_qty2 ? '/' + node.dgn_qty2 : '');
+                        node.final_dgn_price = ZhCalc.div(node.final_tp, node.final_dgn_qty1, 2);
+                        node.final_dgn_qty = node.final_dgn_qty1
+                            ? (node.final_dgn_qty2 ? node.final_dgn_qty1 + '/' + node.final_dgn_qty2 : node.final_dgn_qty1)
+                            : (node.final_dgn_qty2 ? '/' + node.final_dgn_qty2 : '');
+                        node.grow_dgn_qty1 = ZhCalc.mul(ZhCalc.div(ZhCalc.sub(node.final_dgn_qty1, node.gai_dgn_qty1), node.gai_dgn_qty1, 4), 100);
+                        node.grow_dgn_qty2 = ZhCalc.mul(ZhCalc.div(ZhCalc.sub(node.final_dgn_qty2, node.gai_dgn_qty2), node.gai_dgn_qty2, 4), 100);
+                        node.grow_dgn_qty = node.grow_dgn_qty1
+                            ? (node.grow_dgn_qty2 ? node.grow_dgn_qty1 + '/' + node.grow_dgn_qty2 : node.grow_dgn_qty1)
+                            : (node.grow_dgn_qty2 ? '/' + node.grow_dgn_qty2 : '');
+                        node.grow_tp = ZhCalc.mul(ZhCalc.div(ZhCalc.sub(node.final_tp, node.gai_tp), node.gai_tp, 4), 100);
+                    });
+                    SpreadJsObj.reLoadSheetHeader(compareSheet);
+                    SpreadJsObj.reLoadSheetData(compareSheet);
+                    $('#select-final').modal('hide');
+                });
+            });
+        }
+        selectNode(node, select) {
+            const posterity = this.selectTree.getPosterity(node);
+            posterity.unshift(node);
+            for (const p of posterity) {
+                p.selected = select;
+            }
+        }
+        getSelects() {
+            const select = [];
+            for (const n of this.selectTree.nodes) {
+                if ((!n.children || n.children.length === 0) && n.selected) select.push(n.tid);
+            }
+            return select;
+        }
+    }
+
+    let sfSelect;
+    $('#select-final').on('shown.bs.modal', () => {
+        if (!sfSelect) sfSelect = new sfObject();
+    });
 });

+ 89 - 31
app/public/js/budget_list.js

@@ -48,19 +48,6 @@ const delBudget = function () {
     });
 };
 
-const relaTender = function () {
-    // todo 选择标段
-    const rela = [];
-    const select = $('[name=select-rela-check]:checked');
-    for (const s of select) {
-        rela.push(s.getAttribute('tid'));
-    }
-    postData('/budget/save', { id: curBudget.id, rela_tender: rela.join(',') }, function () {
-        $(`[bid=${curBudget.id}]`)[0].setAttribute('rela-tender', rela.join(','));
-        $('#select-rela').modal('hide');
-    });
-};
-
 
 $(document).ready(() => {
     autoFlashHeight();
@@ -70,24 +57,6 @@ $(document).ready(() => {
     $('#del-budget').on('show.bs.modal', () => {
         $('#del-budget-name').text(curBudget.name);
     });
-    $('#sr-select-all').click(function () {
-        $('[name=select-rela-check]').prop("checked", this.checked);
-    });
-    $('#select-rela').on('show.bs.modal', () => {
-        $('#sr-select-all')[0].checked = false;
-        $('#valid-rela-tender').html('');
-        postData(`/budget/rela?id=${curBudget.id}`, {}, tenders => {
-            const rela = curBudget.rela_tender ? curBudget.rela_tender.split(',') : [];
-            const html = [];
-            for (const t of tenders) {
-                html.push(`<tr><td class="text-center"><input type="checkbox" name="select-rela-check" tid="${t.id}"></td><td>${t.name}</td><td>第${t.lastStageOrder}期</td><td>${t.lastStageStatus}</td></tr>`);
-            }
-            $('#valid-rela-tender').html(html.join(''));
-            for (const r of rela) {
-                $(`[tid=${r}]`).attr("checked", "checked");
-            }
-        });
-    });
 
     let timer = null;
     let oldSearchVal = null;
@@ -214,4 +183,93 @@ $(document).ready(() => {
             mem.permission.splice(mem.permission.indexOf(permissionConst[this.getAttribute('ptype')].value), 1);
         }
     });
+
+    class srObject {
+        constructor() {
+            const self = this;
+            this.selectTree = null;
+            const srSpreadSetting = {
+                cols: [
+                    {title: '选择', field: 'selected', hAlign: 1, width: 40, formatter: '@', cellType: 'checkbox'},
+                    {title: '名称', field: 'name', hAlign: 0, width: 180, formatter: '@', cellType: 'tree'},
+                    {title: '期数', field: 'lastStageOrder', hAlign: 1, width: 60, formatter: '@'},
+                    {title: '审批状态', field: 'lastStageStatus', hAlign: 1, width: 60, formatter: '@'},
+                ],
+                emptyRows: 0,
+                headRows: 1,
+                headRowHeight: [32],
+                defaultRowHeight: 21,
+                headerFont: '12px 微软雅黑',
+                font: '12px 微软雅黑',
+                headColWidth: [30],
+                selectedBackColor: '#fffacd',
+                readOnly: true,
+            };
+            this.spread = SpreadJsObj.createNewSpread($('#sr-spread')[0]);
+            this.sheet = this.spread.getActiveSheet();
+            SpreadJsObj.initSheet(this.sheet, srSpreadSetting);
+
+            this.spread.bind(spreadNS.Events.ButtonClicked, function (e, info) {
+                if (!info.sheet.zh_setting) return;
+
+                const col = info.sheet.zh_setting.cols[info.col];
+                if (col.field !== 'selected') return;
+
+                const node = SpreadJsObj.getSelectObject(info.sheet);
+                self.selectNode(node, !node[col.field]);
+                SpreadJsObj.reloadColData(info.sheet, 0);
+            });
+
+
+
+            $('#sr-select-all').click(function () {
+                if (!self.selectTree) return;
+                for (const n of self.selectTree.nodes) {
+                    n.selected = this.checked;
+                }
+                SpreadJsObj.reloadColData(self.sheet, 0);
+            });
+            $('#select-rela-ok').click(() => {
+                const rela = self.getSelects();
+                postData('/budget/save', { id: curBudget.id, rela_tender: rela.join(',') }, function () {
+                    $(`[bid=${curBudget.id}]`)[0].setAttribute('rela-tender', rela.join(','));
+                    $('#select-rela').modal('hide');
+                });
+            });
+        }
+        selectNode(node, select) {
+            const posterity = this.selectTree.getPosterity(node);
+            posterity.unshift(node);
+            for (const p of posterity) {
+                p.selected = select;
+            }
+        }
+        getSelects() {
+            const select = [];
+            for (const n of this.selectTree.nodes) {
+                if ((!n.children || n.children.length === 0) && n.selected) select.push(n.tid);
+            }
+            return select;
+        }
+        init() {
+            $('#sr-select-all')[0].checked = false;
+            const self = this;
+            postData(`/budget/rela?id=${curBudget.id}`, {}, tenders => {
+                const rela = curBudget.rela_tender ? curBudget.rela_tender.split(',') : [];
+                self.selectTree = Tender2Tree.convert(category, tenders, null, null, function (node, source) {
+                    node.lastStageOrder = `第${source.lastStageOrder}期`;
+                    node.lastStageStatus = source.lastStageStatus;
+                });
+                for (const node of self.selectTree.nodes) {
+                    node.selected = rela.indexOf(node.tid + '') >= 0;
+                }
+                SpreadJsObj.loadSheetData(this.sheet, SpreadJsObj.DataType.Tree, this.selectTree);
+            });
+        }
+    }
+    let srSelect;
+    $('#select-rela').on('shown.bs.modal', () => {
+        if (!srSelect) srSelect = new srObject();
+        srSelect.init();
+    });
 });

+ 91 - 46
app/public/js/material.js

@@ -72,13 +72,18 @@ DatePickerCellType.prototype.updateEditor = function (editorContext, cellStyle,
 };
 
 function resetTpTable() {
-    const rate = $('#changeRate').val();
-    const bqhs = ZhCalc.round(ZhCalc.mul(m_tp, 1+rate/100), 2);
-    const jzbqhs = ZhCalc.round(ZhCalc.add(pre_tp_hs, bqhs), 2);
     $('#tp_set').find('td').eq(1).text(ZhCalc.round(m_tp, 2));
     $('#tp_set').find('td').eq(2).text(ZhCalc.round(ZhCalc.add(pre_tp, m_tp), 2));
-    $('#rate_set').find('td').eq(1).text(bqhs !== 0 ? bqhs : '');
-    $('#rate_set').find('td').eq(2).text(jzbqhs !== 0 ? jzbqhs : '');
+    if (materialTax) {
+        $('#rate_set').find('td').eq(1).text(ZhCalc.round(m_tax_tp, 2));
+        $('#rate_set').find('td').eq(2).text(ZhCalc.round(ZhCalc.add(m_tax_pre_tp, m_tax_tp), 2));
+    } else {
+        const rate = $('#changeRate').val();
+        const bqhs = ZhCalc.round(ZhCalc.mul(m_tp, 1+rate/100), 2);
+        const jzbqhs = ZhCalc.round(ZhCalc.add(pre_tp_hs, bqhs), 2);
+        $('#rate_set').find('td').eq(1).text(bqhs !== 0 ? bqhs : '');
+        $('#rate_set').find('td').eq(2).text(jzbqhs !== 0 ? jzbqhs : '');
+    }
 }
 function getPasteHint (str, row = '') {
     let returnObj = str;
@@ -99,27 +104,6 @@ $(document).ready(() => {
     autoFlashHeight();
     const materialSpread = SpreadJsObj.createNewSpread($('#material-spread')[0]);
     const materialSpreadSetting = {
-        cols: [
-            {title: '调差类型', colSpan: '1', rowSpan: '2', field: 't_type', hAlign: 1, width: 80, formatter: '@', readOnly: 'readOnly.isUsed', cellType: 'customizeCombo', comboItems: materialType.t_type, cellTypeKey: 1},
-            {title: '编号', colSpan: '1', rowSpan: '2', field: 'code', hAlign: 0, width: 60, formatter: '@', readOnly: 'readOnly.isUsed'},
-            {title: '名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 180, formatter: '@', readOnly: 'readOnly.isEdit'},
-            {title: '单位', colSpan: '1', rowSpan: '2', field: 'unit', hAlign: 1, width: 60, formatter: '@', readOnly: 'readOnly.isEdit'},
-            {title: '规格', colSpan: '1', rowSpan: '2', field: 'spec', hAlign: 0, width: 180, formatter: '@', readOnly: 'readOnly.isEdit'},
-            {title: '工料分类', colSpan: '1', rowSpan: '2', field: 'm_type', hAlign: 1, width: 60, readOnly: 'readOnly.isEdit', cellType: 'customizeCombo', comboItems: materialType.m_type, cellTypeKey: 2},
-            {title: '本期应耗数量', colSpan: '1', rowSpan: '2', field: 'quantity', hAlign: 2, width: 100, type: 'Number', readOnly: true},
-            {title: '基准价', colSpan: '1', rowSpan: '2', field: 'basic_price', hAlign: 2, width: 60, type: 'Number', readOnly: 'readOnly.isEdit'},
-            {title: '基准时间', colSpan: '1', rowSpan: '2', field: 'basic_times', hAlign: 0, width: 80, formatter: '@', readOnly: 'readOnly.isEdit'},
-            {title: '本期信息价|单价', colSpan: '3|1', rowSpan: '1|1', field: 'msg_tp', hAlign: 2, width: 60, type: 'Number', readOnly: 'readOnly.msg_tp'},
-            {title: '|时间', colSpan: '|1', rowSpan: '|1', field: 'msg_times', hAlign: 0, width: 80, formatter: '@', readOnly: 'readOnly.remark'},
-            {title: '|价差', colSpan: '|1', rowSpan: '|1', field: 'msg_spread', hAlign: 2, width: 60, type: 'Number', readOnly: true, getValue: 'getValue.msg_spread'},
-            {title: '本期材料调差|上涨幅度(%)', colSpan: '4|1', rowSpan: '1|1', field: 'm_up_risk', hAlign: 2, width: 100, type: 'Number', readOnly: 'readOnly.isEdit'},
-            {title: '|下跌幅度(%)', colSpan: '|1', rowSpan: '|1', field: 'm_down_risk', hAlign: 2, width: 100, type: 'Number', readOnly: 'readOnly.isEdit'},
-            {title: '|有效价差', colSpan: '|1', rowSpan: '|1', field: 'm_spread', hAlign: 2, width: 80, type: 'Number', readOnly: true, getValue: 'getValue.m_spread'},
-            {title: '|调差金额', colSpan: '|1', rowSpan: '|1', field: 'm_tp', hAlign: 2, width: 80, type: 'Number', readOnly: true, getValue: 'getValue.m_tp'},
-            {title: '截止上期调差金额', colSpan: '1', rowSpan: '2', field: 'pre_tp', hAlign: 2, width: 120, type: 'Number', readOnly: true},
-            {title: '备注', colSpan: '1', rowSpan: '2', field: 'remark', hAlign: 0, width: 60, formatter: '@', readOnly: 'readOnly.remark'},
-            {title: '是否汇总', colSpan: '1', rowSpan: '2', field: 'is_summary', hAlign: 1, width: 60, cellType: 'checkbox', readOnly: 'readOnly.isEdit'},
-        ],
         emptyRows: 0,
         headRows: 2,
         headRowHeight: [25, 25],
@@ -128,7 +112,49 @@ $(document).ready(() => {
         font: '12px 微软雅黑',
         readOnly: readOnly,
     };
-
+    let materialSpreadSettingCols = [
+        {title: '调差类型', colSpan: '1', rowSpan: '2', field: 't_type', hAlign: 1, width: 60, formatter: '@', readOnly: 'readOnly.isUsed', cellType: 'customizeCombo', comboItems: materialType.t_type, cellTypeKey: 1},
+        {title: '编号', colSpan: '1', rowSpan: '2', field: 'code', hAlign: 0, width: 60, formatter: '@', readOnly: 'readOnly.isUsed'},
+        {title: '名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 150, formatter: '@', readOnly: 'readOnly.isEdit'},
+        {title: '单位', colSpan: '1', rowSpan: '2', field: 'unit', hAlign: 1, width: 50, formatter: '@', readOnly: 'readOnly.isEdit'},
+        {title: '规格', colSpan: '1', rowSpan: '2', field: 'spec', hAlign: 0, width: 150, formatter: '@', readOnly: 'readOnly.isEdit'},
+        {title: '工料分类', colSpan: '1', rowSpan: '2', field: 'm_type', hAlign: 1, width: 60, readOnly: 'readOnly.isEdit', cellType: 'customizeCombo', comboItems: materialType.m_type, cellTypeKey: 2},
+    ];
+    if (materialTax) {
+        materialSpreadSettingCols.push({title: '税率', colSpan: '1', rowSpan: '2', field: 'm_tax', hAlign: 2, width: 50, type: 'Number', readOnly: 'readOnly.isEdit'});
+    }
+    materialSpreadSettingCols = _.concat(materialSpreadSettingCols, [
+        {title: '本期应耗数量', colSpan: '1', rowSpan: '2', field: 'quantity', hAlign: 2, width: 90, type: 'Number', readOnly: true},
+        {title: '基准价', colSpan: '1', rowSpan: '2', field: 'basic_price', hAlign: 2, width: 50, type: 'Number', readOnly: 'readOnly.isEdit'},
+        {title: '基准时间', colSpan: '1', rowSpan: '2', field: 'basic_times', hAlign: 0, width: 70, formatter: '@', readOnly: 'readOnly.isEdit'},
+        {title: '本期信息价|单价', colSpan: '3|1', rowSpan: '1|1', field: 'msg_tp', hAlign: 2, width: 60, type: 'Number', readOnly: 'readOnly.msg_tp'},
+        {title: '|时间', colSpan: '|1', rowSpan: '|1', field: 'msg_times', hAlign: 0, width: 80, formatter: '@', readOnly: 'readOnly.remark'},
+        {title: '|价差', colSpan: '|1', rowSpan: '|1', field: 'msg_spread', hAlign: 2, width: 60, type: 'Number', readOnly: true, getValue: 'getValue.msg_spread'},]
+    );
+    if (materialTax) {
+        materialSpreadSettingCols = _.concat(materialSpreadSettingCols, [
+            {title: '本期材料调差|上涨幅度(%)', colSpan: '5|1', rowSpan: '1|1', field: 'm_up_risk', hAlign: 2, width: 90, type: 'Number', readOnly: 'readOnly.isEdit'},
+            {title: '|下跌幅度(%)', colSpan: '|1', rowSpan: '|1', field: 'm_down_risk', hAlign: 2, width: 90, type: 'Number', readOnly: 'readOnly.isEdit'},
+            {title: '|有效价差', colSpan: '|1', rowSpan: '|1', field: 'm_spread', hAlign: 2, width: 80, type: 'Number', readOnly: true, getValue: 'getValue.m_spread'},
+            {title: '|调差金额', colSpan: '|1', rowSpan: '|1', field: 'm_tp', hAlign: 2, width: 100, type: 'Number', readOnly: true, getValue: 'getValue.m_tp'},
+            {title: '|调差金额(材料税)', colSpan: '|1', rowSpan: '|1', field: 'm_tax_tp', hAlign: 2, width: 100, type: 'Number', readOnly: true, getValue: 'getValue.m_tax_tp'},
+            {title: '截止上期|调差金额', colSpan: '2|1', rowSpan: '1|1', field: 'pre_tp', hAlign: 2, width: 100, type: 'Number', readOnly: true},
+            {title: '|调差金额(材料税)', colSpan: '|1', rowSpan: '|1', field: 'tax_pre_tp', hAlign: 2, width: 100, type: 'Number', readOnly: true},
+            {title: '备注', colSpan: '1', rowSpan: '2', field: 'remark', hAlign: 0, width: 50, formatter: '@', readOnly: 'readOnly.remark'},
+            {title: '是否汇总', colSpan: '1', rowSpan: '2', field: 'is_summary', hAlign: 1, width: 60, cellType: 'checkbox', readOnly: 'readOnly.isEdit'}
+        ])
+    } else {
+        materialSpreadSettingCols = _.concat(materialSpreadSettingCols, [
+            {title: '本期材料调差|上涨幅度(%)', colSpan: '4|1', rowSpan: '1|1', field: 'm_up_risk', hAlign: 2, width: 90, type: 'Number', readOnly: 'readOnly.isEdit'},
+            {title: '|下跌幅度(%)', colSpan: '|1', rowSpan: '|1', field: 'm_down_risk', hAlign: 2, width: 90, type: 'Number', readOnly: 'readOnly.isEdit'},
+            {title: '|有效价差', colSpan: '|1', rowSpan: '|1', field: 'm_spread', hAlign: 2, width: 80, type: 'Number', readOnly: true, getValue: 'getValue.m_spread'},
+            {title: '|调差金额', colSpan: '|1', rowSpan: '|1', field: 'm_tp', hAlign: 2, width: 100, type: 'Number', readOnly: true, getValue: 'getValue.m_tp'},
+            {title: '截止上期|调差金额', colSpan: '1|1', rowSpan: '1|1', field: 'pre_tp', hAlign: 2, width: 100, type: 'Number', readOnly: true},
+            {title: '备注', colSpan: '1', rowSpan: '2', field: 'remark', hAlign: 0, width: 50, formatter: '@', readOnly: 'readOnly.remark'},
+            {title: '是否汇总', colSpan: '1', rowSpan: '2', field: 'is_summary', hAlign: 1, width: 60, cellType: 'checkbox', readOnly: 'readOnly.isEdit'}
+        ])
+    }
+    materialSpreadSetting.cols = materialSpreadSettingCols;
     const spCol = _.find(materialSpreadSetting.cols, {field: 'quantity'});
     spCol.readOnly = true;
     spCol.cellType = 'activeImageBtn';
@@ -192,6 +218,10 @@ $(document).ready(() => {
             },
             m_tp: function (data) {
                 return ZhCalc.round(ZhCalc.mul(materialCol.getValue.m_spread(data), data.quantity), 2);
+            },
+            m_tax_tp: function (data) {
+                const m_tp = ZhCalc.round(ZhCalc.mul(materialCol.getValue.m_spread(data), data.quantity), 2);
+                return data.m_tax ? ZhCalc.round(ZhCalc.mul(m_tp, (1+ZhCalc.div(data.m_tax, 100))), 2) : m_tp;
             }
         },
         readOnly: {
@@ -257,6 +287,9 @@ $(document).ready(() => {
             const select = SpreadJsObj.getSelectObject(sheet);
             postData(window.location.pathname + '/save', {type: 'del', id: select.id}, function (result) {
                 m_tp = result.m_tp;
+                if (materialTax) {
+                    m_tax_tp = result.m_tax_tp;
+                }
                 resetTpTable();
                 const index = materialBillsData.indexOf(select);
                 materialBillsData.splice(index, 1);
@@ -391,21 +424,7 @@ $(document).ready(() => {
                         // return;
                     }
                 }
-                if (col.field === 'm_up_risk') {
-                    // 只能输入正整数
-                    if (isNaN(validText)) {
-                        toastr.error('不能输入其它非数字类型字符');
-                        SpreadJsObj.reLoadRowData(info.sheet, info.row);
-                        return;
-                    }
-                    const num = parseFloat(validText);
-                    if (validText !== null && (num < 0 || num > 100 || !/^\d+$/.test(num))) {
-                        toastr.error('只能输入0-100的正整数');
-                        SpreadJsObj.reLoadRowData(info.sheet, info.row);
-                        return;
-                    }
-                }
-                if (col.field === 'm_down_risk') {
+                if (col.field === 'm_up_risk' || col.field === 'm_down_risk' || col.field === 'm_tax') {
                     // 只能输入正整数
                     if (isNaN(validText)) {
                         toastr.error('不能输入其它非数字类型字符');
@@ -430,6 +449,7 @@ $(document).ready(() => {
                 select.msg_spread = materialCol.getValue.msg_spread(select);
                 select.m_spread = materialCol.getValue.m_spread(select);
                 select.m_tp = materialCol.getValue.m_tp(select);
+                select.m_tax_tp = materialCol.getValue.m_tax_tp(select);
                 delete select.waitingLoading;
 
                 // console.log(select);
@@ -437,6 +457,9 @@ $(document).ready(() => {
                 // 更新至服务器
                 postData(window.location.pathname + '/save', { type:'update', updateData: select }, function (result) {
                     m_tp = result.m_tp;
+                    if (materialTax) {
+                        m_tax_tp = result.m_tax_tp;
+                    }
                     resetTpTable();
                     SpreadJsObj.reLoadRowData(info.sheet, info.row);
                     // 判断如果是更改了编号,名称,单位,月信息价需要跟着改变值
@@ -466,6 +489,9 @@ $(document).ready(() => {
                     // 更新至服务器
                     postData(window.location.pathname + '/save', { type:'update', updateData: select }, function (result) {
                         m_tp = result.m_tp;
+                        if (materialTax) {
+                            m_tax_tp = result.m_tax_tp;
+                        }
                         resetTpTable();
                         SpreadJsObj.reLoadRowData(info.sheet, info.row);
                     }, function () {
@@ -561,7 +587,7 @@ $(document).ready(() => {
                                 // bPaste = false;
                                 // continue;
                             }
-                        } else if (colSetting.field === 'm_up_risk' || colSetting.field === 'm_down_risk') {
+                        } else if (colSetting.field === 'm_up_risk' || colSetting.field === 'm_down_risk' || colSetting.field === 'm_tax') {
                             if (validText !== null && (num < 0 || num > 100 || !/^\d+$/.test(num))) {
                                 toastMessageUniq(getPasteHint(hint.riskCan, hintRow));
                                 bPaste = false;
@@ -580,6 +606,7 @@ $(document).ready(() => {
                     materialData.msg_spread = materialCol.getValue.msg_spread(sortData[curRow]);
                     materialData.m_spread = materialCol.getValue.m_spread(sortData[curRow]);
                     materialData.m_tp = materialCol.getValue.m_tp(sortData[curRow]);
+                    materialData.m_tax_tp = materialCol.getValue.m_tax_tp(sortData[curRow]);
                     data.push(materialData);
                     // rowData.push(curRow);
                 } else {
@@ -611,6 +638,9 @@ $(document).ready(() => {
                     // SpreadJsObj.reLoadSheetData(materialMonthSpread.getActiveSheet());
                 }
                 m_tp = result.m_tp;
+                if (materialTax) {
+                    m_tax_tp = result.m_tax_tp;
+                }
                 resetTpTable();
                 // materialSpreadObj.refreshActn();
             }, function () {
@@ -638,9 +668,9 @@ $(document).ready(() => {
     sheet.resumePaint();
     const static_cols = [
         {title: '编号', colSpan: '1', rowSpan: '2', field: 'code', hAlign: 0, width: 60, formatter: '@', readOnly: true},
-        {title: '名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 140, formatter: '@', readOnly: true},
-        {title: '单位', colSpan: '1', rowSpan: '2', field: 'unit', hAlign: 1, width: 60, formatter: '@', readOnly: true},
-        {title: '来源地', colSpan: '1', rowSpan: '2', field: 'origin', hAlign: 0, width: 80, formatter: '@', readOnly: 'readOnly.isEdit'},
+        {title: '名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 100, formatter: '@', readOnly: true},
+        {title: '单位', colSpan: '1', rowSpan: '2', field: 'unit', hAlign: 1, width: 50, formatter: '@', readOnly: true},
+        {title: '来源地', colSpan: '1', rowSpan: '2', field: 'origin', hAlign: 0, width: 70, formatter: '@', readOnly: 'readOnly.isEdit'},
         {title: '平均单价', colSpan: '1', rowSpan: '2', field: 'average_msg_tp', hAlign: 2, width: 60, type: 'Number', readOnly: true, getValue:'getValue.average_msg_tp'},
     ];
     // 月信息价方法集合
@@ -797,6 +827,9 @@ $(document).ready(() => {
                         materialBillsData = result.materialBillsData;
                         SpreadJsObj.loadSheetData(materialSpread.getActiveSheet(), SpreadJsObj.DataType.Data, materialBillsData);
                         m_tp = result.m_tp;
+                        if (materialTax) {
+                            m_tax_tp = result.m_tax_tp;
+                        }
                         resetTpTable();
                     }, function () {
                         select[col.field] = orgValue;
@@ -926,6 +959,9 @@ $(document).ready(() => {
                     materialBillsData = result.materialBillsData;
                     SpreadJsObj.loadSheetData(materialSpread.getActiveSheet(), SpreadJsObj.DataType.Data, materialBillsData);
                     m_tp = result.m_tp;
+                    if (materialTax) {
+                        m_tax_tp = result.m_tax_tp;
+                    }
                     resetTpTable();
                 }, function () {
                     SpreadJsObj.reLoadRowData(info.sheet, info.cellRange.row, info.cellRange.rowCount);
@@ -1142,6 +1178,9 @@ $(document).ready(() => {
             }
             postData(window.location.pathname + '/save', { type:'expr', id: $('#materialbillsId').val(), expr: expr }, function (result) {
                 m_tp = result.m_tp;
+                if (materialTax) {
+                    m_tax_tp = result.m_tax_tp;
+                }
                 resetTpTable();
                 const sheet = materialSpread.getActiveSheet();
                 const select = SpreadJsObj.getSelectObject(sheet);
@@ -1174,6 +1213,9 @@ $(document).ready(() => {
                 materialBillsData = data.materialBillsData;
                 SpreadJsObj.loadSheetData(materialSpread.getActiveSheet(), SpreadJsObj.DataType.Data, materialBillsData);
                 m_tp = data.m_tp;
+                if (materialTax) {
+                    m_tax_tp = data.m_tax_tp;
+                }
                 resetTpTable();
                 $('#add-month').modal('hide');
             });
@@ -1204,6 +1246,9 @@ $(document).ready(() => {
                 materialBillsData = data.materialBillsData;
                 SpreadJsObj.loadSheetData(materialSpread.getActiveSheet(), SpreadJsObj.DataType.Data, materialBillsData);
                 m_tp = data.m_tp;
+                if (materialTax) {
+                    m_tax_tp = data.m_tax_tp;
+                }
                 resetTpTable();
                 $('#remove-month').modal('hide');
             });

+ 2 - 0
app/public/js/material_list.js

@@ -622,6 +622,7 @@ $(document).ready(() => {
                         const xmjIndex = gclGatherData[index].leafXmjs.indexOf(xmjSelect);
                         loadMaterialData(index, xmjIndex);
                         SpreadJsObj.reLoadRowData(ledgerSpread.getActiveSheet(), index);
+                        materialSpread.getActiveSheet().setSelection(info.row + 1, info.col, 1, 1);
                     }, function () {
                         SpreadJsObj.reLoadRowData(info.sheet, info.row);
                     });
@@ -747,6 +748,7 @@ $(document).ready(() => {
                     const xmjIndex = gclGatherData[index].leafXmjs.indexOf(xmjSelect);
                     loadMaterialData(index, xmjIndex);
                     SpreadJsObj.reLoadRowData(ledgerSpread.getActiveSheet(), index);
+                    materialSpread.getActiveSheet().setSelection(info.cellRange.row, info.cellRange.col, info.cellRange.rowCount, info.cellRange.colCount);
                 }, function () {
                     SpreadJsObj.reLoadRowData(info.sheet, info.row);
                 });

+ 1 - 0
app/public/js/path_tree.js

@@ -1822,6 +1822,7 @@ const createNewPathTree = function (type, setting) {
                 delete x.grow_dgn_qty;
                 delete x.grow_tp;
             });
+            this.loadDatas(this.datas);
         }
         resortChildrenByCustom(fun) {
             for (const n of this.nodes) {

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

@@ -362,7 +362,11 @@ $(document).ready(() => {
                 const parent = tree.getParent(node);
                 const children = parent ? parent.children : tree.children;
                 const index = children.indexOf(node);
-                for (let i = 0; i < count; i++) {
+                if (index > 0 && children[index-1].used) {
+                    toastr.warning('其前节点已计量,选中的节点不可降级');
+                    return;
+                }
+                for (let i = index; i < count; i++) {
                     const child = children[i+index];
                     if (tree.checkNodeUsed(child, pos)) {
                         toastr.warning('选中的节点已计量,不可降级');

+ 4 - 3
app/public/js/shares/tenders2tree.js

@@ -53,7 +53,7 @@ const Tender2Tree = (function () {
         return cate;
     }
 
-    function loadCategoryTreeNode ( tender, levelCate) {
+    function loadCategoryTreeNode (category, tender, levelCate) {
         let tenderCategory = null;
         for (const [i, lc] of levelCate.entries()) {
             const tenderCate = findNode('cid', lc.id, tender.category);
@@ -73,7 +73,7 @@ const Tender2Tree = (function () {
         return tenderCategory;
     }
 
-    function convert (category, tenders, ledgerAuditConst, stageAuditConst) {
+    function convert (category, tenders, ledgerAuditConst, stageAuditConst, loadFun) {
         tenderTree.clearDatas();
 
         const levelCategory = category.filter(function (c) {
@@ -81,7 +81,7 @@ const Tender2Tree = (function () {
         });
 
         for (const t of tenders) {
-            const parent = (t.category && levelCategory.length > 0) ? loadCategoryTreeNode(t, levelCategory) : null;
+            const parent = (t.category && levelCategory.length > 0) ? loadCategoryTreeNode(category, t, levelCategory) : null;
             const node = {
                 tid: t.id,
                 name: t.name,
@@ -91,6 +91,7 @@ const Tender2Tree = (function () {
             if (ledgerAuditConst && stageAuditConst) {
                 node.status = t.lastStage ? stageAuditConst.statusString[t.lastStage.status] : ledgerAuditConst.statusString[t.ledger_status];
             }
+            if (loadFun) loadFun(node, t);
             tenderTree.addNode(node, parent);
         }
         tenderTree.sortTreeNode(true);

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

@@ -201,7 +201,7 @@ function calculateParent(node) {
         node.yf_tp = 0;
         node.end_yf_tp = 0;
         node.advance_tp = 0;
-        node.deal_tp = 0;
+        node.contract_price = 0;
         for (const c of node.children) {
             calculateParent(c);
             node.total_price = ZhCalc.add(node.total_price, c.total_price);
@@ -213,7 +213,7 @@ function calculateParent(node) {
             node.yf_tp = ZhCalc.add(node.yf_tp, c.yf_tp);
             node.end_yf_tp = ZhCalc.add(node.end_yf_tp, c.end_yf_tp);
             node.advance_tp = ZhCalc.add(node.advance_tp, c.advance_tp);
-            node.deal_tp = ZhCalc.add(node.deal_tp, c.deal_tp);
+            node.contract_price = ZhCalc.add(node.contract_price, c.contract_price);
         }
     }
 }
@@ -339,7 +339,7 @@ function recursiveGetTenderNodeHtml (node, arr, pid) {
     html.push('</td>');
     // 签约合同价
     html.push('<td style="width: 6%" class="text-right">');
-    html.push(node.deal_tp || '');
+    html.push(node.contract_price || '');
     html.push('</td>');
     // 0号台账合同
     html.push('<td style="width: 6%" class="text-right">');

+ 3 - 3
app/public/js/tender_list_progress.js

@@ -197,7 +197,7 @@ function calculateParent(node) {
         node.gather_tp = 0;
         node.sum_tp = 0;
         node.lastStage = 0;
-        node.deal_tp = 0;
+        node.contract_price = 0;
         for (const c of node.children) {
             calculateParent(c);
             node.end_qc_tp = ZhCalc.add(node.end_qc_tp, c.end_qc_tp);
@@ -207,7 +207,7 @@ function calculateParent(node) {
             node.lastStage = c.cid
                 ? Math.max(node.lastStage, c.lastStage)
                 : (c.lastStage ? Math.max(node.lastStage, c.lastStage.order) : node.lastStage);
-            node.deal_tp = ZhCalc.add(node.deal_tp, c.deal_tp);
+            node.contract_price = ZhCalc.add(node.contract_price, c.contract_price);
         }
     }
 }
@@ -343,7 +343,7 @@ function recursiveGetTenderNodeHtml (node, arr, pid) {
     html.push('</td>');
     // 签约合同价
     html.push('<td width="8%" class="text-right">');
-    html.push(node.deal_tp ? node.deal_tp : '');
+    html.push(node.contract_price ? node.contract_price : '');
     html.push('</td>');
     // 总价
     html.push('<td width="8%" class="text-right">');

+ 36 - 6
app/service/material.js

@@ -122,6 +122,7 @@ module.exports = app => {
                 user_id: this.ctx.session.sessionUser.accountId,
                 stage_id: data.stage_id.join(','),
                 s_order: data.s_order,
+                material_tax: this.ctx.session.sessionProject.page_show.openMaterialTax,
             };
             const transaction = await this.db.beginTransaction();
             try {
@@ -129,6 +130,7 @@ module.exports = app => {
                     newMaterial.rate = preMaterial.rate;
                     newMaterial.pre_tp = this.ctx.helper.add(preMaterial.m_tp, preMaterial.pre_tp);
                     newMaterial.ex_pre_tp = this.ctx.helper.add(preMaterial.ex_tp, preMaterial.ex_pre_tp);
+                    newMaterial.tax_pre_tp = this.ctx.helper.add(preMaterial.m_tax_tp, preMaterial.tax_pre_tp);
                 }
                 // 新增期记录
                 const result = await transaction.insert(this.tableName, newMaterial);
@@ -149,13 +151,14 @@ module.exports = app => {
                     // 复制调差清单工料关联表
                     await this.ctx.service.materialList.copyPreMaterialList(transaction, preMaterial, newMaterial);
                     // 修改本期应耗数量值和有效价差,需要剔除不参与调差的清单数据,并返回总金额
-                    const m_tp = await this.ctx.service.materialBills.updateNewMaterial(transaction, this.ctx.tender.id, newMaterial.id, this.ctx, newMaterial.stage_id);
+                    const [m_tp, m_tax_tp] = await this.ctx.service.materialBills.updateNewMaterial(transaction, this.ctx.tender.id, newMaterial.id, this.ctx, newMaterial.stage_id);
                     // 修改现行价格指数,并返回调差基数json
                     const ex_calc = await this.ctx.service.materialExponent.updateNewMaterial(transaction, newMaterial.id, this.ctx, newMaterial.stage_id, preMaterial.ex_calc);
                     // 计算得出本期总金额
                     const updateMaterialData = {
                         id: newMaterial.id,
                         m_tp,
+                        m_tax_tp,
                         ex_calc: JSON.stringify(ex_calc),
                     };
                     await transaction.update(this.tableName, updateMaterialData);
@@ -199,7 +202,8 @@ module.exports = app => {
                         'mb.`msg_spread` = mbh.`msg_spread`, mb.`m_up_risk` = mbh.`m_up_risk`, ' +
                         'mb.`m_down_risk` = mbh.`m_down_risk`, mb.`m_spread` = mbh.`m_spread`, ' +
                         'mb.`m_tp` = mbh.`m_tp`, mb.`pre_tp` = mbh.`pre_tp`, ' +
-                        'mb.`origin` = mbh.`origin`, mb.`is_summary` = mbh.`is_summary` ' +
+                        'mb.`m_tax_tp` = mbh.`m_tax_tp`, mb.`tax_pre_tp` = mbh.`tax_pre_tp`, ' +
+                        'mb.`origin` = mbh.`origin`, mb.`is_summary` = mbh.`is_summary`, mb.`m_tax` = mbh.`m_tax` ' +
                         'WHERE mbh.`tid` = ? AND mbh.`order` = ? AND mbh.`mb_id` = mb.`id`';
                     const sqlParam = [this.ctx.tender.id, materialInfo.order - 1];
                     await transaction.query(sql, sqlParam);
@@ -281,20 +285,33 @@ module.exports = app => {
         }
 
         /**
-         * 取当前期截止上期含税金额
+         * 取当前期截止上期含建筑税金额
          * @param {int} tid 标段id
          * @param {int} order 调差期数
          * @return {Promise<*>}
          */
         async getPreTpHs(tid, order) {
-            const sql = 'SELECT SUM(ROUND(`m_tp`*(1+ `rate`/100),2)) AS `pre_tp_hs` FROM ?? WHERE `tid` = ? AND `order` < ?';
-            const sqlParam = [this.tableName, tid, order];
+            const sql = 'SELECT SUM(ROUND(`m_tp`*(1+ `rate`/100),2)) AS `pre_tp_hs` FROM ?? WHERE `tid` = ? AND `material_tax` = ? AND `order` < ?';
+            const sqlParam = [this.tableName, tid, 0, order];
             const result = await this.db.queryOne(sql, sqlParam);
             return result.pre_tp_hs;
         }
 
         /**
-         * 取当前期截止上期含税指数金额
+         * 取当前期截止上期含材料税金额
+         * @param {int} tid 标段id
+         * @param {int} order 调差期数
+         * @return {Promise<*>}
+         */
+        async getTaxPreTpHs(tid, order) {
+            const sql = 'SELECT SUM(`m_tax_tp`) AS `tax_pre_tp_hs` FROM ?? WHERE `tid` = ? AND `material_tax` = ? AND `order` < ?';
+            const sqlParam = [this.tableName, tid, 1, order];
+            const result = await this.db.queryOne(sql, sqlParam);
+            return result.tax_pre_tp_hs;
+        }
+
+        /**
+         * 取当前期截止上期含建筑税指数金额
          * @param {int} tid 标段id
          * @param {int} order 调差期数
          * @return {Promise<*>}
@@ -305,6 +322,19 @@ module.exports = app => {
             const result = await this.db.queryOne(sql, sqlParam);
             return result.ex_pre_tp_hs;
         }
+
+        async updateMaterialTax(id, mtax) {
+            const updateData = {
+                id,
+                material_tax: mtax,
+            };
+            return await this.db.update(this.tableName, updateData);
+        }
+
+        async getMaterialTaxTp(id) {
+            const info = await this.getDataById(id);
+            return info.m_tax_tp;
+        }
     }
 
     return Material;

+ 3 - 0
app/service/material_audit.js

@@ -251,8 +251,11 @@ module.exports = app => {
                         m_spread: mb.m_spread,
                         m_tp: mb.m_tp,
                         pre_tp: mb.pre_tp,
+                        m_tax_tp: mb.m_tax_tp,
+                        tax_pre_tp: mb.tax_pre_tp,
                         origin: mb.origin,
                         is_summary: mb.is_summary,
+                        m_tax: mb.m_tax,
                     };
                     mbhList.push(newMbh);
                 }

+ 26 - 9
app/service/material_bills.js

@@ -225,12 +225,14 @@ module.exports = app => {
         async updateNewMaterial(transaction, tid, mid, ctx, stage_id) {
             const materialBillsData = await this.getAllDataByCondition({ where: { tid } });
             let m_tp = 0;
+            let m_tax_tp = 0;
             const materialCalculator = new MaterialCalculator(ctx, stage_id, ctx.tender.info);
             for (const mb of materialBillsData) {
-                const one_tp = await this.calcQuantityByMB(transaction, mid, mb, materialCalculator);
+                const [one_tp, one_tax_tp] = await this.calcQuantityByMB(transaction, mid, mb, materialCalculator);
                 m_tp = this.ctx.helper.add(m_tp, one_tp);
+                m_tax_tp = this.ctx.helper.add(m_tax_tp, one_tax_tp);
             }
-            return m_tp;
+            return [m_tp, m_tax_tp];
         }
 
         /**
@@ -248,21 +250,28 @@ module.exports = app => {
                 const mb_quantity = await transaction.queryOne(sql, sqlParam);
                 console.log(mb_quantity);
                 // 取历史期记录获取截止上期调差金额,并清空本期单价和时间,来源地,重新计算价差和有效价差
+                const newQuantity = this.ctx.helper.round(mb_quantity.quantity, 3);
+                const newTp = this.ctx.helper.round(this.ctx.helper.mul(newQuantity, newm_spread), 2);
                 const updateData = {
                     id: mb.id,
-                    quantity: this.ctx.helper.round(mb_quantity.quantity, 3),
+                    quantity: newQuantity,
                     msg_tp: null,
                     msg_times: null,
                     msg_spread: newmsg_spread,
                     m_spread: newm_spread,
                     origin: null,
-                    m_tp: this.ctx.helper.round(this.ctx.helper.mul(this.ctx.helper.round(mb_quantity.quantity, 3), newm_spread), 2),
+                    m_tp: newTp,
                     pre_tp: mb.m_tp !== null ? this.ctx.helper.round(this.ctx.helper.add(mb.pre_tp, mb.m_tp), 2) : mb.pre_tp,
+                    m_tax_tp: this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mb.m_tax, 100))), 2),
+                    m_tax_pre_tp: mb.m_tax_tp !== null ? this.ctx.helper.round(this.ctx.helper.add(mb.m_tax_pre_tp, mb.m_tax_tp), 2) : mb.m_tax_pre_tp,
                 };
                 await transaction.update(this.tableName, updateData);
-                return mb.is_summary === 1 ? await this.ctx.helper.round(this.ctx.helper.mul(mb_quantity.quantity, newm_spread), 2) : 0;
+                const m_tp = mb.is_summary === 1 ? await this.ctx.helper.round(this.ctx.helper.mul(mb_quantity.quantity, newm_spread), 2) : 0;
+                const m_tax_tp = this.ctx.helper.round(this.ctx.helper.mul(m_tp, (1 + this.ctx.helper.div(mb.m_tax, 100))), 2);
+                return [m_tp, m_tax_tp];
             } else if (mb.t_type === materialConst.t_type[1].value) {
                 const quantity = await materialCalculator.calculateExpr(mb.expr);
+                const newTp = quantity !== 0 && quantity !== null ? this.ctx.helper.round(this.ctx.helper.mul(this.ctx.helper.round(quantity, 3), newm_spread), 2) : null;
                 const updateData = {
                     id: mb.id,
                     quantity: quantity !== 0 && quantity !== null ? this.ctx.helper.round(quantity, 3) : null,
@@ -271,11 +280,15 @@ module.exports = app => {
                     msg_spread: newmsg_spread,
                     m_spread: newm_spread,
                     origin: null,
-                    m_tp: quantity !== 0 && quantity !== null ? this.ctx.helper.round(this.ctx.helper.mul(this.ctx.helper.round(quantity, 3), newm_spread), 2) : null,
+                    m_tp: newTp,
                     pre_tp: mb.m_tp !== null ? this.ctx.helper.round(this.ctx.helper.add(mb.pre_tp, mb.m_tp), 2) : mb.pre_tp,
+                    m_tax_tp: this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mb.m_tax, 100))), 2),
+                    m_tax_pre_tp: mb.m_tax_tp !== null ? this.ctx.helper.round(this.ctx.helper.add(mb.m_tax_pre_tp, mb.m_tax_tp), 2) : mb.m_tax_pre_tp,
                 };
                 await transaction.update(this.tableName, updateData);
-                return mb.is_summary === 1 ? await this.ctx.helper.round(this.ctx.helper.mul(quantity, newm_spread), 2) : 0;
+                const m_tp = mb.is_summary === 1 ? await this.ctx.helper.round(this.ctx.helper.mul(quantity, newm_spread), 2) : 0;
+                const m_tax_tp = this.ctx.helper.round(this.ctx.helper.mul(m_tp, (1 + this.ctx.helper.div(mb.m_tax, 100))), 2);
+                return [m_tp, m_tax_tp];
             }
         }
 
@@ -325,14 +338,18 @@ module.exports = app => {
         // 更改计算总金额并返回值
         async calcMaterialMTp(transaction) {
             // 金额发生变化,则重新计算本期金额
-            const sql = 'SELECT SUM(`m_tp`) as total_price FROM ' + this.tableName + ' WHERE `tid` = ? AND `is_summary` = 1';
+            const sql = 'SELECT SUM(`m_tp`) as total_price, SUM(IF(`m_tax_tp` is null, `m_tp`, `m_tax_tp`)) as tax_total_price FROM ' + this.tableName + ' WHERE `tid` = ? AND `is_summary` = 1';
             const sqlParam = [this.ctx.tender.id];
             const tp = await transaction.queryOne(sql, sqlParam);
-            console.log(tp);
             const updateData2 = {
                 id: this.ctx.material.id,
                 m_tp: tp.total_price,
+                m_tax_tp: tp.tax_total_price,
             };
+            console.log(tp);
+            // if (this.ctx.material.material_tax) {
+            //     updateData2.m_tax_tp = tp.tax_total_price;
+            // }
             await transaction.update(this.ctx.service.material.tableName, updateData2);
             return tp.total_price;
         }

+ 6 - 2
app/service/material_list.js

@@ -216,20 +216,24 @@ module.exports = app => {
             const sqlParam = [this.ctx.material.id, mb_id];
             const mb_quantity = await transaction.queryOne(sql, sqlParam);
             console.log(mb_quantity);
+            const newQuantity = this.ctx.helper.round(mb_quantity.quantity, 3);
+            const newTp = this.ctx.helper.round(this.ctx.helper.mul(newQuantity, mbInfo.m_spread), 2);
             const updateData = {
                 id: mb_id,
                 quantity: this.ctx.helper.round(mb_quantity.quantity, 3),
-                m_tp: this.ctx.helper.round(this.ctx.helper.mul(this.ctx.helper.round(mb_quantity.quantity, 3), mbInfo.m_spread), 2),
+                m_tp: newTp,
+                m_tax_tp: this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mbInfo.m_tax, 100))), 2),
             };
             await transaction.update(this.ctx.service.materialBills.tableName, updateData);
             // 计算本期总金额
-            const sql2 = 'SELECT SUM(`m_tp`) as total_price FROM ' + this.ctx.service.materialBills.tableName + ' WHERE `tid` = ? AND `is_summary` = 1';
+            const sql2 = 'SELECT SUM(`m_tp`) as total_price, SUM(IF(`m_tax_tp` is null, `m_tp`, `m_tax_tp`)) as tax_total_price FROM ' + this.ctx.service.materialBills.tableName + ' WHERE `tid` = ? AND `is_summary` = 1';
             const sqlParam2 = [this.ctx.tender.id];
             const tp = await transaction.queryOne(sql2, sqlParam2);
             console.log(tp);
             const updateData2 = {
                 id: this.ctx.material.id,
                 m_tp: tp.total_price,
+                m_tax_tp: tp.tax_total_price,
             };
             return await transaction.update(this.ctx.service.material.tableName, updateData2);
         }

+ 12 - 4
app/service/material_month.js

@@ -63,12 +63,14 @@ module.exports = app => {
                             const month_num = material_month.length - this.ctx.helper.arrayCount(this._.concat(this._.map(this._.filter(monthList, { mb_id: mb.id }), 'msg_tp'), one_month.msg_tp), [null, '', 0]);
                             const new_msg_tp = this.ctx.helper.round(this.ctx.helper.div(this.ctx.helper.add(mb_msg_tp_sum, one_month.msg_tp), month_num), 3);
                             const [newmsg_spread, newm_spread] = await this.ctx.service.materialBills.getSpread(mb, new_msg_tp);
+                            const newTp = this.ctx.helper.round(this.ctx.helper.mul(mb.quantity, newm_spread), 2);
                             updateArray.push({
                                 id: mb.id,
                                 msg_tp: new_msg_tp,
                                 msg_spread: newmsg_spread,
                                 m_spread: newm_spread,
-                                m_tp: this.ctx.helper.round(this.ctx.helper.mul(mb.quantity, newm_spread), 2),
+                                m_tp: newTp,
+                                m_tax_tp: this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mb.m_tax, 100))), 2),
                             });
                         }
                     }
@@ -111,12 +113,14 @@ module.exports = app => {
                         const month_num = material_month.length - this.ctx.helper.arrayCount(this._.map(this._.filter(monthList, { mb_id: mb.id }), 'msg_tp'), [null, '', 0]);
                         const new_msg_tp = month_num !== 0 ? this.ctx.helper.round(this.ctx.helper.div(mb_msg_tp_sum, month_num), 3) : null;
                         const [newmsg_spread, newm_spread] = await this.ctx.service.materialBills.getSpread(mb, new_msg_tp);
+                        const newTp = this.ctx.helper.round(this.ctx.helper.mul(mb.quantity, newm_spread), 2);
                         updateArray.push({
                             id: mb.id,
                             msg_tp: new_msg_tp,
                             msg_spread: newmsg_spread,
                             m_spread: newm_spread,
-                            m_tp: this.ctx.helper.round(this.ctx.helper.mul(mb.quantity, newm_spread), 2),
+                            m_tp: newTp,
+                            m_tax_tp: this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mb.m_tax, 100))), 2),
                         });
                     }
                     if (updateArray.length !== 0) await transaction.updateRows(this.ctx.service.materialBills.tableName, updateArray);
@@ -151,12 +155,14 @@ module.exports = app => {
                     const month_num = material_month.length - this.ctx.helper.arrayCount(this._.map(monthList, 'msg_tp'), [null, '', 0]);
                     const new_msg_tp = month_num !== 0 ? this.ctx.helper.round(this.ctx.helper.div(mb_msg_tp_sum, month_num), 3) : null;
                     const [newmsg_spread, newm_spread] = await this.ctx.service.materialBills.getSpread(mbInfo, new_msg_tp);
+                    const newTp = this.ctx.helper.round(this.ctx.helper.mul(mbInfo.quantity, newm_spread), 2);
                     await transaction.update(this.ctx.service.materialBills.tableName, {
                         id: mbInfo.id,
                         msg_tp: new_msg_tp,
                         msg_spread: newmsg_spread,
                         m_spread: newm_spread,
-                        m_tp: this.ctx.helper.round(this.ctx.helper.mul(mbInfo.quantity, newm_spread), 2),
+                        m_tp: newTp,
+                        m_tax_tp: this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mbInfo.m_tax, 100))), 2),
                     });
                 }
                 const m_tp = await this.ctx.service.materialBills.calcMaterialMTp(transaction);
@@ -203,12 +209,14 @@ module.exports = app => {
                         const month_num = material_month.length - this.ctx.helper.arrayCount(this._.map(this._.filter(monthList, { mb_id: mb.id }), 'msg_tp'), [null, '', 0]);
                         const new_msg_tp = month_num !== 0 ? this.ctx.helper.round(this.ctx.helper.div(mb_msg_tp_sum, month_num), 3) : null;
                         const [newmsg_spread, newm_spread] = await this.ctx.service.materialBills.getSpread(mb, new_msg_tp);
+                        const newTp = this.ctx.helper.round(this.ctx.helper.mul(mb.quantity, newm_spread), 2);
                         mbUpdateArray.push({
                             id: mb.id,
                             msg_tp: new_msg_tp,
                             msg_spread: newmsg_spread,
                             m_spread: newm_spread,
-                            m_tp: this.ctx.helper.round(this.ctx.helper.mul(mb.quantity, newm_spread), 2),
+                            m_tp: newTp,
+                            m_tax_tp: this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mb.m_tax, 100))), 2),
                         });
                     }
                     if (mbUpdateArray.length !== 0) await transaction.updateRows(this.ctx.service.materialBills.tableName, mbUpdateArray);

+ 9 - 0
app/service/project.js

@@ -184,6 +184,15 @@ module.exports = app => {
             await this.db.update(this.tableName, { id: id, sjs_rela: JSON.stringify(sjsRela) });
             return sjsField;
         }
+
+        async updatePageshow(id, data) {
+            this.ctx.session.sessionProject.page_show.openChangeRevise = data.openChangeRevise ? 1 : 0;
+            this.ctx.session.sessionProject.page_show.openMaterialTax = data.openMaterialTax ? 1 : 0;
+            const result = await this.db.update(this.tableName, {
+                id, page_show: JSON.stringify(this.ctx.session.sessionProject.page_show),
+            });
+            return result.affectedRows === 1;
+        }
     }
 
     return Project;

+ 6 - 0
app/service/report_memory.js

@@ -845,6 +845,12 @@ module.exports = app => {
                 await this.ctx.service.stage.checkStage(sid);
 
                 const data = await this.ctx.service.stageBonus.getEndStageData(this.ctx.stage.order);
+                for (const d of data) {
+                    const names = this.ctx.helper._.map(d.proof_file, function (x) {
+                        return x.filename + x.fileext;
+                    });
+                    d.proof = names.join('\n');
+                }
                 return data;
             } catch (err) {
                 return [];

+ 1 - 1
app/service/stage_detail_att.js

@@ -133,7 +133,7 @@ module.exports = app => {
             // if (fs.existsSync(path.join(this.ctx.app.baseDir, att.filepath))) {
             //     await fs.unlinkSync(path.join(this.ctx.app.baseDir, att.filepath));
             // }
-            await this.ctx.app.fujianOss.delete(att.filepath);
+            await this.ctx.app.fujianOss.delete(ctx.app.config.fujianOssFolder + att.filepath);
 
 
             await this._complete4Output(detailAtt);

+ 2 - 2
app/service/stage_shoufang.js

@@ -42,7 +42,7 @@ module.exports = app => {
                 const qr_png = await qr.image(text || '', { type: 'png', size: size || 5, margin: margin || 1 });
                 const qrcodePath = 'app/public/upload/' + this.ctx.tender.id + '/stage/shoufang/qrcode/' + result.insertId + '.png';
                 // await this.ctx.helper.saveStreamFile(qr_png, path.resolve(this.app.baseDir, 'app/' + qrcodePath));
-                await this.ctx.app.fujianOss.put(qrcodePath, qr_png);
+                await this.ctx.app.fujianOss.put(ctx.app.config.fujianOssFolder + qrcodePath, qr_png);
                 await transaction.update(this.tableName, { id: result.insertId, qrcode: qrcodePath });
                 await transaction.commit();
                 return result;
@@ -72,7 +72,7 @@ module.exports = app => {
                 // if (fs.existsSync(path.join(this.app.baseDir, 'app/' + sfInfo.qrcode))) {
                 //     await fs.unlinkSync(path.join(this.app.baseDir, 'app/' + sfInfo.qrcode));
                 // }
-                await this.ctx.app.fujianOss.delete(sfInfo.qrcode);
+                await this.ctx.app.fujianOss.delete(ctx.app.config.fujianOssFolder + sfInfo.qrcode);
                 await transaction.delete(this.ctx.service.stageShoufangAtt.tableName, { sfid });
                 await transaction.delete(this.tableName, { id: sfid });
                 await transaction.commit();

+ 5 - 1
app/view/budget/compare.ejs

@@ -33,4 +33,8 @@
             </div>
         </div>
     </div>
-</div>
+</div>
+<script>
+    const category = JSON.parse(unescape('<%- escape(JSON.stringify(categoryData)) %>'));
+    const tenderList = JSON.parse(unescape('<%- escape(JSON.stringify(tenderList)) %>'));
+</script>

+ 2 - 18
app/view/budget/compare_modal.ejs

@@ -4,25 +4,9 @@
             <div class="modal-header">
                 <h5 class="modal-title">选择决算标段</h5>
             </div>
-            <div class="modal-body" style="display: block; overflow: auto; height: 500px">
+            <div class="modal-body">
                 <h5>可选标段</h5>
-                <table class="table table-sm table-bordered">
-                    <thead>
-                    <tr class="text-center">
-                        <th>选择</th>
-                        <th>标段名称</th>
-                        <th>期数</th>
-                        <th>状态</th>
-                    </tr>
-                    </thead>
-                    <tbody>
-                    <% for (const t of tenderList) { %>
-                    <tr>
-                        <td class="text-center"><input type="checkbox" name="sf-tender" tid="<%- t.id %>"><td><%- t.name %></td><td>第<%- t.lastStage.order %>期</td><td><%- auditConst.stage.statusString[t.lastStage.status] %></td>
-                    </tr>
-                    <% } %>
-                    </tbody>
-                </table>
+                <div id="sf-spread" style="height: 300px"></div>
             </div>
             <div class="modal-footer">
                 <div class="form-check form-check-inline">

+ 4 - 1
app/view/budget/list.ejs

@@ -44,4 +44,7 @@
             </div>
         </div>
     </div>
-</div>
+</div>
+<script>
+    const category = JSON.parse(unescape('<%- escape(JSON.stringify(categoryData)) %>'));
+</script>

+ 3 - 10
app/view/budget/list_modal.ejs

@@ -77,16 +77,9 @@
             <div class="modal-header">
                 <h5 class="modal-title">选择决算标段</h5>
             </div>
-            <div class="modal-body" style="display: block; overflow: auto; height: 500px">
+            <div class="modal-body">
                 <h5>可选标段</h5>
-                <table class="table table-sm table-bordered">
-                    <tr class="text-center"><th>选择</th><th>标段名称</th><th>期数</th><th>状态</th></tr>
-                    <tbody id="valid-rela-tender">
-                    <% for (const t of tenderList) { %>
-                    <tr><td class="text-center"><input type="checkbox" name="select-rela-check" tid="<%- t.id %>"></td><td><%- t.name %></td><td>第<%- t.lastStage.order %>期</td><td><%- auditConst.stage.statusString[t.lastStage.status] %></td></tr>
-                    <% } %>
-                    </tbody>
-                </table>
+                <div id="sr-spread" style="height: 300px"></div>
             </div>
             <div class="modal-footer">
                 <div class="form-check form-check-inline">
@@ -94,7 +87,7 @@
                     <label class="form-check-label" for="sr-select-all">全选</label>
                 </div>
                 <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">取消</button>
-                <button type="button" class="btn btn-sm btn-primary" onclick="relaTender();">确定</button>
+                <button type="button" class="btn btn-sm btn-primary" id="select-rela-ok">确定</button>
             </div>
         </div>
     </div>

+ 54 - 22
app/view/material/exponent.ejs

@@ -49,29 +49,61 @@
                             </select>
                         </div>
                     </div>
-                    <div class="sp-wrap" style="max-width: 800px;min-width: 500px;">
-                        <div class="col-12 p-0">
-                            <table class="table table-sm table-bordered">
-                                <tr><th rowspan="2"></th><th colspan="2" class="text-center">信息价</th><th colspan="2" class="text-center">价格指数</th></tr>
-                                <tr class="text-center"><th>本期金额</th><th>截止本期金额</th>
-                                    <th>本期金额
-                                        <a href="javascript:void(0);" id="ex_expr" data-toggle="tooltip" data-placement="bottom" title="本期价差:<%- material.ex_expr ? material.ex_expr : '' %>"><i class="fa fa-question-circle-o"></i></a></th>
-                                    <th>截止本期金额</th></tr>
-                                <tr id="tp_set"><td>材料价差费用</td>
-                                    <td class="text-center"><%= material.m_tp !== null ? ctx.helper.round(material.m_tp, 2) : null %></td>
-                                    <td class="text-center"><%= material.m_tp !== null || material.pre_tp !== null ? ctx.helper.round(ctx.helper.add(material.pre_tp, material.m_tp), 2) : null %></td>
-                                    <td class="text-center"><%= material.ex_tp !== null ? ctx.helper.round(material.ex_tp, 2) : null %></td>
-                                    <td class="text-center"><%= material.ex_tp !== null || material.ex_pre_tp !== null ? ctx.helper.round(ctx.helper.add(material.ex_pre_tp, material.ex_tp), 2) : null %></td>
-                                </tr>
-                                <tr id="rate_set"><td>材料价差费用(含税)</td>
-                                    <td class="text-center"><%= material.m_tp !== null ? ctx.helper.round(ctx.helper.mul(material.m_tp, 1+material.rate/100), 2) : null %></td>
-                                    <td class="text-center"><%= material.m_tp !== null || pre_tp_hs !== null ? ctx.helper.round(ctx.helper.add(pre_tp_hs, ctx.helper.round(ctx.helper.mul(material.m_tp, 1+material.rate/100), 2)), 2) : null %></td>
-                                    <td class="text-center"><%= material.ex_tp !== null ? ctx.helper.round(ctx.helper.mul(material.ex_tp, 1+material.rate/100), 2) : null %></td>
-                                    <td class="text-center"><%= material.ex_tp !== null || ex_pre_tp_hs !== null ? ctx.helper.round(ctx.helper.add(ex_pre_tp_hs, ctx.helper.round(ctx.helper.mul(material.ex_tp, 1+material.rate/100), 2)), 2) : null %></td>
-                                </tr>
-                            </table>
+                    <% if (!material.material_tax) { %>
+                        <div class="sp-wrap" style="max-width: 800px;min-width: 500px;">
+                            <div class="col-12 p-0">
+                                <table class="table table-sm table-bordered">
+                                    <tr><th rowspan="2"></th><th colspan="2" class="text-center">信息价</th><th colspan="2" class="text-center">价格指数</th></tr>
+                                    <tr class="text-center"><th>本期金额</th><th>截止本期金额</th>
+                                        <th>本期金额
+                                            <a href="javascript:void(0);" id="ex_expr" data-toggle="tooltip" data-placement="bottom" title="本期价差:<%- material.ex_expr ? material.ex_expr : '' %>"><i class="fa fa-question-circle-o"></i></a></th>
+                                        <th>截止本期金额</th></tr>
+                                    <tr id="tp_set"><td>材料价差费用</td>
+                                        <td class="text-center"><%= material.m_tp !== null ? ctx.helper.round(material.m_tp, 2) : null %></td>
+                                        <td class="text-center"><%= material.m_tp !== null || material.pre_tp !== null ? ctx.helper.round(ctx.helper.add(material.pre_tp, material.m_tp), 2) : null %></td>
+                                        <td class="text-center"><%= material.ex_tp !== null ? ctx.helper.round(material.ex_tp, 2) : null %></td>
+                                        <td class="text-center"><%= material.ex_tp !== null || material.ex_pre_tp !== null ? ctx.helper.round(ctx.helper.add(material.ex_pre_tp, material.ex_tp), 2) : null %></td>
+                                    </tr>
+                                    <tr id="rate_set"><td>材料价差费用(含建筑税)</td>
+                                        <td class="text-center"><%= material.m_tp !== null ? ctx.helper.round(ctx.helper.mul(material.m_tp, 1+material.rate/100), 2) : null %></td>
+                                        <td class="text-center"><%= material.m_tp !== null || pre_tp_hs !== null ? ctx.helper.round(ctx.helper.add(pre_tp_hs, ctx.helper.round(ctx.helper.mul(material.m_tp, 1+material.rate/100), 2)), 2) : null %></td>
+                                        <td class="text-center"><%= material.ex_tp !== null ? ctx.helper.round(ctx.helper.mul(material.ex_tp, 1+material.rate/100), 2) : null %></td>
+                                        <td class="text-center"><%= material.ex_tp !== null || ex_pre_tp_hs !== null ? ctx.helper.round(ctx.helper.add(ex_pre_tp_hs, ctx.helper.round(ctx.helper.mul(material.ex_tp, 1+material.rate/100), 2)), 2) : null %></td>
+                                    </tr>
+                                </table>
+                            </div>
                         </div>
-                    </div>
+                    <% } else { %>
+                        <div class="sp-wrap" style="max-width: 800px;min-width: 500px;">
+                            <div class="col-12 p-0">
+                                <table class="table table-sm table-bordered">
+                                    <tr><th rowspan="2"></th><th colspan="2" class="text-center">信息价</th><th colspan="2" class="text-center">价格指数</th></tr>
+                                    <tr class="text-center"><th>本期金额</th><th>截止本期金额</th>
+                                        <th>本期金额
+                                            <a href="javascript:void(0);" id="ex_expr" data-toggle="tooltip" data-placement="bottom" title="本期价差:<%- material.ex_expr ? material.ex_expr : '' %>"><i class="fa fa-question-circle-o"></i></a></th>
+                                        <th>截止本期金额</th></tr>
+                                    <tr id="tp_set"><td>材料价差费用</td>
+                                        <td class="text-center"><%= material.m_tp !== null ? ctx.helper.round(material.m_tp, 2) : null %></td>
+                                        <td class="text-center"><%= material.m_tp !== null || material.pre_tp !== null ? ctx.helper.round(ctx.helper.add(material.pre_tp, material.m_tp), 2) : null %></td>
+                                        <td class="text-center"><%= material.ex_tp !== null ? ctx.helper.round(material.ex_tp, 2) : null %></td>
+                                        <td class="text-center"><%= material.ex_tp !== null || material.ex_pre_tp !== null ? ctx.helper.round(ctx.helper.add(material.ex_pre_tp, material.ex_tp), 2) : null %></td>
+                                    </tr>
+                                    <tr id="rate_set"><td>材料价差费用(含材料税)</td>
+                                        <td class="text-center"><%= material.m_tax_tp !== null ? material.m_tax_tp : null %></td>
+                                        <td class="text-center"><%= material.m_tax_tp !== null || material.tax_pre_tp !== null ? ctx.helper.round(ctx.helper.add(material.tax_pre_tp, material.m_tax_tp), 2) : null %></td>
+                                        <td class="text-center">-</td>
+                                        <td class="text-center">-</td>
+                                    </tr>
+                                    <tr id="rate_set"><td>材料价差费用(含建筑税)</td>
+                                        <td class="text-center">-</td>
+                                        <td class="text-center"><%= pre_tp_hs !== null ? pre_tp_hs : '-' %></td>
+                                        <td class="text-center"><%= material.ex_tp !== null ? ctx.helper.round(ctx.helper.mul(material.ex_tp, 1+material.rate/100), 2) : null %></td>
+                                        <td class="text-center"><%= material.ex_tp !== null || ex_pre_tp_hs !== null ? ctx.helper.round(ctx.helper.add(ex_pre_tp_hs, ctx.helper.round(ctx.helper.mul(material.ex_tp, 1+material.rate/100), 2)), 2) : null %></td>
+                                    </tr>
+                                </table>
+                            </div>
+                        </div>
+                    <% } %>
                 </div>
             </div>
             <div id="right-view" class="c-body" style="display:none;width: 33%">

+ 11 - 7
app/view/material/index.ejs

@@ -23,19 +23,21 @@
                         <th rowspan="2">期数</th>
                         <th class="text-center" rowspan="2">添加时间</th>
                         <th class="text-center" rowspan="2">计量期</th>
-                        <th class="text-center" colspan="2">信息价调差</th>
+                        <th class="text-center" colspan="<% if (openMaterialTax && !allMaterialTax) { %>3<% } else { %>2<% } %>">信息价调差</th>
                         <th class="text-center" colspan="2">指数法调差</th>
-                        <th class="text-center" colspan="2">合计</th>
+                        <th class="text-center" colspan="<% if (openMaterialTax) { %>3<% } else { %>2<% } %>">合计</th>
                         <th class="text-center" rowspan="2">审批进度</th>
                         <th class="text-center" rowspan="2" width="140">操作</th>
                     </tr>
                     <tr>
                         <th class="text-center">价差费用</th>
-                        <th class="text-center">价差费用(含税)</th>
+                        <% if (openMaterialTax) { %><th class="text-center">价差费用(含材料税)</th><% } %>
+                        <% if ((openMaterialTax && !allMaterialTax) || !openMaterialTax) { %><th class="text-center">价差费用(含建筑税)</th><% } %>
                         <th class="text-center">价差费用</th>
-                        <th class="text-center">价差费用(含税)</th>
+                        <th class="text-center">价差费用(含建筑税)</th>
                         <th class="text-center">价差费用</th>
-                        <th class="text-center">价差费用(含税)</th>
+                        <% if (openMaterialTax) { %><th class="text-center">价差费用(含材料税)</th><% } %>
+                        <th class="text-center">价差费用(含建筑税)</th>
                     </tr>
                     </thead>
                     <tbody>
@@ -47,11 +49,13 @@
                             <td class="text-center"><%= moment(m.in_time).format('YYYY-MM-DD') %></td>
                             <td class="text-center">第 <%= m.s_order %> 期</td>
                             <td class="text-right"><%= m.m_tp !== null ? ctx.helper.round(m.m_tp, 2) : null %></td>
-                            <td class="text-right"><%= m.m_tp !== null ? ctx.helper.round(ctx.helper.mul(m.m_tp, 1+m.rate/100), 2) : null %></td>
+                            <% if (openMaterialTax) { %><td class="text-right"><% if (m.material_tax) { %><% if (m.m_tax_tp) { %><%- m.m_tax_tp %><% } else { %><%- m.m_tp %><% } %><% } %></td><% } %>
+                            <% if ((openMaterialTax && !allMaterialTax) || !openMaterialTax) { %><td class="text-right"><% if (!m.material_tax) { %><%= m.m_tp !== null ? ctx.helper.round(ctx.helper.mul(m.m_tp, 1+m.rate/100), 2) : null %><% } %></td><% } %>
                             <td class="text-right"><%= m.ex_tp !== null ? ctx.helper.round(m.ex_tp, 2) : null %></td>
                             <td class="text-right"><%= m.ex_tp !== null ? ctx.helper.round(ctx.helper.mul(m.ex_tp, 1+m.rate/100), 2) : null %></td>
                             <td class="text-right"><%= ctx.helper.add(ctx.helper.round(m.ex_tp, 2), ctx.helper.round(m.m_tp, 2)) %></td>
-                            <td class="text-right"><%= ctx.helper.add(ctx.helper.round(ctx.helper.mul(m.ex_tp, 1+m.rate/100), 2), ctx.helper.round(ctx.helper.mul(m.m_tp, 1+m.rate/100), 2)) %></td>
+                            <% if (openMaterialTax) { %><td class="text-right"><% if (m.material_tax) { %><% if (m.m_tax_tp) { %><%- m.m_tax_tp %><% } else { %><%- m.m_tp %><% } %><% } %></td><% } %>
+                            <td class="text-right"><% if (m.material_tax) { %><%= m.ex_tp !== null ? ctx.helper.round(ctx.helper.mul(m.ex_tp, 1+m.rate/100), 2) : null %><% } else { %><%= ctx.helper.add(ctx.helper.round(ctx.helper.mul(m.ex_tp, 1+m.rate/100), 2), ctx.helper.round(ctx.helper.mul(m.m_tp, 1+m.rate/100), 2)) %><% } %></td>
                             <td class="<%- auditConst.auditProgressClass[m.status] %>">
                                 <% if (m.curAuditor) { %>
                                     <a href="#sp-list" data-toggle="modal" data-target="#sp-list" m-order="<%- m.order %>"><%- m.curAuditor.name %><%if (m.curAuditor.role !== '' && m.curAuditor.role !== null) { %>-<%- m.curAuditor.role %><% } %></a>

+ 39 - 3
app/view/material/info.ejs

@@ -37,12 +37,13 @@
                 <!--下部分-->
                 <div class="bcontent-wrap" id="main-bottom">
                     <div id="main-resize" class="resize-y" r-Type="height" div1=".sjs-height-1" div2=".bcontent-wrap" title="调整大小"><!--调整上下高度条--></div>
+
                     <div class="bc-bar mb-1">
                         <div class="input-group input-group-sm ">
                             <div class="input-group-prepend">
-                                <span class="input-group-text" id="basic-addon1">增值税税率</span>
+                                <span class="input-group-text" id="basic-addon1">建筑增值税</span>
                             </div>
-                            <select class="form-control form-control-sm col-1" id="changeRate">
+                            <select class="form-control form-control-sm col-1" id="changeRate" <% if (material.material_tax) { %>disabled<% } %>>
                                 <% if (!material.readOnly) { %>
                                     <option value="9" <% if(material.rate === 9) { %>selected<% } %>>9%</option>
                                     <option value="10" <% if(material.rate === 10) { %>selected<% } %>>10%</option>
@@ -53,6 +54,7 @@
                             </select>
                         </div>
                     </div>
+                    <% if (!material.material_tax) { %>
                     <div class="sp-wrap" style="max-width: 800px;min-width: 500px;">
                         <div class="col-12 p-0">
                             <table class="table table-sm table-bordered">
@@ -67,7 +69,7 @@
                                     <td class="text-center"><%= material.ex_tp !== null ? ctx.helper.round(material.ex_tp, 2) : null %></td>
                                     <td class="text-center"><%= material.ex_tp !== null || material.ex_pre_tp !== null ? ctx.helper.round(ctx.helper.add(material.ex_pre_tp, material.ex_tp), 2) : null %></td>
                                 </tr>
-                                <tr id="rate_set"><td>材料价差费用(含税)</td>
+                                <tr id="rate_set"><td>材料价差费用(含建筑税)</td>
                                     <td class="text-center"><%= material.m_tp !== null ? ctx.helper.round(ctx.helper.mul(material.m_tp, 1+material.rate/100), 2) : null %></td>
                                     <td class="text-center"><%= material.m_tp !== null || pre_tp_hs !== null ? ctx.helper.round(ctx.helper.add(pre_tp_hs, ctx.helper.round(ctx.helper.mul(material.m_tp, 1+material.rate/100), 2)), 2) : null %></td>
                                     <td class="text-center"><%= material.ex_tp !== null ? ctx.helper.round(ctx.helper.mul(material.ex_tp, 1+material.rate/100), 2) : null %></td>
@@ -76,6 +78,37 @@
                             </table>
                         </div>
                     </div>
+                    <% } else { %>
+                    <div class="sp-wrap" style="max-width: 800px;min-width: 500px;">
+                        <div class="col-12 p-0">
+                            <table class="table table-sm table-bordered">
+                                <tr><th rowspan="2"></th><th colspan="2" class="text-center">信息价</th><th colspan="2" class="text-center">价格指数</th></tr>
+                                <tr class="text-center"><th>本期金额</th><th>截止本期金额</th>
+                                    <th>本期金额
+                                        <a href="javascript:void(0);" id="ex_expr" data-toggle="tooltip" data-placement="bottom" title="本期价差:<%- material.ex_expr ? material.ex_expr : '' %>"><i class="fa fa-question-circle-o"></i></a></th>
+                                    <th>截止本期金额</th></tr>
+                                <tr id="tp_set"><td>材料价差费用</td>
+                                    <td class="text-center"><%= material.m_tp !== null ? ctx.helper.round(material.m_tp, 2) : null %></td>
+                                    <td class="text-center"><%= material.m_tp !== null || material.pre_tp !== null ? ctx.helper.round(ctx.helper.add(material.pre_tp, material.m_tp), 2) : null %></td>
+                                    <td class="text-center"><%= material.ex_tp !== null ? ctx.helper.round(material.ex_tp, 2) : null %></td>
+                                    <td class="text-center"><%= material.ex_tp !== null || material.ex_pre_tp !== null ? ctx.helper.round(ctx.helper.add(material.ex_pre_tp, material.ex_tp), 2) : null %></td>
+                                </tr>
+                                <tr id="rate_set"><td>材料价差费用(含材料税)</td>
+                                    <td class="text-center"><%= material.m_tax_tp !== null ? material.m_tax_tp : null %></td>
+                                    <td class="text-center"><%= material.m_tax_tp !== null || material.tax_pre_tp !== null ? ctx.helper.round(ctx.helper.add(material.tax_pre_tp, material.m_tax_tp), 2) : null %></td>
+                                    <td class="text-center">-</td>
+                                    <td class="text-center">-</td>
+                                </tr>
+                                <tr><td>材料价差费用(含建筑税)</td>
+                                    <td class="text-center">-</td>
+                                    <td class="text-center"><%= pre_tp_hs !== null ? pre_tp_hs : '-' %></td>
+                                    <td class="text-center"><%= material.ex_tp !== null ? ctx.helper.round(ctx.helper.mul(material.ex_tp, 1+material.rate/100), 2) : null %></td>
+                                    <td class="text-center"><%= material.ex_tp !== null || ex_pre_tp_hs !== null ? ctx.helper.round(ctx.helper.add(ex_pre_tp_hs, ctx.helper.round(ctx.helper.mul(material.ex_tp, 1+material.rate/100), 2)), 2) : null %></td>
+                                </tr>
+                            </table>
+                        </div>
+                    </div>
+                    <% } %>
                 </div>
             </div>
             <div id="right-view" class="c-body" style="display:none;width: 33%">
@@ -119,12 +152,15 @@
     const materialListData = JSON.parse('<%- JSON.stringify(materialListData) %>');
     const readOnly = <%- material.readOnly %>;
     const materialID = <%- material.id %>;
+    const materialTax = <%- material.material_tax %>;
     let m_tp = <%= material.m_tp !== null ? material.m_tp : 0 %>;
     let ex_tp = <%= material.ex_tp !== null ? material.ex_tp : 0 %>;
     const pre_tp = <%= material.pre_tp !== null ? material.pre_tp : 0 %>;
     const ex_pre_tp = <%= material.ex_pre_tp !== null ? material.ex_pre_tp : 0 %>;
     const pre_tp_hs = <%= pre_tp_hs !== null ? pre_tp_hs : 0 %>;
     const ex_pre_tp_hs = <%= ex_pre_tp_hs !== null ? ex_pre_tp_hs : 0 %>;
+    let m_tax_tp = <%= material.m_tax_tp !== null ? material.m_tax_tp : 0 %>;
+    const m_tax_pre_tp = <%= material.m_tax_pre_tp !== null ? material.m_tax_pre_tp : 0 %>;
     const calcBase = JSON.parse('<%- JSON.stringify(calcBase) %>');
     const months = JSON.parse('<%- JSON.stringify(months) %>');
     let monthsList = JSON.parse('<%- JSON.stringify(monthsList) %>');

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

@@ -50,7 +50,7 @@
                         <td class="text-center"><%- s.s_time %></td>
                         <td class="text-center">
                             <span data-toggle="tooltip" data-placement="bottom" data-original-title="<%- (s.period ? s.period : '') %>">
-                                <%- (s.period ? s.period.split('~')[1] : '') %>
+                                <%- (s.period ? (s.period.split('~')[1] ? s.period.split('~')[1] : s.period)  : '') %>
                             </span>
                         </td>
                         <% if (ctx.tender.info.display.thousandth) { %>

+ 30 - 0
app/view/setting/fun.ejs

@@ -45,6 +45,34 @@
                                 </div>
                             </div>
                         </div>
+                        <div class="row">
+                            <div class="col-6">
+                                <div class="card mb-3">
+                                    <div class="card-body">
+                                        <h5 class="card-title">工程变更</h5>
+                                        <div class="form-group">
+                                            <div class="form-check form-check-inline">
+                                                <input class="form-check-input" type="checkbox" id="openChangeRevise" <% if(ctx.session.sessionProject.page_show.openChangeRevise) { %>checked<% } %> onchange="updateSetting();">
+                                                <label class="form-check-label" for="openChangeRevise">新增部位</label>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div>
+                            </div>
+                            <div class="col-6">
+                                <div class="card mb-3">
+                                    <div class="card-body">
+                                        <h5 class="card-title">材料调差</h5>
+                                        <div class="form-group mb-1">
+                                            <div class="form-check form-check-inline">
+                                                <input class="form-check-input" type="checkbox" id="openMaterialTax" <% if(ctx.session.sessionProject.page_show.openMaterialTax) { %>checked<% } %> onchange="updateSetting();">
+                                                <label class="form-check-label" for="openMaterialTax">使用材料税</label>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div>
+                            </div>
+                        </div>
                         <div class="card mb-3">
                             <div class="card-body">
                                 <h5 class="card-title">概算控制</h5>
@@ -78,6 +106,8 @@
             banOver: $('[name=ban_over]')[0].checked,
             hintOver: $('#hint_over')[0].checked,
             needGcl: $('#need_gcl')[0].checked,
+            openChangeRevise: $('#openChangeRevise')[0].checked,
+            openMaterialTax: $('#openMaterialTax')[0].checked,
         });
     }
 </script>

+ 4 - 3
config/config.default.js

@@ -214,14 +214,15 @@ module.exports = appInfo => {
         default: {
             accessKeyId: 'LTAIALMjBHOs9PLA',
             accessKeySecret: 'HSnULQs87wAJhcziAdyRv3GZ4EYctc',
-            endpoint: 'oss-cn-shenzhen.aliyuncs.com',
+            endpoint: 'oss-cn-shenzhen-internal.aliyuncs.com',
             timeout: '60s',
         },
     };
 
-    config.fujianOssPath = 'https://jiliang-saas.smartcost.com.cn/';
+    config.fujianOssPath = 'https://jiliang-saas-oss.smartcost.com.cn/';
+    config.fujianOssFolder = '';
 
-    config.syncUrl = 'https://sync.jl.smartcost.com.cn/';
+    config.syncUrl = 'http://sync.jl.smartcost.com.cn/';
 
     return config;
 };

+ 2 - 1
config/config.local.js

@@ -108,7 +108,8 @@ module.exports = appInfo => {
         },
     };
 
-    config.fujianOssPath = 'https://jiliang-qa.smartcost.com.cn/';
+    config.fujianOssPath = 'https://jiliang-qa-oss.smartcost.com.cn/qa/';
+    config.fujianOssFolder = 'qa/';
 
     // 自带接口系统地址
     config.syncUrl = 'http://127.0.0.1:7169/';

+ 2 - 1
config/config.qa.js

@@ -70,7 +70,8 @@ module.exports = appInfo => {
         },
     };
 
-    config.fujianOssPath = 'https://jiliang-qa.smartcost.com.cn/';
+    config.fujianOssPath = 'https://jiliang-qa-oss.smartcost.com.cn/qa/';
+    config.fujianOssFolder = 'qa/';
 
     // 自带接口系统地址
     config.syncUrl = 'http://jlqa.smartcost.com.cn:7169/';

+ 2 - 1
config/config.remoteqa.js

@@ -101,7 +101,8 @@ module.exports = appInfo => {
         },
     };
 
-    config.fujianOssPath = 'https://jiliang-qa.smartcost.com.cn/';
+    config.fujianOssPath = 'https://jiliang-qa-oss.smartcost.com.cn/qa/';
+    config.fujianOssFolder = 'qa/';
 
     config.is_debug = true;
 

+ 2 - 1
config/config.remoteuat.js

@@ -71,7 +71,8 @@ module.exports = appInfo => {
         },
     };
 
-    config.fujianOssPath = 'https://jiliang-qa.smartcost.com.cn/';
+    config.fujianOssPath = 'https://jiliang-qa-oss.smartcost.com.cn/uat/';
+    config.fujianOssFolder = 'uat/';
 
     return config;
 };

+ 3 - 2
config/config.uat.js

@@ -71,12 +71,13 @@ module.exports = appInfo => {
         default: {
             accessKeyId: 'LTAIALMjBHOs9PLA',
             accessKeySecret: 'HSnULQs87wAJhcziAdyRv3GZ4EYctc',
-            endpoint: 'oss-cn-shenzhen.aliyuncs.com',
+            endpoint: 'oss-cn-shenzhen-internal.aliyuncs.com',
             timeout: '60s',
         },
     };
 
-    config.fujianOssPath = 'https://jiliang-qa.smartcost.com.cn/';
+    config.fujianOssPath = 'https://jiliang-qa-oss.smartcost.com.cn/uat/';
+    config.fujianOssFolder = 'uat/';
 
     config.syncUrl = 'http://sync.jluat.smartcost.com.cn/';
 

+ 8 - 1
config/web.js

@@ -891,8 +891,14 @@ const JsFiles = {
         },
         budget: {
             list: {
-                files: ['/public/js/moment/moment.min.js'],
+                files: [
+                    '/public/js/moment/moment.min.js',
+                    '/public/js/spreadjs/sheets/v11/gc.spread.sheets.all.11.2.2.min.js',
+                ],
                 mergeFiles: [
+                    '/public/js/path_tree.js',
+                    '/public/js/shares/tenders2tree.js',
+                    '/public/js/spreadjs_rela/spreadjs_zh.js',
                     '/public/js/budget_list.js',
                 ],
                 mergeFile: 'budget_list',
@@ -910,6 +916,7 @@ const JsFiles = {
                     '/public/js/shares/sjs_setting.js',
                     '/public/js/zh_calc.js',
                     '/public/js/path_tree.js',
+                    '/public/js/shares/tenders2tree.js',
                     '/public/js/budget_compare.js',
                 ],
                 mergeFile: 'budget_compare.js'

+ 9 - 1
sql/update.sql

@@ -1,3 +1,11 @@
+-- 附件文件地址更新
 UPDATE `zh_advance_file` SET `filepath` = CONCAT('app/',`filepath`);
-
 UPDATE `zh_material_file` SET `filepath` = CONCAT('app/',`filepath`);
+-- 调差材料税计算
+ALTER TABLE `zh_material` ADD `material_tax` TINYINT NOT NULL DEFAULT '0' COMMENT '是否已使用材料税,默认为0' AFTER `rate`;
+ALTER TABLE `zh_material` ADD `m_tax_tp` DECIMAL(30,8) NULL DEFAULT NULL COMMENT '材料含税金额' AFTER `material_tax`;
+ALTER TABLE `zh_material` ADD `m_tax_pre_tp` DECIMAL(30,8) NULL DEFAULT NULL COMMENT '截止上期材料含税金额' AFTER `m_tax_tp`;
+ALTER TABLE `zh_material_bills` ADD `m_tax_tp` DECIMAL(30,8) NULL DEFAULT NULL COMMENT '调差金额(材料税)' AFTER `pre_tp`, ADD `tax_pre_tp` DECIMAL(30,8) NULL DEFAULT NULL COMMENT '截止上期调差金额(材料税)' AFTER `m_tax_tp`;
+ALTER TABLE `zh_material_bills` ADD `m_tax` SMALLINT(3) NOT NULL DEFAULT NULL COMMENT '材料税税率' AFTER `is_summary`;
+ALTER TABLE `zh_material_bills_history` ADD `m_tax_tp` DECIMAL(30,8) NULL DEFAULT NULL COMMENT '调差金额(材料税)' AFTER `pre_tp`, ADD `tax_pre_tp` DECIMAL(30,8) NULL DEFAULT NULL COMMENT '截止上期调差金额(材料税)' AFTER `m_tax_tp`;
+ALTER TABLE `zh_material_bills_history` ADD `m_tax` SMALLINT(3) NOT NULL DEFAULT NULL COMMENT '材料税税率' AFTER `is_summary`;