2026-03-26 20:18:20 +08:00
|
|
|
|
import { SYSTEM_SERVICE_PREFIX } from '@/constants/service';
|
|
|
|
|
|
import { request } from '../request';
|
|
|
|
|
|
import { clearUserRouteCache } from './route';
|
|
|
|
|
|
import type { ServiceRequestResult } from './shared';
|
|
|
|
|
|
|
|
|
|
|
|
/** 后端登录返回 */
|
|
|
|
|
|
interface BackendLoginToken {
|
|
|
|
|
|
userId: number;
|
|
|
|
|
|
accessToken: string;
|
|
|
|
|
|
refreshToken: string;
|
|
|
|
|
|
expiresTime: number;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
interface BackendUserInfoDTO {
|
|
|
|
|
|
userId: string | number;
|
|
|
|
|
|
userName?: string | null;
|
2026-05-12 21:41:39 +08:00
|
|
|
|
nickname?: string | null;
|
2026-03-26 20:18:20 +08:00
|
|
|
|
roles?: string[] | null;
|
|
|
|
|
|
buttons?: string[] | null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let userInfoPromise: Promise<ServiceRequestResult<BackendUserInfoDTO>> | null = null;
|
|
|
|
|
|
|
|
|
|
|
|
/** 将后端 token 结构转换成前端现有结构 */
|
|
|
|
|
|
function mapLoginToken(data: BackendLoginToken): Api.Auth.LoginToken {
|
|
|
|
|
|
return {
|
|
|
|
|
|
token: data.accessToken,
|
|
|
|
|
|
refreshToken: data.refreshToken
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function mapUserInfo(data: BackendUserInfoDTO): Api.Auth.UserInfo {
|
|
|
|
|
|
return {
|
|
|
|
|
|
userId: String(data.userId ?? ''),
|
|
|
|
|
|
userName: data.userName ?? '',
|
2026-05-12 21:41:39 +08:00
|
|
|
|
nickname: data.nickname ?? '',
|
2026-03-26 20:18:20 +08:00
|
|
|
|
roles: data.roles ?? [],
|
|
|
|
|
|
buttons: data.buttons ?? []
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export function clearUserInfoCache() {
|
|
|
|
|
|
userInfoPromise = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export function clearAuthApiCache() {
|
|
|
|
|
|
clearUserInfoCache();
|
|
|
|
|
|
clearUserRouteCache();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 登录
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param userName 用户名
|
|
|
|
|
|
* @param password 密码
|
|
|
|
|
|
*/
|
|
|
|
|
|
export async function fetchLogin(
|
|
|
|
|
|
userName: string,
|
|
|
|
|
|
password: string
|
|
|
|
|
|
): Promise<ServiceRequestResult<Api.Auth.LoginToken>> {
|
|
|
|
|
|
clearAuthApiCache();
|
|
|
|
|
|
|
|
|
|
|
|
const result = await request<BackendLoginToken>({
|
|
|
|
|
|
url: `${SYSTEM_SERVICE_PREFIX}/auth/login`,
|
|
|
|
|
|
method: 'post',
|
|
|
|
|
|
data: {
|
|
|
|
|
|
username: userName,
|
|
|
|
|
|
password,
|
|
|
|
|
|
rememberMe: true
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
if (result.error || !result.data) {
|
|
|
|
|
|
return result as ServiceRequestResult<Api.Auth.LoginToken>;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
...result,
|
|
|
|
|
|
data: mapLoginToken(result.data)
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 获取用户信息 */
|
|
|
|
|
|
export async function fetchGetUserInfo(force = false): Promise<ServiceRequestResult<Api.Auth.UserInfo>> {
|
|
|
|
|
|
if (!userInfoPromise || force) {
|
|
|
|
|
|
userInfoPromise = request<BackendUserInfoDTO>({
|
|
|
|
|
|
url: `${SYSTEM_SERVICE_PREFIX}/auth/get-user-info`
|
|
|
|
|
|
}).then(result => result as ServiceRequestResult<BackendUserInfoDTO>);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const result = await userInfoPromise;
|
|
|
|
|
|
|
|
|
|
|
|
if (result.error || !result.data) {
|
|
|
|
|
|
userInfoPromise = null;
|
|
|
|
|
|
return result as ServiceRequestResult<Api.Auth.UserInfo>;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
...result,
|
|
|
|
|
|
data: mapUserInfo(result.data)
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 刷新 token
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param refreshToken 刷新 token
|
|
|
|
|
|
*/
|
2026-05-15 13:38:41 +08:00
|
|
|
|
export async function fetchRefreshToken(refreshToken: string): Promise<ServiceRequestResult<Api.Auth.LoginToken>> {
|
|
|
|
|
|
// 后端要求 refreshToken 通过 query 参数传递,且 Content-Type 为 form-urlencoded
|
|
|
|
|
|
// skipAuth: 不注入过期 access 头,否则会被网关拦下死循环(网关一律校验 Authorization,不看 PermitAll)
|
|
|
|
|
|
const result = await request<BackendLoginToken>({
|
2026-03-26 20:18:20 +08:00
|
|
|
|
url: `${SYSTEM_SERVICE_PREFIX}/auth/refresh-token`,
|
|
|
|
|
|
method: 'post',
|
2026-05-15 13:38:41 +08:00
|
|
|
|
params: { refreshToken },
|
|
|
|
|
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
|
|
|
|
skipAuth: true
|
2026-03-26 20:18:20 +08:00
|
|
|
|
});
|
2026-05-15 13:38:41 +08:00
|
|
|
|
|
|
|
|
|
|
if (result.error || !result.data) {
|
|
|
|
|
|
return result as ServiceRequestResult<Api.Auth.LoginToken>;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
...result,
|
|
|
|
|
|
data: mapLoginToken(result.data)
|
|
|
|
|
|
};
|
2026-03-26 20:18:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 返回自定义后端错误
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param code 错误码
|
|
|
|
|
|
* @param msg 错误信息
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function fetchCustomBackendError(code: string, msg: string) {
|
|
|
|
|
|
return request({ url: '/auth/error', params: { code, msg } });
|
|
|
|
|
|
}
|