02 基于vue2的通用后台管理系统实现方案-登录页面

封装requests方法

统一错误处理

npm i axios 
npm nprogress

参考封装
https://blog.csdn.net/a5120184120/article/details/132590955
# utils/request.js
// axios二次封装
// 设置baseURL和timeout
// 在请求拦截器中封装token鉴权
// 在响应拦截器中对数据过滤处理
// 在响应拦截器中http错误状态码进行判断等

//要npm i
import axios from "axios";
import "nprogress/nprogress.css";
// 引入进度条
import nprogress from "nprogress";

import { Message } from "element-ui";
import router from "@/router";

// // 通过全局配置文件载入变量,并根据当前环境 载入变量的值
// axios.defaults.baseURL = process.env.VUE_APP_Server;

// console.log("VUE_APP_Server", process.env.VUE_APP_Server);

// 创建axios新实例
const axiosInstance = axios.create({
  // baseURL: "https://blog.csdn.net/", //接口根地址
  timeout: 3000, //超时时间
});

/**
 * 请求拦截器
 */
axiosInstance.interceptors.request.use(
  (config) => {
    // 进度条开始
    nprogress.start();

    // 封装token鉴权
    const token = localStorage.getItem("Token");
    if (token) {
      config.headers["Authorization"] = token;
    }
    return config;
  },
  (err) => Promise.reject(err)
);

/**
 * 响应拦截器
 */
axiosInstance.interceptors.response.use(
  (res) => {
    // 进度条结束
    nprogress.done();
    // 过滤数据
    return res.data;
  },
  (err) => {
    // 进度条结束
    nprogress.done();
    const { response } = err;
    if (response) {
      const status = response.status;
      switch (status) {
        case 404:
          Message.error("资源不存在 404");
          break;
        case 403:
          Message.error("拒绝访问 403");
          router.push("/login");
          break;
        case 401:
          Message.error("身份凭证确实 401");
          router.push("/login");
          break;
        case 500:
          Message.error("服务器错误 500");
          break;
        default:
          Message.error("出现意想不到的错误");
          break;
      }
    } else {
      // 服务器崩溃问题或是网络问题
      if (!window.navigator.onLine) {
        Message.error("当前网络不可用,请检查你的网络连接");
        return;
      } else {
        Message.error("连接服务器错误" + err?.message);
        return Promise.reject(err);
      }
    }
    return Promise.reject(err);
  }
);

export default axiosInstance;



调用http请求封装

# src/apis/user.js

import request from "@/utils/request";

// 测试
export const testApi = (data) => request.post("/api/test", data);

// 注册
export const regApi = (data) => request.post("/api/reg", data);

// 登录
export const loginApi = (data) => request.post("/api/login", data);

mock模拟数据

# 调用mockServe
#main.js

import Vue from "vue";

import "../mock/mockServe";

import "reset-css";
import App from "./App.vue";
import router from "./router";
import store from "./store";
import "./plugins/element.js";

Vue.config.productionTip = false;

new Vue({
  router,
  store,
  render: (h) => h(App),
}).$mount("#app");


#mock/mockServe.js
import "./user.js";

#mock/user.js
import Mock from "mockjs";

// // 拦截接口,返回mock快速生成批量数据
// Mock.mock("/users/list", "get", {
//   code: 0,
//   msg: "获取成功",
//   data: {
//     // 生成十个如下格式的数据
//     "list|10": [
//       {
//         "id|+1": 1, // 数字从当前数开始依次 +1
//         "age|18-40": 20, // 年龄为18-40之间的随机数字
//         "sex|1": ["男", "女"], // 性别是数组中随机的一个
//         name: "@cname", // 名字为随机中文名字
//         email: "@email", // 随机邮箱
//         isShow: "@boolean", // 随机获取boolean值
//       },
//     ],
//   },
// });

Mock.mock("/api/users", "get", {
  success: true,
  data: [
    { id: 1, name: "John Doe" },
    { id: 2, name: "Jane Smith" },
  ],
});

// 模拟后台登录逻辑
Mock.mock("/api/login", "post", (params) => {
  // console.log(params);
  let loginData = JSON.parse(params.body);
  if (loginData.username !== "admin") {
    return {
      code: 400,
      msg: "用户名错误",
      data: {
        token: "1111111111122",
        userinfo: { id: 2, name: "Jane Smith" },
      },
    };
  }

  if (loginData.pass !== "123456") {
    return {
      code: 200,
      msg: "密码错误",
      data: null,
    };
  }

  if (loginData.code !== "1234") {
    return {
      code: 200,
      msg: "验证码错误",
      data: null,
    };
  }

  return {
    code: 200,
    msg: "登录成功",
    data: {
      token: "1111111111122",
      userinfo: { id: 2, name: "Jane Smith" },
    },
  };
});

// 模拟后台注册逻辑
Mock.mock("/api/reg", "post", (params) => {
  // console.log(params);
  let loginData = JSON.parse(params.body);
  if (loginData.username === "admin") {
    return {
      code: 400,
      msg: "用户已存在",
      data: null,
    };
  }

  return {
    code: 200,
    msg: "注册成功",
    data: null,
  };
});


封装validate.js

#utils/validate.js

export const validateUsername = (rule, value, callback) => {
  if (value.length < 3 || value.length > 20) {
    callback(new Error("用户名必须在3到20位字符内"));
  } else {
    callback();
  }
  console.log(value.length);
};

创建登录页面

# views/LoginView.vue
<template>
  <div class="login-page">
    <div class="login-box">
      <h3>用户登录</h3>
      <el-form
        :model="loginForm"
        status-icon
        :rules="loginFormRules"
        ref="loginForm"
        label-width="70px"
        class="demo-loginForm"
      >
        <el-form-item label="用户名" prop="username">
          <el-input
            type="text"
            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 label="验证码" prop="verifyCode">
          <div class="verify-code">
            <el-input
              type="text"
              v-model="loginForm.verifyCode"
              autocomplete="off"
              placeholder="验证码"
            ></el-input>
            <img src="../assets/imgs/verify-code.png" alt="verifyCode" />
          </div>
        </el-form-item>

        <div>
          <el-button type="primary" @click="submitForm('loginForm')"
            >登录</el-button
          >
        </div>
      </el-form>
      <div>
        <el-button @click="$router.push('/reg')" type="text"
          >注册用户</el-button
        >
      </div>

      <!-- <button @click="test">测试按钮</button> -->
    </div>
  </div>
</template>

<script>
import { validateUsername } from "@/utils/validate";
import { loginApi } from "@/apis/user";
// import { testApi } from "@/apis/user";

export default {
  name: "LoginView",

  data() {
    return {
      loginFormRules: {
        username: [
          //   { required: true, message: "请输入用户名", trigger: "blur" },
          { validator: validateUsername, trigger: "blur" },
        ],
        password: [{ required: true, message: "请输入密码", trigger: "blur" }],
        verifyCode: [
          { required: true, message: "请输入验证码", trigger: "blur" },
        ],
      },
      loginForm: {
        username: "admin",
        password: "123456",
        verifyCode: "1234",
      },
    };
  },

  mounted() {},

  methods: {
    // test() {
    //   testApi().then((data) => {
    //     console.log(data);
    //   });
    // },
    submitForm(formName) {
      this.$refs[formName].validate(async (valid) => {
        if (valid) {
          // 异步等待实现,只处理成功
          const res = await loginApi({
            username: this.loginForm.username,
            pass: this.loginForm.password,
            code: this.loginForm.verifyCode,
          });
          // console.log("res");
          if (res.code === 200 && res.data && res.data.token) {
            localStorage.setItem("Token", res.data.token);
            this.$message({
              message: "登录成功",
              type: "success",
            });
            // 跳转到后台主页面
            this.$router.push("/main");
          } else {
            let msg = res.msg || "登录失败";
            this.$message({
              message: msg,
              type: "error",
            });
          }
          // console.log("valid");
          // // 异步实现
          // loginApi({
          //   username: this.loginForm.username,
          //   pass: this.loginForm.password,
          //   code: this.loginForm.verifyCode,
          // })
          //   .then((res) => {
          //     console.log("res");
          //     if (res.code === 200 && res.data && res.data.token) {
          //       localStorage.setItem("Token", res.data.token);
          //       this.$message({
          //         message: "登录成功",
          //         type: "success",
          //       });
          //     } else {
          //       this.$message({
          //         message: "登录失败",
          //         type: "error",
          //       });
          //     }
          //   })
          //   .catch(() => {
          //     console.log("err");
          //   });
          // console.log("valid");
        } else {
          // console.log("error submit!!");
          // this.$message({
          //   message: "表单输入内容有误",
          //   type: "error",
          // });
          return false;
        }
      });
    },
  },
};
</script>

<style lang="scss" scoped>
.login-page {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100vh;
  background-size: cover;
  background-position: right center;
  background-repeat: no-repeat;
  background: url(../assets/imgs/bg.jpg);
}
.login-box {
  padding: 40px 20px;
  background-color: white;
  width: 400px;
  border-radius: 15px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.5);
  h3 {
    text-align: center;
    font-size: 28px;
    margin-bottom: 20px;
  }
  .el-button {
    width: 100%;
    margin-top: 30px;
  }
  .verify-code {
    display: flex;
    align-items: center;
    justify-content: center;
    img {
      height: 40px;
      margin-left: 10px;
      //   height: 40px;
    }
  }
}
</style>


创建注册页面

<template>
  <div class="reg-page">
    <div class="reg-box">
      <h3>用户注册</h3>
      <el-form
        :model="regForm"
        status-icon
        :rules="regFormRules"
        ref="regForm"
        class="demo-regForm"
      >
        <el-form-item label="用户名" prop="username">
          <el-input
            type="text"
            v-model="regForm.username"
            autocomplete="off"
          ></el-input>
        </el-form-item>
        <el-form-item label="密码" prop="password">
          <el-input
            type="password"
            v-model="regForm.password"
            autocomplete="off"
          ></el-input>
        </el-form-item>
        <el-form-item label="确认密码" prop="checkPass">
          <el-input
            type="password"
            v-model="regForm.checkPass"
            autocomplete="off"
          ></el-input>
        </el-form-item>

        <el-form-item>
          <el-button type="primary" @click="submitForm('regForm')"
            >注册</el-button
          >
        </el-form-item>
      </el-form>
      <div>
        <el-button @click="$router.push('/login')" type="text"
          >返回登录</el-button
        >
      </div>
    </div>
  </div>
</template>

<script>
import { regApi } from "@/apis/user";
export default {
  name: "RegView",

  data() {
    var validateCheckPass = (rule, value, callback) => {
      if (value !== this.regForm.password) {
        callback(new Error("两次输入密码不一致!"));
      } else {
        callback();
      }
    };

    return {
      regFormRules: {
        username: [
          { required: true, message: "请输入用户名", trigger: "blur" },
        ],
        password: [{ required: true, message: "请输入密码", trigger: "blur" }],
        checkPass: [
          { required: true, message: "请输入确认密码", trigger: "blur" },
          {
            validator: validateCheckPass,
            message: "确认密码不正确",
            trigger: "blur",
          },
        ],
      },
      regForm: {
        username: "admin",
        password: "123456",
        checkPass: "123456",
      },
    };
  },

  mounted() {},

  methods: {
    submitForm(formName) {
      this.$refs[formName].validate(async (valid) => {
        if (valid) {
          const res = await regApi({
            username: this.regForm.username,
            pass: this.regForm.password,
            checkPass: this.regForm.checkPass,
          });

          if (res.code === 200) {
            this.$message({
              type: "success",
              message: "注册成功",
            });
            this.$router.push("/login");
          } else {
            let msg = res.msg || "注册失败";
            this.$message({
              message: msg,
              type: "error",
            });
          }
        } else {
          // 客户端验证未通过
          return false;
        }
      });
    },
  },
};
</script>

<style lang="scss" scoped>
.reg-page {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100vh;
  background-size: cover;
  background-position: right center;
  background-repeat: no-repeat;
  background: url(../assets/imgs/bg.jpg);
}
.reg-box {
  padding: 20px;
  background-color: white;
  width: 400px;
  border-radius: 15px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.5);
  h3 {
    text-align: center;
    font-size: 28px;
    margin-bottom: 20px;
  }
  .el-button {
    width: 100%;
  }
}
</style>

后台框架页

#views/MainView.vue

<template>
  <div>后台页面</div>
</template>

<script>
export default {
  name: "MainView",

  data() {
    return {};
  },

  mounted() {},

  methods: {},
};
</script>

<style lang="scss" scoped></style>

配置路由

import Vue from "vue";
import VueRouter from "vue-router";
import HomeView from "../views/HomeView.vue";
import LoginView from "../views/LoginView.vue";
import RegView from "../views/RegView.vue";

Vue.use(VueRouter);

const routes = [
  {
    path: "/test",
    name: "test",
    component: () =>
      import(/* webpackChunkName: "test" */ "../views/TestView.vue"),
  },
  {
    path: "/main",
    name: "main",
    component: () =>
      import(/* webpackChunkName: "main" */ "../views/MainView.vue"),
  },
  {
    path: "/reg",
    name: "reg",
    component: RegView,
  },
  {
    path: "/login",
    name: "login",
    component: LoginView,
  },
  {
    path: "/",
    name: "home",
    component: HomeView,
  },
  {
    path: "/about",
    name: "about",
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () =>
      import(/* webpackChunkName: "about" */ "../views/AboutView.vue"),
  },
];

const router = new VueRouter({
  mode: "history",
  base: process.env.BASE_URL,
  routes,
});

export default router;

可以设置代理服务器

# 未验证
  // devServer: {
  //   proxy: {
  //     "/api": {
  //       //接口地址 以 api开头的都走下面的配置
  //       target: "http://127.0.0.1:5000", //代理目标地址为后端服务器地址
  //       ws: true, //是否支持 websocket 请求 支持
  //       changeOrigin: true, //是否启用跨域
  //       pathRewrite: {
  //         "^/api": "", //发送请求时自动去掉开头
  //       },
  //     },
  //   },
  // },

# 不同环境设置不同环境变量
# .env.development文件
NODE_ENV='development'
VUE_APP_Server= '/api'

# .env.production文件
NODE_ENV='production'
VUE_APP_Server= 'http://115.159.153.85:5000'
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值