refactor(login): 适配后端登录接口

This commit is contained in:
snape 2024-03-26 13:47:24 +08:00
parent fda66ee37c
commit ee77d5c917
17 changed files with 64 additions and 127 deletions

2
.env
View File

@ -1,5 +1,5 @@
# 平台本地运行端口号
VITE_PORT = 8848
VITE_PORT = 10086
# 是否隐藏首页 隐藏 true 不隐藏 false 勿删除VITE_HIDE_HOME只需在.env文件配置
VITE_HIDE_HOME = false

View File

@ -1,5 +1,5 @@
# 平台本地运行端口号
VITE_PORT = 8848
VITE_PORT = 10086
# 开发环境读取配置文件路径
VITE_PUBLIC_PATH = /

View File

@ -10,7 +10,7 @@ import { visualizer } from "rollup-plugin-visualizer";
import removeConsole from "vite-plugin-remove-console";
import { themePreprocessorPlugin } from "@pureadmin/theme";
import { genScssMultipleScopeVars } from "../src/layout/theme";
import { vitePluginFakeServer } from "vite-plugin-fake-server";
// import { vitePluginFakeServer } from "vite-plugin-fake-server";
export function getPluginsList(
VITE_CDN: boolean,
@ -29,12 +29,12 @@ export function getPluginsList(
*/
removeNoMatch(),
// mock支持
vitePluginFakeServer({
logger: false,
include: "mock",
infixName: false,
enableProd: true
}),
// vitePluginFakeServer({
// logger: false,
// include: "mock",
// infixName: false,
// enableProd: true
// }),
// 自定义主题
themePreprocessorPlugin({
scss: {

View File

@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="en">
<!doctype html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />

View File

@ -1,6 +1,6 @@
{
"Version": "5.2.0",
"Title": "PureAdmin",
"Version": "1.0.1",
"Title": "电力配餐后台管理系统",
"FixedHeader": true,
"HiddenSideBar": false,
"MultiTagsCache": false,

View File

@ -1,4 +1,5 @@
import { http } from "@/utils/http";
import { baseUrlApi } from "@/api/utils";
type Result = {
success: boolean;
@ -6,5 +7,8 @@ type Result = {
};
export const getAsyncRoutes = () => {
return http.request<Result>("get", "/get-async-routes");
return http.request<Result>(
"get",
baseUrlApi("api/v1/user/manage/getRoutes")
);
};

View File

@ -1,4 +1,5 @@
import { http } from "@/utils/http";
import { baseUrlApi } from "@/api/utils";
export type UserResult = {
success: boolean;
@ -8,32 +9,13 @@ export type UserResult = {
/** 当前登陆用户的角色 */
roles: Array<string>;
/** `token` */
accessToken: string;
/** 用于调用刷新`accessToken`的接口时所需的`token` */
refreshToken: string;
/** `accessToken`的过期时间(格式'xxxx/xx/xx xx:xx:xx' */
expires: Date;
};
};
export type RefreshTokenResult = {
success: boolean;
data: {
/** `token` */
accessToken: string;
/** 用于调用刷新`accessToken`的接口时所需的`token` */
refreshToken: string;
/** `accessToken`的过期时间(格式'xxxx/xx/xx xx:xx:xx' */
expires: Date;
access_token: string;
};
};
/** 登录 */
export const getLogin = (data?: object) => {
return http.request<UserResult>("post", "/login", { data });
};
/** 刷新token */
export const refreshTokenApi = (data?: object) => {
return http.request<RefreshTokenResult>("post", "/refresh-token", { data });
return http.request<UserResult>("post", baseUrlApi("api/v1/auth/login"), {
data
});
};

1
src/api/utils.ts Normal file
View File

@ -0,0 +1 @@
export const baseUrlApi = (url: string) => `/dev-api/${url}`;

View File

@ -29,7 +29,7 @@ const { title, getLogo } = useNav();
class="sidebar-logo-link"
:to="getTopMenu()?.path ?? '/'"
>
<img :src="getLogo()" alt="logo" />
<!-- <img :src="getLogo()" alt="logo" /> -->
<span class="sidebar-title">{{ title }}</span>
</router-link>
</transition>

View File

@ -113,7 +113,7 @@ router.beforeEach((to: ToRouteType, _from, next) => {
handleAliveRoute(to);
}
}
const userInfo = storageLocal().getItem<DataInfo<number>>(userKey);
const userInfo = storageLocal().getItem<DataInfo>(userKey);
NProgress.start();
const externalLink = isUrl(to?.name as string);
if (!externalLink) {

View File

@ -3,7 +3,7 @@ export default {
redirect: "/error/403",
meta: {
icon: "ri:information-line",
// showLink: false,
showLink: false,
title: "异常页面",
rank: 9
},

View File

@ -83,8 +83,7 @@ function isOneOfArray(a: Array<string>, b: Array<string>) {
/** 从localStorage里取出当前登陆用户的角色roles过滤无权限的菜单 */
function filterNoPermissionTree(data: RouteComponent[]) {
const currentRoles =
storageLocal().getItem<DataInfo<number>>(userKey)?.roles ?? [];
const currentRoles = storageLocal().getItem<DataInfo>(userKey)?.roles ?? [];
const newTree = cloneDeep(data).filter((v: any) =>
isOneOfArray(v.meta?.roles, currentRoles)
);

View File

@ -4,8 +4,8 @@ import type { userType } from "./types";
import { routerArrays } from "@/layout/types";
import { router, resetRouter } from "@/router";
import { storageLocal } from "@pureadmin/utils";
import { getLogin, refreshTokenApi } from "@/api/user";
import type { UserResult, RefreshTokenResult } from "@/api/user";
import { getLogin } from "@/api/user";
import type { UserResult } from "@/api/user";
import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
import { type DataInfo, setToken, removeToken, userKey } from "@/utils/auth";
@ -13,9 +13,9 @@ export const useUserStore = defineStore({
id: "pure-user",
state: (): userType => ({
// 用户名
username: storageLocal().getItem<DataInfo<number>>(userKey)?.username ?? "",
username: storageLocal().getItem<DataInfo>(userKey)?.username ?? "",
// 页面级别权限
roles: storageLocal().getItem<DataInfo<number>>(userKey)?.roles ?? [],
roles: storageLocal().getItem<DataInfo>(userKey)?.roles ?? [],
// 是否勾选了登录页的免登录
isRemembered: false,
// 登录页的免登录存储几天默认7天
@ -39,7 +39,7 @@ export const useUserStore = defineStore({
this.loginDay = Number(value);
},
/** 登入 */
async loginByUsername(data) {
async loginByUsername(data: object) {
return new Promise<UserResult>((resolve, reject) => {
getLogin(data)
.then(data => {
@ -61,21 +61,6 @@ export const useUserStore = defineStore({
useMultiTagsStoreHook().handleTags("equal", [...routerArrays]);
resetRouter();
router.push("/login");
},
/** 刷新`token` */
async handRefreshToken(data) {
return new Promise<RefreshTokenResult>((resolve, reject) => {
refreshTokenApi(data)
.then(data => {
if (data) {
setToken(data.data);
resolve(data);
}
})
.catch(error => {
reject(error);
});
});
}
}
});

View File

@ -2,13 +2,9 @@ import Cookies from "js-cookie";
import { storageLocal } from "@pureadmin/utils";
import { useUserStoreHook } from "@/store/modules/user";
export interface DataInfo<T> {
export interface DataInfo {
/** token */
accessToken: string;
/** `accessToken`的过期时间(时间戳) */
expires: T;
/** 用于调用刷新accessToken的接口时所需的token */
refreshToken: string;
access_token: string;
/** 用户名 */
username?: string;
/** 当前登陆用户的角色 */
@ -16,7 +12,7 @@ export interface DataInfo<T> {
}
export const userKey = "user-info";
export const TokenKey = "authorized-token";
export const TokenKey = "Authorization";
/**
* `multiple-tabs``cookie`
*
@ -26,7 +22,7 @@ export const TokenKey = "authorized-token";
export const multipleTabsKey = "multiple-tabs";
/** 获取`token` */
export function getToken(): DataInfo<number> {
export function getToken(): DataInfo {
// 此处与`TokenKey`相同,此写法解决初始化时`Cookies`中不存在`TokenKey`报错
return Cookies.get(TokenKey)
? JSON.parse(Cookies.get(TokenKey))
@ -39,35 +35,17 @@ export function getToken(): DataInfo<number> {
* `accessToken``expires`key值为authorized-token的cookie里
* `username``roles``refreshToken``expires`key值为`user-info`localStorage里`multipleTabsKey`
*/
export function setToken(data: DataInfo<Date>) {
let expires = 0;
const { accessToken, refreshToken } = data;
const { isRemembered, loginDay } = useUserStoreHook();
expires = new Date(data.expires).getTime(); // 如果后端直接设置时间戳将此处代码改为expires = data.expires然后把上面的DataInfo<Date>改成DataInfo<number>即可
const cookieString = JSON.stringify({ accessToken, expires });
export function setToken(data: DataInfo) {
const { access_token } = data;
const cookieString = JSON.stringify({ access_token });
Cookies.set(TokenKey, cookieString);
expires > 0
? Cookies.set(TokenKey, cookieString, {
expires: (expires - Date.now()) / 86400000
})
: Cookies.set(TokenKey, cookieString);
Cookies.set(
multipleTabsKey,
"true",
isRemembered
? {
expires: loginDay
}
: {}
);
Cookies.set(multipleTabsKey, "true");
function setUserKey(username: string, roles: Array<string>) {
useUserStoreHook().SET_USERNAME(username);
useUserStoreHook().SET_ROLES(roles);
storageLocal().setItem(userKey, {
refreshToken,
expires,
username,
roles
});
@ -77,10 +55,8 @@ export function setToken(data: DataInfo<Date>) {
const { username, roles } = data;
setUserKey(username, roles);
} else {
const username =
storageLocal().getItem<DataInfo<number>>(userKey)?.username ?? "";
const roles =
storageLocal().getItem<DataInfo<number>>(userKey)?.roles ?? [];
const username = storageLocal().getItem<DataInfo>(userKey)?.username ?? "";
const roles = storageLocal().getItem<DataInfo>(userKey)?.roles ?? [];
setUserKey(username, roles);
}
}

View File

@ -12,7 +12,6 @@ import type {
import { stringify } from "qs";
import NProgress from "../progress";
import { getToken, formatToken } from "@/utils/auth";
import { useUserStoreHook } from "@/store/modules/user";
// 相关配置请参考www.axios-js.com/zh-cn/docs/#axios-request-config-1
const defaultConfig: AxiosRequestConfig = {
@ -79,31 +78,10 @@ class PureHttp {
: new Promise(resolve => {
const data = getToken();
if (data) {
const now = new Date().getTime();
const expired = parseInt(data.expires) - now <= 0;
if (expired) {
if (!PureHttp.isRefreshing) {
PureHttp.isRefreshing = true;
// token过期刷新
useUserStoreHook()
.handRefreshToken({ refreshToken: data.refreshToken })
.then(res => {
const token = res.data.accessToken;
config.headers["Authorization"] = formatToken(token);
PureHttp.requests.forEach(cb => cb(token));
PureHttp.requests = [];
})
.finally(() => {
PureHttp.isRefreshing = false;
});
}
resolve(PureHttp.retryOriginalRequest(config));
} else {
config.headers["Authorization"] = formatToken(
data.accessToken
data.access_token
);
resolve(config);
}
} else {
resolve(config);
}

View File

@ -33,8 +33,9 @@ dataThemeChange();
const { title } = useNav();
const ruleForm = reactive({
username: "admin",
password: "admin123"
grantType: "WEB",
username: "",
password: ""
});
const onLogin = async (formEl: FormInstance | undefined) => {
@ -43,7 +44,11 @@ const onLogin = async (formEl: FormInstance | undefined) => {
await formEl.validate((valid, fields) => {
if (valid) {
useUserStoreHook()
.loginByUsername({ username: ruleForm.username, password: "admin123" })
.loginByUsername({
grantType: ruleForm.grantType,
username: ruleForm.username,
password: ruleForm.password
})
.then(res => {
if (res.success) {
//

View File

@ -24,7 +24,14 @@ export default ({ mode }: ConfigEnv): UserConfigExport => {
port: VITE_PORT,
host: "0.0.0.0",
// 本地跨域代理 https://cn.vitejs.dev/config/server-options.html#server-proxy
proxy: {},
proxy: {
"/dev-api": {
// 这里填写后端地址
target: "http://192.168.1.33:8000",
changeOrigin: true,
rewrite: path => path.replace(/^\/dev-api/, "")
}
},
// 预热文件以提前转换和缓存结果,降低启动期间的初始页面加载时长并防止转换瀑布
warmup: {
clientFiles: ["./index.html", "./src/{views,components}/*"]