Просмотр исходного кода

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

TonyKang 5 лет назад
Родитель
Сommit
6c55703925

+ 100 - 0
app/controller/login_controller.js

@@ -162,6 +162,106 @@ module.exports = app => {
             }
             ctx.body = response;
         }
+
+        /**
+         * 接口登录页面
+         *
+         * @param {Object} ctx - egg全局页面
+         * @return {void}
+         */
+        async port(ctx) {
+            // 获取系统维护信息
+            const maintainData = await ctx.service.maintain.getDataById(1);
+
+            if (!ctx.app.config.is_debug) {
+                await ctx.service.maintain.syncMaintainData();
+            }
+            let pa;
+            try {
+                if (ctx.session.loginError !== null) {
+                    throw ctx.session.loginError;
+                }
+                if (!ctx.query.mobile) {
+                    throw '参数有误';
+                }
+                pa = await ctx.service.projectAccount.getDataByCondition({ mobile: ctx.query.mobile, project_id: ctx.projectData.id });
+                if (!pa) {
+                    throw '您无权限登录系统。';
+                }
+                if (pa.bind === 0) {
+                    // 先绑定再登录
+                    throw '';
+                } else {
+                    if (pa.enable !== 1) {
+                        throw '该账号已被停用,请联系销售人员';
+                    }
+                    const result = await ctx.service.projectAccount.accountLogin({ project: ctx.projectData, accountData: pa }, 3);
+                    if (!result) {
+                        throw '登录出错';
+                    }
+                    ctx.redirect('/dashboard');
+                }
+            } catch (error) {
+                this.log(error);
+                ctx.session.loginError = error;
+            }
+            const errorMessage = ctx.session.loginError;
+            // 显示完删除
+            ctx.session.loginError = null;
+            const renderData = {
+                maintainData,
+                maintainConst,
+                errorMessage,
+                projectData: ctx.projectData,
+                accountData: pa,
+            };
+            await ctx.render('login/login_port.ejs', renderData);
+        }
+
+        /**
+         * 登录操作
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        async loginPort(ctx) {
+            let loginType = ctx.request.body.type;
+
+            try {
+                loginType = parseInt(loginType);
+                const data = await ctx.service.project.getProjectByCode(ctx.request.body.code.toString().trim());
+                if (data === null) {
+                    throw '不存在项目数据';
+                }
+                if (data.custom === 0) {
+                    throw '无法通过接口登录本系统';
+                }
+
+                if (data && data.custom === 1) {
+                    const pa = await ctx.service.projectAccount.getDataById(ctx.request.body.accountId);
+                    if (!pa) {
+                        throw '您无权限登录系统。';
+                    }
+
+                    if (pa.enable !== 1) {
+                        throw '该账号已被停用,请联系销售人员';
+                    }
+                    const updateData = {
+                        bind: 1,
+                    };
+                    await ctx.service.projectAccount.update(updateData, { id: pa.id });
+                    const result = await ctx.service.projectAccount.accountLogin({ project: data, accountData: pa }, loginType);
+                    if (!result) {
+                        throw '绑定登录出错,请使用账号密码登录';
+                    }
+                    ctx.redirect('/dashboard');
+                }
+            } catch (error) {
+                this.log(error);
+                ctx.session.loginError = error;
+                ctx.redirect('/login');
+            }
+        }
     }
 
     return LoginController;

+ 3 - 1
app/controller/report_controller.js

@@ -596,7 +596,9 @@ async function getMultiRptsCommon(ctx, params, outputType, baseDir) {
         return params.rpt_ids.indexOf(rpt1.id) - params.rpt_ids.indexOf(rpt2.id);
     });
     for (let rtIdx = 0; rtIdx < rptTpls.length; rtIdx++) {
+        const id = rptTpls[rtIdx].id;
         rptTpls[rtIdx] = JSON.parse(rptTpls[rtIdx].rpt_content);
+        rptTpls[rtIdx].id = id;
     }
     const rptDataUtil = new rptDataExtractor();
     const filterTables = [];
@@ -648,7 +650,7 @@ async function getMultiRptsCommon(ctx, params, outputType, baseDir) {
         for (let tplIdx = 0; tplIdx < rptTpls.length; tplIdx++) {
             const rptTpl = (rptTpls[tplIdx]._doc) ? rptTpls[tplIdx]._doc : rptTpls[tplIdx];
             rptDataUtil.initialize(rptTpl);
-            const customSelect = await ctx.service.rptCustomDefine.getCustomDefine(params.tender_id, params.stage_id, rptTpls[tplIdx].id);
+            const customSelect = await ctx.service.rptCustomDefine.getCustomDefine(params.tender_id, params.stage_id, rptTpl.id);
             const tplData = rptDataUtil.assembleData(ctx, rawDataObj, baseDir, null, customSelect);
             const printCom = JpcEx.createNew();
             rptTpl[JV.NODE_MAIN_INFO][JV.NODE_PAGE_INFO][JV.PROP_PAGE_SIZE] = params.pageSize;

+ 1 - 1
app/controller/setting_controller.js

@@ -106,7 +106,7 @@ module.exports = app => {
                 //     limit: (app.config.pageSize * (page - 1)),
                 //     offset: app.config.pageSize,
                 // });
-                const columns = ['id', 'account', 'name', 'company', 'role', 'mobile', 'auth_mobile', 'telephone', 'enable', 'is_admin', 'account_group'];
+                const columns = ['id', 'account', 'name', 'company', 'role', 'mobile', 'auth_mobile', 'telephone', 'enable', 'is_admin', 'account_group', 'bind'];
                 const accountData = await ctx.service.projectAccount.getListByProjectId(columns, projectId);
 
                 // 分页相关

+ 4 - 1
app/lib/rpt_data_analysis.js

@@ -942,7 +942,7 @@ const auditSelect = {
             }
         } else {
             const setting = JSON.stringify(asDefine.setting);
-            for (const [i, s] of setting.select.entries) {
+            for (const [i, s] of setting.select.entries()) {
                 order.push(i);
             }
         }
@@ -955,6 +955,9 @@ const auditSelect = {
                 case 'mem_stage_pos_compare':
                     this._stagePosCompare(data[t], order);
                     break;
+                case 'mem_stage_pay':
+                    this._stagePay(data[t], order);
+                    break;
             }
         }
     }

+ 58 - 0
app/middleware/api2other_check.js

@@ -0,0 +1,58 @@
+'use strict';
+
+/**
+ *
+ * @author EllisRan
+ * @date
+ * @version
+ */
+const crypto = require('crypto');
+const maintainConst = require('../const/maintain');
+
+module.exports = options => {
+    return function* api2otherCheck(next) {
+        try {
+            // 获取系统维护信息
+            const maintainData = yield this.service.maintain.getDataById(1);
+            if (maintainData.status === maintainConst.status.ongoing) {
+                throw '系统维护中~';
+            }
+            const code = this.query.code || this.request.body.code;
+            const sign = this.query.sign || this.request.body.sign;
+            const time = this.query.time || this.request.body.time;
+            if (!code || !sign || !time) {
+                throw '参数有误';
+            }
+            if (parseFloat(time + 86400 * 1000) < new Date().getTime()) {
+                throw '时间参数已过期';
+            }
+            const data = yield this.service.project.getProjectByCode(code.toString().trim());
+            if (data === null) {
+                throw '不存在项目数据';
+            }
+            if (data.custom === 0) {
+                throw '无法通过接口登录本系统';
+            }
+            const encryptSign = crypto.createHash('md5').update(data.code + data.secret + time.toString()).digest('hex').toString();
+            if (encryptSign !== sign) {
+                throw '参数验证失败';
+            }
+            this.projectData = data;
+            yield next;
+        } catch (err) {
+            console.log(err);
+            // 重定向值标段管理
+            // 判断是登录请求还是接口请求
+            if (this.helper.isAjax(this.request)) {
+                this.body = {
+                    err: 1,
+                    msg: err,
+                    data: '',
+                };
+                return;
+            }
+            this.session.loginError = err;
+            yield next;
+        }
+    };
+};

+ 2 - 1
app/public/js/component/input.js

@@ -10,12 +10,13 @@
 
 // 文本输入框
 Vue.component('input-text', {
-    props: ['label', 'id', 'name', 'value', 'required', 'placeholder', 'maxlength', 'readonly', 'password', 'disabled'],
+    props: ['label', 'id', 'name', 'value', 'required', 'placeholder', 'maxlength', 'readonly', 'password', 'disabled', 'msg'],
     template: '' +
     '<div class="form-group" :class="{ required: required }">' +
         '<label>{{ label }}</label>' +
         '<input :type="[ password ? \'password\' : \'text\']" :id="id" :name="name" :value="value" :placeholder="placeholder" ' +
             ':maxlength="maxlength" :readonly="readonly" :disabled="disabled" class="form-control form-control-sm"/>' +
+        '<small class="form-text text-danger" v-if="readonly && msg !== null && msg !== undefined ">{{ msg }}</small>' +
     '</div>'
 });
 

+ 7 - 0
app/public/js/setting.js

@@ -33,6 +33,13 @@ $(document).ready(() => {
         $('#edit-user select[name="account_group"]').val(account.account_group);
         $('#edit-user input[class="account-check"]').val(account.account);
         $('#edit-user input[data-mobile="auth-mobile"]').val(account.auth_mobile);
+        $('#edit-user input[name="mobile"]').attr('readOnly', account.bind === 1);
+        if (account.bind === 1) {
+            $('#edit-user input[name="mobile"]').siblings('small').show();
+        } else {
+            $('#edit-user input[name="mobile"]').siblings('small').hide();
+        }
+
     });
 
     // 分配随机密码

+ 4 - 0
app/router.js

@@ -14,12 +14,16 @@ module.exports = app => {
     const stageCheck = app.middlewares.stageCheck();
     // 材料调差读取中间件
     const materialCheck = app.middlewares.materialCheck();
+    // 第三方接口认证判断中间件
+    const api2otherCheck = app.middlewares.api2otherCheck();
 
     // 登入登出相关
     app.get('/login', 'loginController.index');
+    app.get('/login/port', api2otherCheck, 'loginController.port');
     app.get('/', 'loginController.index');
     app.get('/logout', 'loginController.logout');
     app.post('/login', 'loginController.login');
+    app.post('/login/port', 'loginController.loginPort');
     app.get('/project/name', 'loginController.projectName');
 
     app.get('/sign', 'signController.index');

+ 29 - 10
app/service/project_account.js

@@ -105,10 +105,12 @@ module.exports = app => {
         async accountLogin(data, loginType) {
             let result = false;
             try {
-                // 验证数据
-                const scene = loginType === 1 ? 'ssoLogin' : 'login';
-                const rule = this.rule(scene);
-                this.ctx.validate(rule, data);
+                if (loginType === 1 || loginType === 2) {
+                    // 验证数据
+                    const scene = loginType === 1 ? 'ssoLogin' : 'login';
+                    const rule = this.rule(scene);
+                    this.ctx.validate(rule, data);
+                }
 
                 let accountData = {};
                 let projectInfo = {};
@@ -125,6 +127,7 @@ module.exports = app => {
                         id: projectData.id,
                         name: projectData.name,
                         userAccount: projectData.user_account,
+                        custom: projectData.custom,
                     };
 
                     // 查找对应数据
@@ -153,11 +156,27 @@ module.exports = app => {
                     //      const sso = new SSO(this.ctx);
                     //      result = await sso.loginValid(data.account, data.project_password.toString());
                     // } else {
-                        // 加密密码
-                        const encryptPassword = crypto.createHmac('sha1', data.account.trim()).update(data.project_password.trim())
-                            .digest().toString('base64');
-                        result = encryptPassword === accountData.password;
-                    //}
+                    // 加密密码
+                    const encryptPassword = crypto.createHmac('sha1', data.account.trim()).update(data.project_password.trim())
+                        .digest().toString('base64');
+                    result = encryptPassword === accountData.password;
+                    // }
+                } else if (loginType === 3) {
+                    // 查找项目数据
+                    const projectData = data.project;
+
+                    projectInfo = {
+                        id: projectData.id,
+                        name: projectData.name,
+                        userAccount: projectData.user_account,
+                        custom: projectData.custom,
+                    };
+
+                    // 查找对应数据
+                    accountData = data.accountData;
+
+                    projectList = await this.getProjectInfoByAccount(accountData.account);
+                    result = true;
                 } else {
                     // sso登录(演示版)
                     const sso = new SSO(this.ctx);
@@ -173,7 +192,7 @@ module.exports = app => {
                     const sessionToken = crypto.createHmac('sha1', currentTime + '').update(accountData.account)
                         .digest('hex').toString('base64');
 
-                    if (loginType === 2) {
+                    if (loginType === 2 || loginType === 3) {
                         const updateData = {
                             last_login: currentTime,
                             session_token: sessionToken,

+ 70 - 0
app/view/login/login_port.ejs

@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=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/main.css">
+    <link rel="stylesheet" href="/public/css/toast.css">
+    <link rel="stylesheet" href="/public/css/font-awesome/font-awesome.min.css">
+</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 { %>
+    <!--演示版-->
+    <form class="form-signin" method="post" action="/login/port">
+        <h4 class="text-center mb-2">纵横云计量</h4>
+        <h5 class="text-center mb-4 text-muted"><%- projectData ? projectData.name : '' %></h5>
+        <% if (accountData) { %>
+            <h5>您好,<%- accountData.mobile %></h5>
+            <% if (accountData.bind === 0) { %>
+            <!--查询账号存在,进行绑定-->
+            <h5>系统查询以下账号,请确认无误后进行绑定。</h5>
+            <h5>姓名:<span class="text-danger"><%- accountData.name %></span></h5>
+            <h5>账号:<span class="text-danger"><%- accountData.account %></span></h5>
+            <h5>手机:<span class="text-danger"><%- accountData.mobile %></span></h5>
+            <h5>单位:<span class="text-danger"><%- accountData.company %></span></h5>
+            <h5>职称:<span class="text-danger"><%- accountData.role %></span></h5>
+            <div class="form-group mt-4">
+                <input type="hidden" value="<%= ctx.csrf %>" name="_csrf" >
+                <input type="hidden" value="3" name="type" >
+                <input type="hidden" value="<%= projectData.code %>" name="code" >
+                <input type="hidden" value="<%= accountData.id %>" name="accountId" >
+                <button type="submit" class="btn btn-primary btn-block">绑定并登录系统</button>
+            </div>
+            <% } %>
+        <% } %>
+        <h5 class="text-danger"><%- errorMessage %></h5>
+    </form>
+    <% } %>
+    <!--项目版-->
+    <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>
+<% if (projectData) { %>
+<script>
+    $(document).ready(function() {
+        setLocalCache('project_name', '<%- projectData.name %>');
+        setLocalCache('project_code', '<%- projectData.code %>');
+    });
+</script>
+<% } %>
+</body>
+</html>

+ 1 - 1
app/view/profile/info.ejs

@@ -16,7 +16,7 @@
                             <input-text label="姓名" value="<%= accountData.name %>" placeholder="请输入姓名" name="name"></input-text>
                             <input-text label="单位" value="<%= accountData.company %>" name="company"></input-text>
                             <input-text label="角色/职称" value="<%= accountData.role %>" name="role"></input-text>
-                            <input-text label="手机" value="<%= accountData.mobile %>" name="mobile" maxlength="11"></input-text>
+                            <input-text label="手机" value="<%= accountData.mobile %>" name="mobile" maxlength="11" :readonly="<%= accountData.bind === 1 %>" msg="已绑定第三方平台,无法修改"></input-text>
                             <input-text label="电话" value="<%= accountData.telephone %>" name="telephone"></input-text>
                             <input type="hidden" name="_csrf" value="<%= ctx.csrf %>">
                             <button type="submit" class="btn btn-primary btn-sm" id="base-submit">确认修改</button>

+ 1 - 0
app/view/setting/user_modal.ejs

@@ -118,6 +118,7 @@
                 <div class="form-group">
                     <label>手机</label>
                     <input class="form-control form-control-sm" value="" name="mobile" type="number">
+                    <small class="form-text text-danger">已绑定第三方平台,无法修改</small>
                 </div>
                 <div class="form-group">
                     <label>电话</label>

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

@@ -329,7 +329,7 @@
                                                 <label>替换文件</label>
                                                 <div class="custom-file">
                                                     <input type="file" class="custom-file-input" id="change-att-btn">
-                                                    <label class="custom-file-label" for="customFile">Choose file</label>
+                                                    <label class="custom-file-label" data-browse="浏览" for="customFile">选择文件</label>
                                                 </div>
                                             </div>
                                         </div>