feat: 业务链条配置管理导航与顶栏用户名统一

业务链条页增加配置管理入口与返回导航;配置管理页通过 aliasPaths 保持侧栏选中;顶栏用户名与设置个人信息页共用 getAccountDisplayName。
This commit is contained in:
fengxiangdebaozi committed 2026-06-16 22:42:42 +08:00
1 parent d8102e8db8
commit 318f6c0c0c
8 files changed
+544 -507

No files matched your search

@@ -6,6 +6,8 @@ import { getStoredAuth } from "@/core/auth";
import { isWujieEnv } from "@/core/embed/wujie";
import {
defaultExpandedIds,
menuItemContainsPath,
menuItemMatchesPath,
type MenuItem,
} from "@/core/page-layout/sidebar-menu";
import { useSidebarMenuItems } from "@/core/page-layout/use-sidebar-menu";
@@ -53,13 +55,7 @@ export function PageSidebarDark({ collapsed, onToggleCollapsed }: PageSidebarDar
}, 180);
};
const hasActiveChild = (item: MenuItem): boolean => {
if (item.path && (pathname === item.path || pathname.startsWith(item.path + "/"))) {
return true;
}
return item.children?.some(hasActiveChild) ?? false;
};
const hasActiveChild = (item: MenuItem): boolean => menuItemContainsPath(item, pathname);
// lazy init:仅在首次 render 计算一次 active id;之后由下面的 useEffect 跟随 pathname 同步
const [activeTopId, setActiveTopId] = useState<string>(
@@ -152,9 +148,9 @@ export function PageSidebarDark({ collapsed, onToggleCollapsed }: PageSidebarDar
const isSidebarItemActive = (item: MenuItem) =>
inWujieEnv
? item.id === activeTopId
: item.path
? pathname === item.path || pathname.startsWith(item.path + "/")
: hasActiveChild(item);
: item.path || item.aliasPaths?.length
? menuItemMatchesPath(item, pathname)
: menuItemContainsPath(item, pathname);
const handleSidebarItemClick = (item: MenuItem) => {
if (inWujieEnv) {
handleTopItemClick(item);
@@ -176,7 +172,9 @@ export function PageSidebarDark({ collapsed, onToggleCollapsed }: PageSidebarDar
{items.map((item) => {
const hasChildren = !!item.children?.length;
const isExpanded = expandedIds.has(item.id);
const isSelected = item.path ? pathname === item.path : hasActiveChild(item);
const isSelected = item.path || item.aliasPaths?.length
? menuItemMatchesPath(item, pathname)
: hasActiveChild(item);
return (
<div
+10 -13
View File
@@ -28,6 +28,8 @@ import { useUnreadCount } from "@/core/notifications";
import {
defaultExpandedIds,
getActiveThirdLevelItems,
menuItemContainsPath,
menuItemMatchesPath,
type MenuItem,
} from "@/core/page-layout/sidebar-menu";
import { useSidebarMenuItems } from "@/core/page-layout/use-sidebar-menu";
@@ -41,12 +43,8 @@ type PageSidebarProps = {
type SettingsSection = "account" | "appearance" | "memory" | "tools" | "about";
const hasActiveChild = (item: MenuItem, pathname: string): boolean => {
if (item.path && (pathname === item.path || pathname.startsWith(item.path + "/"))) {
return true;
}
return item.children?.some((child) => hasActiveChild(child, pathname)) ?? false;
};
const hasActiveChild = (item: MenuItem, pathname: string): boolean =>
menuItemContainsPath(item, pathname);
const findFirstRoutePath = (items?: MenuItem[]): string | null => {
if (!items?.length) {
@@ -116,9 +114,9 @@ function SecondaryNavSidebar() {
const secondaryItems = activeTopItem?.children ?? [];
const isItemActive = (item: MenuItem) =>
item.path
? pathname === item.path || pathname.startsWith(item.path + "/")
: hasActiveChild(item, pathname);
item.path || item.aliasPaths?.length
? menuItemMatchesPath(item, pathname)
: menuItemContainsPath(item, pathname);
const handleItemClick = (item: MenuItem) => {
const path = item.path ?? findFirstRoutePath(item.children);
@@ -211,9 +209,8 @@ function SecondaryNavSidebar() {
<nav className="light-sidebar-subnav" aria-label="三级菜单">
{thirdItems.map((child) => {
const ChildIcon = child.icon;
const childActive = child.path
? pathname === child.path || pathname.startsWith(child.path + "/")
: hasActiveChild(child, pathname);
const childActive = menuItemMatchesPath(child, pathname)
|| (child.children?.length ? menuItemContainsPath(child, pathname) : false);
return (
<button
key={child.id}
@@ -301,7 +298,7 @@ function LegacyAccordionSidebar({
const renderLeaf = (item: MenuItem, depth = 0) => {
const Icon = item.icon;
const isActive = !!item.path && pathname === item.path;
const isActive = menuItemMatchesPath(item, pathname);
return (
<button
@@ -6,7 +6,7 @@ import { toast } from "sonner";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { clearStoredAuth, getStoredAuth } from "@/core/auth";
import { clearStoredAuth, getAccountDisplayName, getStoredAuth } from "@/core/auth";
import { SettingsSection } from "./settings-section";
@@ -37,8 +37,7 @@ export function AccountSettingsPage() {
);
}
const usernameFromEmail = (auth.email ?? "").split("@")[0] ?? "";
const displayName = usernameFromEmail || auth.user_id;
const displayName = getAccountDisplayName(auth);
const handleLogout = () => {
clearStoredAuth();