安装mockjs
yarn add --dev mockjs
配置mock数据
- 根目录下新建mock文件夹
- mock文件夹下新建index.js, user.js
- index.js
import Mock from 'mockjs'
import { param2Obj } from '@/utils'
import user from './user'
const mocks = [
...user
]
// for front mock
// please use it cautiously, it will redefine XMLHttpRequest,
// which will cause many of your third-party libraries to be invalidated(like progress event).
export function mockXHR() {
// mock patch
// https://github.com/nuysoft/Mock/issues/300
Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send
Mock.XHR.prototype.send = function() {
if (this.custom.xhr) {
this.custom.xhr.withCredentials = this.withCredentials || false
if (this.responseType) {
this.custom.xhr.responseType = this.responseType
}
}
this.proxy_send(...arguments)
}
function XHR2ExpressReqWrap(respond) {
return function(options) {
let result = null
if (respond instanceof Function) {
const { body, type, url } = options
// https://expressjs.com/en/4x/api.html#req
result = respond({
method: type,
body: JSON.parse(body),
query: param2Obj(url)
})
} else {
result = respond
}
return Mock.mock(result)
}
}
for (const i of mocks) {
Mock.mock(new RegExp(i.url), i.type || 'get', XHR2ExpressReqWrap(i.response))
}
}
- user.js
import store from "@/store";
const tokens = {
admin: {
token: "admin-token",
},
editor: {
token: "editor-token",
},
};
const users = {
"admin-token": {
user: {
roles: ["admin"],
introduction: "I am a super administrator",
avatar: "",
username: "Super Admin",
},
system: {},
},
"editor-token": {
user: {
roles: ["editor"],
introduction: "I am an editor",
avatar: "",
username: "Normal Editor",
},
system: {},
},
};
export default [
// user login
{
url: "/admin/login",
type: "post",
response: (config) => {
const { username } = config.body;
const token = tokens[username];
// mock error
if (!token) {
return {
code: 60204,
message: "账号或密码不正确",
};
}
return {
code: 20000,
data: token,
};
},
},
// get user info
{
url: "/admin/userinfo",
type: "get",
response: (config) => {
const token = store.getters.token;
const info = users[token];
// mock error
if (!info) {
return {
code: 50008,
message: "获取用户信息失败",
};
}
return {
code: 20000,
data: info,
};
},
},
// user logout
{
url: "/admin/logout",
type: "post",
response: (_) => {
return {
code: 20000,
data: "success",
};
},
},
];
修改src/main.js, 使用mock
import { createApp } from "vue";
import App from "@/App.vue";
import router from "@/router";
import store from "@/store";
import installElementPlus from "@/plugins/element";
import { mockXHR } from "../mock";
import "@/styles/index.scss";
mockXHR();
const app = createApp(App);
installElementPlus(app);
app.use(router).use(store).mount("#app");
登录状态管理
在store/modules目录下新建user.js
- user.js
import { getToken, setToken, removeToken } from "@/utils/auth";
import { login, logout, getInfo } from "@/api/user";
import { resetRouter } from "@/router";
const getDefaultState = () => {
return {
token: getToken(),
name: "",
avatar: "",
system: {},
};
};
const state = getDefaultState();
const mutations = {
RESET_STATE: (state) => {
Object.assign(state, getDefaultState());
},
SET_TOKEN: (state, token) => {
state.token = token;
},
SET_NAME: (state, name) => {
state.name = name;
},
SET_AVATAR: (state, avatar) => {
state.avatar = avatar;
},
SET_SYSTEM: (state, system) => {
state.system = system;
},
};
const actions = {
login({ commit }, userInfo) {
const { username, password, captcha } = userInfo;
return new Promise((resolve, reject) => {
login({ username: username.trim(), password: password, captcha: captcha })
.then((response) => {
const token = response.data.token;
commit("SET_TOKEN", token);
setToken(token);
resolve();
})
.catch((error) => {
reject(error);
});
});
},
// get user info
getInfo({ commit }) {
return new Promise((resolve, reject) => {
getInfo()
.then((response) => {
const { data } = response;
if (!data) {
reject("获取用户信息失败,请重新登录");
}
const { user, system } = data;
commit("SET_NAME", user.username);
commit("SET_AVATAR", user.avatar);
commit("SET_SYSTEM", system);
resolve(data);
})
.catch((error) => {
reject(error);
});
});
},
// user logout
logout({ commit, state }) {
return new Promise((resolve, reject) => {
logout(state.token)
.then(() => {
removeToken(); // must remove token first
resetRouter();
commit("RESET_STATE");
resolve();
})
.catch((error) => {
reject(error);
});
});
},
// remove token
resetToken({ commit }) {
return new Promise((resolve) => {
removeToken(); // must remove token first
commit("RESET_STATE");
resolve();
});
},
};
export default {
namespaced: true,
state,
mutations,
actions,
};
接口和辅助方法
接口
- 在src目录下新建api文件夹,用来存放接口文件
- api文件夹下新建user.js
- user.js
import request from '@/utils/request'
export function login(data) {
return request({
url: `/login`,
method: 'post',
data
})
}
export function captcha(key) {
return request({
url: `/captcha`,
method: 'get',
params: { key }
})
}
export function getInfo() {
return request({
url: `/userinfo`,
method: 'get',
})
}
export function logout() {
return request({
url: `/logout`,
method: 'post'
})
}
export function autoLogin(data) {
return request({
url: `/signed-login`,
method: 'post',
data
})
}
辅助方法
utils文件夹下新建index.js, auth.js
- auth.js
const TokenKey = 'Admin-Token'
export function getToken() {
return localStorage.getItem(TokenKey)
}
export function setToken(token) {
return localStorage.setItem(TokenKey, token)
}
export function removeToken() {
return localStorage.removeItem(TokenKey)
}
- index.js
/**
* Parse the time to string
* @param {(Object|string|number)} time
* @param {string} cFormat
* @returns {string | null}
*/
export function parseTime(time, cFormat) {
if (arguments.length === 0 || !time) {
return null;
}
const format = cFormat || "{y}-{m}-{d} {h}:{i}:{s}";
let date;
if (typeof time === "object") {
date = time;
} else {
if (typeof time === "string") {
if (/^[0-9]+$/.test(time)) {
// support "1548221490638"
time = parseInt(time);
} else {
// support safari
// https://stackoverflow.com/questions/4310953/invalid-date-in-safari
time = time.replace(new RegExp(/-/gm), "/");
}
}
if (typeof time === "number" && time.toString().length === 10) {
time = time * 1000;
}
date = new Date(time);
}
const formatObj = {
y: date.getFullYear(),
m: date.getMonth() + 1,
d: date.getDate(),
h: date.getHours(),
i: date.getMinutes(),
s: date.getSeconds(),
a: date.getDay(),
};
const time_str = format.replace(/{([ymdhisa])+}/g, (result, key) => {
const value = formatObj[key];
// Note: getDay() returns 0 on Sunday
if (key === "a") {
return ["日", "一", "二", "三", "四", "五", "六"][value];
}
return value.toString().padStart(2, "0");
});
return time_str;
}
/**
* @param {number} time
* @param {string} option
* @returns {string}
*/
export function formatTime(time, option) {
if (("" + time).length === 10) {
time = parseInt(time) * 1000;
} else {
time = +time;
}
const d = new Date(time);
const now = Date.now();
const diff = (now - d) / 1000;
if (diff < 30) {
return "刚刚";
} else if (diff < 3600) {
// less 1 hour
return Math.ceil(diff / 60) + "分钟前";
} else if (diff < 3600 * 24) {
return Math.ceil(diff / 3600) + "小时前";
} else if (diff < 3600 * 24 * 2) {
return "1天前";
}
if (option) {
return parseTime(time, option);
} else {
return (
d.getMonth() +
1 +
"月" +
d.getDate() +
"日" +
d.getHours() +
"时" +
d.getMinutes() +
"分"
);
}
}
/**
* @param {string} url
* @returns {Object}
*/
export function param2Obj(url) {
const search = decodeURIComponent(url.split("?")[1]).replace(/\+/g, " ");
if (!search) {
return {};
}
const obj = {};
const searchArr = search.split("&");
searchArr.forEach((v) => {
const index = v.indexOf("=");
if (index !== -1) {
const name = v.substring(0, index);
const val = v.substring(index + 1, v.length);
obj[name] = val;
}
});
return obj;
}
码云地址: https://gitee.com/ccm-git/vite-element-plus-admin
我的博客:https://www.charmingcheng.top/article/5.html