'use client';
import { useMemo, useState } from 'react';
import Link from 'next/link';
import {
AlertTriangle,
Check,
Clipboard,
ExternalLink,
Flame,
Lightbulb,
Link2,
Radar,
Target,
UserRoundCheck,
} from 'lucide-react';
import type { ReactNode } from 'react';
export interface DashboardSignalItem {
chatroom_id: string;
chat_name: string;
local_id: number;
sender: string;
time: string;
title: string;
snippet: string;
score: number;
reasons: string[];
}
export interface DashboardOpportunityItem extends DashboardSignalItem {
action: string;
}
export interface DashboardActionItem extends DashboardOpportunityItem {
why: string;
urgency: 'high' | 'medium' | 'low';
}
export interface DashboardSignalSource {
sender: string;
signal_count: number;
group_count: number;
top_group: string;
last_seen: string;
strengths: string[];
}
export interface DashboardTopicLifecycle {
title: string;
status: 'rising' | 'spreading' | 'hot' | 'cooling';
today_count: number;
previous_avg: number;
group_count: number;
reason: string;
keywords: string[];
}
export interface DashboardLinkHighlight {
kind: 'article' | 'tool';
title: string;
url: string;
domain: string;
score: number;
verdict: string;
count: number;
group_count: number;
last_seen: string;
}
export interface DashboardPeopleRadar {
sender: string;
role: '分享者' | '需求提出者' | '连接者' | '观点源';
score: number;
group_count: number;
signal_count: number;
top_group: string;
reason: string;
}
export interface DashboardContentIdea {
title: string;
angle: string;
suggested_channel: '公众号' | 'X' | '小红书' | '博客';
evidence: string;
source_count: number;
}
export interface DashboardAnomalySignal {
kind: 'spike' | 'cross_group' | 'dense_links' | 'quiet_day';
title: string;
description: string;
severity: 'high' | 'medium' | 'low';
href?: string;
}
export interface DashboardIntelligence {
date: string;
must_read: DashboardSignalItem[];
opportunities: DashboardOpportunityItem[];
signal_sources: DashboardSignalSource[];
action_items: DashboardActionItem[];
topic_lifecycle: DashboardTopicLifecycle[];
link_highlights: DashboardLinkHighlight[];
people_radar: DashboardPeopleRadar[];
content_ideas: DashboardContentIdea[];
anomalies: DashboardAnomalySignal[];
}
export default function IntelligenceBrief({ intelligence }: { intelligence?: DashboardIntelligence }) {
const [copied, setCopied] = useState(false);
const data =
intelligence ??
({
date: '',
must_read: [],
opportunities: [],
signal_sources: [],
action_items: [],
topic_lifecycle: [],
link_highlights: [],
people_radar: [],
content_ideas: [],
anomalies: [],
} satisfies DashboardIntelligence);
const summary = useMemo(() => buildDailySummary(data), [data]);
async function copySummary() {
await navigator.clipboard.writeText(summary);
setCopied(true);
window.setTimeout(() => setCopied(false), 1200);
}
return (
Briefing Note
今日情报简报
{summary.split('\n').slice(1, 4).join(' · ')}
);
}
function ActionPanel({
date,
items,
fallback,
}: {
date: string;
items: DashboardActionItem[];
fallback: DashboardOpportunityItem[];
}) {
const displayItems =
items.length > 0
? items
: fallback.map((item) => ({
...item,
why: '包含明确需求或行动线索,适合进入上下文判断',
urgency: 'medium' as const,
}));
return (
}
title="今日值得出手"
meta={`${displayItems.length} 条`}
/>
{displayItems.length === 0 ? (
) : (
{displayItems.slice(0, 6).map((item) => (
{item.action}
{urgencyText(item.urgency)}
{item.title}
{item.why}
))}
)}
);
}
function TopicLifecyclePanel({ topics }: { topics: DashboardTopicLifecycle[] }) {
return (
}
title="趋势升温"
meta={`${topics.length} 个话题`}
/>
{topics.length === 0 ? (
) : (
{topics.slice(0, 6).map((topic) => (
{topic.title}
{topic.reason}
{topicStatusText(topic.status)}
{topic.today_count} 条
{topic.group_count} 群
均值 {topic.previous_avg}
))}
)}
);
}
function AnomalyPanel({ anomalies }: { anomalies: DashboardAnomalySignal[] }) {
return (
}
title="异常信号"
meta={`${anomalies.length} 条`}
/>
{anomalies.length === 0 ? (
) : (
{anomalies.slice(0, 6).map((item) => {
const body = (
<>
{item.title}
{severityText(item.severity)}
{item.description}
>
);
return item.href ? (
{body}
) : (
{body}
);
})}
)}
);
}
function LinkHighlightPanel({ items }: { items: DashboardLinkHighlight[] }) {
return (
}
title="链接精选"
meta={`${items.length} 条`}
/>
{items.length === 0 ? (
) : (
)}
);
}
function PeopleRadarPanel({
people,
fallback,
}: {
people: DashboardPeopleRadar[];
fallback: DashboardSignalSource[];
}) {
const displayPeople =
people.length > 0
? people
: fallback.map((source) => ({
sender: source.sender,
role: '分享者' as const,
score: source.signal_count,
group_count: source.group_count,
signal_count: source.signal_count,
top_group: source.top_group,
reason: `${source.signal_count} 条高信号`,
}));
return (
}
title="人物雷达"
meta={`${displayPeople.length} 人`}
/>
{displayPeople.length === 0 ? (
) : (
{displayPeople.slice(0, 7).map((person, index) => (
{index + 1}
{person.sender}
{person.role} · {person.reason}
{person.score}
{person.group_count} 群
))}
)}
);
}
function ContentIdeaPanel({ ideas }: { ideas: DashboardContentIdea[] }) {
return (
}
title="内容选题"
meta={`${ideas.length} 个`}
/>
{ideas.length === 0 ? (
) : (
{ideas.slice(0, 6).map((idea) => (
{idea.title}
{idea.suggested_channel}
{idea.angle}
证据:{idea.evidence}
))}
)}
);
}
function MustReadPanel({ date, items }: { date: string; items: DashboardSignalItem[] }) {
return (
}
title="最值得关注"
meta={`${items.length} 条高信号`}
/>
{items.length === 0 ? (
) : (
{items.slice(0, 5).map((item, index) => (
))}
)}
);
}
function SignalRow({
item,
date,
rank,
}: {
item: DashboardSignalItem;
date: string;
rank: number;
}) {
return (
{rank}
{item.title}
{item.score}
{item.chat_name} · {item.sender}
{item.time.slice(11)}
{item.reasons.slice(0, 3).map((reason) => (
{reason}
))}
);
}
function PanelTitle({ icon, title, meta }: { icon: ReactNode; title: string; meta: string }) {
return (
);
}
function EmptyState({ text }: { text: string }) {
return (
{text}
);
}
function buildDailySummary(data: DashboardIntelligence): string {
const lines = [`${data.date || '今日'} 情报摘要`];
lines.push(`出手:${data.action_items.slice(0, 3).map((item) => `${item.action}|${item.title}`).join(';') || '暂无'}`);
lines.push(`趋势:${data.topic_lifecycle.slice(0, 3).map((topic) => `${topic.title}(${topicStatusText(topic.status)})`).join(';') || '暂无'}`);
lines.push(
`链接:${data.link_highlights.slice(0, 3).map((item) => item.title).join(';') || '暂无'}`,
);
lines.push(
`异常:${data.anomalies.slice(0, 2).map((item) => item.title).join(';') || '暂无'}`,
);
return lines.join('\n');
}
function urgencyText(urgency: DashboardActionItem['urgency']): string {
if (urgency === 'high') return '高';
if (urgency === 'medium') return '中';
return '低';
}
function urgencyClass(urgency: DashboardActionItem['urgency']): string {
const base = 'shrink-0 rounded px-1.5 py-0.5 text-[10px]';
if (urgency === 'high') return `${base} bg-[var(--warn-soft)] text-[var(--warn)]`;
if (urgency === 'medium') return `${base} bg-[var(--accent-soft)] text-[var(--accent)]`;
return `${base} bg-[var(--surface-2)] text-[var(--text-3)]`;
}
function topicStatusText(status: DashboardTopicLifecycle['status']): string {
if (status === 'spreading') return '扩散';
if (status === 'rising') return '升温';
if (status === 'cooling') return '退潮';
return '高热';
}
function topicStatusClass(status: DashboardTopicLifecycle['status']): string {
const base = 'shrink-0 rounded px-1.5 py-0.5 text-[10px]';
if (status === 'spreading') return `${base} bg-[var(--accent-soft)] text-[var(--accent)]`;
if (status === 'rising') return `${base} bg-[var(--warn-soft)] text-[var(--warn)]`;
if (status === 'cooling') return `${base} bg-[var(--surface-2)] text-[var(--text-3)]`;
return `${base} bg-[var(--surface-2)] text-[var(--text-2)]`;
}
function severityText(severity: DashboardAnomalySignal['severity']): string {
if (severity === 'high') return '高';
if (severity === 'medium') return '中';
return '低';
}
function severityClass(severity: DashboardAnomalySignal['severity']): string {
const base = 'shrink-0 rounded px-1.5 py-0.5 text-[10px]';
if (severity === 'high') return `${base} bg-[var(--warn-soft)] text-[var(--warn)]`;
if (severity === 'medium') return `${base} bg-[var(--accent-soft)] text-[var(--accent)]`;
return `${base} bg-[var(--surface-2)] text-[var(--text-3)]`;
}
function reasonExplanation(reason: string): string {
const map: Record = {
'机会/需求': '包含合作、采购、报名、求推荐或找资源等可行动信号',
'工具/产品': '提到了工具、产品、模型、插件、项目或技术栈',
链接信号: '包含可跳转链接,适合进入原文或资源查看',
可跟进: '含有联系、报名、评估、试用、帮忙等行动线索',
长观点: '消息长度较高,可能包含完整观点或经验复盘',
问题: '包含明确问题,可能适合回复或继续追踪',
};
return map[reason] ?? reason;
}