Files
yunzerwebsiteallinone/website/src/config/nav.ts
T
2026-09-19 21:44:04 +08:00

94 lines
2.9 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.
/**
* 页头导航菜单配置
*
* 数据来源:后端「官网管理 - 导航菜单」(yz_platform_website_nav),
* 由 GET /site/nav 下发(仅启用且显示中的菜单,已按 pid 组好树)。
* 接口异常或后台未配置任何菜单时,回退到 config/site.ts 里的静态 navItems,
* 保证页头导航不会为空。
*
* 菜单类型(与平台端一致):
* 1 目录 仅分组,本身可带 path;配置了子菜单时页头渲染为下拉
* 2 页面 路由地址
* 3 外链 完整 URL,新窗口打开
* 4 单页 路由地址(内容取自「单页管理」)
*/
import { ref } from "vue";
import { getJSON } from "@/api/request";
import { navItems } from "./site";
import { sections } from "./sections";
export interface NavMenuItem {
/** v-for key:后端菜单用 nav-{id},静态回退用 static-{path} */
key: string;
label: string;
path: string;
/** 是否站外链接:后台菜单类型为「外链」或 path 填写了完整 URL */
external: boolean;
children: NavMenuItem[];
}
/** /site/nav 返回的节点结构 */
interface RemoteNavNode {
id: number;
pid: number;
title: string;
type: number;
path: string;
icon?: string;
external?: boolean;
children?: RemoteNavNode[];
}
const isExternalPath = (path: string): boolean => /^https?:\/\//i.test(path);
function toMenuItem(node: RemoteNavNode): NavMenuItem {
const path = node.path || "/";
return {
key: `nav-${node.id}`,
label: node.title || "",
path,
external: node.external ?? (node.type === 3 || isExternalPath(path)),
children: (node.children ?? []).map(toMenuItem),
};
}
/** 静态回退菜单:后台未配置时使用 */
const fallbackMenus = (): NavMenuItem[] =>
navItems.map((item) => {
const menuItem: NavMenuItem = {
key: `static-${item.path}`,
label: item.label,
path: item.path,
external: isExternalPath(item.path),
children: [],
};
// 新闻中心:默认把「新闻中心」下的分类作为二级菜单(鼠标悬停展开)
if (item.path === "/news") {
menuItem.children = sections.news.categories.map((cat) => ({
key: `static-news-${cat.slug}`,
label: cat.name,
path: `/news/category/${cat.slug}`,
external: false,
children: [],
}));
}
return menuItem;
});
/** 页头导航菜单(应用启动时由 loadNavMenus 拉取,初始为静态回退) */
export const navMenus = ref<NavMenuItem[]>(fallbackMenus());
/**
* 拉取后台配置的导航菜单(应用启动时调用一次)。
* 接口异常或后台未配置时保持静态回退菜单,不置空。
*/
export async function loadNavMenus(): Promise<void> {
const data = await getJSON<{ list: RemoteNavNode[] }>("/site/nav");
const list = data?.list ?? [];
if (list.length > 0) {
navMenus.value = list.map(toMenuItem);
}
}