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> | 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> { clearAuthApiCache(); const result = await request({ url: `${SYSTEM_SERVICE_PREFIX}/auth/login`, method: 'post', data: { username: userName, password, rememberMe: true } }); if (result.error || !result.data) { return result as ServiceRequestResult; } return { ...result, data: mapLoginToken(result.data) }; } /** 获取用户信息 */ export async function fetchGetUserInfo(force = false): Promise> { if (!userInfoPromise || force) { userInfoPromise = request({ url: `${SYSTEM_SERVICE_PREFIX}/auth/get-user-info` }).then(result => result as ServiceRequestResult); } const result = await userInfoPromise; if (result.error || !result.data) { userInfoPromise = null; return result as ServiceRequestResult; } return { ...result, data: mapUserInfo(result.data) }; } /** 获取当前登录人资料详情 */ export async function fetchGetMyProfileDetail( options: { userId?: string; } = {} ): Promise> { const result = await request({ url: `${SYSTEM_SERVICE_PREFIX}/user/profile/get`, method: 'get' }); if (result.error || !result.data) { return result as ServiceRequestResult; } return { ...result, data: mapMyProfileDetail(result.data, options.userId ?? '') }; } /** 更新当前登录人基础资料 */ export function fetchUpdateMyProfile(data: Api.Auth.UpdateMyProfileParams) { return request({ 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({ url: `${SYSTEM_SERVICE_PREFIX}/user/profile/update-avatar`, method: 'put', data: formData }); return mapServiceResult(result as ServiceRequestResult, data => ({ ...data, id: normalizeStringId(data.id), configId: normalizeStringId(data.configId) })); } export function fetchUpdateMyPassword(data: Api.Auth.UpdateMyPasswordParams) { return request({ url: `${SYSTEM_SERVICE_PREFIX}/user/profile/update-password`, method: 'put', data }); } /** * 刷新 token * * @param refreshToken 刷新 token */ export async function fetchRefreshToken(refreshToken: string): Promise> { // 后端要求 refreshToken 通过 query 参数传递,且 Content-Type 为 form-urlencoded // skipAuth: 不注入过期 access 头,否则会被网关拦下死循环(网关一律校验 Authorization,不看 PermitAll) const result = await request({ 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; } 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 } }); }