From b8561e04c61dee84d988e9404e4584f545499e22 Mon Sep 17 00:00:00 2001 From: xiaopeng <1509442308@qq.com> Date: Wed, 27 May 2026 22:05:08 +0800 Subject: [PATCH] fix: source list scroll, citation targeting, and page UI polish - Replace ScrollArea with native overflow-y-auto for reliable mouse wheel scrolling - Scope source DOM IDs by message ID to fix cross-round citation jumps - Improve profile, settings, forum, knowledge page layouts - Update mobile navigation and chat interface Co-Authored-By: Claude Opus 4.7 --- web/src/app/(auth)/login/page.tsx | 2 +- web/src/app/(auth)/register/page.tsx | 2 +- web/src/app/(main)/admin/forum/page.tsx | 2 +- web/src/app/(main)/admin/knowledge/page.tsx | 8 +- web/src/app/(main)/admin/page.tsx | 13 +- web/src/app/(main)/admin/settings/page.tsx | 15 +- web/src/app/(main)/admin/users/page.tsx | 2 +- web/src/app/(main)/analytics/page.tsx | 24 +- web/src/app/(main)/chat/page.tsx | 11 +- web/src/app/(main)/course-content/page.tsx | 2 +- web/src/app/(main)/forum/page.tsx | 207 ++++++++------- web/src/app/(main)/knowledge/[id]/page.tsx | 24 +- web/src/app/(main)/knowledge/page.tsx | 28 +-- web/src/app/(main)/profile/page.tsx | 226 +++++++---------- web/src/app/(main)/settings/page.tsx | 235 +++++++++--------- .../app/(main)/spatial/text-to-image/page.tsx | 2 +- web/src/app/forum/[categoryId]/page.tsx | 2 +- web/src/app/forum/post/[postId]/page.tsx | 2 +- web/src/components/chat/chat-interface.tsx | 2 +- web/src/components/chat/source-references.tsx | 7 +- web/src/components/layout/mobile-nav.tsx | 51 ++-- web/src/store/chat.ts | 4 +- 22 files changed, 430 insertions(+), 441 deletions(-) diff --git a/web/src/app/(auth)/login/page.tsx b/web/src/app/(auth)/login/page.tsx index 15bc98a..83ff8b1 100644 --- a/web/src/app/(auth)/login/page.tsx +++ b/web/src/app/(auth)/login/page.tsx @@ -76,7 +76,7 @@ export default function LoginPage() { href="/" className="flex items-center justify-center space-x-3 mb-6 group cursor-pointer transition-opacity hover:opacity-80" > -
+
diff --git a/web/src/app/(auth)/register/page.tsx b/web/src/app/(auth)/register/page.tsx index 5830b9f..861dc0c 100644 --- a/web/src/app/(auth)/register/page.tsx +++ b/web/src/app/(auth)/register/page.tsx @@ -87,7 +87,7 @@ export default function RegisterPage() { href="/" className="flex items-center justify-center space-x-3 mb-6 group cursor-pointer transition-opacity hover:opacity-80" > -
+
diff --git a/web/src/app/(main)/admin/forum/page.tsx b/web/src/app/(main)/admin/forum/page.tsx index 55fb47c..96031d6 100644 --- a/web/src/app/(main)/admin/forum/page.tsx +++ b/web/src/app/(main)/admin/forum/page.tsx @@ -193,7 +193,7 @@ export default function ForumAdminPage() { {confirmDelete?.type === "cat" && confirmDelete.id === cat.id ? (
- +
) : ( diff --git a/web/src/app/(main)/admin/knowledge/page.tsx b/web/src/app/(main)/admin/knowledge/page.tsx index 3386e0b..175affc 100644 --- a/web/src/app/(main)/admin/knowledge/page.tsx +++ b/web/src/app/(main)/admin/knowledge/page.tsx @@ -91,8 +91,8 @@ export default function KnowledgeAdminPage() { {kb.is_system ? "系统" : "用户"} @@ -108,7 +108,7 @@ export default function KnowledgeAdminPage() {
@@ -122,7 +122,7 @@ export default function KnowledgeAdminPage() { ) : ( diff --git a/web/src/app/(main)/admin/page.tsx b/web/src/app/(main)/admin/page.tsx index fbebab5..a0b7a3e 100644 --- a/web/src/app/(main)/admin/page.tsx +++ b/web/src/app/(main)/admin/page.tsx @@ -16,12 +16,13 @@ interface DashboardStats { total_generated_images: number; } -function TrendChart({ title, icon: Icon, data, color }: { +function TrendChart({ title, icon: Icon, data, variant }: { title: string; icon: React.ElementType; data: { date: string; count: number }[]; - color: string; + variant?: "default" | "secondary"; }) { + const barClass = variant === "secondary" ? "bg-emerald-500/35" : "bg-primary/35"; return (

@@ -36,7 +37,7 @@ function TrendChart({ title, icon: Icon, data, color }: { return (
{d.count || ""} -
+
{d.date.slice(5)}
); @@ -101,8 +102,8 @@ export default function AdminPage() {
- - + +
{systemStatus && ( @@ -118,7 +119,7 @@ export default function AdminPage() { { label: "嵌入模型", ok: true, sub: systemStatus.embedding_model }, ].map((s) => (
- + {s.label} {s.sub && {s.sub}}
diff --git a/web/src/app/(main)/admin/settings/page.tsx b/web/src/app/(main)/admin/settings/page.tsx index 2ee4a25..a43b505 100644 --- a/web/src/app/(main)/admin/settings/page.tsx +++ b/web/src/app/(main)/admin/settings/page.tsx @@ -77,10 +77,7 @@ export default function SystemSettingsPage() { {statusItems.map((s) => (
- + {s.label}
{s.detail} @@ -115,9 +112,9 @@ export default function SystemSettingsPage() {
{/* Danger zone */} -
-
-

危险操作

+
+
+

危险操作

@@ -126,7 +123,7 @@ export default function SystemSettingsPage() {
重新处理所有知识库文档并建立向量索引
diff --git a/web/src/app/(main)/analytics/page.tsx b/web/src/app/(main)/analytics/page.tsx index ab51dc3..53059b7 100644 --- a/web/src/app/(main)/analytics/page.tsx +++ b/web/src/app/(main)/analytics/page.tsx @@ -188,7 +188,7 @@ export default function AnalyticsPage() {
- +

对话会话

{statistics.total_sessions}

@@ -200,7 +200,7 @@ export default function AnalyticsPage() {
- +

消息总数

{statistics.total_messages}

@@ -212,7 +212,7 @@ export default function AnalyticsPage() {
- +

文档数量

{statistics.total_documents}

@@ -224,7 +224,7 @@ export default function AnalyticsPage() {
- +

活跃天数

{statistics.active_days}

@@ -250,7 +250,7 @@ export default function AnalyticsPage() {
@@ -278,7 +278,7 @@ export default function AnalyticsPage() {

{item.question}

{item.category}

-
{item.count} 次
+
{item.count} 次
))}
@@ -300,11 +300,11 @@ export default function AnalyticsPage() {
总体进度 - {learningReport.learning_progress}% + {learningReport.learning_progress}%
@@ -334,8 +334,8 @@ export default function AnalyticsPage() {
{learningReport.recommendations.map((recommendation, index) => ( -
-
+
+

{recommendation}

))} @@ -355,8 +355,8 @@ export default function AnalyticsPage() {
{learningReport.knowledge_gaps.map((gap, index) => ( -
-
+
+

{gap}

))} diff --git a/web/src/app/(main)/chat/page.tsx b/web/src/app/(main)/chat/page.tsx index 14286b2..64aac59 100644 --- a/web/src/app/(main)/chat/page.tsx +++ b/web/src/app/(main)/chat/page.tsx @@ -14,7 +14,7 @@ import { PanelLeftClose, PanelLeftOpen } from "lucide-react"; export default function ChatPage() { const router = useRouter(); const { isAuthenticated, user, isLoading: authLoading } = useAuthStore(); - const { loadSessions, sessions } = useChatStore(); + const { loadSessions, sessions, selectSession, currentSession } = useChatStore(); const [isInitialized, setIsInitialized] = useState(false); const [sidebarOpen, setSidebarOpen] = useState(true); const [initialLoading, setInitialLoading] = useState(true); @@ -26,7 +26,14 @@ export default function ChatPage() { } if (isAuthenticated && !isInitialized) { - loadSessions().then(() => setInitialLoading(false)); + loadSessions().then(async () => { + setInitialLoading(false); + // Auto-select the most recent session, or do nothing (welcome page) + const store = useChatStore.getState(); + if (!store.currentSession && store.sessions.length > 0) { + await store.selectSession(store.sessions[0].id); + } + }); setIsInitialized(true); } }, [isAuthenticated, authLoading, isInitialized, router, loadSessions]); diff --git a/web/src/app/(main)/course-content/page.tsx b/web/src/app/(main)/course-content/page.tsx index 97c3da2..aed30d3 100644 --- a/web/src/app/(main)/course-content/page.tsx +++ b/web/src/app/(main)/course-content/page.tsx @@ -131,7 +131,7 @@ export default function CourseContentPage() { <> {/* 知识图谱视图 */} {viewMode === 'graph' && ( -
+
)} diff --git a/web/src/app/(main)/forum/page.tsx b/web/src/app/(main)/forum/page.tsx index d2885fe..2ff6a35 100644 --- a/web/src/app/(main)/forum/page.tsx +++ b/web/src/app/(main)/forum/page.tsx @@ -12,43 +12,26 @@ import { ChevronRight, Clock, User, + Plus, } from "lucide-react"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { forumAPI } from "@/lib/api"; import type { ForumCategory, ForumPostSummary } from "@/types"; - -const CATEGORY_ICONS: Record = { - default: , -}; +import { format } from "date-fns"; const CATEGORY_ORDER = ["公告", "通知", "学习", "讨论", "课程", "反馈", "使用"]; function getCategoryIcon(name: string) { if (name.includes("公告") || name.includes("通知")) - return ; + return ; if (name.includes("学习") || name.includes("讨论") || name.includes("课程")) - return ; + return ; if (name.includes("反馈") || name.includes("使用")) - return ; - return CATEGORY_ICONS.default; + return ; + return ; } -function getCategoryAccent(name: string) { - if (name.includes("公告") || name.includes("通知")) return "text-rose-600 dark:text-rose-400"; - if (name.includes("学习") || name.includes("讨论") || name.includes("课程")) return "text-blue-600 dark:text-blue-400"; - if (name.includes("反馈") || name.includes("使用")) return "text-amber-600 dark:text-amber-400"; - return "text-slate-600 dark:text-slate-400"; -} - -function getCategoryBorder(name: string) { - if (name.includes("公告") || name.includes("通知")) return "border-l-rose-500"; - if (name.includes("学习") || name.includes("讨论") || name.includes("课程")) return "border-l-blue-500"; - if (name.includes("反馈") || name.includes("使用")) return "border-l-amber-500"; - return "border-l-slate-500"; -} - -import { format } from "date-fns"; - export default function ForumHomePage() { const [categories, setCategories] = useState([]); const [categoryPosts, setCategoryPosts] = useState< @@ -56,17 +39,30 @@ export default function ForumHomePage() { >({}); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); + const [activeTab, setActiveTab] = useState(""); useEffect(() => { const loadCategories = async () => { try { setIsLoading(true); const data = await forumAPI.getCategories(); - setCategories(data); + const sorted = [...data].sort((a, b) => { + const getOrder = (name: string) => { + for (let i = 0; i < CATEGORY_ORDER.length; i++) { + if (name.includes(CATEGORY_ORDER[i])) return i; + } + return CATEGORY_ORDER.length; + }; + return getOrder(a.name) - getOrder(b.name); + }); + setCategories(sorted); + if (sorted.length > 0) { + setActiveTab(String(sorted[0].id)); + } const postsEntries = await Promise.all( - data.map(async (category) => { + sorted.map(async (category) => { try { - const posts = await forumAPI.getPosts(category.id, 3); + const posts = await forumAPI.getPosts(category.id, 10); return [category.id, posts] as const; } catch { return [category.id, []] as const; @@ -87,69 +83,83 @@ export default function ForumHomePage() { loadCategories(); }, []); - return ( -
-
- {isLoading ? ( + if (isLoading) { + return ( +
+
正在加载社区...
- ) : error ? ( +
+
+ ); + } + + if (error) { + return ( +
+

{error}

- ) : ( -
- {[...categories] - .sort((a, b) => { - const getOrder = (name: string) => { - for (let i = 0; i < CATEGORY_ORDER.length; i++) { - if (name.includes(CATEGORY_ORDER[i])) return i; - } - return CATEGORY_ORDER.length; - }; - return getOrder(a.name) - getOrder(b.name); - }) - .map((category) => { - const posts = categoryPosts[category.id] || []; - return ( -
- {/* Category header */} -
-
- - {getCategoryIcon(category.name)} - -
-

- {category.name} -

- {category.description && ( -

- {category.description} -

- )} -
-
-
- - {category.post_count} 条讨论 - - - 查看全部 - - -
-
+
+
+ ); + } - {/* Posts list */} + return ( +
+
+ + + {categories.map((category) => ( + + {getCategoryIcon(category.name)} + {category.name} + + ))} + + + {categories.map((category) => { + const posts = categoryPosts[category.id] || []; + return ( + + {/* Category description */} + {category.description && ( +

+ {category.description} +

+ )} + + {/* New post button */} +
+ + {category.post_count} 条讨论 + + + + 发表讨论 + +
+ + {/* Posts list */} +
{posts.length > 0 ? ( posts.map((post) => ( @@ -169,7 +179,10 @@ export default function ForumHomePage() { {post.author_name} - {format(new Date(post.created_at), "yyyy/M/d HH:mm")} + {format( + new Date(post.created_at), + "yyyy/M/d HH:mm" + )} @@ -181,16 +194,32 @@ export default function ForumHomePage() { )) ) : ( -
- 暂无讨论,成为第一个发帖的人 +
+ +

+ 暂无讨论,成为第一个发帖的人 +

)}
- ); - })} -
- )} + + {/* View all link */} + {posts.length > 0 && ( +
+ + 查看全部 {category.post_count} 条讨论 + + +
+ )} +
+ ); + })} +
); diff --git a/web/src/app/(main)/knowledge/[id]/page.tsx b/web/src/app/(main)/knowledge/[id]/page.tsx index 9bea8a8..7c67369 100644 --- a/web/src/app/(main)/knowledge/[id]/page.tsx +++ b/web/src/app/(main)/knowledge/[id]/page.tsx @@ -209,7 +209,7 @@ export default function KnowledgeBaseDetailPage() { 返回
- +

{knowledgeBase.name}

@@ -262,7 +262,7 @@ export default function KnowledgeBaseDetailPage() { }} > - @@ -302,17 +302,17 @@ export default function KnowledgeBaseDetailPage() {

- + {file.name} ({(file.size / 1024 / 1024).toFixed(2)} MB)
{error && ( -
{error}
+
{error}
)} {progress > 0 && progress < 100 && ( -
+
)} {progress === 100 && !error && ( -
✓ 上传完成
+
✓ 上传完成
)}
@@ -398,7 +398,7 @@ export default function KnowledgeBaseDetailPage() {
- + {doc.is_processed ? ( - + ) : ( - + )}
- + {doc.title}
@@ -480,7 +480,7 @@ export default function KnowledgeBaseDetailPage() { variant="ghost" size="sm" onClick={() => handleDeleteDocument(doc.id)} - className="text-red-600 hover:text-red-700" + className="text-destructive hover:text-destructive/80" > diff --git a/web/src/app/(main)/knowledge/page.tsx b/web/src/app/(main)/knowledge/page.tsx index 60a0045..5e58e5c 100644 --- a/web/src/app/(main)/knowledge/page.tsx +++ b/web/src/app/(main)/knowledge/page.tsx @@ -144,7 +144,7 @@ export default function KnowledgePage() { {/* 创建知识库按钮 */} - @@ -206,7 +206,7 @@ export default function KnowledgePage() {
- + 0 && (
- +

系统知识库

({systemKBs.length})
{systemKBs.map((kb) => ( - +
- +
{kb.name} @@ -244,9 +244,9 @@ export default function KnowledgePage() {
{kb.document_count > 0 ? ( - + ) : ( - + )}
@@ -263,7 +263,7 @@ export default function KnowledgePage() {
状态 - 0 ? "text-green-600" : "text-gray-500"}> + 0 ? "text-emerald-500" : "text-muted-foreground"}> {kb.document_count > 0 ? "已就绪" : "空知识库"}
@@ -311,7 +311,7 @@ export default function KnowledgePage() {
{systemKBs.length > 0 && (
- +

我的知识库

({userKBs.length})
@@ -322,7 +322,7 @@ export default function KnowledgePage() {
- +
{kb.name} @@ -332,9 +332,9 @@ export default function KnowledgePage() {
{kb.document_count > 0 ? ( - + ) : ( - + )}
@@ -351,7 +351,7 @@ export default function KnowledgePage() {
状态 - 0 ? "text-green-600" : "text-gray-500"}> + 0 ? "text-emerald-500" : "text-muted-foreground"}> {kb.document_count > 0 ? "已就绪" : "空知识库"}
@@ -371,7 +371,7 @@ export default function KnowledgePage() { variant="outline" size="sm" onClick={() => handleDeleteKnowledgeBase(kb.id)} - className="text-red-600 hover:text-red-700" + className="text-destructive hover:text-destructive/80" > diff --git a/web/src/app/(main)/profile/page.tsx b/web/src/app/(main)/profile/page.tsx index dff9e89..6659174 100644 --- a/web/src/app/(main)/profile/page.tsx +++ b/web/src/app/(main)/profile/page.tsx @@ -7,6 +7,7 @@ import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; import { useAuthStore } from "@/store/auth"; import MobileNav from "@/components/layout/mobile-nav"; +import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { @@ -15,11 +16,9 @@ import { Edit2, Save, X, - MessageSquare, - Database, - FileText + User, } from "lucide-react"; -import { authAPI, analyticsAPI } from "@/lib/api"; +import { authAPI } from "@/lib/api"; import { formatDate } from "@/lib/utils"; const profileSchema = z.object({ @@ -37,12 +36,6 @@ export default function ProfilePage() { const [isSaving, setIsSaving] = useState(false); const [error, setError] = useState(null); const [success, setSuccess] = useState(null); - const [statistics, setStatistics] = useState<{ - total_sessions: number; - total_messages: number; - total_documents: number; - active_days: number; - } | null>(null); const { register, @@ -79,17 +72,6 @@ export default function ProfilePage() { setError(null); const userData = await authAPI.getCurrentUser(); setUser(userData); - try { - const stats = await analyticsAPI.getStatistics(); - setStatistics({ - total_sessions: stats.total_sessions || 0, - total_messages: stats.total_messages || 0, - total_documents: stats.total_documents || 0, - active_days: stats.active_days || 0, - }); - } catch (err) { - console.warn("加载统计数据失败:", err); - } } catch (err) { console.error("加载用户信息失败:", err); setError("加载用户信息失败"); @@ -142,139 +124,111 @@ export default function ProfilePage() { const initials = (user.full_name || user.username || "U").charAt(0).toUpperCase(); return ( -
+
{/* 状态提示 */} {error && ( -
{error}
+
{error}
)} {success && ( -
+
{success}
)} -
- {/* 头像与基本信息 */} -
-
-

个人信息

- {!isEditing && ( - - )} -
- - {/* 头像 */} -
-
- {initials} -
-
-

{user.full_name || user.username}

-

{user.email}

-
-
- - {/* 表单 */} -
-
-
- - -

用户名创建后无法修改

+
+ {/* 个人信息卡片 */} + + +
+
+ + 个人信息
-
- - -
-
- -
- - - {errors.email &&

{errors.email.message}

} -
- -
- - -
- - {isEditing && ( -
+ {!isEditing && ( - + )} +
+ 管理您的账户基本信息 +
+ + {/* 头像 + 表单 */} +
+
+ {initials}
- )} - -
+
+

{user.full_name || user.username}

+

{user.email}

+
+
- {/* 学习统计 */} -
-
-

学习统计

-
- {statistics ? ( -
-
- -

{statistics.total_sessions}

-

对话数

+
+
+
+ + +

用户名创建后无法修改

+
+
+ + +
-
- -

{statistics.total_messages}

-

消息数

+ +
+
+ + + {errors.email &&

{errors.email.message}

} +
+
+ + +
-
- -

{statistics.total_documents}

-

文档数

-
-
- -

{statistics.active_days}

-

活跃天数

-
-
- ) : ( -
- -

加载中...

-
- )} -
+ + {isEditing && ( +
+ + +
+ )} + + + +
diff --git a/web/src/app/(main)/settings/page.tsx b/web/src/app/(main)/settings/page.tsx index 018e7dd..a138cf4 100644 --- a/web/src/app/(main)/settings/page.tsx +++ b/web/src/app/(main)/settings/page.tsx @@ -9,6 +9,7 @@ import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; import { useAuthStore } from "@/store/auth"; import MobileNav from "@/components/layout/mobile-nav"; +import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { ThemeToggle } from "@/components/ui/theme-toggle"; @@ -44,9 +45,9 @@ function getPasswordStrength(password: string) { if (/[0-9]/.test(password)) score++; if (/[^a-zA-Z0-9]/.test(password)) score++; - if (score <= 2) return { label: "弱", color: "text-red-600", score }; - if (score <= 4) return { label: "中", color: "text-yellow-600", score }; - return { label: "强", color: "text-green-600", score }; + if (score <= 2) return { label: "弱", color: "text-destructive", score }; + if (score <= 4) return { label: "中", color: "text-amber-500", score }; + return { label: "强", color: "text-emerald-500", score }; } export default function SettingsPage() { @@ -106,140 +107,152 @@ export default function SettingsPage() { } return ( -
+
{/* 状态提示 */} {error && ( -
+
{error}
)} {success && ( -
+
{success}
)} -
+
{/* 账户安全 */} -
-
- -

账户安全

-
-
-
- -
- - -
- {errors.old_password &&

{errors.old_password.message}

} + + +
+ + 账户安全
- -
- -
- - -
- {newPassword && ( -
-
- 密码强度: - {passwordStrength.label} -
-
-
修改您的登录密码 + + + +
+
+ +
+ +
+ {errors.old_password &&

{errors.old_password.message}

}
- )} - {errors.new_password &&

{errors.new_password.message}

} -
-
- -
- +
+ +
+ + +
+ {newPassword && ( +
+
+ 密码强度: + {passwordStrength.label} +
+
+
+
+
+ )} + {errors.new_password &&

{errors.new_password.message}

} +
+
+ +
+ +
+ + +
+ {errors.confirm_password &&

{errors.confirm_password.message}

} +
+ +
- {errors.confirm_password &&

{errors.confirm_password.message}

} -
- -
- -
- -
+ + + {/* 偏好设置 */} -
-
- -

偏好设置

-
-
-
-

外观主题

-

切换浅色或深色模式

+ + +
+ + 偏好设置
- -
-
+ 自定义您的使用体验 + + +
+
+

外观主题

+

切换浅色或深色模式

+
+ +
+
+
diff --git a/web/src/app/(main)/spatial/text-to-image/page.tsx b/web/src/app/(main)/spatial/text-to-image/page.tsx index a58e48e..620b778 100644 --- a/web/src/app/(main)/spatial/text-to-image/page.tsx +++ b/web/src/app/(main)/spatial/text-to-image/page.tsx @@ -120,7 +120,7 @@ export default function TextToImagePage() { transition={{ duration: 0.5 }} className="text-center mb-8" > -

+

文生图 - Text to Image

diff --git a/web/src/app/forum/[categoryId]/page.tsx b/web/src/app/forum/[categoryId]/page.tsx index d559fae..f5db7dc 100644 --- a/web/src/app/forum/[categoryId]/page.tsx +++ b/web/src/app/forum/[categoryId]/page.tsx @@ -130,7 +130,7 @@ export default function ForumCategoryPage() { {isAuthenticated && ( +

- {/* 移动端侧边菜单 */} + {/* Side menu overlay */} {isOpen && (
- {/* 遮罩 */}
setIsOpen(false)} /> - - {/* 菜单内容 */} -
+
- {/* 用户信息 */} -
+ {/* User info */} +
-
- +
+
-

+

{user?.full_name || user?.username}

-

+

{user?.email}

- {/* 导航菜单 */} + {/* Navigation */}
- {/* 底部操作 */} -
+ {/* Bottom actions */} +
{user?.is_superuser && (