介绍
介绍
福哥今天带着大家完成会员中心的最后一个表单——设置安全问题的开发。这个安全问题一般情况下是不允许修改的,所以我们暂时也不提供修改的功能。
密码安全问题一共有三组,每一组一个问题配着一个答案。问题都是一样的,所以实际上我们是在一组问题里面挑出三个问题。既然问题是固定的,就可以用编号来表示,而答案是根据用户自己的想法写的,只能是原封不动地保存起来了。
这里有个难题,就是三个问题下拉框,一个下拉框选中的选项其他下拉框就不能再选了。也就是说,不能出现重复的问题,第一个问题选择:我居住的城市名称是?,第二个问题就不能选这个了。
模型user
setSecurityQuestions
public function setSecurityQuestions(int $userID, int $q1, string $a1, int $q2, string $a2, int $q3, string $a3):int { $tfdo = $this->tfphp->getDatabase()->getTFDO(); $userInfo = $this->getByTable("user", array($userID)); if($userInfo == null){ return 1; } $sqInfo = $this->getByTable("user_security_questions", array($userID)); if($sqInfo == null){ $ret = $tfdo->insert("user_security_questions", array( 'userID'=>$userID, 'q1'=>$q1, 'a1'=>$a1, 'q2'=>$q2, 'a2'=>$a2, 'q3'=>$q3, 'a3'=>$a3, ), array( 'userID'=>"int", 'q1'=>"int", 'q2'=>"int", 'q3'=>"int", )); } else{ $ret = $tfdo->update("user_security_questions", array( 'q1'=>$q1, 'a1'=>$a1, 'q2'=>$q2, 'a2'=>$a2, 'q3'=>$q3, 'a3'=>$a3, ), array( 'q1'=>"int", 'q2'=>"int", 'q3'=>"int", ), "userID = @int", array($userID)); } if(!$ret){ return 2; } return 0; }
接口控制器
doSave
private function doSave(){ $req = $this->tfphp->getRequest(); $post = $req->post; $user = new user($this->tfphp); $q1 = $post->get("q1"); $a1 = $post->get("a1"); $q2 = $post->get("q2"); $a2 = $post->get("a2"); $q3 = $post->get("q3"); $a3 = $post->get("a3"); try{ // request test if($q1 == "" || $a1 == "" || $q2 == "" || $a2 == "" || $q3 == "" || $a3 == ""){ return $this->tfphp->getResponse()->responseJSON_CM(200, 1001061, "错误请求"); } // create user $ret = $user->setSecurityQuestions($this->permission->getLoginStatus()->userID, $q1, $a1, $q2, $a2, $q3, $a3); switch ($ret){ case 1: return $this->tfphp->getResponse()->responseJSON_CM(200, 1001062, "用户名不存在"); break; case 2: return $this->tfphp->getResponse()->responseJSON_CM(200, 1001063, "邮箱地址已经存在"); break; case 3: return $this->tfphp->getResponse()->responseJSON_CM(200, 1001064, "发送邮件失败"); break; } } catch(\TypeError $e){ return $this->tfphp->getResponse()->responseJSON_CM(200, 1001061, "错误请求".$e->getMessage()); } // output return $this->tfphp->getResponse()->responseJSON_CM(200, 0, "OK"); }
视图
HTML代码
<!-- security question form begin --> <div class="row login-form"> <div class="col-sm-12"> <h3 class="text-center">安全问题</h3> <p>设置三个安全问题以及对应的答案,在忘记密码的时候可以通过安全问题重置密码</p> <form> <div class="form-group"> <label>第一个问题</label> <select class="form-control" name="q1"> <option>选择一个问题</option> <% foreach item=cItem key=cKey from=$sqArr %> <option value="<% $cKey %>"><% $cItem %></option> <% /foreach %> </select> </div> <div class="form-group"> <label>第一个问题的答案</label> <input class="form-control" type="text" name="a1" /> </div> <div class="form-group"> <label>第二个问题</label> <select class="form-control" name="q2"> <option>选择一个问题</option> <% foreach item=cItem key=cKey from=$sqArr %> <option value="<% $cKey %>"><% $cItem %></option> <% /foreach %> </select> </div> <div class="form-group"> <label>第二个问题的答案</label> <input class="form-control" type="text" name="a2" /> </div> <div class="form-group"> <label>第三个问题</label> <select class="form-control" name="q3"> <option>选择一个问题</option> <% foreach item=cItem key=cKey from=$sqArr %> <option value="<% $cKey %>"><% $cItem %></option> <% /foreach %> </select> </div> <div class="form-group"> <label>第三个问题的答案</label> <input class="form-control" type="text" name="a3" /> </div> <div class="form-group"> <button class="btn btn-primary btn-sm form-control">设置安全问题</button> </div> </form> </div> </div> <!-- security question form end -->
JS代码
$('form').form({ url: "<% $TFReq->server->BASE_URI %>api/member/securityQuestions/_save", method: "post", validations: [ {type:"empty", name:"q1", msg:"请选择第一个问题"}, {type:"empty", name:"a1", msg:"请填写第一个问题的答案"}, {type:"empty", name:"q2", msg:"请选择第二个问题"}, {type:"empty", name:"a2", msg:"请填写第二个问题的答案"}, {type:"empty", name:"q3", msg:"请选择第三个问题"}, {type:"empty", name:"a3", msg:"请填写第三个问题的答案"} ], onSuccess: function (d) { if(d.errcode == 0){ document.location = '<% $TFReq->server->BASE_URI %>member/securityQuestionsOK.htm'; } else{ $('form').tips({ text:d.errmsg }); } }, onError: function (d) { $('form').tips({ text:"服务器响应错误" }); }, onValidationError: function (form, name, msg) { $('form').tips({ text:msg }); $('form').find('[name="'+ name +'"]').focus(); } }); var onQuestionChanged = function(){ var qs = [$('[name="q1"]'), $('[name="q2"]'), $('[name="q3"]')], qi, oi, si, selecteds = [], opts; for(qi=0;qi<qs.length;qi++){ selecteds.push(qs[qi].val()); } for(qi=0;qi<qs.length;qi++){ opts = qs[qi].find('option'); opts.show(); for(oi=0;oi<opts.length;oi++){ if(!$(opts[oi]).prop('selected')){ for(si=0;si<selecteds.length;si++){ if(selecteds[si] == $(opts[oi]).val()){ $(opts[oi]).hide(); } } } } } }; $('[name="q1"]').bind('change', onQuestionChanged); $('[name="q2"]').bind('change', onQuestionChanged); $('[name="q3"]').bind('change', onQuestionChanged);
讲解
模型user
setSecurityQuestions
首先检查用户是否存在,不存在就报错。
接着尝试写入user_security_questions表,不存在就写入,存在就更新。
接口控制器
doSave
使用setSecurityQuestions方法处理设置安全问题表单数据。
视图模板
HTML代码
这里使用PHP传入的问题数据渲染出三个问题下拉框的选项。
JS代码
前面是标准的表单处理JS程序,没什么可说的。
后面是难点,我们要通过JS实现三个问题下拉框不能重复选择相同问题的控制。
思路是这样的,首先将三个问题下拉框放到一个数组qs里面。接着遍历所有问题下拉框找出已经选中的选项,把它们存进一个数组selecteds里面。然后就是重点了,这是一个三层嵌套的循环语句,第一层遍历所有下拉框,将所有选项置为显示;第二层遍历每个下拉框的所有选项,找出不是选中项的选项进行遍历;第三次遍历selecteds数组,如果当前选项属于某一个下拉框的选项中项就隐藏起来。这样就可以避免多个问题下拉框的问题选择重复的问题了!
效果
设置表单界面
设置完成界面
总结
今天福哥带着童鞋们完成了安全问题设置表单的功能。这里面的一个避免选择重复问题的逻辑稍微有点难度,童鞋们可以发现这个东西实现起来需要很多技巧的,最重要的是要有很好的逻辑思维才能实现。
下一课我们将使用绑定邮箱和安全问题实现密码重置的功能了~~