feat: 类目管理

This commit is contained in:
2025-10-21 13:56:51 +08:00
parent 1e5ea1879b
commit 476ee7a754
155 changed files with 9496 additions and 1026 deletions

View File

@@ -1,34 +1,29 @@
import type { Settings as LayoutSettings } from '@ant-design/pro-components';
import { SettingDrawer } from '@ant-design/pro-components';
import type { RequestConfig, RunTimeLayoutConfig } from '@umijs/max';
import { history, Navigate } from '@umijs/max';
import { Spin } from 'antd';
import React from 'react';
import type { Settings as LayoutSettings } from "@ant-design/pro-components";
import { SettingDrawer } from "@ant-design/pro-components";
import type { RequestConfig, RunTimeLayoutConfig } from "@umijs/max";
import { history } from "@umijs/max";
import {
AvatarDropdown,
AvatarName,
Footer,
Question,
SelectLang,
} from '@/components';
import { getInfo } from '@/services/login';
import type { UserInfoVO } from '@/services/login/types';
import defaultSettings from '../config/defaultSettings';
import { errorConfig } from './requestErrorConfig';
import '@ant-design/v5-patch-for-react-19';
import { useDictStore } from '@/hooks/stores/dict';
import { getAccessToken, getTenantId } from '@/utils/auth';
import { CACHE_KEY, useCache } from './hooks/web/useCache';
import type { MenuVO } from './services/system/menu';
import { loopMenuItem } from './utils/menuUtils';
} from "@/components";
import { getInfo } from "@/services/login";
import type { UserInfoVO } from "@/services/login/types";
import defaultSettings from "../config/defaultSettings";
import { errorConfig } from "./requestErrorConfig";
import "@ant-design/v5-patch-for-react-19";
import { useDictStore } from "@/hooks/stores/dict";
import { getAccessToken, getTenantId } from "@/utils/auth";
import { CACHE_KEY, useCache } from "./hooks/web/useCache";
import type { MenuVO } from "./services/system/menu";
import { loopMenuItem } from "./utils/menuUtils";
const isDev = process.env.NODE_ENV === 'development';
const isDev = process.env.NODE_ENV === "development";
const isDevOrTest = isDev || process.env.CI;
const loginPath = '/user/login';
const loginPath = "/user/login";
// 全局存储菜单数据和路由映射
const dynamicRoutesAdded = false;
// 标记是否已添加动态路由
/**
* @see https://umijs.org/docs/api/runtime-config#getinitialstate
@@ -47,7 +42,7 @@ export async function getInitialState(): Promise<{
try {
const token = getAccessToken();
if (!token) {
throw new Error('No token found');
throw new Error("No token found");
}
const data = await getInfo();
wsCache.set(CACHE_KEY.USER, data);
@@ -69,8 +64,8 @@ export async function getInitialState(): Promise<{
const { location } = history;
if (
![loginPath, '/user/register', '/user/register-result'].includes(
location.pathname,
![loginPath, "/user/register", "/user/register-result"].includes(
location.pathname
)
) {
const currentUser = wsCache.get(CACHE_KEY.USER);
@@ -127,22 +122,22 @@ export const layout: RunTimeLayoutConfig = ({
},
bgLayoutImgList: [
{
src: 'https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/D2LWSqNny4sAAAAAAAAAAAAAFl94AQBr',
src: "https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/D2LWSqNny4sAAAAAAAAAAAAAFl94AQBr",
left: 85,
bottom: 100,
height: '303px',
height: "303px",
},
{
src: 'https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/C2TWRpJpiC0AAAAAAAAAAAAAFl94AQBr',
src: "https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/C2TWRpJpiC0AAAAAAAAAAAAAFl94AQBr",
bottom: -68,
right: -45,
height: '303px',
height: "303px",
},
{
src: 'https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/F6vSTbj8KpYAAAAAAAAAAAAAFl94AQBr',
src: "https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/F6vSTbj8KpYAAAAAAAAAAAAAFl94AQBr",
bottom: 0,
left: 0,
width: '331px',
width: "331px",
},
],
menuHeaderRender: undefined,
@@ -180,30 +175,57 @@ export const layout: RunTimeLayoutConfig = ({
* @doc https://umijs.org/docs/max/request#配置
*/
export const request: RequestConfig = {
baseURL: isDev ? '' : 'https://proapi.azurewebsites.net',
baseURL: isDev ? "" : "https://proapi.azurewebsites.net",
...errorConfig,
// 添加请求拦截器
requestInterceptors: [
(url, options) => {
// 为所有请求添加 API 前缀
if (url && !url.startsWith(process.env.API_PREFIX || '/admin-api')) {
url = (process.env.API_PREFIX || '/admin-api') + url;
if (url && !url.startsWith(process.env.API_PREFIX || "/admin-api")) {
url = (process.env.API_PREFIX || "/admin-api") + url;
}
// 获取存储在本地的 token 和 tenantId
const token = getAccessToken();
const tenantId = getTenantId(); // 默认租户ID为1
const contentType: string = options.headers?.["Content-Type"] as string;
// 设置统一的请求头
const headers: Record<string, string> = {
...options.headers,
Accept: '*',
'tenant-id': tenantId,
Accept: "*",
"tenant-id": tenantId,
};
// 如果有token则添加Authorization头
if (token) {
headers.Authorization = `Bearer ${getAccessToken()}`;
headers["Content-Type"] = contentType || "application/json";
}
return { url, options: { ...options, headers } };
},
// requestInterceptors: [
// (url, options) => {
// // 为所有请求添加 API 前缀
// if (url && !url.startsWith(process.env.API_PREFIX || "/admin-api")) {
// url = (process.env.API_PREFIX || "/admin-api") + url;
// }
// // 获取存储在本地的 token 和 tenantId
// const token = getAccessToken();
// const tenantId = getTenantId(); // 默认租户ID为1
// console.log("request", options);
// // 设置统一的请求头
// const contentType: string = options.headers?.["Content-Type"] as string;
// const headers: Record<string, string> = {
// ...options.headers,
// Accept: "*",
// "Content-Type": contentType || "application/json",
// "tenant-id": tenantId,
// };
// // 如果有token则添加Authorization头
// if (token) {
// headers.Authorization = `Bearer ${getAccessToken()}`;
// }
// console.log("headers", headers);
// return { url, options: { ...options, ...headers } };
// },
],
// 添加参数序列化配置
@@ -212,7 +234,7 @@ export const request: RequestConfig = {
const appendParams = (key: string, value: any) => {
if (Array.isArray(value)) {
// 特殊处理 createTime 数组,转换为 createTime[0] 和 createTime[1] 格式
if (key === 'createTime') {
if (key === "createTime") {
value.forEach((val, index) => {
searchParams.append(`${key}[${index}]`, val);
});
@@ -250,7 +272,7 @@ export async function patchClientRoutes({ routes }: any) {
wsCache.set(CACHE_KEY.ROLE_ROUTERS, data.menus);
menus = data.menus;
} catch (error) {
console.error('获取菜单失败:', error);
console.error("获取菜单失败:", error);
return;
}
}
@@ -258,7 +280,7 @@ export async function patchClientRoutes({ routes }: any) {
if (!menus || menus.length === 0) {
return;
}
const routerIndex = routes.findIndex((item: any) => item.path === '/');
const routerIndex = routes.findIndex((item: any) => item.path === "/");
const parentId = routes[routerIndex].id;
if (menus) {