feat(frontend): P2 页面开发 — 今日行动中心 + 对比 + 决策线程 + OODA + 助推追踪 + 密级标签
- 今日行动中心: 6 区块结构(AI早报/必须处理/建议关注/增长机会/等待他人/已完成) - 多企业对比: 集成 CompareMode 组件 + 企业选择器 - 决策线程列表/详情: 集成 ThreadList/ThreadDetail 组件 - OODA 决策循环: 四阶段可视化 + 决策延迟追踪 - 助推效果追踪: 采纳率/行动率/疲劳度指标面板 - 信息分级标识: 4 级密级标签组件(公开/内部/机密/绝密)
This commit is contained in:
@@ -1,9 +1,57 @@
|
|||||||
/** 多企业对比工作区 — 2-5 家企业并排对比。 */
|
/** 多企业对比工作区 — 2-5 家企业并排对比。 */
|
||||||
|
|
||||||
|
"use client";
|
||||||
|
|
||||||
import { GitCompareArrows } from "lucide-react";
|
import { GitCompareArrows } from "lucide-react";
|
||||||
|
import { CompareMode, type CompareColumn } from "@/components/workbench/CompareMode";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
/** 多企业对比页面。 */
|
/** 多企业对比页面。 */
|
||||||
export default function ComparePage() {
|
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 (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
@@ -11,38 +59,27 @@ export default function ComparePage() {
|
|||||||
<h1 className="text-2xl font-bold">多企业对比</h1>
|
<h1 className="text-2xl font-bold">多企业对比</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="rounded-lg border bg-white p-4 shadow-sm">
|
{/* 企业选择器 */}
|
||||||
<p className="text-sm text-muted-foreground">
|
<div className="flex flex-wrap items-center gap-2">
|
||||||
选择 2-5 家企业进行并排对比,支持指标选择、差异高亮和趋势对比。
|
<span className="text-sm text-muted-foreground">选择企业(2-5 家):</span>
|
||||||
</p>
|
{allCompanies.map((name) => (
|
||||||
</div>
|
<button
|
||||||
|
key={name}
|
||||||
{/* 对比卡片占位 */}
|
type="button"
|
||||||
<div className="grid grid-cols-1 gap-4 md:grid-cols-3">
|
onClick={() => toggleCompany(name)}
|
||||||
{["智链科技", "云栈数据", "深瞳智能"].map((name) => (
|
className={`rounded-md border px-3 py-1 text-sm transition-colors ${
|
||||||
<div key={name} className="rounded-lg border bg-white p-4 shadow-sm">
|
selected.includes(name)
|
||||||
<h3 className="mb-3 font-medium">{name}</h3>
|
? "border-indigo-300 bg-indigo-50 text-indigo-600"
|
||||||
<div className="space-y-2 text-sm">
|
: "border-gray-200 bg-white text-gray-600 hover:bg-gray-50"
|
||||||
<div className="flex justify-between">
|
}`}
|
||||||
<span className="text-muted-foreground">健康度</span>
|
>
|
||||||
<span className="font-medium">78.5</span>
|
{name}
|
||||||
</div>
|
</button>
|
||||||
<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>
|
</div>
|
||||||
|
|
||||||
|
{/* 对比卡片 */}
|
||||||
|
<CompareMode columns={columns} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { useEffect, useState } from "react";
|
|||||||
import { apiFetch } from "@/lib/api";
|
import { apiFetch } from "@/lib/api";
|
||||||
import { LoadingSpinner } from "@/components/shared/LoadingSpinner";
|
import { LoadingSpinner } from "@/components/shared/LoadingSpinner";
|
||||||
import { EmptyState } from "@/components/shared/EmptyState";
|
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() {
|
export default function NudgesPage() {
|
||||||
@@ -117,6 +117,38 @@ export default function NudgesPage() {
|
|||||||
<EmptyState title="暂无助推记录" />
|
<EmptyState title="暂无助推记录" />
|
||||||
)}
|
)}
|
||||||
</div>
|
</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>
|
</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 链接。 */
|
/** 决策线程详情页 — 状态机时间线 + 关联事件 + AAR 链接。 */
|
||||||
|
|
||||||
import { GitBranch, ArrowLeft } from "lucide-react";
|
"use client";
|
||||||
import Link from "next/link";
|
|
||||||
|
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 } }) {
|
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 (
|
return (
|
||||||
<div className="space-y-6">
|
<ThreadDetail
|
||||||
<Link href="/threads" className="flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground">
|
threadId={params.id}
|
||||||
<ArrowLeft size={16} />
|
title="量子芯微 融资策略:天使+ vs Pre-A"
|
||||||
返回线程列表
|
company="量子芯微"
|
||||||
</Link>
|
status="analyzing"
|
||||||
|
timeline={timeline}
|
||||||
<div className="flex items-center gap-2">
|
relatedEvents={relatedEvents}
|
||||||
<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>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,19 @@
|
|||||||
/** 决策线程列表页 — 按状态/企业筛选 + 线程卡片。 */
|
/** 决策线程列表页 — 按状态/企业筛选 + 线程卡片。 */
|
||||||
|
|
||||||
|
"use client";
|
||||||
|
|
||||||
import { GitBranch } from "lucide-react";
|
import { GitBranch } from "lucide-react";
|
||||||
|
import { ThreadList, type ThreadItem } from "@/components/threads/ThreadList";
|
||||||
|
|
||||||
/** 决策线程列表页面。 */
|
/** 决策线程列表页面。 */
|
||||||
export default function ThreadsPage() {
|
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 (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
@@ -17,26 +27,7 @@ export default function ThreadsPage() {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 线程卡片占位 */}
|
<ThreadList threads={threads} />
|
||||||
<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>
|
|
||||||
</div>
|
</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() {
|
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 (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center justify-between">
|
||||||
<CalendarClock className="text-[var(--investor-primary)]" size={24} />
|
<div className="flex items-center gap-2">
|
||||||
<h1 className="text-2xl font-bold">今日行动中心</h1>
|
<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>
|
</div>
|
||||||
|
|
||||||
{/* AI 简报 */}
|
{/* 1. AI 早报 */}
|
||||||
<div className="rounded-lg border bg-white p-4 shadow-sm">
|
<div className="rounded-lg border bg-gradient-to-r from-indigo-50 to-blue-50 p-4 shadow-sm">
|
||||||
<h2 className="mb-2 text-sm font-medium text-muted-foreground">AI 简报</h2>
|
<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">
|
<p className="text-sm text-gray-700">
|
||||||
今日有 3 条待处理风险、2 份月报待审阅、5 个任务待完成。量子芯微现金 Runway 不足 7 月,需紧急关注。
|
自上次登录后:量子芯微健康度下降 5 分(Runway 7 月),智链科技客户流失率连续 2 月上升,
|
||||||
|
深瞳智能 CTO 出现技术路线分歧弱信号。建议优先处理量子芯微融资问题。
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 四象限概览 */}
|
{/* 2. 必须处理 */}
|
||||||
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
|
<ActionSection
|
||||||
<div className="rounded-lg border bg-white p-4 shadow-sm">
|
title="必须处理"
|
||||||
<div className="mb-3 flex items-center gap-2">
|
icon={AlertTriangle}
|
||||||
<AlertTriangle className="text-amber-500" size={18} />
|
iconColor="text-red-500"
|
||||||
<h3 className="font-medium">风险队列</h3>
|
items={mustHandle}
|
||||||
</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>
|
|
||||||
|
|
||||||
<div className="rounded-lg border bg-white p-4 shadow-sm">
|
{/* 3. 建议关注 */}
|
||||||
<div className="mb-3 flex items-center gap-2">
|
<ActionSection
|
||||||
<FileText className="text-blue-500" size={18} />
|
title="建议关注"
|
||||||
<h3 className="font-medium">月报状态</h3>
|
icon={Eye}
|
||||||
</div>
|
iconColor="text-amber-500"
|
||||||
<div className="space-y-2">
|
items={watchItems}
|
||||||
<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>
|
|
||||||
|
|
||||||
<div className="rounded-lg border bg-white p-4 shadow-sm">
|
{/* 4. 增长机会 */}
|
||||||
<div className="mb-3 flex items-center gap-2">
|
<ActionSection
|
||||||
<ListTodo className="text-indigo-500" size={18} />
|
title="增长机会"
|
||||||
<h3 className="font-medium">任务概览</h3>
|
icon={TrendingUp}
|
||||||
</div>
|
iconColor="text-emerald-500"
|
||||||
<div className="space-y-2">
|
items={growthItems}
|
||||||
<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>
|
|
||||||
|
|
||||||
<div className="rounded-lg border bg-white p-4 shadow-sm">
|
{/* 5. 等待他人 */}
|
||||||
<div className="mb-3 flex items-center gap-2">
|
<ActionSection
|
||||||
<TrendingUp className="text-emerald-500" size={18} />
|
title="等待他人"
|
||||||
<h3 className="font-medium">健康度变化</h3>
|
icon={Clock}
|
||||||
</div>
|
iconColor="text-blue-500"
|
||||||
<div className="space-y-2">
|
items={waitingItems}
|
||||||
<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>
|
{/* 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>
|
||||||
<div className="flex items-center justify-between rounded bg-red-50 px-3 py-2 text-sm">
|
<div className="flex items-center gap-2 text-xs">
|
||||||
<span>量子芯微 48.0 ↓</span>
|
{item.dueDate && <span className="opacity-70">{item.dueDate}</span>}
|
||||||
<span className="text-red-600">-5.0</span>
|
<span className="font-medium">{PRIORITY_LABELS[item.priority]}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center justify-between rounded bg-gray-50 px-3 py-2 text-sm">
|
</Link>
|
||||||
<span>云栈数据 62.0 →</span>
|
))}
|
||||||
<span className="text-gray-600">持平</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</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";
|
import type { ThreadStatus } from "./ThreadList";
|
||||||
|
|
||||||
/** 时间线节点定义。 */
|
/** 时间线节点定义。 */
|
||||||
interface TimelineNode {
|
export interface TimelineNode {
|
||||||
status: ThreadStatus;
|
status: ThreadStatus;
|
||||||
label: string;
|
label: string;
|
||||||
date: string;
|
date: string;
|
||||||
@@ -16,7 +16,7 @@ interface TimelineNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** 关联事件定义。 */
|
/** 关联事件定义。 */
|
||||||
interface RelatedEvent {
|
export interface RelatedEvent {
|
||||||
type: "risk" | "report" | "task" | "aar";
|
type: "risk" | "report" | "task" | "aar";
|
||||||
title: string;
|
title: string;
|
||||||
href: string;
|
href: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user