初始化
This commit is contained in:
125
src/service/api/auth.ts
Normal file
125
src/service/api/auth.ts
Normal file
@@ -0,0 +1,125 @@
|
||||
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;
|
||||
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 ?? '',
|
||||
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
|
||||
*/
|
||||
export function fetchRefreshToken(refreshToken: string) {
|
||||
return request<Api.Auth.LoginToken>({
|
||||
url: `${SYSTEM_SERVICE_PREFIX}/auth/refresh-token`,
|
||||
method: 'post',
|
||||
data: {
|
||||
refreshToken
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回自定义后端错误
|
||||
*
|
||||
* @param code 错误码
|
||||
* @param msg 错误信息
|
||||
*/
|
||||
export function fetchCustomBackendError(code: string, msg: string) {
|
||||
return request({ url: '/auth/error', params: { code, msg } });
|
||||
}
|
||||
104
src/service/api/dict.ts
Normal file
104
src/service/api/dict.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
import { SYSTEM_SERVICE_PREFIX } from '@/constants/service';
|
||||
import { request } from '../request';
|
||||
|
||||
const DICT_TYPE_PREFIX = `${SYSTEM_SERVICE_PREFIX}/dict-type`;
|
||||
const DICT_DATA_PREFIX = `${SYSTEM_SERVICE_PREFIX}/dict-data`;
|
||||
|
||||
function createBatchDeleteQuery(ids: number[]) {
|
||||
// 后端批量删除接口要求使用重复 query 参数,而不是数组 JSON。
|
||||
const query = new URLSearchParams();
|
||||
|
||||
ids.forEach(id => {
|
||||
query.append('ids', String(id));
|
||||
});
|
||||
|
||||
return query.toString();
|
||||
}
|
||||
|
||||
/** 获取字典类型分页 */
|
||||
export function fetchGetDictTypePage(params?: Api.Dict.DictTypeSearchParams) {
|
||||
return request<Api.Dict.PageResult<Api.Dict.DictType>>({
|
||||
url: `${DICT_TYPE_PREFIX}/page`,
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
/** 创建字典类型 */
|
||||
export function fetchCreateDictType(data: Api.Dict.SaveDictTypeParams) {
|
||||
return request<number>({
|
||||
url: `${DICT_TYPE_PREFIX}/create`,
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/** 更新字典类型 */
|
||||
export function fetchUpdateDictType(data: { id: number } & Api.Dict.SaveDictTypeParams) {
|
||||
return request<boolean>({
|
||||
url: `${DICT_TYPE_PREFIX}/update`,
|
||||
method: 'put',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/** 删除字典类型 */
|
||||
export function fetchDeleteDictType(id: number) {
|
||||
return request<boolean>({
|
||||
url: `${DICT_TYPE_PREFIX}/delete`,
|
||||
method: 'delete',
|
||||
params: { id }
|
||||
});
|
||||
}
|
||||
|
||||
/** 批量删除字典类型 */
|
||||
export function fetchBatchDeleteDictType(ids: number[]) {
|
||||
return request<boolean>({
|
||||
url: `${DICT_TYPE_PREFIX}/delete-list?${createBatchDeleteQuery(ids)}`,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
|
||||
/** 获取字典数据分页 */
|
||||
export function fetchGetDictDataPage(params: Api.Dict.DictDataSearchParams) {
|
||||
return request<Api.Dict.PageResult<Api.Dict.DictData>>({
|
||||
url: `${DICT_DATA_PREFIX}/page`,
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
/** 创建字典数据 */
|
||||
export function fetchCreateDictData(data: Api.Dict.SaveDictDataParams) {
|
||||
return request<number>({
|
||||
url: `${DICT_DATA_PREFIX}/create`,
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/** 更新字典数据 */
|
||||
export function fetchUpdateDictData(data: { id: number } & Api.Dict.SaveDictDataParams) {
|
||||
return request<boolean>({
|
||||
url: `${DICT_DATA_PREFIX}/update`,
|
||||
method: 'put',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/** 删除字典数据 */
|
||||
export function fetchDeleteDictData(id: number) {
|
||||
return request<boolean>({
|
||||
url: `${DICT_DATA_PREFIX}/delete`,
|
||||
method: 'delete',
|
||||
params: { id }
|
||||
});
|
||||
}
|
||||
|
||||
/** 批量删除字典数据 */
|
||||
export function fetchBatchDeleteDictData(ids: number[]) {
|
||||
return request<boolean>({
|
||||
url: `${DICT_DATA_PREFIX}/delete-list?${createBatchDeleteQuery(ids)}`,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
4
src/service/api/index.ts
Normal file
4
src/service/api/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export * from './auth';
|
||||
export * from './dict';
|
||||
export * from './route';
|
||||
export * from './system-manage';
|
||||
92
src/service/api/route.ts
Normal file
92
src/service/api/route.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
import type { LastLevelRouteKey } from '@elegant-router/types';
|
||||
import { SYSTEM_SERVICE_PREFIX } from '@/constants/service';
|
||||
import { request } from '../request';
|
||||
import type { ServiceRequestResult } from './shared';
|
||||
|
||||
type BackendMenuRoute = Omit<Api.Route.MenuRoute, 'id' | 'children'> & {
|
||||
id: string | number;
|
||||
children?: BackendMenuRoute[];
|
||||
};
|
||||
|
||||
interface BackendUserRouteDTO {
|
||||
routes?: BackendMenuRoute[] | null;
|
||||
home?: string | null;
|
||||
}
|
||||
|
||||
let userRoutePromise: Promise<ServiceRequestResult<BackendUserRouteDTO>> | null = null;
|
||||
|
||||
export function clearUserRouteCache() {
|
||||
userRoutePromise = null;
|
||||
}
|
||||
|
||||
function normalizeMenuRoute(route: BackendMenuRoute): Api.Route.MenuRoute {
|
||||
return {
|
||||
...route,
|
||||
id: String(route.id),
|
||||
children: route.children?.map(child => normalizeMenuRoute(child))
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeUserRoute(data: BackendUserRouteDTO): Api.Route.UserRoute {
|
||||
return {
|
||||
routes: (data.routes ?? []).map(route => normalizeMenuRoute(route)),
|
||||
home: (data.home || 'system_user') as LastLevelRouteKey
|
||||
};
|
||||
}
|
||||
|
||||
/** 获取常量路由 */
|
||||
export function fetchGetConstantRoutes() {
|
||||
return request<Api.Route.MenuRoute[]>({ url: '/route/getConstantRoutes' });
|
||||
}
|
||||
|
||||
/** 获取用户路由 */
|
||||
export async function fetchGetUserRoutes(force = false): Promise<ServiceRequestResult<Api.Route.UserRoute>> {
|
||||
if (!userRoutePromise || force) {
|
||||
userRoutePromise = request<BackendUserRouteDTO>({
|
||||
url: `${SYSTEM_SERVICE_PREFIX}/auth/get-user-routes`
|
||||
}).then(result => result as ServiceRequestResult<BackendUserRouteDTO>);
|
||||
}
|
||||
|
||||
const result = await userRoutePromise;
|
||||
|
||||
if (result.error || !result.data) {
|
||||
userRoutePromise = null;
|
||||
return result as ServiceRequestResult<Api.Route.UserRoute>;
|
||||
}
|
||||
|
||||
return {
|
||||
...result,
|
||||
data: normalizeUserRoute(result.data)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断路由是否存在
|
||||
*
|
||||
* @param routeName 路由名称
|
||||
*/
|
||||
export async function fetchIsRouteExist(routeName: string): Promise<ServiceRequestResult<boolean>> {
|
||||
const result = await fetchGetUserRoutes();
|
||||
|
||||
if (result.error || !result.data) {
|
||||
return {
|
||||
...result,
|
||||
data: false
|
||||
} as unknown as ServiceRequestResult<boolean>;
|
||||
}
|
||||
|
||||
const isExist = result.data.routes.some(route => recursiveIsRouteExist(route, routeName));
|
||||
|
||||
return {
|
||||
...result,
|
||||
data: isExist
|
||||
};
|
||||
}
|
||||
|
||||
function recursiveIsRouteExist(route: Api.Route.MenuRoute, routeName: string): boolean {
|
||||
if (route.name === routeName) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return route.children?.some(child => recursiveIsRouteExist(child, routeName)) || false;
|
||||
}
|
||||
13
src/service/api/shared.ts
Normal file
13
src/service/api/shared.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import type { AxiosError, AxiosResponse } from 'axios';
|
||||
|
||||
export type ServiceRequestResult<T> =
|
||||
| {
|
||||
data: T;
|
||||
error: null;
|
||||
response: AxiosResponse<App.Service.Response<unknown>>;
|
||||
}
|
||||
| {
|
||||
data: null;
|
||||
error: AxiosError<App.Service.Response<unknown>>;
|
||||
response: AxiosResponse<App.Service.Response<unknown>> | undefined;
|
||||
};
|
||||
415
src/service/api/system-manage.ts
Normal file
415
src/service/api/system-manage.ts
Normal file
@@ -0,0 +1,415 @@
|
||||
import { SYSTEM_SERVICE_PREFIX } from '@/constants/service';
|
||||
import { request } from '../request';
|
||||
import type { ServiceRequestResult } from './shared';
|
||||
|
||||
const ROLE_PREFIX = `${SYSTEM_SERVICE_PREFIX}/role`;
|
||||
const MENU_PREFIX = `${SYSTEM_SERVICE_PREFIX}/menu`;
|
||||
const PERMISSION_PREFIX = `${SYSTEM_SERVICE_PREFIX}/permission`;
|
||||
const USER_PREFIX = `${SYSTEM_SERVICE_PREFIX}/user`;
|
||||
const DEPT_PREFIX = `${SYSTEM_SERVICE_PREFIX}/dept`;
|
||||
const POST_PREFIX = `${SYSTEM_SERVICE_PREFIX}/post`;
|
||||
const ORG_LEADER_PREFIX = `${SYSTEM_SERVICE_PREFIX}/org-leader`;
|
||||
|
||||
function createRolePageQuery(params?: Api.SystemManage.RoleSearchParams) {
|
||||
const query = new URLSearchParams();
|
||||
|
||||
if (!params) {
|
||||
return query.toString();
|
||||
}
|
||||
|
||||
if (params.pageNo !== undefined) {
|
||||
query.append('pageNo', String(params.pageNo));
|
||||
}
|
||||
|
||||
if (params.pageSize !== undefined) {
|
||||
query.append('pageSize', String(params.pageSize));
|
||||
}
|
||||
|
||||
if (params.name) {
|
||||
query.append('name', params.name);
|
||||
}
|
||||
|
||||
if (params.code) {
|
||||
query.append('code', params.code);
|
||||
}
|
||||
|
||||
if (params.status !== undefined) {
|
||||
query.append('status', String(params.status));
|
||||
}
|
||||
|
||||
params.createTime?.forEach(item => {
|
||||
if (item) {
|
||||
query.append('createTime', item);
|
||||
}
|
||||
});
|
||||
|
||||
return query.toString();
|
||||
}
|
||||
|
||||
function createBatchDeleteQuery(ids: number[]) {
|
||||
const query = new URLSearchParams();
|
||||
|
||||
ids.forEach(id => {
|
||||
query.append('ids', String(id));
|
||||
});
|
||||
|
||||
return query.toString();
|
||||
}
|
||||
|
||||
/** 获取角色分页 */
|
||||
export function fetchGetRolePage(params?: Api.SystemManage.RoleSearchParams) {
|
||||
const query = createRolePageQuery(params);
|
||||
|
||||
return request<Api.SystemManage.RoleList>({
|
||||
url: query ? `${ROLE_PREFIX}/page?${query}` : `${ROLE_PREFIX}/page`,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
/** 为兼容旧代码保留原函数名 */
|
||||
export const fetchGetRoleList = fetchGetRolePage;
|
||||
|
||||
/** 获取角色详情 */
|
||||
export function fetchGetRole(id: number) {
|
||||
return request<Api.SystemManage.Role>({
|
||||
url: `${ROLE_PREFIX}/get`,
|
||||
method: 'get',
|
||||
params: { id }
|
||||
});
|
||||
}
|
||||
|
||||
/** 创建角色 */
|
||||
export function fetchCreateRole(data: Api.SystemManage.SaveRoleParams) {
|
||||
return request<number>({
|
||||
url: `${ROLE_PREFIX}/create`,
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/** 更新角色 */
|
||||
export function fetchUpdateRole(data: { id: number } & Api.SystemManage.SaveRoleParams) {
|
||||
return request<boolean>({
|
||||
url: `${ROLE_PREFIX}/update`,
|
||||
method: 'put',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/** 删除角色 */
|
||||
export function fetchDeleteRole(id: number) {
|
||||
return request<boolean>({
|
||||
url: `${ROLE_PREFIX}/delete`,
|
||||
method: 'delete',
|
||||
params: { id }
|
||||
});
|
||||
}
|
||||
|
||||
/** 批量删除角色 */
|
||||
export function fetchBatchDeleteRole(ids: number[]) {
|
||||
return request<boolean>({
|
||||
url: `${ROLE_PREFIX}/delete-list?${createBatchDeleteQuery(ids)}`,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取全部角色
|
||||
*
|
||||
* 为当前用户页面保留 `roleName / roleCode` 字段,直到该页面完成重构
|
||||
*/
|
||||
export async function fetchGetAllRoles(): Promise<ServiceRequestResult<Api.SystemManage.AllRole[]>> {
|
||||
const result = await request<Api.SystemManage.RoleSimpleList>({
|
||||
url: `${ROLE_PREFIX}/simple-list`,
|
||||
method: 'get'
|
||||
});
|
||||
|
||||
if (result.error || !result.data) {
|
||||
return result as ServiceRequestResult<Api.SystemManage.AllRole[]>;
|
||||
}
|
||||
|
||||
return {
|
||||
...result,
|
||||
data: result.data.map(item => ({
|
||||
...item,
|
||||
roleName: item.name,
|
||||
roleCode: item.code
|
||||
}))
|
||||
};
|
||||
}
|
||||
|
||||
/** 获取启用状态的角色简表 */
|
||||
export function fetchGetRoleSimpleList() {
|
||||
return request<Api.SystemManage.RoleSimpleList>({
|
||||
url: `${ROLE_PREFIX}/simple-list`,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
/** 获取部门列表 */
|
||||
export function fetchGetDeptList(params?: Api.SystemManage.DeptSearchParams) {
|
||||
return request<Api.SystemManage.DeptList>({
|
||||
url: `${DEPT_PREFIX}/list`,
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
/** 获取部门简表 */
|
||||
export function fetchGetDeptSimpleList() {
|
||||
return request<Api.SystemManage.DeptSimpleList>({
|
||||
url: `${DEPT_PREFIX}/simple-list`,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
/** 创建部门 */
|
||||
export function fetchCreateDept(data: Api.SystemManage.SaveDeptParams) {
|
||||
return request<number>({
|
||||
url: `${DEPT_PREFIX}/create`,
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/** 更新部门 */
|
||||
export function fetchUpdateDept(data: { id: number } & Api.SystemManage.SaveDeptParams) {
|
||||
return request<boolean>({
|
||||
url: `${DEPT_PREFIX}/update`,
|
||||
method: 'put',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/** 删除部门 */
|
||||
export function fetchDeleteDept(id: number) {
|
||||
return request<boolean>({
|
||||
url: `${DEPT_PREFIX}/delete`,
|
||||
method: 'delete',
|
||||
params: { id }
|
||||
});
|
||||
}
|
||||
|
||||
/** 根据部门获取组织负责人关系 */
|
||||
export function fetchGetOrgLeaderListByDept(deptId: number) {
|
||||
return request<Api.SystemManage.OrgLeaderRelationList>({
|
||||
url: `${ORG_LEADER_PREFIX}/list-by-dept`,
|
||||
method: 'get',
|
||||
params: { deptId }
|
||||
});
|
||||
}
|
||||
|
||||
/** 获取组织负责人的候选用户 */
|
||||
export function fetchGetOrgLeaderCandidateUsers(deptId: number) {
|
||||
return request<Api.SystemManage.OrgLeaderCandidateUserList>({
|
||||
url: `${ORG_LEADER_PREFIX}/candidate-users`,
|
||||
method: 'get',
|
||||
params: { deptId }
|
||||
});
|
||||
}
|
||||
|
||||
/** 创建组织负责人关系 */
|
||||
export function fetchCreateOrgLeaderRelation(data: Api.SystemManage.SaveOrgLeaderRelationParams) {
|
||||
return request<number>({
|
||||
url: `${ORG_LEADER_PREFIX}/create`,
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/** 更新组织负责人关系 */
|
||||
export function fetchUpdateOrgLeaderRelation(data: { id: number } & Api.SystemManage.SaveOrgLeaderRelationParams) {
|
||||
return request<boolean>({
|
||||
url: `${ORG_LEADER_PREFIX}/update`,
|
||||
method: 'put',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/** 删除组织负责人关系 */
|
||||
export function fetchDeleteOrgLeaderRelation(id: number) {
|
||||
return request<boolean>({
|
||||
url: `${ORG_LEADER_PREFIX}/delete`,
|
||||
method: 'delete',
|
||||
params: { id }
|
||||
});
|
||||
}
|
||||
|
||||
/** 获取启用状态的岗位简表 */
|
||||
export function fetchGetPostSimpleList() {
|
||||
return request<Api.SystemManage.PostSimpleList>({
|
||||
url: `${POST_PREFIX}/simple-list`,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
/** 获取用户分页 */
|
||||
export function fetchGetUserPage(params?: Api.SystemManage.UserSearchParams) {
|
||||
return request<Api.SystemManage.UserList>({
|
||||
url: `${USER_PREFIX}/page`,
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
/** 为兼容旧代码保留原函数名 */
|
||||
export const fetchGetUserList = fetchGetUserPage;
|
||||
|
||||
/** 获取用户详情 */
|
||||
export function fetchGetUser(id: number) {
|
||||
return request<Api.SystemManage.User>({
|
||||
url: `${USER_PREFIX}/get`,
|
||||
method: 'get',
|
||||
params: { id }
|
||||
});
|
||||
}
|
||||
|
||||
/** 创建用户 */
|
||||
export function fetchCreateUser(data: Api.SystemManage.SaveUserParams) {
|
||||
return request<number>({
|
||||
url: `${USER_PREFIX}/create`,
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/** 更新用户 */
|
||||
export function fetchUpdateUser(data: { id: number } & Api.SystemManage.SaveUserParams) {
|
||||
return request<boolean>({
|
||||
url: `${USER_PREFIX}/update`,
|
||||
method: 'put',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/** 更新用户状态 */
|
||||
export function fetchUpdateUserStatus(data: Api.SystemManage.UpdateUserStatusParams) {
|
||||
return request<boolean>({
|
||||
url: `${USER_PREFIX}/update-status`,
|
||||
method: 'put',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/** 重置用户密码 */
|
||||
export function fetchUpdateUserPassword(data: Api.SystemManage.UpdateUserPasswordParams) {
|
||||
return request<boolean>({
|
||||
url: `${USER_PREFIX}/update-password`,
|
||||
method: 'put',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/** 删除用户 */
|
||||
export function fetchDeleteUser(id: number) {
|
||||
return request<boolean>({
|
||||
url: `${USER_PREFIX}/delete`,
|
||||
method: 'delete',
|
||||
params: { id }
|
||||
});
|
||||
}
|
||||
|
||||
/** 批量删除用户 */
|
||||
export function fetchBatchDeleteUser(ids: number[]) {
|
||||
return request<boolean>({
|
||||
url: `${USER_PREFIX}/delete-list?${createBatchDeleteQuery(ids)}`,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
|
||||
/** 获取菜单列表 */
|
||||
export function fetchGetMenuList(params?: Api.SystemManage.MenuSearchParams) {
|
||||
return request<Api.SystemManage.MenuList>({
|
||||
url: `${MENU_PREFIX}/list`,
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
/** 获取菜单详情 */
|
||||
export function fetchGetMenu(id: number) {
|
||||
return request<Api.SystemManage.Menu>({
|
||||
url: `${MENU_PREFIX}/get`,
|
||||
method: 'get',
|
||||
params: { id }
|
||||
});
|
||||
}
|
||||
|
||||
/** 创建菜单 */
|
||||
export function fetchCreateMenu(data: Api.SystemManage.SaveMenuParams) {
|
||||
return request<number>({
|
||||
url: `${MENU_PREFIX}/create`,
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/** 更新菜单 */
|
||||
export function fetchUpdateMenu(data: { id: number } & Api.SystemManage.SaveMenuParams) {
|
||||
return request<boolean>({
|
||||
url: `${MENU_PREFIX}/update`,
|
||||
method: 'put',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/** 删除菜单 */
|
||||
export function fetchDeleteMenu(id: number) {
|
||||
return request<boolean>({
|
||||
url: `${MENU_PREFIX}/delete`,
|
||||
method: 'delete',
|
||||
params: { id }
|
||||
});
|
||||
}
|
||||
|
||||
/** 批量删除菜单 */
|
||||
export function fetchBatchDeleteMenu(ids: number[]) {
|
||||
return request<boolean>({
|
||||
url: `${MENU_PREFIX}/delete-list?${createBatchDeleteQuery(ids)}`,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
|
||||
/** 获取启用状态的菜单简表 */
|
||||
export function fetchGetMenuSimpleList() {
|
||||
return request<Api.SystemManage.MenuSimpleList>({
|
||||
url: `${MENU_PREFIX}/simple-list`,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
/** 获取角色关联的菜单 ID 列表 */
|
||||
export function fetchGetRoleMenuIds(roleId: number) {
|
||||
return request<number[]>({
|
||||
url: `${PERMISSION_PREFIX}/list-role-menus`,
|
||||
method: 'get',
|
||||
params: { roleId }
|
||||
});
|
||||
}
|
||||
|
||||
/** 分配角色菜单 */
|
||||
export function fetchAssignRoleMenus(data: Api.SystemManage.AssignRoleMenuParams) {
|
||||
return request<boolean>({
|
||||
url: `${PERMISSION_PREFIX}/assign-role-menu`,
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/** 获取用户关联的角色 ID 列表 */
|
||||
export function fetchGetUserRoleIds(userId: number) {
|
||||
return request<number[]>({
|
||||
url: `${PERMISSION_PREFIX}/list-user-roles`,
|
||||
method: 'get',
|
||||
params: { userId }
|
||||
});
|
||||
}
|
||||
|
||||
/** 分配用户角色 */
|
||||
export function fetchAssignUserRoles(data: Api.SystemManage.AssignUserRoleParams) {
|
||||
return request<boolean>({
|
||||
url: `${PERMISSION_PREFIX}/assign-user-role`,
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
168
src/service/request/index.ts
Normal file
168
src/service/request/index.ts
Normal file
@@ -0,0 +1,168 @@
|
||||
import type { AxiosResponse } from 'axios';
|
||||
import { BACKEND_ERROR_CODE, createFlatRequest, createRequest } from '@sa/axios';
|
||||
import { useAuthStore } from '@/store/modules/auth';
|
||||
import { localStg } from '@/utils/storage';
|
||||
import { getServiceBaseURL } from '@/utils/service';
|
||||
import { $t } from '@/locales';
|
||||
import { getAuthorization, handleExpiredRequest, showErrorMsg } from './shared';
|
||||
import type { RequestInstanceState } from './type';
|
||||
|
||||
const isHttpProxy = import.meta.env.DEV && import.meta.env.VITE_HTTP_PROXY === 'Y';
|
||||
const { baseURL, otherBaseURL } = getServiceBaseURL(import.meta.env, isHttpProxy);
|
||||
|
||||
export const request = createFlatRequest(
|
||||
{
|
||||
baseURL,
|
||||
headers: {
|
||||
apifoxToken: 'XL299LiMEDZ0H5h3A29PxwQXdMJqWyY2'
|
||||
}
|
||||
},
|
||||
{
|
||||
defaultState: {
|
||||
errMsgStack: [],
|
||||
refreshTokenPromise: null
|
||||
} as RequestInstanceState,
|
||||
transform(response: AxiosResponse<App.Service.Response<any>>) {
|
||||
return response.data.data;
|
||||
},
|
||||
async onRequest(config) {
|
||||
const Authorization = getAuthorization();
|
||||
Object.assign(config.headers, { Authorization });
|
||||
|
||||
return config;
|
||||
},
|
||||
isBackendSuccess(response) {
|
||||
// 当后端返回码为 "0"(默认)时,表示请求成功
|
||||
// 如需调整该逻辑,可修改 `.env` 中的 `VITE_SERVICE_SUCCESS_CODE`
|
||||
return String(response.data.code) === import.meta.env.VITE_SERVICE_SUCCESS_CODE;
|
||||
},
|
||||
async onBackendFail(response, instance) {
|
||||
const authStore = useAuthStore();
|
||||
const responseCode = String(response.data.code);
|
||||
|
||||
function handleLogout() {
|
||||
authStore.resetStore();
|
||||
}
|
||||
|
||||
function logoutAndCleanup() {
|
||||
handleLogout();
|
||||
window.removeEventListener('beforeunload', handleLogout);
|
||||
|
||||
request.state.errMsgStack = request.state.errMsgStack.filter(msg => msg !== response.data.msg);
|
||||
}
|
||||
|
||||
// 当后端返回码命中 `logoutCodes` 时,表示用户需要退出登录并跳转到登录页
|
||||
const logoutCodes = import.meta.env.VITE_SERVICE_LOGOUT_CODES?.split(',') || [];
|
||||
if (logoutCodes.includes(responseCode)) {
|
||||
handleLogout();
|
||||
return null;
|
||||
}
|
||||
|
||||
// 当后端返回码命中 `modalLogoutCodes` 时,表示通过弹窗提示后再退出登录
|
||||
const modalLogoutCodes = import.meta.env.VITE_SERVICE_MODAL_LOGOUT_CODES?.split(',') || [];
|
||||
if (modalLogoutCodes.includes(responseCode) && !request.state.errMsgStack?.includes(response.data.msg)) {
|
||||
request.state.errMsgStack = [...(request.state.errMsgStack || []), response.data.msg];
|
||||
|
||||
// 防止用户刷新页面绕过退出逻辑
|
||||
window.addEventListener('beforeunload', handleLogout);
|
||||
|
||||
window.$messageBox
|
||||
?.confirm(response.data.msg, $t('common.error'), {
|
||||
confirmButtonText: $t('common.confirm'),
|
||||
cancelButtonText: $t('common.cancel'),
|
||||
type: 'error',
|
||||
closeOnClickModal: false,
|
||||
closeOnPressEscape: false
|
||||
})
|
||||
.then(() => {
|
||||
logoutAndCleanup();
|
||||
});
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// 当后端返回码命中 `expiredTokenCodes` 时,表示 token 已过期,需要刷新 token
|
||||
// `refreshToken` 接口不能再返回 `expiredTokenCodes` 中的错误码,否则会形成死循环,应返回 `logoutCodes` 或 `modalLogoutCodes`
|
||||
const expiredTokenCodes = import.meta.env.VITE_SERVICE_EXPIRED_TOKEN_CODES?.split(',') || [];
|
||||
if (expiredTokenCodes.includes(responseCode)) {
|
||||
const success = await handleExpiredRequest(request.state);
|
||||
if (success) {
|
||||
const Authorization = getAuthorization();
|
||||
Object.assign(response.config.headers, { Authorization });
|
||||
|
||||
return instance.request(response.config) as Promise<AxiosResponse>;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
onError(error) {
|
||||
// 请求失败时,在这里统一处理错误提示
|
||||
|
||||
let message = error.message;
|
||||
let backendErrorCode = '';
|
||||
|
||||
// 获取后端错误信息和错误码
|
||||
if (error.code === BACKEND_ERROR_CODE) {
|
||||
message = error.response?.data?.msg || message;
|
||||
backendErrorCode = String(error.response?.data?.code || '');
|
||||
}
|
||||
|
||||
// 这类错误信息已经通过弹窗展示,不再重复提示
|
||||
const modalLogoutCodes = import.meta.env.VITE_SERVICE_MODAL_LOGOUT_CODES?.split(',') || [];
|
||||
if (modalLogoutCodes.includes(backendErrorCode)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// token 过期时会自动刷新并重试请求,这里无需额外提示
|
||||
const expiredTokenCodes = import.meta.env.VITE_SERVICE_EXPIRED_TOKEN_CODES?.split(',') || [];
|
||||
if (expiredTokenCodes.includes(backendErrorCode)) {
|
||||
return;
|
||||
}
|
||||
|
||||
showErrorMsg(request.state, message);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const demoRequest = createRequest(
|
||||
{
|
||||
baseURL: otherBaseURL.demo
|
||||
},
|
||||
{
|
||||
transform(response: AxiosResponse<App.Service.DemoResponse>) {
|
||||
return response.data.result;
|
||||
},
|
||||
async onRequest(config) {
|
||||
const { headers } = config;
|
||||
|
||||
// 设置 token
|
||||
const token = localStg.get('token');
|
||||
const Authorization = token ? `Bearer ${token}` : null;
|
||||
Object.assign(headers, { Authorization });
|
||||
|
||||
return config;
|
||||
},
|
||||
isBackendSuccess(response) {
|
||||
// 当后端返回码为 "200" 时,表示请求成功
|
||||
// 如有需要可以自行调整这段逻辑
|
||||
return response.data.status === '200';
|
||||
},
|
||||
async onBackendFail(_response) {
|
||||
// 当后端返回码不是 "200" 时,表示请求失败
|
||||
// 例如:token 过期后可以在这里刷新 token 并重试请求
|
||||
},
|
||||
onError(error) {
|
||||
// 请求失败时,在这里统一处理错误提示
|
||||
|
||||
let message = error.message;
|
||||
|
||||
// 展示后端返回的错误信息
|
||||
if (error.code === BACKEND_ERROR_CODE) {
|
||||
message = error.response?.data?.message || message;
|
||||
}
|
||||
|
||||
window.$message?.error(message);
|
||||
}
|
||||
}
|
||||
);
|
||||
65
src/service/request/shared.ts
Normal file
65
src/service/request/shared.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import { useAuthStore } from '@/store/modules/auth';
|
||||
import { localStg } from '@/utils/storage';
|
||||
import { fetchRefreshToken } from '../api';
|
||||
import type { RequestInstanceState } from './type';
|
||||
|
||||
export function getAuthorization() {
|
||||
const token = localStg.get('token');
|
||||
const Authorization = token ? `Bearer ${token}` : null;
|
||||
|
||||
return Authorization;
|
||||
}
|
||||
|
||||
/** 刷新 token */
|
||||
async function handleRefreshToken() {
|
||||
const { resetStore } = useAuthStore();
|
||||
|
||||
const rToken = localStg.get('refreshToken') || '';
|
||||
const { error, data } = await fetchRefreshToken(rToken);
|
||||
if (!error) {
|
||||
localStg.set('token', data.token);
|
||||
localStg.set('refreshToken', data.refreshToken);
|
||||
return true;
|
||||
}
|
||||
|
||||
resetStore();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export async function handleExpiredRequest(state: RequestInstanceState) {
|
||||
if (!state.refreshTokenFn) {
|
||||
state.refreshTokenFn = handleRefreshToken();
|
||||
}
|
||||
|
||||
const success = await state.refreshTokenFn;
|
||||
|
||||
setTimeout(() => {
|
||||
state.refreshTokenFn = null;
|
||||
}, 1000);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
export function showErrorMsg(state: RequestInstanceState, message: string) {
|
||||
if (!state.errMsgStack?.length) {
|
||||
state.errMsgStack = [];
|
||||
}
|
||||
|
||||
const isExist = state.errMsgStack.includes(message);
|
||||
|
||||
if (!isExist) {
|
||||
state.errMsgStack.push(message);
|
||||
|
||||
window.$message?.error({
|
||||
message,
|
||||
onClose: () => {
|
||||
state.errMsgStack = state.errMsgStack.filter(msg => msg !== message);
|
||||
|
||||
setTimeout(() => {
|
||||
state.errMsgStack = [];
|
||||
}, 5000);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
7
src/service/request/type.ts
Normal file
7
src/service/request/type.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export interface RequestInstanceState {
|
||||
/** 刷新 token 的 Promise */
|
||||
refreshTokenPromise: Promise<boolean> | null;
|
||||
/** 请求错误信息栈 */
|
||||
errMsgStack: string[];
|
||||
[key: string]: unknown;
|
||||
}
|
||||
Reference in New Issue
Block a user