diff --git a/src/api/comments.ts b/src/api/comments.ts index e8d5564..928ca1b 100644 --- a/src/api/comments.ts +++ b/src/api/comments.ts @@ -1,5 +1,5 @@ import apiClient from './client' -import type { Comment, ApiResponse, PaginatedResponse } from '@/types' +import type { Comment, ApiResponse, PaginatedResponse, CommentImage } from '@/types' // 评论查询参数 export interface CommentQueryParams { @@ -24,6 +24,8 @@ export interface CommentDetail extends Comment { post?: { id: string title: string + content?: string + images?: CommentImage[] } ip_address?: string device_info?: string diff --git a/src/components/Layout/Sidebar.tsx b/src/components/Layout/Sidebar.tsx index 9f94751..18b7a27 100644 --- a/src/components/Layout/Sidebar.tsx +++ b/src/components/Layout/Sidebar.tsx @@ -111,7 +111,7 @@ const menuItems: MenuItem[] = [ export default function Sidebar({ collapsed, onCollapse }: SidebarProps) { const { hasAnyRole } = useAuthStore() - const [expandedItems, setExpandedItems] = useState(['学习资料']) + const [expandedItems, setExpandedItems] = useState([]) // 切换展开状态 const toggleExpand = (title: string) => { @@ -178,6 +178,7 @@ export default function Sidebar({ collapsed, onCollapse }: SidebarProps) { cn( 'flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium transition-colors', diff --git a/src/index.css b/src/index.css index 811bc5a..f431598 100644 --- a/src/index.css +++ b/src/index.css @@ -31,3 +31,12 @@ @apply bg-background text-foreground; } } + +@layer utilities { + .text-dynamic-color { + color: var(--dynamic-color); + } + .bg-dynamic-color { + background-color: var(--dynamic-color); + } +} diff --git a/src/pages/Comments.tsx b/src/pages/Comments.tsx index d29b115..c5376b8 100644 --- a/src/pages/Comments.tsx +++ b/src/pages/Comments.tsx @@ -47,6 +47,10 @@ import { AlertTriangle, MessageSquare, ExternalLink, + ThumbsUp, + Check, + Reply, + ImageIcon, } from 'lucide-react' import { format } from 'date-fns' @@ -242,23 +246,30 @@ export default function Comments() { {/* 筛选栏 */} - - - 筛选条件 + + + + + 筛选条件 + 根据条件筛选评论 -
-
- setKeyword(e.target.value)} - onKeyDown={(e) => e.key === 'Enter' && handleSearch()} - /> +
+
+
+ + setKeyword(e.target.value)} + onKeyDown={(e) => e.key === 'Enter' && handleSearch()} + className="pl-10 bg-slate-50 border-slate-200 focus:bg-white" + /> +
- @@ -279,12 +290,17 @@ export default function Comments() { {/* 批量操作栏 */} {selectedIds.length > 0 && ( - +
- - 已选择 {selectedIds.length} 项 - +
+
+ +
+ + 已选择 {selectedIds.length} 项 + +
+ {/* 帖子图片预览 */} + {selectedComment.post.images && selectedComment.post.images.length > 0 && ( +
+ {selectedComment.post.images.slice(0, 3).map((img, index) => ( + { + (e.target as HTMLImageElement).style.display = 'none'; + }} + /> + ))} + {selectedComment.post.images.length > 3 && ( +
+ +{selectedComment.post.images.length - 3} +
+ )} +
+ )} )} + + {/* 回复信息 */} + {selectedComment.reply_to_user && ( +
+ + + 回复给 @{selectedComment.reply_to_user.nickname || selectedComment.reply_to_user.username} + +
+ )} {/* 评论内容 */} -
-
评论内容
-

{selectedComment.content}

+
+
+ + 评论内容 +
+
+

{selectedComment.content}

+
-
- 👍 {selectedComment.like_count} 点赞 + {/* 评论图片 */} + {selectedComment.images && selectedComment.images.length > 0 && ( +
+
+ + 评论图片 ({selectedComment.images.length}张) +
+
+ {selectedComment.images.map((img, index) => ( +
+ {`图片 { + (e.target as HTMLImageElement).src = 'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 24 24" fill="none" stroke="%239ca3af" stroke-width="1"%3E%3Crect x="3" y="3" width="18" height="18" rx="2" ry="2"/%3E%3Ccircle cx="8.5" cy="8.5" r="1.5"/%3E%3Cpolyline points="21 15 16 10 5 21"/%3E%3C/svg%3E'; + (e.target as HTMLImageElement).classList.add('p-4'); + }} + /> +
+
+ ))} +
+
+ )} + + {/* 统计数据 */} +
+
+
+ +
+
+
{selectedComment.likes_count}
+
点赞
+
+
-
- 评论时间:{formatDate(selectedComment.created_at)} + {/* 时间信息 */} +
+ 评论时间:{formatDate(selectedComment.created_at)} + {selectedComment.updated_at !== selectedComment.created_at && ( + 更新于:{formatDate(selectedComment.updated_at)} + )}
) : null} diff --git a/src/pages/MaterialSubjects.tsx b/src/pages/MaterialSubjects.tsx index b932370..f1f9636 100644 --- a/src/pages/MaterialSubjects.tsx +++ b/src/pages/MaterialSubjects.tsx @@ -123,7 +123,7 @@ export default function MaterialSubjects() { setLoading(true) try { const response = await subjectsApi.getSubjects() - const list = response.data.data + const list = response.data.data || [] setSubjects(list) } catch (error) { console.error('Failed to load subjects:', error) @@ -273,13 +273,13 @@ export default function MaterialSubjects() { {subject.sort_order} - + {subject.name}
@@ -302,6 +302,7 @@ export default function MaterialSubjects() { variant="ghost" size="icon" onClick={() => handleOpenEdit(subject)} + title="编辑" > @@ -309,6 +310,7 @@ export default function MaterialSubjects() { variant="ghost" size="icon" onClick={() => handleOpenDelete(subject)} + title="删除" > @@ -370,6 +372,7 @@ export default function MaterialSubjects() { ? 'border-primary bg-primary/10' : 'border-muted hover:border-muted-foreground' }`} + title={iconName} > @@ -386,12 +389,12 @@ export default function MaterialSubjects() { key={color.value} type="button" onClick={() => setFormData({ ...formData, color: color.value })} - className={`w-8 h-8 rounded-full border-2 transition-colors ${ + className={`w-8 h-8 rounded-full border-2 transition-colors bg-dynamic-color ${ formData.color === color.value ? 'border-primary scale-110' : 'border-transparent hover:scale-105' }`} - style={{ backgroundColor: color.value }} + style={{ '--dynamic-color': color.value } as React.CSSProperties} title={color.name} /> ))} @@ -427,6 +430,7 @@ export default function MaterialSubjects() { checked={formData.is_active ?? true} onChange={(e) => setFormData({ ...formData, is_active: e.target.checked })} className="rounded" + aria-label="启用此学科" />
diff --git a/src/pages/Posts.tsx b/src/pages/Posts.tsx index 35d8239..0a329f6 100644 --- a/src/pages/Posts.tsx +++ b/src/pages/Posts.tsx @@ -50,6 +50,12 @@ import { X, Loader2, AlertTriangle, + ImageIcon, + ThumbsUp, + MessageCircle, + Eye as EyeIcon, + Pin, + Star, } from 'lucide-react' import { format } from 'date-fns' @@ -298,23 +304,30 @@ export default function Posts() {
{/* 筛选栏 */} - - - 筛选条件 + + + + + 筛选条件 + 根据条件筛选帖子 -
-
- setKeyword(e.target.value)} - onKeyDown={(e) => e.key === 'Enter' && handleSearch()} - /> +
+
+
+ + setKeyword(e.target.value)} + onKeyDown={(e) => e.key === 'Enter' && handleSearch()} + className="pl-10 bg-slate-50 border-slate-200 focus:bg-white" + /> +
- @@ -335,18 +348,24 @@ export default function Posts() { {/* 批量操作栏 */} {selectedIds.length > 0 && ( - +
- - 已选择 {selectedIds.length} 项 - +
+
+ +
+ + 已选择 {selectedIds.length} 项 + +