260 lines
6.8 KiB
TypeScript
260 lines
6.8 KiB
TypeScript
import { SYSTEM_SERVICE_PREFIX } from '@/constants/service';
|
||
import { request } from '../request';
|
||
import { clearUserRouteCache } from './route';
|
||
import { type ServiceRequestResult, mapServiceResult, normalizeStringId } from './shared';
|
||
|
||
/** 后端登录返回 */
|
||
interface BackendLoginToken {
|
||
userId: number;
|
||
accessToken: string;
|
||
refreshToken: string;
|
||
expiresTime: number;
|
||
}
|
||
|
||
interface BackendUserInfoDTO {
|
||
userId: string | number;
|
||
userName?: string | null;
|
||
nickname?: string | null;
|
||
roles?: string[] | null;
|
||
buttons?: string[] | null;
|
||
}
|
||
|
||
interface BackendMyProfileDetailDTO {
|
||
id?: string | number | null;
|
||
userId?: string | number | null;
|
||
username?: string | null;
|
||
userName?: string | null;
|
||
nickname?: string | null;
|
||
company?: string | null;
|
||
email?: string | null;
|
||
mobile?: string | null;
|
||
sex?: Api.SystemManage.UserGender | null;
|
||
avatar?: string | null;
|
||
loginIp?: string | null;
|
||
loginDate?: string | null;
|
||
createTime?: string | null;
|
||
roles?: Api.SystemManage.RoleSimple[] | null;
|
||
dept?: Api.SystemManage.DeptSimple | null;
|
||
position?: Api.SystemManage.PostSimple | null;
|
||
}
|
||
|
||
interface BackendFileDTO {
|
||
id: string | number;
|
||
configId: string | number;
|
||
name?: string | null;
|
||
path: string;
|
||
url: string;
|
||
}
|
||
|
||
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 ?? '',
|
||
nickname: data.nickname ?? '',
|
||
roles: data.roles ?? [],
|
||
buttons: data.buttons ?? []
|
||
};
|
||
}
|
||
|
||
function safeStringId(value: string | number | null | undefined): string | null {
|
||
return value === null || value === undefined ? null : String(value);
|
||
}
|
||
|
||
// eslint-disable-next-line complexity
|
||
function mapMyProfileDetail(data: BackendMyProfileDetailDTO, fallbackUserId = ''): Api.Auth.MyProfileDetail {
|
||
const baseInfo = {
|
||
userId: String(data.id ?? data.userId ?? fallbackUserId ?? ''),
|
||
username: data.username ?? data.userName ?? '',
|
||
nickname: data.nickname ?? '',
|
||
deptId: safeStringId(data.dept?.id),
|
||
deptName: data.dept?.name ?? '',
|
||
positionId: safeStringId(data.position?.id),
|
||
positionName: data.position?.name ?? ''
|
||
};
|
||
|
||
const contactInfo = {
|
||
company: data.company ?? null,
|
||
email: data.email ?? '',
|
||
mobile: data.mobile ?? '',
|
||
sex: data.sex ?? 0,
|
||
avatar: data.avatar ?? ''
|
||
};
|
||
|
||
const extraInfo = {
|
||
roles: data.roles ?? [],
|
||
dept: data.dept ?? null,
|
||
position: data.position ?? null,
|
||
loginIp: data.loginIp ?? '',
|
||
loginDate: data.loginDate ?? null,
|
||
createTime: data.createTime ?? null
|
||
};
|
||
|
||
return { ...baseInfo, ...contactInfo, ...extraInfo };
|
||
}
|
||
|
||
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)
|
||
};
|
||
}
|
||
|
||
/** 获取当前登录人资料详情 */
|
||
export async function fetchGetMyProfileDetail(
|
||
options: {
|
||
userId?: string;
|
||
} = {}
|
||
): Promise<ServiceRequestResult<Api.Auth.MyProfileDetail>> {
|
||
const result = await request<BackendMyProfileDetailDTO>({
|
||
url: `${SYSTEM_SERVICE_PREFIX}/user/profile/get`,
|
||
method: 'get'
|
||
});
|
||
|
||
if (result.error || !result.data) {
|
||
return result as ServiceRequestResult<Api.Auth.MyProfileDetail>;
|
||
}
|
||
|
||
return {
|
||
...result,
|
||
data: mapMyProfileDetail(result.data, options.userId ?? '')
|
||
};
|
||
}
|
||
|
||
/** 更新当前登录人基础资料 */
|
||
export function fetchUpdateMyProfile(data: Api.Auth.UpdateMyProfileParams) {
|
||
return request<boolean>({
|
||
url: `${SYSTEM_SERVICE_PREFIX}/user/profile/update`,
|
||
method: 'put',
|
||
data
|
||
});
|
||
}
|
||
|
||
/** 修改当前登录人密码 */
|
||
export async function fetchUpdateMyAvatar(file: File) {
|
||
const formData = new FormData();
|
||
formData.append('file', file);
|
||
|
||
const result = await request<BackendFileDTO>({
|
||
url: `${SYSTEM_SERVICE_PREFIX}/user/profile/update-avatar`,
|
||
method: 'put',
|
||
data: formData
|
||
});
|
||
|
||
return mapServiceResult(result as ServiceRequestResult<BackendFileDTO>, data => ({
|
||
...data,
|
||
id: normalizeStringId(data.id),
|
||
configId: normalizeStringId(data.configId)
|
||
}));
|
||
}
|
||
|
||
export function fetchUpdateMyPassword(data: Api.Auth.UpdateMyPasswordParams) {
|
||
return request<boolean>({
|
||
url: `${SYSTEM_SERVICE_PREFIX}/user/profile/update-password`,
|
||
method: 'put',
|
||
data
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 刷新 token
|
||
*
|
||
* @param refreshToken 刷新 token
|
||
*/
|
||
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>({
|
||
url: `${SYSTEM_SERVICE_PREFIX}/auth/refresh-token`,
|
||
method: 'post',
|
||
params: { refreshToken },
|
||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||
skipAuth: true,
|
||
suppressErrorMessage: true,
|
||
skipTokenRefresh: true
|
||
});
|
||
|
||
if (result.error || !result.data) {
|
||
return result as ServiceRequestResult<Api.Auth.LoginToken>;
|
||
}
|
||
|
||
return {
|
||
...result,
|
||
data: mapLoginToken(result.data)
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 返回自定义后端错误
|
||
*
|
||
* @param code 错误码
|
||
* @param msg 错误信息
|
||
*/
|
||
export function fetchCustomBackendError(code: string, msg: string) {
|
||
return request({ url: '/auth/error', params: { code, msg } });
|
||
}
|