feat(frontend): 全部页面接入后端API并同步全局企业选择
- ai-plus: Class组件→函数组件,接入 listHealthScores + listAgentExecutions API - ooda: 硬编码→接入 risks/weak-signals/sentinels/tasks API 构建OODA各阶段 - threads: 硬编码→接入 risks/tasks/events API 组合决策线程 - today: 硬编码→接入 risks/weak-signals/synergies/reports API 构建行动项 - compare: 硬编码企业名→使用全局企业列表 + listHealthScores + listRisks API - innovation/knowledge-graph/portfolio: 加 useCompanyScope 标题显示企业名 - 所有页面标题在单企业选择时显示企业名 - 编译验证通过
This commit is contained in:
@@ -1,24 +1,105 @@
|
||||
/** 决策线程列表页 — 按状态/企业筛选 + 线程卡片。 */
|
||||
/** 决策线程列表页 — 按状态/企业筛选 + 线程卡片,数据来自后端 API。 */
|
||||
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { GitBranch } from "lucide-react";
|
||||
import { ThreadList, type ThreadItem } from "@/components/threads/ThreadList";
|
||||
import { useCompanyScope, useScopeEffect, useCompanyName } from "@/lib/company-scope";
|
||||
import { listRisks, type RiskEvent } from "@/lib/risks";
|
||||
import { listTasks } from "@/lib/api-v2";
|
||||
import { listMajorEvents } from "@/lib/api-v2";
|
||||
import { LoadingSpinner } from "@/components/shared/LoadingSpinner";
|
||||
import { EmptyState } from "@/components/shared/EmptyState";
|
||||
|
||||
/** 任务项。 */
|
||||
interface TaskItem {
|
||||
id: string;
|
||||
company_id?: string;
|
||||
title: string;
|
||||
status?: string;
|
||||
}
|
||||
|
||||
/** 重大事项项。 */
|
||||
interface MajorEventItem {
|
||||
id: string;
|
||||
company_id?: string;
|
||||
event_type: string;
|
||||
title: string;
|
||||
}
|
||||
|
||||
/** 决策线程列表页面。 */
|
||||
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 },
|
||||
];
|
||||
const { companyName } = useCompanyScope();
|
||||
const getCompanyName = useCompanyName();
|
||||
const [threads, setThreads] = useState<ThreadItem[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
useScopeEffect(() => {
|
||||
Promise.all([
|
||||
listRisks({ page_size: 50 }),
|
||||
listTasks(),
|
||||
listMajorEvents(),
|
||||
])
|
||||
.then(([risksResp, tasksResp, eventsResp]) => {
|
||||
const risks = (risksResp.data?.items as RiskEvent[]) ?? [];
|
||||
const tasks = (tasksResp.data as TaskItem[]) ?? [];
|
||||
const events = (eventsResp.data as MajorEventItem[]) ?? [];
|
||||
|
||||
// 将风险、任务、事件组合为决策线程
|
||||
const combined: ThreadItem[] = [];
|
||||
|
||||
// 风险 → 线程
|
||||
risks.forEach((risk) => {
|
||||
combined.push({
|
||||
id: `risk-${risk.id}`,
|
||||
title: risk.title,
|
||||
company: getCompanyName(risk.company_id),
|
||||
status: risk.status === "closed" ? "closed" : risk.status === "in_progress" ? "acted" : risk.status === "assigned" ? "identified" : "analyzing",
|
||||
updatedAt: risk.updated_at?.slice(0, 10) ?? "",
|
||||
riskCount: 1,
|
||||
});
|
||||
});
|
||||
|
||||
// 重大事项 → 线程
|
||||
events.forEach((event) => {
|
||||
combined.push({
|
||||
id: `event-${event.id}`,
|
||||
title: event.title,
|
||||
company: getCompanyName(event.company_id),
|
||||
status: "identified",
|
||||
updatedAt: "",
|
||||
riskCount: 0,
|
||||
});
|
||||
});
|
||||
|
||||
// 任务 → 线程
|
||||
tasks.forEach((task) => {
|
||||
combined.push({
|
||||
id: `task-${task.id}`,
|
||||
title: task.title,
|
||||
company: getCompanyName(task.company_id),
|
||||
status: task.status === "completed" ? "closed" : task.status === "in_progress" ? "acted" : "identified",
|
||||
updatedAt: "",
|
||||
riskCount: 0,
|
||||
});
|
||||
});
|
||||
|
||||
setThreads(combined.slice(0, 20));
|
||||
})
|
||||
.catch(() => {
|
||||
setThreads([]);
|
||||
})
|
||||
.finally(() => setIsLoading(false));
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center gap-2">
|
||||
<GitBranch className="text-[var(--investor-primary)]" size={24} />
|
||||
<h1 className="text-2xl font-bold">决策线程</h1>
|
||||
<h1 className="text-2xl font-bold">
|
||||
决策线程{companyName ? ` — ${companyName}` : ""}
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div className="rounded-lg border bg-white p-4 shadow-sm">
|
||||
@@ -27,7 +108,13 @@ export default function ThreadsPage() {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<ThreadList threads={threads} />
|
||||
{isLoading ? (
|
||||
<LoadingSpinner />
|
||||
) : threads.length === 0 ? (
|
||||
<EmptyState description="暂无决策线程" />
|
||||
) : (
|
||||
<ThreadList threads={threads} />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user