通用后台管理系统前端界面Ⅵ——首页、登录页、404页面

登录页

1、为了方便起见,先将element-ui的使用改为全局引入的方式。修改main.js文件如下:

import Vue from 'vue'
import App from './App.vue'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
//这个是局部引入,前面的文章有讲过
// import '../plugins/element'
import 'font-awesome/css/font-awesome.min.css'
import axios from 'axios'
import router from './router/index'
Vue.config.productionTip = false
Vue.prototype.axios = axios
Vue.use(ElementUI)
new Vue({
  router,
  render: h => h(App),
}).$mount('#app')

2、写登陆页面:

        2.1、components文件夹下新建Login.vue

        2.2、从element-ui官网找需要的组件:+

 

         2.3、修改代码(包括数据和表单绑定)整合后:

<template>
  <div class="login">
    <el-card class="box-card">
      <div slot="header" class="clearfix">
        <span>疫起健康后台管理系统</span>
      </div>
      <el-form
        :model="loginForm"
        ref="loginForm"
        label-width="100px"
      >
        <el-form-item label="用户名" prop="username">
          <el-input
            v-model="loginForm.username"
            autocomplete="off"
          ></el-input>
        </el-form-item>
        <el-form-item label="密码" prop="password">
          <el-input
            type="password"
            v-model="loginForm.password"
            autocomplete="off"
          ></el-input>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="submitForm('loginForm')"
            >登录</el-button>
          <el-button @click="resetForm('loginForm')">重置</el-button>
        </el-form-item>
      </el-form>
    </el-card>
  </div>
</template>

<script>
export default {
  data() {
    return{
        loginForm:{
            username:'',
            password:''
    }
    }
  },
};
</script>

<style lang="scss">
.login{
    width: 100%;
    height: 100%;
    position:absolute;
    background: #88b2dc;
    .box-card{
        width: 450px;
        margin: 160px auto;
        .el-card__header{
            font-size: 34px;
        }
        .el-button{
            width: 30%;
        }
    }
}
</style>

3、修改路由:启动项目(使用重定向)和输入http://localhost/login,进入的页面都是为登录页面 

import Vue from 'vue'
import Router from 'vue-router'
//import Home from '../components/Home.vue'

Vue.use(Router)

export default new Router({
    routes: [
        {
            path: '/',
            // component: Home
            redirect:'/login',
            component: () => import('@/components/Login') //路由懒加载
            //component: resolve => require(['@/components/Home'], resolve) //异步加载
        },
        {
            path: '/login',
            name:'Login',
            component: () => import('@/components/Login') //路由懒加载
            //component: resolve => require(['@/components/Home'], resolve) //异步加载
        },
        {
            path: '/home',
            // component: Home
            component: () => import('@/components/Home') //路由懒加载
            //component: resolve => require(['@/components/Home'], resolve) //异步加载
        }
    ],
    mode: 'history'
})

运行结果:

 4、登录验证

        4.1 简易版,适用于小项目和简单的验证规则,实现:将验证规则直接写在html中

<template>
  <div class="login">
    <el-card class="box-card">
      <div slot="header" class="clearfix">
        <span>疫起健康后台管理系统</span>
      </div>
      <el-form :model="loginForm" ref="loginForm" label-width="100px">
        <el-form-item
          label="用户名"
          prop="username"
          :rules="[
            { required: true, message: '请输入用户名', trigger: 'blur' },
            {
              min: 4,
              max: 10,
              message: '长度在4-10位字符之间',
              trigger: 'blur',
            },
          ]"
        >
          <el-input v-model="loginForm.username" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item
          label="密码"
          prop="password"
          :rules="[
            { required: true, message: '请输入密码', trigger: 'blur' },
            {
              min: 6,
              max: 12,
              message: '长度在6-12位字符之间',
              trigger: 'blur',
            },
          ]"
        >
          <el-input
            type="password"
            v-model="loginForm.password"
            autocomplete="off"
          ></el-input>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="login('loginForm')"
            >登录</el-button
          >
          <el-button @click="resetForm('loginForm')">重置</el-button>
        </el-form-item>
      </el-form>
    </el-card>
  </div>
</template>

当输入框失去焦点时,会自动进行表单校验

         4.2登录验证进阶版 

                ①在表单里绑定rules,直接在Login.vue页面的data中写校验规则,写法参考element-ui的form表单

<template>
  <div class="login">
    <el-card class="box-card">
      <div slot="header" class="clearfix">
        <span>疫起健康后台管理系统</span>
      </div>
      <el-form
        :model="loginForm"
        ref="loginForm"
        label-width="100px"
        :rules="rules"
      >
        <el-form-item label="用户名" prop="username">
          <el-input v-model="loginForm.username" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="密码" prop="password">
          <el-input
            type="password"
            v-model="loginForm.password"
            autocomplete="off"
          ></el-input>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="login('loginForm')">登录</el-button>
          <el-button @click="resetForm('loginForm')">重置</el-button>
        </el-form-item>
      </el-form>
    </el-card>
  </div>
</template>

<script>
export default {
  data() {
    // rule 是校验规则,value是input用户输入的值,callback是回调函数 参考element-ui的api文档
    const validateName = (rule, value, callback) => {
      //   请输入4-10位昵称
      let reg = /(^[a-zA-Z0-9]{4,10}$)/;
      if (value === "") {
        callback(new Error("请输入用户名"));
      } else if (!reg.test(value)) {
        callback(new Error("请输入4-10位用户名"));
      } else {
        callback();
      }
    };
    const validatePass = (rule, value, callback) => {
      //   6-12位密码需要包含大小写字母和数字以及特殊符号
      let pass =
        /^\S*(?=\S{6,12})(?=\S*\d)(?=\S*[A-Z])(?=\S*[a-z])(?=\S*[!@#$%^&*? ])\S*$/;
      if (value === "") {
        callback(new Error("请输入密码"));
      } else if (!pass.test(value)) {
        callback(new Error("6-12位密码需要包含大小写字母和数字及特殊符号"));
      } else {
        callback();
      }
    };
    return {
      loginForm: {
        username: "",
        password: "",
      },
      rules: {
        username: [{ validator: validateName, trigger: "blur" }],
        password: [{ validator: validatePass, trigger: "blur" }],
      },
    };
  },

  methods: {
    login(loginForm) {
      this.$refs[loginForm].validate((valid) => {
        if (valid) {
          console.log(this.loginForm);
        } else {
          console.log(this.loginForm);
        }
      });
    },
    resetForm(loginForm) {
      this.$refs[loginForm].resetFields();
    },
  },
};
</script>

<style lang="scss">
.login {
  width: 100%;
  height: 100%;
  position: absolute;
  background: #88b2dc;
  .box-card {
    width: 450px;
    margin: 160px auto;
    .el-card__header {
      font-size: 34px;
    }
    .el-button {
      width: 30%;
    }
  }
}
</style>

 效果:

小技巧:使用写校验规则插件

 使用:按下f1(我的笔记本需要按下Fn+f1)

                ②在表单里绑定rules,校验规则封装后,再在Login.vue页面导入校验规则(更推荐)

在src下新建utlis文件夹,新建validate.js文件,把Login.vue页面data中的校验规则过来,修改为如下:

// 用户名匹配
export function nameRule(rule, value, callback) {
    //  请输入4-10位昵称
    let reg = /(^[a-zA-Z0-9]{4,10}$)/;
    if (value === "") {
        callback(new Error("请输入用户名"));
    } else if (!reg.test(value)) {
        callback(new Error("请输入4-10位用户名"));
    } else {
        callback();
    }
}

// 密码正则匹配
export function passRule(rule, value, callback) {
    //   6-12位密码需要包含大小写字母和数字以及特殊符号
    let pass = /^\S*(?=\S{6,12})(?=\S*\d)(?=\S*[A-Z])(?=\S*[a-z])(?=\S*[!@#$%^&*? ])\S*$/;
    if (value === "") {
        callback(new Error("请输入密码"));
    } else if (!pass.test(value)) {
        callback(new Error("6-12位密码需要包含大小写字母和数字及特殊符号"));
    } else {
        callback();
    }
}

在Login.vue页面修改为:

<template>
  <div class="login">
    <el-card class="box-card">
      <div slot="header" class="clearfix">
        <span>疫起健康后台管理系统</span>
      </div>
      <el-form
        :model="loginForm"
        ref="loginForm"
        label-width="100px"
        :rules="rules"
      >
        <el-form-item label="用户名" prop="username">
          <el-input v-model="loginForm.username" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="密码" prop="password">
          <el-input
            type="password"
            v-model="loginForm.password"
            autocomplete="off"
          ></el-input>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="login('loginForm')">登录</el-button>
          <el-button @click="resetForm('loginForm')">重置</el-button>
        </el-form-item>
      </el-form>
    </el-card>
  </div>
</template>

<script>
import { nameRule, passRule } from '../utils/validate.js'

export default {
  data() {
    return {
      loginForm: {
        username: "",
        password: "",
      },
      rules: {
        username: [{ validator: nameRule, trigger: "blur" }],
        password: [{ validator: passRule, trigger: "blur" }],
      },
    };
  },

  methods: {
    login(loginForm) {
      this.$refs[loginForm].validate((valid) => {
        if (valid) {
          console.log(this.loginForm);
          this.axios
            .post("http://1.116.64.64:5004/api2/login", this.loginForm)
            .then((res) => {
              console.log(res);
              if (res.data.status === 200) {
                localStorage.setItem("username", res.data.username);
                this.$message({ message: res.data.message, type: "success" });
                this.$router.push("/home");
              }
            })
            .catch((err) => {
              console.error(err);
            });
        } else {
          console.log(this.loginForm);
        }
      });
    },
    resetForm(loginForm) {
      this.$refs[loginForm].resetFields();
    },
  },
};
</script>

<style lang="scss">
.login {
  width: 100%;
  height: 100%;
  position: absolute;
  background: #88b2dc;
  .box-card {
    width: 450px;
    margin: 160px auto;
    .el-card__header {
      font-size: 34px;
    }
    .el-button {
      width: 30%;
    }
  }
}
</style>

效果:

5、登录页面连接后端

第一种

首先:使用mock准备模拟一下网络请求后端接口:

 ① 在vscode终端输入,ctrl+c结束正在运行的项目,再下载mock插件,输入

npm i @shymean/mock-server -g

② 插件安装完成后,然后在磁盘中随便一个地方新建一个文件夹,命名为 mock; 在mock文件里面新建一个mock.js空文件;

在终端进入mock文件夹,输入命令mock,启动本地mock服务器,默认端口为7654

mock>mock server listen at 7654

操作步骤如下图:

 打开mock.js这个文件,自己写一些测试数据如下:

//登录接口
Mock.mock(/login/, {
    code: 200,
    data: {
      access_token: "748_bef_246_test",
      expires_in: 7200,
    }
  })
  
  //用户信息
  Mock.mock(/userInfo/, {
    code: 200,
    user: {
     userName:'admin',
     password:'123456',
     role:'admim',
    }
  })
  

 第二种

找一个自己或别人写好的后端接口,B站有很多,找一下直接用

 封装token

 在utils文件夹下新建setToken.js文件,内容如下:

export function setToken(tokenKey, token) {
    return localStorage.setItem(tokenKey, token)
}

export function getToken(tokenKey) {
    return localStorage.getItem(tokenKey)
}

export function removeToken(tokenKey) {
    return localStorage.removeItem(tokenKey)
}

在Login.vue进行导入使用

<template>
  <div class="login">
    <el-card class="box-card">
      <div slot="header" class="clearfix">
        <span>疫起健康后台管理系统</span>
      </div>
      <el-form
        :model="loginForm"
        ref="loginForm"
        label-width="100px"
        :rules="rules"
      >
        <el-form-item label="用户名" prop="username">
          <el-input v-model="loginForm.username" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="密码" prop="password">
          <el-input
            type="password"
            v-model="loginForm.password"
            autocomplete="off"
          ></el-input>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="login('loginForm')">登录</el-button>
          <el-button @click="resetForm('loginForm')">重置</el-button>
        </el-form-item>
      </el-form>
    </el-card>
  </div>
</template>

<script>
import { nameRule, passRule } from '../utils/validate.js'
import { setToken } from '@/utils/setToken.js'
export default {
  data() {
    return {
      loginForm: {
        username: "",
        password: "",
      },
      rules: {
        username: [{ validator: nameRule, trigger: "blur" }],
        password: [{ validator: passRule, trigger: "blur" }],
      },
    };
  },

  methods: {
    login(loginForm) {
      this.$refs[loginForm].validate((valid) => {
        if (valid) {
          console.log(this.loginForm);
          this.axios
            .post("http://1.116.64.64:5004/api2/login", this.loginForm)
            .then((res) => {
              console.log(res);
              if (res.data.status === 200) {
                // localStorage.setItem("username", res.data.username);
                setToken("username", res.data.username);
                this.$message({ message: res.data.message, type: "success" });
                this.$router.push("/home");
              }
            })
            .catch((err) => {
              console.error(err);
            });
        } else {
          console.log(this.loginForm);
        }
      });
    },
    resetForm(loginForm) {
      this.$refs[loginForm].resetFields();
    },
  },
};
</script>

<style lang="scss">
.login {
  width: 100%;
  height: 100%;
  position: absolute;
  background: #88b2dc;
  .box-card {
    width: 450px;
    margin: 160px auto;
    .el-card__header {
      font-size: 34px;
    }
    .el-button {
      width: 30%;
    }
  }
}
</style>

连接后端登录接口,二次封装axios

 设置项目代理,修改vue.config.js文件如下: 

const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  transpileDependencies: true,
  devServer: {
    open: true,
    host: 'localhost',
    proxy: {
      '/api': {
        target: 'http://1.116.64.64:5004/api2/',
        changeOrigin: true,
        pathRewrite: {
          '^/api': ''
        }
      }

    }
  }
})

项目根目录下新建service.js文件,进行封装axios

import axios from 'axios'
import { getToken } from '@/utils/setToken.js'
import { Message } from 'element-ui'

const service = axios.create({
    baseURL: '/api', // baseURL会自动加在请求地址上
    timeout: 3000
})

// 添加请求拦截器
service.interceptors.request.use((config) => {
    // 在请求之前做些什么(获取并设置token)
    config.headers['token'] = getToken('token')
    return config
}, (error) => {
    return Promise.reject(error)
})

// 添加响应拦截器
service.interceptors.response.use((response) => {
    // 对响应数据做些什么
    let { status, message } = response.data
    if(status !== 200) {
        Message({message: message || 'error', type: 'warning'})
    }
    return response
}, (error) => {
    return Promise.reject(error)
})

export default service

使用二次封装的axios,依旧采用全局导入的方式,修改main.js文件如下:

import Vue from 'vue'
import App from './App.vue'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
// import '../plugins/element'
import 'font-awesome/css/font-awesome.min.css'
// import axios from 'axios'
import service from '../service'
import router from './router/index'
//或者这样导入:会自动找到index文件
//import router from './router'
Vue.config.productionTip = false
// Vue.prototype.axios = axios
Vue.prototype.service = service
Vue.use(ElementUI)
new Vue({
  router,
  render: h => h(App),
}).$mount('#app')

修改Login.vue页面,注释掉引入的setToken文件

<template>
  <div class="login">
    <el-card class="box-card">
      <div slot="header" class="clearfix">
        <span>疫起健康后台管理系统</span>
      </div>
      <el-form
        :model="loginForm"
        ref="loginForm"
        label-width="100px"
        :rules="rules"
      >
        <el-form-item label="用户名" prop="username">
          <el-input v-model="loginForm.username" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="密码" prop="password">
          <el-input
            type="password"
            v-model="loginForm.password"
            autocomplete="off"
          ></el-input>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="login('loginForm')">登录</el-button>
          <el-button @click="resetForm('loginForm')">重置</el-button>
        </el-form-item>
      </el-form>
    </el-card>
  </div>
</template>

<script>
import { nameRule, passRule } from '../utils/validate.js'
// import { setToken } from '@/utils/setToken.js'
export default {
  data() {
    return {
      loginForm: {
        username: "",
        password: "",
      },
      rules: {
        username: [{ validator: nameRule, trigger: "blur" }],
        password: [{ validator: passRule, trigger: "blur" }],
      },
    };
  },

  methods: {
    login(loginForm) {
      this.$refs[loginForm].validate((valid) => {
        if (valid) {
          console.log(this.loginForm);
          this.service.post('/login',this.loginForm)
            .then((res) => {
                console.log(res.data)
            }) 
          } else {
          console.log(this.loginForm);
        }
      });
    },
    resetForm(loginForm) {
      this.$refs[loginForm].resetFields();
    },
  },
};
</script>

<style lang="scss">
.login {
  width: 100%;
  height: 100%;
  position: absolute;
  background: #88b2dc;
  .box-card {
    width: 450px;
    margin: 160px auto;
    .el-card__header {
      font-size: 34px;
    }
    .el-button {
      width: 30%;
    }
  }
}
</style>

ctrl+c关掉当前运行的项目,重新新建终端输入:npm run serve,修改了vue.config.js文件一定要重启项目,配置才会生效,再进行接口测试,否则会报错如下:访问的依旧是localhhost:8080端口

如果重启服务还是没有用,那就再一一排查一下语法,拼写是否有误或者漏掉,以下为我调试过程发现的:

 axios封装分析(其实还可以更完善:axios发送的数据不能是对象,只能是字符串的形式,所以可以使用统一的工具类对axios发送请求的数据进行处理;以此类推,接收返回的请求,可以通过判断不同的状态码,进行不同的处理(500服务器内部错误、404访问地址不存在等)参考博文):

 测试结果:

 接下来是康康想一下,接口返回的数据,除了token还有什么是要存起来的===》username===》当登录成功,进入系统首页,需要显示用户名,所以:修改Login.vue页面的login方法为下:

login(loginForm) {
      this.$refs[loginForm].validate((valid) => {
        if (valid) {
          console.log(this.loginForm);
          this.service.post('/login',this.loginForm)
          .then((res) => {
                if (res.data.status === 200) {
                    setToken('username', res.data.username)
                    setToken('token', res.data.token)
                    this.$message({message: res.data.message, type: 'success'})
                    this.$router.push('/home')
                }
            }) 
          } else {
          console.log(this.loginForm);
        }
      });
    },

做到这一步,发现代码没问题,但是为了方便后续项目整理和维护,管理接口和方法,∴把登录方法可以再封装成api进行调用:

        在src下,新建api文件夹,新建api.js文件

// 把对应的接口请求封装成api来调用
import service from '../service.js'

// 登录接口
export function login(data) {
    return service({
        method: 'post',
        url: '/login',
        data
    })
}

 在Login.vue页面进行使用:

 404页面

 在项目中准备好静态资源:

在components下新建NotFound.vue

<template>
    <div class="notfound">
      <div class="wrapper">
          <div class="big">页面不见了!</div>
          <div>首页瞧瞧,点击<router-link to="/">这里</router-link>进入首页.</div>
      </div>
    </div>
  </template>
  
  <script>
  export default {
    data() {
      return {};
    },
  };
  </script>
  
  <style>
  .notfound {
    height: 100%;
    background-image: url('../assets/img/astronauta.jpg'), url('../assets/img/stars404.png');
    background-position: right top, center center;
    background-repeat: no-repeat, repeat;
    background-size: cover, auto;
  }
  .notfound .wrapper {
    position: absolute;
    top: 60%;
    right: 2%;
    color: #fff;
    width: 635px;
    font-size: 19px;
    line-height: 29px;
    -webkit-font-smoothing: antialiased;
    padding: 20px;
    font-family: 'Source Sans Pro', sans-serif;
  }
  .notfound .wrapper .big {
    font-size: 74px;
    font-weight: 700;
    line-height: 68px;
    margin-bottom: 48px;
  }
  .notfound .wrapper a {
    color: #ffcc00;
    text-decoration: none;
    font-weight: 700;
    cursor: pointer;
  }
  @media only screen and (max-width: 666px) {
    .notfound .wrapper {
      left: auto;
      right: 0;
      width: 100%;
      max-width: 450px;
      top: 35%;
    }
    .notfound .wrapper .big {
      font-size: 42px;
      line-height: 50px;
      margin-bottom: 15px;
    }
  }
  </style>

 配置路由

 效果:

 分析:

猜你喜欢

转载自blog.csdn.net/qq_45947664/article/details/127910950