Sfoglia il codice sorgente

手机端审批期和wap页面 no.1 up

laiguoran 5 anni fa
parent
commit
32f01318ff

+ 199 - 0
app/controller/wap_controller.js

@@ -0,0 +1,199 @@
+'use strict';
+
+/**
+ * 登录页面控制器
+ *
+ * @author CaiAoLin
+ * @date 2017/11/15
+ * @version
+ */
+const URL = require('url');
+const maintainConst = require('../const/maintain');
+const auditConst = require('../const/audit');
+
+module.exports = app => {
+
+    class WapController extends app.BaseController {
+
+        /**
+         * 登录页面
+         *
+         * @param {Object} ctx - egg全局页面
+         * @return {void}
+         */
+        async index(ctx) {
+            const errorMessage = ctx.session.loginError;
+            // 显示完删除
+            ctx.session.loginError = null;
+            // 获取系统维护信息
+            const maintainData = await ctx.service.maintain.getDataById(1);
+
+            if (!ctx.app.config.is_debug) {
+                await ctx.service.maintain.syncMaintainData();
+            }
+
+            const renderData = {
+                maintainData,
+                maintainConst,
+                errorMessage,
+            };
+            await ctx.render('wap/login.ejs', renderData);
+        }
+
+        /**
+         * 登录操作
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        async login(ctx) {
+            let loginType = ctx.request.body.type;
+
+            try {
+                loginType = parseInt(loginType);
+                const result = await ctx.service.projectAccount.accountLogin(ctx.request.body, loginType);
+
+                if (!result) {
+                    throw '用户名或密码错误';
+                }
+
+                if (result === 2) {
+                    throw '该账号已被停用,请联系销售人员';
+                }
+
+                // 调用 rotateCsrfSecret 刷新用户的 CSRF token
+                ctx.rotateCsrfSecret();
+
+                // 判断是否已经有对应用户信息,没有则跳转初始化页面
+                const needBoot = await ctx.service.customer.isNeedBoot(ctx.request.body);
+                const url = needBoot ? '/boot' : '/wap/dashboard';
+
+                const query = URL.parse(ctx.request.header.referer, true).query;
+                ctx.redirect(query.referer ? query.referer : url);
+            } catch (error) {
+                this.log(error);
+                ctx.session.loginError = error;
+                ctx.redirect('/wap');
+            }
+        }
+
+        /**
+         * 退出登录
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        async logout(ctx) {
+            // 删除session并跳转
+            ctx.session = null;
+            ctx.redirect('/wap');
+        }
+
+
+        /**
+         * 待办页
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        async dashboard(ctx) {
+            // 获取待审批的期
+            const auditStages = await ctx.service.stageAudit.getAuditStageByWap(ctx.session.sessionUser.accountId);
+            for (const audit of auditStages) {
+                await this.ctx.service.stage.checkStageGatherData(audit);
+                audit.gather_tp = ctx.helper.add(audit.contract_tp, audit.qc_tp);
+                audit.end_contract_tp = ctx.helper.add(audit.contract_tp, audit.pre_contract_tp);
+                audit.end_qc_tp = ctx.helper.add(audit.qc_tp, audit.pre_qc_tp);
+                audit.end_gather_tp = ctx.helper.add(audit.end_contract_tp, audit.end_qc_tp);
+                audit.pre_gather_tp = ctx.helper.add(audit.pre_contract_tp, audit.pre_qc_tp);
+            }
+            const renderData = {
+                auditStages,
+            };
+            await ctx.render('wap/dashboard.ejs', renderData);
+        }
+
+        /**
+         * 标段列表页
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        async list(ctx) {
+            try {
+                // 获取用户新建标段权利
+                const accountInfo = await this.ctx.service.projectAccount.getDataById(this.ctx.session.sessionUser.accountId);
+                const userPermission = accountInfo !== undefined && accountInfo.permission !== '' ? JSON.parse(accountInfo.permission) : null;
+
+                const tenderList = await this.ctx.service.tender.getList('', userPermission);
+
+                for (const t of tenderList) {
+                    if (t.user_id === this.ctx.session.sessionUser.accountId && (
+                        t.ledger_status === auditConst.ledger.status.checkNo || t.ledger_status === auditConst.ledger.status.uncheck)) {
+                        const sum = await this.ctx.service.ledger.addUp({tender_id: t.id/*, is_leaf: true*/});
+                        t.total_price = sum.total_price;
+                        t.deal_tp = sum.deal_tp;
+                    }
+                    if (t.ledger_status === auditConst.ledger.status.checked) {
+                        t.lastStage = await this.ctx.service.stage.getLastestStage(t.id, true);
+                        if (t.lastStage) {
+                            await this.ctx.service.stage.checkStageGatherData(t.lastStage);
+                        }
+                    }
+                }
+                const categoryData = await this.ctx.service.category.getAllCategory(this.ctx.session.sessionProject.id);
+                const valuations = await this.ctx.service.valuation.getProjectValidValuation(this.ctx.session.sessionProject.id);
+                const renderData = {
+                    tenderList,
+                    categoryData,
+                    auditConst,
+                    userPermission,
+                    valuations,
+                    uid: this.ctx.session.sessionUser.accountId,
+                    pid: this.ctx.session.sessionProject.id,
+                };
+                await ctx.render('wap/list.ejs', renderData);
+            } catch (err) {
+                this.log(err);
+                this.ctx.redirect('/wap/dashboard');
+            }
+        }
+
+        /**
+         * 标段详细页
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        async tender(ctx) {
+            try {
+                const renderData = {
+                    tender: ctx.tender.data,
+                    auditConst: auditConst.stage,
+                };
+                renderData.stages = await ctx.service.stage.getValidStages(ctx.tender.id);
+                if (renderData.stages.length > 0) {
+                    for (const s of renderData.stages) {
+                        // s.curAuditor = null;
+                        // 根据期状态返回展示用户
+                        s.curAuditor = await ctx.service.stageAudit.getAuditorByStatus(s.id, s.status, s.times);
+                        if (s.status === auditConst.stage.status.checkNoPre) {
+                            s.curAuditor2 = await ctx.service.stageAudit.getAuditorByStatus(s.id, auditConst.stage.status.checking);
+                        }
+                    }
+                    renderData.stage = renderData.stages[0];
+                    renderData.stage.user = await ctx.service.projectAccount.getAccountInfoById(renderData.stages[0].user_id);
+                    renderData.stage.auditors = await ctx.service.stageAudit.getAuditors(renderData.stages[0].id, renderData.stages[0].times);
+                    // 获取审批流程中左边列表
+                    renderData.stage.auditors2 = await ctx.service.stageAudit.getAuditGroupByList(renderData.stages[0].id, renderData.stages[0].times);
+                }
+                await ctx.render('wap/tender.ejs', renderData);
+            } catch (err) {
+                this.log(err);
+                ctx.redirect('/wap/list');
+            }
+        }
+    }
+
+    return WapController;
+};

+ 16 - 1
app/extend/helper.js

@@ -958,4 +958,19 @@ module.exports = {
         }
         return o;
     },
-};
+
+    /**
+     * 短链接生成
+     * @param url
+     * @returns {*}
+     */
+    async urlToShort(url) {
+        const apiUrl = 'https://api.uomg.com/api/long2dwz';
+        const data = {
+            dwzapi: 'tcn',
+            url,
+        };
+        const result = await this.sendRequest(apiUrl, data, 'get');
+        return result && result.code && result.code === 1 ? result.ae_url : url;
+    },
+}

+ 23 - 0
app/public/css/wap/main.css

@@ -0,0 +1,23 @@
+/*bootstrap 初始化*/
+.bg-dark{
+  background-color:#192948!important;
+}
+.pb-6,.py-6{
+ padding-bottom: 4.5rem !important;
+}
+.pt-6,.py-6{
+ padding-top: 4.5rem !important;
+}
+/**/
+.login-body{
+  background: linear-gradient(#192948,#33425b)
+}
+.in-1{padding-left:5px!important}
+.in-2{padding-left:21px!important}
+.in-3{padding-left:42px!important}
+.in-4{padding-left:63px!important}
+.in-5{padding-left:84px!important}
+.in-6{padding-left:105px!important}
+.bg-gray {
+    background-color: #bbb !important;
+}

BIN
app/public/images/favicon.ico


BIN
app/public/images/loginlogo.png


BIN
app/public/images/logo.png


+ 244 - 0
app/public/js/wap.js

@@ -0,0 +1,244 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Mai
+ * @date 2018/10/11
+ * @version
+ */
+
+const EmptyTenderHtml = [
+    '',
+];
+const tenderTree = [];
+let parentId = 0;
+
+// 查询方法
+function findNode (key, value, arr) {
+    for (const a of arr) {
+        if (a[key] && a[key] === value) {
+            return a;
+        }
+    }
+}
+function getPId(level) {
+    if (level !== 1) {
+        const p = findNode('level', level - 1, levelNodes);
+        if (p) {
+            return p.lid
+        } else {
+            return 1;
+        }
+    } else {
+        return 2;
+    }
+}
+// 分类数据排序
+function sortCategory() {
+    category.sort(function (a, b) {
+        return a.level ? (b.level ? a.level - b.level : -1) : a.id - b.id;
+    });
+}
+function calculateParent(node) {
+    if (node.children && node.cid) {
+        node.end_qc_tp = 0;
+        node.pre_gather_tp = 0;
+        node.gather_tp = 0;
+        node.sum_tp = 0;
+        node.lastStage = 0;
+        for (const c of node.children) {
+            calculateParent(c);
+            node.end_qc_tp = ZhCalc.add(node.end_qc_tp, c.end_qc_tp);
+            node.pre_gather_tp = ZhCalc.add(node.pre_gather_tp, c.pre_gather_tp);
+            node.gather_tp = ZhCalc.add(node.gather_tp, c.gather_tp);
+            node.sum_tp = ZhCalc.add(node.sum_tp, c.sum_tp);
+            node.lastStage = c.cid
+                ? Math.max(node.lastStage, c.lastStage)
+                : (c.lastStage ? Math.max(node.lastStage, c.lastStage.order) : node.lastStage);
+        }
+    }
+}
+// 初始化TenderTree数据
+function initTenderTree () {
+    const levelCategory = category.filter(function (c) {
+        return c.level && c.level > 0;
+    });
+    function findCategoryNode(cid, value, array) {
+        for (const a of array) {
+            if (a.cid === cid && a.vid === value) {
+                return a;
+            }
+        }
+    }
+    function getCategoryNode(category, value, parent, i = null) {
+        const array = parent ?  parent.children : tenderTree;
+        let cate = findCategoryNode(category.id, value, array);
+        if (!cate) {
+            const cateValue = findNode('id', value, category.value);
+            if (!cateValue) return null;
+            cate = {
+                cid: category.id,
+                vid: value,
+                name: cateValue.value,
+                children: [],
+                level: i ? i : category.level,
+                sort_id: ++parentId,
+            };
+            array.push(cate);
+        }
+        return cate;
+    }
+    function loadTenderCategory (tender) {
+        let tenderCategory = null;
+        for (const [index, lc] of levelCategory.entries()) {
+            const tenderCate = findNode('cid', lc.id, tender.category);
+            if (tenderCate) {
+                tenderCategory = getCategoryNode(lc, tenderCate.value, tenderCategory);
+            } else {
+                if (index === 0 && tender.category) {
+                    for (const [i,c] of tender.category.entries()) {
+                        const cate = findNode('id', c.cid, category);
+                        tenderCategory = getCategoryNode(cate, c.value, tenderCategory, i+1);
+                    }
+                }
+                return tenderCategory;
+            }
+        }
+        return tenderCategory;
+    }
+    function calculateTender(tender) {
+        if (tender.lastStage) {
+            tender.end_qc_tp = ZhCalc.add(tender.lastStage.pre_qc_tp, tender.lastStage.qc_tp);
+            tender.pre_gather_tp = ZhCalc.add(tender.lastStage.pre_contract_tp, tender.lastStage.pre_qc_tp);
+            tender.gather_tp = ZhCalc.add(tender.lastStage.contract_tp, tender.lastStage.qc_tp);
+            tender.sum_tp = ZhCalc.add(tender.total_price, tender.end_qc_tp);
+        } else {
+            tender.sum_tp = tender.total_price;
+        }
+    }
+    tenderTree.splice(0, tenderTree.length);
+    for (const t of tenders) {
+        calculateTender(t);
+        t.valid = true;
+        delete t.level;
+        if (t.category && levelCategory.length > 0) {
+            const parent = loadTenderCategory(t);
+            if (parent) {
+                t.level = parent.level + 1;
+                parent.children.push(t);
+            } else {
+                tenderTree.push(t);
+            }
+        } else {
+            tenderTree.push(t);
+        }
+    }
+    for (const t of tenderTree) {
+        calculateParent(t);
+    }
+}
+function getProgressHtml(total, pre, cur) {
+    if (total !== 0) {
+        let preP = ZhCalc.mul(ZhCalc.div(pre, total, 2), 100, 0);
+        let curP = ZhCalc.mul(ZhCalc.div(cur, total, 2), 100, 0);
+        let other = Math.max(ZhCalc.sub(ZhCalc.sub(total, pre), cur), 0);
+        let otherP = Math.max(100 - preP - curP, 0);
+        const html = '<div class="progress">' +
+            '<div class="progress-bar bg-success" style="width: ' + preP + '%;" data-placement="bottom" data-toggle="tooltip" data-original-title="截止上期完成:¥' + pre + '">' + preP + '%</div>' +
+            '<div class="progress-bar bg-info" style="width: ' + curP + '%;" data-placement="bottom" data-toggle="tooltip" data-original-title="本期完成:¥' + cur + '">' + curP + '%</div>' +
+            '<div class="progress-bar bg-gray" style="width: ' + otherP + '%;" data-placement="bottom" data-toggle="tooltip" data-original-title="未完成:¥' + other + '">' + otherP + '%</div>' +
+            '</div>';
+        return html;
+    } else {
+        return '';
+    }
+}
+function recursiveGetTenderNodeHtml (node, arr, pid) {
+    const html = [];
+    html.push('<tr pid="' + pid + '">');
+    // 名称
+    if (node.cid) {
+        html.push('<td class="in-' + node.level + '">');
+        html.push('<span onselectstart="return false" style="{-moz-user-select:none}" class="fold-switch mr-1" title="收起" cid="'+ node.sort_id +'"><i class="fa fa-minus-square-o"></i></span> <i class="fa fa-folder-o"></i> ', node.name);
+        html.push('</td><td></td><td></td>');
+    } else {
+        html.push('<td colspan="3" class="in-' + node.level + '">');
+        html.push('<div class="row">');
+        html.push('<span class="col-8">');
+        html.push('<span class="text-muted mr-2">');
+        html.push(arr.indexOf(node) === arr.length - 1 ? '└' : '├');
+        html.push('</span>');
+        html.push('<a href="javascript: void(0)" id="' + node.id + '">', node.name, '</a></span>');
+        html.push('<span class="col-auto ml-auto"></span>');
+        html.push('</div>');
+        html.push('<div class="d-flex justify-content-between"><span>');
+        // 计量期数
+        if (!node.cid) {
+            html.push(node.lastStage ? '第' + node.lastStage.order + '期' : '台账');
+        }
+        html.push('</span><span>');
+        // 累计合同计量
+        const sum = node.lastStage ? ZhCalc.add(node.total_price, node.lastStage.end_qc_tp) : node.total_price;
+        html.push(node.sum_tp ? node.sum_tp : '');
+        html.push('</span></div>');
+        // 截止本期累计完成/本期完成/未完成
+        if (node.lastStage) {
+            html.push(getProgressHtml(node.sum_tp, node.pre_gather_tp, node.gather_tp));
+        } else {
+            html.push('');
+        }
+        html.push('</td>');
+    }
+    html.push('</tr>');
+    if (node.children) {
+        for (const c of node.children) {
+            html.push(recursiveGetTenderNodeHtml(c, node.children, node.sort_id));
+        }
+    }
+    return html.join('');
+}
+// 根据TenderTree数据获取Html代码
+function getTenderTreeHtml () {
+    const html = [];
+    html.push('<table class="table">');
+    html.push('<thead>', '<tr>');
+    html.push('<th>名称</th>');
+    html.push('<th width="120">计量期数</th>');
+    html.push('<th>总价</th>');
+    html.push('</tr>', '</thead>');
+    if (tenderTree.length > 0) {
+        parentId = 0;
+        for (const t of tenderTree) {
+            html.push(recursiveGetTenderNodeHtml(t, tenderTree, ''));
+        }
+    } else {
+        html.push(EmptyTenderHtml.join(''));
+    }
+    html.push('</table>');
+    return html.join('');
+}
+function bindTenderUrl() {
+    $('.c-body').on('click', 'a', function () {
+        const tenderId = parseInt($(this).attr('id'));
+        const tender = _.find(tenders, function (t) {
+            return t.id === tenderId;
+        });
+        if (tender.measure_type) {
+            window.location.href = '/wap/tender/' + tenderId;
+        } else {
+            // for (const a of $('a', '#jlms')) {
+            //     a.href = '/wap/tender/' + tenderId + '/type?type=' + $(a).attr('mst');
+            // }
+            // $('#jlms').modal('show');
+        }
+    });
+}
+
+$(document).ready(() => {
+    // 初始化标段树结构
+    initTenderTree();
+    $('.c-body').html(getTenderTreeHtml());
+    bindTenderUrl();
+    localHideList();
+});

+ 9 - 0
app/router.js

@@ -312,4 +312,13 @@ module.exports = app => {
     app.post('/gather/tz/load', sessionAuth, 'spssController.loadGatherTz');
     app.get('/gather/stage', sessionAuth, 'spssController.gatherStage');
     app.post('/gather/stage/load', sessionAuth, 'spssController.loadGatherStage');
+
+    // wap页面
+    app.get('/wap', 'wapController.index');
+    app.get('/wap/login', 'wapController.index');
+    app.post('/wap/login', 'wapController.login');
+    app.get('/wap/logout', 'wapController.logout');
+    app.get('/wap/dashboard', sessionAuth, 'wapController.dashboard');
+    app.get('/wap/list', sessionAuth, 'wapController.list');
+    app.get('/wap/tender/:id', sessionAuth, tenderCheck, 'wapController.tender');
 };

+ 24 - 2
app/service/stage_audit.js

@@ -302,8 +302,9 @@ module.exports = app => {
                             const sms = new SMS(this.ctx);
                             const tenderName = await sms.contentChange(tenderInfo.name);
                             const projectName = await sms.contentChange(this.ctx.tender.info.deal_info.buildName);
+                            const result = await this.ctx.helper.urlToShort('http://' + this.ctx.request.header.host + '/wap/tender/' + this.ctx.tender.id + '#shenpi');
                             const ptmsg = projectName !== '' ? '项目「' + projectName + '」标段「' + tenderName + '」' : tenderName;
-                            const content = '【纵横计量支付】' + ptmsg + '第' + stageInfo.order + '期,需要您审批。';
+                            const content = '【纵横计量支付】' + ptmsg + '第' + stageInfo.order + '期,需要您审批。' + result;
                             sms.send(smsUser.auth_mobile, content);
                         }
                     }
@@ -513,7 +514,8 @@ module.exports = app => {
                         const tenderName = await sms.contentChange(tenderInfo.name);
                         const projectName = await sms.contentChange(this.ctx.tender.info.deal_info.buildName);
                         const ptmsg = projectName !== '' ? '项目「' + projectName + '」标段「' + tenderName + '」' : tenderName;
-                        const content = '【纵横计量支付】' + ptmsg + '第' + stageInfo.order + '期,需要您审批。';
+                        const result = await this.ctx.helper.urlToShort('http://' + this.ctx.request.header.host + '/wap/tender/' + this.ctx.tender.id + '#shenpi');
+                        const content = '【纵横计量支付】' + ptmsg + '第' + stageInfo.order + '期,需要您审批。' + result;
                         sms.send(smsUser.auth_mobile, content);
                     }
                 }
@@ -895,6 +897,26 @@ module.exports = app => {
             const rst = await this.db.query(sql, sqlParam);
             return rst;
         }
+
+
+        /**
+         * 取待审批期列表(wap用)
+         *
+         * @param auditorId
+         * @returns {Promise<*>}
+         */
+        async getAuditStageByWap(auditorId) {
+            const sql = 'SELECT sa.`aid`, sa.`times`, sa.`begin_time`, sa.`end_time`, sa.`tid`, sa.`sid`,' +
+                // '    s.`order` As `sorder`, s.`status` As `sstatus`, s.`s_time`, s.`contract_tp`, s.`qc_tp`, s.`pre_contract_tp`, s.`pre_qc_tp`, s.`yf_tp`, s.`pre_yf_tp`, ' +
+                '    s.*,' +
+                '    t.`name`, t.`project_id`, t.`type`, t.`user_id`,' +
+                '    ti.`deal_info` ' +
+                '  FROM ?? AS sa, ?? AS s, ?? As t, ?? AS ti ' +
+                '  WHERE sa.`aid` = ? and sa.`status` = ?' +
+                '    and sa.`sid` = s.`id` and sa.`tid` = t.`id` and ti.`tid` = t.`id`';
+            const sqlParam = [this.tableName, this.ctx.service.stage.tableName, this.ctx.service.tender.tableName, this.ctx.service.tenderInfo.tableName, auditorId, auditConst.status.checking];
+            return await this.db.query(sql, sqlParam);
+        }
     }
 
     return StageAudit;

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

@@ -339,7 +339,7 @@
                                                         <span class="text-success"><small><%- auditors[iA].end_time.toLocaleDateString() %></small> 审批通过</span>
                                                         <p class="card-text"><%- auditors[iA].opinion %></p>
                                                     </div>
-                                                <% } else if (auditors[iA].stauts == auditConst.status.checking) { %>
+                                                <% } else if (auditors[iA].status == auditConst.status.checking) { %>
                                                     <span class="pull-right">审批中</span>
                                                     <h5 class="card-title">
                                                         <i class="<%- (iA < auditors.length - 1 ? 'fa fa-chevron-circle-down' : 'fa fa-stop-circle') %>"></i> <%- auditors[iA].name %> <small class="text-muted"><%- auditors[iA].role %></small><span class="pull-right"><%= auditors[iA].sort === auditors[iA].max_sort ? '终' : ctx.helper.transFormToChinese(auditors[iA].sort) %>审</span>
@@ -1362,7 +1362,7 @@
                                                         <span class="text-success"><small><%- auditors[iA].end_time.toLocaleDateString() %></small> 审批通过</span>
                                                         <p class="card-text"><%- auditors[iA].opinion %></p>
                                                     </div>
-                                                <% } else if (auditors[iA].stauts == auditConst.status.checking) { %>
+                                                <% } else if (auditors[iA].status == auditConst.status.checking) { %>
                                                     <h5 class="card-title">
                                                         <i class="<%- (iA < auditors.length - 1 ? 'fa fa-chevron-circle-down' : 'fa fa-stop-circle') %>"></i> <%- auditors[iA].name %> <small class="text-muted"><%- auditors[iA].role %></small><span class="pull-right"><%= auditors[iA].sort === auditors[iA].max_sort ? '终' : ctx.helper.transFormToChinese(auditors[iA].sort) %>审</span>
                                                     </h5>

+ 29 - 46
app/view/wap/dashboard.ejs

@@ -22,10 +22,10 @@
                 <div class="mr-3">
                     <div class="dropdown">
                       <button class="btn btn-sm btn-light dropdown-toggle" type="button" data-toggle="dropdown">
-                        张三
+                          <%- ctx.session.sessionUser.name.substr(ctx.session.sessionUser.name.length > 2 ? ctx.session.sessionUser.name.length - 2 : 0) %>
                       </button>
                       <div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
-                        <a class="dropdown-item" href="#">退出登录</a>
+                        <a class="dropdown-item" href="/wap/logout">退出登录</a>
                       </div>
                     </div>
                 </div>
@@ -33,60 +33,43 @@
         </nav>
         <!--待审批期列表-->
         <div class="py-6">
-            <h3 class="text-center text-muted">暂无待审批期计量</h3>
-            <div class="card mb-3">
-                <div class="card-header">
-                    建设项目名称
-                </div>
-                <div class="bg-light p-2 px-3"><b>A1标段</b></div>
-                <div class="card-body">
-                    <div class="d-flex justify-content-between"><span>第1期</span><span>2017-10</span></div>
-                    <div class="my-2">
-                        <table class="table table-sm table-bordered">
-                            <tr><th>本期合同计量</th><td class="text-right">34234234.00</td></tr>
-                            <tr><th>本期数量变更计量</th><td class="text-right">34234234.00</td></tr>
-                            <tr><th>本期完成计量</th><td class="text-right">34234234.00</td></tr>
-                            <tr><th>截止上期完成计量</th><td class="text-right">34234234.00</td></tr>
-                            <tr><th>截止本期完成计量</th><td class="text-right">34234234.00</td></tr>
-                            <tr><th>本期应付</th><td class="text-right">34234234.00</td></tr>
-                        </table>
+            <% if (auditStages.length !== 0) { %>
+                <% for (const audit of auditStages) { %>
+                <div class="card mb-3">
+                    <div class="card-header">
+                        <%- JSON.parse(audit.deal_info).buildName %>
                     </div>
-                    <div class="">
-                        <a href="" class="btn btn-block btn-success">审批</a>
+                    <div class="bg-light p-2 px-3"><b><%- audit.name %></b></div>
+                    <div class="card-body">
+                        <div class="d-flex justify-content-between"><span>第<%- audit.order %>期</span><span><%- audit.s_time %></span></div>
+                        <div class="my-2">
+                            <table class="table table-sm table-bordered">
+                                <tr><th>本期合同计量</th><td class="text-right"><%- ctx.helper.formatMoney(audit.contract_tp,2) %></td></tr>
+                                <tr><th>本期数量变更计量</th><td class="text-right"><%- ctx.helper.formatMoney(audit.qc_tp,2) %></td></tr>
+                                <tr><th>本期完成计量</th><td class="text-right"><%- ctx.helper.formatMoney(audit.gather_tp,2) %></td></tr>
+                                <tr><th>截止上期完成计量</th><td class="text-right"><%- ctx.helper.formatMoney(audit.pre_gather_tp,2) %></td></tr>
+                                <tr><th>截止本期完成计量</th><td class="text-right"><%- ctx.helper.formatMoney(audit.end_gather_tp,2) %></td></tr>
+                                <tr><th>本期应付</th><td class="text-right"><%- ctx.helper.formatMoney(audit.yf_tp,2) %></td></tr>
+                            </table>
+                        </div>
+                        <div class="">
+                            <a href="/wap/tender/<%- audit.tid %>" class="btn btn-block btn-success">审批</a>
+                        </div>
                     </div>
                 </div>
-            </div>
-            <div class="card mb-3">
-                <div class="card-header">
-                    建设项目名称
-                </div>
-                <div class="bg-light p-2 px-3"><b>A2标段</b></div>
-                <div class="card-body">
-                    <div class="d-flex justify-content-between"><span>第1期</span><span>2017-10</span></div>
-                    <div class="my-2">
-                        <table class="table table-sm table-bordered">
-                            <tr><th>本期合同计量</th><td class="text-right">34234234.00</td></tr>
-                            <tr><th>本期数量变更计量</th><td class="text-right">34234234.00</td></tr>
-                            <tr><th>本期完成计量</th><td class="text-right">34234234.00</td></tr>
-                            <tr><th>截止上期完成计量</th><td class="text-right">34234234.00</td></tr>
-                            <tr><th>截止本期完成计量</th><td class="text-right">34234234.00</td></tr>
-                            <tr><th>本期应付</th><td class="text-right">34234234.00</td></tr>
-                        </table>
-                    </div>
-                    <div class="">
-                        <a href="" class="btn btn-block btn-success">审批</a>
-                    </div>
-                </div>
-            </div>
+                <% } %>
+            <% } else { %>
+                <h3 class="text-center text-muted">暂无待审批期计量</h3>
+            <% } %>
         </div>
         <!--底栏菜单-->
         <nav class="fixed-bottom navbar-dark bg-light border-top">
           <ul class="nav nav-fill my-2">
               <li class="nav-item">
-                <a class="nav-link active" href="todo.html"><i class="fa fa-check-square-o"></i> 待审批</a>
+                <a class="nav-link active" href="/wap/dashboard"><i class="fa fa-check-square-o"></i> 待审批</a>
               </li>
               <li class="nav-item">
-                <a class="nav-link text-muted" href="biaoduan.html"><i class="fa fa-list-ul"></i> 项目</a>
+                <a class="nav-link text-muted" href="/wap/list"><i class="fa fa-list-ul"></i> 项目</a>
               </li>
             </ul>
         </nav>

+ 126 - 0
app/view/wap/list.ejs

@@ -0,0 +1,126 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">
+    <meta http-equiv="x-ua-compatible" content="ie=edge">
+    <title>项目-计量支付</title>
+    <link rel="stylesheet" href="/public/css/bootstrap/bootstrap.min.css">
+    <link rel="stylesheet" href="/public/css/wap/main.css">
+    <link rel="stylesheet" href="/public/css/toast.css">
+    <link rel="stylesheet" href="/public/css/font-awesome/font-awesome.min.css">
+    <link rel="shortcut icon" href="/public/images/favicon.ico">
+    <style>
+        html{height:100%;}
+    </style>
+</head>
+<body>
+<div class="container">
+    <!--顶部-->
+    <nav class="fixed-top bg-dark">
+        <div class="my-2 d-flex justify-content-between">
+            <span class="text-white ml-3">项目</span>
+            <div class="mr-3">
+                <div class="dropdown">
+                    <button class="btn btn-sm btn-light dropdown-toggle" type="button" data-toggle="dropdown">
+                        <%- ctx.session.sessionUser.name.substr(ctx.session.sessionUser.name.length > 2 ? ctx.session.sessionUser.name.length - 2 : 0) %>
+                    </button>
+                    <div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
+                        <a class="dropdown-item" href="/wap/logout">退出登录</a>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </nav>
+    <!--标段列表-->
+    <div class="py-6">
+        <ul class="d-flex justify-content-start list-unstyled">
+            <li class="mr-3"><i class="fa fa-stop text-success"></i>截止上期完成</li>
+            <li class="mr-3"><i class="fa fa-stop text-info"></i>本期完成</li>
+            <li class="mr-3"><i class="fa fa-stop text-muted"></i>未完成</li>
+        </ul>
+        <div class="c-body"></div>
+    </div>
+    <!--底栏菜单-->
+    <nav class="fixed-bottom navbar-dark bg-light border-top">
+        <ul class="nav nav-fill my-2">
+            <li class="nav-item">
+                <a class="nav-link text-muted" href="/wap/dashboard"><i class="fa fa-check-square-o"></i> 待审批</a>
+            </li>
+            <li class="nav-item">
+                <a class="nav-link active " href="/wap/list"><i class="fa fa-list-ul"></i> 项目</a>
+            </li>
+        </ul>
+    </nav>
+</div>
+<script>
+    const tenders = JSON.parse('<%- JSON.stringify(tenderList) %>');
+    const category = JSON.parse('<%- JSON.stringify(categoryData) %>');
+    const uid = '<%- uid %>';
+    const pid = '<%- pid %>';
+    const uphlname = 'user_' + uid + '_pro_' + pid + '_category_wap_hide_list';
+</script>
+<!-- JS. -->
+<script src="/public/js/jquery/jquery-3.2.1.min.js"></script>
+<script src="/public/js/popper/popper.min.js"></script>
+<script src="/public/js/bootstrap/bootstrap.min.js"></script>
+<script src="/public/js/lodash.js"></script>
+<script src="/public/js/lz-string/lz-string.js"></script>
+<script src="/public/js/number-precision.js"></script>
+<script>
+
+    const zeroRange = 0.00000001;
+    function checkZero(value) {
+        return value === null || value === undefined || (_.isNumber(value) && Math.abs(value) < zeroRange);
+    }
+    /**
+     * 设置本地缓存
+     *
+     * @param {String} key
+     * @param {String|Number} value
+     * @return {void}
+     */
+    function setLocalCache(key, value) {
+        const storage = window.localStorage;
+        if (!storage || key === '' || value === '') {
+            return;
+        }
+
+        storage.setItem(key, value);
+    }
+
+    /**
+     * 获取本地缓存
+     *
+     * @param {String} key
+     * @return {String}
+     */
+    function getLocalCache(key) {
+        const storage = window.localStorage;
+        if (!storage || key === '') {
+            return null;
+        }
+
+        return storage.getItem(key);
+    }
+
+    /**
+     * 移除本地缓存
+     * @param {String} key
+     * @returns {Boolean}
+     */
+    function removeLocalCache(key) {
+        const storage = window.localStorage;
+        if (!storage || key === '') {
+            return null;
+        }
+        return storage.removeItem(key);
+    }
+</script>
+<script src="/public/js/decimal.min.js"></script>
+<script src="/public/js/zh_calc.js"></script>
+<script src="/public/js/shares/tender_list_order.js"></script>
+<script src="/public/js/tender_showhide.js"></script>
+<script src="/public/js/wap.js"></script>
+</body>
+</html>

+ 81 - 0
app/view/wap/login.ejs

@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">
+    <meta http-equiv="x-ua-compatible" content="ie=edge">
+    <title>用户登录-计量支付</title>
+    <link rel="stylesheet" href="/public/css/bootstrap/bootstrap.min.css">
+    <link rel="stylesheet" href="/public/css/wap/main.css">
+    <link rel="stylesheet" href="/public/css/toast.css">
+    <link rel="stylesheet" href="/public/css/font-awesome/font-awesome.min.css">
+    <link rel="shortcut icon" href="/public/images/favicon.ico">
+    <style>
+        html{height:100%;}
+    </style>
+</head>
+<body class="login-body">
+<div class="container">
+    <% if (maintainData.status === maintainConst.status.ongoing) { %>
+    <form class="form-signin">
+        <h4 class="text-center mb-3"><i class="fa fa-wrench"></i>系统正在维护</h4>
+        <h4>预计恢复时间<%- (maintainData.duration !== maintainConst.duration.forever ? '为 ' + ctx.helper.dateTran(parseFloat(maintainData.maintain_time) + ctx.helper.timeAdd(maintainData.duration)) : ' 暂未确定') %></h4>
+        <h4>造成不便敬请谅解。</h4>
+    </form>
+    <% } else { %>
+    <!--演示版-->
+    <div class="row">
+        <div class="col-12 text-center">
+            <img src="/public/images/loginlogo.png" class="my-3">
+        </div>
+        <div class="col-12">
+            <form class="card m-3 mt-3" method="post" action="/wap/login">
+                <div class="card-body">
+                    <h5 class="text-center mb-4 text-muted" id="project_name"></h5>
+                    <h4 class="text-center mb-4">账号登录</h4>
+                    <div class="form-group mb-3 <% if (errorMessage !== undefined && errorMessage !== null) { %>has-danger<% } %>">
+                        <input id="project" class="form-control" name="project" placeholder="项目编号" autofocus="" />
+                    </div>
+                    <div class="form-group mb-3 <% if (errorMessage !== undefined && errorMessage !== null) { %>has-danger<% } %>">
+                        <input id="account" class="form-control" name="account" placeholder="输入账号" autofocus="" />
+                    </div>
+                    <div class="form-group mb-3 <% if (errorMessage !== undefined && errorMessage !== null) { %>has-danger<% } %>">
+                        <input id="project-password" name="project_password" class="form-control" placeholder="输入密码" type="password" />
+                    </div>
+                    <div class="form-group mb-3">
+                        <div class="alert alert-danger" <% if(errorMessage === undefined || errorMessage === null) { %>style="display: none"<% } %> role="alert" id="error-msg">
+                            <% if(errorMessage !== undefined && errorMessage !== null) { %><strong>登录失败</strong> <%= errorMessage %><% } %>
+                        </div>
+                    </div>
+                    <div class="form-group mb-3">
+                        <button class="btn btn-primary btn-block" type="submit">登录</button>
+                        <input type="hidden" name="_csrf" value="<%= ctx.csrf %>" />
+                        <input type="hidden" name="type" value="2" />
+                    </div>
+                    <div class="pt-1 d-flex justify-content-end">
+                        <!--<a href="#fg-password" data-toggle="modal" data-target="#fg-password"  class="mr-3">忘记密码?</a>-->
+                    </div>
+                </div>
+            </form>
+        </div>
+    </div>
+    <% } %>
+    <!--项目版-->
+    <div class="text-white fixed-bottom"><p class="text-center mb-1">Copyright © 2019 <a href="https://smartcost.com.cn" target="_blank" class="text-white">珠海纵横创新软件有限公司</a>.All Rights Reserved.<a class="text-white ml-2" href="http://www.miitbeian.gov.cn" target="_blank">粤ICP备14032472号</a></p></div>
+</div>
+<!-- JS. -->
+<div class="toast" style="text-align: center">
+    <i class="icon fa"></i>
+    <span class="message"></span>
+</div>
+<!-- JS. -->
+<script src="/public/js/jquery/jquery-3.2.1.min.js"></script>
+<script src="/public/js/popper/popper.min.js"></script>
+<script src="/public/js/bootstrap/bootstrap.min.js"></script>
+<!--<script src="/public/js/global.js"></script>-->
+<script>
+    const csrf = '<%= ctx.csrf %>'
+</script>
+<!--<script src="/public/js/login.js"></script>-->
+</body>
+</html>

+ 532 - 0
app/view/wap/tender.ejs

@@ -0,0 +1,532 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">
+    <meta http-equiv="x-ua-compatible" content="ie=edge">
+    <title>标段概况-计量支付</title>
+    <link rel="stylesheet" href="/public/css/bootstrap/bootstrap.min.css">
+    <link rel="stylesheet" href="/public/css/wap/main.css">
+    <link rel="stylesheet" href="/public/css/toast.css">
+    <link rel="stylesheet" href="/public/css/font-awesome/font-awesome.min.css">
+    <script src=/public/js/echarts/echarts.min.js></script>
+    <link rel="shortcut icon" href="/public/images/favicon.ico">
+</head>
+<body>
+<div class="container">
+    <!--顶部-->
+    <nav class="fixed-top bg-dark">
+        <div class="my-2 d-flex justify-content-between">
+            <span class="text-white ml-3"><a href="/wap/list" class="mr-2 text-white"><i class="fa fa-chevron-left"></i></a>标段概况</span>
+            <div class="mr-3">
+                <div class="dropdown">
+                    <button class="btn btn-sm btn-light dropdown-toggle" type="button" data-toggle="dropdown">
+                        <%- ctx.session.sessionUser.name.substr(ctx.session.sessionUser.name.length > 2 ? ctx.session.sessionUser.name.length - 2 : 0) %>
+                    </button>
+                    <div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
+                        <a class="dropdown-item" href="/wap/logout">退出登录</a>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </nav>
+    <!--标段概况-->
+    <div class="py-6">
+        <!--标签-->
+        <ul class="nav nav-tabs nav-fill">
+            <li class="nav-item">
+                <a class="nav-link active" data-toggle="tab" href="#gaikuang" role="tab">概况</a>
+            </li>
+            <li class="nav-item">
+                <a class="nav-link" data-toggle="tab" href="#jlqi" role="tab">计量期</a>
+            </li>
+            <li class="nav-item">
+                <a class="nav-link" data-toggle="tab" href="#shenpi" role="tab">期审批</a>
+            </li>
+        </ul>
+        <div class="tab-content">
+            <div class="tab-pane active" id="gaikuang">
+                <!--图表-->
+                <div class="card mb-3 mr-1 mt-3">
+                    <div class="card-body">
+                        <h5 class="card-title">月进度表</h5>
+                        <div id="chartContainer3" style="height: 300px; width: 100%;">
+                        </div>
+                    </div>
+                </div>
+                <div class="card mb-3 mr-1">
+                    <div class="card-body">
+                        <h5 class="card-title">期进度表</h5>
+                        <div id="chartContainer4" style="height: 300px; width: 100%;">
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="tab-pane" id="jlqi">
+                <!--期列表-->
+                <dl class="mb-2 mt-3">
+                    <% for (const s of stages) { %>
+                    <dt class="bg-light p-2 d-flex justify-content-between"><span>第<%- s.order %>期</span>
+                        <span class="<%- auditConst.auditStringClass[s.status] %>">
+                            <% if (s.curAuditor && s.status !== auditConst.status.checked) { %>
+                                <%- s.curAuditor.name %><%if (s.curAuditor.role !== '' && s.curAuditor.role !== null) { %>-<%- s.curAuditor.role %><% } %>
+                            <% } %>
+                                <%- s.status === auditConst.status.checked ? '审批完成' : auditConst.auditProgress[s.status] %>
+                        </span>
+                    </dt>
+                    <dd>
+                        <table class="table table-hover">
+                            <tbody><tr>
+                                <td>
+                                    <p class="mb-0">本期合同计量</p>
+                                    <b>¥<%- ctx.helper.formatMoney((s.contract_tp ? s.contract_tp : 0)) %></b>
+                                </td>
+                                <td>
+                                    <p class="mb-0">本期数量变更计量</p>
+                                    <b>¥<%- ctx.helper.formatMoney((s.qc_tp ? s.qc_tp : 0)) %></b>
+                                </td>
+                            </tr>
+                            <tr>
+                                <td>
+                                    <p class="mb-0">本期完成计量</p>
+                                    <b>¥<%- ctx.helper.formatMoney((s.tp ? s.tp : 0)) %></b>
+                                </td>
+                                <td>
+                                    <p class="mb-0">截止上期完成计量</p>
+                                    <b>¥<%- ctx.helper.formatMoney((s.pre_tp ? s.pre_tp : 0)) %></b>
+                                </td>
+                            </tr>
+                            <tr>
+                                <td>
+                                    <p class="mb-0">截止本期完成计量</p>
+                                    <b>¥<%- ctx.helper.formatMoney((s.end_tp ? s.end_tp : 0)) %></b>
+                                </td>
+                                <td>
+                                    <p class="mb-0">本期应付</p>
+                                    <b>¥<%- ctx.helper.formatMoney((s.yf_tp ? s.yf_tp : 0)) %></b>
+                                </td>
+                            </tr>
+                            </tbody></table>
+                    </dd>
+                    <% } %>
+                </dl>
+            </div>
+            <div class="tab-pane" id="shenpi">
+                <!--最新期-->
+                <% let audit = 0; %>
+                <% if (stages.length > 0 && stage) { %>
+                <dl class="mb-2 mt-3">
+                    <dt class="bg-light p-2 d-flex justify-content-between"><span>第<%- stage.order %>期</span>
+                        <span class="<%- auditConst.auditStringClass[stage.status] %>">
+                            <% if (stage.curAuditor && stage.status !== auditConst.status.checked) { %>
+                                <%- stage.curAuditor.name %><%if (stage.curAuditor.role !== '' && stage.curAuditor.role !== null) { %>-<%- stage.curAuditor.role %><% } %>
+                            <% } %>
+                            <%- stage.status === auditConst.status.checked ? '审批完成' : auditConst.auditProgress[stage.status] %>
+                        </span>
+                    </dt>
+                    <dd>
+                        <table class="table table-hover">
+                            <tbody><tr>
+                                <td>
+                                    <p class="mb-0">本期合同计量</p>
+                                    <b>¥<%- ctx.helper.formatMoney((stage.contract_tp ? stage.contract_tp : 0)) %></b>
+                                </td>
+                                <td>
+                                    <p class="mb-0">本期数量变更计量</p>
+                                    <b>¥<%- ctx.helper.formatMoney((stage.qc_tp ? stage.qc_tp : 0)) %></b>
+                                </td>
+                            </tr>
+                            <tr>
+                                <td>
+                                    <p class="mb-0">本期完成计量</p>
+                                    <b>¥<%- ctx.helper.formatMoney((stage.tp ? stage.tp : 0)) %></b>
+                                </td>
+                                <td>
+                                    <p class="mb-0">截止上期完成计量</p>
+                                    <b>¥<%- ctx.helper.formatMoney((stage.pre_tp ? stage.pre_tp : 0)) %></b>
+                                </td>
+                            </tr>
+                            <tr>
+                                <td>
+                                    <p class="mb-0">截止本期完成计量</p>
+                                    <b>¥<%- ctx.helper.formatMoney((stage.end_tp ? stage.end_tp : 0)) %></b>
+                                </td>
+                                <td>
+                                    <p class="mb-0">本期应付</p>
+                                    <b>¥<%- ctx.helper.formatMoney((stage.yf_tp ? stage.yf_tp : 0)) %></b>
+                                </td>
+                            </tr>
+                            </tbody></table>
+                    </dd>
+                </dl>
+                <!--审批流程-->
+                <div class="card mt-3">
+                    <ul class="list-group list-group-flush">
+                        <li class="list-group-item">
+                            <% if (stage.status === auditConst.status.uncheck) { %>
+                            <span class="pull-right"> 上报中</span>
+                            <% } else { %>
+                            <span class="text-success pull-right"><small><%- stage.auditors[0].begin_time.toLocaleDateString() %></small> 上报</span>
+                            <% } %>
+                            <h5 class="card-title"><i class="fa fa-play-circle fa-rotate-90 text-success"></i> <%- stage.user.name %><small class="text-muted"><%- stage.user.role %></small></h5>
+                        </li>
+                        <% for (let iA = 0; iA < stage.auditors.length; iA++) { %>
+                            <% const auditors = stage.auditors; %>
+                        <li class="list-group-item">
+                            <% if (auditors[iA].status === auditConst.status.checked) { %>
+                            <span class="text-success pull-right"><small><%- auditors[iA].end_time.toLocaleDateString() %></small> 审批通过</span>
+                            <h5 class="card-title"><i class="<%- (iA < auditors.length - 1 ? 'fa fa-chevron-circle-down text-success' : 'fa fa-stop-circle text-success') %>"></i> <%- auditors[iA].name %> <small class="text-muted"><%- auditors[iA].role %></small></h5>
+                            <p class="card-text"><%- auditors[iA].opinion %></p>
+                            <% } else if (auditors[iA].status == auditConst.status.checking) { %>
+                            <span class="pull-right">审批中</span>
+                            <h5 class="card-title"><i class="<%- (iA < auditors.length - 1 ? 'fa fa-chevron-circle-down' : 'fa fa-stop-circle') %>"></i> <%- auditors[iA].name %> <small class="text-muted"><%- auditors[iA].role %></small></h5>
+                                <% if (auditors[iA].aid === ctx.session.sessionUser.accountId) { %>
+                                <% audit = auditors[iA]; %>
+                                <div class="form-group">
+                                    <div class="text-center">
+                                        <button class="btn btn-success" data-toggle="modal" data-target="#sp-done" >审批通过</button>
+                                        <button class="btn btn-warning" data-toggle="modal" data-target="#sp-back" >审批退回</button>
+                                    </div>
+                                </div>
+                                <% } %>
+                            <% } else if (auditors[iA].status === auditConst.status.checkNoPre) { %>
+                            <% const auditorIndex = stage.auditors2.findIndex(function (item) { return item.aid === auditors[iA].aid }) %>
+                            <span class="text-warning pull-right"><small><%- auditors[iA].end_time.toLocaleDateString() %></small>审批退回 <%- stage.auditors2[auditorIndex-1].name %></span>
+                            <h5 class="card-title"><i class="<%- (iA < auditors.length - 1 ? 'fa fa-chevron-circle-down text-warning' : 'fa fa-stop-circle text-warning') %>"></i> <%- auditors[iA].name %> <small class="text-muted"><%- auditors[iA].role %></small></h5>
+                            <p class="card-text"><%- auditors[iA].opinion %></p>
+                            <% } else if (auditors[iA].status === auditConst.status.checkNo) { %>
+                            <span class="text-warning pull-right"><small><%- auditors[iA].end_time.toLocaleDateString() %></small>审批退回</span>
+                            <h5 class="card-title"><i class="<%- (iA < auditors.length - 1 ? 'fa fa-chevron-circle-down text-warning' : 'fa fa-stop-circle text-warning') %>"></i> <%- auditors[iA].name %> <small class="text-muted"><%- auditors[iA].role %></small></h5>
+                            <p class="card-text"><%- auditors[iA].opinion %></p>
+                            <% } else if (auditors[iA].status === auditConst.status.checkAgain) { %>
+                            <span class="text-warning pull-right"><small><%- auditors[iA].end_time.toLocaleDateString() %></small>重新审批</span>
+                            <h5 class="card-title"><i class="<%- (iA < auditors.length - 1 ? 'fa fa-chevron-circle-down text-warning' : 'fa fa-stop-circle text-warning') %>"></i> <%- auditors[iA].name %> <small class="text-muted"><%- auditors[iA].role %></small></h5>
+                            <p class="card-text"><%- auditors[iA].opinion %></p>
+                            <% } else { %>
+                            <h5 class="card-title"><i class="<%- (iA < auditors.length - 1 ? 'fa fa-chevron-circle-down' : 'fa fa-stop-circle') %>"></i> <%- auditors[iA].name %> <small class="text-muted"><%- auditors[iA].role %></small></h5>
+                            <% } %>
+                        </li>
+                        <% } %>
+                    </ul>
+                </div>
+                <% } %>
+            </div>
+        </div>
+    </div>
+    <!--底栏菜单-->
+    <nav class="fixed-bottom navbar-dark bg-light border-top">
+        <ul class="nav nav-fill my-2">
+            <li class="nav-item">
+                <a class="nav-link text-muted" href="/wap/dashboard"><i class="fa fa-check-square-o"></i> 待审批</a>
+            </li>
+            <li class="nav-item">
+                <a class="nav-link active " href="/wap/list"><i class="fa fa-list-ul"></i> 项目</a>
+            </li>
+        </ul>
+    </nav>
+</div>
+<% if (audit !== 0) { %>
+<!--审批通过弹窗-->
+<div class="modal" tabindex="-1" role="dialog" id="sp-done">
+    <div class="modal-dialog" role="document">
+        <form class="modal-content" action="/tender/<%- stage.tid %>/measure/stage/<%- stage.order %>/audit/check" method="post" onsubmit="return auditCheck(0);">
+            <div class="modal-header">
+                <h5 class="modal-title">审批通过</h5>
+                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                    <span aria-hidden="true">&times;</span>
+                </button>
+            </div>
+            <div class="modal-body">
+                <div class="form-group">
+                    <label>审批意见</label>
+                    <textarea class="form-control" rows="8" name="opinion">同意</textarea>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+                <input type="hidden" name="_csrf" value="<%= ctx.csrf %>" />
+                <input type="hidden" name="checkType" value="<%= auditConst.status.checked %>" />
+                <button type="submit" class="btn btn-success">审批通过</button>
+            </div>
+        </form>
+    </div>
+</div>
+<!--审批退回弹窗-->
+<div class="modal" tabindex="-1" role="dialog" id="sp-back">
+    < class="modal-dialog" role="document">
+        <form class="modal-content" action="/tender/<%- stage.tid %>/measure/stage/<%- stage.order %>/audit/check" method="post" onsubmit="return auditCheck(1);">
+            <div class="modal-header">
+                <h5 class="modal-title">审批通过</h5>
+                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                    <span aria-hidden="true">&times;</span>
+                </button>
+            </div>
+            <div class="modal-body">
+                <div class="form-group">
+                    <label>审批意见</label>
+                    <textarea class="form-control" rows="8" name="opinion">不同意</textarea>
+                </div>
+                <div class="alert alert-warning">
+                    <div class="custom-control custom-radio custom-control-inline">
+                        <input type="radio" id="inlineRadio1" class="custom-control-input" value="<%- auditConst.status.checkNo %>" <% if (audit.order === 1 || audit.aid === stage.auditors[0].aid) { %>checked<% } %>>
+                        <label class="custom-control-label" for="customRadioInline1">退回上报 <%- stage.user.name %></label>
+                    </div>
+                    <% if (audit.order > 1 && audit.aid !== stage.auditors[0].aid) { %>
+                    <% const auditorIndex = stage.auditors2.findIndex(function (item) { return item.aid === audit.aid }) %>
+                    <div class="custom-control custom-radio custom-control-inline">
+                        <input class="custom-control-input" type="radio" name="checkType" id="customRadioInline2" value="<%- auditConst.status.checkNoPre %>" checked>
+                        <label class="custom-control-label" for="customRadioInline2">退回上一审批人 <%- stage.auditors2[auditorIndex-1].name %></label>
+                    </div>
+                    <% } %>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+                <input type="hidden" name="_csrf" value="<%= ctx.csrf %>" />
+                <button type="submit" class="btn btn-warning">确认退回</button>
+            </div>
+        </form>
+    </div>
+</div>
+<% } %>
+<!-- JS. -->
+<script src="/public/js/jquery/jquery-3.2.1.min.js"></script>
+<script src="/public/js/popper/popper.min.js"></script>
+<script src="/public/js/bootstrap/bootstrap.min.js"></script>
+<!--<script src="js/global.js"></script>-->
+<script type="text/javascript">
+    //4 标段期数计量进度//
+    var myChart = echarts.init(document.getElementById('chartContainer4'));
+    var option = {
+        color: ['#e9af68','#57b7b6','#e4575a','#959eac','#6699FF',
+            '#d38b70','#8fb7cf','#cd5c5c','#ffa500','#40e0d0',
+            '#1e90ff','#ff6347','#7b68ee','#00fa9a','#ffd700',
+            '#5c616b','#ff6666','#3cb371','#b8860b','#30e0e0'],
+        title : {
+            text: ''
+        },
+        tooltip : {
+            trigger: 'axis'
+        },
+        calculable : true,
+        legend: {
+            data:['本期合同计量','本期数量变更计量','截止上期累计完成','本期完成计量','完成度']
+        },
+        dataZoom: [
+            {show: true,start: 0, end: 100}
+        ],
+        xAxis : [
+            {
+                type : 'category',
+                splitLine : {show : true},
+                data : ['第一期','第二期','第三期','第四期','第五期','第六期','第七期']
+            }
+        ],
+        yAxis : [
+            {
+                type : 'value',
+                name : '金额',
+                position:'left',
+                axisLabel : {
+                    formatter: '{value} 元'
+                },
+                splitArea : {show : true}
+            },
+            {
+                type : 'value',
+                name:'完成度',
+                axisLabel : {
+                    formatter: '{value} %'
+                },
+                position: 'right',
+                splitArea : {show : true}
+            }
+        ],
+        series : [
+            {
+                name:'本期合同计量',
+                type:'bar',
+                tooltip : {trigger: 'item',formatter: "{b}  <br/>{a}:{c}元"},
+                stack: '合同',
+                data:[320, 332, 301, 334, 390, 330, 320]
+            },
+            {
+                name:'本期数量变更计量',
+                type:'bar',
+                tooltip : {trigger: 'item',formatter: "{b}  <br/>{a}:{c}元"},
+                stack: '合同',
+                data:[320, -20, 301, 334, 390, 330, 320]
+            },
+            {
+                name:'截止上期累计完成',
+                type:'bar',
+                tooltip : {trigger: 'item',formatter: "{b}  <br/>{a}:{c}元"},
+                stack: '完成',
+                data:[120, 132, 101, 134, 90, 230, 210]
+            },
+            {
+                name:'本期完成计量',
+                type:'bar',
+                tooltip : {trigger: 'item',formatter: "{b}  <br/>{a}:{c}元"},
+                stack: '完成',
+                data:[220, 182, 191, 234, 290, 330, 310]
+            },
+            {
+                name:'完成度',
+                type:'line',
+                tooltip : {trigger: 'axis',formatter: "{b}占总标段<br/>{a}:{c} %"},
+                yAxisIndex: 1,
+                data:[10, 15, 20, 13, 11, 9, 5]
+            },
+        ]
+    };
+
+    // 为echarts对象加载数据
+    myChart.setOption(option);
+    //4 标段期数计量进度//
+    //3 标段月进度//
+    // 基于准备好的dom,初始化echarts图表
+    var myChart = echarts.init(document.getElementById('chartContainer3'));
+    var option = {
+        color:["#e9af68","#57b7b6"],
+        title : {
+            text: ''
+        },
+        tooltip : {
+            trigger: 'axis',
+            formatter: "{b} <br/>{a}:{c} %<br/>{a1}:{c1} %"
+        },
+        legend: {
+            data:['截止本月完成','本月完成']
+        },
+        toolbox: {
+            show : true,
+            feature : {
+                magicType : {show: true, type: ['line', 'bar']}
+            }
+        },
+        dataZoom : {
+            show : true,
+            start : 50,
+            end : 100
+        },
+        xAxis : [
+            {
+                type : 'category',
+                boundaryGap : true,
+                data : [
+                    '2月','3月','4月','5月','6月','7月','8月','9月','10月'
+                ]
+            }
+        ],
+        yAxis : [
+            {
+                type : 'value',
+                axisLabel : {
+                    formatter: '{value} %'
+                },
+                splitArea : {show : true}
+            }
+        ],
+        series : [
+            {
+                name:'截止本月完成',
+                type:'line',
+                itemStyle: {
+                    normal: {
+                        lineStyle: {
+                            shadowColor : 'rgba(0,0,0,0.4)',
+                            shadowBlur: 5,
+                            shadowOffsetX: 3,
+                            shadowOffsetY: 3
+                        }
+                    }
+                },
+                data:[10, 10, 30, 40, 50, 60, 80, 85, 100]
+            },
+            {
+                name:'本月完成',
+                type:'line',
+                itemStyle: {
+                    normal: {
+                        lineStyle: {
+                            shadowColor : 'rgba(0,0,0,0.4)',
+                            shadowBlur: 5,
+                            shadowOffsetX: 3,
+                            shadowOffsetY: 3
+                        }
+                    }
+                },
+                data:[10, 0, 20, 10, 10, 10, 10, 5, 15]
+            }
+        ]
+    };
+    // 为echarts对象加载数据
+    myChart.setOption(option);
+    //3 标段月进度//
+</script>
+<!--sjs-->
+<script>
+    $(document).ready(function () {
+        const data = [
+            {
+                单位:'稍等',
+                精度:3,
+            },{
+                单位:'km',
+                精度:3,
+            },{
+                单位:'m',
+                精度:3,
+            },{
+                单位:'m2',
+                精度:3,
+            },{
+                单位:'m3',
+                精度:3,
+            },{
+                单位:'kg',
+                精度:3,
+            },{
+                单位:'个',
+                精度:3,
+            },{
+                单位:'台',
+                精度:3,
+            },{
+                单位:'套',
+                精度:3,
+            },{
+                单位:'棵',
+                精度:3,
+            },{
+                单位:'组',
+                精度:3,
+            },{
+                单位:'总额',
+                精度:3,
+            },{
+                单位:'系统',
+                精度:3,
+            },{
+                单位:'其他未列单位',
+                精度:3,
+            }
+        ];
+        const spread = new GC.Spread.Sheets.Workbook($('#option-spread1')[0], {
+            sheetCount: 1
+        });
+        spread.getActiveSheet().setDataSource(data);
+        spread.options.tabStripVisible = false;
+    })
+
+    // texterea换行
+    function auditCheck(i) {
+        const opinion = $('textarea[name="opinion"]').eq(i).val().replace(/\r\n/g, '<br/>').replace(/\n/g, '<br/>').replace(/\s/g, ' ');
+        $('textarea[name="opinion"]').eq(i).val(opinion);
+        return true;
+    }
+</script>
+</body>
+
+</html>