feat: 简介模式菜单按类型 A/B 分套,兼容未配置的旧部署

两套网页可通过 runtime-config.js 的 VITE_COMPACT_MENU_TYPE 加载各自左侧菜单;缺省或旧页面不传参数时仍读取原来的类型 A 数据。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
董宏凯andCursor committed 2026-08-19 16:59:34 +08:00
1 parent 5e1765d889
commit acf538ac01
21 files changed
+610 -103

No files matched your search

+49 -9
View File
@@ -78,9 +78,13 @@ import {
type MenuOverride,
type MergedMenuNode,
} from "@/core/page-layout/menu-overrides";
import type {
CompactMenuOverride,
CompactMenuPlacement,
import {
COMPACT_MENU_TYPES,
COMPACT_MENU_TYPE_LABELS,
getRuntimeCompactMenuType,
type CompactMenuOverride,
type CompactMenuPlacement,
type CompactMenuType,
} from "@/core/page-layout/compact-menu-overrides";
import { sidebarMenuItems, type MenuItem } from "@/core/page-layout/sidebar-menu";
import { injectLightApps } from "@/core/page-layout/use-sidebar-menu";
@@ -975,8 +979,10 @@ export default function MenuManagementPage() {
}
function CompactMenuManagementPanel({ baseTree }: { baseTree: MenuItem[] }) {
const { data: overrides = [], isLoading } = useCompactMenuOverrides();
const { save } = useCompactMenuOverrideActions();
const runtimeType = getRuntimeCompactMenuType();
const [menuType, setMenuType] = useState<CompactMenuType>(runtimeType);
const { data: overrides = [], isLoading } = useCompactMenuOverrides(menuType);
const { save } = useCompactMenuOverrideActions(menuType);
const initialRows = useMemo(() => compactRowsFromTree(baseTree, overrides), [baseTree, overrides]);
const [rows, setRows] = useState<CompactRow[]>(initialRows);
const [loadedKey, setLoadedKey] = useState("");
@@ -988,8 +994,9 @@ function CompactMenuManagementPanel({ baseTree }: { baseTree: MenuItem[] }) {
(top.children ?? []).map((child) => [top.id, child.id, child.label]),
),
overrides,
menuType,
}),
[baseTree, overrides],
[baseTree, overrides, menuType],
);
useEffect(() => {
if (sourceKey !== loadedKey) {
@@ -1031,17 +1038,23 @@ function CompactMenuManagementPanel({ baseTree }: { baseTree: MenuItem[] }) {
const handleSave = async () => {
try {
await save.mutateAsync(currentOverrides);
toast.success("简介菜单配置已保存");
toast.success(`简介菜单配置已保存(${COMPACT_MENU_TYPE_LABELS[menuType]})`);
} catch (err) {
toast.error(err instanceof Error ? err.message : "保存失败");
}
};
const handleReset = () => {
if (!confirm("确定要重置简介模式菜单为默认布局吗?保存后将清除简介模式自定义配置。")) return;
if (!confirm(`确定要重置${COMPACT_MENU_TYPE_LABELS[menuType]}的简介模式菜单为默认布局吗?保存后将清除该类型的自定义配置。`)) return;
setRows(compactRowsFromTree(baseTree, []));
};
const switchMenuType = (next: CompactMenuType) => {
if (next === menuType) return;
if (dirty && !confirm("当前类型有未保存的修改,切换后将丢失。确定切换吗?")) return;
setMenuType(next);
};
return (
<>
<div className="relative mb-6 overflow-hidden rounded-3xl border border-slate-200/60 bg-white p-6 shadow-sm md:p-8">
@@ -1082,9 +1095,36 @@ function CompactMenuManagementPanel({ baseTree }: { baseTree: MenuItem[] }) {
</button>
</div>
</div>
<div className="mb-4 flex flex-wrap items-center gap-3">
<div className="inline-flex rounded-2xl border border-slate-200 bg-slate-50 p-1 text-sm font-semibold">
{COMPACT_MENU_TYPES.map((type) => (
<button
key={type}
type="button"
onClick={() => switchMenuType(type)}
className={`rounded-xl px-4 py-1.5 transition-all ${
menuType === type ? "bg-red-600 text-white shadow-sm" : "text-slate-500 hover:text-slate-800"
}`}
>
{COMPACT_MENU_TYPE_LABELS[type]}
{runtimeType === type ? (
<span className={`ml-1.5 text-[10px] font-medium ${menuType === type ? "text-white/80" : "text-slate-400"}`}>
当前网页
</span>
) : null}
</button>
))}
</div>
</div>
<p className="flex max-w-2xl items-start gap-2.5 rounded-2xl border border-slate-200/50 bg-slate-50/70 p-3.5 text-sm leading-relaxed text-slate-600">
<Info className="mt-0.5 size-4 shrink-0 text-slate-400" />
<span>这里配置的是简介模式工作区左侧菜单:可改显示名称、调整顺序,或迁移到「设置和更多」下拉中;全量模式菜单不受影响。</span>
<span>
这里配置的是简介模式工作区左侧菜单,按类型 A / B 分套保存。两套网页在{" "}
<code className="rounded bg-slate-200/70 px-1 py-0.5 text-xs">runtime-config.js</code> 里填写{" "}
<code className="rounded bg-slate-200/70 px-1 py-0.5 text-xs">VITE_COMPACT_MENU_TYPE</code> 为 A 或 B
即可加载对应配置;全量模式菜单不受影响。当前网页正在使用
{COMPACT_MENU_TYPE_LABELS[runtimeType]}。
</span>
</p>
</div>
</div>