浏览代码

动态投资,资料归集,关联标段调整

MaiXinRong 1 年之前
父节点
当前提交
8bdf0ec1c9

+ 3 - 86
app/public/js/budget_list.js

@@ -179,92 +179,9 @@ $(document).ready(() => {
         table: '#budgetList',
     });
 
-    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('/subproj/rela/save', { id: curBudget.id, rela_tender: rela.join(',') }, function () {
-                    $(`[bid=${curBudget.bid}]`)[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(`/subproj/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 = new srObject({
+        getRelaProject: function() {
+            return curBudget;
         }
-    }
-    let srSelect;
-    $('#select-rela').on('shown.bs.modal', () => {
-        if (!srSelect) srSelect = new srObject();
-        srSelect.init();
     });
 });

+ 3 - 87
app/public/js/file_list.js

@@ -166,93 +166,9 @@ $(document).ready(() => {
         source: projectList,
         table: '#projectList',
     });
-
-    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('/subproj/rela/save', { id: curProject.id, rela_tender: rela.join(',') }, function () {
-                    $(`[tree_id=${curProject.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(`/subproj/rela?id=${curProject.id}`, {}, tenders => {
-                const rela = curProject.rela_tender ? curProject.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 = new srObject({
+        getRelaProject: function() {
+            return curProject;
         }
-    }
-    let srSelect;
-    $('#select-rela').on('shown.bs.modal', () => {
-        if (!srSelect) srSelect = new srObject();
-        srSelect.init();
     });
 });

+ 121 - 0
app/public/js/shares/select_rela_tender.js

@@ -0,0 +1,121 @@
+class srObject {
+    constructor(setting) {
+        this.firstInit = true;
+        this.setting = setting;
+        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-source-spread')[0]);
+        this.sheet = this.spread.getActiveSheet();
+        SpreadJsObj.initSheet(this.sheet, srSpreadSetting);
+
+        const srResultSpreadSetting = {
+            cols: [
+                {title: '名称', field: 'name', hAlign: 0, width: 180, formatter: '@', },
+            ],
+            emptyRows: 0,
+            headRows: 1,
+            headRowHeight: [32],
+            defaultRowHeight: 21,
+            headerFont: '12px 微软雅黑',
+            font: '12px 微软雅黑',
+            headColWidth: [30],
+            readOnly: true,
+        };
+        this.resultSpread = SpreadJsObj.createNewSpread($('#sr-result-spread')[0]);
+        this.resultSheet = this.resultSpread.getActiveSheet();
+        SpreadJsObj.initSheet(this.resultSheet, srResultSpreadSetting);
+
+        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);
+            self.refreshResult();
+        });
+
+        $('#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);
+            self.refreshResult();
+        });
+        $('#select-rela-ok').click(() => {
+            const rela = self.getSelects();
+            postData('/subproj/rela/save', { id: self.relaProject.id, rela_tender: rela.join(',') }, function () {
+                $(`[tree_id=${self.relaProject.id}]`)[0].setAttribute('rela-tender', rela.join(','));
+                $('#select-rela').modal('hide');
+            });
+        });
+
+        $('#select-rela').on('shown.bs.modal', () => {
+            self.init(self.setting.getRelaProject());
+        });
+    }
+    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;
+    }
+    refreshResult() {
+        const result = [];
+        for (const n of this.selectTree.nodes) {
+            if ((!n.children || n.children.length === 0) && n.selected) result.push(n);
+        }
+        SpreadJsObj.loadSheetData(this.resultSheet, SpreadJsObj.DataType.Data, result);
+    }
+    init(relaProject) {
+        $('#sr-select-all')[0].checked = false;
+        const self = this;
+        if (this.firstInit) {
+            this.spread.refresh();
+            this.resultSpread.refresh();
+            this.firstInit = false;
+        }
+        self.relaProject = relaProject;
+        postData(`/subproj/rela?id=${relaProject.id}`, {}, tenders => {
+            const rela = relaProject.rela_tender ? relaProject.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);
+            self.refreshResult();
+        });
+    }
+}

+ 1 - 22
app/view/budget/list_modal.ejs

@@ -20,25 +20,4 @@
         </div>
     </div>
 </div>
-<!--弹出关联标段-->
-<div class="modal fade" id="select-rela" data-backdrop="static">
-    <div class="modal-dialog" role="document">
-        <div class="modal-content">
-            <div class="modal-header">
-                <h5 class="modal-title">选择关联标段</h5>
-            </div>
-            <div class="modal-body">
-                <h5>可选标段</h5>
-                <div id="sr-spread" style="height: 300px"></div>
-            </div>
-            <div class="modal-footer">
-                <div class="form-check form-check-inline">
-                    <input class="form-check-input" type="checkbox" id="sr-select-all">
-                    <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" id="select-rela-ok">确定</button>
-            </div>
-        </div>
-    </div>
-</div>
+<% include ../shares/select_rela_tender_modal.ejs %>

+ 1 - 22
app/view/file/modal.ejs

@@ -1,22 +1 @@
-<!--弹出关联标段-->
-<div class="modal fade" id="select-rela" data-backdrop="static">
-    <div class="modal-dialog" role="document">
-        <div class="modal-content">
-            <div class="modal-header">
-                <h5 class="modal-title">选择关联标段</h5>
-            </div>
-            <div class="modal-body">
-                <h5>可选标段</h5>
-                <div id="sr-spread" style="height: 300px"></div>
-            </div>
-            <div class="modal-footer">
-                <div class="form-check form-check-inline">
-                    <input class="form-check-input" type="checkbox" id="sr-select-all">
-                    <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" id="select-rela-ok">确定</button>
-            </div>
-        </div>
-    </div>
-</div>
+<% include ../shares/select_rela_tender_modal.ejs %>

+ 112 - 0
app/view/settle/list.ejs

@@ -0,0 +1,112 @@
+<% include ../tender/tender_sub_menu.ejs %>
+<div class="panel-content">
+    <div class="panel-title">
+        <div class="title-main d-flex">
+            <% include ../tender/tender_sub_mini_menu.ejs %>
+            <h2>
+                结算期列表
+            </h2>
+            <div class="ml-auto">
+                <% if (ctx.session.sessionUser.accountId === ctx.tender.data.user_id && (settles.length === 0 || settles[0].status === auditConst.status.checked) && checkedStageCount > 0) { %>
+                <a href="#add-qi" data-toggle="modal" data-target="#add-qi" class="btn btn-primary btn-sm">开始新一期</a>
+                <% } %>
+            </div>
+        </div>
+    </div>
+    <div class="content-wrap">
+        <div class="c-body">
+            <div class="sjs-height-0">
+                <table class="table table-bordered table-hover">
+                    <thead>
+                    <tr>
+                        <th class="text-center" width="70px">结算期数</th>
+                        <th class="text-center" width="70px">结算月份</th>
+                        <th class="text-center" width="70px">结算周期</th>
+                        <th class="text-center" width="100px" name="contract_tp">本期合同结算</th>
+                        <th class="text-center" width="100px" name="qc_tp">本期变更结算</th>
+                        <th class="text-center" width="100px" name="tp">本期完成结算</th>
+                        <th class="text-center" width="100px" name="pre_tp">截止上期完成结算</th>
+                        <th class="text-center" width="100px" name="end_tp">截止本期完成结算</th>
+                        <th class="text-center" width="200px">审批进度</th>
+                        <th class="text-center" width="90px">操作</th>
+                    </tr>
+                    </thead>
+                    <tbody>
+                    <% for (const [i,s] of settles.entries()) { %>
+                    <tr>
+                        <td>
+                            <a href="<%- '/tender/' + ctx.tender.id + '/settle/' + s.order %>" target="_blank">第 <%- s.order %> 期</a>
+                            <% if ((i === 0 || (settles[i-1] && settles[i-1].status !== auditConst.status.checked)) && s.user_id === ctx.session.sessionUser.accountId) { %>
+                            <a href="#edit" class="edit-stage" data-index="<%- i %>" data-toggle="modal" data-target="#edit"><i class="fa fa-pencil-square-o "></i></a>
+                            <% } %>
+                        </td>
+                        <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.split('~')[1] : s.period)  : '') %>
+                            </span>
+                        </td>
+                        <% if (ctx.tender.info.display.thousandth) { %>
+                        <td class="text-right"><%- (s.contract_tp ? ctx.helper.formatNum(s.contract_tp, '#,##0.######') : '')%></td>
+                        <td class="text-right"><%- (s.qc_tp ? ctx.helper.formatNum(s.qc_tp, '#,##0.######') : '')%></td>
+                        <td class="text-right"><%- (s.tp ? ctx.helper.formatNum(s.tp, '#,##0.######') : '')%></td>
+                        <td class="text-right"><%- (s.pre_tp ? ctx.helper.formatNum(s.pre_tp, '#,##0.######') : '')%></td>
+                        <td class="text-right"><%- (s.end_tp ? ctx.helper.formatNum(s.end_tp, '#,##0.######') : '')%></td>
+                        <% } else { %>
+                        <td class="text-right"><%- (s.contract_tp ? s.contract_tp : '')%></td>
+                        <td class="text-right"><%- (s.qc_tp ? s.qc_tp : '')%></td>
+                        <td class="text-right"><%- (s.tp ? s.tp : '')%></td>
+                        <td class="text-right"><%- (s.pre_tp ? s.pre_tp : '')%></td>
+                        <td class="text-right"><%- (s.end_tp ? s.end_tp : '')%></td>
+                        <% } %>
+                        <td class="<%- auditConst.auditProgressClass[s.status] %>">
+                            <% if (s.curAuditors.length > 0) { %>
+                            <% if (s.curAuditors[0].audit_type === auditType.key.common) { %>
+                            <a href="#sp-list" data-toggle="modal" data-target="#sp-list" s-order="<%- s.order %>"><%- s.curAuditors[0].name %><%if (s.curAuditors[0].role !== '' && s.curAuditors[0].role !== null) { %>-<%- s.curAuditors[0].role %><% } %></a>
+                            <% } else { %>
+                            <a href="#sp-list" data-toggle="modal" data-target="#sp-list" s-order="<%- s.order %>"><%- ctx.helper.transFormToChinese(s.curAuditors[0].audit_order) + '审' %></a>
+                            <% } %>
+                            <% } %>
+                            <%- auditConst.auditProgress[s.status] %>
+                        </td>
+                        <td class="text-center">
+                            <% if (s.status === auditConst.status.uncheck && s.user_id === ctx.session.sessionUser.accountId) { %>
+                            <a href="<%- '/tender/' + ctx.tender.id + '/settle/' + s.order %>" target="_blank" class="btn <%- auditConst.statusButtonClass[s.status] %> btn-sm"><%- auditConst.statusButton[s.status] %></a>
+                            <% } else if (s.status === auditConst.status.checkNo && s.curAuditors && s.user_id === ctx.session.sessionUser.accountId) { %>
+                            <a href="<%- '/tender/' + ctx.tender.id + '/settle/' + s.order %>" target="_blank" class="btn <%- auditConst.statusButtonClass[s.status] %> btn-sm"><%- auditConst.statusButton[s.status] %></a>
+                            <% } else if (s.status === auditConst.status.checking && s.curAuditors && s.curAuditors.findIndex(x => { return x.aid === ctx.session.sessionUser.accountId; }) >= 0) { %>
+                            <a href="<%- '/tender/' + ctx.tender.id + '/settle/' + s.order %>" target="_blank" class="btn <%- auditConst.statusButtonClass[s.status] %> btn-sm"><%- auditConst.statusButton[s.status] %></a>
+                            <% } else if (s.status === auditConst.status.checkNoPre && s.curAuditors && s.curAuditor2.findIndex(x => { return x.aid === ctx.session.sessionUser.accountId; }) >= 0) { %>
+                            <a href="<%- '/tender/' + ctx.tender.id + '/settle/' + s.order %>" target="_blank" class="btn <%- auditConst.statusButtonClass[s.status] %> btn-sm"><%- auditConst.statusButton[s.status] %></a>
+                            <% } else { %>
+                            <span class="<%- auditConst.auditStringClass[s.status] %>"><%- auditConst.auditString[s.status] %></span>
+                            <% } %>
+                        </td>
+                    </tr>
+                    <% } %>
+                    </tbody>
+                </table>
+            </div>
+        </div>
+    </div>
+</div>
+<script src="/public/js/sub_menu.js"></script>
+<script>
+    const settles = JSON.parse('<%- JSON.stringify(settles) %>');
+    $.subMenu({
+        menu: '#sub-menu', miniMenu: '#sub-mini-menu', miniMenuList: '#mini-menu-list',
+        toMenu: '#to-menu', toMiniMenu: '#to-mini-menu',
+        key: 'menu.1.0.0',
+        miniHint: '#sub-mini-hint', hintKey: 'menu.hint.1.0.1',
+        callback: function (info) {
+            if (info.mini) {
+                $('.panel-title').addClass('fluid');
+                $('#sub-menu').removeClass('panel-sidebar');
+            } else {
+                $('.panel-title').removeClass('fluid');
+                $('#sub-menu').addClass('panel-sidebar');
+            }
+            autoFlashHeight();
+        }
+    });
+</script>

+ 301 - 0
app/view/settle/list_modal.ejs

@@ -0,0 +1,301 @@
+<% if (ctx.session.sessionUser.accountId === ctx.tender.data.user_id && ctx.tender.data.ledger_status === auditConst.status.checked &&
+        (settles.length === 0 || settles[settles.length- 1].status === auditConst.status.checked)) { %>
+<!--弹出添加期-->
+<div class="modal fade" id="add-qi" data-backdrop="static">
+    <div class="modal-dialog" role="document">
+        <form class="modal-content" action="/tender/<%- ctx.tender.id %>/settle/add" method="post" onsubmit="return checkValidSettle(this);">
+            <div class="modal-header">
+                <h5 class="modal-title">添加新一期</h5>
+            </div>
+            <div class="modal-body">
+                <div class="form-group">
+                    <label>期</label>
+                    <input class="form-control form-control-sm" value="第 <%- settles.length + 1 %> 期" type="text" readonly="">
+                </div>
+                <div class="form-group">
+                    <label>结算年月<b class="text-danger">*</b></label>
+                    <input class="datepicker-here form-control form-control-sm" autocomplete="off" readonly placeholder="点击选择年月" data-view="months" data-min-view="months" data-date-format="yyyy-MM" data-language="zh" type="text" name="date" autocomplete="off">
+                </div>
+                <div class="form-group">
+                    <label>结算周期<b class="text-danger">*</b></label>
+                    <input class="datepicker-here form-control form-control-sm" autocomplete="off" readonly placeholder="点击选择时间" data-range="true" data-multiple-dates-separator=" ~ " data-language="zh" type="text" name="period" autocomplete="off">
+                </div>
+            </div>
+            <div class="modal-footer">
+                <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>" />
+                <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
+                <button type="submit" class="btn btn-primary btn-sm" id="add-stage-btn">确定添加</button>
+            </div>
+        </form>
+    </div>
+</div>
+<% } %>
+<!--审批流程/结果-->
+<div class="modal fade" id="sp-list" data-backdrop="static">
+    <div class="modal-dialog modal-lg" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">审批流程</h5>
+            </div>
+            <div class="modal-body">
+                <div class="row">
+                    <div class="col-4 modal-height-500" style="overflow: auto">
+                        <div class="card mt-3">
+                            <ul class="list-group list-group-flush" id="auditor-list">
+                            </ul>
+                        </div>
+                    </div>
+                    <div class="col-8 modal-height-500" style="overflow: auto" id="audit-list">
+                    </div>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
+            </div>
+        </div>
+    </div>
+</div>
+<% if (settles.length > 0 && settles[0].user_id === ctx.session.sessionUser.accountId) { %>
+<!--设置-->
+<div class="modal fade" id="edit" data-backdrop="static">
+    <div class="modal-dialog" role="document">
+        <form class="modal-content" action="/tender/<%- ctx.tender.id %>/settle/save" method="post" onsubmit="return checkValidSettle(this);">
+            <div class="modal-header">
+                <h5 class="modal-title">期编辑</h5>
+            </div>
+            <div class="modal-body">
+                <div class="form-group">
+                    <label>期</label>
+                    <input class="form-control form-control-sm" id="edit-name" value="第 <%- stages[0].order %> 期" type="text" readonly="" name="name">
+                </div>
+                <div class="form-group">
+                    <label>结算年月<b class="text-danger">*</b></label>
+                    <input class="datepicker-here form-control form-control-sm" autocomplete="off" readonly name="date" placeholder="点击选择年月" data-view="months" data-min-view="months" data-date-format="yyyy-MM" data-language="zh" type="text">
+                </div>
+                <div class="form-group">
+                    <label>结算周期<b class="text-danger">*</b></label>
+                    <input class="datepicker-here form-control form-control-sm" autocomplete="off" readonly name="period" placeholder="点击选择时间" data-range="true" data-multiple-dates-separator=" ~ " data-language="zh" type="text">
+                </div>
+            </div>
+            <div class="modal-footer">
+                <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>" />
+                <input type="hidden" name="order" id="edit-order" value="<%- stages[0].order %>">
+                <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
+                <button type="submit" class="btn btn-primary btn-sm" id="edit-ok" >确定修改</button>
+            </div>
+        </form>
+    </div>
+</div>
+<% } %>
+<script src="/public/js/datepicker/datepicker.min.js"></script>
+<script src="/public/js/datepicker/datepicker.zh.js"></script>
+<script src="/public/js/moment/moment.min.js"></script>
+<script>
+    const tenderId = '<%- ctx.tender.id %>';
+    const auditConst = JSON.parse('<%- JSON.stringify(auditConst) %>');
+    const auditType = JSON.parse('<%- JSON.stringify(auditType) %>');
+    $('.datepicker-here').datepicker({
+        autoClose: true,
+    });
+
+    $('.edit-stage').on('click', function () {
+        const index = parseInt($(this).data('index'));
+        const editDate = $('#edit-date').datepicker().data('datepicker');
+        $('#edit-name').val('第 ' + stages[index].order + ' 期');
+        $('#edit-order').val(stages[index].order);
+        if (stages[index].s_time && stages[index].s_time !== '') {
+            editDate.selectDate(new Date(stages[index].s_time));
+        }
+        const period = [];
+        for (const p of stages[index].period.split('~')) {
+            if (p && p !== '') {
+                period.push(new Date(p));
+            }
+        }
+        const editPeriod = $('#edit-period').datepicker().data('datepicker');
+        if (period.length > 0) {
+            editPeriod.selectDate(period);
+        }
+    });
+
+    function checkValidSettle(obj) {
+        const date = $('input[name=date]', obj).val();
+        if (date === '') {
+            toastr.error('请选择结算年月');
+            return false;
+        }
+        const period = $('input[name=period]', obj).val();
+        if (period === '') {
+            toastr.error('请选择结算周期');
+            return false;
+        }
+
+        const startDate = period.split('~')[0];
+        const endDate = period.split('~')[1] ? period.split('~')[1] : null;
+
+        if ((startDate.indexOf(date) === -1 && !endDate) || (startDate.indexOf(date) === -1 && endDate && endDate.indexOf(date) === -1)) {
+            toastr.error('所选日期与当前月份不匹配,请重新选择');
+            $('input[name="period"]', obj).parents('.form-group').find('.text-danger').remove();
+            $('input[name="period"]', obj).parents('.form-group').append('<small class="text-danger">所选日期与当前月份不匹配,请重新选择</small>');
+            return false;
+        }
+        return true;
+    }
+
+    $('#audit-list').on('click', 'a', function() {
+        const type = $(this).data('target')
+        const auditCard = $(this).parent().parent()
+        if (type === 'show') {
+            $(this).data('target', 'hide')
+            auditCard.find('.fold-card').slideDown('swing', () => {
+                auditCard.find('#end-target').text($(this).data('idx') + '#')
+                auditCard.find('#fold-btn').text('收起历史审核记录')
+            })
+        } else {
+            $(this).data('target', 'show')
+            auditCard.find('.fold-card').slideUp('swing', () => {
+                auditCard.find('#end-target').text('1#')
+                auditCard.find('#fold-btn').text('展开历史审核记录')
+            })
+        }
+    });
+
+    const getGroupAuditHtml = function (group) {
+        return group.map(u => { return `<small class="d-inline-block text-dark mx-1" title="${u.role}" data-auditorId="${u.aid}">${u.name}</small>`; }).join('');
+    };
+    const getAuditTypeHtml = function (type) {
+        if (type === auditType.key.common) return '';
+        return `<div class="li-subscript"><span class="badge badge-pill badge-${auditType.info[type].class} p-1 badge-bg-small"><small>${auditType.info[type].short}</small></span></div>`;
+    };
+    const getAuditTypeText = function (type) {
+        if (type === auditType.key.common) return '';
+        return `<span class="text-${auditType.info[type].class}">${auditType.info[type].long}</span>`;
+    };
+    const getAuditorsHtml = function (auditors) {
+        const auditorsHTML = [];
+        auditors.forEach((group, idx) => {
+            if (idx === 0) {
+                auditorsHTML.push(`<li class="list-group-item d-flex justify-content-between align-items-center">
+                    <span class="mr-1"><i class="fa fa fa-play-circle fa-rotate-90"></i></span>
+                <span class="text-muted">${getGroupAuditHtml(group)}</span>
+                <span class="badge badge-light badge-pill ml-auto"><small>原报</small></span>
+                </li>`);
+            } else if(idx === auditors.length -1 && idx !== 0) {
+                auditorsHTML.push(`<li class="list-group-item d-flex justify-content-between align-items-center">
+                    <span class="mr-1"><i class="fa fa fa-stop-circle fa-rotate-90"></i></span>
+                <span class="text-muted">${getGroupAuditHtml(group)}</span>
+                <div class="d-flex ml-auto">
+                ${getAuditTypeHtml(group[0].audit_type)}
+                <span class="badge badge-light badge-pill ml-auto"><small>终审</small></span>
+                </div>
+                </li>`);
+            } else {
+                auditorsHTML.push(`<li class="list-group-item d-flex justify-content-between align-items-center">
+                    <span class="mr-1"><i class="fa fa fa-chevron-circle-down"></i></span>
+                <span class="text-muted">${getGroupAuditHtml(group)}</span>
+                <div class="d-flex ml-auto">
+                ${getAuditTypeHtml(group[0].audit_type)}
+                <span class="badge badge-light badge-pill"><small>${transFormToChinese(idx)}审</small></span>
+                </div>
+                </li>`);
+            }
+        });
+        return auditorsHTML;
+    }
+    const getAuditHistroyHtml = function (auditHistory) {
+        const historyHTML = [];
+        auditHistory.forEach((his, idx) => {
+            if (idx === auditHistory.length - 1 && auditHistory.length !== 1) {
+                historyHTML.push(`<div class="text-right"><a href="javascript: void(0);" id="fold-btn" data-target="show">展开历史审批流程</a></div>`);
+            }
+            historyHTML.push(`<div class="${idx < auditHistory.length - 1 ? 'fold-card' : ''}">`);
+            historyHTML.push(`<div class="text-center text-muted">${idx+1}#</div>`);
+            historyHTML.push(`<ul class="timeline-list list-unstyled mt-2 ${ idx === auditHistory.length - 1 && auditHistory.length !== 1 ? 'last-auditor-list' : '' }">`);
+            his.forEach((group) => {
+                historyHTML.push(`<li class="timeline-list-item pb-2 ${ group.status === auditConst.status.uncheck && idx === auditHistory.length - 1 && auditHistory.length !== 1 ? 'is_uncheck' : ''}">`);
+                if (group.auditYear) {
+                    historyHTML.push(`<div class="timeline-item-date">${group.auditYear}<span>${group.auditDate}</span><span>${group.auditTime}</span></div>`);
+                }
+                if (group.audit_order < his.length - 1) {
+                    historyHTML.push('<div class="timeline-item-tail"></div>');
+                }
+                if (group.status === auditConst.status.checked) {
+                    historyHTML.push('<div class="timeline-item-icon bg-success text-light"><i class="fa fa-check"></i></div>');
+                } else if (group.status === auditConst.status.checkNo || group.status === auditConst.status.checkNoPre || group.status === auditConst.status.checkCancel) {
+                    historyHTML.push('<div class="timeline-item-icon bg-warning text-light"><i class="fa fa-level-up"></i></div>');
+                } else if (group.status === auditConst.status.checking) {
+                    historyHTML.push('<div class="timeline-item-icon bg-warning text-light"><i class="fa fa-ellipsis-h"></i></div>');
+                } else {
+                    historyHTML.push('<div class="timeline-item-icon bg-secondary text-light"></div>');
+                }
+
+                historyHTML.push('<div class="timeline-item-content">');
+                if (group.audit_order > 0) {
+                    const statuStr = group.status !== auditConst.status.uncheck ?
+                        `<span class="pull-right ${auditConst.statusClass[group.status]}">${auditConst.statusString[group.status]}</span>` : '';
+                    historyHTML.push(`<div class="py-1">
+                        <span class="text-black-50">
+                        ${ !group.is_final ? group.audit_order + '' : '终' }审 ${getAuditTypeText(group.audit_type)}
+                        </span>
+                        ${statuStr}
+                    </div>`);
+                } else {
+                    historyHTML.push(` <div class="py-1">
+                        <span class="text-black-50">原报</span>
+                        <span class="pull-right text-success">${idx !== 0 ? '重新' : '' }上报审批</span>
+                    </div>`);
+                }
+                historyHTML.push('<div class="card"><div class="card-body px-3 py-0">');
+                for (const [i, auditor] of group.auditors.entries()) {
+                    historyHTML.push(`<div class="card-text p-2 py-3 row ${ ( i > 0 ? 'border-top' : '') }">`);
+                    historyHTML.push(`<div class="col"><span class="h6">${auditor.name}</span><span class="text-muted ml-1">${auditor.role}</span></div>`);
+                    historyHTML.push('<div class="col">');
+                    if (auditor.status === auditConst.status.checked) {
+                        historyHTML.push('<span class="pull-right text-success"><i class="fa fa-check-circle"></i></span>');
+                    } if (auditor.status === auditConst.status.checkNo || auditor.status === auditConst.status.checkNoPre || auditor.status === auditConst.status.checkCancel) {
+                        historyHTML.push('<span class="pull-right text-warning"><i class="fa fa-share-square fa-rotate-270"></i></span>');
+                    }
+                    historyHTML.push('</div>');
+                    if (group.audit_order > 0 && auditor.opinion) {
+                        historyHTML.push(`<div class="col-12 py-1 bg-light"><i class="fa fa-commenting-o mr-1"></i>${auditor.opinion}</div>`);
+                    }
+                    historyHTML.push('</div>');
+                }
+                historyHTML.push('</div></div>');
+                historyHTML.push('</div>');
+                historyHTML.push('</li>');
+            });
+            historyHTML.push('</div>');
+            historyHTML.push('</ul>');
+        });
+        return historyHTML.join('');
+    }
+    // 获取审批流程
+    $('a[data-target="#sp-list" ]').on('click', function () {
+        postData('/tender/' + tenderId + '/settle/auditors', { order: $(this).attr('s-order') }, function (result) {
+            $('#auditor-list').html(getAuditorsHtml(result.hisUserGroup));
+            $('#audit-list').html(getAuditHistroyHtml(result.auditHistory));
+        });
+    });
+
+    $(window).resize(checkTableWidth);
+    function checkTableWidth() {
+        if($('table th[name=contract_tp]').outerWidth() < 107) {
+            $('table th[name=contract_tp]').html('本期<br>合同计量');
+            $('table th[name=qc_tp]').html('本期数量<br>变更计量');
+            $('table th[name=tp]').html('本期<br>完成计量');
+            $('table th[name=pre_tp]').html('截止上期<br>完成计量');
+            $('table th[name=end_tp]').html('截止本期<br>完成计量');
+        } else {
+            $('table th[name=contract_tp]').html('本期合同计量');
+            $('table th[name=qc_tp]').html('本期数量变更计量');
+            $('table th[name=tp]').html('本期完成计量');
+            $('table th[name=pre_tp]').html('截止上期完成计量');
+            $('table th[name=end_tp]').html('截止本期完成计量');
+        }
+    }
+
+    $(function () {
+        checkTableWidth();
+    });
+</script>

+ 30 - 0
app/view/shares/select_rela_tender_modal.ejs

@@ -0,0 +1,30 @@
+<!--弹出关联标段-->
+<div class="modal fade" id="select-rela" data-backdrop="static">
+    <div class="modal-dialog modal-lg" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">选择关联标段</h5>
+            </div>
+            <div class="modal-body">
+                <div class="row">
+                    <div class="col-7">
+                        <h5>可选标段 </h5>
+                        <div class="modal-height-300" id="sr-source-spread"></div>
+                    </div>
+                    <div class="col-5">
+                        <h5>已选标段 </h5>
+                        <div class="modal-height-300" id="sr-result-spread"></div>
+                    </div>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <div class="form-check form-check-inline">
+                    <input class="form-check-input" type="checkbox" id="sr-select-all">
+                    <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" id="select-rela-ok">确定</button>
+            </div>
+        </div>
+    </div>
+</div>

+ 2 - 0
config/web.js

@@ -1088,6 +1088,7 @@ const JsFiles = {
                     '/public/js/shares/tenders2tree.js',
                     '/public/js/shares/show_level.js',
                     '/public/js/spreadjs_rela/spreadjs_zh.js',
+                    '/public/js/shares/select_rela_tender.js',
                     '/public/js/file_list.js',
                 ],
                 mergeFile: 'file_list',
@@ -1120,6 +1121,7 @@ const JsFiles = {
                     '/public/js/shares/tenders2tree.js',
                     '/public/js/shares/show_level.js',
                     '/public/js/spreadjs_rela/spreadjs_zh.js',
+                    '/public/js/shares/select_rela_tender.js',
                     '/public/js/budget_list.js',
                 ],
                 mergeFile: 'budget_list',