fix: 更新API请求方法和参数处理,优化路由组件解析逻辑
- 将`updateAnchor`方法的请求方式改为PUT,`deleteAnchor`方法改为DELETE并使用params传递数据 - 在路由组件中添加`normalizeRouteComponent`和`resolveRouteComponent`函数,增强动态路由解析能力 - 更新多个组件中的ID处理逻辑,确保ID始终为字符串类型 - 修改样式以统一选择框的宽度
This commit is contained in:
@@ -10,8 +10,17 @@ import { useRoutesList } from '/@/stores/routesList';
|
||||
import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
|
||||
import { getUserMenus } from '/@/api/system/menu/index';
|
||||
|
||||
// 扩展Window接口,添加nextLoading属性
|
||||
declare global {
|
||||
interface Window {
|
||||
nextLoading?: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
const layouModules: any = import.meta.glob('../layout/routerView/*.{vue,tsx}');
|
||||
const viewsModules: any = import.meta.glob('../views/**/*.{vue,tsx}');
|
||||
const parentView = layouModules['../layout/routerView/parent.vue'];
|
||||
const notFoundView = viewsModules['../views/error/404.vue'];
|
||||
|
||||
// 后端控制路由
|
||||
|
||||
@@ -22,6 +31,57 @@ const viewsModules: any = import.meta.glob('../views/**/*.{vue,tsx}');
|
||||
*/
|
||||
const dynamicViewsModules: Record<string, Function> = Object.assign({}, { ...layouModules }, { ...viewsModules });
|
||||
|
||||
const normalizeRouteComponent = (component?: string) => {
|
||||
if (!component) return '';
|
||||
return component
|
||||
.trim()
|
||||
.replace(/^\/@\//, '')
|
||||
.replace(/^\//, '')
|
||||
.replace(/^views\//, '')
|
||||
.replace(/\.(vue|tsx)$/i, '')
|
||||
.replace(/\/index$/i, '');
|
||||
};
|
||||
|
||||
const resolveRouteComponent = (component?: string, path?: string, isParent = false) => {
|
||||
const normalizedComponent = normalizeRouteComponent(component);
|
||||
const normalizedPath = normalizeRouteComponent(path);
|
||||
const candidates = [normalizedComponent, normalizedPath].filter(Boolean);
|
||||
|
||||
for (const candidate of candidates) {
|
||||
const exactViewIndexVueKey = `../views/${candidate}/index.vue`;
|
||||
if (dynamicViewsModules[exactViewIndexVueKey]) {
|
||||
return dynamicViewsModules[exactViewIndexVueKey];
|
||||
}
|
||||
|
||||
const exactViewVueKey = `../views/${candidate}.vue`;
|
||||
if (dynamicViewsModules[exactViewVueKey]) {
|
||||
return dynamicViewsModules[exactViewVueKey];
|
||||
}
|
||||
|
||||
const exactViewTsxKey = `../views/${candidate}.tsx`;
|
||||
if (dynamicViewsModules[exactViewTsxKey]) {
|
||||
return dynamicViewsModules[exactViewTsxKey];
|
||||
}
|
||||
|
||||
const exactLayoutVueKey = `../${candidate}.vue`;
|
||||
if (dynamicViewsModules[exactLayoutVueKey]) {
|
||||
return dynamicViewsModules[exactLayoutVueKey];
|
||||
}
|
||||
|
||||
const exactLayoutTsxKey = `../${candidate}.tsx`;
|
||||
if (dynamicViewsModules[exactLayoutTsxKey]) {
|
||||
return dynamicViewsModules[exactLayoutTsxKey];
|
||||
}
|
||||
|
||||
if (candidate === 'layout/routerView/parent') {
|
||||
return parentView;
|
||||
}
|
||||
}
|
||||
|
||||
if (isParent) return parentView;
|
||||
return notFoundView || parentView;
|
||||
};
|
||||
|
||||
/**
|
||||
* 后端控制路由:初始化方法,防止刷新时路由丢失
|
||||
* @method NextLoading 界面 loading 动画开始执行
|
||||
@@ -31,25 +91,18 @@ const dynamicViewsModules: Record<string, Function> = Object.assign({}, { ...lay
|
||||
* @method setFilterMenuAndCacheTagsViewRoutes 设置路由到 vuex routesList 中(已处理成多级嵌套路由)及缓存多级嵌套数组处理后的一维数组
|
||||
*/
|
||||
export async function initBackEndControlRoutes() {
|
||||
// 界面 loading 动画开始执行
|
||||
if (window.nextLoading === undefined) NextLoading.start();
|
||||
// 无 token 停止执行下一步
|
||||
if (!Session.get('token')) return false;
|
||||
// 触发初始化用户信息 pinia
|
||||
// https://gitee.com/lyt-top/vue-next-admin/issues/I5F1HP
|
||||
|
||||
await useUserInfo().setUserInfos();
|
||||
await useUserInfo().setPermissions();
|
||||
// 获取路由菜单数据
|
||||
await getBackEndControlRoutes();
|
||||
let menuRoute = Session.get('userMenu');
|
||||
// 存储接口原始路由(未处理component),根据需求选择使用
|
||||
const menuRoute = Session.get('userMenu');
|
||||
|
||||
useRequestOldRoutes().setRequestOldRoutes(JSON.parse(JSON.stringify(menuRoute)));
|
||||
// 处理路由(component),替换 dynamicRoutes(/@/router/route)第一个顶级 children 的路由
|
||||
dynamicRoutes[0].children = [...defaultDynamicRouteChildren];
|
||||
dynamicRoutes[0].children?.push(...(await backEndComponent(menuRoute)));
|
||||
// 添加动态路由
|
||||
await setAddRoute();
|
||||
// 设置路由到 vuex routesList 中(已处理成多级嵌套路由)及缓存多级嵌套数组处理后的一维数组
|
||||
await setFilterMenuAndCacheTagsViewRoutes();
|
||||
}
|
||||
|
||||
@@ -79,7 +132,7 @@ export function setCacheTagsViewRoutes() {
|
||||
* @returns 返回替换后的路由数组
|
||||
*/
|
||||
export function setFilterRouteEnd() {
|
||||
let filterRouteEnd: any = formatTwoStageRoutes(formatFlatteningRoutes(dynamicRoutes));
|
||||
const filterRouteEnd: any = formatTwoStageRoutes(formatFlatteningRoutes(dynamicRoutes));
|
||||
filterRouteEnd[0].children = [...filterRouteEnd[0].children, ...notFoundAndNoPower];
|
||||
return filterRouteEnd;
|
||||
}
|
||||
@@ -103,8 +156,8 @@ export async function setAddRoute() {
|
||||
* @returns 返回后端路由菜单数据
|
||||
*/
|
||||
export async function getBackEndControlRoutes() {
|
||||
let menuRoute = Session.get('userMenu');
|
||||
let permissions = Session.get('permissions');
|
||||
const menuRoute = Session.get('userMenu');
|
||||
const permissions = Session.get('permissions');
|
||||
if (!menuRoute || !permissions) {
|
||||
await refreshBackEndControlRoutes();
|
||||
}
|
||||
@@ -116,7 +169,6 @@ export async function getBackEndControlRoutes() {
|
||||
* @returns 返回后端路由菜单数据
|
||||
*/
|
||||
export async function refreshBackEndControlRoutes() {
|
||||
// 获取路由
|
||||
await getUserMenus().then((res: any) => {
|
||||
Session.set('userMenu', res.data.menuList);
|
||||
Session.set('permissions', res.data.permissions);
|
||||
@@ -141,51 +193,21 @@ export function setBackEndControlRefreshRoutes() {
|
||||
export function backEndComponent(routes: any) {
|
||||
if (!routes) return [];
|
||||
return routes.map((item: any) => {
|
||||
// 递归处理子路由
|
||||
if (item.children && item.children.length > 0) {
|
||||
const hasChildren = Array.isArray(item.children) && item.children.length > 0;
|
||||
|
||||
if (hasChildren) {
|
||||
item.children = backEndComponent(item.children);
|
||||
// 找到第一个非隐藏的子路由作为重定向
|
||||
const firstVisibleChild = item.children.find((ci: any) => !ci.meta?.isHide);
|
||||
if (firstVisibleChild) {
|
||||
item.redirect = firstVisibleChild.path;
|
||||
}
|
||||
// 确保父级路由有component
|
||||
if (!item.component || item.component === false) {
|
||||
item.component = dynamicViewsModules['../layout/routerView/parent.vue'];
|
||||
}
|
||||
|
||||
const routeComponent = resolveRouteComponent(item.component as string, item.path as string, false);
|
||||
item.component = routeComponent === notFoundView ? parentView : routeComponent;
|
||||
} else {
|
||||
// 确保叶子路由有component
|
||||
let componentFound = false;
|
||||
if (item.component && item.component !== false) {
|
||||
const comp = dynamicImport(dynamicViewsModules, item.component as string);
|
||||
if (comp) {
|
||||
item.component = comp;
|
||||
componentFound = true;
|
||||
}
|
||||
}
|
||||
if (!componentFound) {
|
||||
// 尝试根据path生成component路径
|
||||
const path = item.path.replace(/^\//, '');
|
||||
let comp = dynamicImport(dynamicViewsModules, path);
|
||||
if (!comp) {
|
||||
comp = dynamicImport(dynamicViewsModules, path + '/index');
|
||||
}
|
||||
if (!comp) {
|
||||
// 尝试直接拼接views路径
|
||||
const viewsPath = 'views/' + path + '/index.vue';
|
||||
const directKey = Object.keys(dynamicViewsModules).find((key) => key.includes(viewsPath));
|
||||
if (directKey) {
|
||||
comp = dynamicViewsModules[directKey];
|
||||
}
|
||||
}
|
||||
if (comp) {
|
||||
item.component = comp;
|
||||
} else {
|
||||
// 如果还是找不到,使用一个默认组件
|
||||
item.component = dynamicViewsModules['../layout/routerView/parent.vue'];
|
||||
}
|
||||
}
|
||||
item.component = resolveRouteComponent(item.component as string, item.path as string, false);
|
||||
}
|
||||
|
||||
return item;
|
||||
});
|
||||
}
|
||||
@@ -197,43 +219,27 @@ export function backEndComponent(routes: any) {
|
||||
* @returns 返回处理成函数后的 component
|
||||
*/
|
||||
export function dynamicImport(dynamicViewsModules: Record<string, Function>, component: string) {
|
||||
const normalizedComponent = normalizeRouteComponent(component);
|
||||
if (!normalizedComponent) return false;
|
||||
|
||||
const directViewIndexVueKey = `../views/${normalizedComponent}/index.vue`;
|
||||
if (dynamicViewsModules[directViewIndexVueKey]) return dynamicViewsModules[directViewIndexVueKey];
|
||||
|
||||
const directViewVueKey = `../views/${normalizedComponent}.vue`;
|
||||
if (dynamicViewsModules[directViewVueKey]) return dynamicViewsModules[directViewVueKey];
|
||||
|
||||
const directViewTsxKey = `../views/${normalizedComponent}.tsx`;
|
||||
if (dynamicViewsModules[directViewTsxKey]) return dynamicViewsModules[directViewTsxKey];
|
||||
|
||||
const directLayoutVueKey = `../${normalizedComponent}.vue`;
|
||||
if (dynamicViewsModules[directLayoutVueKey]) return dynamicViewsModules[directLayoutVueKey];
|
||||
|
||||
const directLayoutTsxKey = `../${normalizedComponent}.tsx`;
|
||||
if (dynamicViewsModules[directLayoutTsxKey]) return dynamicViewsModules[directLayoutTsxKey];
|
||||
|
||||
const keys = Object.keys(dynamicViewsModules);
|
||||
|
||||
// 尝试多种匹配方式
|
||||
let matchKeys = keys.filter((key) => {
|
||||
const k = key.replace(/..\/views|../, '');
|
||||
return k.startsWith(`${component}`) || k.startsWith(`/${component}`);
|
||||
});
|
||||
|
||||
// 如果没有匹配到,尝试带index的路径
|
||||
if (matchKeys?.length === 0) {
|
||||
matchKeys = keys.filter((key) => {
|
||||
const k = key.replace(/..\/views|../, '');
|
||||
return k.startsWith(`${component}/index`) || k.startsWith(`/${component}/index`);
|
||||
});
|
||||
}
|
||||
|
||||
// 尝试直接匹配完整路径
|
||||
if (matchKeys?.length === 0) {
|
||||
matchKeys = keys.filter((key) => {
|
||||
return key.includes(component);
|
||||
});
|
||||
}
|
||||
|
||||
// 尝试更宽松的匹配方式
|
||||
if (matchKeys?.length === 0) {
|
||||
matchKeys = keys.filter((key) => {
|
||||
return key.replace(/..\/views\//, '').includes(component.replace(/\//g, ''));
|
||||
});
|
||||
}
|
||||
|
||||
if (matchKeys?.length === 1) {
|
||||
const matchKey = matchKeys[0];
|
||||
return dynamicViewsModules[matchKey];
|
||||
}
|
||||
if (matchKeys?.length > 1) {
|
||||
return false;
|
||||
}
|
||||
const fuzzyKey = keys.find((key) => key.includes(`/${normalizedComponent}/`) || key.includes(`/${normalizedComponent}.`));
|
||||
if (fuzzyKey) return dynamicViewsModules[fuzzyKey];
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user