feat(monitor): 作品栏按博主分组折叠,评论栏改为 博主/作品/评论 三级
先回答现状:跳转作品的按钮本来就有(作品栏每行末尾的外链图标); 评论栏原本是**两级**(作品 -> 评论),第一级是作品不是博主,所以并不是三级。 - MonitorNote 新增 creator_name(爬虫产出的 jsonl 里本来就有昵称,只是没存)。 存的是**已脱敏**的值(张***三),与项目一贯的匿名化姿态一致 —— 爬虫刻意不落原始 user_id(tools/user_hash.py),所以 creator_hash 是唯一稳定的分组依据。 实测该哈希是无盐 sha256,能用任务目标的 external_id 反算配对。 - 入库时刷新 creator_name:作者改昵称是常事,只在首次写一次会一直显示旧的 - 作品栏:按 creator_hash 分组,组头可折叠(默认展开 —— 折叠的默认值不该藏数据), 行内跳转按钮加了 title 说明 - 评论栏:一级博主、二级作品、三级评论。_note_meta_map 补上博主维度, 评论流和作品分组都带上它 - 认不出博主的作品归到「未知博主」,不丢 顺带修一个语法错误:JSX 注释放在三元表达式分支里是非法的(那是子节点语法不是表达式), 移进 div 内。
This commit is contained in:
@@ -7,6 +7,7 @@ import {
|
||||
LayoutList,
|
||||
Rows3,
|
||||
ThumbsUp,
|
||||
Users,
|
||||
} from 'lucide-react'
|
||||
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
@@ -156,6 +157,78 @@ function CollapsibleGroup({
|
||||
)
|
||||
}
|
||||
|
||||
/** 把作品分组按博主归并 —— 三级视图的第一级。 */
|
||||
function groupByCreator(buckets: CommentBucket[]) {
|
||||
const byCreator = new Map<string, { key: string; name: string; buckets: CommentBucket[] }>()
|
||||
for (const bucket of buckets) {
|
||||
const key = bucket.creator_hash || '__unknown__'
|
||||
if (!byCreator.has(key)) {
|
||||
byCreator.set(key, { key, name: bucket.creator_name || '', buckets: [] })
|
||||
}
|
||||
byCreator.get(key)!.buckets.push(bucket)
|
||||
}
|
||||
return [...byCreator.values()]
|
||||
}
|
||||
|
||||
/**
|
||||
* 一级:博主。二级作品、三级评论都收在它下面。
|
||||
*
|
||||
* 分组键是 `creator_hash`(爬虫刻意不落原始 user_id,这是唯一稳定的创作者标识),
|
||||
* 显示名用已脱敏的昵称。默认展开 —— 折叠的默认值不该把数据藏起来。
|
||||
*/
|
||||
function CreatorGroup({
|
||||
name,
|
||||
buckets,
|
||||
expandedNotes,
|
||||
onToggleNote,
|
||||
}: {
|
||||
name: string
|
||||
buckets: CommentBucket[]
|
||||
expandedNotes: Set<string>
|
||||
onToggleNote: (noteId: string) => void
|
||||
}) {
|
||||
const [open, setOpen] = useState(true)
|
||||
const commentCount = buckets.reduce((sum, bucket) => sum + bucket.comments.length, 0)
|
||||
|
||||
return (
|
||||
<div className="rounded-lg border border-cyber-border-DEFAULT overflow-hidden">
|
||||
<button
|
||||
onClick={() => setOpen(!open)}
|
||||
className="w-full flex items-center gap-2 px-3 py-2 bg-cyber-bg-elevated/50 hover:bg-cyber-bg-elevated/80 transition-colors text-left"
|
||||
>
|
||||
{open ? (
|
||||
<ChevronDown className="w-3.5 h-3.5 text-cyber-text-muted flex-shrink-0" />
|
||||
) : (
|
||||
<ChevronRight className="w-3.5 h-3.5 text-cyber-text-muted flex-shrink-0" />
|
||||
)}
|
||||
<Users className="w-3.5 h-3.5 text-cyber-neon-cyan flex-shrink-0" />
|
||||
<span className="font-mono text-xs text-cyber-text-primary truncate">
|
||||
{name || '未知博主'}
|
||||
</span>
|
||||
<span className="text-[10px] font-mono text-cyber-text-muted flex-shrink-0">
|
||||
{buckets.length} 篇作品
|
||||
</span>
|
||||
<Badge variant="outline" className="text-[10px] px-1.5 py-0 flex-shrink-0 ml-auto">
|
||||
{commentCount} 条评论
|
||||
</Badge>
|
||||
</button>
|
||||
|
||||
{open && (
|
||||
<div className="p-2 space-y-2 bg-cyber-bg-secondary/30">
|
||||
{buckets.map((bucket) => (
|
||||
<CollapsibleGroup
|
||||
key={bucket.note_id}
|
||||
bucket={bucket}
|
||||
open={expandedNotes.has(bucket.note_id)}
|
||||
onToggle={() => onToggleNote(bucket.note_id)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export function CommentsFeed({ taskId }: CommentsFeedProps) {
|
||||
const [grouped, setGrouped] = useState(true)
|
||||
const [noteFilter, setNoteFilter] = useState<string>(ALL_NOTES)
|
||||
@@ -267,12 +340,15 @@ export function CommentsFeed({ taskId }: CommentsFeedProps) {
|
||||
</p>
|
||||
) : grouped ? (
|
||||
<div className="space-y-2">
|
||||
{groups?.map((bucket) => (
|
||||
<CollapsibleGroup
|
||||
key={bucket.note_id}
|
||||
bucket={bucket}
|
||||
open={expanded.has(bucket.note_id)}
|
||||
onToggle={() => toggleGroup(bucket.note_id)}
|
||||
{/* 三级:博主 -> 作品 -> 评论。一个任务可以配多个博主,平铺作品的话
|
||||
看不出哪条评论属于谁。 */}
|
||||
{groupByCreator(groups ?? []).map((creator) => (
|
||||
<CreatorGroup
|
||||
key={creator.key}
|
||||
name={creator.name}
|
||||
buckets={creator.buckets}
|
||||
expandedNotes={expanded}
|
||||
onToggleNote={toggleGroup}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user