Files
cn-rdms-web/src/service/api/auth.ts
2026-05-21 10:44:00 +08:00

260 lines
6.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 } });
}