diff --git a/frontend/src/components/shared/ContextBar.tsx b/frontend/src/components/shared/ContextBar.tsx new file mode 100644 index 0000000..a3b50a3 --- /dev/null +++ b/frontend/src/components/shared/ContextBar.tsx @@ -0,0 +1,130 @@ +/** Context Bar 组件 — Scope/Lens/Time 三维上下文切换器。 */ + +"use client"; + +import { ChevronDown, Building2, Layers, Clock, Filter } from "lucide-react"; +import { useState, useRef, useEffect } from "react"; +import { + useContextBar, + SCOPE_OPTIONS, + LENS_OPTIONS, + TIME_OPTIONS, + ACTION_FILTER_OPTIONS, + type ScopeOption, + type LensOption, + type TimeOption, + type ActionFilter, +} from "@/lib/context-bar-context"; + +/** + * 下拉选择器内部组件。 + */ +function Dropdown({ + icon: Icon, + label, + options, + value, + onChange, +}: { + icon: typeof Building2; + label: string; + options: { value: T; label: string }[]; + value: T; + onChange: (value: T) => void; +}) { + const [open, setOpen] = useState(false); + const ref = useRef(null); + + useEffect(() => { + function handleClickOutside(e: MouseEvent) { + if (ref.current && !ref.current.contains(e.target as Node)) { + setOpen(false); + } + } + document.addEventListener("mousedown", handleClickOutside); + return () => document.removeEventListener("mousedown", handleClickOutside); + }, []); + + const current = options.find((o) => o.value === value); + + return ( +
+ + {open && ( +
+ {options.map((opt) => ( + + ))} +
+ )} +
+ ); +} + +/** + * Context Bar 组件 — 全局上下文切换栏。 + * + * 包含 Scope(范围)、Lens(主题)、Time(时间)三个维度, + * 以及 Action Filter(行动筛选器)。 + */ +export function ContextBar() { + const { scope, lens, time, actionFilter, setScope, setLens, setTime, setActionFilter } = + useContextBar(); + + return ( +
+ setScope(v)} + /> + setLens(v)} + /> + setTime(v)} + /> +
+ setActionFilter(v)} + /> +
+
+ ); +} diff --git a/frontend/src/components/shared/InsightRail.tsx b/frontend/src/components/shared/InsightRail.tsx new file mode 100644 index 0000000..1f40c08 --- /dev/null +++ b/frontend/src/components/shared/InsightRail.tsx @@ -0,0 +1,208 @@ +/** Insight Rail 组件 — 右侧 AI 洞察面板,可展开/折叠。 */ + +"use client"; + +import { useState } from "react"; +import { + ChevronRight, ChevronLeft, Bot, Sparkles, FileText, AlertTriangle, + Users, ScrollText, Network, UserCircle, TrendingUp, Cpu, ShieldCheck, + type LucideIcon, +} from "lucide-react"; + +/** Agent 类型定义。 */ +interface AgentDef { + key: string; + name: string; + icon: LucideIcon; + trigger: string; + output: string; + action: string; +} + +/** 12 个 Agent 配置。 */ +const AGENTS: AgentDef[] = [ + { key: "report", name: "报表分析", icon: FileText, trigger: "查看月报/季报", output: "指标提取卡片 + 异常高亮", action: "生成投后摘要草稿" }, + { key: "validator", name: "数据校验", icon: ShieldCheck, trigger: "指标出现矛盾", output: "校验维度矩阵 + 可信度评分", action: "标记可疑数据" }, + { key: "risk", name: "风险预警", icon: AlertTriangle, trigger: "健康度下降/弱信号", output: "风险等级 + 证据链", action: "创建决策线程" }, + { key: "board", name: "董事会", icon: Users, trigger: "董事会前后", output: "决议追踪 + 提问清单", action: "加入董事会议题" }, + { key: "agreement", name: "投资协议", icon: ScrollText, trigger: "协议条款即将触发", output: "条款原文 + 触发条件", action: "发送披露提醒" }, + { key: "synergy", name: "协同匹配", icon: Network, trigger: "查看协同中心", output: "匹配度评分 + 资源互补图", action: "生成协同方案草稿" }, + { key: "talent", name: "人才分析", icon: UserCircle, trigger: "核心团队变动", output: "稳定性评分 + 9-Box 矩阵", action: "启动人才搜索" }, + { key: "financing", name: "融资支持", icon: TrendingUp, trigger: "融资阶段/Runway", output: "融资准备度 + 投资人画像", action: "生成融资材料清单" }, + { key: "research", name: "行业研究", icon: Bot, trigger: "竞品/行业动态", output: "行业风险提示 + 对标分析", action: "加入洞察域报告" }, + { key: "ai_commercial", name: "AI+商业化", icon: Sparkles, trigger: "PoC/转化率指标", output: "转化漏斗 + 证据链", action: "生成董事会问题清单" }, + { key: "ai_cost", name: "AI+模型成本", icon: Cpu, trigger: "推理成本/毛利指标", output: "成本趋势 + 单位经济模型", action: "建议模型调用优化" }, + { key: "ai_compliance", name: "AI+数据合规", icon: ShieldCheck, trigger: "合规指标变化", output: "合规风险等级 + 整改建议", action: "生成合规报告草稿" }, +]; + +/** Insight Rail Props。 */ +interface InsightRailProps { + /** 当前激活的 Agent key,默认 "risk"。 */ + defaultAgent?: string; +} + +/** + * Insight Rail 组件 — 桌面端右侧可折叠 AI 洞察面板。 + * + * 展开宽度 w-80(320px),折叠宽度 w-10(40px)。 + * 包含 12 个 Agent 差异化卡片,支持 Tab 切换。 + */ +export function InsightRail({ defaultAgent = "risk" }: InsightRailProps) { + const [expanded, setExpanded] = useState(false); + const [activeAgent, setActiveAgent] = useState(defaultAgent); + const [activeTabs, setActiveTabs] = useState([defaultAgent]); + + const agent = AGENTS.find((a) => a.key === activeAgent) ?? AGENTS[0]; + + /** 切换 Agent(最多 3 个 Tab)。 */ + function switchAgent(key: string) { + setActiveAgent(key); + setActiveTabs((prev) => { + if (prev.includes(key)) return prev; + if (prev.length >= 3) return [...prev.slice(1), key]; + return [...prev, key]; + }); + } + + if (!expanded) { + return ( + + ); + } + + return ( + + ); +} diff --git a/frontend/src/components/shared/WorkModeSwitcher.tsx b/frontend/src/components/shared/WorkModeSwitcher.tsx new file mode 100644 index 0000000..aadfe7d --- /dev/null +++ b/frontend/src/components/shared/WorkModeSwitcher.tsx @@ -0,0 +1,72 @@ +/** Work Mode 切换器组件 — Overview/Compare/Focus/Queue 四种自适应模式。 */ + +"use client"; + +import { LayoutGrid, GitCompareArrows, Focus, Columns2 } from "lucide-react"; +import { useState, type ReactNode } from "react"; + +/** 工作模式类型。 */ +export type WorkMode = "overview" | "compare" | "focus" | "queue"; + +/** 工作模式配置。 */ +const MODE_CONFIG: Record = { + overview: { + label: "总览", + icon: LayoutGrid, + description: "Portfolio 全局浏览", + }, + compare: { + label: "对比", + icon: GitCompareArrows, + description: "2-5 家企业并排对比", + }, + focus: { + label: "聚焦", + icon: Focus, + description: "单企业深度分析", + }, + queue: { + label: "队列", + icon: Columns2, + description: "左右分栏批量处理", + }, +}; + +/** Work Mode 切换器 Props。 */ +interface WorkModeSwitcherProps { + mode: WorkMode; + onChange: (mode: WorkMode) => void; +} + +/** + * Work Mode 切换器组件。 + * + * 四种自适应工作模式:Overview / Compare / Focus / Queue。 + */ +export function WorkModeSwitcher({ mode, onChange }: WorkModeSwitcherProps) { + return ( +
+ {(Object.keys(MODE_CONFIG) as WorkMode[]).map((key) => { + const config = MODE_CONFIG[key]; + const isActive = mode === key; + return ( + + ); + })} +
+ ); +} diff --git a/frontend/src/components/shared/WorkspaceTabs.tsx b/frontend/src/components/shared/WorkspaceTabs.tsx new file mode 100644 index 0000000..c8bbd70 --- /dev/null +++ b/frontend/src/components/shared/WorkspaceTabs.tsx @@ -0,0 +1,85 @@ +/** Multi-Workspace Tab 管理器 — 多 Tab + 独立上下文 + 最多 8 个。 */ + +"use client"; + +import { useState } from "react"; +import { X, Plus } from "lucide-react"; + +/** 工作区 Tab 定义。 */ +export interface WorkspaceTab { + id: string; + title: string; + href: string; +} + +/** Workspace Tabs Props。 */ +interface WorkspaceTabsProps { + tabs: WorkspaceTab[]; + activeId: string; + onSwitch: (id: string) => void; + onClose: (id: string) => void; + onAdd: () => void; +} + +/** 最大 Tab 数量。 */ +const MAX_TABS = 8; + +/** + * Multi-Workspace Tab 管理器组件。 + * + * 支持多 Tab 独立上下文,最多 8 个 Tab,超出时淘汰最久未访问的 Tab。 + */ +export function WorkspaceTabs({ tabs, activeId, onSwitch, onClose, onAdd }: WorkspaceTabsProps) { + return ( +
+ {tabs.map((tab) => ( +
+ + {tabs.length > 1 && ( + + )} +
+ ))} + {tabs.length < MAX_TABS && ( + + )} +
+ ); +} diff --git a/frontend/src/components/threads/ThreadDetail.tsx b/frontend/src/components/threads/ThreadDetail.tsx new file mode 100644 index 0000000..41a036f --- /dev/null +++ b/frontend/src/components/threads/ThreadDetail.tsx @@ -0,0 +1,148 @@ +/** 决策线程详情组件 — 状态机时间线 + 关联事件 + AAR 链接。 */ + +"use client"; + +import { GitBranch, ArrowLeft, BookOpen, AlertTriangle, FileText } from "lucide-react"; +import Link from "next/link"; +import type { ThreadStatus } from "./ThreadList"; + +/** 时间线节点定义。 */ +interface TimelineNode { + status: ThreadStatus; + label: string; + date: string; + description?: string; + active: boolean; +} + +/** 关联事件定义。 */ +interface RelatedEvent { + type: "risk" | "report" | "task" | "aar"; + title: string; + href: string; +} + +/** ThreadDetail Props。 */ +interface ThreadDetailProps { + threadId: string; + title: string; + company: string; + status: ThreadStatus; + timeline: TimelineNode[]; + relatedEvents: RelatedEvent[]; +} + +/** 状态标签配置。 */ +const STATUS_LABELS: Record = { + identified: "已识别", + analyzing: "分析中", + acted: "已行动", + closed: "已关闭", +}; + +/** 事件图标映射。 */ +const EVENT_ICONS = { + risk: AlertTriangle, + report: FileText, + task: FileText, + aar: BookOpen, +} as const; + +/** + * 决策线程详情组件。 + * + * 包含状态机时间线、关联事件列表和 AAR 链接。 + */ +export function ThreadDetail({ + threadId, + title, + company, + status, + timeline, + relatedEvents, +}: ThreadDetailProps) { + return ( +
+ {/* 返回链接 */} + +