博客列表 >laravel实战-通用后台管理系统-登录/注销和主界面

laravel实战-通用后台管理系统-登录/注销和主界面

岂几岂几
岂几岂几原创
2020年06月25日 16:32:101127浏览

laravel实战-通用后台管理系统-登录/注销和主界面

1. 登录/注销

1.1 界面布局: 登录框水平垂直居中

  • 使用定位的方式
    • 创建登录框, 指定宽度和高度, 登录框容器为 <body> 的第一个元素, 这样登录框的原始位置就抵住浏览器左边和顶部.
    • 使用 position: absolute 定位, 相对自己原位置定位. 设置偏移登录框原位置的左边50%, 顶部50%; 因为登录框有宽度和高度, 所以使用 margin-left: -登录框宽度的一半margin-top: -登录框高度的一半 , 把登录框再往回退.

代码:

1-登录页 <body> 元素代码片段:

  1. <body style="background: #1E9FFF">
  2. <!-- 1. login-box是<body>的第一个子元素, 它的原始位置是抵住浏览器窗口的左边和顶部 -->
  3. <div class="login-box">
  4. <div class="layui-form">
  5. @CSRF
  6. <div class="layui-form-item">
  7. <span class="title">通用后台管理系统</span>
  8. </div>
  9. <div class="layui-form-item">
  10. <label class="layui-form-label">用户名</label>
  11. <div class="layui-input-inline">
  12. <input type="text" class="layui-input" name="username">
  13. </div>
  14. </div>
  15. <!-- 其他登录表单空间省略... -->
  16. </div>
  17. </div>
  18. </body>

2-水平垂直居中的样式代码片段

  1. /* 2. 设置登录框水平垂直居中 */
  2. .login-box {
  3. /* 相对登录框在文档流中的位置定位, 因为登录框是<body>元素的第一个子元素,
  4. 相当于相对浏览器的左边框和上边框定位 */
  5. position: absolute;
  6. width: 480px;
  7. height: 400px;
  8. /* 偏移浏览器窗口宽度的50% */
  9. left: 50%;
  10. /* 偏移浏览器窗口宽度的50% */
  11. top: 50%;
  12. /* 左外边距设置为"负值的登录框宽度的一半", 这样登录框会向左移动240px */
  13. margin-left: -240px;
  14. /* 上外边距设置为"负值的登录框高度的一半", 这样登录框会向上移动200px */
  15. margin-top: -200px;
  16. background: white;
  17. padding: 10px;
  18. border-radius: 5px;
  19. box-shadow: 5px 5px 20px #444;
  20. }
  • 复习: 设置元素水平垂直居中的其他方式
      1. 使用 margin: 0 auto , 把容器设为水平居中; 再为设置父容器的样式: display: table-cell; vertical-align: middle; , 即把父容器的显示方式设置为表格的单元格, 就能使用 vertical-align 属性设置垂直居中了.
      1. 把父容器设置为 flex 布局, 再设置样式属性: justify-content: center; 实现水平居中; 设置样式属性: align-items: center 实现垂直居中(主轴为水平方向).
      1. 把父容器设置为 grid 布局, 设置样式属性: grid-template-columns: auto 登录框宽度 autogrid-template-rows: auto 登录框高度 auto 把父容器设置为九宫格布局, 其中第5个单元格的宽高跟登录框相同. 为登录框容器设置样式: grid-column-start: 2; grid-column-end: 3; grid-row-start: 2; grid-column-end: 3 把登录框填充到第5个单元格.

1.2 验证码实现

  • 使用 composer 下载 gregwar/captcha 验证码插件.

  • 在图片点击时发送请求获取验证码, 并把服务器返回的验证码图片数据赋给 img.src 属性.

  • 服务器生成验证码后, 把验证码在 session 中也保存一份, 用来跟用户输入的验证码比对.

代码:

1-显示验证码的 <img> 元素:

  1. <img src="" alt="" style="height: 38px; width: 140px; cursor: pointer" onclick="getCaptcha()">

2-异步获取验证码图片数据的js方法

  1. function getCaptcha() {
  2. $.get('/admin/account/captcha?rand=' + Math.random(), null, function(data) {
  3. // 把服务器返回的验证码图片数据设置给img的src属性.
  4. $('img').attr('src', data);
  5. });
  6. }

3-生成验证码的控制器方法

  1. // 生成二维码
  2. public function getCaptcha() {
  3. //生成验证码图片的Builder对象,配置相应属性(4位验证码)
  4. $builder = new CaptchaBuilder(4);
  5. //可以设置图片宽高及字体
  6. $builder->build($width = 100, $height = 40, $font = null);
  7. //获取验证码的内容
  8. $phrase = $builder->getPhrase();
  9. session_start();
  10. //把内容存入session
  11. $_SESSION['captcha'] = $phrase;
  12. // 返回验证码到客户端
  13. echo $builder->inline();
  14. }

4-登录时验证验证码的代码片段

  1. public function doLogin(Request $request) {
  2. // 通过laravel封装的Request对象获取前端封装的数据,当获取不到某个参数值时,会返回null
  3. // 使用$_POST, $_GET, $_REQUEST获取参数值有个缺点, 就是如果获取未定义的key值时,会报错;
  4. $username = $request->username;
  5. $password = $request->password;
  6. // 用户输入的验证码
  7. $vericode = $request->vericode;
  8. // 判断验证码
  9. session_start();
  10. $captcha = $_SESSION['captcha'];
  11. if(strtoupper($vericode) != strtoupper($captcha)) {
  12. exit(json_encode(['status' => 1, 'message' => '验证码输入错误']));
  13. }
  14. // 后续业务处理代码省略...
  15. }

5-路由(略)

1.3 登录认证和注销登录

  • 使用laravel提供的门面类 \Illuminate\Support\Facades\Auth 提供 attempt([用户字段名 => 用户字段值, 密码字段名 => 密码字段值]) 的方法验证登录名和密码.

  • 执行登录验证前要开启session: session_start() ; 登录成功返回json消息时, 要用return返回, 不能用 exit() , 因为后者会无法触发session写入用户信息.

  • 给转到登录页面的路由起名字, 当session过期时, 自动跳转到登录界面. 路由名字要跟登录情况验证中间件\App\Http\Middleware\AuthenticateredirectTo()方法指定的路由名称一致(默认为login).
  • 同样使用 Auth 门面类提供的 logout() 方式实现用户注销.

登录功能代码:
1-登录按钮

  1. <div class="layui-form-item">
  2. <div class="layui-input-block">
  3. <button class="layui-btn" lay-submit lay-filter="formDemo" onclick="doLogin()">立即提交</button>
  4. </div>
  5. </div>

2-提交登录请求的js方法

  1. function doLogin() {
  2. var username = $.trim($('input[name="username"]').val());
  3. var password = $.trim($('input[name="password"]').val());
  4. var vericode = $.trim($('input[name="vericode"]').val());
  5. // laravel token,不带上,laravel会报419错误
  6. var _token = $('input[name="_token"]').val();
  7. if (username == undefined || username == '') {
  8. return layer.alert('请输入用户名', {
  9. icon: 2
  10. });
  11. }
  12. if (password == undefined || password == '') {
  13. return layer.alert('请输入密码', {
  14. icon: 2
  15. });
  16. }
  17. if (vericode == undefined || vericode == '') {
  18. return layer.alert('请输入验证码', {
  19. icon: 2
  20. });
  21. }
  22. var data = {
  23. username: username,
  24. password: password,
  25. vericode: vericode,
  26. _token: _token
  27. };
  28. // 提交登录请求
  29. $.post('/admin/account/doLogin', data, function(data) { //alert(data);return;
  30. var res = JSON.parse(data);
  31. // 登陆失败
  32. if (res.status != undefined && res.status == '1') {
  33. // 提示错误
  34. layer.alert(res.message, {
  35. icon: 2
  36. });
  37. } else if (res.status == '0') { // 登陆成功
  38. layer.msg(res.message, {
  39. icon: 1
  40. });
  41. // 1秒后跳转到主页面
  42. setTimeout(() => {
  43. window.location.href = "/admin/home/index";
  44. }, 1000);
  45. }
  46. });
  47. }

3-后台处理登录验证的控制器方法

  1. public function doLogin(Request $request) {
  2. // 通过laravel封装的Request对象获取前端封装的数据,当获取不到某个参数值时,会返回null
  3. // 使用$_POST, $_GET, $_REQUEST获取参数值有个缺点, 就是如果获取未定义的key值时,会报错;
  4. $username = $request->username;
  5. $password = $request->password;
  6. $vericode = $request->vericode;
  7. // 判断验证码
  8. session_start();
  9. $captcha = $_SESSION['captcha'];
  10. if(strtoupper($vericode) != strtoupper($captcha)) {
  11. exit(json_encode(['status' => 1, 'message' => '验证码输入错误']));
  12. }
  13. // 判空
  14. if($username == null || $username == '') {
  15. exit(json_encode(['status' => 1, 'message' => '用户名不能为空']));
  16. }
  17. if($password == null || $password == '') {
  18. exit(json_encode(['status' => 1, 'message' => '用户名不能为空']));
  19. }
  20. // 查询数据库,校验用户名和密码
  21. // laravel提供的一个用户名和密码的认证工具Auth::attempt--AES加密
  22. if(Auth::attempt(['username' => $username, 'password' => $password])) {
  23. // 注意,这里要用return返回,不要用exit,否则无法触发session写入用户信息的功能
  24. return (json_encode(['status' => 0, 'message' => '登陆成功']));
  25. } else {
  26. exit(json_encode(['status' => 1, 'message' => '账号或密码错误']));
  27. }
  28. }

4-路由

  1. // 后台登录(name()方法: 给路由起名字)
  2. Route::get('/admin/account/login', 'admins\Account@login')->name('login');

注销登录功能代码:

1-执行注销登录的控制器方法

  1. public function logout() {
  2. Auth::logout();
  3. return (json_encode(['status' => 0, 'message' => '登出成功!']));
  4. }

2-注销链接, 路由(略)

2. 主界面

2.1 页面布局

  • 左边栏导航, 整体浮动起来, 一级菜单用layui的手风琴折叠面板, 二级菜单采用layui的垂直/侧边导航的一级导航样式.

  • 内容区容器也浮动起来, 内容区采用内嵌iframe加载功能页面的方式. 页面加载完成, 要重新设置iframe的高度 = 浏览器窗口高度 - 顶部导航高度(50px).

布局代码:
1-左边栏菜单布局

  1. <!-- left menu -->
  2. <div class="left-menu">
  3. <!-- 在父容器加上lay-accordion属性, 就会开启手风琴模式, 打开一个子菜单, 其他菜单的子菜单自动合并 -->
  4. <div class="layui-collapse" lay-accordion style="width: 200px; float:left" lay-accordion>
  5. @foreach($menus as $menu1st)
  6. <!-- 一级菜单 -->
  7. <div class="layui-colla-item">
  8. <h2 class="layui-colla-title">{{$menu1st->title}}</h2>
  9. <!-- 加入.layui-show样式, 就会默认打开子菜单 -->
  10. <div class="layui-colla-content">
  11. <!-- 二级菜单列表 -->
  12. <ul class="layui-nav layui-nav-tree" id="L_demoNav" lay-filter="test">
  13. @foreach($menu1st->childs as $menu2st)
  14. <li class="layui-nav-item">
  15. <!-- controller和method属性分别记录该菜单项对应的控制器名和方法名 -->
  16. <a href="javascript:;" onclick="firemenu(this)" controller="{{$menu2st->controller}}" method="{{$menu2st->action}}">{{$menu2st->title}}</a>
  17. </li>
  18. @endforeach
  19. </ul>
  20. </div>
  21. </div>
  22. @endforeach
  23. </div>
  24. </div>

2-内容区布局

  1. <!-- main -->
  2. <div class="main">
  3. <!-- frameborder="0": 设置后iframe就没有边框了. 提升美观度 -->
  4. <!-- onload: 加载页面完成后要重新设置iframe的高度 -->
  5. <iframe src="/admin/home/welcome" frameborder="0" onload="resetIframeHeight(this)"></iframe>
  6. </div>

3-内容区布局样式: 不给 .main 设置宽高, 使用定位的上下左右属性值, 来设置 .main 容器的大小和位置.

  1. .main {
  2. position: absolute;
  3. /* 距离左边200px */
  4. left: 200px;
  5. /* 距离右边0px, 这样就可以撑满从左边200px到最右边的宽度 */
  6. right: 0px;
  7. top: 50px;
  8. bottom: 0px;
  9. }
  10. .main iframe {
  11. /* .main设置了left和right, 但是iframe并没有充满整个.main的宽度, 所以要设置width:100% */
  12. width: 100%;
  13. height: 100%;
  14. }

4-页面加载完成后重新设置iframe的高度

  1. function resetIframeHeight(iframe) {
  2. // 设置iframe的高度 = 浏览器窗口高度 - 顶部导航高度(50px)
  3. var main_height = document.documentElement.clientHeight - 50;
  4. iframe.style.height = main_height;
  5. }

2.2 用户菜单权限获取和菜单点击后渲染相应页面

  • 查询 admin_menu , admin_group, admin表获取用户菜单权限.

  • 在遍历渲染菜单项时, 给菜单项元素添加自定义属性 controlleraction , 分别赋值为该菜单项对应的控制器名和方法名.

    • 可以扩展 admin_menu 表, 再增加 module 属性和 menu_param 属性, 前者记录控制器所属模块; 后者记录点击该菜单项, 默认发送给后台的参数.
  • 在获取菜单项对应的页面的js方法中, 获取被点击菜单的 controlleraction , 拼成获取对应页面的url.

代码:

1-左侧菜单渲染(见上一节)

2-获取用户菜单权限列表代码片段

  1. public function index(Request $req) {
  2. // 从request对象中取出登录用户的信息(在权限中间件中有设置)
  3. $loginInfo = $req->loginInfo;
  4. $loginRights = $loginInfo->rights;
  5. // 查询出一级菜单列表(加上whereIn, 过滤出登录用户才有的菜单权限)
  6. $data['menus'] = DB::table('admin_menu')->where('pid', 0)->where('ishidden', 0)->where('status', 0)
  7. ->whereIn('mid', $loginRights)
  8. ->orderBy('ord')
  9. ->get()->all();
  10. // 查询二级菜单(加上whereIn, 过滤出登录用户才有的菜单权限)
  11. foreach($data['menus'] as $key => $menu) {
  12. $childs = DB::table('admin_menu')->where('pid', $menu->mid)->where('ishidden', 0)->where('status', 0)
  13. ->whereIn('mid', $loginRights)
  14. ->get()->all();
  15. $menu->childs = $childs;
  16. }
  17. // 其他处理略...
  18. return view('admins/home/index', $data);
  19. }

3-点击后在iframe中渲染相应的页面

  1. // 点击左边栏的菜单处理脚本
  2. function firemenu(obj) {
  3. var controller = $(obj).attr('controller');
  4. var method = $(obj).attr('method');
  5. // iframe中渲染链接到的页面
  6. $('.main iframe').attr('src', '/admin/' + controller + '/' + method);
  7. }

学习心得

  • 设置项目水平垂直居中的方式有多种, 西门老师教的是相对元素在文档流中定位+ margin-left 的方式实现.

  • 使用laravel提供的 Auth 门面类, 可以很方便的实现用户登录验证和注销登录.

  • 让iframe完美的嵌入到父页面中的实现, 很有用, 写下来备查.

声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议