完善用户中心功能

This commit is contained in:
2020-04-15 14:56:30 +08:00
parent 906dccda61
commit 10b40f0071
14 changed files with 370 additions and 16 deletions

View File

@@ -16,9 +16,11 @@ use app\model\Form;
class Base extends BaseC { class Base extends BaseC {
protected $outAuthUrl = ['user/index/login', 'user/index/logout', 'user/index/verify', 'user/index/register', 'user/index/forget', 'user/index/resetpasswd'];
protected function initialize() { protected function initialize() {
$url = str_replace(".", "/", strtolower($this->request->controller())) . '/' . $this->request->action(); $url = str_replace(".", "/", strtolower($this->request->controller())) . '/' . $this->request->action();
if (!is_login() && !in_array($url, array('user/index/login', 'user/index/logout', 'user/index/verify', 'user/index/register'))) { if (!is_login() && !in_array($url, $this->outAuthUrl)) {
$this->redirect('/user/index/login'); $this->redirect('/user/index/login');
} }

View File

@@ -8,6 +8,9 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
namespace app\controller\user; namespace app\controller\user;
use app\model\Member;
use think\facade\Session;
/** /**
* @title 用户中心 * @title 用户中心
*/ */
@@ -26,7 +29,19 @@ class Index extends Base {
* @return [type] [description] * @return [type] [description]
*/ */
public function login() { public function login() {
return $this->fetch(); if ($this->request->isAjax()) {
try {
$userinfo = (new Member())->login($this->request);
if ($userinfo) {
Session::set('userInfo', $userinfo);
return $this->success('登录成功!', url('/user/index/index'));
}
} catch (Exception $e) {
return $this->error($e->getError(), '');
}
}else{
return $this->fetch();
}
} }
/** /**
@@ -34,7 +49,8 @@ class Index extends Base {
* @return [type] [description] * @return [type] [description]
*/ */
public function logout() { public function logout() {
return $this->fetch(); Session::delete('userInfo');
$this->redirect('/user/index/login');
} }
/** /**
@@ -42,7 +58,16 @@ class Index extends Base {
* @return [type] [description] * @return [type] [description]
*/ */
public function register() { public function register() {
return $this->fetch(); if ($this->request->isAjax()) {
$result = (new Member())->register($this->request);
if (false !== $result) {
return $this->success("注册成功!", url('/user/index/login'));
}else{
return $this->error("注册失败!");
}
}else{
return $this->fetch();
}
} }
/** /**
@@ -50,7 +75,30 @@ class Index extends Base {
* @return [type] [description] * @return [type] [description]
*/ */
public function forget() { public function forget() {
return $this->fetch(); if ($this->request->isAjax()) {
$data = $this->request->post();
$map = [];
if (!$data['username'] || !$data['email']) {
return $this->error("请完整填写信息!");
}
$map[] = ['username', '=', $data['username']];
$map[] = ['email', '=', $data['email']];
$user = Member::where($map)->findOrEmpty();
if (!$user->isEmpty()) {
//发生重置密码连接电子邮件
$result = Member::sendFindPaswd($user);
if (false !== $result) {
return $this->success("已发送找回密码邮件!", url('/user/index/login'));
}else{
return $this->error("发送邮件失败!");
}
}else{
return $this->error('无此用户!');
}
}else{
return $this->fetch();
}
} }
/** /**
@@ -58,6 +106,33 @@ class Index extends Base {
* @return [type] [description] * @return [type] [description]
*/ */
public function resetpasswd() { public function resetpasswd() {
return $this->fetch(); if ($this->request->isAjax()) {
$token = $this->request->get('token');
$data = $this->request->post();
list($username, $email) = explode("|", \xin\helper\Secure::decrypt($token, \think\facade\Env::get('jwt.secret')));
if (!$username || !$email) {
return $this->error("找回密码地址错误或已过期!");
}
$map[] = ['username', '=', $username];
$map[] = ['email', '=', $email];
$user = Member::where($map)->findOrEmpty();
if (!$user->isEmpty()) {
$data['salt'] = \xin\helper\Str::random(6);
$result = Member::update($data, ['uid' => $user['uid']]);
if (false !== $result) {
return $this->success("已重置!", url('/user/index/login'));
}else{
return $this->error("发送邮件失败!");
}
}else{
return $this->error('无此用户!');
}
}else{
$token = $this->request->param('token');
return $this->fetch();
}
} }
} }

View File

@@ -20,8 +20,8 @@ class User extends Base {
*/ */
public function profile() { public function profile() {
if ($this->request->isPost()) { if ($this->request->isPost()) {
$reuslt = (new Member())->editUser($this->request, session('userInfo.uid')); $result = (new Member())->editUser($this->request, session('userInfo.uid'));
if (false !== $reuslt) { if (false !== $result) {
return $this->success('修改成功!'); return $this->success('修改成功!');
} else { } else {
return $this->error('修改失败'); return $this->error('修改失败');
@@ -41,7 +41,29 @@ class User extends Base {
* @return [type] [description] * @return [type] [description]
*/ */
public function repasswd() { public function repasswd() {
return $this->fetch(); if ($this->request->isAjax()) {
$data = $this->request->post();
$user = Member::where('uid', $data['uid'])->findOrEmpty();
if (!$user->isEmpty()) {
if (md5($data['oldpassword'] . $user['salt']) !== $user['password']) {
return $this->error('旧密码不正确!');
}
$data['salt'] = \xin\helper\Str::random(6);
$result = $user->save($data);
if (false !== $result) {
return $this->success('修改成功!');
} else {
return $this->error('修改失败');
}
}else{
return $this->error('无此用户!');
}
}else{
return $this->fetch();
}
} }
/** /**

View File

@@ -1,4 +1,4 @@
<select class="form-control selectpicker" name="{$name}" id="{$name}" style="min-width: 200px;" {if isset($is_must) && $is_must}data-rule="required"{/if}> <select class="form-control selectpicker" name="{$name}" id="{$name}" style="width:auto; min-width: 200px;" {if isset($is_must) && $is_must}data-rule="required"{/if}>
{volist name="option" id="item"} {volist name="option" id="item"}
<option value="{$item['key']}" {if $item['key'] == $value}selected{/if}>{$item['label']}</option> <option value="{$item['key']}" {if $item['key'] == $value}selected{/if}>{$item['label']}</option>
{/volist} {/volist}

View File

@@ -242,6 +242,12 @@ class Member extends Model {
self::where(['uid' => $user['uid']])->update($data); self::where(['uid' => $user['uid']])->update($data);
} }
public static function sendFindPaswd($user){
$token = \xin\helper\Secure::encrypt($user['username'] . "|" . $user['email'], \think\facade\Env::get('jwt.secret'));
$url = url('/user/index/resetpasswd', ['token'=>$token], true, true);
return true;
}
public function depart() { public function depart() {
return $this->hasOne('Department', 'id', 'department'); return $this->hasOne('Department', 'id', 'department');
} }

View File

@@ -57,7 +57,7 @@ define(['jquery', 'bootstrap', 'validator'], function ($, undefined, Validator)
//验证通过提交表单 //验证通过提交表单
var submitResult = Form.api.submit($(ret), function (data, ret) { var submitResult = Form.api.submit($(ret), function (data, ret) {
that.holdSubmit(false); that.holdSubmit(false);
// submitBtn.removeClass("disabled"); submitBtn.removeClass("disabled").removeAttr('disabled');
if (false === $(this).triggerHandler("success.form", [data, ret])) { if (false === $(this).triggerHandler("success.form", [data, ret])) {
return false; return false;
} }
@@ -81,7 +81,7 @@ define(['jquery', 'bootstrap', 'validator'], function ($, undefined, Validator)
if (false === $(this).triggerHandler("error.form", [data, ret])) { if (false === $(this).triggerHandler("error.form", [data, ret])) {
return false; return false;
} }
submitBtn.removeClass("disabled"); submitBtn.removeClass("disabled").removeAttr('disabled');
if (typeof error === 'function') { if (typeof error === 'function') {
if (false === error.call($(this), data, ret)) { if (false === error.call($(this), data, ret)) {
return false; return false;
@@ -98,7 +98,7 @@ define(['jquery', 'bootstrap', 'validator'], function ($, undefined, Validator)
}, form.data("validator-options") || {})); }, form.data("validator-options") || {}));
//移除提交按钮的disabled类 //移除提交按钮的disabled类
$("button.btn[type=submit]", form).removeClass("disabled"); $("button.btn[type=submit]", form).removeClass("disabled").removeAttr('disabled');
}, },
editor: function (form) { editor: function (form) {
//绑定编辑器元素事件 //绑定编辑器元素事件

View File

@@ -10,7 +10,9 @@
<!-- Styles --> <!-- Styles -->
<style> <style>
html, body {background-color: #fff; color: #636b6f; font-family: 'Raleway', sans-serif; font-weight: 100; height: 100vh; margin: 0;} html, body {background-color: #fff; color: #636b6f; font-family: 'Raleway', sans-serif; font-weight: 100; height: 100vh; margin: 0;}
.full-height {height: 100vh;} .top{text-align: right; line-height: 35px; padding: 0 20px;}
.top a{color: #333333; padding: 0 10px}
.full-height {height: 90vh;}
.flex-center {align-items: center;display: flex;justify-content: center;} .flex-center {align-items: center;display: flex;justify-content: center;}
.position-ref {position: relative;} .position-ref {position: relative;}
.top-right {position: absolute;right: 10px;top: 18px;} .top-right {position: absolute;right: 10px;top: 18px;}
@@ -21,6 +23,10 @@ html, body {background-color: #fff; color: #636b6f; font-family: 'Raleway', sans
</style> </style>
</head> </head>
<body> <body>
<div class="top">
<a href="{:url('/user/index/register')}">注册</a>
<a href="{:url('/user/index/login')}">登录</a>
</div>
<div class="flex-center position-ref full-height"> <div class="flex-center position-ref full-height">
<div class="content"> <div class="content">
<div class="title m-b-md"> <div class="title m-b-md">

View File

@@ -0,0 +1,3 @@
.reg-box, .log-box,.foret-box{margin-top: 30px; padding: 10px; height: 460px; background: #ffffff; border-radius: 4px;}
.reg-box .title, .log-box .title{font-size: 16px; margin: 15px auto; font-weight: bold; border-bottom: 1px solid #dedede; line-height: 35px; padding: 0 10px;}
.foret-box .body-content{width: 480px; margin: 40px auto;}

View File

@@ -6,6 +6,7 @@
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport"> <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
<title>用户中心</title> <title>用户中心</title>
<link rel="stylesheet" type="text/css" href="__static__/common/css/main.css?time={:time()}"> <link rel="stylesheet" type="text/css" href="__static__/common/css/main.css?time={:time()}">
<link rel="stylesheet" type="text/css" href="__css__/style.css?time={:time()}">
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries --> <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// --> <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]> <!--[if lt IE 9]>

View File

@@ -0,0 +1,83 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!-- Tell the browser to be responsive to screen width -->
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
<title>用户中心</title>
<link rel="stylesheet" type="text/css" href="__static__/common/css/main.css?time={:time()}">
<link rel="stylesheet" type="text/css" href="__css__/style.css?time={:time()}">
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="__static__/common/js/html5shiv.js"></script>
<script src="__static__/common/js/respond.min.js"></script>
<![endif]-->
</head>
<body class="hold-transition skin-blue sidebar-mini layout-top-nav">
<div class="wrapper">
<header class="main-header">
<nav class="navbar navbar-static-top">
<div class="container">
<div class="navbar-header">
<a href="{:url('/user/index/index')}" class="navbar-brand"><b>忘记密码</b></a>
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-collapse">
<i class="fa fa-bars"></i>
</button>
</div>
<!-- /.navbar-custom-menu -->
</div>
<!-- /.container-fluid -->
</nav>
</header>
<!-- Full Width Column -->
<div class="content-wrapper">
<div class="container">
<!-- Main content -->
<section class="content">
<div class="foret-box">
<div class="body-content">
<!-- 修改密码表单 -->
<form method="post" class="form-horizontal" role="form">
<div class="form-group">
<label class="col-sm-2 control-label">用户名:</label>
<div class="col-sm-10">
<input type="text" name="username" class="form-control " data-rule="required" autocomplete="off" />
<div class="help-block"></div>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">邮箱:</label>
<div class="col-sm-10">
<input type="text" name="email" class="form-control " data-rule="required;email" autocomplete="off" />
<div class="help-block"></div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-success submit-btn">确认提交</button>
</div>
</div>
</form>
</div>
</div>
</section>
</div>
</div>
<!-- /.content-wrapper -->
<footer class="main-footer">
<div class="pull-right hidden-xs">
<b>Version</b> 4.x
</div>
<strong>Copyright &copy; 2013-2020 <a href="https://www.tensent.cn">SentCMS</a>.</strong> All rights
reserved.
</footer>
</div>
<script type="text/javascript">
var require = {
config: {"site": {$config|json_encode|raw}, 'module': 'admin', 'jsname': "{$require['jsname']|default=''}", 'actionname': "{$require['actionname']|default=''}", }
}
</script>
<script src="__plugins__/require/require.js" data-main="__js__/main.js"></script>
</body>
</html>

View File

@@ -6,6 +6,7 @@
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport"> <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
<title>用户中心</title> <title>用户中心</title>
<link rel="stylesheet" type="text/css" href="__static__/common/css/main.css?time={:time()}"> <link rel="stylesheet" type="text/css" href="__static__/common/css/main.css?time={:time()}">
<link rel="stylesheet" type="text/css" href="__css__/style.css?time={:time()}">
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries --> <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// --> <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]> <!--[if lt IE 9]>
@@ -34,6 +35,35 @@
<div class="container"> <div class="container">
<!-- Main content --> <!-- Main content -->
<section class="content"> <section class="content">
<div class="log-box row">
<div class="col-sm-6"></div>
<div class="col-sm-6">
<h3 class="title">用户登录</h3>
<!-- 修改密码表单 -->
<form method="post" class="form-horizontal" role="form">
<div class="form-group">
<label class="col-sm-2 control-label">用户名:</label>
<div class="col-sm-10">
<input type="text" name="username" class="form-control " data-rule="required" autocomplete="off" />
<div class="help-block"></div>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">密码:</label>
<div class="col-sm-10">
<input type="password" name="password" class="form-control " data-rule="required;password" autocomplete="off" />
<div class="help-block"></div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-7">
<button type="submit" class="btn btn-success submit-btn">确认提交</button>
</div>
<div class="col-sm-3" style="text-align: right;"><a href="{:url('/user/index/forget')}" class="btn btn-link">忘记密码</a></div>
</div>
</form>
</div>
</div>
</section> </section>
</div> </div>
</div> </div>

View File

@@ -6,6 +6,7 @@
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport"> <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
<title>用户中心</title> <title>用户中心</title>
<link rel="stylesheet" type="text/css" href="__static__/common/css/main.css?time={:time()}"> <link rel="stylesheet" type="text/css" href="__static__/common/css/main.css?time={:time()}">
<link rel="stylesheet" type="text/css" href="__css__/style.css?time={:time()}">
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries --> <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// --> <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]> <!--[if lt IE 9]>
@@ -34,6 +35,48 @@
<div class="container"> <div class="container">
<!-- Main content --> <!-- Main content -->
<section class="content"> <section class="content">
<div class="reg-box row">
<div class="col-sm-6"></div>
<div class="col-sm-6">
<h3 class="title">用户注册</h3>
<!-- 修改密码表单 -->
<form method="post" class="form-horizontal" role="form">
<div class="form-group">
<label class="col-sm-2 control-label">用户名:</label>
<div class="col-sm-10">
<input type="text" name="username" class="form-control " data-rule="required" autocomplete="off" />
<div class="help-block"></div>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">密码:</label>
<div class="col-sm-10">
<input type="password" name="password" class="form-control " data-rule="required;password" autocomplete="off" />
<div class="help-block"></div>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">确认密码:</label>
<div class="col-sm-10">
<input type="password" name="repassword" class="form-control " data-rule="required;match(password)" autocomplete="off" />
<div class="help-block"></div>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">邮箱:</label>
<div class="col-sm-10">
<input type="text" name="email" class="form-control " data-rule="required;email" autocomplete="off" />
<div class="help-block"></div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-success submit-btn">确认提交</button>
</div>
</div>
</form>
</div>
</div>
</section> </section>
</div> </div>
</div> </div>

View File

@@ -0,0 +1,83 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!-- Tell the browser to be responsive to screen width -->
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
<title>用户中心</title>
<link rel="stylesheet" type="text/css" href="__static__/common/css/main.css?time={:time()}">
<link rel="stylesheet" type="text/css" href="__css__/style.css?time={:time()}">
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="__static__/common/js/html5shiv.js"></script>
<script src="__static__/common/js/respond.min.js"></script>
<![endif]-->
</head>
<body class="hold-transition skin-blue sidebar-mini layout-top-nav">
<div class="wrapper">
<header class="main-header">
<nav class="navbar navbar-static-top">
<div class="container">
<div class="navbar-header">
<a href="{:url('/user/index/index')}" class="navbar-brand"><b>忘记密码</b></a>
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-collapse">
<i class="fa fa-bars"></i>
</button>
</div>
<!-- /.navbar-custom-menu -->
</div>
<!-- /.container-fluid -->
</nav>
</header>
<!-- Full Width Column -->
<div class="content-wrapper">
<div class="container">
<!-- Main content -->
<section class="content">
<div class="foret-box">
<div class="body-content">
<!-- 修改密码表单 -->
<form method="post" class="form-horizontal" role="form">
<div class="form-group">
<label class="col-sm-3 control-label">新密码:</label>
<div class="col-sm-9">
<input type="password" name="password" class="form-control " data-rule="required;password" autocomplete="off" />
<div class="help-block"></div>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">确认新密码:</label>
<div class="col-sm-9">
<input type="password" name="repassword" class="form-control " data-rule="required;match(password)" autocomplete="off" />
<div class="help-block"></div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<button type="submit" class="btn btn-success submit-btn">确认提交</button>
</div>
</div>
</form>
</div>
</div>
</section>
</div>
</div>
<!-- /.content-wrapper -->
<footer class="main-footer">
<div class="pull-right hidden-xs">
<b>Version</b> 4.x
</div>
<strong>Copyright &copy; 2013-2020 <a href="https://www.tensent.cn">SentCMS</a>.</strong> All rights
reserved.
</footer>
</div>
<script type="text/javascript">
var require = {
config: {"site": {$config|json_encode|raw}, 'module': 'admin', 'jsname': "{$require['jsname']|default=''}", 'actionname': "{$require['actionname']|default=''}", }
}
</script>
<script src="__plugins__/require/require.js" data-main="__js__/main.js"></script>
</body>
</html>

View File

@@ -17,14 +17,14 @@
<div class="form-group"> <div class="form-group">
<label class="col-sm-2 control-label">新密码:</label> <label class="col-sm-2 control-label">新密码:</label>
<div class="col-sm-10"> <div class="col-sm-10">
<input type="password" name="password" class="form-control " data-rule="required" autocomplete="off" /> <input type="password" name="password" class="form-control " data-rule="required;password" autocomplete="off" />
<div class="help-block"></div> <div class="help-block"></div>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="col-sm-2 control-label">确认密码:</label> <label class="col-sm-2 control-label">确认密码:</label>
<div class="col-sm-10"> <div class="col-sm-10">
<input type="password" name="repassword" class="form-control " data-rule="required" autocomplete="off" /> <input type="password" name="repassword" class="form-control " data-rule="required;match(password)" autocomplete="off" />
<div class="help-block"></div> <div class="help-block"></div>
</div> </div>
</div> </div>