浏览代码

1.提交后台登陆相关代码

caiaolin 8 年之前
父节点
当前提交
37b7083a59
共有 55 个文件被更改,包括 4929 次插入1291 次删除
  1. 3 0
      .babelrc
  2. 2 1
      config/config.js
  3. 77 0
      config/menu.js
  4. 114 0
      modules/common/base/base_controller.js
  5. 135 0
      modules/common/base/base_model.js
  6. 206 0
      modules/common/helper/mongoose_helper.js
  7. 44 0
      modules/users/controllers/dashboard_controller.js
  8. 92 0
      modules/users/controllers/login_controller.js
  9. 156 0
      modules/users/controllers/manager_controller.js
  10. 25 0
      modules/users/controllers/notify_controller.js
  11. 24 0
      modules/users/controllers/tool_controller.js
  12. 56 0
      modules/users/controllers/user_controller.js
  13. 0 85
      modules/users/controllers/users_controller.js
  14. 117 0
      modules/users/models/manager_model.js
  15. 64 0
      modules/users/models/schemas/manager.js
  16. 49 0
      modules/users/models/schemas/user.js
  17. 64 0
      modules/users/models/user_model.js
  18. 0 49
      modules/users/models/users.js
  19. 20 0
      modules/users/routes/dashboard_route.js
  20. 22 0
      modules/users/routes/login_route.js
  21. 29 0
      modules/users/routes/manager_route.js
  22. 19 0
      modules/users/routes/notify_route.js
  23. 0 41
      modules/users/routes/users_route.js
  24. 14 9
      operation.js
  25. 2 0
      package.json
  26. 1 1
      public/rpt_tpl_def.js
  27. 6 0
      web/users/css/bootstrap.min.css
  28. 296 0
      web/users/css/style.css
  29. 二进制
      web/users/fonts/glyphicons-halflings-regular.eot
  30. 288 0
      web/users/fonts/glyphicons-halflings-regular.svg
  31. 二进制
      web/users/fonts/glyphicons-halflings-regular.ttf
  32. 二进制
      web/users/fonts/glyphicons-halflings-regular.woff
  33. 二进制
      web/users/fonts/glyphicons-halflings-regular.woff2
  34. 49 0
      web/users/js/admin.js
  35. 29 0
      web/users/js/global.js
  36. 657 0
      web/users/js/lib/bootstrap-paginator.js
  37. 7 0
      web/users/js/lib/bootstrap.min.js
  38. 1578 0
      web/users/js/lib/jquery.validate.js
  39. 33 0
      web/users/js/lib/messages_zh.js
  40. 14 0
      web/users/js/lib/validate.extend.js
  41. 80 0
      web/users/js/login.js
  42. 0 88
      web/users/login-infoinput.html
  43. 0 296
      web/users/login-welcome.html
  44. 0 132
      web/users/login.html
  45. 0 589
      web/users/project-management.html
  46. 48 0
      web/users/views/dashboard/index.html
  47. 58 0
      web/users/views/layout/layout.html
  48. 66 0
      web/users/views/layout/page.html
  49. 18 0
      web/users/views/layout/second_menu.html
  50. 54 0
      web/users/views/login/index.html
  51. 54 0
      web/users/views/manager/index.html
  52. 36 0
      web/users/views/manager/save.html
  53. 114 0
      web/users/views/notify/index.html
  54. 29 0
      web/users/views/tool/index.html
  55. 80 0
      web/users/views/user/index.html

+ 3 - 0
.babelrc

@@ -0,0 +1,3 @@
+{
+  "presets": ["es2015", "stage-2"]
+}

+ 2 - 1
config/config.js

@@ -17,5 +17,6 @@ module.exports = {
         var me = this;
         me.current.server = me.prod.server;
         me.current.port = me.prod.port;
-    }
+    },
+    pageSize: 30
 }

+ 77 - 0
config/menu.js

@@ -0,0 +1,77 @@
+/**
+ * 菜单配置
+ *
+ * @author CaiAoLin
+ * @date 2017/6/5
+ * @version
+ */
+let menuData = {
+    'dashboard': {
+        title: '首页',
+        url: '/dashboard',
+        name: 'dashboard',
+        iconClass: 'glyphicon glyphicon-home'
+    },
+    'user': {
+        title: '用户管理',
+        url: '/user',
+        name: 'user',
+        iconClass: 'glyphicon glyphicon-user',
+        children: {
+            'index' : {
+                title: '最近注册',
+                url: '/user',
+                name: 'index',
+            },
+            'last-login' : {
+                title: '最近登录',
+                url: '/user/last-login',
+                name: 'last-login',
+            }
+        }
+    },
+    'notify': {
+        title: '通知管理',
+        url: '/notify',
+        name: 'notify',
+        iconClass: 'glyphicon glyphicon-bell',
+        children: {
+            'index' : {
+                title: '用户通知',
+                url: '/notify',
+                name: 'index',
+            },
+            'company' : {
+                title: '内部通知',
+                url: '/notify/company',
+                name: 'company',
+            }
+        }
+    },
+    'tool': {
+        title: '工具',
+        url: '/tool',
+        name: 'tool',
+        iconClass: 'glyphicon glyphicon-wrench'
+    },
+    'manager': {
+        title: '后台管理',
+        url: '/manager',
+        name: 'manager',
+        iconClass: 'glyphicon glyphicon-cog',
+        children: {
+            'index' : {
+                title: '账号管理',
+                url: '/manager',
+                name: 'index',
+            },
+            'admin' : {
+                title: '超级管理员',
+                url: '/manager/admin',
+                name: 'admin',
+            }
+        }
+    }
+};
+
+export default menuData;

+ 114 - 0
modules/common/base/base_controller.js

@@ -0,0 +1,114 @@
+/**
+ * 控制器基类
+ *
+ * @author CaiAoLin
+ * @date 2017/6/29
+ * @version
+ */
+import crypto from "crypto";
+import Url from "url";
+import Moment from "moment";
+import menuData from "../../../config/menu";
+
+class BaseController {
+
+    /**
+     * 页面title
+     *
+     * @var string
+     */
+    title = '';
+
+    /**
+     * 构造函数
+     *
+     * @return {void}
+     */
+    constructor() {
+        if (new.target === BaseController) {
+            throw new Error('BaseController不能实例化,只能继承使用。');
+        }
+    }
+
+    /**
+     * 初始化函数
+     *
+     * @param {object} request
+     * @param {object} response
+     * @param {function} next
+     * @return {void}
+     */
+    init(request, response, next) {
+        // 获取当前控制器和动作名称
+        let urlInfo = Url.parse(request.originalUrl, true);
+        let url = urlInfo.pathname.substr(1);
+        let actionInfo = url.split('/');
+        let controller = 'index';
+        let action = 'index';
+        switch (actionInfo.length) {
+            case 1:
+                controller = actionInfo[0];
+                break;
+            case 2:
+                controller = actionInfo[0];
+                action = actionInfo[1];
+                break;
+        }
+
+        // 菜单数据
+        response.locals.menu = menuData;
+        // 二级菜单数据
+        response.locals.secondMenu = menuData[controller] !== undefined && menuData[controller].children !== undefined ?
+            menuData[controller].children : {};
+
+        // url相关数据
+        response.locals.urlQuery = JSON.stringify(urlInfo.query);
+        response.locals.controller = controller;
+        response.locals.action = action;
+
+        // 用户session数据
+        response.locals.manager = request.session.managerData;
+
+        // moment工具
+        response.locals.moment = Moment;
+
+        next();
+    }
+
+    /**
+     * 验证方法
+     *
+     * @param {object} request
+     * @param {object} response
+     * @param {function} next
+     * @return {void}
+     */
+    auth(request, response, next) {
+        // 判断session
+        let mangerData = request.session.managerData;
+        try {
+            if (typeof mangerData !== 'object' || Object.keys(mangerData).length < 0) {
+                throw 'err data';
+            }
+
+            if (mangerData.username === undefined || mangerData.loginTime === undefined) {
+                throw 'username empty';
+            }
+            // 校验session
+            let sessionToken = crypto.createHmac('sha1', mangerData.loginTime + '')
+                .update(mangerData.username).digest().toString('base64');
+            if (sessionToken !== mangerData.sessionToken) {
+                throw 'session error';
+            }
+
+        } catch (error) {
+            console.log(error);
+            // 未登录
+            response.redirect('/login');
+        }
+
+        next();
+    }
+}
+
+export default BaseController;

+ 135 - 0
modules/common/base/base_model.js

@@ -0,0 +1,135 @@
+/**
+ * 数据模型基类
+ *
+ * @author CaiAoLin
+ * @date 2017/6/22
+ * @version
+ */
+import MongooseHelper from "../helper/mongoose_helper";
+
+class BaseModel {
+
+    /**
+     * mongoose数据模型
+     *
+     * @var {object}
+     */
+    model = null;
+
+    /**
+     * 构造函数
+     *
+     * @return {void}
+     */
+    constructor() {
+        if (new.target === BaseModel) {
+            throw new Error('BaseModel不能实例化,只能继承使用。');
+        }
+    }
+
+    /**
+     * 初始化函数
+     *
+     * @return {void}
+     */
+    init() {
+        if (this.model === null) {
+            throw new Error('子类数据有误');
+        }
+
+        this.db = new MongooseHelper();
+        this.db.model = this.model;
+    }
+
+    /**
+     * 根据id查找对应数据
+     *
+     * @param {Object} condition
+     * @param {Object} fields
+     * @param {boolean} singleData
+     * @param {String} indexBy
+     * @return {Promise}
+     */
+    async findDataByCondition(condition, fields = null, singleData = true, indexBy = null) {
+        let result = [];
+        if (Object.keys(condition).length <= 0) {
+            return result;
+        }
+
+        result = singleData ? await this.db.findOne(condition, fields) : await this.db.find(condition, fields);
+
+        if (indexBy !== null && !singleData && result.length > 0) {
+            let tmpResult = {};
+            for(let tmp of result) {
+                tmpResult[tmp[indexBy]] = tmp;
+            }
+            result = tmpResult;
+        }
+        return result;
+    }
+
+    /**
+     * 根据条件返回数据数量
+     *
+     * @param {object} condition
+     * @return {Promise}
+     */
+    async count(condition = null) {
+        let total = 0;
+        try {
+            total = await this.db.count(condition);
+        } catch (error) {
+            total = 0;
+        }
+        return total;
+    }
+
+    /**
+     * 根据id删除
+     *
+     * @param {Number|String} id
+     * @param {boolean} isString 设置是否为_id
+     * @return {Promise}
+     */
+    async deleteById(id, isString = false) {
+        let result = false;
+        if (!isString) {
+            id = parseInt(id);
+            if (isNaN(id) || id <= 0) {
+                return false;
+            }
+        }
+
+        let condition = !isString ? {id: id} : {_id: id};
+        try {
+            let deleteResult = await this.db.delete(condition);
+            result = deleteResult.result.ok === 1;
+        } catch (error) {
+            console.log(error);
+            result = false;
+        }
+
+        return result;
+    }
+
+    /**
+     * 更新数据
+     *
+     * @param {Number} id
+     * @param {Object} updateData
+     * @return {Promise}
+     */
+    async updateById(id, updateData) {
+        id = parseInt(id);
+        if (isNaN(id) || id <= 0 || Object.keys(updateData).length <= 0) {
+            return false;
+        }
+
+        let result = await this.db.update({id: id}, updateData);
+
+        return result.ok !== undefined && result.ok === 1;
+    }
+
+}
+
+export default BaseModel;

+ 206 - 0
modules/common/helper/mongoose_helper.js

@@ -0,0 +1,206 @@
+/**
+ * mongodb Helper
+ *
+ * @author caiaolin
+ * @date 2017/5/22.
+ */
+import mongoose from "mongoose";
+
+class MongooseHelper {
+
+    /**
+     * mongoose连接对象
+     *
+     * @var {object}
+     */
+    connect = null;
+
+    /**
+     * mongoose数据模型
+     *
+     * @var {object}
+     */
+    model = null;
+
+    /**
+     * 查找单一数据
+     *
+     * @param {object} conditions
+     * @param {object} fields
+     * @return {Promise}
+     */
+    findOne(conditions, fields = null) {
+        let self = this;
+        return new Promise(function (resolve, reject) {
+            self.model.findOne(conditions, fields, function (error, data) {
+                if (error) {
+                    reject(null);
+                } else {
+                    resolve(data);
+                }
+            });
+        });
+    }
+
+    /**
+     * 查找数据
+     *
+     * @param {object} conditions
+     * @param {object} fields
+     * @param {object} option
+     * @return {Promise}
+     */
+    find(conditions, fields = null, option = null) {
+        let self = this;
+        return new Promise(function (resolve, reject) {
+            self.model.find(conditions, fields, option, function (error, data) {
+                if (error) {
+                    reject(error);
+                } else {
+                    resolve(data);
+                }
+            });
+        });
+    }
+
+    /**
+     * 关联查找数据
+     *
+     * @param {object} conditions
+     * @param {object} fields
+     * @param {String|Object} populate
+     * @return {Promise}
+     */
+    findWithPopulate(conditions, fields = null, populate = '') {
+        let self = this;
+        return new Promise(function (resolve, reject) {
+            self.model.find(conditions, fields).populate(populate).exec(function(error, data) {
+                if (error) {
+                    reject(error);
+                } else {
+                    resolve(data);
+                }
+            });
+        });
+    }
+
+    /**
+     * 查找且更新(原子操作)
+     *
+     * @param {object} update
+     * @param {object} condition
+     * @param {object} options
+     * @return {Promise}
+     */
+    findAndModify(condition, update, options) {
+        let self = this;
+        return new Promise(function (resolve, reject) {
+            self.model.findOneAndUpdate(condition, update, options, function(error, data) {
+                    if (error) {
+                        reject(error);
+                    } else {
+                        resolve(data);
+                    }
+                });
+        });
+    }
+
+    /**
+     * 新增操作
+     *
+     * @param {object} data
+     * @return {Promise}
+     */
+    create(data) {
+        let self = this;
+        return new Promise(function (resolve, reject) {
+            self.model.create(data, function(error, data) {
+                if (error) {
+                    reject(error);
+                } else {
+                    resolve(data);
+                }
+            });
+        });
+    }
+
+    /**
+     * 统计数据数量
+     *
+     * @param {Object} condition
+     * @return {Promise}
+     */
+    count(condition) {
+        let self = this;
+        return new Promise(function(resolve, reject) {
+            self.model.count(condition, function(error, data) {
+                if (error) {
+                    reject(error);
+                } else {
+                    resolve(data);
+                }
+            });
+        });
+    }
+
+    /**
+     * 删除数据
+     *
+     * @param {Object} condition
+     * @return {Promise}
+     */
+    delete(condition) {
+        let self = this;
+        return new Promise(function(resolve, reject) {
+            condition = self._convertId(condition);
+            self.model.remove(condition, function(error, data) {
+                if (error) {
+                    reject(error);
+                } else {
+                    resolve(data);
+                }
+            });
+        });
+    }
+
+    /**
+     * 更新数据
+     *
+     * @param {Object} condition
+     * @param {Object} updateData
+     * @return {Promise}
+     */
+    update(condition, updateData) {
+        let self = this;
+        return new Promise(function(resolve, reject) {
+            condition = self._convertId(condition);
+            self.model.update(condition, {$set: updateData}, function(error, data) {
+                if (error) {
+                    reject(error);
+                } else {
+                    resolve(data);
+                }
+            });
+        });
+    }
+
+    /**
+     * id转换为objectId
+     *
+     * @param {object} condition
+     * @return {object}
+     */
+    _convertId(condition) {
+        // 对于ID的处理
+        if (condition === null || condition._id === undefined) {
+            return condition;
+        }
+        let result = mongoose.Types.ObjectId(condition._id);
+        condition._id = result;
+
+        return condition;
+    }
+
+}
+
+export default MongooseHelper;

+ 44 - 0
modules/users/controllers/dashboard_controller.js

@@ -0,0 +1,44 @@
+/**
+ * 控制面板相关控制器
+ *
+ * @author CaiAoLin
+ * @date 2017/6/2
+ * @version
+ */
+import BaseController from "../../common/base/base_controller";
+
+class DashboardController extends BaseController {
+
+    /**
+     * 一级菜单显示
+     *
+     * @var {string}
+     */
+    static parentTitle = '后台管理';
+
+    /**
+     * 一级菜单
+     *
+     * @var {string}
+     */
+    static parentIndex = 'manager';
+
+
+    /**
+     * 控制面板首页
+     *
+     * @param {object} request
+     * @param {object} response
+     * @return {void}
+     */
+    index(request, response) {
+        let renderData = {
+            parentTitle: DashboardController.parentTitle,
+            parentIndex: DashboardController.parentIndex,
+        };
+        response.render('users/views/dashboard/index', renderData);
+    }
+
+}
+
+export default DashboardController;

+ 92 - 0
modules/users/controllers/login_controller.js

@@ -0,0 +1,92 @@
+/**
+ * 登录页面控制器
+ *
+ * @author CaiAoLin
+ * @date 2017/6/1
+ * @version
+ */
+import BaseController from "../../common/base/base_controller";
+import ManagerModel from "../models/manager_model";
+import crypto from "crypto";
+
+class LoginController extends BaseController {
+
+    /**
+     * 登录页面
+     *
+     * @param {object} request
+     * @param {object} response
+     * @return {void}
+     */
+    index(request, response) {
+        let renderData = {
+            layout: false,
+        };
+        response.render('users/views/login/index', renderData);
+    }
+
+    /**
+     * 登录操作
+     *
+     * @param {object} request
+     * @param {object} response
+     * @return {string}
+     */
+    async login(request, response) {
+        let username = request.body.username;
+        let password = request.body.password;
+        let managerModel = new ManagerModel();
+
+        let responseData = {
+            error: 0,
+            msg: ''
+        };
+        try {
+            let managerData = await managerModel.findDataByCondition({username: username});
+
+            // 没有找到对应数据
+            if (managerData === null || managerData._id === undefined) {
+                throw {code: 44001, err: '用户名或密码错误'};
+            }
+
+            // 加密密码
+            let encryptPassword = managerModel.encryptPassword(managerData.token, password);
+            if (encryptPassword !== managerData.password) {
+                throw {code: 44001, err: '用户名或密码错误'};
+            }
+
+            // 成功后写入session
+            let currentTime = new Date().getTime();
+            let sessionToken = crypto.createHmac('sha1', currentTime + '').update(managerData.username)
+                .digest().toString('base64');
+
+            let managerSession = {
+                username: managerData.username,
+                loginTime: currentTime,
+                sessionToken: sessionToken,
+            };
+            request.session.managerData = managerSession;
+        } catch (error) {
+            responseData.error = error.code;
+            responseData.msg = error.err;
+        }
+
+        response.json(responseData);
+    }
+
+    /**
+     * 退出操作
+     *
+     * @param {object} request
+     * @param {object} response
+     * @return {void}
+     */
+    logout(request, response) {
+        // 清空session
+        request.session.destroy();
+        response.redirect('/login');
+    }
+
+}
+
+export default LoginController;

+ 156 - 0
modules/users/controllers/manager_controller.js

@@ -0,0 +1,156 @@
+/**
+ * 后台用户管理控制器
+ *
+ * @author CaiAoLin
+ * @date 2017/6/2
+ * @version
+ */
+import BaseController from "../../common/base/base_controller";
+import ManagerModel from "../models/manager_model";
+import Config from "../../../config/config";
+
+class ManagerController extends BaseController {
+
+    /**
+     *  账号管理(管理员列表)
+     *
+     * @param {object} request
+     * @param {object} response
+     * @return {void}
+     */
+    async index(request, response) {
+        let pageData = {};
+        let managerList = [];
+        try {
+            // 查找管理员用户列表
+            let managerModel = new ManagerModel();
+            let total = await managerModel.count();
+
+            // 分页数据
+            let page = request.query.page === undefined ? 1 : request.query.page;
+            pageData = {
+                current: page,
+                total: parseInt(total / Config.pageSize),
+                queryData: response.locals.urlQuery
+            };
+
+            // 获取管理员列表
+            managerList = await managerModel.getList(null, page);
+        } catch (error) {
+
+        }
+
+        let renderData = {
+            managerList: managerList,
+            pages: pageData
+        };
+        response.render('users/views/manager/index', renderData);
+    }
+
+    /**
+     * 编辑管理员
+     *
+     * @param {object} request
+     * @param {object} response
+     * @return {void}
+     */
+    async modify(request, response) {
+        let id = request.params.id;
+        let managerData = {};
+        try {
+            let managerModel = new ManagerModel();
+            managerData = await managerModel.findDataByCondition({id: id});
+
+        } catch (error) {
+            console.log(error);
+        }
+
+        response.end('111');
+    }
+
+    /**
+     * 删除管理员
+     *
+     * @param {object} request
+     * @param {object} response
+     * @return {void}
+     */
+    async delete(request, response) {
+        let id = request.params.id;
+        let managerModel = new ManagerModel();
+        let result = await managerModel.deleteById(id, true);
+
+        // 删除成功
+        if (result) {
+
+        }
+        response.redirect(request.headers.referer);
+    }
+
+    /**
+     * 超级管理员修改
+     *
+     * @param {object} request
+     * @param {object} response
+     * @return {void}
+     */
+    async admin(request, response) {
+        let adminData = {};
+        try {
+            // 查找对应超级管理员数据
+            let managerModel = new ManagerModel();
+            adminData = await managerModel.findDataByCondition({username: 'admin'});
+
+        } catch (error) {
+            console.log(error);
+        }
+
+        let renderData = {
+            adminData: adminData,
+        };
+        response.render('users/views/manager/save', renderData);
+    }
+
+    /**
+     * 超级管理员修改提交
+     *
+     * @param {object} request
+     * @param {object} response
+     * @return
+     */
+    async adminSubmit(request, response) {
+        let newPassword = request.body.newPassword.toString();
+        let password = request.body.password.toString();
+        let managerModel = new ManagerModel();
+        let responseData = {
+            err: 0,
+            msg: ''
+        };
+        try {
+            if (!newPassword || !password) {
+                throw '内容有误';
+            }
+            // 更改密码操作
+            managerModel.setScene('changPassword');
+            let result = await managerModel.changePassword('admin', password, newPassword);
+            if (!result) {
+                throw '更新错误';
+            }
+        } catch (error) {
+            console.log(error);
+            responseData.err = 40002;
+            responseData.msg = error;
+        }
+
+        response.json(responseData);
+    }
+
+    async create(request, response) {
+        let managerModel = new ManagerModel();
+        let result = await managerModel.createManager();
+        console.log('result:' + result);
+        response.end('success');
+    }
+}
+
+export default ManagerController;

+ 25 - 0
modules/users/controllers/notify_controller.js

@@ -0,0 +1,25 @@
+/**
+ * 通知管理控制器
+ *
+ * @author CaiAoLin
+ * @date 2017/6/7
+ * @version
+ */
+import BaseController from "../../common/base/base_controller";
+
+class NotifyController extends BaseController {
+
+    /**
+     * 用户通知页面
+     *
+     * @param {object} request
+     * @param {object} response
+     * @return {void}
+     */
+    index(request, response) {
+        response.render('users/views/notify/index');
+    }
+
+}
+
+export default NotifyController;

+ 24 - 0
modules/users/controllers/tool_controller.js

@@ -0,0 +1,24 @@
+/**
+ * 工具页面控制器
+ *
+ * @author CaiAoLin
+ * @date 2017/7/21
+ * @version
+ */
+import BaseController from "../../common/base/base_controller";
+
+class ToolController extends BaseController {
+
+    /**
+     *  工具首页
+     *
+     * @param {object} request
+     * @param {object} response
+     * @return {void}
+     */
+    index(request, response) {
+        response.render('users/views/tool/index');
+    }
+
+}
+export default ToolController;

+ 56 - 0
modules/users/controllers/user_controller.js

@@ -0,0 +1,56 @@
+/**
+ * 用户管理控制器
+ *
+ * @author CaiAoLin
+ * @date 2017/6/7
+ * @version
+ */
+import BaseController from "../../common/base/base_controller";
+import UserModel from "../models/user_model";
+import Config from "../../../config/config";
+
+class UserController extends BaseController {
+
+    /**
+     * 最近注册列表(最近登录前台用户列表)
+     *
+     * @param {object} request
+     * @param {object} response
+     * @return {void}
+     */
+    async lastRegister(request, response) {
+        let userModel = new UserModel();
+        let total = 0;
+        let pageData = {};
+        let userList = [];
+        try {
+            // 获取用户总数
+            total = await userModel.count();
+
+            // 分页数据
+            let page = request.query.page === undefined ? 1 : request.query.page;
+            pageData = {
+                current: page,
+                total: parseInt(total / Config.pageSize),
+                queryData: response.locals.urlQuery
+            };
+
+            // 获取用户列表
+            userList = await userModel.getList(null, page);
+        } catch (error) {
+            console.log(error);
+        }
+
+        // 渲染数据
+        let renderData = {
+            userList: userList,
+            pages: pageData,
+            total: total,
+            model: userModel
+        };
+        response.render('users/views/user/index', renderData);
+    }
+
+}
+
+export default UserController;

+ 0 - 85
modules/users/controllers/users_controller.js

@@ -1,85 +0,0 @@
-var ut = require('../models/users');
-var rq = require('request');
-var online = true;
-
-module.exports = {
-    userLogin: function (req, res) {
-        var account = req.body.account;
-        var pw = req.body.pw;
-
-        if (online) {
-            rq.post(
-                {
-                    url: 'http://sso.smartcost.com.cn/api/jzlogin',
-                    form: {username: account, userpasswd: pw},
-                    encoding: 'utf8'
-                },
-                function (err, response, userData) {
-                    if (response.statusCode !== 200) {
-                        res.json({state: false, error: '通行证验证失败!出错代号:' + response.statusCode});
-                    } else {
-                        switch (userData) {
-                            case '-2':
-                                res.json({state: false, error: '密码错误!'});
-                                break;
-                            case '-22':
-                                res.json({state: false, error: '输入的邮箱/手机无效!'});
-                                break;
-                            default:
-                                userData = JSON.parse(userData);
-                                req.session.userID = userData[0].id;
-                                req.session.userAccount = userData[0].username;
-                                req.session.userEmail = userData[0].useremail;
-                                req.session.userMobile = userData[0].mobile;
-                                res.json({state: true, data: userData});
-                        }
-
-                    }
-                }
-            );
-        }
-        else {
-            ut.findUser(account, pw, function (err, userData) {
-                if (err) {
-                    res.json({state: false, error: err});
-                }
-                else {
-                    req.session.userID = userData[0].profile.id;
-                    req.session.userName = userData[0].profile.userName;
-                    req.session.userAccount = userData[0].profile.userAccount;
-                    req.session.userEmail = userData[0].profile.useRemail;
-                    req.session.userMobile = userData[0].profile.Mobile;
-                    res.json({state: true, data: userData});
-                }
-                ;
-            })
-        }
-    },
-
-    userReg: function (req, res) {
-        var account = req.body.account;
-        var pw = req.body.pw;
-        var name = req.body.name;
-
-        ut.checkAccount(account, function (userData) {
-            if (!userData) {  // 找不到用户,则注册
-                ut.addUser(account, pw, name, function (err) {
-                    if (err) {
-                        res.json({state: false, error: '“注册失败,原因:' + err});
-                    }
-                    else {
-                        res.json({state: true});
-                    }
-                });
-            }
-            else {  // 找到用户,则提示
-                res.json({state: false, error: '“' + account + '”已存在!'});
-            }
-            ;
-        })
-    }
-
-}
-
-
-

+ 117 - 0
modules/users/models/manager_model.js

@@ -0,0 +1,117 @@
+/**
+ * 后台管理员数据模型
+ *
+ * @author CaiAoLin
+ * @date 2017/6/1
+ * @version
+ */
+import BaseModel from "../../common/base/base_model";
+import ManagerSchema from "./schemas/manager";
+import crypto from "crypto";
+
+class ManagerModel extends BaseModel {
+
+    /**
+     * 构造函数
+     *
+     * @return {void}
+     */
+    constructor() {
+        let parent = super();
+        parent.model = ManagerSchema;
+        parent.init();
+    }
+
+    /**
+     * 设置场景
+     *
+     * @param {string} scene
+     * @return {void}
+     */
+    setScene(scene = '') {
+        switch (scene) {
+            // 更改密码验证规则
+            case 'changePassword':
+                this.model.schema.path('password').required(true);
+                break;
+        }
+    }
+
+    /**
+     * 获取列表
+     *
+     * @param {object} condition
+     * @param {number} page
+     * @return {Promise}
+     */
+    getList(condition = null, page = 1) {
+        page = parseInt(page);
+        page = page <= 1 ? 1 : page;
+        let option = {page: page};
+        return this.db.find(condition, null, option);
+    }
+
+    /**
+     * 用户密码加密
+     *
+     * @param {string} token
+     * @param {string} password
+     * @return {string}
+     */
+    encryptPassword(token, password) {
+        let encryptPassword = crypto.createHmac('sha1', token).update(password)
+            .digest().toString('base64');
+        return encryptPassword;
+    }
+
+    /**
+     * 更改密码
+     *
+     * @param {string} username
+     * @param {string} password
+     * @param {string} newPassword
+     * @throws {string}
+     * @return {Promise}
+     */
+    async changePassword(username, password, newPassword) {
+
+        // 查找对应用户
+        let managerData = await this.findDataByCondition({username: username});
+        if (managerData.length <= 0) {
+            console.log('222');
+            return false;
+        }
+
+        // 验证旧密码
+        let encryptPassword = this.encryptPassword(managerData.token, password);
+        if (encryptPassword !== managerData.password) {
+            throw '用户名或密码错误';
+        }
+
+        // 加密新密码
+        let encryptNewPassword = this.encryptPassword(managerData.token, newPassword);
+        let result = await this.db.update({username: username}, {password: encryptNewPassword});
+
+        return result.ok === 1;
+    }
+
+    /**
+     * 创建管理员用户
+     *
+     * @return {Promise}
+     */
+    createManager() {
+        let insertData = {
+            username: 'test',
+            password: this.encryptPassword('DjfDTys2dh2', 'test123'),
+            token: 'DjfDTys2dh2',
+            create_time: new Date().getTime(),
+            role: 1,
+            super_admin: 1
+        };
+        return this.db.create(insertData);
+    }
+
+}
+
+export default ManagerModel;

+ 64 - 0
modules/users/models/schemas/manager.js

@@ -0,0 +1,64 @@
+/**
+ * 后台管理用户数据模型
+ *
+ * @author CaiAoLin
+ * @date 2017/7/20
+ * @version
+ */
+import mongoose from "mongoose";
+
+let Schema = mongoose.Schema;
+let collectionName = 'manager';
+let modelSchema = {
+    // 用户名
+    username: {
+        type: String,
+        index: true
+    },
+    // 密码
+    password: String,
+    // token 10位随机字符串(用于加密)
+    token: String,
+    // 最后登录时间
+    last_login: {
+        type: Number,
+        default: 0
+    },
+    // 创建时间
+    create_time: {
+        type: Number,
+        default: 0
+    },
+    // 最后登录ip
+    login_ip: {
+        type: String,
+        default: ''
+    },
+    // 登录用户电脑信息
+    login_info: {
+        type: String,
+        default: ''
+    },
+    // 是否可以登录 0为禁止登录
+    can_login: {
+        type: Number,
+        default: 1
+    },
+    // 角色id
+    role: {
+        type: Number,
+        default: 0
+    },
+    // 办事处
+    office: {
+        type: Number,
+        default: 0
+    },
+    // 超级管理员 1为超级管理员
+    super_admin: {
+        type: Number,
+        default: 0
+    }
+};
+let model = mongoose.model(collectionName, new Schema(modelSchema, {versionKey: false, collection: collectionName}));
+export {model as default, collectionName as collectionName};

+ 49 - 0
modules/users/models/schemas/user.js

@@ -0,0 +1,49 @@
+/**
+ * 用户数据模型
+ *
+ * @author CaiAoLin
+ * @date 2017/7/20
+ * @version
+ */
+
+import mongoose from "mongoose";
+
+let Schema = mongoose.Schema;
+let collectionName = 'users';
+let modelSchema = {
+    // 用户名
+    username: String,
+    // 电子邮件
+    email: String,
+    // 手机号码
+    mobile: String,
+    // 真实姓名
+    real_name: String,
+    // 公司
+    company: String,
+    // 省份
+    province: Number,
+    // 公司类型
+    company_type: {
+        type: Number,
+        default: -1
+    },
+    // 公司规模
+    company_scale: {
+        type: Number,
+        default: -1
+    },
+    // 最后登录时间
+    last_login: {
+        type: Number,
+        default: 0
+    },
+    // 创建时间
+    create_time: {
+        type: Number,
+        default: 0
+    },
+};
+let model = mongoose.model(collectionName, new Schema(modelSchema, {versionKey: false, collection: collectionName}));
+export {model as default, collectionName as collectionName};
+

+ 64 - 0
modules/users/models/user_model.js

@@ -0,0 +1,64 @@
+/**
+ * 前台用户相关数据模型
+ *
+ * @author CaiAoLin
+ * @date 2017/6/12
+ * @version
+ */
+import BaseModel from "../../common/base/base_model";
+import UserSchema from "./schemas/user";
+
+class UserModel extends BaseModel {
+
+    /**
+     * 企业所在地区
+     *
+     * @var {object}
+     */
+    province = ['广东省', '北京市'];
+
+    /**
+     * 企业类型
+     *
+     * @var
+     */
+    companyType = ['设计', '施工'];
+
+    /**
+     * 企业规模
+     *
+     * @var
+     */
+    companyScale = ['1-20', '20-50', '50-100', '100+'];
+
+    /**
+     * 构造函数
+     *
+     * @return {void}
+     */
+    constructor() {
+        let parent = super();
+        parent.model = UserSchema;
+        parent.init();
+    }
+
+    /**
+     * 获取列表
+     *
+     * @param {object} condition
+     * @param {number} page
+     * @return {promise}
+     */
+    async getList(condition = null, page = 1) {
+        page = parseInt(page);
+        page = page <= 1 ? 1 : page;
+        let option = {page: page};
+        let userList = await this.db.find(condition, null, option);
+        userList = userList.length > 0 ? userList : [];
+
+        return userList;
+    }
+
+}
+
+export default UserModel;

+ 0 - 49
modules/users/models/users.js

@@ -1,49 +0,0 @@
-//*/
-var mongoose = require("mongoose");
-
-var dbm = require("../../../config/db/db_manager");
-var umDB = dbm.getCfgConnection("usersManages");
-var usersSchema = new mongoose.Schema({ account: String, pw: String, name: String });
-var usersModel = umDB.model('users', usersSchema);
-/*/
-var umDB = require('./umDB');
-var usersSchema = new umDB.mongoose.Schema({ account: String, pw: String, name: String });
-var usersModel = umDB.mongoose.model('users', usersSchema);
-//*/
-
-var usersData = function(){};
-
-usersData.prototype.findUser = function(account, pw, controllerFun){
-    usersModel.find({"account": account, "pw": pw}, function(err, data){
-        if(data.length){
-            controllerFun(0, data[0]);
-        }
-        else{
-            controllerFun('用户名或密码错误!', 0);
-        }
-    })
-};
-
-usersData.prototype.checkAccount = function(account, controllerFun){
-    usersModel.find({"account": account}, function(err, data){
-        if(data.length){
-            controllerFun(data[0]);
-        }
-        else{
-            controllerFun(0);
-        }
-    })
-};
-
-usersData.prototype.addUser = function(account, pw, name, controllerFun){
-    var user = new usersModel({account: account, pw: pw, name: name});
-    user.save(function (err) {
-        if (err) {
-            controllerFun(err);
-        } else {
-            controllerFun(0);
-        }
-    });
-};
-
-module.exports = new usersData();

+ 20 - 0
modules/users/routes/dashboard_route.js

@@ -0,0 +1,20 @@
+/**
+ * 控制面板路由分发
+ *
+ * @author CaiAoLin
+ * @date 2017/6/2
+ * @version
+ */
+import Express from "express";
+import DashboardController from "../controllers/dashboard_controller"
+
+const router = Express.Router();
+let dashboardController = new DashboardController();
+
+module.exports =function (app) {
+
+    // action定义区域
+    router.get('/', dashboardController.auth, dashboardController.init, dashboardController.index);
+
+    app.use("/dashboard", router);
+};

+ 22 - 0
modules/users/routes/login_route.js

@@ -0,0 +1,22 @@
+/**
+ * 登录相关路由
+ *
+ * @author CaiAoLin
+ * @date 2017/6/1
+ * @version
+ */
+import Express from "express";
+import LoginController from "../controllers/login_controller";
+
+const router = Express.Router();
+const loginController = new LoginController();
+
+module.exports =function (app) {
+
+    // action定义区域
+    router.get('/', loginController.index);
+    router.post('/login', loginController.login);
+    router.get('/logout', loginController.logout);
+
+    app.use("/login", router);
+};

+ 29 - 0
modules/users/routes/manager_route.js

@@ -0,0 +1,29 @@
+/**
+ * 账号管理路由分发
+ *
+ * @author CaiAoLin
+ * @date 2017/6/2
+ * @version
+ */
+import Express from "express";
+import ManagerController from "../controllers/manager_controller";
+
+const router = Express.Router();
+const managerController = new ManagerController();
+
+module.exports =function (app) {
+
+    // 管理员列表action
+    router.get('/', managerController.auth, managerController.init, managerController.index);
+    // 修改管理员
+    router.get('/modify/:id', managerController.auth, managerController.init, managerController.modify);
+    // 删除管理员
+    router.get('/delete/:id',managerController.auth,  managerController.init, managerController.delete);
+    // 超级管理员action
+    router.get('/admin', managerController.auth, managerController.init, managerController.admin);
+    router.post('/admin', managerController.auth, managerController.init, managerController.adminSubmit);
+
+    router.get('/create', managerController.create);
+
+    app.use("/manager", router);
+};

+ 19 - 0
modules/users/routes/notify_route.js

@@ -0,0 +1,19 @@
+/**
+ * 通知相关路由
+ *
+ * @author CaiAoLin
+ * @date 2017/6/7
+ * @version
+ */
+import Express from "express";
+import NotifyController from "../controllers/notify_controller";
+
+const router = Express.Router();
+const notifyController = new NotifyController();
+
+module.exports =function (app) {
+    // action定义区域
+    router.get('/', notifyController.auth, notifyController.init, notifyController.index);
+
+    app.use("/notify", router);
+};

+ 0 - 41
modules/users/routes/users_route.js

@@ -1,41 +0,0 @@
-var express = require('express');
-var path = require('path');
-var router = express.Router();
-var uc = require('../controllers/users_controller');
-
-var htmlPath = path.join(__dirname,'../../../','web/users/');
-
-module.exports =function (app) {
-    router.get('/', function(req, res) {
-        if(!req.session.userAccount){
-            res.redirect('/login');
-        }
-        else{
-            res.redirect('/pm');
-        }
-    });
-
-    router.get('/login', function(req, res) {
-        res.render('users/login', {});
-    });
-
-    router.post('/login', uc.userLogin);
-
-    router.get('/reg', function(req, res, next) {
-        res.render('reg',{});
-    });
-
-    router.post('/reg', uc.userReg);
-
-    router.get("/logout",function(req,res){
-        delete req.session.userID;
-        delete req.session.userAccount;
-        delete req.session.userEmail;
-        delete req.session.userMobile;
-        res.redirect("/");
-    });
-    app.use('/',router);
-};
-
-
-

+ 14 - 9
operation.js

@@ -11,6 +11,7 @@ let path = require('path');
 let session = require('express-session');
 let DBStore = require('connect-mongo')(session);
 let fileUtils = require("./modules/common/fileUtils");
+let partials = require("express-partials");
 
 let URL = require('url');
 let fs = require('fs');
@@ -25,6 +26,10 @@ app.use(express.static(_rootDir));
 app.set('views', path.join(__dirname, 'web'));
 app.engine('.html', require('ejs').__express);
 app.set('view engine', 'html');
+app.set('view options', {
+    defaultLayout: 'users/views/layout/layout'
+});
+app.use(partials());
 
 let bodyParser = require('body-parser');
 app.use(bodyParser.urlencoded({extended: false}));
@@ -45,15 +50,15 @@ app.use(session({
 }));
 
 app.use(function (req, res, next) {
-    let url = req.originalUrl, referer;
-    if (!/^\/login/.test(req.originalUrl) && !req.session.userAccount) {
-        if (/\/api/.test(req.originalUrl)) {
-            referer = URL.parse(req.headers.referer);
-            return res.redirect('/login' + '?referer=' + referer.path);
-        } else {
-            return res.redirect("/login" + '?referer=' + req.originalUrl);
-        }
-    }
+    // let url = req.originalUrl, referer;
+    // if (!/^\/login/.test(req.originalUrl) && !req.session.userAccount) {
+    //     if (/\/api/.test(req.originalUrl)) {
+    //         referer = URL.parse(req.headers.referer);
+    //         return res.redirect('/login' + '?referer=' + referer.path);
+    //     } else {
+    //         return res.redirect("/login" + '?referer=' + req.originalUrl);
+    //     }
+    // }
     next();
 });
 

+ 2 - 0
package.json

@@ -7,6 +7,7 @@
     "babel-preset-es2015": "^6.24.1",
     "babel-preset-stage-2": "^6.24.1",
     "express": "^4.13.1",
+    "express-partials": "^0.3.0",
     "mongoose": "^4.8.5",
     "async": "^2.1.5",
     "connect-mongo": "^1.3.2",
@@ -14,6 +15,7 @@
     "debug": "~2.6.0",
     "ejs": "~2.5.5",
     "express-session": "^1.15.1",
+    "moment": "^2.18.1",
     "request": "^2.79.0",
     "tape": "^4.6.3",
     "glob": "~4.0.5"

+ 1 - 1
public/rpt_tpl_def.js

@@ -5,7 +5,7 @@
 const fs = require('fs');
 var rptTplDef = null;
 
-getTreeNodeUtil = function() {
+var getTreeNodeUtil = function() {
     if (!(rptTplDef)) {
         var data = fs.readFileSync(__dirname + '/web/rpt_tpl_def.js', 'utf8', 'r');
         eval(data + ' ; rptTplDef = RT;');

文件差异内容过多而无法显示
+ 6 - 0
web/users/css/bootstrap.min.css


+ 296 - 0
web/users/css/style.css

@@ -0,0 +1,296 @@
+@charset "utf-8";
+/*
+1.登录
+2.主体框架
+3.侧栏主菜单
+4.内容区
+*/
+/*1.登录*/
+body{
+  background:#ededed
+}
+.loginItem {
+  padding:5px 20px 25px;
+  margin-bottom:20px;
+  background: #fff;
+  border-radius: 3px;
+  box-shadow: 0 2px 6px 0 rgba(0,0,0,.15)
+}
+.wraplogin {
+  width:690px;
+  margin:5% auto 0px;
+}
+.wraplogin .loginItem{
+  padding:0;
+  width:400px;
+  position: relative;
+  z-index: 1
+}
+.wraplogin .loginTop {
+  text-align: center;
+  color:#428BCA;
+  padding:30px 0;
+}
+.wraplogin .loginTop a{
+  font-size:30px
+}
+.wraplogin .loginTop a:hover{
+  text-decoration: none;
+}
+.wraplogin .loginForm{
+  padding: 20px 20px 10px
+}
+.wraplogin .loginBottom{
+  padding: 10px 20px 25px;
+  color: #ccc
+}
+/*2.主体框架*/
+.header {
+  background:#f4f5f5;
+  position: fixed;
+  z-index: 10;
+  width: 100%;
+  height: 50px;
+  top: 0;
+  left: 0;
+  border-bottom: 1px solid #ddd
+}
+.main{
+  position: relative;
+  z-index: 4;
+}
+.main-nav {
+  position: fixed;
+  z-index: 99;
+  width:124px;
+  left: 0;
+  top: 0;
+  height: 100%;
+  background: #f4f5f5;
+  border-right:1px solid #ddd;
+  box-shadow: 3px 0 10px 2px #e3e3e3
+}
+.main-panel{
+  padding-left:124px;
+  box-sizing: border-box;
+}
+.panel-sidebar{
+  box-sizing: border-box;
+  background: #fbfcfd;
+  position: fixed;
+  height: 100%;
+  z-index: 4;
+  left:124px;
+  padding-top: 100px;
+  border-right: 1px solid #ddd;
+  width: 200px
+}
+.panel-content{
+  padding:115px 0 0;
+  position: relative;
+  z-index: 3;
+  box-sizing: border-box;
+  overflow-y: auto;
+  height: 100vh;
+}
+.panel-content .content-wrap{
+  margin:0 15px 15px;
+}
+.panel-sidebar+.panel-content{
+  padding: 115px 0 0 200px;
+}
+.panel-title, .panel-title>.title-bar {
+  height:50px;
+  line-height: 50px
+}
+.panel-title{
+  position: fixed;
+  top: 50px;
+  z-index: 98;
+  width: 100%;
+  box-sizing: border-box;
+  background: #fff;
+  box-shadow: 0 1px 3px rgba(0,0,0,.05)
+}
+.panel-sidebar .panel-title{
+  width:200px;
+  border-right: 1px solid #ddd;
+  box-shadow: 0 1px 3px rgba(0,0,0,.1);
+}
+.panel-content .panel-title{
+  left: 0;
+  padding-left: 324px;
+  padding-right: 20px;
+}
+.panel-content .panel-title.fluid{
+  padding-left:124px
+}
+.panel-title>.title-bar{
+  padding-left: 20px
+}
+.panel-title>.title-bar>h2,.panel-title>.title-main>h2{
+  font-size: 16px;
+  margin:0;
+  height: 50px;
+  line-height: 50px;
+  display:block
+}
+.panel-title>.title-bar>h2 .btn{
+  margin-right:15px
+}
+.panel-title>.title-main .btn {
+  margin:0 0 0 20px
+}
+.panel-title>.title-main .btn.pull-right {
+  margin:10px 0 0 10px
+}
+.panel-title>.title-main{
+  padding-left: 15px
+}
+/*滚动*/
+.scrollbar-auto {
+    overflow-y: auto;
+    position: absolute;
+    bottom: 0;
+    left: 0;
+    top: 0;
+    right: 0;
+}
+.panel-sidebar .scrollbar-auto{
+    padding-top: 20px;
+    box-sizing: border-box;
+}
+.panel-sidebar .scrollbar-auto {
+    height: 100%;
+    width: 100%;
+    overflow-y: auto;
+    position: static;
+}
+/*头部*/
+.header .logo {
+  float: left;
+  margin-right: 20px;
+  margin:0
+}
+.header .logo>a{
+  height:50px;
+  line-height: 50px;
+  display: inline-block;
+  color:#337ab7;
+  font-size:20px;
+  padding:0 10px;
+  text-align: center
+}
+.header .logo>a:hover{
+  text-decoration: none;
+}
+.header-user > div {
+  float:left
+}
+.avatar .pic {
+  height: 35px;
+  width: 35px;
+  border-radius: 100%;
+  display: inline-block;
+  float:left;
+  margin:7px 7px 0 0
+}
+.avatar .pic img{
+  display: block;
+  width: 100%;
+  height: 100%;
+  border-radius: 100%;
+}
+.avatar > a{
+  display: block;
+  height:50px;
+  line-height: 50px;
+  color:#666;
+  padding:0 15px;
+  cursor: pointer;
+}
+.avatar > a:hover{
+  text-decoration: none;
+  box-shadow: inset 0 3px 5px rgba(0,0,0,.125)
+}
+.header .poj-name {
+  float:left;
+  height:50px;
+  line-height:50px;
+  padding:0 0 0 15px;
+  font-size:18px
+}
+.header .poj-name a{
+  color:#666
+}
+/*侧栏主菜单*/
+.nav-top{
+  padding-top: 50px
+}
+.bg-nav a{
+  color:#999;
+}
+.bg-nav > li.active > a{
+  border-radius: 0;
+  background: #666
+}
+.bg-nav > li > a:hover,.bg-nav > li.active > a:hover{
+  background: #999;
+  color:#f2f2f2;
+  border-radius: 0
+}
+.bg-nav > li + li {
+    margin-top:0;
+}
+.nav-box h3{
+  font-size: 14px;
+  font-weight: 700;
+  padding-bottom: 4px;
+  border-bottom: 1px solid #e2eaec;
+  padding-right: 15px;
+  margin-bottom: 10px;
+  margin-left: 20px
+}
+.nav-list li a{
+  color: #333;
+  display: block;
+  height: 35px;
+  line-height: 35px;
+  box-sizing: border-box;
+  padding-left: 17px;
+  padding-right: 45px;
+  text-overflow: ellipsis;
+  position: relative;
+}
+.nav-list li a:hover{
+  text-decoration: none;
+  background:#efefef;
+  cursor: pointer;
+}
+.nav-list li a .badge{
+  position: absolute;
+  right:17px;
+  top:9px
+}
+.nav-list li.active a{
+  background:#e1e1e1
+}
+.nav-list li.active .badge{
+  background:#207fd1
+}
+/*内容区*/
+.c-header {
+  padding:0 0 5px
+}
+.c-body{
+  padding:15px;
+  background:#fff;
+  box-shadow:0 1px 3px rgba(0,0,0,.05)
+}
+.form-group .necessary{
+  font-size:18px;
+  color:#f90000
+}
+.mb-30 {
+  margin-bottom:30px
+}

二进制
web/users/fonts/glyphicons-halflings-regular.eot


文件差异内容过多而无法显示
+ 288 - 0
web/users/fonts/glyphicons-halflings-regular.svg


二进制
web/users/fonts/glyphicons-halflings-regular.ttf


二进制
web/users/fonts/glyphicons-halflings-regular.woff


二进制
web/users/fonts/glyphicons-halflings-regular.woff2


+ 49 - 0
web/users/js/admin.js

@@ -0,0 +1,49 @@
+/**
+ * 后台用户修改相关js
+ *
+ * @author CaiAoLin
+ * @date 2017/6/6
+ * @version
+ */
+let rules = {
+    newPassword: {
+        required: true,
+        minlength: 6
+    },
+    password: {
+        required: true,
+        minlength: 4
+    }
+};
+$(document).ready(function() {
+
+    // 新增只有前端需要的验证规则
+    rules.confirmPassword = {
+        required: true,
+        equalTo: "input[name='newPassword']"
+    };
+
+    // 表单验证规则
+    $("#save-form").validate({
+        rules: rules,
+        errorPlacement: function(error, element) {
+            error.addClass('help-block');
+            let parentEle = $(element).parent();
+            parentEle.addClass('has-warning');
+            $(element).prev('label').addClass('control-label');
+            $(element).after('<span class="glyphicon glyphicon-warning-sign form-control-feedback" aria-hidden="true"></span>');
+            $(element).after(error);
+        },
+        errorElement: "span",
+        success: function(element) {
+            $(element).parent().removeClass('has-warning');
+            $(element).siblings('.glyphicon-warning-sign').remove();
+        }
+    });
+
+    // 保存数据
+    $("#save").click(function() {
+        $("#save-form").attr('action', '/manager/admin').submit();
+    });
+
+});

+ 29 - 0
web/users/js/global.js

@@ -0,0 +1,29 @@
+/*自动高度*/
+function autoFlashHeight() {
+    $(".wrapContent").height($(window).height() - 48);
+    $(".mainContent").height($(window).height() - 48);
+    $(".scollContent").height($(window).height() - 130);
+    $(".slideContent").height($(window).height() - 46);
+};
+$(window).resize(autoFlashHeight);
+$(function () {
+    /*登录页*/
+    function waveloop1() {
+        $("#wave_bg_1").css({"left": "-236px"}).animate({"left": "-1233px"}, 25000, 'linear', waveloop1);
+    }
+
+    function waveloop2() {
+        $("#wave_bg_2").css({"left": "0px"}).animate({"left": "-1009px"}, 60000, 'linear', waveloop2);
+    }
+
+    waveloop1();
+    waveloop2();
+    /*工具提示*/
+    $(function () {
+        $('[data-toggle="tooltip"]').tooltip()
+    });
+    $(function () {
+        $('[data-toggle="popover"]').popover()
+    });
+
+});

+ 657 - 0
web/users/js/lib/bootstrap-paginator.js

@@ -0,0 +1,657 @@
+/**
+ * bootstrap-paginator.js v0.5
+ * --
+ * Copyright 2013 Yun Lai <lyonlai1984@gmail.com>
+ * --
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+(function ($) {
+
+    "use strict"; // jshint ;_;
+
+
+    /* Paginator PUBLIC CLASS DEFINITION
+     * ================================= */
+
+    /**
+     * Boostrap Paginator Constructor
+     *
+     * @param element element of the paginator
+     * @param options the options to config the paginator
+     *
+     * */
+    var BootstrapPaginator = function (element, options) {
+        this.init(element, options);
+    },
+        old = null;
+
+    BootstrapPaginator.prototype = {
+
+        /**
+         * Initialization function of the paginator, accepting an element and the options as parameters
+         *
+         * @param element element of the paginator
+         * @param options the options to config the paginator
+         *
+         * */
+        init: function (element, options) {
+
+            this.$element = $(element);
+
+            var version = (options && options.bootstrapMajorVersion) ? options.bootstrapMajorVersion : $.fn.bootstrapPaginator.defaults.bootstrapMajorVersion,
+                id = this.$element.attr("id");
+
+            if (version === 2 && !this.$element.is("div")) {
+
+                throw "in Bootstrap version 2 the pagination must be a div element. Or if you are using Bootstrap pagination 3. Please specify it in bootstrapMajorVersion in the option";
+            } else if (version > 2 && !this.$element.is("ul")) {
+                throw "in Bootstrap version 3 the pagination root item must be an ul element."
+            }
+
+
+
+            this.currentPage = 1;
+
+            this.lastPage = 1;
+
+            this.setOptions(options);
+
+            this.initialized = true;
+        },
+
+        /**
+         * Update the properties of the paginator element
+         *
+         * @param options options to config the paginator
+         * */
+        setOptions: function (options) {
+
+            this.options = $.extend({}, (this.options || $.fn.bootstrapPaginator.defaults), options);
+
+            this.totalPages = parseInt(this.options.totalPages, 10);  //setup the total pages property.
+            this.numberOfPages = parseInt(this.options.numberOfPages, 10); //setup the numberOfPages to be shown
+
+            //move the set current page after the setting of total pages. otherwise it will cause out of page exception.
+            if (options && typeof (options.currentPage)  !== 'undefined') {
+
+                this.setCurrentPage(options.currentPage);
+            }
+
+            this.listen();
+
+            //render the paginator
+            this.render();
+
+            if (!this.initialized && this.lastPage !== this.currentPage) {
+                this.$element.trigger("page-changed", [this.lastPage, this.currentPage]);
+            }
+
+        },
+
+        /**
+         * Sets up the events listeners. Currently the pageclicked and pagechanged events are linked if available.
+         *
+         * */
+        listen: function () {
+
+            this.$element.off("page-clicked");
+
+            this.$element.off("page-changed");// unload the events for the element
+
+            if (typeof (this.options.onPageClicked) === "function") {
+                this.$element.bind("page-clicked", this.options.onPageClicked);
+            }
+
+            if (typeof (this.options.onPageChanged) === "function") {
+                this.$element.on("page-changed", this.options.onPageChanged);
+            }
+
+            this.$element.bind("page-clicked", this.onPageClicked);
+        },
+
+
+        /**
+         *
+         *  Destroys the paginator element, it unload the event first, then empty the content inside.
+         *
+         * */
+        destroy: function () {
+
+            this.$element.off("page-clicked");
+
+            this.$element.off("page-changed");
+
+            this.$element.removeData('bootstrapPaginator');
+
+            this.$element.empty();
+
+        },
+
+        /**
+         * Shows the page
+         *
+         * */
+        show: function (page) {
+
+            this.setCurrentPage(page);
+
+            this.render();
+
+            if (this.lastPage !== this.currentPage) {
+                this.$element.trigger("page-changed", [this.lastPage, this.currentPage]);
+            }
+        },
+
+        /**
+         * Shows the next page
+         *
+         * */
+        showNext: function () {
+            var pages = this.getPages();
+
+            if (pages.next) {
+                this.show(pages.next);
+            }
+
+        },
+
+        /**
+         * Shows the previous page
+         *
+         * */
+        showPrevious: function () {
+            var pages = this.getPages();
+
+            if (pages.prev) {
+                this.show(pages.prev);
+            }
+
+        },
+
+        /**
+         * Shows the first page
+         *
+         * */
+        showFirst: function () {
+            var pages = this.getPages();
+
+            if (pages.first) {
+                this.show(pages.first);
+            }
+
+        },
+
+        /**
+         * Shows the last page
+         *
+         * */
+        showLast: function () {
+            var pages = this.getPages();
+
+            if (pages.last) {
+                this.show(pages.last);
+            }
+
+        },
+
+        /**
+         * Internal on page item click handler, when the page item is clicked, change the current page to the corresponding page and
+         * trigger the pageclick event for the listeners.
+         *
+         *
+         * */
+        onPageItemClicked: function (event) {
+
+            var type = event.data.type,
+                page = event.data.page;
+
+            this.$element.trigger("page-clicked", [event, type, page]);
+
+        },
+
+        onPageClicked: function (event, originalEvent, type, page) {
+
+            //show the corresponding page and retrieve the newly built item related to the page clicked before for the event return
+
+            var currentTarget = $(event.currentTarget);
+
+            switch (type) {
+            case "first":
+                currentTarget.bootstrapPaginator("showFirst");
+                break;
+            case "prev":
+                currentTarget.bootstrapPaginator("showPrevious");
+                break;
+            case "next":
+                currentTarget.bootstrapPaginator("showNext");
+                break;
+            case "last":
+                currentTarget.bootstrapPaginator("showLast");
+                break;
+            case "page":
+                currentTarget.bootstrapPaginator("show", page);
+                break;
+            }
+
+        },
+
+        /**
+         * Renders the paginator according to the internal properties and the settings.
+         *
+         *
+         * */
+        render: function () {
+
+            //fetch the container class and add them to the container
+            var containerClass = this.getValueFromOption(this.options.containerClass, this.$element),
+                size = this.options.size || "normal",
+                alignment = this.options.alignment || "left",
+                pages = this.getPages(),
+                listContainer = this.options.bootstrapMajorVersion === 2 ? $("<ul></ul>") : this.$element,
+                listContainerClass = this.options.bootstrapMajorVersion === 2 ? this.getValueFromOption(this.options.listContainerClass, listContainer) : null,
+                first = null,
+                prev = null,
+                next = null,
+                last = null,
+                p = null,
+                i = 0;
+
+
+            this.$element.prop("class", "");
+
+            this.$element.addClass("pagination");
+
+            switch (size.toLowerCase()) {
+            case "large":
+            case "small":
+            case "mini":
+                this.$element.addClass($.fn.bootstrapPaginator.sizeArray[this.options.bootstrapMajorVersion][size.toLowerCase()]);
+                break;
+            default:
+                break;
+            }
+
+            if (this.options.bootstrapMajorVersion === 2) {
+                switch (alignment.toLowerCase()) {
+                case "center":
+                    this.$element.addClass("pagination-centered");
+                    break;
+                case "right":
+                    this.$element.addClass("pagination-right");
+                    break;
+                default:
+                    break;
+                }
+            }
+
+
+            this.$element.addClass(containerClass);
+
+            //empty the outter most container then add the listContainer inside.
+            this.$element.empty();
+
+            if (this.options.bootstrapMajorVersion === 2) {
+                this.$element.append(listContainer);
+
+                listContainer.addClass(listContainerClass);
+            }
+
+            //update the page element reference
+            this.pageRef = [];
+
+            if (pages.first) {//if the there is first page element
+                first = this.buildPageItem("first", pages.first);
+
+                if (first) {
+                    listContainer.append(first);
+                }
+
+            }
+
+            if (pages.prev) {//if the there is previous page element
+
+                prev = this.buildPageItem("prev", pages.prev);
+
+                if (prev) {
+                    listContainer.append(prev);
+                }
+
+            }
+
+
+            for (i = 0; i < pages.length; i = i + 1) {//fill the numeric pages.
+
+                p = this.buildPageItem("page", pages[i]);
+
+                if (p) {
+                    listContainer.append(p);
+                }
+            }
+
+            if (pages.next) {//if there is next page
+
+                next = this.buildPageItem("next", pages.next);
+
+                if (next) {
+                    listContainer.append(next);
+                }
+            }
+
+            if (pages.last) {//if there is last page
+
+                last = this.buildPageItem("last", pages.last);
+
+                if (last) {
+                    listContainer.append(last);
+                }
+            }
+        },
+
+        /**
+         *
+         * Creates a page item base on the type and page number given.
+         *
+         * @param page page number
+         * @param type type of the page, whether it is the first, prev, page, next, last
+         *
+         * @return Object the constructed page element
+         * */
+        buildPageItem: function (type, page) {
+
+            var itemContainer = $("<li></li>"),//creates the item container
+                itemContent = $("<a></a>"),//creates the item content
+                text = "",
+                title = "",
+                itemContainerClass = this.options.itemContainerClass(type, page, this.currentPage),
+                itemContentClass = this.getValueFromOption(this.options.itemContentClass, type, page, this.currentPage),
+                tooltipOpts = null;
+
+
+            switch (type) {
+
+            case "first":
+                if (!this.getValueFromOption(this.options.shouldShowPage, type, page, this.currentPage)) { return; }
+                text = this.options.itemTexts(type, page, this.currentPage);
+                title = this.options.tooltipTitles(type, page, this.currentPage);
+                break;
+            case "last":
+                if (!this.getValueFromOption(this.options.shouldShowPage, type, page, this.currentPage)) { return; }
+                text = this.options.itemTexts(type, page, this.currentPage);
+                title = this.options.tooltipTitles(type, page, this.currentPage);
+                break;
+            case "prev":
+                if (!this.getValueFromOption(this.options.shouldShowPage, type, page, this.currentPage)) { return; }
+                text = this.options.itemTexts(type, page, this.currentPage);
+                title = this.options.tooltipTitles(type, page, this.currentPage);
+                break;
+            case "next":
+                if (!this.getValueFromOption(this.options.shouldShowPage, type, page, this.currentPage)) { return; }
+                text = this.options.itemTexts(type, page, this.currentPage);
+                title = this.options.tooltipTitles(type, page, this.currentPage);
+                break;
+            case "page":
+                if (!this.getValueFromOption(this.options.shouldShowPage, type, page, this.currentPage)) { return; }
+                text = this.options.itemTexts(type, page, this.currentPage);
+                title = this.options.tooltipTitles(type, page, this.currentPage);
+                break;
+            }
+
+            itemContainer.addClass(itemContainerClass).append(itemContent);
+
+            itemContent.addClass(itemContentClass).html(text).on("click", null, {type: type, page: page}, $.proxy(this.onPageItemClicked, this));
+
+            if (this.options.pageUrl) {
+                itemContent.attr("href", this.getValueFromOption(this.options.pageUrl, type, page, this.currentPage));
+            }
+
+            if (this.options.useBootstrapTooltip) {
+                tooltipOpts = $.extend({}, this.options.bootstrapTooltipOptions, {title: title});
+
+                itemContent.tooltip(tooltipOpts);
+            } else {
+                itemContent.attr("title", title);
+            }
+
+            return itemContainer;
+
+        },
+
+        setCurrentPage: function (page) {
+            if (page > this.totalPages || page < 1) {// if the current page is out of range, throw exception.
+
+                throw "Page out of range";
+
+            }
+
+            this.lastPage = this.currentPage;
+
+            this.currentPage = parseInt(page, 10);
+
+        },
+
+        /**
+         * Gets an array that represents the current status of the page object. Numeric pages can be access via array mode. length attributes describes how many numeric pages are there. First, previous, next and last page can be accessed via attributes first, prev, next and last. Current attribute marks the current page within the pages.
+         *
+         * @return object output objects that has first, prev, next, last and also the number of pages in between.
+         * */
+        getPages: function () {
+
+            var totalPages = this.totalPages,// get or calculate the total pages via the total records
+                pageStart = (this.currentPage % this.numberOfPages === 0) ? (parseInt(this.currentPage / this.numberOfPages, 10) - 1) * this.numberOfPages + 1 : parseInt(this.currentPage / this.numberOfPages, 10) * this.numberOfPages + 1,//calculates the start page.
+                output = [],
+                i = 0,
+                counter = 0;
+
+            pageStart = pageStart < 1 ? 1 : pageStart;//check the range of the page start to see if its less than 1.
+
+            for (i = pageStart, counter = 0; counter < this.numberOfPages && i <= totalPages; i = i + 1, counter = counter + 1) {//fill the pages
+                output.push(i);
+            }
+
+            output.first = 1;//add the first when the current page leaves the 1st page.
+
+            if (this.currentPage > 1) {// add the previous when the current page leaves the 1st page
+                output.prev = this.currentPage - 1;
+            } else {
+                output.prev = 1;
+            }
+
+            if (this.currentPage < totalPages) {// add the next page when the current page doesn't reach the last page
+                output.next = this.currentPage + 1;
+            } else {
+                output.next = totalPages;
+            }
+
+            output.last = totalPages;// add the last page when the current page doesn't reach the last page
+
+            output.current = this.currentPage;//mark the current page.
+
+            output.total = totalPages;
+
+            output.numberOfPages = this.options.numberOfPages;
+
+            return output;
+
+        },
+
+        /**
+         * Gets the value from the options, this is made to handle the situation where value is the return value of a function.
+         *
+         * @return mixed value that depends on the type of parameters, if the given parameter is a function, then the evaluated result is returned. Otherwise the parameter itself will get returned.
+         * */
+        getValueFromOption: function (value) {
+
+            var output = null,
+                args = Array.prototype.slice.call(arguments, 1);
+
+            if (typeof value === 'function') {
+                output = value.apply(this, args);
+            } else {
+                output = value;
+            }
+
+            return output;
+
+        }
+
+    };
+
+
+    /* TYPEAHEAD PLUGIN DEFINITION
+     * =========================== */
+
+    old = $.fn.bootstrapPaginator;
+
+    $.fn.bootstrapPaginator = function (option) {
+
+        var args = arguments,
+            result = null;
+
+        $(this).each(function (index, item) {
+            var $this = $(item),
+                data = $this.data('bootstrapPaginator'),
+                options = (typeof option !== 'object') ? null : option;
+
+            if (!data) {
+                data = new BootstrapPaginator(this, options);
+
+                $this = $(data.$element);
+
+                $this.data('bootstrapPaginator', data);
+
+                return;
+            }
+
+            if (typeof option === 'string') {
+
+                if (data[option]) {
+                    result = data[option].apply(data, Array.prototype.slice.call(args, 1));
+                } else {
+                    throw "Method " + option + " does not exist";
+                }
+
+            } else {
+                result = data.setOptions(option);
+            }
+        });
+
+        return result;
+
+    };
+
+    $.fn.bootstrapPaginator.sizeArray = {
+
+        "2": {
+            "large": "pagination-large",
+            "small": "pagination-small",
+            "mini": "pagination-mini"
+        },
+        "3": {
+            "large": "pagination-lg",
+            "small": "pagination-sm",
+            "mini": ""
+        }
+
+    };
+
+    $.fn.bootstrapPaginator.defaults = {
+        containerClass: "",
+        size: "normal",
+        alignment: "left",
+        bootstrapMajorVersion: 2,
+        listContainerClass: "",
+        itemContainerClass: function (type, page, current) {
+            return (page === current) ? "active" : "";
+        },
+        itemContentClass: function (type, page, current) {
+            return "";
+        },
+        currentPage: 1,
+        numberOfPages: 5,
+        totalPages: 1,
+        pageUrl: function (type, page, current) {
+            return null;
+        },
+        onPageClicked: null,
+        onPageChanged: null,
+        useBootstrapTooltip: false,
+        shouldShowPage: function (type, page, current) {
+
+            var result = true;
+
+            switch (type) {
+            case "first":
+                result = (current !== 1);
+                break;
+            case "prev":
+                result = (current !== 1);
+                break;
+            case "next":
+                result = (current !== this.totalPages);
+                break;
+            case "last":
+                result = (current !== this.totalPages);
+                break;
+            case "page":
+                result = true;
+                break;
+            }
+
+            return result;
+
+        },
+        itemTexts: function (type, page, current) {
+            switch (type) {
+            case "first":
+                return "&lt;&lt;";
+            case "prev":
+                return "&lt;";
+            case "next":
+                return "&gt;";
+            case "last":
+                return "&gt;&gt;";
+            case "page":
+                return page;
+            }
+        },
+        tooltipTitles: function (type, page, current) {
+
+            switch (type) {
+            case "first":
+                return "Go to first page";
+            case "prev":
+                return "Go to previous page";
+            case "next":
+                return "Go to next page";
+            case "last":
+                return "Go to last page";
+            case "page":
+                return (page === current) ? "Current page is " + page : "Go to page " + page;
+            }
+        },
+        bootstrapTooltipOptions: {
+            animation: true,
+            html: true,
+            placement: 'top',
+            selector: false,
+            title: "",
+            container: false
+        }
+    };
+
+    $.fn.bootstrapPaginator.Constructor = BootstrapPaginator;
+
+
+
+}(window.jQuery));

文件差异内容过多而无法显示
+ 7 - 0
web/users/js/lib/bootstrap.min.js


文件差异内容过多而无法显示
+ 1578 - 0
web/users/js/lib/jquery.validate.js


+ 33 - 0
web/users/js/lib/messages_zh.js

@@ -0,0 +1,33 @@
+(function( factory ) {
+	if ( typeof define === "function" && define.amd ) {
+		define( ["jquery", "../jquery.validate"], factory );
+	} else {
+		factory( jQuery );
+	}
+}(function( $ ) {
+
+/*
+ * Translated default messages for the jQuery validation plugin.
+ * Locale: ZH (Chinese, 中文 (Zhōngwén), 汉语, 漢語)
+ */
+$.extend($.validator.messages, {
+	required: "这是必填字段",
+	remote: "请修正此字段",
+	email: "请输入有效的电子邮件地址",
+	url: "请输入有效的网址",
+	date: "请输入有效的日期",
+	dateISO: "请输入有效的日期 (YYYY-MM-DD)",
+	number: "请输入有效的数字",
+	digits: "只能输入数字",
+	creditcard: "请输入有效的信用卡号码",
+	equalTo: "你的输入不相同",
+	extension: "请输入有效的后缀",
+	maxlength: $.validator.format("最多可以输入 {0} 个字符"),
+	minlength: $.validator.format("最少要输入 {0} 个字符"),
+	rangelength: $.validator.format("请输入长度在 {0} 到 {1} 之间的字符串"),
+	range: $.validator.format("请输入范围在 {0} 到 {1} 之间的数值"),
+	max: $.validator.format("请输入不大于 {0} 的数值"),
+	min: $.validator.format("请输入不小于 {0} 的数值")
+});
+
+}));

+ 14 - 0
web/users/js/lib/validate.extend.js

@@ -0,0 +1,14 @@
+/**
+ * jQuery validate 自定义验证
+ *
+ * @author CaiAoLin
+ * @date 2017/6/8
+ * @version
+ */
+
+//检测手机号是否正确
+jQuery.validator.addMethod("isMobile", function (value, element) {
+    let length = value.length;
+    let regPhone = /^1([34578]\d)\d{8}$/;
+    return this.optional(element) || (length == 11 && regPhone.test(value));
+}, "请正确填写您的手机号码");

+ 80 - 0
web/users/js/login.js

@@ -0,0 +1,80 @@
+/**
+ * 登录相关js
+ *
+ * @author CaiAoLin
+ * @date 2017/6/1
+ * @version
+ */
+let rules = {
+    username: {
+        required: true,
+        minlength: 2
+    },
+    password:{
+        required: true,
+        minlength: 4
+    }
+};
+$(document).ready(function() {
+    $("#login-form").validate({
+        rules: rules,
+        errorPlacement: function(error, element) {
+            error.addClass('help-block');
+            let parentEle = $(element).parent();
+            parentEle.parent().addClass('has-error');
+            $(element).parent().after(error);
+        },
+        errorElement: "span",
+        success: function(element) {
+            $("#common-error").remove();
+            $(element).parent().removeClass('has-error');
+        }
+    });
+
+    // 登录操作
+    let isLogin = false;
+    $("#login").click(function() {
+        if (isLogin) {
+            return false;
+        }
+        // 验证数据
+        if (!$("#login-form").valid()) {
+            return false;
+        }
+        let username = $("#username").val();
+        let password = $("#password").val();
+        $.ajax({
+            url: '/login/login',
+            type: 'post',
+            data: {username: username, password: password},
+            dataType: 'json',
+            error: function() {
+                isLogin = false;
+            },
+            beforeSend: function() {
+                isLogin = true;
+            },
+            success: function(response) {
+                console.log('test');
+                isLogin = false;
+                if (response.error === 0) {
+                    // 正确则跳转
+                    window.location.href = '/dashboard';
+                } else {
+                    // 错误则提示
+                    show_error(response.msg);
+                }
+            }
+        });
+    });
+});
+/**
+ * 显示错误
+ *
+ * @param {string} msg
+ * @return {void}
+ */
+function show_error(msg) {
+    $("form > .form-group").addClass('has-error');
+    $("input").last().parent().after('<span id="common-error" class="error help-block">'+ msg +'</span>');
+}

+ 0 - 88
web/users/login-infoinput.html

@@ -1,88 +0,0 @@
-<!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>用户信息填写-Smartcost</title>
-    <link rel="stylesheet" href="css/bootstrap/bootstrap.min.css">
-    <link rel="stylesheet" href="css/bootstrap/themes.css">
-    <link rel="stylesheet" href="css/main.css">
-    <link rel="stylesheet" href="css/font-awesome/font-awesome.min.css">
-</head>
-
-<body>
-    <div class="header">
-        <nav class="navbar navbar-toggleable-lg navbar-light bg-faded p-0 justify-content-between">
-            <span class="header-logo px-2">Smartcost</span>
-            <div class="float-lg-right navbar-text pt-0">
-                <div class=" d-inline-block">
-                    <button class="btn btn-link btn-sm " type="button">15812644017</button>
-                </div>
-                <span class="btn btn-link btn-sm new-msg">
-                  <i class="fa fa-envelope-o" aria-hidden="true"></i>&nbsp;2
-                </span>
-                <button class="btn btn-link btn-sm">注销</button>
-            </div>
-        </nav>
-    </div>
-    <div class="container mt-3">
-        <div class="row">
-            <div class="col-lg-8 offset-lg-2">
-                <div class="card newuser-input">
-                    <div class="card-block">
-                        <h4 class="card-title">在开始使用前,请填写以下信息。</h4>
-                        <h6 class="card-subtitle text-muted">详细填写这些信息,可以让我们更好的服务您。</h6>
-                    </div>
-                    <div class="card-block">
-                            <div class="form-group">
-                                <input class="form-control" placeholder="你的姓名" required="" autofocus="">
-                            </div>
-                            <div class="form-group">
-                                <input class="form-control" placeholder="企业名称" required="" autofocus="">
-                            </div>
-                            <div class="form-group">
-                                <select class="form-control">
-                                  <option>请选择企业所在地区</option>
-                                  <option>广东省</option>
-                                  <option>北京市</option>
-                                </select>
-                            </div>
-                        <div class="form-group">
-                            <a class="btn btn-link" data-toggle="collapse" href="#moreinfo" aria-expanded="false" aria-controls="moreinfo">更多选项</a>
-                        </div>
-                        <div class="collapse" id="moreinfo">
-                                <div class="form-group">
-                                    <select class="form-control">
-                                     <option>请选择企业类型</option>
-                                     <option>设计</option>
-                                     <option>施工</option>
-                                   </select>
-                                </div>
-                                <div class="form-group">
-                                    <select class="form-control">
-                                     <option>请选择企业规模</option>
-                                     <option>1-20</option>
-                                     <option>20-50</option>
-                                     <option>50-100</option>
-                                     <option>100+</option>
-                                   </select>
-                                </div>
-                        </div>
-                        <div class="form-group">
-                            <a class="btn btn-primary btn-block" href="login-welcome.html">下一步</a>
-                        </div>
-                    </div>
-                </div>
-            </div>
-        </div>
-    </div>
-    <!-- JS. -->
-    <script src="js/jquery/jquery.min.js"></script>
-    <script src="js/tether/tether.min.js"></script>
-    <script src="js/bootstrap/bootstrap.min.js"></script>
-    <script src="js/global.js"></script>
-</body>
-
-</html>

+ 0 - 296
web/users/login-welcome.html

@@ -1,296 +0,0 @@
-<!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>项目管理-Smartcost</title>
-    <link rel="stylesheet" href="css/bootstrap/bootstrap.min.css">
-    <link rel="stylesheet" href="css/bootstrap/themes.css">
-    <link rel="stylesheet" href="css/main.css">
-    <link rel="stylesheet" href="css/font-awesome/font-awesome.min.css">
-</head>
-
-<body>
-    <div class="header">
-      <nav class="navbar navbar-toggleable-lg navbar-light bg-faded p-0 justify-content-between">
-      <span class="header-logo px-2">Smartcost</span>
-      <div class="navbar-text pt-0">
-          <div class="dropdown d-inline-block">
-              <button class="btn btn-link btn-sm dropdown-toggle" type="button" data-toggle="dropdown">陈特</button>
-              <div class="dropdown-menu dropdown-menu-right">
-                  <a class="dropdown-item" href="user-info.html" target="_blank">账号资料</a>
-                  <a class="dropdown-item" href="user-buy.html" target="_blank">产品购买</a>
-                  <a class="dropdown-item" href="user-set.html" target="_blank">偏好设置</a>
-              </div>
-          </div>
-          <span class="btn btn-link btn-sm new-msg">
-            <i class="fa fa-envelope-o" aria-hidden="true"></i>&nbsp;2
-          </span>
-          <button class="btn btn-link btn-sm">注销</button>
-      </div>
-    </nav>
-      <nav class="navbar navbar-toggleable-lg justify-content-between navbar-light p-0">
-        <ul class="nav navbar-nav px-1">
-            <li class="nav-item dropdown">
-                <a class="nav-link dropdown-toggle" href="http://example.com" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">文件</a>
-                <div class="dropdown-menu" aria-labelledby="supportedContentDropdown">
-                    <a class="dropdown-item" href="#">Action</a>
-                    <a class="dropdown-item" href="#">Another action</a>
-                    <a class="dropdown-item" href="#">Something else here</a>
-                </div>
-            </li>
-            <li class="nav-item dropdown">
-                <a class="nav-link dropdown-toggle" href="#" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">编辑</a>
-                <div class="dropdown-menu">
-                    <a class="dropdown-item" href="#">Action</a>
-                    <a class="dropdown-item" href="#">Another action</a>
-                    <a class="dropdown-item" href="#">Something else here</a>
-                </div>
-            </li>
-            <li class="nav-item dropdown">
-                <a class="nav-link dropdown-toggle" href="#" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">工具</a>
-                <div class="dropdown-menu">
-                    <a class="dropdown-item" href="#">Action</a>
-                    <a class="dropdown-item" href="#">Another action</a>
-                    <a class="dropdown-item" href="#">Something else here</a>
-                </div>
-            </li>
-            <li class="nav-item">
-                <a class="nav-link" href="#" aria-haspopup="true" aria-expanded="false">帮助</a>
-            </li>
-        </ul>
-        <form class="form-inline">
-            <input class="form-control form-control-sm mr-1" type="text" placeholder="告诉我你想做什么">
-        </form>
-    </nav>
-    </div>
-    <div class="main">
-        <div class="poj-manage container-fluid">
-            <div class="row">
-                <div class="col-lg-2">
-                    <div class="poj-cate">
-                        <input type="text" class="mt-1 mb-1 form-control form-control-sm" placeholder="搜索所有工程">
-                        <ul class="nav nav-pills flex-column">
-                            <li class="nav-item">
-                                <a class="nav-link active" href="#">全部</a>
-                            </li>
-                            <li class="nav-item">
-                                <a class="nav-link" href="#">最近使用</a>
-                            </li>
-                            <li class="nav-item">
-                                <a class="nav-link" href="#">共享</a>
-                            </li>
-                            <li class="nav-item">
-                                <a class="nav-link" href="#">协同工作</a>
-                            </li>
-                            <li class="nav-item">
-                                <a class="nav-link" href="#">归档</a>
-                            </li>
-                            <li class="nav-item">
-                                <a class="nav-link" href="#">回收站</a>
-                            </li>
-                        </ul>
-                    </div>
-                </div>
-                <div class="col-lg-10">
-                    <div class="toolsbar">
-                        <div class="tools-btn btn-group align-top">
-                            <a href="" class="btn btn-sm">新建工程</a>
-                            <a href="" class="btn btn-sm"><i class="fa fa-folder-o"></i>&nbsp;新建文件夹</a>
-                            <a href="" class="btn btn-sm">重命名</a>
-                            <a href="" class="btn btn-sm">删除</a>
-                            <a href="" class="btn btn-sm">移动到...</a>
-                            <a href="" class="btn btn-sm">复制到...</a>
-                            <a href="" class="btn btn-sm">共享</a>
-                            <a href="" class="btn btn-sm">协同</a>
-                        </div>
-                    </div>
-                    <div class="poj-list">
-                        <legend>全部</legend>
-                        <table class="table table-hover table-sm">
-                            <thead>
-                                <tr>
-                                    <th width="40"></th>
-                                    <th width="38%"></th>
-                                    <th width="40%">工程名称</th>
-                                    <th width="10%">最近使用</th>
-                                    <th width="10%">创建日期</th>
-                                </tr>
-                            </thead>
-                            <tbody>
-                                <tr>
-                                    <td></td>
-                                    <td><a href="#" class="tree-open" title="收起"><i class="fa fa-minus-square-o mr-1"></i></a><i class="fa fa-folder-open-o"></i>&nbsp;XX项目文件夹</td>
-                                    <td></td>
-                                    <td></td>
-                                    <td></td>
-                                </tr>
-                                <tr>
-                                    <td></td>
-                                    <td class="pl-1"><a href="#" class="tree-open" title="收起"><i class="fa fa-minus-square-o mr-1"></i></a><i class="fa fa-folder-open-o"></i>&nbsp;XX项目文件夹</td>
-                                    <td></td>
-                                    <td></td>
-                                    <td></td>
-                                </tr>
-                                <tr>
-                                    <td></td>
-                                    <td class="pl-2"><a href="#" class="tree-open" title="收起"><i class="fa fa-minus-square-o mr-1"></i></a><i class="fa fa-folder-open-o"></i>&nbsp;<a href="#">某某某某工厂工厂某某工厂建设某某工厂建设</a></td>
-                                    <td></td>
-                                    <td></td>
-                                    <td></td>
-                                </tr>
-                                <tr>
-                                    <td></td>
-                                    <td class="pl-3"><a href="#" class="tree-open" title="收起"><i class="fa fa-minus-square-o mr-1"></i></a><i class="fa fa-folder-open-o"></i>&nbsp;<a href="#" class="open-sidebar">1号生产车间(click)</a></td>
-                                    <td></td>
-                                    <td></td>
-                                    <td></td>
-                                </tr>
-                                <tr>
-                                    <td><i class="fa fa-sort" data-toggle="tooltip" data-placement="top" title="长安拖动"></i></td>
-                                    <td></td>
-                                    <td><a href="zaojiashu.html">建筑工程(click)</a></td>
-                                    <td>2016-01-01</td>
-                                    <td>2016-01-01</td>
-                                </tr>
-                                <tr>
-                                    <td></td>
-                                    <td></td>
-                                    <td><a href="#">机械设备安装工程</a></td>
-                                    <td>2016-01-01</td>
-                                    <td>2016-01-01</td>
-                                </tr>
-                                <tr>
-                                    <td></td>
-                                    <td class="pl-2"><a href="#" class="tree-close" title="展开"><i class="fa fa-plus-square-o  mr-1"></i></a><i class="fa fa-folder-o"></i>&nbsp;<a href="#">2号生产车间</a></td>
-                                    <td>......</td>
-                                    <td></td>
-                                    <td></td>
-                                </tr>
-                            </tbody>
-                        </table>
-                    </div>
-                </div>
-            </div>
-        </div>
-        <div class="slide-sidebar">
-            <div class="side-content">
-                <div class="p-1">
-                    <legend>1号生产车间 汇总</legend>
-                    <table class="table table-bordered table-hover table-sm">
-                        <thead>
-                            <tr>
-                                <th rowspan="2"></th>
-                                <th rowspan="2">序号</th>
-                                <th rowspan="2">名称</th>
-                                <th rowspan="2">金额</th>
-                                <th colspan="6">其中</th>
-                                <th rowspan="2">占造价比例(%)</th>
-                                <th rowspan="2">建筑面积</th>
-                                <th rowspan="2">单方造价</th>
-                            </tr>
-                            <tr>
-                                <th>分部分项合计</th>
-                                <th>措施项目合计</th>
-                                <th>其他项目合计</th>
-                                <th>安全文明施工费</th>
-                                <th>规费</th>
-                                <th>税金</th>
-                            </tr>
-                        </thead>
-                        <tbody>
-                            <tr>
-                                <td>1</td>
-                                <td>一</td>
-                                <td>建筑工程</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                            </tr>
-                            <tr>
-                                <td>2</td>
-                                <td>二</td>
-                                <td>建筑工程</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                            </tr>
-                            <tr>
-                                <td>3</td>
-                                <td> </td>
-                                <td> </td>
-                                <td> </td>
-                                <td> </td>
-                                <td> </td>
-                                <td> </td>
-                                <td> </td>
-                                <td> </td>
-                                <td> </td>
-                                <td> </td>
-                                <td> </td>
-                                <td> </td>
-                            </tr>
-                            <tr>
-                                <td>4</td>
-                                <td>一</td>
-                                <td>合计</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td> </td>
-                                <td> </td>
-                                <td> </td>
-                            </tr>
-                        </tbody>
-                    </table>
-                </div>
-            </div>
-        </div>
-    </div>
-    <!--弹出信息-->
-    <div class="modal fade" id="myModal" data-backdrop="static">
-        <div class="modal-dialog modal-lg" role="document">
-            <div class="modal-content">
-                <div class="modal-header">
-                    <h5 class="modal-title">欢迎使用Smartcost</h5>
-                </div>
-                <div class="modal-body">
-                    <p>推送内容在这</p>
-                </div>
-                <div class="modal-footer text-xs-center">
-                    <a href="project-management.html" class="btn btn-primary btn-lg">开始使用Smartcost</a>
-                </div>
-            </div>
-        </div>
-    </div>
-    <!-- JS. -->
-    <script src="js/jquery/jquery.min.js"></script>
-    <script src="js/tether/tether.min.js"></script>
-    <script src="js/bootstrap/bootstrap.min.js"></script>
-    <script src="js/global.js"></script>
-</body>
-<script type="text/javascript">
-    $('#myModal').modal('show')
-</script>
-
-</html>

+ 0 - 132
web/users/login.html

@@ -1,132 +0,0 @@
-<!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>用户登录-Smartcost</title>
-    <link rel="stylesheet" href="/lib/bootstrap/css/bootstrap.min.css">
-    <link rel="stylesheet" href="/web/maintain/ration_repository/css/main.css">
-    <link rel="stylesheet" href="/lib/font-awesome/font-awesome.min.css">
-    <script src="/lib/jquery/jquery.min.js"></script>
-    <script src="/public/web/url_util.js"></script>
-</head>
-<body>
-    <div class="container">
-        <form class="form-signin" method="post" onsubmit="return false">
-            <h1 class="d-flex justify-content-center">Smartcost</h1>
-            <h4 class="d-flex justify-content-center mb-2">用户登录</h4>
-            <div class="form-group">
-                <input id="inputEmail" class="form-control " placeholder="通行账号 邮箱/手机" required="" autofocus="" value="laiku123@qq.com">
-            </div>
-            <div class="form-group">
-                <input id="inputPassword" class="form-control " placeholder="输入密码" required="" type="password" value="19930523">
-            </div>
-            <div class="form-group has-danger">
-                <div id="hint" class="form-control-feedback">&nbsp;</div>
-            </div>
-            <div class="form-group">
-                <!--<button id="login" class="btn btn-primary btn-block" data-toggle="modal" data-target="#ver">登录</button>-->
-                <button id="login" class="btn btn-primary btn-block">登录</button>
-            </div>
-            <div class="pt-1 d-flex justify-content-center">
-                <a href="http://sso.smartcost.com.cn/getpasswd" target="_blank" class="mr-3">忘记密码</a>
-                <a href="http://sso.smartcost.com.cn/reg" target="_blank">免费注册</a>
-            </div>
-        </form>
-
-        <script>
-            $(document).ready(function () {
-                var referer = scUrlUtil.GetQueryString('referer');
-
-                $("#login").click(function () {
-                    var account = $("#inputEmail").val();
-                    var pw = $("#inputPassword").val();
-
-                    $.ajax({
-                        url: '/login',
-                        type: 'post',
-                        data: {"account": account, "pw": pw},
-                        success: function (result) {
-                            if (result.data) {
-//                                $('#ver').modal('show');
-                                if (referer) {
-                                    location.href = referer;
-                                } else {
-                                    location.href = '/';
-                                }
-                            }
-                            else {
-                                $('#hint').html(result.error);
-                            }
-                        },
-                        error: function (result) {
-                            $('#hint').html('内部程序错误!');
-                        }
-                    });
-                });
-
-                $(".form-control").on('input', function () {
-                    $('#hint').html('&nbsp;');
-                });
-            });
-        </script>
-
-        <!--登录错误-->
-        <!--<form class="form-signin login-error">
-            <h1 class="d-flex justify-content-center">Smartcost</h1>
-            <h4 class="d-flex justify-content-center mb-2">用户登录</h4>
-            <div class="form-group has-danger">
-                <input class="form-control form-control-danger" value="1212@qq.com" placeholder="通行账号 邮箱/手机" required="" autofocus="">
-                <div class="form-control-feedback">输入的邮箱/手机无效</div>
-            </div>
-            <div class="form-group has-danger">
-                <input class="form-control gform-control-danger" value="12313" placeholder="输入密码" required="" type="password">
-                <div class="form-control-feedback">密码错误</div>
-            </div>
-            <div class="form-group">
-                <button class="btn btn-primary btn-block">登录</button>
-            </div>
-            <div class="pt-1 d-flex justify-content-center">
-                <a href="http://sso.smartcost.com.cn/getpasswd" target="_blank" class="mr-3">忘记密码</a>
-                <a href="http://sso.smartcost.com.cn/reg" target="_blank">免费注册</a>
-            </div>
-        </form>-->
-    </div>
-    <!--弹出信息-->
-    <div class="modal fade" id="ver" data-backdrop="static">
-        <div class="modal-dialog modal-lg" role="document">
-            <div class="modal-content">
-                <div class="modal-header">
-                    <h4 class="modal-title">选择登录版本</h4>
-                    <p class="m-0 text-warning"><i class="fa fa-exclamation-triangle"></i> <b>偏好设置</b> 中可以修改您的登录习惯。</p>
-                </div>
-                <div class="modal-body">
-                    <div class="row">
-                        <div class="col-sm-6">
-                            <div class="card card-block">
-                                <h3 class="card-title">重庆版免费版</h3>
-                                <p class="card-text">With supporting text below as a natural lead-in to additional content.</p>
-                                <a class="btn btn-primary" href="login-infoinput.html">开始使用</a>
-                            </div>
-                        </div>
-                        <div class="col-sm-6">
-                            <div class="card card-block">
-                                <h3 class="card-title">广东版免费版</h3>
-                                <p class="card-text">With supporting text below as a natural lead-in to additional content.</p>
-                                <a class="btn btn-primary" href="login-infoinput.html">开始使用</a>
-                            </div>
-                        </div>
-                    </div>
-                </div>
-            </div>
-        </div>
-    </div>
-    <!-- JS. -->
-
-    <script src="/lib/tether/tether.min.js"></script>
-    <script src="/lib/bootstrap/bootstrap.min.js"></script>
-    <script src="/web/maintain/ration_repository/js/global.js"></script>
-</body>
-
-</html>

+ 0 - 589
web/users/project-management.html

@@ -1,589 +0,0 @@
-<!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>项目管理-Smartcost</title>
-    <link rel="stylesheet" href="/lib/bootstrap/css/bootstrap.min.css">
-    <!--<link rel="stylesheet" href="/web/css/bootstrap/themes.css">-->
-    <link rel="stylesheet" href="/web/building_saas/css/main.css">
-    <link rel="stylesheet" href="/lib/font-awesome/font-awesome.min.css">
-    <!--zTree-->
-  	<link rel="stylesheet" href="/lib/ztree/css/zTreeStyle.css" type="text/css">
-
-    <script>
-        // 这里的变量供页面调用
-        var userAccount = '<%- userAccount %>';
-        var userID = '<%- userID %>';
-    </script>
-</head>
-
-<body>
-    <div class="header">
-<!--        <div class="top-msg clearfix">
-            <div class="alert alert-warning mb-0 py-0" role="alert">
-                <button type="button" class="close" data-dismiss="alert" aria-label="Close">
-                  <span aria-hidden="true">&times;</span>
-                </button>
-                <strong>注意!</strong> 这是一条消息通知 <a href="#">链接</a>
-            </div>
-        </div>-->
-        <nav class="navbar navbar-toggleable-lg navbar-light bg-faded p-0 justify-content-between">
-          <span class="header-logo px-2">Smartcost</span>
-          <div class="navbar-text pt-0">
-              <div class="dropdown d-inline-block">
-                  <button class="btn btn-link btn-sm dropdown-toggle" type="button" data-toggle="dropdown"><%- userAccount %></button>
-                  <div class="dropdown-menu dropdown-menu-right">
-                      <a class="dropdown-item" href="user-info.html" target="_blank">账号资料</a>
-                      <a class="dropdown-item" href="user-buy.html" target="_blank">产品购买</a>
-                      <a class="dropdown-item" href="user-set.html" target="_blank">偏好设置</a>
-                  </div>
-              </div>
-              <span class="btn btn-link btn-sm new-msg">
-                <i class="fa fa-envelope-o" aria-hidden="true"></i>&nbsp;2
-              </span>
-              <button id="logout" class="btn btn-link btn-sm">注销</button>
-          </div>
-        </nav>
-        <nav class="navbar navbar-toggleable-lg justify-content-between navbar-light p-0">
-            <ul class="nav navbar-nav px-1">
-                <li class="nav-item dropdown">
-                    <a class="nav-link dropdown-toggle" href="http://example.com" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">文件</a>
-                    <div class="dropdown-menu" aria-labelledby="supportedContentDropdown">
-                        <a class="dropdown-item" href="#">Action</a>
-                        <a class="dropdown-item" href="#">Another action</a>
-                        <a class="dropdown-item" href="#">Something else here</a>
-                    </div>
-                </li>
-                <li class="nav-item dropdown">
-                    <a class="nav-link dropdown-toggle" href="#" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">编辑</a>
-                    <div class="dropdown-menu">
-                        <a class="dropdown-item" href="#">Action</a>
-                        <a class="dropdown-item" href="#">Another action</a>
-                        <a class="dropdown-item" href="#">Something else here</a>
-                    </div>
-                </li>
-                <li class="nav-item dropdown">
-                    <a class="nav-link dropdown-toggle" href="#" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">工具</a>
-                    <div class="dropdown-menu">
-                        <a class="dropdown-item" href="#">Action</a>
-                        <a class="dropdown-item" href="#">Another action</a>
-                        <a class="dropdown-item" href="#">Something else here</a>
-                    </div>
-                </li>
-                <li class="nav-item">
-                    <a class="nav-link" href="#" aria-haspopup="true" aria-expanded="false">帮助</a>
-                </li>
-            </ul>
-            <form class="form-inline">
-                <input class="form-control form-control-sm mr-1" type="text" placeholder="告诉我你想做什么">
-            </form>
-        </nav>
-    </div>
-    <div class="main">
-        <div class="poj-manage container-fluid">
-            <div class="row">
-                <div class="col-lg-2">
-                    <div class="poj-cate">
-                        <input type="text" class="my-2 form-control form-control-sm" placeholder="搜索所有工程">
-                        <ul class="nav nav-pills flex-column">
-                            <li class="nav-item">
-                                <a class="nav-link active" href="#">全部</a>
-                            </li>
-                            <li class="nav-item">
-                                <a class="nav-link" href="#">最近使用</a>
-                            </li>
-                            <li class="nav-item">
-                                <a class="nav-link" href="#">共享</a>
-                            </li>
-                            <li class="nav-item">
-                                <a class="nav-link" href="#">协同工作</a>
-                            </li>
-                            <li class="nav-item">
-                                <a class="nav-link" href="#">归档</a>
-                            </li>
-                            <li class="nav-item">
-                                <a class="nav-link" href="#">回收站</a>
-                            </li>
-                        </ul>
-                    </div>
-                </div>
-                <div class="col-lg-10">
-                    <div class="toolsbar">
-                        <div class="tools-btn btn-group align-top">
-                            <a href="javacript:void(0);" data-toggle="modal" data-target="#addPoj" class="btn btn-sm">新建工程</a>
-                            <a href="javacript:void(0);" data-toggle="modal" data-target="#addFolder" class="btn btn-sm"><i class="fa fa-folder-o"></i>&nbsp;新建文件夹</a>
-                            <a href="javacript:void(0);" data-toggle="modal" data-target="#rename" class="btn btn-sm">重命名</a>
-                            <a href="javacript:void(0);" data-toggle="modal" data-target="#del" class="btn btn-sm">删除</a>
-                            <a href="javacript:void(0);" data-toggle="modal" data-target="#moveto" class="btn btn-sm">移动到...</a>
-                            <a href="javacript:void(0);" data-toggle="modal" data-target="#copyto" class="btn btn-sm">复制到...</a>
-                            <a href="" class="btn btn-sm">共享</a>
-                            <a href="" class="btn btn-sm">协同</a>
-                        </div>
-                    </div>
-                    <div class="poj-list">
-                        <legend>全部</legend>
-                        <table class="table table-hover table-sm">
-                            <thead>
-                                <tr>
-                                    <th width="40"></th>
-                                    <th width="78%">工程列表</th>
-                                    <th width="10%">最近使用</th>
-                                    <th width="10%">创建日期</th>
-                                </tr>
-                            </thead>
-                            <tbody>
-                                <tr>
-                                    <td></td>
-                                    <td class="in-1"><a href="#" class="tree-open" title="收起"><i class="fa fa-minus-square-o mr-1"></i></a><i class="fa fa-folder-open-o"></i>&nbsp;XX项目文件夹</td>
-                                    <td></td>
-                                    <td></td>
-                                </tr>
-                                  <tr>
-                                      <td></td>
-                                      <td class="in-2"><a href="#" class="tree-open" title="收起"><i class="fa fa-minus-square-o mr-1"></i></a><i class="fa fa-folder-open-o"></i>&nbsp;XX项目文件夹</td>
-                                      <td></td>
-                                      <td></td>
-                                  </tr>
-                                <tr>
-                                    <td></td>
-                                    <td class="in-3"><a href="#" class="tree-open" title="收起"><i class="fa fa-minus-square-o mr-1"></i></a><i class="fa fa-folder-open-o"></i>&nbsp;XX项目文件夹</td>
-                                    <td></td>
-                                    <td></td>
-                                </tr>
-                                <tr>
-                                    <td></td>
-                                    <td class="in-4"><a href="#" class="tree-open" title="收起"><i class="fa fa-minus-square-o mr-1"></i></a><i class="fa fa-folder-open-o"></i>&nbsp;<a href="#">某某某某工厂工厂某某工厂建设某某工厂建设</a></td>
-                                    <td></td>
-                                    <td></td>
-                                </tr>
-                                <tr>
-                                    <td></td>
-                                    <td class="in-5"><a href="#" class="tree-open" title="收起"><i class="fa fa-minus-square-o mr-1"></i></a><i class="fa fa-folder-open-o"></i>&nbsp;<a href="#" class="open-sidebar">左1号生产车间(click)</a></td>
-                                    <td></td>
-                                    <td></td>
-                                </tr>
-                                <tr>
-                                    <td><i class="fa fa-sort" data-toggle="tooltip" data-placement="top" title="长安拖动"></i></td>
-                                    <td class="in-6"><span class="in-3 poj-icon">└</span><a href="zaojiashu.html">建筑工程(click)</a></td>
-                                    <td>2016-01-01</td>
-                                    <td>2016-01-01</td>
-                                </tr>
-                                <tr>
-                                    <td></td>
-                                    <td class="in-6"><span class="in-3 poj-icon">└</span><a href="#">机械设备安装工程</a></td>
-                                    <td>2016-01-01</td>
-                                    <td>2016-01-01</td>
-                                </tr>
-                                <tr>
-                                    <td></td>
-                                    <td class="in-5"><a href="#" class="tree-close" title="展开"><i class="fa fa-plus-square-o  mr-1"></i></a><i class="fa fa-folder-o"></i>&nbsp;<a href="#">2号生产车间</a></td>
-                                    <td>......</td>
-                                    <td>......</td>
-                                </tr>
-                            </tbody>
-                        </table>
-                    </div>
-                </div>
-            </div>
-        </div>
-        <div class="slide-sidebar">
-            <div class="side-content">
-                <div class="p-3">
-                    <legend>1号生产车间 汇总</legend>
-                    <table class="table table-bordered table-hover table-sm">
-                        <thead>
-                            <tr>
-                                <th rowspan="2"></th>
-                                <th rowspan="2">序号</th>
-                                <th rowspan="2">名称</th>
-                                <th rowspan="2">金额</th>
-                                <th colspan="6">其中</th>
-                                <th rowspan="2">占造价比例(%)</th>
-                                <th rowspan="2">建筑面积</th>
-                                <th rowspan="2">单方造价</th>
-                            </tr>
-                            <tr>
-                                <th>分部分项合计</th>
-                                <th>措施项目合计</th>
-                                <th>其他项目合计</th>
-                                <th>安全文明施工费</th>
-                                <th>规费</th>
-                                <th>税金</th>
-                            </tr>
-                        </thead>
-                        <tbody>
-                            <tr>
-                                <td>1</td>
-                                <td>一</td>
-                                <td>建筑工程</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                            </tr>
-                            <tr>
-                                <td>2</td>
-                                <td>二</td>
-                                <td>建筑工程</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                            </tr>
-                            <tr>
-                                <td>3</td>
-                                <td> </td>
-                                <td> </td>
-                                <td> </td>
-                                <td> </td>
-                                <td> </td>
-                                <td> </td>
-                                <td> </td>
-                                <td> </td>
-                                <td> </td>
-                                <td> </td>
-                                <td> </td>
-                                <td> </td>
-                            </tr>
-                            <tr>
-                                <td>4</td>
-                                <td>一</td>
-                                <td>合计</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td>0</td>
-                                <td> </td>
-                                <td> </td>
-                                <td> </td>
-                            </tr>
-                        </tbody>
-                    </table>
-                </div>
-            </div>
-        </div>
-    </div>
-    <!--弹出新建工程-->
-    <div class="modal fade" id="addPoj" data-backdrop="static">
-        <div class="modal-dialog" role="document">
-            <div class="modal-content">
-                <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">
-                    <form>
-                    <div class="collapse" id="moreinfo">
-                        <div class="form-group">
-                            <label>建设项目</label>
-                            <input type="text" class="form-control" placeholder="输入建设项目名称">
-                        </div>
-                        <div class="form-group">
-                            <label>单项工程</label>
-                            <input type="text" class="form-control" placeholder="输入单项工程名称">
-                        </div>
-                      </div>
-                        <div class="form-group">
-                            <label>单位工程</label>
-                            <input type="text" class="form-control" placeholder="输入单位工程名称">
-                        </div>
-                        <div class="form-group" >
-                            <label class="custom-control custom-checkbox">
-                              <input type="checkbox" class="custom-control-input" href="#moreinfo" data-toggle="collapse" data-parent="#moreinfo" aria-expanded="false" aria-controls="moreinfo">
-                              <span class="custom-control-indicator" ></span>
-                              <span class="custom-control-description">建立 <b>建设项目</b> 和 <b>单项工程</b> 文件夹</span>
-                            </label>
-                        </div>
-                        <div class="form-group">
-                            <label>计价方式</label>
-                            <div>
-                                <label class="custom-control custom-radio">
-                                  <input id="radio1" name="radio" type="radio" class="custom-control-input">
-                                  <span class="custom-control-indicator"></span>
-                                  <span class="custom-control-description">清单计价</span>
-                                </label>
-                                <label class="custom-control custom-radio">
-                                  <input id="radio2" name="radio" type="radio" class="custom-control-input">
-                                  <span class="custom-control-indicator"></span>
-                                  <span class="custom-control-description">定额计价</span>
-                                </label>
-                            </div>
-                        </div>
-                    </form>
-                </div>
-                <div class="modal-footer">
-                    <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
-                    <a href="project-management.html" class="btn btn-primary">确定</a>
-                </div>
-            </div>
-        </div>
-    </div>
-    <!--弹出新建文件夹-->
-    <div class="modal fade" id="addFolder" data-backdrop="static">
-        <div class="modal-dialog" role="document">
-            <div class="modal-content">
-                <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">
-                    <form>
-                        <div class="form-group">
-                            <label>文件夹</label>
-                            <input type="text" class="form-control" placeholder="输入文件夹名称">
-                            <span class="form-text text-muted">Smartcost为你提供了灵活的工程管理功能,如:</span>
-                            <span class="form-text text-muted">当你想汇总多个 <b>单位工程</b> 时,只需把它们都放在一个文件夹即可。</span>
-                        </div>
-                    </form>
-                </div>
-                <div class="modal-footer">
-                    <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
-                    <a href="project-management.html" class="btn btn-primary">确定</a>
-                </div>
-            </div>
-        </div>
-    </div>
-    <!--弹出重命名-->
-    <div class="modal fade" id="rename" data-backdrop="static">
-        <div class="modal-dialog" role="document">
-            <div class="modal-content">
-                <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">
-                    <form>
-                        <div class="form-group">
-                            <input type="text" class="form-control" placeholder="输入名称">
-                        </div>
-                    </form>
-                </div>
-                <div class="modal-footer">
-                    <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
-                    <a href="project-management.html" class="btn btn-primary">确定</a>
-                </div>
-            </div>
-        </div>
-    </div>
-    <!--弹出删除-->
-    <div class="modal fade" id="del" data-backdrop="static">
-        <div class="modal-dialog" role="document">
-            <div class="modal-content">
-                <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">
-                    <h5 class="text-danger">删除 "建筑工程" ?</h5>
-                    <h5 class="text-danger">删除 "XX项目文件夹" 以及它包含的子项?</h5>
-                    <p class="">删除后,你可以在回收站找到它。</p>
-                </div>
-                <div class="modal-footer">
-                    <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
-                    <a href="" class="btn btn-danger">删除</a>
-                </div>
-            </div>
-        </div>
-    </div>
-    <!--弹出移动到-->
-    <div class="modal fade" id="moveto" data-backdrop="static">
-        <div class="modal-dialog" role="document">
-            <div class="modal-content">
-                <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">
-                  <ul id="treeDemo" class="ztree"></ul>
-                </div>
-                <div class="modal-footer">
-                    <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
-                    <a href="" class="btn btn-primary">确定</a>
-                </div>
-            </div>
-        </div>
-    </div>
-    <!--弹出复制到-->
-    <div class="modal fade" id="copyto" data-backdrop="static">
-        <div class="modal-dialog" role="document">
-            <div class="modal-content">
-                <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">
-                  <ul id="treeDemo2" class="ztree"></ul>
-                </div>
-                <div class="modal-footer">
-                    <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
-                    <a href="" class="btn btn-primary">确定</a>
-                </div>
-            </div>
-        </div>
-    </div>
-    <!-- JS. -->
-    <script src="/lib/jquery/jquery.min.js"></script>
-    <script src="/lib/tether/tether.min.js"></script>
-    <script src="/lib/bootstrap/bootstrap.min.js"></script>
-    <script src="/web/building_saas/js/global.js"></script>
-    <!-- zTree -->
-  	<script type="text/javascript" src="/lib/ztree/jquery.ztree.core.js"></script>
-  	<script type="text/javascript" src="/lib/ztree/jquery.ztree.excheck.js"></script>
-    <SCRIPT type="text/javascript">
-  		<!--
-  		var setting = {	};
-
-  		var zNodes =[
-  			{ name:"父节点1 - 展开", open:true,
-  				children: [
-  					{ name:"父节点11 - 折叠",
-  						children: [
-  							{ name:"叶子节点111"},
-  							{ name:"叶子节点112"},
-  							{ name:"叶子节点113"},
-  							{ name:"叶子节点114"}
-  						]},
-  					{ name:"父节点12 - 折叠",
-  						children: [
-  							{ name:"叶子节点121"},
-  							{ name:"叶子节点122"},
-  							{ name:"叶子节点123"},
-  							{ name:"叶子节点124"}
-  						]},
-  					{ name:"父节点13 - 没有子节点", isParent:true}
-  				]},
-  			{ name:"父节点2 - 折叠",
-  				children: [
-  					{ name:"父节点21 - 展开", open:true,
-  						children: [
-  							{ name:"叶子节点211"},
-  							{ name:"叶子节点212"},
-  							{ name:"叶子节点213"},
-  							{ name:"叶子节点214"}
-  						]},
-  					{ name:"父节点22 - 折叠",
-  						children: [
-  							{ name:"叶子节点221"},
-  							{ name:"叶子节点222"},
-  							{ name:"叶子节点223"},
-  							{ name:"叶子节点224"}
-  						]},
-  					{ name:"父节点23 - 折叠",
-  						children: [
-  							{ name:"叶子节点231"},
-  							{ name:"叶子节点232"},
-  							{ name:"叶子节点233"},
-  							{ name:"叶子节点234"}
-  						]}
-  				]},
-  			{ name:"父节点3 - 没有子节点", isParent:true}
-
-  		];
-
-  		$(document).ready(function(){
-  			$.fn.zTree.init($("#treeDemo"), setting, zNodes);
-  		});
-  		//-->
-  	</SCRIPT>
-    <SCRIPT type="text/javascript">
-  		<!--
-  		var setting = {	};
-
-  		var zNodes =[
-  			{ name:"父节点1 - 展开", open:true,
-  				children: [
-  					{ name:"父节点11 - 折叠",
-  						children: [
-  							{ name:"叶子节点111"},
-  							{ name:"叶子节点112"},
-  							{ name:"叶子节点113"},
-  							{ name:"叶子节点114"}
-  						]},
-  					{ name:"父节点12 - 折叠",
-  						children: [
-  							{ name:"叶子节点121"},
-  							{ name:"叶子节点122"},
-  							{ name:"叶子节点123"},
-  							{ name:"叶子节点124"}
-  						]},
-  					{ name:"父节点13 - 没有子节点", isParent:true}
-  				]},
-  			{ name:"父节点2 - 折叠",
-  				children: [
-  					{ name:"父节点21 - 展开", open:true,
-  						children: [
-  							{ name:"叶子节点211"},
-  							{ name:"叶子节点212"},
-  							{ name:"叶子节点213"},
-  							{ name:"叶子节点214"}
-  						]},
-  					{ name:"父节点22 - 折叠",
-  						children: [
-  							{ name:"叶子节点221"},
-  							{ name:"叶子节点222"},
-  							{ name:"叶子节点223"},
-  							{ name:"叶子节点224"}
-  						]},
-  					{ name:"父节点23 - 折叠",
-  						children: [
-  							{ name:"叶子节点231"},
-  							{ name:"叶子节点232"},
-  							{ name:"叶子节点233"},
-  							{ name:"叶子节点234"}
-  						]}
-  				]},
-  			{ name:"父节点3 - 没有子节点", isParent:true}
-
-  		];
-
-  		$(document).ready(function(){
-  			$.fn.zTree.init($("#treeDemo2"), setting, zNodes);
-  		});
-  		//-->
-  	</SCRIPT>
-</body>
-<script type="text/javascript">
-    autoFlashHeight();
-</script>
-
-<script>
-    $(document).ready(function () {
-        $("#logout").click(function () {
-            location.href = '/logout';
-        });
-    });
-</script>
-
-
-
-</html>

+ 48 - 0
web/users/views/dashboard/index.html

@@ -0,0 +1,48 @@
+<div class="panel-content">
+    <div class="panel-title fluid">
+        <div class="title-main"><h2>首页</h2></div>
+    </div>
+    <div class="content-wrap">
+        <div class="c-header">
+            <h4>通知</h4>
+        </div>
+        <div class="c-body">
+            <table class="table">
+                <thead>
+                <tr>
+                    <th>标题</th>
+                    <th width="200">发布时间</th>
+                    <th width="120">发布人</th>
+                </tr>
+                </thead>
+                <tbody>
+                <tr>
+                    <td><a href="#">标题A</a></td>
+                    <td>2017-02-01 09:30</td>
+                    <td>陈特</td>
+                </tr>
+                <tr>
+                    <td><a href="#">标题B</a></td>
+                    <td>2017-02-01 09:30</td>
+                    <td>陈特</td>
+                </tr>
+                <tr>
+                    <td><a href="#">标题C</a></td>
+                    <td>2017-02-01 09:30</td>
+                    <td>陈特</td>
+                </tr>
+                <tr>
+                    <td>【内部】<a href="#">标题D</a></td>
+                    <td>2017-02-01 09:30</td>
+                    <td>陈特</td>
+                </tr>
+                <tr>
+                    <td><a href="#">标题E</a></td>
+                    <td>2017-02-01 09:30</td>
+                    <td>陈特</td>
+                </tr>
+                </tbody>
+            </table>
+        </div>
+    </div>
+</div>

+ 58 - 0
web/users/views/layout/layout.html

@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html lang=zh-cn>
+<head>
+    <meta charset=utf-8>
+    <title>建筑造价后台</title>
+    <meta name=description content="纵横变更令审批系统">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="renderer" content="webkit">
+    <meta name=copyright content="smartcost.com.cn">
+    <link rel="stylesheet" href="/web/users/css/bootstrap.min.css">
+    <link rel="stylesheet" href="/web/users/css/style.css">
+    <script src="/lib/jquery/jquery.min.js"></script>
+    <script src="/web/users/js/lib/bootstrap.min.js"></script>
+    <script src="/web/users/js/global.js"></script>
+    <script src="/web/users/js/lib/jquery.validate.js"></script>
+    <script src="/web/users/js/lib/validate.extend.js"></script>
+    <script src="/web/users/js/lib/messages_zh.js"></script>
+    <script src="/web/users/js/lib/bootstrap-paginator.js"></script>
+</head>
+<body>
+<div class="header">
+    <h1 class="logo"><a>建筑造价后台</a></h1>
+    <div class="header-box">
+        <div class="header-nav"></div>
+        <div class="header-user pull-right">
+            <div class="avatar btn-group">
+                <a class="dropdown-toggle" data-toggle="dropdown">
+                    <span class="pic"><img src="/img/avatar.png"></span>
+                    <span><%= manager.username %></span>
+                    <span class="caret"></span>
+                </a>
+                <ul class="dropdown-menu dropdown-menu-right">
+                    <li><a href="#">账号设置(CLD)</a></li>
+                    <li><a href="/login/logout">退出登录</a></li>
+                </ul>
+            </div>
+        </div>
+    </div>
+</div>
+<div class="main">
+    <div class="main-nav">
+        <div class="nav-top">
+            <ul class="nav nav-pills nav-stacked bg-nav">
+                <% for(let tmp in menu) {%>
+                <li <% if (controller === menu[tmp].name) {%>class="active"<% } %>>
+                    <a href="<%= menu[tmp].url %>">
+                        <i class="<%= menu[tmp].iconClass %>" aria-hidden="true"></i> <%= menu[tmp].title %>
+                    </a>
+                </li>
+                <% } %>
+            </ul>
+        </div>
+    </div>
+    <div class="main-panel">
+        <%- body %>
+    </div>
+</div>
+</body>

+ 66 - 0
web/users/views/layout/page.html

@@ -0,0 +1,66 @@
+<ul aria-label="Page navigation" id="pages"></ul>
+<script type="text/javascript">
+    let options = {
+        bootstrapMajorVersion: 3,
+        currentPage: "<%= pages.current %>",
+        totalPages: "<%= pages.total %>",
+        size: "small",
+        itemTexts: function(type, page, current) {
+            switch (type) {
+                case "first":
+                    return "&laquo;";
+                case "prev":
+                    return "&lsaquo;";
+                case "next":
+                    return "&rsaquo;";
+                case "last":
+                    return "&raquo;";
+                case "page":
+                    return page;
+            }
+        },
+        shouldShowPage: function (type, page, current) {
+            let result = true;
+            switch (type) {
+                case "first":
+                    result = (current !== 1);
+                    break;
+                case "prev":
+                    result = false;
+                    break;
+                case "next":
+                    result = false;
+                    break;
+                case "last":
+                    result = (current !== this.totalPages);
+                    break;
+                case "page":
+                    result = true;
+                    break;
+            }
+            return result;
+
+        },
+        pageUrl: function(type, page, current){
+            let queryData = JSON.parse(pages.queryData);
+            // 如果没有附带查询条件则直接返回
+            if (typeof queryData !== 'object') {
+                return "?page=" + page;
+            }
+            // 有其它数据则重新赋值page,然后组合字符串
+            queryData.page = page;
+            let queryArray = [];
+            for(let tmp in queryData) {
+                let tempString = tmp + '=' + queryData[tmp];
+                queryArray.push(tempString);
+            }
+
+            let firstQuery = queryArray.shift();
+            let queryString = queryArray.join('&');
+            return '?' + firstQuery + '&' + queryString;
+        }
+    };
+    if (options.totalPages > 0) {
+        $("#pages").bootstrapPaginator(options);
+    }
+</script>

+ 18 - 0
web/users/views/layout/second_menu.html

@@ -0,0 +1,18 @@
+<div class="panel-sidebar">
+    <div class="panel-title">
+        <div class="title-bar">
+            <h2><%= secondMenu[action].title %></h2>
+        </div>
+    </div>
+    <div class="scrollbar-auto">
+        <div class="nav-box">
+            <ul class="nav-list list-unstyled">
+                <% for (let tmp in secondMenu) { %>
+                <li <% if (secondMenu[tmp].name === action) { %>class="active"
+                        <% } %>
+                ><a href="<%= secondMenu[tmp].url %>"><span><%= secondMenu[tmp].title %></span></a></li>
+                <% } %>
+            </ul>
+        </div>
+    </div>
+</div>

+ 54 - 0
web/users/views/login/index.html

@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<html lang=zh-cn>
+<head>
+    <meta charset=utf-8>
+    <title>建筑造价后台</title>
+    <meta name=description content=纵横变更令审批系统>
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="renderer" content="webkit">
+    <meta name="copyright" content="smartcost.com.cn">
+    <link rel="stylesheet" href="/web/users/css/bootstrap.min.css">
+    <link rel="stylesheet" href="/web/users/css/style.css">
+    <script src="/lib/jquery/jquery.min.js"></script>
+    <script src="/web/users/js/lib/bootstrap.min.js"></script>
+    <script src="/web/users/js/global.js"></script>
+    <script src="/web/users/js/lib/jquery.validate.js"></script>
+    <script src="/web/users/js/lib/validate.extend.js"></script>
+    <script src="/web/users/js/lib/messages_zh.js"></script>
+</head>
+<body class="loginbody">
+<div class="wraplogin">
+    <div class="loginTop">
+        <a title="返回首页" href="#">建筑造价后台</a>
+    </div>
+    <div class="loginItem  center-block">
+        <div class="loginForm">
+            <form role="form" id="login-form">
+                <div class="form-group">
+                    <div class="input-group">
+                        <div class="input-group-addon"><i class="glyphicon glyphicon-user"></i></div>
+                        <input  class="form-control input-lg" placeholder="输入账号" name="username" id="username">
+                    </div>
+                </div>
+                <div class="form-group">
+                    <div class="input-group">
+                        <div class="input-group-addon"><i class="glyphicon glyphicon-lock"></i></div>
+                        <input type="password" class="form-control input-lg"  placeholder="输入密码" id="password" name="password">
+                    </div>
+                </div>
+                <a class="btn btn-primary btn-lg btn-block" href="javascript:void(0);" id="login">登录</a>
+            </form>
+        </div>
+        <div class="loginBottom">
+            <a href="getpasswd.html" target="_blank">忘记密码</a>
+        </div>
+    </div>
+</div>
+<div class="login_bottom">
+    <div class="login_wave">
+        <div id="wave_bg_1" style="left: -434.722px;"></div>
+        <div id="wave_bg_2" style="left: -336.283px;"></div>
+    </div>
+</div>
+<script type="text/javascript" src="/web/users/js/login.js"></script>
+</body>

+ 54 - 0
web/users/views/manager/index.html

@@ -0,0 +1,54 @@
+<%include ../layout/second_menu.html %>
+<div class="panel-content">
+    <div class="panel-title">
+        <div class="title-main">
+            <h2><%= secondMenu[action].title %></h2>
+        </div>
+    </div>
+    <div class="content-wrap">
+        <div class="c-header">
+            <!--办事处筛选-->
+            <div class="btn-group">
+                <button type="button" class="btn btn-default dropdown-toggle btn-sm" data-toggle="dropdown"
+                        aria-haspopup="true" aria-expanded="false">
+                    办事处 <span class="caret"></span>
+                </button>
+                <ul class="dropdown-menu">
+                    <li><a href="#">广东办</a></li>
+                    <li><a href="#">总部</a></li>
+                </ul>
+            </div>
+        </div>
+        <div class="c-body">
+            <table class="table">
+                <thead>
+                <tr>
+                    <th>姓名</th>
+                    <th>办事处</th>
+                    <th>权限</th>
+                    <th width="100">操作</th>
+                </tr>
+                </thead>
+                <tbody>
+                <% managerList.forEach(function(manager) { %>
+                <tr>
+                    <td><%= manager.username %></td>
+                    <td><%= manager.office %></td>
+                    <td>用户管理,通知管理,工具,后台管理</td>
+                    <td>
+                        <a href="/manager/modify/<%= manager._id %>" class="btn btn-xs">编辑</a>
+                        <% if (manager.super_admin !== 1) { %>
+                        <a href="/manager/delete/<%= manager._id %>" class="btn btn-xs">删除</a>
+                        <% } %>
+                    </td>
+                </tr>
+                <% }) %>
+                </tbody>
+            </table>
+            <nav aria-label="Page navigation">
+                <%include ../layout/page.html %>
+            </nav>
+        </div>
+    </div>
+</div>
+</div>

+ 36 - 0
web/users/views/manager/save.html

@@ -0,0 +1,36 @@
+<%include ../layout/second_menu.html %>
+<div class="panel-content">
+    <div class="panel-title">
+        <div class="title-main">
+            <h2>
+                <%= secondMenu[action].title %>
+                <a href="javascript:void(0);" class="btn btn-primary btn-sm pull-right" id="save">确定修改</a>
+            </h2>
+        </div>
+    </div>
+    <div class="content-wrap">
+        <div class="c-body">
+            <form class="row" id="save-form" action="" method="post">
+                <div class="col-lg-4">
+                    <div class="form-group">
+                        <label>账号</label>
+                        <input class="form-control" value="<%= adminData.username %>" disabled="disabled">
+                    </div>
+                    <div class="form-group has-feedback">
+                        <label>旧密码</label>
+                        <input type="password" class="form-control" name="password" id="password">
+                    </div>
+                    <div class="form-group has-feedback">
+                        <label>新密码</label>
+                        <input type="password" class="form-control" name="newPassword" id="new-password">
+                    </div>
+                    <div class="form-group has-feedback">
+                        <label>确认新密码</label>
+                        <input type="password" class="form-control" name="confirmPassword">
+                    </div>
+                </div>
+            </form>
+        </div>
+    </div>
+</div>
+<script type="text/javascript" src="/web/users/js/admin.js"></script>

+ 114 - 0
web/users/views/notify/index.html

@@ -0,0 +1,114 @@
+<%include ../layout/second_menu.html %>
+<div class="panel-content">
+    <div class="panel-title">
+        <div class="title-main">
+            <h2>用户通知
+                <a href="news-add.html" class="btn btn-primary btn-sm pull-right">新建通知</a></h2>
+        </div>
+    </div>
+    <div class="content-wrap">
+        <div class="c-header">
+            <!--变更类型-->
+            <div class="btn-group">
+                <button type="button" class="btn btn-default dropdown-toggle btn-sm" data-toggle="dropdown"
+                        aria-haspopup="true" aria-expanded="false">
+                    所有状态 <span class="caret"></span>
+                </button>
+                <ul class="dropdown-menu">
+                    <li><a href="#">已发布</a></li>
+                    <li><a href="#">未发布</a></li>
+                </ul>
+            </div>
+            <!--变更类别-->
+            <div class="btn-group">
+                <button type="button" class="btn btn-default dropdown-toggle btn-sm" data-toggle="dropdown"
+                        aria-haspopup="true" aria-expanded="false">
+                    所有年 <span class="caret"></span>
+                </button>
+                <ul class="dropdown-menu">
+                    <li><a href="#">2015</a></li>
+                    <li><a href="#">2016</a></li>
+                    <li><a href="#">2017</a></li>
+                </ul>
+            </div>
+            <!--变更性质-->
+            <div class="btn-group">
+                <button type="button" class="btn btn-default dropdown-toggle btn-sm" data-toggle="dropdown"
+                        aria-haspopup="true" aria-expanded="false">
+                    所有月 <span class="caret"></span>
+                </button>
+                <ul class="dropdown-menu">
+                    <li><a href="#">1</a></li>
+                    <li><a href="#">2</a></li>
+                    <li><a href="#">3</a></li>
+                    <li><a href="#">4</a></li>
+                    <li><a href="#">5</a></li>
+                    <li><a href="#">6</a></li>
+                    <li><a href="#">7</a></li>
+                    <li><a href="#">8</a></li>
+                    <li><a href="#">9</a></li>
+                    <li><a href="#">10</a></li>
+                    <li><a href="#">11</a></li>
+                </ul>
+            </div>
+        </div>
+        <div class="c-body">
+            <table class="table">
+                <thead>
+                <tr>
+                    <th>标题</th>
+                    <th>创建人</th>
+                    <th width="180">发布时间</th>
+                    <th width="100">操作</th>
+                </tr>
+                </thead>
+                <tbody>
+                <tr>
+                    <td><a href="javascript:void(0)" data-toggle="modal" data-target="#view">标题A chick me</a></td>
+                    <td>陈特</td>
+                    <td>2017-03-01 09:03:09</td>
+                    <td><a href="" class="btn btn-xs">编辑</a></td>
+                </tr>
+                <tr class="warning">
+                    <td><a href="#">标题B</a></td>
+                    <td>陈特</td>
+                    <td>未发布</td>
+                    <td><a href="" class="btn btn-xs">编辑</a></td>
+                </tr>
+                <tr>
+                    <td><a href="#">标题C</a></td>
+                    <td>陈特</td>
+                    <td>2017-03-01 09:03:09</td>
+                    <td><a href="" class="btn btn-xs">编辑</a></td>
+                </tr>
+                <tr>
+                    <td><a href="#">标题D</a></td>
+                    <td>陈特</td>
+                    <td>2017-03-01 09:03:09</td>
+                    <td><a href="" class="btn btn-xs">编辑</a></td>
+                </tr>
+
+                </tbody>
+            </table>
+            <nav aria-label="Page navigation">
+                <ul class="pagination pagination-sm">
+                    <li class="disabled">
+                        <a href="#" aria-label="Previous">
+                            <span aria-hidden="true">&laquo;</span>
+                        </a>
+                    </li>
+                    <li class="active"><a href="#">1</a></li>
+                    <li><a href="#">2</a></li>
+                    <li><a href="#">3</a></li>
+                    <li><a href="#">4</a></li>
+                    <li><a href="#">5</a></li>
+                    <li>
+                        <a href="#" aria-label="Next">
+                            <span aria-hidden="true">&raquo;</span>
+                        </a>
+                    </li>
+                </ul>
+            </nav>
+        </div>
+    </div>
+</div>

+ 29 - 0
web/users/views/tool/index.html

@@ -0,0 +1,29 @@
+<div class="panel-content">
+    <div class="panel-title fluid">
+        <div class="title-main">
+            <h2>工具</h2>
+        </div>
+    </div>
+    <div class="content-wrap">
+        <div class="row">
+            <div class="col-xs-6 mb-30 ">
+                <div class="c-body">
+                    <h2>清单规则编辑器
+                        <a href="#" class="btn btn-primary pull-right">进入</a></h2>
+                </div>
+            </div>
+            <div class="col-xs-6 mb-30 ">
+                <div class="c-body">
+                    <h2>定额编辑器
+                        <a href="#" class="btn btn-primary pull-right">进入</a></h2>
+                </div>
+            </div>
+            <div class="col-xs-6 mb-30 ">
+                <div class="c-body">
+                    <h2>报表模板
+                        <a href="#" class="btn btn-primary pull-right">进入</a></h2>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>

+ 80 - 0
web/users/views/user/index.html

@@ -0,0 +1,80 @@
+<%include ../layout/second_menu.html %>
+<div class="panel-content">
+    <div class="panel-title">
+        <div class="title-main">
+            <h2><%= secondMenu[action].title %></h2>
+        </div>
+    </div>
+    <div class="content-wrap">
+        <div class="c-header">
+            <!--最新注册-->
+            <div class="btn-group">
+                <button type="button" class="btn btn-default dropdown-toggle btn-sm" data-toggle="dropdown"
+                        aria-haspopup="true" aria-expanded="false">
+                    最新注册:最近24小时<span class="caret"></span>
+                </button>
+                <ul class="dropdown-menu">
+                    <li><a href="#">最近24小时</a></li>
+                    <li><a href="#">最近3天</a></li>
+                    <li><a href="#">最近7天</a></li>
+                    <li><a href="#">最近30天</a></li>
+                </ul>
+            </div>
+            <!--版本-->
+            <div class="btn-group">
+                <button type="button" class="btn btn-default dropdown-toggle btn-sm" data-toggle="dropdown"
+                        aria-haspopup="true" aria-expanded="false">
+                    版本 <span class="caret"></span>
+                </button>
+                <ul class="dropdown-menu">
+                    <li><a href="#">广东版</a></li>
+                    <li><a href="#">重庆版</a></li>
+                </ul>
+            </div>
+            <!--结果-->
+            <div class="btn-group">
+                &nbsp;共 <%= total %> 条结果
+            </div>
+            <!--搜索-->
+            <div class="btn-group pull-right">
+                <div class="input-group">
+                    <input type="text" class="form-control input-sm" placeholder="手机/邮箱/姓名/公司">
+                    <span class="input-group-btn">
+                        <button class="btn btn-default btn-sm" type="button">
+                            <i class="glyphicon glyphicon-search"></i>
+                        </button>
+                    </span>
+                </div>
+            </div>
+        </div>
+        <div class="c-body">
+            <table class="table">
+                <thead>
+                <tr>
+                    <th width="350">注册手机/邮箱</th>
+                    <th>姓名</th>
+                    <th>企业名称</th>
+                    <th>地区</th>
+                    <th width="180">注册时间</th>
+                </tr>
+                </thead>
+                <tbody>
+                <% userList.forEach(function (user){ %>
+                <tr>
+                    <td><%= user.mobile %> / <%= user.email %></td>
+                    <td><%= user.real_name %></td>
+                    <td><a tabindex="0" role="button" data-toggle="popover" data-trigger="focus" title="更多信息"
+                           data-content="企业类型:<%= model.companyType[user.company_type] %>,企业规模:<%= model.companyScale[user.company_scale] %>"><%= user.company %></a>
+                    </td>
+                    <td><%= model.province[user.province] %></td>
+                    <td><%= moment(user.create_time).format('YYYY-MM-DD HH:mm:ss') %></td>
+                </tr>
+                <% }) %>
+                </tbody>
+            </table>
+            <nav aria-label="Page navigation">
+                <%include ../layout/page.html %>
+            </nav>
+        </div>
+    </div>
+</div>