Преглед изворни кода

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

Tony Kang пре 1 недеља
родитељ
комит
22c3a6ae66

+ 2 - 2
app/controller/contract_controller.js

@@ -1035,7 +1035,7 @@ module.exports = app => {
                 if (!att) {
                     throw '未找到合同文件';
                 }
-                att.viewpath = ctx.helper.getPreviewPath(att.fileext, ctx.app.config.fujianOssPath + att.filepath);
+                att.viewpath = ctx.app.config.fujianOssPath + att.filepath;
                 const aiDify = new AiDify({ apiKey: ctx.difyInfo.apiKey.contract });
                 const transResult = await aiDify.contractTrans(att);
                 transResult.res = JSON.parse(transResult.res);
@@ -1096,7 +1096,7 @@ module.exports = app => {
                 }
 
                 // 重新查出该cid下的附件,按filepath精确匹配出刚上传的这一份(避免拿到该cid下其他历史文件)
-                newFile.viewpath = ctx.helper.getPreviewPath(newFile.fileext, ctx.app.config.fujianOssPath + newFile.filepath);
+                newFile.viewpath = ctx.app.config.fujianOssPath + newFile.filepath;
                 const aiDify = new AiDify({ apiKey: ctx.difyInfo.apiKey.contract });
                 const transResult = await aiDify.contractTrans(newFile);
                 transResult.res = JSON.parse(transResult.res);

+ 31 - 32
app/controller/datacollect_controller.js

@@ -156,43 +156,42 @@ module.exports = app => {
                     });
                     for (const t of tenderList) {
                         // 用标段管理的方法获取t数据
-                        if (!have_cost) {
-                            await this.ctx.service.tenderCache.loadTenderCache(t, '');
-                            t.total_price = t.ledger_tp && t.ledger_tp.total_price ? t.ledger_tp.total_price : 0;
-                            [t.change_tp, t.change_p_tp, t.change_n_tp, t.change_valuation_tp, t.change_unvaluation_tp] = await ctx.service.change.getChangeTp(t.id);
-                            // t.material_tp = await ctx.service.material.getSumMaterial(t.id);
-                            // 获取本标段 本月计量期审批通过数目,变更令审批通过数目,台账修订通过数目,材料调差通过数目
-                            t.month_stage_num = await ctx.service.stageAudit.getNumByMonth(t.id, startMonth, endMonth);
-                            t.month_change_num = await ctx.service.changeAudit.getNumByMonth(t.id, startMonth, endMonth);
-                            t.month_revise_num = await ctx.service.reviseAudit.getNumByMonth(t.id, startMonth, endMonth);
-                            t.month_material_num = await ctx.service.materialAudit.getNumByMonth(t.id, startMonth, endMonth);
-                            // 获取标段计量月统计及截止月累计计量
-                            // 这个慢,统计下面这个方法时长
-                            const stageList = await ctx.service.stage.getStageByDataCollect(t.id, t.stage_tp);
-                            // const stageList = [];
-                            const month_stage = [];
-                            for (const s of stageList) {
-                                const monthOneStage = ctx.app._.find(month_stage, { yearmonth: s.s_time });
-                                if (monthOneStage) {
-                                    monthOneStage.tp = ctx.helper.add(monthOneStage.tp, s.tp);
-                                    monthOneStage.end_yf_tp = ctx.helper.add(monthOneStage.end_yf_tp, s.yf_tp);
-                                    monthOneStage.end_sf_tp = ctx.helper.add(monthOneStage.end_sf_tp, s.sf_tp);
-                                } else {
-                                    const data = {
-                                        yearmonth: s.s_time,
-                                        tp: s.tp,
-                                        end_tp: s.end_tp,
-                                        end_yf_tp: s.yf_tp,
-                                        end_sf_tp: s.sf_tp,
-                                    };
-                                    month_stage.push(data);
-                                }
+                        await this.ctx.service.tenderCache.loadTenderCache(t, '');
+                        t.total_price = t.ledger_tp && t.ledger_tp.total_price ? t.ledger_tp.total_price : 0;
+                        [t.change_tp, t.change_p_tp, t.change_n_tp, t.change_valuation_tp, t.change_unvaluation_tp] = await ctx.service.change.getChangeTp(t.id);
+                        // t.material_tp = await ctx.service.material.getSumMaterial(t.id);
+                        // 获取本标段 本月计量期审批通过数目,变更令审批通过数目,台账修订通过数目,材料调差通过数目
+                        t.month_stage_num = await ctx.service.stageAudit.getNumByMonth(t.id, startMonth, endMonth);
+                        t.month_change_num = await ctx.service.changeAudit.getNumByMonth(t.id, startMonth, endMonth);
+                        t.month_revise_num = await ctx.service.reviseAudit.getNumByMonth(t.id, startMonth, endMonth);
+                        t.month_material_num = await ctx.service.materialAudit.getNumByMonth(t.id, startMonth, endMonth);
+                        // 获取标段计量月统计及截止月累计计量
+                        // 这个慢,统计下面这个方法时长
+                        const stageList = await ctx.service.stage.getStageByDataCollect(t.id, t.stage_tp);
+                        // const stageList = [];
+                        const month_stage = [];
+                        for (const s of stageList) {
+                            const monthOneStage = ctx.app._.find(month_stage, { yearmonth: s.s_time });
+                            if (monthOneStage) {
+                                monthOneStage.tp = ctx.helper.add(monthOneStage.tp, s.tp);
+                                monthOneStage.end_yf_tp = ctx.helper.add(monthOneStage.end_yf_tp, s.yf_tp);
+                                monthOneStage.end_sf_tp = ctx.helper.add(monthOneStage.end_sf_tp, s.sf_tp);
+                            } else {
+                                const data = {
+                                    yearmonth: s.s_time,
+                                    tp: s.tp,
+                                    end_tp: s.end_tp,
+                                    end_yf_tp: s.yf_tp,
+                                    end_sf_tp: s.sf_tp,
+                                };
+                                month_stage.push(data);
                             }
-                            t.month_stage = month_stage;
                         }
+                        t.month_stage = month_stage;
                         if (have_cost) {
                             // 取最新已审批完成的成本管理-成本分析期数据
                             t.cost_analysis = await ctx.service.costStage.getLastCheckedStage(t.id, 'analysis');
+                            t.cost_duty = await ctx.service.costStage.getStageByOrder(t.id, 'duty', 1);
                             t.stage_num = await ctx.service.stage.getNumByChecked(t.id);
                             t.cost_ledger_num = await ctx.service.costStage.getNumByChecked(t.id, 'ledger');
                             t.cost_analysis_num = await ctx.service.costStage.getNumByChecked(t.id, 'analysis');

BIN
app/public/images/juecedaping07.png


BIN
app/public/images/juecedaping08.png


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

@@ -350,7 +350,7 @@ $(document).ready(function() {
                 case 'num_o':
                 case 'num_p':
                     info.cancel = node.tree_level === 1 || (node.children && node.children.length > 0);
-                    if (!info.cancel) info.cancel = !!node.import_cost_id || (detailRange && detailRange.length > 0);
+                    if (!info.cancel) info.cancel = (!!node.import_cost_id && !!node.import_cost_type) || (detailRange && detailRange.length > 0);
                     break;
             }
         }

+ 5 - 1
app/service/cost_stage_analysis.js

@@ -17,7 +17,7 @@ const costFields = {
     hisFields: ['calc_his'],
     taxFields: ['tax'],
     treeFields: ['tree_id', 'tree_pid', 'tree_level', 'tree_order', 'tree_full_path', 'tree_is_leaf'],
-    baseFields: ['id', 'cost_id', 'tender_id', 'stage_id', 'node_type', 'calc_type', 'has_detail', 'import_cost_id'],
+    baseFields: ['id', 'cost_id', 'tender_id', 'stage_id', 'node_type', 'calc_type', 'has_detail', 'import_cost_id', 'import_cost_type'],
 };
 costFields.sumFields = [...costFields.calcFields, ...costFields.selfCalcFields];
 costFields.preCopyFields = [...costFields.treeFields, ...costFields.textFields, ...costFields.selfTextFields, ...costFields.calcFields, ...costFields.selfCalcFields, ...costFields.taxFields];
@@ -185,6 +185,7 @@ module.exports = app => {
                 idata.calc_type = pl.calc_type;
                 idata.has_detail = pl.has_detail && pl.detail.length > 0;
                 idata.import_cost_id = pl.import_cost_id;
+                idata.import_cost_type = pl.import_cost_type;
                 if (!idata.has_detail) {
                     for (const prop of costFields.preCopyFields) {
                         idata[prop] = pl[prop];
@@ -222,6 +223,7 @@ module.exports = app => {
         //         idata.calc_type = pl.calc_type;
         //         idata.has_detail = pl.has_detail && pl.detail.length > 0;
         //         idata.import_cost_id = pl.import_cost_id;
+        //         idata.import_cost_type = pl.import_cost_type;
         //         if (!idata.has_detail) {
         //             for (const prop of costFields.preCopyFields) {
         //                 idata[prop] = pl[prop];
@@ -674,7 +676,9 @@ module.exports = app => {
                         updateData[prop] = this.ctx.helper.add(updateData[prop], id[prop]);
                     }
                 }
+                updateData.import_cost_type = insertDetails[0].is_deal ? 2 : 1;
             } else {
+                updateData.import_cost_type = 0;
                 for (const node of nodes) {
                     updateData.yf_excl_tax_tp = this.ctx.helper.add(updateData.yf_excl_tax_tp, node.end_yf_excl_tax_tp || 0);
                     updateData.sf_excl_tax_tp = this.ctx.helper.add(updateData.sf_excl_tax_tp, node.end_sf_excl_tax_tp || 0);

+ 428 - 290
app/view/datacollect/index_cost.ejs

@@ -62,165 +62,142 @@
         </div>
         <div class="c-body" style="background:#2c3237 !important">
             <div class="flex-content">
-                <div class="row mx-2" style="height: 63.5vh">
-                    <div class="col-3 px-0 height-100">
-                        <div class="left-content height-100">
-                            <div class="left-card-content height-100">
-                                <div class="height-25 mb-2">
-                                    <div class="card text-center bg-dark text-white mr-2 py-2 height-100">
-                                        <div class="height-100" style="display: grid;place-items: center;">
-                                            <div style="line-height: 3;">
-                                                <div style="font-size: 1.5rem" class="data_total_in_tp">0.00</div>
-                                                <div style="font-size: .9rem;">
-                                                    <span style="background-color: #42474c;border-radius: 1rem;padding: .25rem .75rem">项目收入</span>
-                                                </div>
-                                            </div>
-                                        </div>
-                                    </div>
+                <div class="row mx-2" style="height: 95.5vh">
+                    <div class="col-9 px-0 height-100">
+                        <div class="row m-0 px-0 mb-2" style="height: 50%;">
+                            <div class="col-4 px-0 bg-dark height-100">
+                                <div class="col-12 text-white pt-2">
+                                    <div class="card-big-htext">|  金额对比<span class="float-right mr-2">万元&nbsp;</span></div>
                                 </div>
-                                <div class="height-25 mb-2">
-                                    <div class="card text-center bg-dark text-white mr-2 py-2 height-100">
-                                        <div class="height-100" style="display: grid;place-items: center;">
-                                            <div style="line-height: 3;">
-                                                <div style="font-size: 1.5rem" class="data_total_out_tp">0.00</div>
-                                                <div style="font-size: .9rem;">
-                                                    <span style="background-color: #42474c;border-radius: 1rem;padding: .25rem .75rem">项目支出</span>
-                                                </div>
-                                            </div>
-                                        </div>
-                                    </div>
+                                <div class="col-12 pb-2 text-white m-0 mt-2 bg-dark" style="height: 89%;overflow: auto;">
+                                    <style>
+                                        .level1-table tbody tr td {
+                                            padding: 6px 10px; /* 默认一般是 8~16px,可根据需要继续调小 */
+                                            line-height: 1.2;
+                                            border-bottom: 1px solid rgba(255,255,255,0.2);
+                                        }
+                                        .level1-table tbody tr:last-child td {
+                                            border-bottom: none;
+                                        }
+                                    </style>
+                                    <table class="level1-table" style="width: 100%; height: 100%;">
+                                        <thead style="height: 50px;border-bottom: 1px solid rgba(255,255,255,0.2);background-color: #2C3034;">
+                                        <tr class="text-center">
+                                            <th>分类</th>
+                                            <th>责任成本</th>
+                                            <th>实际成本</th>
+                                        </tr>
+                                        </thead>
+                                        <tbody>
+                                        <tr>
+                                            <td>项目收入</td>
+                                            <td class="text-center data_duty_total_in_tp"></td>
+                                            <td class="text-center data_total_in_tp"></td>
+                                        </tr>
+                                        <tr>
+                                            <td>项目成本</td>
+                                            <td class="text-center data_duty_total_out_tp"></td>
+                                            <td class="text-center data_total_out_tp"></td>
+                                        </tr>
+                                        <tr>
+                                            <td>利润</td>
+                                            <td class="text-center data_duty_total_profit"></td>
+                                            <td class="text-center data_total_profit"></td>
+                                        </tr>
+                                        <tr>
+                                            <td>利润率</td>
+                                            <td class="text-center data_duty_total_profit_percent"></td>
+                                            <td class="text-center data_total_profit_percent"></td>
+                                        </tr>
+                                        </tbody>
+                                    </table>
                                 </div>
-                                <div class="height-25 mb-2">
-                                    <div class="card text-center bg-dark text-white mr-2 py-2 height-100">
-                                        <div class="height-100" style="display: grid;place-items: center;">
-                                            <div style="line-height: 3;">
-                                                <div style="font-size: 1.5rem" class="data_total_profit">0.00</div>
-                                                <div style="font-size: .9rem;">
-                                                    <span style="background-color: #42474c;border-radius: 1rem;padding: .25rem .75rem">利润</span>
-                                                </div>
-                                            </div>
-                                        </div>
+                            </div>
+                            <div class="col-8 px-0 height-100">
+                                <div class="row mx-2 mb-2 height-100 bg-dark">
+                                    <div class="col-12 text-white pt-2 pl-3">
+                                        <div class="card-big-htext">|  标段利润及利润率<span class="float-right mr-2">万元&nbsp;</span></div>
                                     </div>
-                                </div>
-                                <div class="height-25" style="height: 24.3%">
-                                    <div class="card text-center bg-dark text-white mr-2 py-2 height-100">
-                                        <div class="height-100" style="display: grid;place-items: center;">
-                                            <div style="line-height: 3;">
-                                                <div style="font-size: 1.5rem" class="data_total_profit_percent">0%</div>
-                                                <div style="font-size: .9rem;">
-                                                    <span style="background-color: #42474c;border-radius: 1rem;padding: .25rem .75rem">利润率</span>
-                                                </div>
-                                            </div>
-                                        </div>
+                                    <div class="col-12 m-0" style="height: 88%">
+                                        <div class="jlchart" data-chart-num="1" id="jlchart" style="height: 100%; width: 100%;"></div>
                                     </div>
                                 </div>
                             </div>
                         </div>
-                    </div>
-                    <div class="col-6 px-0 height-100">
-                        <div class="center-content height-100 mr-2">
-                            <div class="center-chart-content height-100">
-                                <div class="center-di">
-                                    <div class="card bg-dark height-100">
-                                        <div class="jlchart" data-chart-num="1" id="jlchart" style="height: 100%; width: 100%;"></div>
-                                    </div>
-                                </div>
-                                <div class="center-chart">
-                                    <div class="card height-100 bg-dark mt-2">
-                                        <div class="di-content mb-2">
-                                            <div class="jldbchart" data-chart-num="1" id="jldbchart" style="height: 100%; width: 100%;"></div>
-                                        </div>
-                                    </div>
-                                </div>
+                        <div class="row m-0 px-0 mr-2 bg-dark" style="height: 49%;">
+                            <div class="col-12 text-white pt-2 pl-3">
+                                <div class="card-big-htext">|  累计计量<span class="float-right mr-2">万元&nbsp;</span></div>
+                            </div>
+                            <div class="col-12 m-0" style="height: 88%">
+                                <div class="jldbchart" id="jldbchart" style="height: 100%; width: 100%;"></div>
                             </div>
                         </div>
                     </div>
                     <div class="col-3 px-0 height-100">
-                        <div class="right-content height-100">
-                            <div class="right-chart-content height-100">
-                                <div class="right-month">
-                                    <h6 class="card bg-dark text-center text-white m-0 pt-2 pb-3">期数统计</h6>
-                                    <div class="row right-month-height">
-                                        <div class="col-6 pr-0 height-50">
-                                            <div class="card text-center bg-dark text-white border-right-0 border-botton-0 height-100">
-                                                <div class="card-body card-small-body height-100">
-                                                    <h5 class="card-title text-center height-50" style="font-size: 2.80rem;line-height: 200%"><span class="stage_num">0</span></h5>
-                                                    <p class="card-text text-muted height-50">计量期</p>
-                                                </div>
+                        <div class="row mb-2 bg-dark m-0 p-0" style="height: 31.2vh">
+                            <div class="col-12 text-white pt-2 pl-3">
+                                <div class="card-big-htext">|  期数统计<span class="float-right mr-2">&nbsp;</span></div>
+                            </div>
+<!--                                    <h6 class="card bg-dark text-center text-white m-0 pt-2 pb-3">期数统计</h6>-->
+                            <div class="col-12 p-0 m-0 right-month-height">
+                                <div class="row p-0 m-0 height-100">
+                                    <div class="col-6 px-0 height-50">
+                                        <div class="card text-center bg-dark text-white border-0 height-100">
+                                            <div class="card-body card-small-body height-100">
+                                                <h5 class="card-title text-center height-50" style="font-size: 2.80rem;line-height: 200%"><span class="stage_num">0</span></h5>
+                                                <p class="card-text text-muted height-50">计量期</p>
                                             </div>
                                         </div>
-                                        <div class="col-6 pl-0 height-50">
-                                            <div class="card text-center bg-dark text-white border-botton-0 height-100">
-                                                <div class="card-body card-small-body height-100">
-                                                    <h5 class="card-title text-center height-50" style="font-size: 2.80rem;line-height: 200%"><span class="cost_ledger_num">0</span></h5>
-                                                    <p class="card-text text-muted height-50">成本报审</p>
-                                                </div>
+                                    </div>
+                                    <div class="col-6 px-0 height-50">
+                                        <div class="card text-center bg-dark text-white border-0 height-100">
+                                            <div class="card-body card-small-body height-100">
+                                                <h5 class="card-title text-center height-50" style="font-size: 2.80rem;line-height: 200%"><span class="cost_ledger_num">0</span></h5>
+                                                <p class="card-text text-muted height-50">成本报审</p>
                                             </div>
                                         </div>
-                                        <div class="col-6 pr-0 height-50">
-                                            <div class="card text-center bg-dark text-white border-right-0 border-top-0 height-100">
-                                                <div class="card-body card-small-body height-100">
-                                                    <h5 class="card-title text-center height-50" style="font-size: 2.80rem;line-height: 200%"><span class="cost_book_num">0</span></h5>
-                                                    <p class="card-text text-muted height-50">财务账面</p>
-                                                </div>
+                                    </div>
+                                    <div class="col-6 px-0 height-50">
+                                        <div class="card text-center bg-dark text-white border-0 border-top-0 height-100">
+                                            <div class="card-body card-small-body height-100">
+                                                <h5 class="card-title text-center height-50" style="font-size: 2.80rem;line-height: 200%"><span class="cost_book_num">0</span></h5>
+                                                <p class="card-text text-muted height-50">财务账面</p>
                                             </div>
                                         </div>
-                                        <div class="col-6 pl-0 height-50">
-                                            <div class="card text-center bg-dark text-white border-top-0 height-100">
-                                                <div class="card-body card-small-body height-100">
-                                                    <h5 class="card-title text-center height-50" style="font-size: 2.80rem;line-height: 200%"><span class="cost_analysis_num">0</span></h5>
-                                                    <p class="card-text text-muted height-50">成本分析</p>
-                                                </div>
+                                    </div>
+                                    <div class="col-6 px-0 height-50">
+                                        <div class="card text-center bg-dark text-white border-0 height-100">
+                                            <div class="card-body card-small-body height-100">
+                                                <h5 class="card-title text-center height-50" style="font-size: 2.80rem;line-height: 200%"><span class="cost_analysis_num">0</span></h5>
+                                                <p class="card-text text-muted height-50">成本分析</p>
                                             </div>
                                         </div>
                                     </div>
                                 </div>
-                                <div class="right-chart">
-                                    <div class="card height-100 bg-dark">
-                                        <div class="jlwcdchart" id="jlwcdchart" style="height: 100%; width: 100%;"></div>
-                                    </div>
-                                </div>
                             </div>
                         </div>
-                    </div>
-                </div>
-                <div class="row mx-2" style="height: 32vh">
-                    <div class="col-9 px-0 pt-1 height-100">
-                        <div class="center-table height-100" style="padding-right: .5rem !important;">
-                            <div class="card height-100 bg-dark mt-2">
-                                <h6 class="bg-dark text-center text-white m-0 py-3">投资控制(万元)</h6>
-                                <div class="tablebox">
-                                    <table id="tableId">
-                                        <thead>
-                                        <tr class="text-center">
-                                            <th></th>
-                                            <th>投资估算</th>
-                                            <th>设计概算</th>
-                                            <th>施工图预算</th>
-                                            <th>控制目标</th>
-                                            <th>已完成</th>
-                                            <th>完成比例(%)</th>
-                                        </tr>
-                                        </thead>
-                                        <tbody class="stage-data">
-                                        </tbody>
-                                    </table>
-                                    <table id="tableId1"></table>
+                        <div class="m-0 mb-2 bg-dark p-0" style="height: 31.2vh">
+                            <div class="row mx-0 mb-2 height-100">
+                                <div class="col-12 text-white pt-2 pl-3">
+                                    <div class="card-big-htext">|  利润占比<span class="float-right mr-2">万元&nbsp;</span></div>
+                                </div>
+                                <div class="col-12 m-0" style="height: 88%">
+                                    <div class="jlwcdchart" id="jlwcdchart" style="height: 100%; width: 100%;"></div>
                                 </div>
                             </div>
                         </div>
-                    </div>
-                    <div class="col-3 px-0 pt-1 height-100">
-                        <div class="right-biaoduan height-100">
-                            <div class="card height-100 bg-dark mt-2">
-                                <h6 class="bg-dark text-center text-white m-0 py-3">利润率排名</h6>
-                                <div class="tablebox">
+                        <div class="m-0 mb-2 bg-dark p-0" style="height: 31.3vh">
+                            <div class="height-100">
+                                <div class="col-12 text-white pt-2 pl-3">
+                                    <div class="card-big-htext">|  利润率排名<span class="float-right mr-2">&nbsp;</span></div>
+                                </div>
+                                <div class="tablebox mt-2" style="height: 80%">
                                     <table id="profit_tableId">
                                         <thead>
                                         <tr class="text-center">
-                                            <th></th>
+                                            <th width="50">排名</th>
                                             <th>标段</th>
-                                            <th>利润率</th>
+                                            <th width="80">利润率</th>
                                         </tr>
                                         </thead>
                                         <tbody class="tender-data">
@@ -250,9 +227,6 @@
             // position: 'top',
         },
         title: {
-            text: '利润排名占比',
-            left: 'center',
-            top:'7%'
         },
         color: ['rgba(38, 217, 217,0.7)','rgba(78, 139, 229,0.7)',
             'rgba(78, 229, 139,0.7)','rgba(108, 78, 229,0.7)',
@@ -272,8 +246,8 @@
             {
                 name: '利润金额',
                 type: 'pie',
-                radius: '60%',
-                top:'15%',
+                radius: '65%',
+                top:'2%',
                 formatter: function(name){
                     return name.length>10?name.substr(0,10)+"...":name;
                 },
@@ -293,9 +267,6 @@
     // 利润统计状图表
     option2 = {
         title: {
-            text: '利润统计',
-            left: 'center',
-            top:'5%'
         },
         color: ['rgba(38, 217, 217,0.7)','rgba(78, 139, 229,0.7)',
             'rgba(78, 229, 139,0.7)','rgba(108, 78, 229,0.7)',
@@ -309,6 +280,28 @@
             axisPointer: {            // 坐标轴指示器,坐标轴触发有效
                 type: 'shadow'        // 默认为直线,可选为:'line' | 'shadow'
             },
+            formatter: function (params) {
+
+                let html = params[0].axisValue + '<br/>';
+
+                params.forEach(function (item) {
+
+                    let value = item.value;
+
+                    if (item.seriesName === '利润率') {
+                        value += '%';
+                    }
+
+                    html += `
+            <div style="display:flex;justify-content:space-between;min-width:150px;">
+                <span>${item.marker}${item.seriesName}</span>
+                <span style="font-weight:bold;">${value}</span>
+            </div>
+        `;
+                });
+
+                return html;
+            }
         },
 
         dataZoom: [
@@ -327,25 +320,17 @@
                 height: 10,
                 bottom: '10%',
             },
-            // {
-            //     // realtime: true,
-            //     type: 'slider',
-            //     show: true,
-            //     realtime: true,
-            //     showdetail: false,
-            //     showDataShadow: false,
-            //     // dataZoomIndex: 10,
-            //     start: 0,
-            //     end: 8,
-            //     handleSize: 0,
-            //     bottom:30,
-            //     height:10,
-            // }
         ],
-        // legend: {
-        //     data: ['利润'],
-        //     top:'17%'
-        // },
+        legend: {
+            top: '5%',
+            left: 'center',
+            data: ['利润', '利润率'],
+            textStyle: {
+                color: '#fff',
+                fontSize: 14
+            },
+            icon: 'roundRect' // 可选:rect、circle、roundRect
+        },
         grid: {
             top:'25%',
             left: '3%',
@@ -377,7 +362,7 @@
         yAxis: [
             {
                 type: 'value',
-                name:'金额',
+                name:'',
                 position: 'left',
                 axisLabel : {
                     formatter: function (value, index) {
@@ -398,19 +383,28 @@
                         return value;
                     }
                 },
-                splitArea : {show : true}
+                splitLine: {
+                    show: true,
+                    lineStyle: {
+                        color: 'rgba(255,255,255,0.5)',
+                        type: 'dashed',   // 虚线
+                        width: 1
+                    }
+                }
             },
-            // {
-            //     type: 'value',
-            //     name:'完成度',
-            //     position: 'right',
-            //     min:0,
-            //     max:100,
-            //     axisLabel : {
-            //         formatter: '{value} %'
-            //     },
-            //     splitArea : {show : true}
-            // }
+            {
+                type: 'value',
+                name: '',
+                position: 'right',
+
+                axisLabel: {
+                    formatter: '{value}%'
+                },
+
+                splitLine: {
+                    show: false      // 不显示右侧网格线
+                }
+            }
         ],
         series: [
             {
@@ -421,19 +415,35 @@
                 },
                 data: []
             },
+            {
+                name: '利润率',
+                type: 'line',
+                yAxisIndex: 1,     // 使用右侧坐标轴
+
+                smooth: true,
+
+                symbol: 'circle',
+                symbolSize: 8,
+
+                lineStyle: {
+                    width: 3
+                },
+
+                itemStyle: {
+                    color: '#fea844'
+                },
+
+                data: []
+            }
         ]
     };
     var chart2 = document.getElementsByClassName('jlchart');
     var myChart2_1 = echarts.init(chart2[0], 'dark');
     myChart2_1.setOption(option2);
     // myChart2.setOption(option);
-    // 利润率统计柱状图表
-    // var myChart3 = echarts.init(document.getElementsByClassName('jlwcdchart')[0], 'dark');
-    option3 = {
+
+    const option4_default = {
         title: {
-            text: '利润率统计',
-            left: 'center',
-            top:'5%'
         },
         color: ['rgba(38, 217, 217,0.7)','rgba(78, 139, 229,0.7)',
             'rgba(78, 229, 139,0.7)','rgba(108, 78, 229,0.7)',
@@ -444,34 +454,23 @@
         backgroundColor: '#343a40 ',
         tooltip: {
             trigger: 'axis',
-            axisPointer: {            // 坐标轴指示器,坐标轴触发有效
-                type: 'shadow'        // 默认为直线,可选为:'line' | 'shadow'
-            },
+            axisPointer: {
+                type: 'cross',
+                label: {
+                    backgroundColor: '#6a7985'
+                }
+            }
+        },
+        legend: {
+            type: 'scroll',
+            bottom: '2%',
+            data: [],
+            textStyle: {
+                color: '#fff'
+            }
         },
-
-        dataZoom: [
-            {
-                brushSelect:false,
-                // zoomLock: false,
-                type: 'slider',
-                show: true,
-                realtime: true,
-                showdetail: false,
-                showDataShadow: false,
-                // dataZoomIndex: 10,
-                start: 0,
-                end: 8,
-                handleSize: 0,
-                height: 10,
-                bottom: '10%',
-            },
-        ],
-        // legend: {
-        //     data: ['利润率'],
-        //     top:'17%'
-        // },
         grid: {
-            top:'25%',
+            top:'10%',
             left: '3%',
             right: '4%',
             bottom: '15%',
@@ -480,81 +479,66 @@
         xAxis: [
             {
                 type: 'category',
-                data: [],
-                axisLabel: {
-                    show: true,
-                    interval: 0,
-                    textStyle: {
-                        color: "#fff",
-                        fontSize: 14
-                    },
-                    formatter: function(value) {
-                        var res = value;
-                        if(res.length > 6) {
-                            res = res.substring(0, 5) + "..";
-                        }
-                        return res;
-                    }
-                }
+                boundaryGap: false,
+                data: []
             }
         ],
         yAxis: [
-            // {
-            //     type: 'value',
-            //     name:'利润率',
-            //     position: 'left',
-            //     axisLabel : {
-            //         formatter: function (value, index) {
-            //             if (value < 0) {
-            //                 let newValue = Math.abs(value);
-            //                 if (newValue >= 10000 && newValue < 10000000) {
-            //                     newValue = newValue / 10000 + "万";
-            //                 } else if (newValue >= 10000000) {
-            //                     newValue = newValue / 10000000 + "千万";
-            //                 }
-            //                 value = '-' + newValue;
-            //             }
-            //             if (value >= 10000 && value < 10000000) {
-            //                 value = value / 10000 + "万";
-            //             } else if (value >= 10000000) {
-            //                 value = value / 10000000 + "千万";
-            //             }
-            //             return value;
-            //         }
-            //     },
-            //     splitArea : {show : true}
-            // },
             {
                 type: 'value',
-                name:'利润率',
-                position: 'left',
-                min:0,
-                max:100,
                 axisLabel : {
-                    formatter: '{value} %'
+                    formatter: function (value, index) {
+                        if (value < 0) {
+                            let newValue = Math.abs(value);
+                            if (newValue >= 10000 && newValue < 10000000) {
+                                newValue = newValue / 10000 + "万";
+                            } else if (newValue >= 10000000) {
+                                newValue = newValue / 10000000 + "千万";
+                            }
+                            value = '-' + newValue;
+                        }
+                        if (value >= 10000 && value < 10000000) {
+                            value = value / 10000 + "万";
+                        } else if (value >= 10000000) {
+                            value = value / 10000000 + "千万";
+                        }
+                        return value;
+                    }
                 },
-                splitArea : {show : true}
+                splitLine: {
+                    show: true,
+                    lineStyle: {
+                        color: 'rgba(255,255,255,0.5)',
+                        type: 'dashed',   // 虚线
+                        width: 1
+                    }
+                }
             }
         ],
-        series: [
+        dataZoom: [
             {
-                name: '利润率',
-                type: 'bar',
-                emphasis: {
-                    focus: 'series'
-                },
-                data: []
+                brushSelect: false,
+                showdetail: false,
+                show: true,
+                realtime: true,
+                dataZoomIndex: 10,
+                start: 0,
+                end: 5,
+                handleSize: 0,
+                height: 10,
+                bottom: '10%'
             },
-        ]
+        ],
+        series: [],
     };
-    var chart3 = document.getElementsByClassName('jldbchart');
-    var myChart3_1 = echarts.init(chart3[0], 'dark');
-    myChart3_1.setOption(option3);
+    var chart4 = document.getElementsByClassName('jldbchart');
+    var myChart4_1 = echarts.init(chart4[0], 'dark');
+    myChart4_1.setOption(option4_default);
 
     function echartsReset() {
         myChart1_1.resize();
         myChart2_1.resize();
-        myChart3_1.resize();
+        myChart4_1.resize();
     }
     $(function () {
         $('#showFull').click(function () {
@@ -677,24 +661,36 @@
                     rootId: -1,
                 });
                 const setting = { id: 'tree_id', pid: 'tree_pid', order: 'order', level: 'level', rootId: -1, calcFields: ['total_price'] };
-                const guTree = createNewPathTree('ledger', setting);
-                guTree.loadDatas(result.gu);
-                treeCalc.calculateAll(guTree);
-                compareTree.loadTree(guTree, function (cur, source) {
+                const realTree = createNewPathTree('ledger', setting);
+                realTree.loadDatas(result.real);
+                treeCalc.calculateAll(realTree);
+                compareTree.loadTree(realTree, function (cur, source) {
                     cur.base = true;
-                    cur.gu_dgn_qty1 = ZhCalc.add(cur.gu_dgn_qty1, source.dgn_qty1);
-                    cur.gu_dgn_qty2 = ZhCalc.add(cur.gu_dgn_qty2, source.dgn_qty2);
-                    cur.gu_tp = ZhCalc.add(cur.gu_tp, source.total_price);
+                    cur.real_dgn_qty1 = ZhCalc.add(cur.real_dgn_qty1, source.dgn_qty1);
+                    cur.real_dgn_qty2 = ZhCalc.add(cur.real_dgn_qty2, source.dgn_qty2);
+                    cur.real_tp = ZhCalc.add(cur.real_tp, source.total_price);
                 });
-                const gaiTree = createNewPathTree('ledger', setting);
-                gaiTree.loadDatas(result.gai);
-                treeCalc.calculateAll(gaiTree);
-                compareTree.loadTree(gaiTree, function (cur, source) {
+
+                const ctrlTree = createNewPathTree('ledger', setting);
+                ctrlTree.loadDatas(result.ctrl);
+                treeCalc.calculateAll(ctrlTree);
+                compareTree.loadTree(ctrlTree, function (cur, source) {
                     cur.base = true;
-                    cur.gai_dgn_qty1 = ZhCalc.add(cur.gai_dgn_qty1, source.dgn_qty1);
-                    cur.gai_dgn_qty2 = ZhCalc.add(cur.gai_dgn_qty2, source.dgn_qty2);
-                    cur.gai_tp = ZhCalc.add(cur.gai_tp, source.total_price);
+                    cur.ctrl_dgn_qty1 = ZhCalc.add(cur.ctrl_dgn_qty1, source.dgn_qty1);
+                    cur.ctrl_dgn_qty2 = ZhCalc.add(cur.ctrl_dgn_qty2, source.dgn_qty2);
+                    cur.ctrl_tp = ZhCalc.add(cur.ctrl_tp, source.total_price);
                 });
+
+                const zbTree = createNewPathTree('ledger', setting);
+                zbTree.loadDatas(result.zb);
+                treeCalc.calculateAll(zbTree);
+                compareTree.loadTree(zbTree, function (cur, source) {
+                    cur.base = true;
+                    cur.zb_dgn_qty1 = ZhCalc.add(cur.zb_dgn_qty1, source.dgn_qty1);
+                    cur.zb_dgn_qty2 = ZhCalc.add(cur.zb_dgn_qty2, source.dgn_qty2);
+                    cur.zb_tp = ZhCalc.add(cur.zb_tp, source.total_price);
+                });
+
                 const yuTree = createNewPathTree('ledger', setting);
                 yuTree.loadDatas(result.yu);
                 treeCalc.calculateAll(yuTree);
@@ -704,6 +700,26 @@
                     cur.yu_dgn_qty2 = ZhCalc.add(cur.yu_dgn_qty2, source.dgn_qty2);
                     cur.yu_tp = ZhCalc.add(cur.yu_tp, source.total_price);
                 });
+
+                const gaiTree = createNewPathTree('ledger', setting);
+                gaiTree.loadDatas(result.gai);
+                treeCalc.calculateAll(gaiTree);
+                compareTree.loadTree(gaiTree, function (cur, source) {
+                    cur.base = true;
+                    cur.gai_dgn_qty1 = ZhCalc.add(cur.gai_dgn_qty1, source.dgn_qty1);
+                    cur.gai_dgn_qty2 = ZhCalc.add(cur.gai_dgn_qty2, source.dgn_qty2);
+                    cur.gai_tp = ZhCalc.add(cur.gai_tp, source.total_price);
+                });
+
+                const guTree = createNewPathTree('ledger', setting);
+                guTree.loadDatas(result.gu);
+                treeCalc.calculateAll(guTree);
+                compareTree.loadTree(guTree, function (cur, source) {
+                    cur.base = true;
+                    cur.gu_dgn_qty1 = ZhCalc.add(cur.gu_dgn_qty1, source.dgn_qty1);
+                    cur.gu_dgn_qty2 = ZhCalc.add(cur.gu_dgn_qty2, source.dgn_qty2);
+                    cur.gu_tp = ZhCalc.add(cur.gu_tp, source.total_price);
+                });
                 compareTree.afterLoad(node => {
                     node.gu_dgn_price = ZhCalc.div(node.gu_tp, node.gu_dgn_qty1, 2);
                     node.gu_dgn_qty = node.gu_dgn_qty1
@@ -717,6 +733,18 @@
                     node.yu_dgn_qty = node.yu_dgn_qty1
                         ? (node.yu_dgn_qty2 ? node.yu_dgn_qty1 + '/' + node.yu_dgn_qty2 : node.yu_dgn_qty1)
                         : (node.yu_dgn_qty2 ? '/' + node.yu_dgn_qty2 : '');
+                    node.zb_dgn_price = ZhCalc.div(node.zb_tp, node.zb_dgn_qty1, 2);
+                    node.zb_dgn_qty = node.zb_dgn_qty1
+                        ? (node.zb_dgn_qty2 ? node.zb_dgn_qty1 + '/' + node.zb_dgn_qty2 : node.zb_dgn_qty1)
+                        : (node.zb_dgn_qty2 ? '/' + node.zb_dgn_qty2 : '');
+                    node.ctrl_dgn_price = ZhCalc.div(node.ctrl_tp, node.ctrl_dgn_qty1, 2);
+                    node.ctrl_dgn_qty = node.ctrl_dgn_qty1
+                        ? (node.ctrl_dgn_qty2 ? node.ctrl_dgn_qty1 + '/' + node.ctrl_dgn_qty2 : node.ctrl_dgn_qty1)
+                        : (node.ctrl_dgn_qty2 ? '/' + node.ctrl_dgn_qty2 : '');
+                    node.real_dgn_price = ZhCalc.div(node.real_tp, node.real_dgn_qty1, 2);
+                    node.real_dgn_qty = node.real_dgn_qty1
+                        ? (node.real_dgn_qty2 ? node.real_dgn_qty1 + '/' + node.real_dgn_qty2 : node.real_dgn_qty1)
+                        : (node.real_dgn_qty2 ? '/' + node.real_dgn_qty2 : '');
                 });
                 compareTree.resortChildrenByCustom(function (x, y) {
                     const iCode = compareCode(x.code, y.code);
@@ -850,6 +878,9 @@
         }
 
         function setData(tenderList, categoryIndex = 0) {
+            let total_duty_in_tp = 0;
+            let total_duty_out_tp = 0;
+            let total_duty_profit = 0;
             let total_in_tp = 0;
             let total_out_tp = 0;
             let total_profit = 0;
@@ -879,17 +910,26 @@
             // } else {
             //     option1_is_tender = true;
             // }
-
+            const chart_option4_data = [];
             for(const t of tenderList) {
                 const stage_tp = t.cost_analysis ? t.cost_analysis.stage_tp : null;
                 if (stage_tp) {
                     total_in_tp = ZhCalc.add(total_in_tp, stage_tp.in_tp);
                     total_out_tp = ZhCalc.add(total_out_tp, stage_tp.out_tp);
                     total_profit = ZhCalc.add(total_profit, stage_tp.profit);
-                    chart_option2_data.push(stage_tp.profit ? stage_tp.profit : 0);
+                    chart_option2_data.push(stage_tp.profit ? ZhCalc.round(ZhCalc.div(stage_tp.profit, 10000), 0) : 0);
                     chart_option3_data.push(stage_tp.profit_percent ? stage_tp.profit_percent : 0);
                     chart_option_name.push(t.name);
-                    chart_option1_data.push({ value: stage_tp.profit, name: t.name});
+                    chart_option1_data.push({ value: stage_tp.profit ? ZhCalc.round(ZhCalc.div(stage_tp.profit, 10000), 0) : 0, name: t.name});
+                }
+                const dutyInfo = t.cost_duty ? t.cost_duty : null;
+                if (dutyInfo) {
+                    const duty_in_tp = dutyInfo.extra_info ? dutyInfo.extra_info.in_tp : 0;
+                    const duty_out_tp = dutyInfo.stage_tp ? dutyInfo.stage_tp.total_price : 0;
+                    total_duty_in_tp = ZhCalc.add(total_duty_in_tp, duty_in_tp);
+                    total_duty_out_tp = ZhCalc.add(total_duty_out_tp, duty_out_tp);
+                    const profit = ZhCalc.sub(duty_in_tp, duty_out_tp);
+                    total_duty_profit = ZhCalc.add(total_duty_profit, profit);
                 }
                 stage_num = ZhCalc.add(stage_num, t.stage_num);
                 cost_ledger_num = ZhCalc.add(cost_ledger_num, t.cost_ledger_num);
@@ -904,6 +944,25 @@
                 //         chart_option1_data[index].value = ZhCalc.add(chart_option1_data[index].value, (stage_tp.profit ? stage_tp.profit : 0));
                 //     }
                 // }
+                const one_option4_data = {
+                    id: t.id,
+                    name: t.name,
+                    list: [],
+                };
+                for (const s of t.month_stage) {
+                    const index = _.findIndex(one_option4_data.list, { yearmonth: s.yearmonth });
+                    if (index === -1) {
+                        one_option4_data.list.push({
+                            yearmonth: s.yearmonth,
+                            tp: s.tp,
+                            end_tp: s.end_tp,
+                        })
+                    } else {
+                        one_option4_data.list[index].tp = ZhCalc.add(one_option4_data.list[index].tp, s.tp);
+                        one_option4_data.list[index].end_tp = ZhCalc.add(one_option4_data.list[index].end_tp, s.end_tp);
+                    }
+                }
+                chart_option4_data.push(one_option4_data);
             }
             // 根据利润率排行并只显示前5位
             let index = 1;
@@ -923,17 +982,22 @@
                     tender_html += `<tr class="bg-dark">
                     <td class="text-center py-2">${rankDisplay}</td>
                     <td class="py-2">${t.name}</td>
-                    <td class="text-center py-2">${stage_tp.profit_percent}</td>
+                    <td class="text-center py-2">${stage_tp.profit_percent}%</td>
                 </tr>`;
                     index++;
                 }
             }
             // console.log(tenderList);
             const profit_percent = total_in_tp && total_profit ? ZhCalc.round(ZhCalc.div(total_profit, total_in_tp) * 100, 2) : 0;
+            const profit_duty_percent = total_duty_in_tp && total_duty_profit ? ZhCalc.round(ZhCalc.div(total_duty_profit, total_duty_in_tp) * 100, 2) : 0;
             $('.data_total_profit_percent').text(profit_percent ? profit_percent + '%' : '0%');
-            $('.data_total_in_tp').text(formatMoney(total_in_tp));
-            $('.data_total_out_tp').text(formatMoney(total_out_tp));
-            $('.data_total_profit').text(formatMoney(total_profit));
+            $('.data_total_in_tp').text(ZhCalc.round(ZhCalc.div(total_in_tp, 10000), 0));
+            $('.data_total_out_tp').text(ZhCalc.round(ZhCalc.div(total_out_tp, 10000), 0));
+            $('.data_total_profit').text(ZhCalc.round(ZhCalc.div(total_profit, 10000), 0));
+            $('.data_duty_total_profit_percent').text(profit_duty_percent ? profit_duty_percent + '%' : '0%');
+            $('.data_duty_total_in_tp').text(ZhCalc.round(ZhCalc.div(total_duty_in_tp, 10000), 0));
+            $('.data_duty_total_out_tp').text(ZhCalc.round(ZhCalc.div(total_duty_out_tp, 10000), 0));
+            $('.data_duty_total_profit').text(ZhCalc.round(ZhCalc.div(total_duty_profit, 10000), 0));
             $('.stage_num').text(stage_num);
             $('.cost_ledger_num').text(cost_ledger_num);
             $('.cost_analysis_num').text(cost_analysis_num);
@@ -952,6 +1016,7 @@
             option2.dataZoom[0].end = computedPosition(analysis_num);
             option2.xAxis[0].data = chart_option_name;
             option2.series[0].data = chart_option2_data;
+            option2.series[1].data = chart_option3_data;
             if (analysis_num >= 8) {
                 option2.dataZoom[0].show = true;
             } else {
@@ -959,24 +1024,97 @@
             }
             myChart2_1.setOption(option2);
 
-            const option3 = myChart3_1.getOption();
-            option3.dataZoom[0].start = 0;
-            option3.dataZoom[0].end = computedPosition(analysis_num);
-            option3.xAxis[0].data = chart_option_name;
-            option3.series[0].data = chart_option3_data;
-            if (analysis_num >= 8) {
-                option3.dataZoom[0].show = true;
+            const option4_data = {
+                yearmonth: [],
+                series: [],
+                names: [],
+                totalMap: {},
+            }
+            console.log(chart_option4_data);
+            if (chart_option4_data.length > 0) {
+                const monthSet = new Set();
+                const namesSet = new Set();
+                chart_option4_data.forEach(tender => {
+                    namesSet.add(tender.name);
+                    tender.list.forEach(item => {
+                        monthSet.add(item.yearmonth);
+                    });
+                });
+                option4_data.names = [...namesSet];
+                option4_data.yearmonth = [...monthSet].sort();
+                chart_option4_data.forEach(tender => {
+                    const data = [];
+                    let total = 0; // 当前标段累计
+
+                    option4_data.yearmonth.forEach(month => {
+
+                        const item = tender.list.find(v => v.yearmonth === month);
+
+                        // const value = item ? ZhCalc.round(ZhCalc.div(item.tp, 10000), 0) : 0;
+
+                        const endtp = item ? ZhCalc.round(ZhCalc.div(item.end_tp, 10000), 0) : 0;
+
+                        total = endtp ? endtp : total;   // 累计
+
+                        data.push(total);
+                        option4_data.totalMap[month] = ZhCalc.add((option4_data.totalMap[month] || 0), total);
+                    });
+
+                    option4_data.series.push({
+                        name: tender.name,
+                        type: 'line',
+                        smooth: true,
+                        // itemStyle: {
+                        //     color: option4_default.color[index % option4_default.color.length]
+                        // },
+                        // lineStyle: {
+                        //     color: option4_default.color[index % option4_default.color.length]
+                        // },
+                        data
+                    });
+                });
+                option4_data.names.push('合计');
+                option4_data.series.push({
+                    name: '合计',
+
+                    type: 'line',
+
+                    smooth: true,
+
+                    lineStyle: {
+                        width: 4,
+                        color: '#FFD54F'
+                    },
+                    itemStyle: {
+                        color: '#FFD54F'
+                    },
+
+                    symbolSize: 8,
+
+                    data: option4_data.yearmonth.map(month => option4_data.totalMap[month] || 0)
+                })
+            }
+            console.log(option4_data);
+            const option4 = _.cloneDeep(option4_default);
+            option4.dataZoom[0].start = 0;
+            option4.dataZoom[0].end = computedPosition(option4_data.yearmonth.length);
+            option4.xAxis[0].data = option4_data.yearmonth;
+            option4.series = option4_data.series;
+            option4.legend.data = option4_data.names;
+            if (option4_data.yearmonth.length >= 8) {
+                option4.dataZoom[0].show = true;
             } else {
-                option3.dataZoom[0].show = false;
+                option4.dataZoom[0].show = false;
             }
-            myChart3_1.setOption(option3);
+            console.log(option4);
+            myChart4_1.setOption(option4, true);
 
             const option1 = myChart1_1.getOption();
             option1.series[0].data = _.filter(chart_option1_data, function (item) {
                 return item.value !== 0;
             });
             myChart1_1.setOption(option1);
-            $('#profit_tableId').css({'margin-top': 0});
+            // $('#profit_tableId').css({'margin-top': 0});
         }
         // 第一层分类选择
         $("body").on('click', '#first-category .select-cate', function () {

+ 101 - 17
app/view/datacollect/index_tz.ejs

@@ -62,7 +62,30 @@
                                 <div class="col-12 text-white pt-2 pl-3">
                                     <div class="card-big-htext">|  金额对比<span class="float-right mr-2">万元&nbsp;</span></div>
                                 </div>
-                                <div class="col-12 pb-2 text-white m-0 bg-dark" style="height: 89%;overflow: auto;">
+                                <style>
+                                    .table-scroll::-webkit-scrollbar {
+                                        width: 6px;
+                                        height: 6px;
+                                    }
+
+                                    .table-scroll::-webkit-scrollbar-track {
+                                        background: transparent;
+                                    }
+
+                                    .table-scroll::-webkit-scrollbar-thumb {
+                                        background: rgba(255,255,255,.25);
+                                        border-radius: 3px;
+                                    }
+
+                                    .table-scroll::-webkit-scrollbar-thumb:hover {
+                                        background: rgba(255,255,255,.45);
+                                    }
+
+                                    .table-scroll::-webkit-scrollbar-corner {
+                                        background: transparent;
+                                    }
+                                </style>
+                                <div class="col-12 pb-2 text-white m-0 bg-dark table-scroll" style="height: 89%;overflow: auto;">
                                     <style>
                                         .level1-table tbody tr td {
                                             padding: 6px 10px; /* 默认一般是 8~16px,可根据需要继续调小 */
@@ -98,7 +121,7 @@
                             </div>
                         </div>
                     </div>
-                    <div class="col-3 m-0 px-0 height-100">
+                    <div class="col-3 m-0 px-0 height-100" id="tender-chart">
                         <style>
                             #tender-chart .card-big-htext {
                                 display: flex;
@@ -116,7 +139,7 @@
                                 flex-shrink: 0;
                             }
                         </style>
-                        <div class="row m-0 px-0 pb-2" id="tender-chart" style="height: 23.85vh">
+                        <div class="row m-0 px-0 pb-2" style="height: 23.85vh">
                             <div class="row mx-0 w-100 height-100 bg-dark">
                                 <div class="col-12 text-white pt-2 pl-3">
                                     <div class="card-big-htext"><span id="tender1_name" data-toggle="tooltip" data-original-title="">标段1</span><span class="float-right mr-2">万元&nbsp;</span></div>
@@ -694,24 +717,37 @@
                     rootId: -1,
                 });
                 const setting = { id: 'tree_id', pid: 'tree_pid', order: 'order', level: 'level', rootId: -1, calcFields: ['total_price'] };
-                const guTree = createNewPathTree('ledger', setting);
-                guTree.loadDatas(result.gu);
-                treeCalc.calculateAll(guTree);
-                compareTree.loadTree(guTree, function (cur, source) {
+
+                const realTree = createNewPathTree('ledger', setting);
+                realTree.loadDatas(result.real);
+                treeCalc.calculateAll(realTree);
+                compareTree.loadTree(realTree, function (cur, source) {
                     cur.base = true;
-                    cur.gu_dgn_qty1 = ZhCalc.add(cur.gu_dgn_qty1, source.dgn_qty1);
-                    cur.gu_dgn_qty2 = ZhCalc.add(cur.gu_dgn_qty2, source.dgn_qty2);
-                    cur.gu_tp = ZhCalc.add(cur.gu_tp, source.total_price);
+                    cur.real_dgn_qty1 = ZhCalc.add(cur.real_dgn_qty1, source.dgn_qty1);
+                    cur.real_dgn_qty2 = ZhCalc.add(cur.real_dgn_qty2, source.dgn_qty2);
+                    cur.real_tp = ZhCalc.add(cur.real_tp, source.total_price);
                 });
-                const gaiTree = createNewPathTree('ledger', setting);
-                gaiTree.loadDatas(result.gai);
-                treeCalc.calculateAll(gaiTree);
-                compareTree.loadTree(gaiTree, function (cur, source) {
+
+                const ctrlTree = createNewPathTree('ledger', setting);
+                ctrlTree.loadDatas(result.ctrl);
+                treeCalc.calculateAll(ctrlTree);
+                compareTree.loadTree(ctrlTree, function (cur, source) {
                     cur.base = true;
-                    cur.gai_dgn_qty1 = ZhCalc.add(cur.gai_dgn_qty1, source.dgn_qty1);
-                    cur.gai_dgn_qty2 = ZhCalc.add(cur.gai_dgn_qty2, source.dgn_qty2);
-                    cur.gai_tp = ZhCalc.add(cur.gai_tp, source.total_price);
+                    cur.ctrl_dgn_qty1 = ZhCalc.add(cur.ctrl_dgn_qty1, source.dgn_qty1);
+                    cur.ctrl_dgn_qty2 = ZhCalc.add(cur.ctrl_dgn_qty2, source.dgn_qty2);
+                    cur.ctrl_tp = ZhCalc.add(cur.ctrl_tp, source.total_price);
+                });
+
+                const zbTree = createNewPathTree('ledger', setting);
+                zbTree.loadDatas(result.zb);
+                treeCalc.calculateAll(zbTree);
+                compareTree.loadTree(zbTree, function (cur, source) {
+                    cur.base = true;
+                    cur.zb_dgn_qty1 = ZhCalc.add(cur.zb_dgn_qty1, source.dgn_qty1);
+                    cur.zb_dgn_qty2 = ZhCalc.add(cur.zb_dgn_qty2, source.dgn_qty2);
+                    cur.zb_tp = ZhCalc.add(cur.zb_tp, source.total_price);
                 });
+
                 const yuTree = createNewPathTree('ledger', setting);
                 yuTree.loadDatas(result.yu);
                 treeCalc.calculateAll(yuTree);
@@ -721,6 +757,26 @@
                     cur.yu_dgn_qty2 = ZhCalc.add(cur.yu_dgn_qty2, source.dgn_qty2);
                     cur.yu_tp = ZhCalc.add(cur.yu_tp, source.total_price);
                 });
+
+                const gaiTree = createNewPathTree('ledger', setting);
+                gaiTree.loadDatas(result.gai);
+                treeCalc.calculateAll(gaiTree);
+                compareTree.loadTree(gaiTree, function (cur, source) {
+                    cur.base = true;
+                    cur.gai_dgn_qty1 = ZhCalc.add(cur.gai_dgn_qty1, source.dgn_qty1);
+                    cur.gai_dgn_qty2 = ZhCalc.add(cur.gai_dgn_qty2, source.dgn_qty2);
+                    cur.gai_tp = ZhCalc.add(cur.gai_tp, source.total_price);
+                });
+
+                const guTree = createNewPathTree('ledger', setting);
+                guTree.loadDatas(result.gu);
+                treeCalc.calculateAll(guTree);
+                compareTree.loadTree(guTree, function (cur, source) {
+                    cur.base = true;
+                    cur.gu_dgn_qty1 = ZhCalc.add(cur.gu_dgn_qty1, source.dgn_qty1);
+                    cur.gu_dgn_qty2 = ZhCalc.add(cur.gu_dgn_qty2, source.dgn_qty2);
+                    cur.gu_tp = ZhCalc.add(cur.gu_tp, source.total_price);
+                });
                 compareTree.afterLoad(node => {
                     node.gu_dgn_price = ZhCalc.div(node.gu_tp, node.gu_dgn_qty1, 2);
                     node.gu_dgn_qty = node.gu_dgn_qty1
@@ -734,6 +790,18 @@
                     node.yu_dgn_qty = node.yu_dgn_qty1
                         ? (node.yu_dgn_qty2 ? node.yu_dgn_qty1 + '/' + node.yu_dgn_qty2 : node.yu_dgn_qty1)
                         : (node.yu_dgn_qty2 ? '/' + node.yu_dgn_qty2 : '');
+                    node.zb_dgn_price = ZhCalc.div(node.zb_tp, node.zb_dgn_qty1, 2);
+                    node.zb_dgn_qty = node.zb_dgn_qty1
+                        ? (node.zb_dgn_qty2 ? node.zb_dgn_qty1 + '/' + node.zb_dgn_qty2 : node.zb_dgn_qty1)
+                        : (node.zb_dgn_qty2 ? '/' + node.zb_dgn_qty2 : '');
+                    node.ctrl_dgn_price = ZhCalc.div(node.ctrl_tp, node.ctrl_dgn_qty1, 2);
+                    node.ctrl_dgn_qty = node.ctrl_dgn_qty1
+                        ? (node.ctrl_dgn_qty2 ? node.ctrl_dgn_qty1 + '/' + node.ctrl_dgn_qty2 : node.ctrl_dgn_qty1)
+                        : (node.ctrl_dgn_qty2 ? '/' + node.ctrl_dgn_qty2 : '');
+                    node.real_dgn_price = ZhCalc.div(node.real_tp, node.real_dgn_qty1, 2);
+                    node.real_dgn_qty = node.real_dgn_qty1
+                        ? (node.real_dgn_qty2 ? node.real_dgn_qty1 + '/' + node.real_dgn_qty2 : node.real_dgn_qty1)
+                        : (node.real_dgn_qty2 ? '/' + node.real_dgn_qty2 : '');
                 });
                 compareTree.resortChildrenByCustom(function (x, y) {
                     const iCode = compareCode(x.code, y.code);
@@ -830,6 +898,10 @@
                 realData: [],
             };
             const table_data = [];
+            const totalLevel1_table_data = {
+                ctrl_tp: 0,
+                real_tp: 0,
+            };
             if (tree.children.length > 0) {
                 // 分析第一层结构,获取各个部分金额非全0的及除了回收金额层
                 const level1List = _.filter(tree.children, function (item) {
@@ -874,6 +946,9 @@
                         ]
                     });
 
+                    totalLevel1_table_data.ctrl_tp = ZhCalc.add(totalLevel1_table_data.ctrl_tp, level1.ctrl_tp ? ZhCalc.round(ZhCalc.div(level1.ctrl_tp, 10000), 0) : 0);
+                    totalLevel1_table_data.real_tp = ZhCalc.add(totalLevel1_table_data.real_tp, level1.real_tp ? ZhCalc.round(ZhCalc.div(level1.real_tp, 10000), 0) : 0);
+
                     table_data.push(`
                     <tr>
                         <td>${level1.name}</td>
@@ -887,6 +962,12 @@
             }
             table_data.push(`
                 <tr>
+                    <td>公路总造价</td>
+                    <td class="text-center">${totalLevel1_table_data.ctrl_tp}</td>
+                    <td class="text-center">${totalLevel1_table_data.real_tp}</td>
+                </tr>`);
+            table_data.push(`
+                <tr>
                     <td>设计优化率(%)</td>
                     <td class="text-center">${info.ctrl_optimize_rate}</td>
                     <td class="text-center">${info.real_optimize_rate}</td>
@@ -916,6 +997,9 @@
             $('#level1-data').html(table_data.join(''));
 
             const mbsjOption1 = mbsjChart1.getOption();
+            chart_mbsj_data.xData.push('收益金额');
+            chart_mbsj_data.ctrlData.push(info.ctrl_profit ? ZhCalc.round(ZhCalc.div(info.ctrl_profit, 10000), 0) : 0);
+            chart_mbsj_data.realData.push(info.real_profit ? ZhCalc.round(ZhCalc.div(info.real_profit, 10000), 0) : 0);
             mbsjOption1.xAxis[0].data = chart_mbsj_data.xData;
             mbsjOption1.series[0].data = chart_mbsj_data.ctrlData;
             mbsjOption1.series[1].data = chart_mbsj_data.realData;

+ 3 - 1
app/view/template/cost.ejs

@@ -13,9 +13,11 @@
                     <div id="detail-ctrl" style="display: none;">
                         <a href="javascript: void(0);" class="btn btn-sm btn-light text-primary" id="reset"> 重置</a>
                         <a href="javascript: void(0);" class="btn btn-sm btn-light text-primary" id="save"> 保存</a>
-                        <a href="javascript: void(0);" class="btn btn-sm btn-light text-primary" id="export"> 导出</a>
                         <a href="javascript: void(0);" class="btn btn-sm btn-light text-primary" id="import"> 导入</a>
                     </div>
+                    <div>
+                        <a href="javascript: void(0);" class="btn btn-sm btn-light text-primary" id="export"> 导出</a>
+                    </div>
                 </div>
             </div>
         </div>

+ 3 - 1
app/view/template/pos_calc.ejs

@@ -23,9 +23,11 @@
                     <div id="detail-ctrl" style="display: none;">
                         <a href="javascript: void(0);" class="btn btn-sm btn-light text-primary" id="reset"> 重置</a>
                         <a href="javascript: void(0);" class="btn btn-sm btn-light text-primary" id="save"> 保存</a>
-                        <a href="javascript: void(0);" class="btn btn-sm btn-light text-primary" id="export"> 导出</a>
                         <a href="javascript: void(0);" class="btn btn-sm btn-light text-primary" id="import"> 导入</a>
                     </div>
+                    <div>
+                        <a href="javascript: void(0);" class="btn btn-sm btn-light text-primary" id="export"> 导出</a>
+                    </div>
                     <div id="detail-user-info" class="ml-auto"></div>
                 </div>
             </div>

+ 2 - 1
sql/update.sql

@@ -22,7 +22,8 @@ ADD COLUMN `cost_ledger_col_set` json NULL COMMENT '成本报审-列设置' AFTE
 
 ALTER TABLE `zh_cost_stage_analysis`
 ADD COLUMN `has_detail` int(1) NOT NULL DEFAULT 0 COMMENT '是否含有明细' AFTER `calc_type`,
-ADD COLUMN `import_cost_id` varchar(5000) NOT NULL DEFAULT '' COMMENT '导入的成本id' AFTER `has_detail`;
+ADD COLUMN `import_cost_id` varchar(5000) NOT NULL DEFAULT '' COMMENT '导入的成本id' AFTER `has_detail`,
+ADD COLUMN `import_cost_type` tinyint(4) UNSIGNED NOT NULL DEFAULT 0 COMMENT '导入的成本类型(0无明细,1普通,2合同)' AFTER `import_cost_id`;
 
 CREATE TABLE `zh_budget_real`  (
   `id` varchar(100) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL COMMENT '自增id',