瀏覽代碼

新增项目账号列表以及项目名称显示

olym 7 年之前
父節點
當前提交
359bed2bed

+ 10 - 0
app/base/base_service.js

@@ -77,6 +77,16 @@ class BaseService extends Service {
     }
 
     /**
+     * 根据条件查找单条数据
+     *
+     * @param {Object} condition - 筛选条件
+     * @return {Array} - 返回数据
+     */
+    async getAllDataByCondition(condition) {
+        return await this.db.select(this.tableName, condition);
+    }
+
+    /**
      * 根据id删除数据
      *
      * @param {Number} id - 数据库中的id

+ 66 - 0
app/controller/account_controller.js

@@ -0,0 +1,66 @@
+'use strict';
+
+/**
+ * 账号管理相关控制器
+ *
+ * @author CaiAoLin
+ * @date 2018/1/23
+ * @version
+ */
+
+module.exports = app => {
+
+    class AccountController extends app.BaseController {
+
+        /**
+         * 账号管理页面
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        async index(ctx) {
+            try {
+                const sessionProject = ctx.session.sessionProject;
+                // 获取当前项目的用户列表
+                const accountList = await ctx.service.projectAccount.getAccountByProjectId(sessionProject.id);
+                const renderData = {
+                    accountList,
+                };
+                await this.layout('account/index.ejs', renderData);
+            } catch (error) {
+                this.setMessage(error.toString(), this.messageType.ERROR);
+                ctx.redirect(ctx.request.headers.referer);
+            }
+        }
+
+        /**
+         * 停用/启用操作
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        async enable(ctx) {
+            let accountId = ctx.params.accountId;
+            try {
+                accountId = parseInt(accountId);
+                if (isNaN(accountId) || accountId <= 0) {
+                    throw '参数错误!';
+                }
+
+                const result = await ctx.service.projectAccount.enableAccount(accountId);
+                if (!result) {
+                    throw '设置失败';
+                }
+
+                this.setMessage('设置成功', this.messageType.SUCCESS);
+            } catch (error) {
+                this.setMessage(error.toString(), this.messageType.ERROR);
+            }
+            ctx.redirect(ctx.request.headers.referer);
+        }
+
+
+    }
+
+    return AccountController;
+};

+ 3 - 3
app/controller/project_controller.js

@@ -22,7 +22,7 @@ module.exports = app => {
         async info(ctx) {
             try {
                 // 获取项目数据
-                const projectId = ctx.session.sessionUser.projectId;
+                const projectId = ctx.session.sessionProject.id;
                 const projectData = await ctx.service.project.getDataById(projectId);
                 if (projectData === null) {
                     throw '没有对应的项目数据';
@@ -43,7 +43,7 @@ module.exports = app => {
                 };
                 await this.layout('project/info.ejs', renderData);
             } catch (error) {
-                console.log(error);
+                this.setMessage(error.toString(), this.messageType.ERROR);
                 ctx.redirect('/dashboard');
             }
         }
@@ -76,7 +76,7 @@ module.exports = app => {
 
                 this.setMessage('保存成功', this.messageType.SUCCESS);
             } catch (error) {
-                console.log(error);
+                this.setMessage(error.toString(), this.messageType.ERROR);
                 this.setMessage(error, this.messageType.ERROR);
             }
 

+ 1 - 0
app/lib/sql_builder.js

@@ -44,6 +44,7 @@ class SqlBuilder {
         this.limit = -1;
         this.offset = -1;
         this.orderBy = [];
+        this.groupBy = [];
     }
 
     /**

+ 1 - 1
app/middleware/permission_filter.js

@@ -30,7 +30,7 @@ module.exports = option => {
             } catch (error) {
                 this.session.message = {
                     type: 'error',
-                    icon: 'exclamation-sign',
+                    icon: 'exclamation-circle',
                     message: error.toString(),
                 };
                 return this.redirect('/dashboard');

+ 33 - 0
app/middleware/project_manager_check.js

@@ -0,0 +1,33 @@
+'use strict';
+
+/**
+ * 检验是否为项目管理员中间件
+ *
+ * @author CaiAoLin
+ * @date 2018/1/23
+ * @version
+ */
+
+module.exports = app => {
+    return function* projectManagerCheck(next) {
+        const sessionProject = this.session.sessionProject;
+        const sessionUser = this.session.sessionUser;
+        try {
+            if (sessionProject.userAccount === undefined) {
+                throw '不存在对应项目数据';
+            }
+            // 判断当前用户是否为管理员
+            if (sessionUser.account !== sessionProject.userAccount) {
+                throw '当前用户没有权限';
+            }
+        } catch (error) {
+            this.session.message = {
+                type: 'error',
+                icon: 'exclamation-circle',
+                message: error.toString(),
+            };
+            return this.redirect(this.request.headers.referer);
+        }
+        yield next;
+    };
+};

+ 0 - 29
app/middleware/white_list_filter.js

@@ -1,29 +0,0 @@
-'use strict';
-
-module.exports = options => {
-    /**
-     * 白名单过滤器
-     *
-     * @param {function} next - 中间件继续执行的方法
-     * @return {void}
-     */
-    return function* whiteListFilter(next) {
-        // 获取当前ip
-        const ip = this.request.ip;
-        // 获取白名单数据
-        const whiteList = yield this.service.whiteList.getAllData();
-        // 判断是否为ajax请求
-        if (this.helper.isAjax(this.request)) {
-            // 检测token @todo
-        } else {
-            // 不是ajax请求则判断ip是否为合法
-            if (whiteList[ip + ':1'] === undefined) {
-                this.status = 404;
-                return;
-            }
-        }
-
-        yield next;
-    };
-};
-

+ 5 - 0
app/router.js

@@ -6,6 +6,8 @@ module.exports = app => {
     const sessionAuth = app.middlewares.sessionAuth();
     // 创建时间自动填充中间件
     const datetimeFill = app.middlewares.datetimeFill();
+    // 项目管理员判断中间件
+    const projectManagerCheck = app.middlewares.projectManagerCheck();
 
     // 登入登出相关
     app.get('/login', 'loginController.index');
@@ -22,6 +24,9 @@ module.exports = app => {
 
     // 项目相关
     app.get('/project/info', sessionAuth, 'projectController.info');
+    app.get('/project/account', sessionAuth, projectManagerCheck, 'accountController.index');
+    app.get('/project/account/enable/:accountId', sessionAuth, projectManagerCheck, 'accountController.enable');
+    app.get('/project/account/disable/:accountId', sessionAuth, projectManagerCheck, 'accountController.enable');
     app.post('/project/info', sessionAuth, 'projectController.saveInfo');
 
     // 台账管理相关

+ 2 - 2
app/service/customer.js

@@ -26,8 +26,8 @@ module.exports = app => {
         /**
          * 数据规则
          *
-         * @param {String} scene
-         * @return {Object}
+         * @param {String} scene - 场景
+         * @return {Object} - 返回规则数据
          */
         rule(scene) {
             let rule = {};

+ 68 - 3
app/service/project_account.js

@@ -70,25 +70,33 @@ module.exports = app => {
                 this.ctx.validate(rule, data);
 
                 let accountData = {};
-                let projectId = 0;
+                let projectInfo = {};
+                let projectList = [];
                 if (loginType === 2) {
                     // 查找项目数据
                     const projectData = await this.ctx.service.project.getProjectByCode(data.project.toString());
                     if (projectData === null) {
                         throw '不存在项目数据';
                     }
-                    projectId = projectData.id;
+                    projectInfo = {
+                        id: projectData.id,
+                        name: projectData.name,
+                        userAccount: projectData.user_account,
+                    };
 
                     // 查找对应数据
                     accountData = await this.db.get(this.tableName, {
                         account: data.account,
                         project_id: projectData.id,
+                        enable: 1,
                     });
 
                     if (accountData === null) {
                         throw '不存在对应用户数据';
                     }
 
+                    projectList = await this.getProjectInfoByAccount(data.account);
+
                     // 判断密码
                     if (accountData.is_admin === 1) {
                         // 管理员则用sso通道判断
@@ -128,8 +136,9 @@ module.exports = app => {
                         loginTime: currentTime,
                         sessionToken,
                         loginType,
-                        projectId,
                     };
+                    this.ctx.session.sessionProject = projectInfo;
+                    this.ctx.session.sessionProjectList = projectList;
                 }
             } catch (error) {
                 console.log(error);
@@ -138,6 +147,62 @@ module.exports = app => {
 
             return result;
         }
+
+        /**
+         * 根据项目id获取用户列表
+         *
+         * @param {Number} projectId - 项目id
+         * @return {Array} - 返回用户数据
+         */
+        async getAccountByProjectId(projectId) {
+            const condition = {
+                columns: ['id', 'account', 'name', 'company', 'role', 'mobile', 'telephone', 'enable'],
+                where: { project_id: projectId, is_admin: 0 },
+            };
+            const accountList = await this.getAllDataByCondition(condition);
+
+            return accountList;
+        }
+
+        /**
+         * 停用/启用
+         *
+         * @param {Number} accountId - 账号id
+         * @return {Boolean} - 返回操作结果
+         */
+        async enableAccount(accountId) {
+            let result = false;
+            const accountData = await this.getDataByCondition({ id: accountId });
+            if (accountData === null) {
+                return result;
+            }
+
+            const changeStatus = accountData.enable === 1 ? 0 : 1;
+            result = await this.update({ enable: changeStatus }, { id: accountId });
+
+            return result;
+        }
+
+        /**
+         * 根据账号id查找对应的项目数据
+         *
+         * @param {Number} account - 账号
+         * @return {Array} - 返回数据
+         */
+        async getProjectInfoByAccount(account) {
+            let column = ['p.name', 'p.id'];
+            column = column.join(',');
+            const sql = 'SELECT ' + column + ' FROM ' +
+                '?? AS pa ' +
+                'LEFT JOIN ?? AS p ' +
+                'ON pa.`project_id` = p.`id` ' +
+                'WHERE pa.`account` = ? ' +
+                'GROUP BY pa.`project_id`;';
+            const sqlParam = [this.tableName, this.ctx.service.project.tableName, account];
+            const projectInfo = await this.db.query(sql, sqlParam);
+
+            return projectInfo;
+        }
     }
 
     return ProjectAccount;

+ 81 - 0
app/view/account/index.ejs

@@ -0,0 +1,81 @@
+<% include ../layout/body_header.ejs %>
+<div class="panel-content">
+    <div class="panel-title">
+        <div class="title-main">
+            <h2><%= ctx.menu.children[ctx.actionName].name %>
+            <a href="#ver" data-toggle="modal" data-target="#add-user" class="btn btn-primary btn-sm pull-right">添加账号</a>
+            </h2>
+        </div>
+    </div>
+    <div class="content-wrap">
+        <div class="c-body">
+            <nav class="nav nav-tabs mb-3" role="tablist">
+                <a class="nav-item nav-link active" data-toggle="tab" href="#user-list" role="tab">账号列表</a>
+                <a class="nav-item nav-link" data-toggle="tab" href="#user-purview" role="tab">账号权限</a>
+            </nav>
+            <div class="tab-content">
+                <div id="user-list" class="tab-pane active">
+                    <table class="table table-hover table-bordered table-sm">
+                        <thead>
+                        <tr>
+                            <th>账号</th>
+                            <th>姓名</th>
+                            <th>单位</th>
+                            <th>职位</th>
+                            <th>手机</th>
+                            <th>电话</th>
+                            <th class="text-center">操作</th>
+                        </tr>
+                        </thead>
+                        <tbody>
+                        <% if (accountList.length > 0) { %>
+                        <% accountList.forEach(function (account) { %>
+                        <tr class="<%= account.enable !== 1 ? 'table-danger' : ''%>">
+                            <td><%= account.account %></td>
+                            <td><%= account.name %></td>
+                            <td><%= account.company %></td>
+                            <td><%= account.role %></td>
+                            <td><%= account.mobile %></td>
+                            <td><%= account.telephone %></td>
+                            <td class="text-center">
+                                <a href="#edit-user" data-toggle="modal" data-target="#edit-user" class="btn btn-sm btn-outline-primary">编辑</a>
+                                <a href="/project/account/enable/<%= account.id %>" class="btn btn-sm btn-outline-<%= account.enable === 1 ? 'danger' : 'success'%>"><%= account.enable === 1 ? '停用' : '启用'%></a>
+                            </td>
+                        </tr>
+                        <% }) %>
+                        <% } %>
+                        </tbody>
+                    </table>
+                </div>
+                <div id="user-purview" class="tab-pane">
+                    <table class="table table-hover table-bordered table-sm">
+                        <thead>
+                        <tr>
+                            <th>账号</th>
+                            <th>姓名</th>
+                            <th>单位</th>
+                            <th>职位</th>
+                            <th>权限</th>
+                        </thead>
+                        <tbody>
+                        <tr>
+                            <td>chente</td>
+                            <td>陈特</td>
+                            <td>珠海纵横创新软件有限公司</td>
+                            <td>产品经理</td>
+                            <td>台帐管理(创建标段)<a href="" class="btn btn-sm">编辑</a></td>
+                        </tr>
+                        <tr>
+                            <td>chente</td>
+                            <td>陈特</td>
+                            <td>珠海纵横创新软件有限公司</td>
+                            <td>产品经理</td>
+                            <td><a href="" class="btn btn-sm">编辑</a></td>
+                        </tr>
+                        </tbody>
+                    </table>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>

+ 1 - 1
app/view/layout/body_header.ejs

@@ -10,7 +10,7 @@
             <ul class="nav-list list-unstyled">
                 <% for (const index in ctx.menu.children) { %>
                 <li <% if (ctx.actionName === index) { %>class="active"<% } %>>
-                    <a href="settings-poj.html"><span><%= ctx.menu.children[index].name %></span></a>
+                    <a href="<%= ctx.menu.children[index].url %>"><span><%= ctx.menu.children[index].name %></span></a>
                 </li>
                 <% } %>
             </ul>

+ 11 - 4
app/view/layout/layout.ejs

@@ -23,21 +23,27 @@
 <body>
 <div class="header">
     <h1 class="logo"><a>主页-纵横变更管理系统</a></h1>
+    <% if (Object.keys(ctx.session.sessionProject).length > 0) { %>
     <div class="poj-name">
-        <span class="name">项目A</span>
+        <span class="name"><%= ctx.session.sessionProject.name %></span>
+        <% if (ctx.session.sessionProjectList.length > 0) { %>
         <div class="btn-group">
             <a class=" btn" data-toggle="dropdown">
                 <span class="fa fa-caret-down" data-toggle="tooltip" data-placement="bottom" title="切换项目"></span>
             </a>
             <div class="dropdown-menu">
-                <a href="#" class="dropdown-item">项目B</a>
-                <a href="#" class="dropdown-item">项目C</a>
-                <a href="#" class="dropdown-item">项目D</a>
+                <% ctx.session.sessionProjectList.forEach(function(project) {%>
+                <% if (project.name !== null) {%>
+                <a href="#" class="dropdown-item"><%= project.name %></a>
+                <% } %>
+                <% }) %>
             </div>
         </div>
+        <% } %>
         <a href="/project/info" class="btn" data-toggle="tooltip" data-placement="bottom" title="项目设置"><i
                     class="fa fa-cogs"></i></a>
     </div>
+    <% } %>
     <div class="header-box">
         <div class="header-nav"></div>
         <div class="header-user pull-right">
@@ -76,6 +82,7 @@
 <% include ./modal.ejs %>
 <script type="text/javascript">
     let toastInfo = '<%- message %>';
+    console.log(toastInfo);
     try {
         toastInfo = toastInfo !== '' && toastInfo !== 'null' ? JSON.parse(toastInfo) : '';
     } catch (error) {

+ 4 - 4
config/menu.js

@@ -16,15 +16,15 @@ const menu = {
         children: {
             info: {
                 name: '项目信息',
-                url: '',
+                url: '/project/info',
             },
-            accountSetting: {
+            account: {
                 name: '账号设置',
-                url: '',
+                url: '/project/account',
             },
             approvalSetting: {
                 name: '审批设置',
-                url: '',
+                url: '/project/approval',
             },
         },
     },

+ 5 - 5
package-lock.json

@@ -8552,11 +8552,6 @@
       "resolved": "http://registry.npm.taobao.org/streamsearch/download/streamsearch-0.1.2.tgz",
       "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo="
     },
-    "string_decoder": {
-      "version": "0.10.31",
-      "resolved": "http://registry.npm.taobao.org/string_decoder/download/string_decoder-0.10.31.tgz",
-      "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
-    },
     "string-width": {
       "version": "2.1.1",
       "resolved": "http://registry.npm.taobao.org/string-width/download/string-width-2.1.1.tgz",
@@ -8586,6 +8581,11 @@
         }
       }
     },
+    "string_decoder": {
+      "version": "0.10.31",
+      "resolved": "http://registry.npm.taobao.org/string_decoder/download/string_decoder-0.10.31.tgz",
+      "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
+    },
     "stringifier": {
       "version": "1.3.0",
       "resolved": "http://registry.npm.taobao.org/stringifier/download/stringifier-1.3.0.tgz",

+ 0 - 29
test/app/extend/helper.test.js

@@ -80,33 +80,4 @@ describe('test/app/extend/helper.test.js', () => {
         assert(responseData.data.ip === '116.7.222.12');
     });
 
-    it('convertBreadCrumb append test', function* () {
-        // 创建 ctx
-        const ctx = app.mockContext({
-            topPermission: {
-                name: 'test',
-            },
-            currentName: 'current',
-        });
-        const breadCrumb = [{
-            name: 'append',
-            url: 'http://www.baidu.com',
-        }];
-        const result = ctx.helper.convertBreadCrumb(breadCrumb);
-        const expect = 'test / <a href="/http://www.baidu.com">append</a> / current';
-        assert(result === expect);
-    });
-
-    it('convertBreadCrumb replace test', function* () {
-        // 创建 ctx
-        const ctx = app.mockContext();
-        const breadCrumb = [
-            { name: 'test' },
-            { name: 'append', url: 'http://www.baidu.com' },
-            { name: 'current' },
-        ];
-        const result = ctx.helper.convertBreadCrumb(breadCrumb, 'replace');
-        const expect = 'test / <a href="/http://www.baidu.com">append</a> / current';
-        assert(result === expect);
-    });
 });

+ 25 - 25
test/app/service/project_account.test.js

@@ -19,32 +19,32 @@ describe('test/app/service/project_account.test.js', () => {
             project: 'J201711163164',
             project_password: '19930523',
         };
-
-        const result = yield ctx.service.projectAccount.accountLogin(postData);
-        assert(result);
-    });
-
-    it('test login success (local)', function* () {
-        const ctx = app.mockContext();
-        const postData = {
-            account: 'test',
-            project: 'Y201711167257',
-            project_password: '123123',
-        };
-
-        const result = yield ctx.service.projectAccount.accountLogin(postData);
+        ctx.session = {};
+        const result = yield ctx.service.projectAccount.accountLogin(postData, 2);
         assert(result);
     });
 
-    it('test login fail', function* () {
-        const ctx = app.mockContext();
-        const postData = {
-            account: 'laiku123@qq.com',
-            project: 'J201711163164',
-            project_password: '1111',
-        };
-
-        const result = yield ctx.service.projectAccount.accountLogin(postData);
-        assert(!result);
-    });
+    // it('test login success (local)', function* () {
+    //     const ctx = app.mockContext();
+    //     const postData = {
+    //         account: 'test',
+    //         project: 'Y201711167257',
+    //         project_password: '123123',
+    //     };
+    //
+    //     const result = yield ctx.service.projectAccount.accountLogin(postData);
+    //     assert(result);
+    // });
+    //
+    // it('test login fail', function* () {
+    //     const ctx = app.mockContext();
+    //     const postData = {
+    //         account: 'laiku123@qq.com',
+    //         project: 'J201711163164',
+    //         project_password: '1111',
+    //     };
+    //
+    //     const result = yield ctx.service.projectAccount.accountLogin(postData);
+    //     assert(!result);
+    // });
 });