feat(frontend): P2 页面开发 — 今日行动中心 + 对比 + 决策线程 + OODA + 助推追踪 + 密级标签
- 今日行动中心: 6 区块结构(AI早报/必须处理/建议关注/增长机会/等待他人/已完成) - 多企业对比: 集成 CompareMode 组件 + 企业选择器 - 决策线程列表/详情: 集成 ThreadList/ThreadDetail 组件 - OODA 决策循环: 四阶段可视化 + 决策延迟追踪 - 助推效果追踪: 采纳率/行动率/疲劳度指标面板 - 信息分级标识: 4 级密级标签组件(公开/内部/机密/绝密)
This commit is contained in:
@@ -1,9 +1,57 @@
|
||||
/** 多企业对比工作区 — 2-5 家企业并排对比。 */
|
||||
|
||||
"use client";
|
||||
|
||||
import { GitCompareArrows } from "lucide-react";
|
||||
import { CompareMode, type CompareColumn } from "@/components/workbench/CompareMode";
|
||||
import { useState } from "react";
|
||||
|
||||
/** 多企业对比页面。 */
|
||||
export default function ComparePage() {
|
||||
const [selected, setSelected] = useState<string[]>(["智链科技", "云栈数据", "深瞳智能"]);
|
||||
|
||||
const allCompanies = ["智链科技", "云栈数据", "深瞳智能", "量子芯微", "光合生物"];
|
||||
|
||||
const companyData: Record<string, { healthScore: number; runway: number; highRisks: number }> = {
|
||||
"智链科技": { healthScore: 78.5, runway: 18, highRisks: 0 },
|
||||
"云栈数据": { healthScore: 62.0, runway: 15, highRisks: 1 },
|
||||
"深瞳智能": { healthScore: 85.5, runway: 24, highRisks: 0 },
|
||||
"量子芯微": { healthScore: 48.0, runway: 7, highRisks: 2 },
|
||||
"光合生物": { healthScore: 68.5, runway: 20, highRisks: 0 },
|
||||
};
|
||||
|
||||
const columns: CompareColumn[] = selected.map((name) => ({
|
||||
id: name,
|
||||
name,
|
||||
...companyData[name],
|
||||
content: (
|
||||
<div className="space-y-2 text-xs">
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">月营收</span>
|
||||
<span className="font-medium">800万</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">客户增长</span>
|
||||
<span className="font-medium text-emerald-600">+15%</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">AI 商业化</span>
|
||||
<span className="font-medium">3 个 PoC</span>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
}));
|
||||
|
||||
function toggleCompany(name: string) {
|
||||
setSelected((prev) => {
|
||||
if (prev.includes(name)) {
|
||||
return prev.filter((n) => n !== name);
|
||||
}
|
||||
if (prev.length >= 5) return prev;
|
||||
return [...prev, name];
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -11,38 +59,27 @@ export default function ComparePage() {
|
||||
<h1 className="text-2xl font-bold">多企业对比</h1>
|
||||
</div>
|
||||
|
||||
<div className="rounded-lg border bg-white p-4 shadow-sm">
|
||||
<p className="text-sm text-muted-foreground">
|
||||
选择 2-5 家企业进行并排对比,支持指标选择、差异高亮和趋势对比。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* 对比卡片占位 */}
|
||||
<div className="grid grid-cols-1 gap-4 md:grid-cols-3">
|
||||
{["智链科技", "云栈数据", "深瞳智能"].map((name) => (
|
||||
<div key={name} className="rounded-lg border bg-white p-4 shadow-sm">
|
||||
<h3 className="mb-3 font-medium">{name}</h3>
|
||||
<div className="space-y-2 text-sm">
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">健康度</span>
|
||||
<span className="font-medium">78.5</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">月营收</span>
|
||||
<span className="font-medium">800万</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">Runway</span>
|
||||
<span className="font-medium">12月</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">高风险</span>
|
||||
<span className="font-medium">0</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* 企业选择器 */}
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<span className="text-sm text-muted-foreground">选择企业(2-5 家):</span>
|
||||
{allCompanies.map((name) => (
|
||||
<button
|
||||
key={name}
|
||||
type="button"
|
||||
onClick={() => toggleCompany(name)}
|
||||
className={`rounded-md border px-3 py-1 text-sm transition-colors ${
|
||||
selected.includes(name)
|
||||
? "border-indigo-300 bg-indigo-50 text-indigo-600"
|
||||
: "border-gray-200 bg-white text-gray-600 hover:bg-gray-50"
|
||||
}`}
|
||||
>
|
||||
{name}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* 对比卡片 */}
|
||||
<CompareMode columns={columns} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useEffect, useState } from "react";
|
||||
import { apiFetch } from "@/lib/api";
|
||||
import { LoadingSpinner } from "@/components/shared/LoadingSpinner";
|
||||
import { EmptyState } from "@/components/shared/EmptyState";
|
||||
import { Lightbulb, Sparkles, Check, X } from "lucide-react";
|
||||
import { Lightbulb, Sparkles, Check, X, TrendingUp, BarChart3 } from "lucide-react";
|
||||
|
||||
/** 行为助推引擎页面。 */
|
||||
export default function NudgesPage() {
|
||||
@@ -117,6 +117,38 @@ export default function NudgesPage() {
|
||||
<EmptyState title="暂无助推记录" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 助推效果追踪 */}
|
||||
<div className="rounded-lg border border-[var(--border)] bg-white p-4">
|
||||
<div className="mb-3 flex items-center gap-2">
|
||||
<BarChart3 size={18} className="text-[var(--investor-primary)]" />
|
||||
<h2 className="text-sm font-medium">助推效果追踪</h2>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-4 md:grid-cols-4">
|
||||
<div className="rounded-md border p-3 text-center">
|
||||
<div className="text-xs text-muted-foreground">总推送数</div>
|
||||
<div className="mt-1 text-2xl font-bold">{nudges.length}</div>
|
||||
</div>
|
||||
<div className="rounded-md border p-3 text-center">
|
||||
<div className="text-xs text-muted-foreground">采纳率</div>
|
||||
<div className="mt-1 text-2xl font-bold text-emerald-600">
|
||||
{nudges.length > 0 ? Math.round((nudges.filter((n) => n.accepted).length / nudges.length) * 100) : 0}%
|
||||
</div>
|
||||
</div>
|
||||
<div className="rounded-md border p-3 text-center">
|
||||
<div className="text-xs text-muted-foreground">后续行动率</div>
|
||||
<div className="mt-1 text-2xl font-bold text-indigo-600">67%</div>
|
||||
</div>
|
||||
<div className="rounded-md border p-3 text-center">
|
||||
<div className="text-xs text-muted-foreground">助推疲劳度</div>
|
||||
<div className="mt-1 text-2xl font-bold text-amber-600">低</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-3 flex items-center gap-1.5 text-xs text-muted-foreground">
|
||||
<TrendingUp size={12} aria-hidden="true" />
|
||||
采纳率较上月提升 12%,"默认选项"策略效果最佳。疲劳度正常,无需调整推送频率。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/** OODA 决策循环可视化页面 — Observe/Orient/Decide/Act 循环图 + 决策延迟追踪。 */
|
||||
|
||||
"use client";
|
||||
|
||||
import { Eye, Compass, Brain, Zap, Clock } from "lucide-react";
|
||||
|
||||
/** OODA 阶段定义。 */
|
||||
interface OODAStage {
|
||||
key: string;
|
||||
label: string;
|
||||
icon: typeof Eye;
|
||||
color: string;
|
||||
items: string[];
|
||||
avgDelay: string;
|
||||
}
|
||||
|
||||
/** OODA 决策循环可视化页面。 */
|
||||
export default function OODAPage() {
|
||||
const stages: OODAStage[] = [
|
||||
{
|
||||
key: "observe",
|
||||
label: "Observe — 观察",
|
||||
icon: Eye,
|
||||
color: "border-blue-300 bg-blue-50",
|
||||
items: ["健康度下降 5 分", "Runway 降至 7 月", "客户流失率上升"],
|
||||
avgDelay: "实时",
|
||||
},
|
||||
{
|
||||
key: "orient",
|
||||
label: "Orient — 定向",
|
||||
icon: Compass,
|
||||
color: "border-indigo-300 bg-indigo-50",
|
||||
items: ["行业对标分析", "融资环境评估", "风险等级判定"],
|
||||
avgDelay: "2.3 天",
|
||||
},
|
||||
{
|
||||
key: "decide",
|
||||
label: "Decide — 决策",
|
||||
icon: Brain,
|
||||
color: "border-amber-300 bg-amber-50",
|
||||
items: ["天使+ vs Pre-A 方案对比", "估值区间确定", "投资条款协商"],
|
||||
avgDelay: "5.7 天",
|
||||
},
|
||||
{
|
||||
key: "act",
|
||||
label: "Act — 行动",
|
||||
icon: Zap,
|
||||
color: "border-emerald-300 bg-emerald-50",
|
||||
items: ["BP 准备", "投资人接触", "尽调配合"],
|
||||
avgDelay: "12.4 天",
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center gap-2">
|
||||
<Compass className="text-[var(--investor-primary)]" size={24} />
|
||||
<h1 className="text-2xl font-bold">OODA 决策循环</h1>
|
||||
</div>
|
||||
|
||||
{/* 决策延迟摘要 */}
|
||||
<div className="rounded-lg border bg-white p-4 shadow-sm">
|
||||
<div className="mb-3 flex items-center gap-2">
|
||||
<Clock className="text-amber-500" size={18} aria-hidden="true" />
|
||||
<h2 className="font-medium">决策延迟追踪</h2>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-4 md:grid-cols-4">
|
||||
{stages.map((stage) => (
|
||||
<div key={stage.key} className="rounded-md border p-3 text-center">
|
||||
<div className="text-xs text-muted-foreground">{stage.label.split(" — ")[0]}</div>
|
||||
<div className="mt-1 text-lg font-bold text-indigo-600">{stage.avgDelay}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<p className="mt-3 text-xs text-muted-foreground">
|
||||
全循环平均耗时 20.4 天,较上季度缩短 3.2 天。定向阶段延迟最长,建议加强弱信号自动化分析。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* OODA 循环图 */}
|
||||
<div className="grid grid-cols-1 gap-4 md:grid-cols-4">
|
||||
{stages.map((stage, i) => (
|
||||
<div key={stage.key} className={`rounded-lg border-2 p-4 ${stage.color}`}>
|
||||
<div className="mb-3 flex items-center gap-2">
|
||||
<stage.icon size={18} aria-hidden="true" />
|
||||
<h3 className="text-sm font-medium">{stage.label}</h3>
|
||||
</div>
|
||||
<ul className="space-y-1.5 text-xs text-gray-600">
|
||||
{stage.items.map((item, j) => (
|
||||
<li key={j} className="flex items-center gap-1.5">
|
||||
<span className="h-1.5 w-1.5 rounded-full bg-current opacity-40" />
|
||||
{item}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
{i < stages.length - 1 && (
|
||||
<div className="mt-3 text-center text-gray-300">→</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,52 +1,34 @@
|
||||
/** 决策线程详情页 — 状态机时间线 + 关联事件 + AAR 链接。 */
|
||||
|
||||
import { GitBranch, ArrowLeft } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
"use client";
|
||||
|
||||
import { ThreadDetail } from "@/components/threads/ThreadDetail";
|
||||
import type { TimelineNode } from "@/components/threads/ThreadDetail";
|
||||
import type { RelatedEvent } from "@/components/threads/ThreadDetail";
|
||||
|
||||
/** 决策线程详情页面。 */
|
||||
export default function ThreadDetailPage({ params }: { params: { id: string } }) {
|
||||
const timeline: TimelineNode[] = [
|
||||
{ status: "identified", label: "已识别", date: "2026-07-09", description: "Runway 不足 7 月,弱信号触发", active: true },
|
||||
{ status: "analyzing", label: "分析中", date: "2026-07-12", description: "对比天使+ vs Pre-A 方案", active: true },
|
||||
{ status: "acted", label: "已行动", date: "—", active: false },
|
||||
{ status: "closed", label: "已关闭", date: "—", active: false },
|
||||
];
|
||||
|
||||
const relatedEvents: RelatedEvent[] = [
|
||||
{ type: "risk", title: "现金 Runway 不足 7 月", href: "/risks" },
|
||||
{ type: "report", title: "2026 年 6 月月报", href: "/reports" },
|
||||
{ type: "task", title: "准备天使+轮 BP", href: "/tasks" },
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<Link href="/threads" className="flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground">
|
||||
<ArrowLeft size={16} />
|
||||
返回线程列表
|
||||
</Link>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<GitBranch className="text-[var(--investor-primary)]" size={24} />
|
||||
<h1 className="text-2xl font-bold">决策线程详情</h1>
|
||||
</div>
|
||||
|
||||
<div className="rounded-lg border bg-white p-4 shadow-sm">
|
||||
<div className="mb-4 flex items-center justify-between">
|
||||
<h2 className="text-lg font-medium">线程 #{params.id}</h2>
|
||||
<span className="rounded-full bg-indigo-50 px-3 py-1 text-xs text-indigo-600">分析中</span>
|
||||
</div>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
状态机时间线、关联事件和 AAR 链接将在 P1 #17 组件完成后集成。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* 时间线占位 */}
|
||||
<div className="rounded-lg border bg-white p-4 shadow-sm">
|
||||
<h3 className="mb-4 font-medium">状态机时间线</h3>
|
||||
<div className="space-y-4">
|
||||
{[
|
||||
{ label: "已识别", date: "2026-07-09", active: true },
|
||||
{ label: "分析中", date: "2026-07-12", active: true },
|
||||
{ label: "已行动", date: "—", active: false },
|
||||
{ label: "已关闭", date: "—", active: false },
|
||||
].map((step, i) => (
|
||||
<div key={i} className="flex items-center gap-3">
|
||||
<div className={`h-3 w-3 rounded-full ${step.active ? "bg-indigo-500" : "bg-gray-300"}`} />
|
||||
<span className={`text-sm ${step.active ? "font-medium" : "text-muted-foreground"}`}>
|
||||
{step.label}
|
||||
</span>
|
||||
<span className="text-xs text-muted-foreground">{step.date}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ThreadDetail
|
||||
threadId={params.id}
|
||||
title="量子芯微 融资策略:天使+ vs Pre-A"
|
||||
company="量子芯微"
|
||||
status="analyzing"
|
||||
timeline={timeline}
|
||||
relatedEvents={relatedEvents}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,19 @@
|
||||
/** 决策线程列表页 — 按状态/企业筛选 + 线程卡片。 */
|
||||
|
||||
"use client";
|
||||
|
||||
import { GitBranch } from "lucide-react";
|
||||
import { ThreadList, type ThreadItem } from "@/components/threads/ThreadList";
|
||||
|
||||
/** 决策线程列表页面。 */
|
||||
export default function ThreadsPage() {
|
||||
const threads: ThreadItem[] = [
|
||||
{ id: "thread-001", title: "云栈数据 A+轮融资时机选择", company: "云栈数据", status: "analyzing", updatedAt: "2026-07-12", riskCount: 2 },
|
||||
{ id: "thread-002", title: "深瞳智能 CTO retention 策略", company: "深瞳智能", status: "identified", updatedAt: "2026-07-10", riskCount: 1 },
|
||||
{ id: "thread-003", title: "量子芯微 融资策略:天使+ vs Pre-A", company: "量子芯微", status: "acted", updatedAt: "2026-07-14", riskCount: 3 },
|
||||
{ id: "thread-004", title: "智链科技 客户流失干预方案", company: "智链科技", status: "closed", updatedAt: "2026-06-28", riskCount: 1 },
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -17,26 +27,7 @@ export default function ThreadsPage() {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* 线程卡片占位 */}
|
||||
<div className="space-y-3">
|
||||
{[
|
||||
{ title: "云栈数据 A+轮融资时机选择", status: "分析中", company: "云栈数据" },
|
||||
{ title: "深瞳智能 CTO retention 策略", status: "已识别", company: "深瞳智能" },
|
||||
{ title: "量子芯微 融资策略:天使+ vs Pre-A", status: "已行动", company: "量子芯微" },
|
||||
].map((thread) => (
|
||||
<div key={thread.title} className="rounded-lg border bg-white p-4 shadow-sm">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h3 className="font-medium">{thread.title}</h3>
|
||||
<p className="mt-1 text-sm text-muted-foreground">{thread.company}</p>
|
||||
</div>
|
||||
<span className="rounded-full bg-indigo-50 px-3 py-1 text-xs text-indigo-600">
|
||||
{thread.status}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<ThreadList threads={threads} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,109 +1,174 @@
|
||||
/** 今日行动中心 — 投后负责人/投资经理默认首页。 */
|
||||
|
||||
import { CalendarClock, AlertTriangle, FileText, ListTodo, TrendingUp } from "lucide-react";
|
||||
"use client";
|
||||
|
||||
import { CalendarClock, Sparkles, AlertTriangle, Eye, TrendingUp, Clock, CheckCircle2, ArrowRight } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
|
||||
/** 优先级行动项。 */
|
||||
interface ActionItem {
|
||||
title: string;
|
||||
company: string;
|
||||
priority: "critical" | "high" | "medium" | "low";
|
||||
confidence: number;
|
||||
dueDate?: string;
|
||||
href: string;
|
||||
}
|
||||
|
||||
/** 优先级颜色映射。 */
|
||||
const PRIORITY_COLORS: Record<ActionItem["priority"], string> = {
|
||||
critical: "bg-red-50 text-red-600 border-red-200",
|
||||
high: "bg-amber-50 text-amber-600 border-amber-200",
|
||||
medium: "bg-blue-50 text-blue-600 border-blue-200",
|
||||
low: "bg-gray-50 text-gray-600 border-gray-200",
|
||||
};
|
||||
|
||||
const PRIORITY_LABELS: Record<ActionItem["priority"], string> = {
|
||||
critical: "紧急",
|
||||
high: "高",
|
||||
medium: "中",
|
||||
low: "低",
|
||||
};
|
||||
|
||||
/** 今日行动中心页面。 */
|
||||
export default function TodayPage() {
|
||||
const mustHandle: ActionItem[] = [
|
||||
{ title: "现金 Runway 不足 7 月,需启动融资", company: "量子芯微", priority: "critical", confidence: 0.92, dueDate: "3 天内", href: "/risks" },
|
||||
{ title: "客户流失率连续 2 月上升", company: "智链科技", priority: "high", confidence: 0.85, href: "/risks" },
|
||||
{ title: "营收增长停滞,需突破策略", company: "云栈数据", priority: "high", confidence: 0.78, href: "/risks" },
|
||||
{ title: "月报逾期未提交", company: "量子芯微", priority: "high", confidence: 1.0, dueDate: "已逾期 3 天", href: "/reports" },
|
||||
];
|
||||
|
||||
const watchItems: ActionItem[] = [
|
||||
{ title: "竞品发布类似产品,市场份额可能受挤压", company: "深瞳智能", priority: "medium", confidence: 0.65, href: "/weak-signals" },
|
||||
{ title: "CTO 技术路线分歧弱信号", company: "深瞳智能", priority: "medium", confidence: 0.58, href: "/weak-signals" },
|
||||
];
|
||||
|
||||
const growthItems: ActionItem[] = [
|
||||
{ title: "智链科技 × 云栈数据供应链协同机会", company: "智链科技", priority: "medium", confidence: 0.72, href: "/synergies" },
|
||||
{ title: "光合生物半导体验证进展,可加速商业化", company: "光合生物", priority: "low", confidence: 0.68, href: "/milestones" },
|
||||
];
|
||||
|
||||
const waitingItems: ActionItem[] = [
|
||||
{ title: "等待创始人提交修正后月报", company: "云栈数据", priority: "medium", confidence: 1.0, href: "/reports" },
|
||||
{ title: "等待董事会决议确认", company: "智链科技", priority: "low", confidence: 1.0, href: "/board" },
|
||||
];
|
||||
|
||||
const completedItems: ActionItem[] = [
|
||||
{ title: "审阅智链科技月报", company: "智链科技", priority: "low", confidence: 1.0, href: "/reports" },
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center gap-2">
|
||||
<CalendarClock className="text-[var(--investor-primary)]" size={24} />
|
||||
<h1 className="text-2xl font-bold">今日行动中心</h1>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<CalendarClock className="text-[var(--investor-primary)]" size={24} />
|
||||
<h1 className="text-2xl font-bold">今日行动中心</h1>
|
||||
</div>
|
||||
<Link
|
||||
href="/risks"
|
||||
className="flex items-center gap-1 rounded-md bg-indigo-50 px-3 py-1.5 text-sm text-indigo-600 transition-colors hover:bg-indigo-100"
|
||||
>
|
||||
开始处理 {mustHandle.length + watchItems.length} 项
|
||||
<ArrowRight size={14} aria-hidden="true" />
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/* AI 简报 */}
|
||||
<div className="rounded-lg border bg-white p-4 shadow-sm">
|
||||
<h2 className="mb-2 text-sm font-medium text-muted-foreground">AI 简报</h2>
|
||||
{/* 1. AI 早报 */}
|
||||
<div className="rounded-lg border bg-gradient-to-r from-indigo-50 to-blue-50 p-4 shadow-sm">
|
||||
<div className="mb-2 flex items-center gap-2">
|
||||
<Sparkles className="text-indigo-500" size={18} aria-hidden="true" />
|
||||
<h2 className="text-sm font-medium text-indigo-700">AI 早报</h2>
|
||||
</div>
|
||||
<p className="text-sm text-gray-700">
|
||||
今日有 3 条待处理风险、2 份月报待审阅、5 个任务待完成。量子芯微现金 Runway 不足 7 月,需紧急关注。
|
||||
自上次登录后:量子芯微健康度下降 5 分(Runway 7 月),智链科技客户流失率连续 2 月上升,
|
||||
深瞳智能 CTO 出现技术路线分歧弱信号。建议优先处理量子芯微融资问题。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* 四象限概览 */}
|
||||
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<div className="rounded-lg border bg-white p-4 shadow-sm">
|
||||
<div className="mb-3 flex items-center gap-2">
|
||||
<AlertTriangle className="text-amber-500" size={18} />
|
||||
<h3 className="font-medium">风险队列</h3>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center justify-between rounded bg-red-50 px-3 py-2 text-sm">
|
||||
<span>量子芯微 — 现金Runway不足7月</span>
|
||||
<span className="text-red-600">紧急</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between rounded bg-amber-50 px-3 py-2 text-sm">
|
||||
<span>云栈数据 — 营收增长停滞</span>
|
||||
<span className="text-amber-600">高</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between rounded bg-blue-50 px-3 py-2 text-sm">
|
||||
<span>智链科技 — 客户流失率上升</span>
|
||||
<span className="text-blue-600">中</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* 2. 必须处理 */}
|
||||
<ActionSection
|
||||
title="必须处理"
|
||||
icon={AlertTriangle}
|
||||
iconColor="text-red-500"
|
||||
items={mustHandle}
|
||||
/>
|
||||
|
||||
<div className="rounded-lg border bg-white p-4 shadow-sm">
|
||||
<div className="mb-3 flex items-center gap-2">
|
||||
<FileText className="text-blue-500" size={18} />
|
||||
<h3 className="font-medium">月报状态</h3>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center justify-between rounded bg-green-50 px-3 py-2 text-sm">
|
||||
<span>智链科技 — 已提交</span>
|
||||
<span className="text-green-600">AI 解析完成</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between rounded bg-green-50 px-3 py-2 text-sm">
|
||||
<span>深瞳智能 — 已审阅</span>
|
||||
<span className="text-green-600">完成</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between rounded bg-amber-50 px-3 py-2 text-sm">
|
||||
<span>量子芯微 — 草稿中</span>
|
||||
<span className="text-amber-600">待提交</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* 3. 建议关注 */}
|
||||
<ActionSection
|
||||
title="建议关注"
|
||||
icon={Eye}
|
||||
iconColor="text-amber-500"
|
||||
items={watchItems}
|
||||
/>
|
||||
|
||||
<div className="rounded-lg border bg-white p-4 shadow-sm">
|
||||
<div className="mb-3 flex items-center gap-2">
|
||||
<ListTodo className="text-indigo-500" size={18} />
|
||||
<h3 className="font-medium">任务概览</h3>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center justify-between rounded bg-indigo-50 px-3 py-2 text-sm">
|
||||
<span>联系流失客户进行回访</span>
|
||||
<span className="text-indigo-600">进行中</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between rounded bg-gray-50 px-3 py-2 text-sm">
|
||||
<span>准备天使+轮 BP</span>
|
||||
<span className="text-gray-600">待办</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between rounded bg-green-50 px-3 py-2 text-sm">
|
||||
<span>审阅智链科技月报</span>
|
||||
<span className="text-green-600">已完成</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* 4. 增长机会 */}
|
||||
<ActionSection
|
||||
title="增长机会"
|
||||
icon={TrendingUp}
|
||||
iconColor="text-emerald-500"
|
||||
items={growthItems}
|
||||
/>
|
||||
|
||||
<div className="rounded-lg border bg-white p-4 shadow-sm">
|
||||
<div className="mb-3 flex items-center gap-2">
|
||||
<TrendingUp className="text-emerald-500" size={18} />
|
||||
<h3 className="font-medium">健康度变化</h3>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center justify-between rounded bg-green-50 px-3 py-2 text-sm">
|
||||
<span>智链科技 78.5 ↑</span>
|
||||
<span className="text-green-600">+2.3</span>
|
||||
{/* 5. 等待他人 */}
|
||||
<ActionSection
|
||||
title="等待他人"
|
||||
icon={Clock}
|
||||
iconColor="text-blue-500"
|
||||
items={waitingItems}
|
||||
/>
|
||||
|
||||
{/* 6. 已完成待验证 */}
|
||||
<ActionSection
|
||||
title="已完成待验证"
|
||||
icon={CheckCircle2}
|
||||
iconColor="text-gray-400"
|
||||
items={completedItems}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/** 行动区块组件。 */
|
||||
function ActionSection({
|
||||
title,
|
||||
icon: Icon,
|
||||
iconColor,
|
||||
items,
|
||||
}: {
|
||||
title: string;
|
||||
icon: typeof AlertTriangle;
|
||||
iconColor: string;
|
||||
items: ActionItem[];
|
||||
}) {
|
||||
if (items.length === 0) return null;
|
||||
return (
|
||||
<div className="rounded-lg border bg-white p-4 shadow-sm">
|
||||
<div className="mb-3 flex items-center gap-2">
|
||||
<Icon className={iconColor} size={18} aria-hidden="true" />
|
||||
<h2 className="font-medium">{title}</h2>
|
||||
<span className="text-xs text-muted-foreground">({items.length})</span>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
{items.map((item, i) => (
|
||||
<Link
|
||||
key={i}
|
||||
href={item.href}
|
||||
className={`flex items-center justify-between rounded-md border px-3 py-2 text-sm transition-colors hover:bg-gray-50 ${PRIORITY_COLORS[item.priority]}`}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="font-medium">{item.title}</span>
|
||||
<span className="text-xs opacity-70">{item.company}</span>
|
||||
{item.confidence < 0.6 && (
|
||||
<span className="rounded bg-amber-100 px-1.5 py-0.5 text-xs text-amber-700">需人工核对</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center justify-between rounded bg-red-50 px-3 py-2 text-sm">
|
||||
<span>量子芯微 48.0 ↓</span>
|
||||
<span className="text-red-600">-5.0</span>
|
||||
<div className="flex items-center gap-2 text-xs">
|
||||
{item.dueDate && <span className="opacity-70">{item.dueDate}</span>}
|
||||
<span className="font-medium">{PRIORITY_LABELS[item.priority]}</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between rounded bg-gray-50 px-3 py-2 text-sm">
|
||||
<span>云栈数据 62.0 →</span>
|
||||
<span className="text-gray-600">持平</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/** 信息分级标识组件 — 4 级密级标签。 */
|
||||
|
||||
import { Shield, ShieldCheck, ShieldAlert, ShieldX } from "lucide-react";
|
||||
|
||||
/** 密级类型。 */
|
||||
export type ClassificationLevel = "public" | "internal" | "confidential" | "secret";
|
||||
|
||||
/** 密级配置。 */
|
||||
const LEVEL_CONFIG: Record<ClassificationLevel, {
|
||||
label: string;
|
||||
icon: typeof Shield;
|
||||
color: string;
|
||||
description: string;
|
||||
}> = {
|
||||
public: { label: "公开", icon: Shield, color: "text-gray-500 bg-gray-50 border-gray-200", description: "可对外公开" },
|
||||
internal: { label: "内部", icon: ShieldCheck, color: "text-blue-600 bg-blue-50 border-blue-200", description: "仅限内部使用" },
|
||||
confidential: { label: "机密", icon: ShieldAlert, color: "text-amber-600 bg-amber-50 border-amber-200", description: "限授权人员查看" },
|
||||
secret: { label: "绝密", icon: ShieldX, color: "text-rose-600 bg-rose-50 border-rose-200", description: "最高密级,查看留痕" },
|
||||
};
|
||||
|
||||
/** ClassificationBadge Props。 */
|
||||
interface ClassificationBadgeProps {
|
||||
level: ClassificationLevel;
|
||||
showDescription?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* 信息分级标识组件 — 4 级密级标签。
|
||||
*
|
||||
* 密级从低到高:公开 → 内部 → 机密 → 绝密。
|
||||
*/
|
||||
export function ClassificationBadge({ level, showDescription = false }: ClassificationBadgeProps) {
|
||||
const config = LEVEL_CONFIG[level];
|
||||
return (
|
||||
<span
|
||||
className={`inline-flex items-center gap-1 rounded border px-2 py-0.5 text-xs font-medium ${config.color}`}
|
||||
title={config.description}
|
||||
>
|
||||
<config.icon size={12} aria-hidden="true" />
|
||||
{config.label}
|
||||
{showDescription && (
|
||||
<span className="font-normal opacity-70">· {config.description}</span>
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import Link from "next/link";
|
||||
import type { ThreadStatus } from "./ThreadList";
|
||||
|
||||
/** 时间线节点定义。 */
|
||||
interface TimelineNode {
|
||||
export interface TimelineNode {
|
||||
status: ThreadStatus;
|
||||
label: string;
|
||||
date: string;
|
||||
@@ -16,7 +16,7 @@ interface TimelineNode {
|
||||
}
|
||||
|
||||
/** 关联事件定义。 */
|
||||
interface RelatedEvent {
|
||||
export interface RelatedEvent {
|
||||
type: "risk" | "report" | "task" | "aar";
|
||||
title: string;
|
||||
href: string;
|
||||
|
||||
Reference in New Issue
Block a user