feat(monitor): 博主组头补上指标合计与本轮增量
折叠之后组头只有「N 篇」,等于把信息藏了起来 —— 折叠应该意味着「收起来但仍可一眼读到」, 而不是「看不见」。现在组头与数据行列对齐,每个指标列给出该博主的合计,下面再带本轮增量 (那才是监控真正要看的)。 合计口径与项目一致:某个指标在所有作品上都是 null 时,合计是 null 而不是 0 —— 「0」是真实值、「null」是不知道,合计成 0 会让「还没采到」看起来像「互动为零」。
This commit is contained in:
@@ -39,6 +39,41 @@ const METRIC_COLUMNS: Array<{ key: keyof NoteMetrics; label: string }> = [
|
||||
{ key: 'share_count', label: '分享' },
|
||||
]
|
||||
|
||||
/**
|
||||
* 一个博主名下所有作品的指标合计。
|
||||
*
|
||||
* **全为 null 时结果是 null 而不是 0** —— 与项目一贯的口径一致:「0」是真实值,
|
||||
* 「null」是不知道。合计成 0 会让"还没采到"看起来像"互动为零"。
|
||||
*/
|
||||
function sumMetrics(notes: MonitorNote[]) {
|
||||
const values: Record<string, number | null> = {}
|
||||
const deltas: Record<string, number | null> = {}
|
||||
|
||||
for (const column of METRIC_COLUMNS) {
|
||||
let sum = 0
|
||||
let sawValue = false
|
||||
let deltaSum = 0
|
||||
let sawDelta = false
|
||||
|
||||
for (const note of notes) {
|
||||
const value = note.metrics[column.key]
|
||||
if (value !== null && value !== undefined) {
|
||||
sum += value
|
||||
sawValue = true
|
||||
}
|
||||
const delta = note.deltas[column.key]
|
||||
if (delta !== null && delta !== undefined) {
|
||||
deltaSum += delta
|
||||
sawDelta = true
|
||||
}
|
||||
}
|
||||
|
||||
values[column.key] = sawValue ? sum : null
|
||||
deltas[column.key] = sawDelta ? deltaSum : null
|
||||
}
|
||||
return { values, deltas }
|
||||
}
|
||||
|
||||
// 多出来的那个空列给展开箭头;分组表头会跨掉整行。
|
||||
const COLUMN_COUNT = METRIC_COLUMNS.length + 4
|
||||
|
||||
@@ -112,8 +147,11 @@ export function NotesTable({ taskId, onlyNew }: NotesTableProps) {
|
||||
<tbody>
|
||||
{groups.map((group) => {
|
||||
const isCollapsed = collapsed.has(group.key)
|
||||
const totals = sumMetrics(group.notes)
|
||||
return (
|
||||
<Fragment key={group.key}>
|
||||
{/* 组头与数据行**列对齐**:每个指标列给出该博主的合计,下面再带本轮增量。
|
||||
折叠之后如果什么都看不到,那折叠就只是把信息藏起来了。 */}
|
||||
<tr
|
||||
onClick={() => toggleCreator(group.key)}
|
||||
className="border-t border-cyber-border-subtle bg-cyber-bg-tertiary/50 cursor-pointer hover:bg-cyber-bg-elevated/50"
|
||||
@@ -125,18 +163,25 @@ export function NotesTable({ taskId, onlyNew }: NotesTableProps) {
|
||||
<ChevronDown className="w-3 h-3" />
|
||||
)}
|
||||
</td>
|
||||
<td colSpan={COLUMN_COUNT - 1} className="py-1.5 px-2">
|
||||
<td className="py-1.5 px-2">
|
||||
<span className="flex items-center gap-1.5">
|
||||
<Users className="w-3 h-3 text-cyber-neon-cyan" />
|
||||
<span className="text-cyber-text-primary">
|
||||
{group.name || '未知博主'}
|
||||
</span>
|
||||
<span className="text-cyber-text-muted">{group.notes.length} 篇</span>
|
||||
{isCollapsed && (
|
||||
<span className="text-cyber-text-muted">(已折叠)</span>
|
||||
)}
|
||||
</span>
|
||||
</td>
|
||||
{METRIC_COLUMNS.map((column) => (
|
||||
<td key={column.key} className="py-1.5 px-2">
|
||||
<MetricCell
|
||||
value={totals.values[column.key]}
|
||||
delta={totals.deltas[column.key]}
|
||||
/>
|
||||
</td>
|
||||
))}
|
||||
<td />
|
||||
<td />
|
||||
</tr>
|
||||
|
||||
{!isCollapsed &&
|
||||
|
||||
Reference in New Issue
Block a user