Browse Source

Merge branch 'master' of http://192.168.1.12:3000/SmartCost/ConstructionCost

TonyKang 7 years ago
parent
commit
beb6f308d5

+ 1 - 0
modules/all_models/user.js

@@ -13,6 +13,7 @@ let collectionName = 'user';
 
 // 表结构
 let schema = {
+    ssoId: Number,
     username: String,
     email: String,
     mobile: String,

+ 3 - 1
modules/common/helper/mongoose_helper.js

@@ -61,9 +61,11 @@ class MongooseHelper {
         let self = this;
         let limit = 0;
         let skip = 0;
+        let sort = {_id:1};
         if (option !== null && Object.keys(option).length > 0) {
             limit = option.pageSize !== undefined ? option.pageSize : limit;
             skip = option.offset !== undefined ? option.offset : skip;
+            sort = option.sort !== undefined ? option.sort : sort;
         }
 
         return new Promise(function (resolve, reject) {
@@ -73,7 +75,7 @@ class MongooseHelper {
                 } else {
                     resolve(data);
                 }
-            }).skip(skip).limit(limit);
+            }).sort(sort).skip(skip).limit(limit);
         });
     }
 

+ 6 - 2
modules/users/controllers/login_controller.js

@@ -54,12 +54,17 @@ class LoginController {
 
             // 正确登录后 存入session
             let userData = responseData[0];
+
+            if (userData.mobile === '') {
+                return response.json({error: 2,ssoId: userData.id});
+            }
             let sessionUser = {
                 ssoId: userData.id,
                 username: userData.username,
                 email: userData.useremail,
                 mobile: userData.mobile,
             };
+
             request.session.sessionUser = sessionUser;
             // 记录用户数据到数据库
             let result = await userModel.markUser(sessionUser, request);
@@ -76,6 +81,7 @@ class LoginController {
             compilationList = preferenceSetting.login_ask === 1 ? await compilationModel.getList() : [];
             // 获取编办信息
             let sessionCompilation = request.session.sessionCompilation;
+
             if (preferenceSetting.login_ask === 0 && !sessionCompilation &&
                 preferenceSetting.select_version !== '') {
 
@@ -83,12 +89,10 @@ class LoginController {
                 request.session.sessionCompilation = compilationData;
             }
 
-
         } catch (error) {
             console.log(error);
             return response.json({error: 1, msg: error});
         }
-        console.log(request.session.lastPage);
         response.json({
             error: 0,
             msg: '',

+ 80 - 0
modules/users/controllers/sms_controller.js

@@ -0,0 +1,80 @@
+/**
+ * 短信相关控制器
+ *
+ * @author EllisRan
+ * @date 2018/4/17
+ * @version
+ */
+import SmsModel from "../models/sms_model";
+
+class SmsController {
+
+    /**
+     * 发送短信验证码
+     *
+     * @param {object} request
+     * @param {object} response
+     * @return {void}
+     */
+    async code(request, response) {
+        let responseData = {
+            err: 0,
+            msg: ''
+        };
+        let mobile = request.body.mobile;
+        let type = request.body.type;
+        try {
+            let smsModel = new SmsModel();
+            let returnStatus = await smsModel.sendSmsFromSSO(mobile, type);
+            if (returnStatus === null) {
+                throw '获取数据失败!';
+            }
+            if(returnStatus != 1){
+                responseData.err = 1;
+                responseData.msg = await smsModel.getStatusMsg(returnStatus);
+            }
+        } catch (error) {
+            console.log(error);
+            responseData.err = 1;
+            responseData.msg = error;
+        }
+
+        response.json(responseData);
+    }
+
+    /**
+     * 手机和验证码验证并更新sso
+     *
+     * @param {object} request
+     * @param {object} response
+     * @return {void}
+     */
+    async setMobile(request, response) {
+        let responseData = {
+            err: 0,
+            msg: ''
+        };
+        let ssoId = request.body.ssoId;
+        let mobile = request.body.mobile;
+        let code = request.body.code;
+        try {
+            let smsModel = new SmsModel();
+            let returnStatus = await smsModel.checkCodeFromSSO(ssoId, mobile, code);
+            if (returnStatus === null) {
+                throw '获取数据失败!';
+            }
+            if(returnStatus != 1){
+                responseData.err = 1;
+                responseData.msg = await smsModel.getStatusMsg(returnStatus);
+            }
+        } catch (error) {
+            console.log(error);
+            responseData.err = 1;
+            responseData.msg = error;
+        }
+
+        response.json(responseData);
+    }
+}
+
+export default SmsController;

+ 1 - 1
modules/users/controllers/user_controller.js

@@ -59,7 +59,7 @@ class UserController extends BaseController {
             let sessionUser = request.session.sessionUser;
             // 切换验证场景
             let userModel = new UserModel();
-            let condition = {email: sessionUser.email};
+            let condition = {ssoId: sessionUser.ssoId};
             userModel.setScene('saveInfo');
             let result = await userModel.updateUser(condition, updateData);
 

+ 1 - 1
modules/users/models/log_model.js

@@ -95,7 +95,7 @@ class LogModel extends BaseModel {
         };
         page = parseInt(page);
         page = page <= 1 ? 1 : page;
-        let option = {pageSize: pageSize, offset: parseInt((page - 1) * pageSize)};
+        let option = {pageSize: pageSize, offset: parseInt((page - 1) * pageSize), sort: {create_time:-1}};
 
         let logList = await this.db.find(condition, null, option);
         logList = logList.length > 0 ? logList : [];

+ 97 - 0
modules/users/models/sms_model.js

@@ -0,0 +1,97 @@
+/**
+ * 短信业务模型
+ *
+ * @author EllisRan
+ * @date 2018/4/17
+ * @version
+ */
+import Request from "request";
+import BaseModel from "../../common/base/base_model";
+
+class SmsModel extends BaseModel {
+
+    /**
+     * 状态信息
+     *
+     * @var {object}
+     */
+    statusMsg = { 1:'发送成功', 2:'该手机号已注册', 3:'该手机号未注册', 0:'参数有误',
+        4:'短信接口方出错', 5:'验证码添加到数据库出错', 6:'手机号更改到数据库出错',
+        7:'验证码有误', 8:'sso账号不存在' };
+
+    /**
+     * 根据手机号和短信类型调用SSO短信接口获取信息
+     *
+     * @param {string} mobile
+     * @param {int} type  短信用途: 1->未注册过sso手机或更换手机号; 2->找回密码或修改密码;
+     * @return {int}  返回状态码
+     */
+    async sendSmsFromSSO(mobile, type) {
+        let postData = {
+            url: 'http://sso.smartcost.com.cn/building/api/smscode',
+            form: {mobile: mobile, type: type},
+            encoding: 'utf8'
+        };
+        return new Promise(function (resolve, reject) {
+            try {
+                // 请求接口
+                Request.post(postData, function (err, postResponse, body) {
+                    if (err) {
+                        throw '请求错误';
+                    }
+                    if (postResponse.statusCode !== 200) {
+                        throw '通行证验证失败!';
+                    }
+                    resolve(body);
+                });
+            } catch (error) {
+                reject([]);
+            }
+        });
+    }
+
+    /**
+     * 根据手机号和短信调用SSO短信接口并更新手机号
+     *
+     * @param {string} ssoid
+     * @param {string} mobile
+     * @param {string} code
+     * @return {int}  返回状态码
+     */
+    async checkCodeFromSSO(ssoid, mobile, code) {
+        let postData = {
+            url: 'http://sso.smartcost.com.cn/building/api/set/mobile',
+            form: {ssoId: ssoid, mobile: mobile, code: code},
+            encoding: 'utf8'
+        };
+        return new Promise(function (resolve, reject) {
+            try {
+                // 请求接口
+                Request.post(postData, function (err, postResponse, body) {
+                    if (err) {
+                        throw '请求错误';
+                    }
+                    if (postResponse.statusCode !== 200) {
+                        throw '通行证验证失败!';
+                    }
+                    resolve(body);
+                });
+            } catch (error) {
+                reject([]);
+            }
+        });
+    }
+
+
+    /**
+     * 根据状态码获取反馈信息
+     *
+     * @param {string} status
+     * @return {string}
+     */
+    async getStatusMsg(status) {
+        return this.statusMsg[status];
+    }
+}
+
+export default SmsModel;

+ 27 - 5
modules/users/models/user_model.js

@@ -84,17 +84,28 @@ class UserModel extends BaseModel {
      * @return {Promise}
      */
     async markUser(userData, request = null) {
-        let userDataFromDb = await this.findDataByName(userData.username);
+        let userDataFromDb2 = await this.findDataBySsoId(userData.ssoId);
+        let userDataFromDb = await this.findDataByName(userData.username);  //后面新增的账号可淘汰这方法,当前使用是为了兼容旧的账号
         let result = false;
 
-        if (userDataFromDb === null) {
+        if (userDataFromDb === null && userDataFromDb2 === null) {
             // 不存在用户则入库
             result = await this.addUser(userData);
             userDataFromDb = result;
         } else {
-            // 存在则新增登录信息
-            let logModel = new LogModel();
-            result = await logModel.addLoginLog(userDataFromDb._id, request);
+            // 存在则新增登录信息并更新账号信息
+            // let condition = {ssoId: sessionUser.ssoId};
+            let condition = {username: userData.username};
+            let UpdateData = {
+                email : userData.email,
+                mobile : userData.mobile,
+                ssoId : userData.ssoId
+            };
+            let updateResult = await this.updateUser(condition,UpdateData);
+            if (updateResult.ok === 1) {
+                let logModel = new LogModel();
+                result = await logModel.addLoginLog(userDataFromDb._id, request);
+            }
         }
         request.session.sessionUser.id = userDataFromDb._id;
         request.session.sessionUser.real_name = userDataFromDb.real_name;
@@ -129,6 +140,16 @@ class UserModel extends BaseModel {
     }
 
     /**
+     * 根据ssoID查找数据
+     *
+     * @param {string} ssoId
+     * @return {object}
+     */
+    findDataBySsoId(ssoId) {
+        return this.db.findOne({ssoId: ssoId});
+    }
+
+    /**
      * 新增用户
      *
      * @param {object} userData
@@ -136,6 +157,7 @@ class UserModel extends BaseModel {
      */
     addUser(userData) {
         let insertData = {
+            ssoId: userData.ssoId,
             username: userData.username,
             email: userData.email,
             mobile: userData.mobile,

+ 21 - 0
modules/users/routes/sms_route.js

@@ -0,0 +1,21 @@
+/**
+ * 短信相关路由
+ *
+ * @author EllisRan
+ * @date 2018/4/17
+ * @version
+ */
+import Express from "express";
+import SmsController from "../controllers/sms_controller";
+
+module.exports = function (app) {
+
+    const router = Express.Router();
+    const smsController = new SmsController();
+
+// action定义区域
+    router.post('/code', smsController.code);
+    router.post('/mobile', smsController.setMobile);
+
+    app.use('/sms',router);
+};

+ 2 - 2
server.js

@@ -55,8 +55,8 @@ app.use(session({
 // 登录状态全局判断
 app.use(function (req, res, next) {
     let url = req.originalUrl;
-    if (/^\/login/.test(url) || /\.map|\.ico$/.test(url)) {
-        // 如果是登录页面则忽略判断数据
+    if (/^\/login/.test(url) || /\.map|\.ico$/.test(url) || /^\/sms/.test(url)) {
+        // 如果是登录页面或短信接口则忽略判断数据
         next();
     } else {
         try {

+ 1 - 1
test/calculation/test_analyzer.js

@@ -213,5 +213,5 @@ let calcTemplate = {
 let expr = "F2+F5+F6+F10";
 let arr = analyzer.getFArr(expr);
 console.log(JSON.stringify(arr));
-let id = analyzer.getFID('F10', calcTemplate);
+let id = analyzer.getID('F10', calcTemplate);
 console.log(JSON.stringify(id));

+ 68 - 30
web/building_saas/main/js/models/calc_program.js

@@ -194,7 +194,7 @@ let calcTools = {
         let ns = fieldName.split(".");
         if (ns.length != 2)
             return 0
-        else if (treeNode.data.feesIndex[ns[0]] && treeNode.data.feesIndex[ns[0]][ns[1]])
+        else if (treeNode.data.feesIndex && treeNode.data.feesIndex[ns[0]] && treeNode.data.feesIndex[ns[0]][ns[1]])
             return parseFloat(treeNode.data.feesIndex[ns[0]][ns[1]])
         else
             return 0;
@@ -708,7 +708,7 @@ let analyzer = {
         let arrF = expr.match(pattF);
         return arrF ? arrF : [];
     },
-    getAtIDArr: function (expr) {
+    getAtIDArr: function (expr) {     // ['@1','@2']
         let patt = new RegExp(/@\d+/gi);
         let arr = expr.match(patt);
         return arr ? arr : [];
@@ -719,12 +719,20 @@ let analyzer = {
         return arrBase ? arrBase : [];
     },
 
-    getFID: function (FName, calcTemplate) {          // F3、F22 → 4、99
+    getID: function (FName, calcTemplate) {          // F13 → 4
         let idx = FName.slice(1) - 1;
         let id = calcTemplate.calcItems[idx] ? calcTemplate.calcItems[idx].ID : null;
         return id;
     },
-    getFItem: function (FName, calcTemplate){      // F3 → calcItems[2] → {Object}
+    getFName: function (atID, calcTemplate) {          // @3 → F7
+        for (var i = 0; i < calcTemplate.calcItems.length; i++) {
+            if (calcTemplate.calcItems[i].ID == atID.slice(1)) {
+                return 'F'+ (i + 1);
+            }
+        }
+        return null;
+    },
+    getItem: function (FName, calcTemplate){      // F3 → calcItems[2] → {Object}
         let idx = FName.slice(1) - 1;
         return calcTemplate.calcItems[idx];
     },
@@ -797,32 +805,46 @@ let analyzer = {
 
         return true;  // 表达式合法
     },
-    getExpression: function (dispExpr, calcTemplate) {
-        function refLineToID(expr, template) {
-            let rst = expr;
-            let fArr = me.getFArr(rst);
-            let IDArr = [];
-            for (let F of fArr){
-                let ID = me.getFID(F, template);
-                IDArr.push(ID);
-            };
-            for (let i = 0; i < fArr.length; i++) {
-                let patt = new RegExp(fArr[i]);
-                let val = `@${IDArr[i]}`;
-                rst = rst.replace(patt, val);
-            };
-            return rst;
+    refIDToLines: function (expression, template) {    // @2、@3 → F7、F8
+        let rst = expression;
+        let atIDArr = analyzer.getAtIDArr(rst);
+        let fArr = [];
+        for (let atID of atIDArr) {
+            let FN = analyzer.getFName(atID, template);
+            fArr.push(FN);
         };
-
-        let me = analyzer;
-        let expr = me.standard(dispExpr);
-        return refLineToID(expr, calcTemplate);
+        for (let i = 0; i < atIDArr.length; i++) {
+            let patt = new RegExp(atIDArr[i]);
+            let val = fArr[i];
+            rst = rst.replace(patt, val);
+        };
+        return rst;
+    },
+    refLineToIDs: function (dispExpr, template) {   // F7、F8 → @2、@3
+        let rst = analyzer.standard(dispExpr);
+        let fArr = me.getFArr(rst);
+        let IDArr = [];
+        for (let F of fArr) {
+            let ID = me.getID(F, template);
+            IDArr.push(ID);
+        };
+        for (let i = 0; i < fArr.length; i++) {
+            let patt = new RegExp(fArr[i]);
+            let val = `@${IDArr[i]}`;
+            rst = rst.replace(patt, val);
+        };
+        return rst;
+    },
+    getDispExpr: function (expression, calcTemplate) {
+        return analyzer.refIDToLines(expression, calcTemplate);
+    },
+    getExpression: function (dispExpr, calcTemplate) {
+        return analyzer.refLineToIDs(dispExpr, calcTemplate);
     },
     getDispExprUser: function (dispExpr, labourCoe) {   // labourCoe 是 str 类型
-        let me = analyzer;
-        let expr = me.standard(dispExpr);
-        expr = expr.replace(/L/g, labourCoe);
-        return expr;
+        let rst = analyzer.standard(dispExpr);
+        rst = rst.replace(/L/g, labourCoe);
+        return rst;
     },
     getCompiledExpr: function (expression, labourCoe) {   // labourCoe 是 str 类型
         let me = analyzer;
@@ -1053,8 +1075,7 @@ class CalcProgram {
             for (let idx of template.compiledSeq) {
                 let item = template.calcItems[idx];
 
-                let lc = 0;
-                if (item.labourCoeID) lc = me.compiledLabourCoes[item.labourCoeID].coe.toString();
+                let lc = me.getLabourCoe(item);
                 // 用于界面显示。disExpr是公式模板,不允许修改:人工系数占位符被修改后变成数值,第二次无法正确替换。
                 item.dispExprUser = analyzer.getDispExprUser(item.dispExpr, lc);
                 if (item.expression == 'HJ')
@@ -1083,7 +1104,8 @@ class CalcProgram {
 
             for (let i = 0; i < template.calcItems.length; i++) {
                 let item = template.calcItems[i];
-                item.expression = analyzer.getExpression(item.dispExpr, template);
+                // item.expression = analyzer.getExpression(item.dispExpr, template);
+                item.dispExpr = analyzer.getDispExpr(item.expression, template);
                 template.compiledCalcItems[item.ID] = item;
                 template.compiledCalcItems[item.ID + "_idx"] = i;
             }
@@ -1103,6 +1125,22 @@ class CalcProgram {
             }
         };
     };
+    
+    refreshTemplate(template){
+        let me = this;
+        for (let item of template){
+             item.dispExpr = analyzer.getDispExpr(item.expression, template);
+             item.dispExprUser = analyzer.getDispExprUser(item.dispExpr, me.getLabourCoe(item));
+        };
+    };
+
+    getLabourCoe(calcItem){
+        let me = this;
+        let lc = 0;
+        if (calcItem.labourCoeID)
+            lc = me.compiledLabourCoes[calcItem.labourCoeID].coe.toString();
+        return lc;
+    };
 
     // 存储、刷新零散的多个结点。
     saveNodes(treeNodes, callback){

+ 1 - 3
web/building_saas/main/js/views/calc_base_view.js

@@ -281,9 +281,7 @@ let calcBaseView = {
                 if (calcItem.dispExpr != expr){
                     if (analyzer.isLegal(expr, calcItem.ID, template)){
                         let cp = projectObj.project.calcProgram;
-                        let lc = 0;
-                        if (calcItem.labourCoeID)
-                            lc = cp.compiledLabourCoes[calcItem.labourCoeID].coe.toString();
+                        let lc = cp.getLabourCoe(calcItem);
                         calcItem.dispExpr = expr;
                         calcItem.dispExprUser = analyzer.getDispExprUser(expr, lc);
                         calcItem.expression = analyzer.getExpression(expr, template);

+ 6 - 7
web/building_saas/main/js/views/calc_program_manage.js

@@ -116,15 +116,14 @@ let calcProgramManage = {
         }
     },
     onEnterCell: function (sender, args) {
-       /* let t = calcProgramManage.getSelectionInfo().template;
+        let t = calcProgramManage.getSelectionInfo().template;
         let c = calcProgramManage.getSelectionInfo().calcItem;
-        c.expression = analyzer.getExpression(c.dispExpr, t);
-        let lc = 0;
-        if (c.labourCoeID) lc = projectObj.project.calcProgram.compiledLabourCoes[c.labourCoeID].coe.toString();
+        let lc = projectObj.project.calcProgram.getLabourCoe(c);
+        c.dispExpr = analyzer.getDispExpr(c.expression, t);
+        c.dispExprUser = analyzer.getDispExprUser(c.dispExpr, lc);
         c.compiledExpr = analyzer.getCompiledExpr(c.expression, lc);
-
-        let e = c.dispExpr + '  ' + c.expression + '  ' + c.compiledExpr;
-        projectObj.testDisplay('', e);*/
+        let e = c.expression + ' ' + c.dispExpr + ' ' + c.dispExprUser + ' ' + c.compiledExpr;
+        projectObj.testDisplay('', e);
     },
     saveCalcItem: function (data,callback) {//data
         let me = this;

+ 3 - 33
web/building_saas/main/js/views/project_view.js

@@ -31,9 +31,6 @@ var projectObj = {
         }
         project.mainTree.preSelected = node;
         projectObj.setNodesStyle(projectObj.mainController.sheet, refreshNodes);
-   /*     TREE_SHEET_HELPER.massOperationSheet(projectObj.mainController.sheet, function () {
-            TREE_SHEET_HELPER.refreshTreeNodeData(projectObj.mainController.setting, projectObj.mainController.sheet, refreshNodes, false);
-        });*/
 
         subViewObj.loadComments(node);
         gljOprObj.showDataIfRationSelect(node);
@@ -455,35 +452,6 @@ var projectObj = {
             projectObj.mainController.refreshTreeNode([node], false);
         }
     },
-    mainSpreadSlectionChanging: function (sender, info) {
-        console.log('bbbb');
-        let oldSel = info.oldSelections[0], newSel = info.newSelections[0];
-        let project = projectObj.project;
-        //设置选中行底色和恢复前选中行底色
-        let refreshNodes = [];
-        if(oldSel){
-            oldSel.row === -1 ? 0 : oldSel.row;
-            for(let i = 0; i < oldSel.rowCount; i++){
-                if(project.mainTree.items[i + oldSel.row]){
-                    refreshNodes.push(project.mainTree.items[i + oldSel.row]);
-                }
-            }
-        }
-        if(newSel){
-            newSel.row === -1 ? 0 : newSel.row;
-            for(let i = 0; i < newSel.rowCount; i++){
-                if(project.mainTree.items[i + newSel.row]){
-                    refreshNodes.push(project.mainTree.items[i + newSel.row]);
-                }
-            }
-        }
-        if(refreshNodes.length > 0){
-            projectObj.setNodesStyle(projectObj.mainController.sheet, refreshNodes, newSel);
-            /* TREE_SHEET_HELPER.massOperationSheet(projectObj.mainController.sheet, function () {
-             TREE_SHEET_HELPER.refreshTreeNodeData(projectObj.mainController.setting, projectObj.mainController.sheet, refreshNodes, false, true);
-             });*/
-        }
-    },
     mainSpreadLeaveCell: function (sender, info) {
         let colSetting = projectObj.mainController.setting.cols[info.col];
         projectObj.lastCol = colSetting;
@@ -1187,7 +1155,9 @@ var projectObj = {
         let me = this;
         TREE_SHEET_HELPER.massOperationSheet(sheet, function () {
             for(let node of nodes){
-                sheet.setStyle(node.serialNo(), -1, me.getNodeColorStyle(sheet, node));
+                if(node){
+                    sheet.setStyle(node.serialNo(), -1, me.getNodeColorStyle(sheet, node));
+                }
             }
         });
      

+ 1 - 1
web/common/html/header.html

@@ -37,7 +37,7 @@
     <div id="testDisplay" style="color:#ff7e0e;">&nbsp;&nbsp;</div>
     <div class="ml-auto navbar-text p-0">
         <div class="dropdown d-inline-block navbar-nav">
-            <button class="btn btn-link btn-sm dropdown-toggle" type="button" data-toggle="dropdown"><%= sessionUser.real_name === '' ? sessionUser.email : sessionUser.real_name %></button>
+            <button class="btn btn-link btn-sm dropdown-toggle" type="button" data-toggle="dropdown"><%= sessionUser.real_name === '' ? sessionUser.mobile : sessionUser.real_name %></button>
             <div class="dropdown-menu dropdown-menu-right">
                 <a class="dropdown-item" href="/user/info" target="_blank">账号资料</a>
                 <a class="dropdown-item" href="user-buy.html" target="_blank">产品购买</a>

+ 2 - 1
web/common/html/page.html

@@ -1,6 +1,7 @@
 <nav aria-label="...">
-    <ul aria-label="pagination" id="pages"></ul>
+    <ul class="pagination" id="pages"></ul>
 </nav>
+<script type="text/javascript" src="/lib/bootstrap/bootstrap-paginator.js"></script>
 <script type="text/javascript">
     let options = {
         bootstrapMajorVersion: 3,

+ 34 - 0
web/users/html/login.html

@@ -66,6 +66,40 @@
             </div>
         </div>
     </div>
+    <!--弹出手机号-->
+    <div class="modal fade" id="phone" data-backdrop="static">
+        <div class="modal-dialog" role="document">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <h5 class="modal-title">验证手机号</h5>
+                </div>
+                <div class="modal-body">
+                    <input type="hidden" id="check_ssoId" value="" />
+                    <div class="form-row">
+                        <div class="form-group col-md-8">
+                            <input type="text" class="form-control" id="mobile" placeholder="输入手机号">
+                            <div class="invalid-feedback">
+                            </div>
+                        </div>
+                    </div>
+                    <div class="form-row">
+                        <div class="form-group col-md-8">
+                            <input type="text" class="form-control" readonly id="code" placeholder="输入验证码">
+                            <div class="invalid-feedback">
+                            </div>
+                        </div>
+                        <div class="form-group col-md-4">
+                            <button class="btn btn-primary" id="get-code">获取验证码</button>
+                        </div>
+                    </div>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+                    <button class="btn btn-primary" id="check-code">确定</button>
+                </div>
+            </div>
+        </div>
+    </div>
     <!-- JS. -->
     <!-- inject:js -->
     <script type="text/javascript" src="/public/web/scMathUtil.js"></script>

+ 3 - 3
web/users/html/user-info.html

@@ -19,16 +19,16 @@
     <div class="poj-manage container-fluid">
         <div class="row">
             <div class="col-lg-2">
-                <div class="poj-cate mt-3">
+                <div class="mt-3">
                     <ul class="nav nav-pills flex-column">
                         <li class="nav-item">
-                            <a class="nav-link active" href="user-info.html">账号资料</a>
+                            <a class="nav-link active" href="/user/info">账号资料</a>
                         </li>
                         <li class="nav-item">
                             <a class="nav-link" href="/user/safe">账号安全</a>
                         </li>
                         <li class="nav-item">
-                            <a class="nav-link" href="user-buy.html">产品购买</a>
+                            <a class="nav-link" href="/user/buy">产品购买</a>
                         </li>
                         <li class="nav-item">
                             <a class="nav-link" href="/user/preferences">偏好设置</a>

+ 8 - 8
web/users/html/user-safe.html

@@ -5,7 +5,7 @@
     <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>
+    <title>账号安全-Smartcost</title>
     <link rel="stylesheet" href="/lib/bootstrap/css/bootstrap.min.css">
     <link rel="stylesheet" href="/web/building_saas/css/main.css">
     <link rel="stylesheet" href="/lib/font-awesome/font-awesome.min.css">
@@ -13,8 +13,8 @@
     <script src="/lib/jquery/jquery-3.2.1.min.js"></script>
     <script src="/lib/popper/popper.min.js"></script>
     <script src="/lib/bootstrap/bootstrap.min.js"></script>
-    <script type="text/javascript" src="/lib/bootstrap/bootstrap-paginator.js"></script>
-    <script src="/web/building_saas/js/global.js"></script>
+    <!--<script type="text/javascript" src="/lib/bootstrap/bootstrap-paginator.js"></script>-->
+    <!--<script src="/web/building_saas/js/global.js"></script>-->
 </head>
 
 <body>
@@ -25,7 +25,7 @@
     <div class="poj-manage container-fluid">
         <div class="row">
             <div class="col-lg-2">
-                <div class="poj-cate mt-3">
+                <div class="mt-3">
                     <ul class="nav nav-pills flex-column">
                         <li class="nav-item">
                             <a class="nav-link" href="/user/info">账号资料</a>
@@ -34,7 +34,7 @@
                             <a class="nav-link active" href="/user/safe">账号安全</a>
                         </li>
                         <li class="nav-item">
-                            <a class="nav-link" href="user-buy.html">产品购买</a>
+                            <a class="nav-link" href="/user/buy">产品购买</a>
                         </li>
                         <li class="nav-item">
                             <a class="nav-link" href="/user/preferences">偏好设置</a>
@@ -129,8 +129,8 @@
     </div>
 </div>
 </body>
-<script type="text/javascript">
-    autoFlashHeight();
-</script>
+<!--<script type="text/javascript">-->
+    <!--autoFlashHeight();-->
+<!--</script>-->
 
 </html>

+ 15 - 16
web/users/html/user-set.html

@@ -19,19 +19,20 @@
         <div class="poj-manage container-fluid">
             <div class="row">
                 <div class="col-lg-2">
-                    <div class="poj-cate mt-3">
+                    <!--<div class="poj-cate mt-3">-->
+                    <div class="mt-3">
                         <ul class="nav nav-pills flex-column">
                             <li class="nav-item">
-                                <a class="nav-link" href="user-info.html">账号资料</a>
+                                <a class="nav-link" href="/user/info">账号资料</a>
                             </li>
                             <li class="nav-item">
-                                <a class="nav-link" href="user-safe.html">账号安全</a>
+                                <a class="nav-link" href="/user/safe">账号安全</a>
                             </li>
                             <li class="nav-item">
-                                <a class="nav-link" href="user-buy.html">产品购买</a>
+                                <a class="nav-link" href="/user/buy">产品购买</a>
                             </li>
                             <li class="nav-item">
-                                <a class="nav-link active" href="user-set.html">偏好设置</a>
+                                <a class="nav-link active" href="/user/preferences">偏好设置</a>
                             </li>
                         </ul>
                     </div>
@@ -42,19 +43,17 @@
                         <form method="post" action="/user/save-preferences">
                             <div class="form-group">
                                 <label class="form-control-label">登录时选择版本</label>
-                                <div>
-                                    <label class="custom-control custom-radio">
-                                      <input name="login_ask" type="radio" class="custom-control-input" value="1"
+                                <div class="form-control">
+                                    <div class="form-check form-check-inline">
+                                      <input name="login_ask" type="radio" class="form-check-input" value="1"
                                         <% if(preferenceSetting.login_ask === 1) { %>checked="checked" <% } %>>
-                                      <span class="custom-control-indicator"></span>
-                                      <span class="custom-control-description">每次询问</span>
-                                    </label>
-                                    <label class="custom-control custom-radio">
-                                      <input name="login_ask" type="radio" class="custom-control-input" value="0"
+                                      <label class="form-check-label">每次询问</label>
+                                    </div>
+                                    <div class="form-check form-check-inline">
+                                      <input name="login_ask" type="radio" class="form-check-input" value="0"
                                         <% if(preferenceSetting.login_ask === 0) { %>checked="checked" <% } %>>
-                                      <span class="custom-control-indicator"></span>
-                                      <span class="custom-control-description">指定版本</span>
-                                    </label>
+                                      <span class="form-check-label">指定版本</span>
+                                    </div>
                                 </div>
                             </div>
                             <div class="form-group">

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

@@ -35,6 +35,9 @@ $(document).ready(function () {
                         setVersion(response.compilation_list);
                         $('#ver').modal('show');
                     }
+                } else if(response.error === 2) {
+                    $('#check_ssoId').val(response.ssoId);
+                    $('#phone').modal('show');
                 } else {
                     let msg = response.msg !== undefined ? response.msg : '未知错误';
                     showError(msg, $("input"));
@@ -48,15 +51,146 @@ $(document).ready(function () {
 
     $("input").blur(function () {
         cleanError();
+        cleanValidError($(this));
     });
 
     $(".form-control").on('input', function () {
         $('#hint').html('&nbsp;');
     });
 
+    $("#get-code").click(function() {
+        const mobile = $("#mobile").val();
+        if(!validMobile(mobile)){
+            return false;
+        }
+        const btn = $(this);
+        if(!btn.hasClass('disabled')){
+            $.ajax({
+                url: '/sms/code',
+                type: 'post',
+                data: { mobile: mobile, type: 1},
+                error: function() {
+                    showValidError('短信接口出错!',$('#mobile'));
+                },
+                beforeSend: function() {
+                },
+                success: function(response) {
+                    if (response.err === 0) {
+                        codeSuccess(btn);
+                    } else {
+                        showValidError(response.msg,$('#mobile'));
+                    }
+                }
+            });
+        }
+    });
+
+    $('#check-code').click(function () {
+        const mobile = $("#mobile").val();
+        const ssoId = $("#check_ssoId").val();
+        const code = $("#code").val();
+        if(!validMobile(mobile)) {
+            return false;
+        }
+        if(ssoId === undefined || ssoId === '') {
+            showValidError('账号有误!', $('#code'));
+            return false;
+        }
+        if($.trim(code) === '') {
+            showValidError('验证码不能为空!', $('#code'));
+            return false;
+        }
+        $.ajax({
+            url: '/sms/mobile',
+            type: 'post',
+            data: {ssoId: ssoId, mobile: mobile, code: code},
+            error: function() {
+                showValidError('接口出错!',$('#code'));
+            },
+            beforeSend: function() {
+            },
+            success: function(response) {
+                if (response.err === 0) {
+                    $("#login").click();
+                    $('#phone').modal('hide');
+                } else {
+                    showValidError(response.msg,$('#code'));
+                }
+            }
+        })
+
+    });
+
 });
 
 /**
+ * 获取成功后的操作
+ *
+ * @param {Object} btn - 点击的按钮
+ * @return {void}
+ */
+function codeSuccess(btn) {
+    let counter = 60;
+    btn.removeClass('btn-primary').addClass('btn-outline-secondary disabled').text(counter + '秒 重新获取');
+    btn.parents().siblings('div').children('input').removeAttr('readonly');
+
+    const countDown = setInterval(function() {
+        const countString = counter - 1 <= 0 ? '' : ' ' + (counter - 1) + '秒 ';
+        // 倒数结束后
+        if (countString === '') {
+            clearInterval(countDown);
+            btn.removeClass('btn-outline-secondary disabled').addClass('btn-primary').text('获取验证码');
+        }
+        const text = countString + '重新获取';
+        btn.text(text);
+        counter -= 1;
+    }, 1000);
+}
+
+/**
+ * 验证手机号是否正确
+ *
+ * @return {boolean}
+ */
+function validMobile(mobile) {
+    let result = true;
+    if($.trim(mobile) === ''){
+        showValidError('手机号不能为空!',$('#mobile'));
+        return false;
+    }
+    let mobileValid =  /^(((13[0-9]{1})|(15[0-9]{1})|(18[0-9]{1})|(17[0-9]{1})|(14[0-9]{1}))+\d{8})$/;
+    if(!mobileValid.test(mobile)){
+        showValidError('手机号码格式有误!',$('#mobile'));
+        return false;
+    }
+    return result;
+}
+
+/**
+ * 提示验证信息错误
+ *
+ * @param {string} msg
+ * @param {object} element
+ * @return {void}
+ */
+function showValidError(msg, element) {
+    if (element !== null) {
+        element.addClass('is-invalid');
+        element.siblings().text(msg);
+    }
+}
+
+/**
+ * 清除验证信息错误提示
+ *
+ * @return {void}
+ */
+function cleanValidError(element) {
+    element.removeClass('is-invalid');
+    element.siblings().text('');
+}
+
+/**
  * 验证数据
  *
  * @return {boolean}