+ |
{item.title} |
{item.signed_at} |
diff --git a/frontend/src/app/(investor)/alpha/page.tsx b/frontend/src/app/(investor)/alpha/page.tsx
index a7a25bc..afdcc2d 100644
--- a/frontend/src/app/(investor)/alpha/page.tsx
+++ b/frontend/src/app/(investor)/alpha/page.tsx
@@ -2,6 +2,7 @@
import { useState } from "react";
import { useScopeEffect } from "@/lib/company-scope";
+import { CompanyNameTag } from "@/components/shared/CompanyNameTag";
import {Plus } from "lucide-react";
import { listInterventions } from "@/lib/api-v2";
import { PageContainer, Badge, Card } from "@/components/shared/PageContainer";
@@ -10,6 +11,7 @@ import { EmptyState } from "@/components/shared/EmptyState";
/** 干预记录项。 */
interface Intervention {
+ company_id?: string;
intervention_type: string;
title: string;
executed_at: string;
@@ -48,6 +50,7 @@ export default function AlphaPage() {
{item.intervention_type}
+
{item.title}
{item.executed_at}
diff --git a/frontend/src/app/(investor)/board/page.tsx b/frontend/src/app/(investor)/board/page.tsx
index a6f0f93..ec629f7 100644
--- a/frontend/src/app/(investor)/board/page.tsx
+++ b/frontend/src/app/(investor)/board/page.tsx
@@ -2,6 +2,7 @@
import { useState } from "react";
import { useScopeEffect } from "@/lib/company-scope";
+import { CompanyNameTag } from "@/components/shared/CompanyNameTag";
import { listBoardMeetings } from "@/lib/api-v2";
import { PageContainer, Badge} from "@/components/shared/PageContainer";
import { LoadingSpinner } from "@/components/shared/LoadingSpinner";
@@ -9,6 +10,7 @@ import { EmptyState } from "@/components/shared/EmptyState";
/** 董事会会议项。 */
interface BoardMeeting {
+ company_id?: string;
title: string;
meeting_at: string;
status: string;
@@ -37,6 +39,7 @@ export default function BoardPage() {
+ | 企业 |
会议主题 |
会议时间 |
状态 |
@@ -46,6 +49,7 @@ export default function BoardPage() {
{items.map((item, i) => (
+ |
{item.title} |
{item.meeting_at} |
diff --git a/frontend/src/app/(investor)/customer-success/page.tsx b/frontend/src/app/(investor)/customer-success/page.tsx
index 15f763b..a4e617f 100644
--- a/frontend/src/app/(investor)/customer-success/page.tsx
+++ b/frontend/src/app/(investor)/customer-success/page.tsx
@@ -2,6 +2,7 @@
import { useState } from "react";
import { useScopeEffect } from "@/lib/company-scope";
+import { CompanyNameTag } from "@/components/shared/CompanyNameTag";
import { apiFetch } from "@/lib/api";
import { LoadingSpinner } from "@/components/shared/LoadingSpinner";
import { EmptyState } from "@/components/shared/EmptyState";
@@ -191,7 +192,7 @@ export default function CustomerSuccessPage() {
{churnRisks.map((risk, i) => (
- {risk.company_name || risk.company_id || "企业"}
+
{risk.signals && {risk.signals} }
{item.event_type}
+
{item.title}
diff --git a/frontend/src/app/(investor)/exit-signals/page.tsx b/frontend/src/app/(investor)/exit-signals/page.tsx
index 41f672a..ff5ab10 100644
--- a/frontend/src/app/(investor)/exit-signals/page.tsx
+++ b/frontend/src/app/(investor)/exit-signals/page.tsx
@@ -2,6 +2,7 @@
import { useState } from "react";
import { useScopeEffect } from "@/lib/company-scope";
+import { CompanyNameTag } from "@/components/shared/CompanyNameTag";
import {Sparkles } from "lucide-react";
import { listExitPredictions, predictExit } from "@/lib/api-v2";
import { PageContainer, Badge, Card } from "@/components/shared/PageContainer";
@@ -11,6 +12,7 @@ import { toast } from "sonner";
/** 退出预测项。 */
interface ExitPrediction {
+ company_id?: string;
exit_path?: string;
expected_return?: string;
confidence?: number;
@@ -80,6 +82,7 @@ export default function ExitSignalsPage() {
{item.exit_path && {item.exit_path}}
+
期望收益:{item.expected_return ?? "-"}
{item.confidence != null && (
diff --git a/frontend/src/app/(investor)/nudges/page.tsx b/frontend/src/app/(investor)/nudges/page.tsx
index 57724fa..7f70a7b 100644
--- a/frontend/src/app/(investor)/nudges/page.tsx
+++ b/frontend/src/app/(investor)/nudges/page.tsx
@@ -2,6 +2,7 @@
import { useState } from "react";
import { useScopeEffect } from "@/lib/company-scope";
+import { CompanyNameTag } from "@/components/shared/CompanyNameTag";
import { apiFetch } from "@/lib/api";
import { LoadingSpinner } from "@/components/shared/LoadingSpinner";
import { EmptyState } from "@/components/shared/EmptyState";
@@ -12,6 +13,7 @@ import { Lightbulb, Sparkles, Check, X, TrendingUp, BarChart3 } from "lucide-rea
/** 助推记录项。 */
interface NudgeItem {
id: string;
+ company_id?: string;
nudge_type: string;
message: string;
accepted: boolean;
@@ -117,7 +119,10 @@ export default function NudgesPage() {
- {n.nudge_type}
+
+ {n.nudge_type}
+
+
{n.message}
diff --git a/frontend/src/app/(investor)/okrs/page.tsx b/frontend/src/app/(investor)/okrs/page.tsx
index 0c6d144..e1f1f34 100644
--- a/frontend/src/app/(investor)/okrs/page.tsx
+++ b/frontend/src/app/(investor)/okrs/page.tsx
@@ -2,6 +2,7 @@
import { useState } from "react";
import { useScopeEffect } from "@/lib/company-scope";
+import { CompanyNameTag } from "@/components/shared/CompanyNameTag";
import {Plus } from "lucide-react";
import { listOKRs } from "@/lib/api-v2";
import { PageContainer, Badge, Card } from "@/components/shared/PageContainer";
@@ -17,6 +18,7 @@ interface KeyResult {
/** OKR 项。 */
interface OKRItem {
+ company_id?: string;
quarter: string;
objective: string;
alignment_score?: number;
@@ -56,6 +58,7 @@ export default function OKRsPage() {
{item.quarter}
+
{item.objective}
diff --git a/frontend/src/app/(investor)/peer-circles/page.tsx b/frontend/src/app/(investor)/peer-circles/page.tsx
index a2bb97d..3ca17f3 100644
--- a/frontend/src/app/(investor)/peer-circles/page.tsx
+++ b/frontend/src/app/(investor)/peer-circles/page.tsx
@@ -2,6 +2,7 @@
import { useState } from "react";
import { useScopeEffect } from "@/lib/company-scope";
+import { CompanyNameTag } from "@/components/shared/CompanyNameTag";
import { apiFetch } from "@/lib/api";
import { LoadingSpinner } from "@/components/shared/LoadingSpinner";
import { EmptyState } from "@/components/shared/EmptyState";
@@ -12,6 +13,7 @@ import { Users, Sparkles, Circle } from "lucide-react";
/** Circle 项。 */
interface CircleItem {
id: string;
+ company_id?: string;
topic: string;
status: string;
description?: string;
@@ -138,6 +140,7 @@ export default function PeerCirclesPage() {
+
{c.topic}
{preMortems.map((item, i) => (
+
{item.decision_context as string}
{Array.isArray(item.failure_paths) && (
@@ -136,6 +140,7 @@ export default function PreMortemsPage() {
{redTeams.map((item, i) => (
+
{item.perspective as string}
{item.analysis as string}
diff --git a/frontend/src/app/(investor)/product-diagnostics/page.tsx b/frontend/src/app/(investor)/product-diagnostics/page.tsx
index 87899a2..50e7641 100644
--- a/frontend/src/app/(investor)/product-diagnostics/page.tsx
+++ b/frontend/src/app/(investor)/product-diagnostics/page.tsx
@@ -2,6 +2,7 @@
import { useState } from "react";
import { useScopeEffect } from "@/lib/company-scope";
+import { CompanyNameTag } from "@/components/shared/CompanyNameTag";
import { apiFetch } from "@/lib/api";
import { LoadingSpinner } from "@/components/shared/LoadingSpinner";
import { EmptyState } from "@/components/shared/EmptyState";
@@ -24,6 +25,7 @@ interface DiagnosticResult {
/** 历史诊断项。 */
interface DiagnosticHistory {
id: string;
+ company_id?: string;
product_name?: string;
dimensions?: DiagnosticDimension[];
}
@@ -159,7 +161,10 @@ export default function ProductDiagnosticsPage() {
{diagnostics.map((d) => (
- {d.product_name || "未命名产品"}
+
+
+ {d.product_name || "未命名产品"}
+
{d.dimensions && Array.isArray(d.dimensions) && (
{d.dimensions.map((dim, i: number) => (
diff --git a/frontend/src/app/(investor)/reports/page.tsx b/frontend/src/app/(investor)/reports/page.tsx
index 6599e6c..8817e4c 100644
--- a/frontend/src/app/(investor)/reports/page.tsx
+++ b/frontend/src/app/(investor)/reports/page.tsx
@@ -4,6 +4,7 @@ import { useState, useCallback } from "react";
import {Plus, Trash2, Send } from "lucide-react";
import { listReports, submitReport, deleteReport, STATUS_LABELS, STATUS_COLORS, type MonthlyReport } from "@/lib/reports";
import { useScopeEffect } from "@/lib/company-scope";
+import { CompanyNameTag } from "@/components/shared/CompanyNameTag";
import { LoadingSpinner } from "@/components/shared/LoadingSpinner";
import { EmptyState } from "@/components/shared/EmptyState";
@@ -80,6 +81,7 @@ export default function ReportsPage() {
+ | 企业 |
期间 |
状态 |
内容摘要 |
@@ -90,6 +92,7 @@ export default function ReportsPage() {
{reports.map((report) => (
+ |
{report.period_year}年{report.period_month}月
|
diff --git a/frontend/src/app/(investor)/sentinels/page.tsx b/frontend/src/app/(investor)/sentinels/page.tsx
index 6c8a618..dbd504c 100644
--- a/frontend/src/app/(investor)/sentinels/page.tsx
+++ b/frontend/src/app/(investor)/sentinels/page.tsx
@@ -2,6 +2,7 @@
import { useState } from "react";
import { useScopeEffect } from "@/lib/company-scope";
+import { CompanyNameTag } from "@/components/shared/CompanyNameTag";
import { listDecisionSentinels } from "@/lib/api-v2";
import { PageContainer, Badge} from "@/components/shared/PageContainer";
import { LoadingSpinner } from "@/components/shared/LoadingSpinner";
@@ -9,6 +10,7 @@ import { EmptyState } from "@/components/shared/EmptyState";
/** 决策前哨项。 */
interface DecisionSentinel {
+ company_id?: string;
decision_type: string;
title: string;
status: string;
@@ -39,6 +41,7 @@ export default function SentinelsPage() {
{item.decision_type}
+
{item.title}
diff --git a/frontend/src/app/(investor)/synergies/page.tsx b/frontend/src/app/(investor)/synergies/page.tsx
index f325f32..8a7ec75 100644
--- a/frontend/src/app/(investor)/synergies/page.tsx
+++ b/frontend/src/app/(investor)/synergies/page.tsx
@@ -2,6 +2,7 @@
import { useState } from "react";
import { useScopeEffect } from "@/lib/company-scope";
+import { CompanyNameTag } from "@/components/shared/CompanyNameTag";
import { listSynergies, authorizeSynergy } from "@/lib/api-v2";
import { PageContainer, Badge } from "@/components/shared/PageContainer";
import { LoadingSpinner } from "@/components/shared/LoadingSpinner";
@@ -11,6 +12,7 @@ import { toast } from "sonner";
/** 协同机会项。 */
interface Synergy {
id: string;
+ company_id?: string;
type: string;
title: string;
status: string;
@@ -63,6 +65,7 @@ export default function SynergiesPage() {
{SYNERGY_TYPE_LABELS[item.type] ?? item.type}
+
{item.title}
diff --git a/frontend/src/app/(investor)/talents/page.tsx b/frontend/src/app/(investor)/talents/page.tsx
index ada6cb0..6441e05 100644
--- a/frontend/src/app/(investor)/talents/page.tsx
+++ b/frontend/src/app/(investor)/talents/page.tsx
@@ -2,6 +2,7 @@
import { useState } from "react";
import { useScopeEffect } from "@/lib/company-scope";
+import { CompanyNameTag } from "@/components/shared/CompanyNameTag";
import { listTalents } from "@/lib/api-v2";
import { PageContainer, Badge } from "@/components/shared/PageContainer";
import { LoadingSpinner } from "@/components/shared/LoadingSpinner";
@@ -9,6 +10,7 @@ import { EmptyState } from "@/components/shared/EmptyState";
/** 人才项。 */
interface Talent {
+ company_id?: string;
name: string;
current_role: string;
performance_rating?: string;
@@ -39,6 +41,7 @@ export default function TalentsPage() {
+ | 企业 |
姓名 |
当前职位 |
绩效 |
@@ -50,6 +53,7 @@ export default function TalentsPage() {
{items.map((item, i) => (
+ |
{item.name} |
{item.current_role} |
{item.performance_rating ?? "-"} |
diff --git a/frontend/src/app/(investor)/tasks/page.tsx b/frontend/src/app/(investor)/tasks/page.tsx
index 1a03b73..40d9239 100644
--- a/frontend/src/app/(investor)/tasks/page.tsx
+++ b/frontend/src/app/(investor)/tasks/page.tsx
@@ -2,6 +2,7 @@
import { useState } from "react";
import { useScopeEffect } from "@/lib/company-scope";
+import { CompanyNameTag } from "@/components/shared/CompanyNameTag";
import {Plus } from "lucide-react";
import { listTasks, updateTask } from "@/lib/api-v2";
import { PageContainer, Badge } from "@/components/shared/PageContainer";
@@ -12,6 +13,7 @@ import { toast } from "sonner";
/** 任务项。 */
interface TaskItem {
id: string;
+ company_id?: string;
title: string;
status: string;
priority: string;
@@ -80,7 +82,10 @@ export default function TasksPage() {
{items.filter((i) => i.status === col).map((item, i) => (
- {item.title}
+
+
+ {item.title}
+
{item.priority}
diff --git a/frontend/src/app/(investor)/weak-signals/page.tsx b/frontend/src/app/(investor)/weak-signals/page.tsx
index ee81ea8..d8b030b 100644
--- a/frontend/src/app/(investor)/weak-signals/page.tsx
+++ b/frontend/src/app/(investor)/weak-signals/page.tsx
@@ -2,6 +2,7 @@
import { useState } from "react";
import { useScopeEffect } from "@/lib/company-scope";
+import { CompanyNameTag } from "@/components/shared/CompanyNameTag";
import { listWeakSignals } from "@/lib/api-v2";
import { PageContainer, Badge} from "@/components/shared/PageContainer";
import { LoadingSpinner } from "@/components/shared/LoadingSpinner";
@@ -9,6 +10,7 @@ import { EmptyState } from "@/components/shared/EmptyState";
/** 弱信号项。 */
interface WeakSignal {
+ company_id?: string;
signal_type: string;
content: string;
confidence: number;
@@ -45,6 +47,7 @@ export default function WeakSignalsPage() {
+ | 企业 |
类型 |
内容 |
置信度 |
@@ -55,6 +58,7 @@ export default function WeakSignalsPage() {
{items.map((item, i) => (
+ |
{SIGNAL_TYPE_LABELS[item.signal_type] ?? item.signal_type}
|
diff --git a/frontend/src/components/customer/PlanCard.tsx b/frontend/src/components/customer/PlanCard.tsx
index 8777282..e4cfda4 100644
--- a/frontend/src/components/customer/PlanCard.tsx
+++ b/frontend/src/components/customer/PlanCard.tsx
@@ -1,6 +1,7 @@
"use client";
import { Target, ArrowRight, DollarSign, Users, Trophy } from "lucide-react";
+import { CompanyNameTag } from "@/components/shared/CompanyNameTag";
/** 决策链节点。 */
interface DecisionChainNode {
@@ -16,6 +17,7 @@ interface CompetitiveAnalysis {
/** 客户获取方案。 */
interface CustomerPlanData {
+ company_id?: string;
target_customer?: string;
execution_status?: string;
entry_angle?: string;
@@ -40,6 +42,7 @@ export function PlanCard({ plan }: { plan: CustomerPlanData }) {
+
{plan.target_customer || "未指定目标客户"}
diff --git a/frontend/src/components/risk/RiskCard.tsx b/frontend/src/components/risk/RiskCard.tsx
index 377cf9b..9bdc412 100644
--- a/frontend/src/components/risk/RiskCard.tsx
+++ b/frontend/src/components/risk/RiskCard.tsx
@@ -1,6 +1,6 @@
"use client";
-import { AlertTriangle, Trash2 } from "lucide-react";
+import { AlertTriangle, Trash2, Building2 } from "lucide-react";
import {
RISK_STATUS_LABELS,
RISK_STATUS_COLORS,
@@ -9,6 +9,7 @@ import {
RISK_TYPE_LABELS,
type RiskEvent,
} from "@/lib/risks";
+import { useCompanyName } from "@/lib/company-scope";
/** 风险卡片组件 — 从风险工作台抽取的独立组件。 */
@@ -22,6 +23,7 @@ interface RiskCardProps {
* 风险事件卡片。
*/
export function RiskCard({ risk, onStatusChange, onDelete }: RiskCardProps) {
+ const getCompanyName = useCompanyName();
return (
@@ -38,6 +40,9 @@ export function RiskCard({ risk, onStatusChange, onDelete }: RiskCardProps) {
+
+ {getCompanyName(risk.company_id)}
+
{RISK_TYPE_LABELS[risk.type] || risk.type}
严重度: {SEVERITY_LABELS[risk.severity] || risk.severity}
diff --git a/frontend/src/components/shared/CompanyNameTag.tsx b/frontend/src/components/shared/CompanyNameTag.tsx
new file mode 100644
index 0000000..9bcbf9b
--- /dev/null
+++ b/frontend/src/components/shared/CompanyNameTag.tsx
@@ -0,0 +1,15 @@
+"use client";
+
+import { Building2 } from "lucide-react";
+import { useCompanyName } from "@/lib/company-scope";
+
+/** 企业名标签 — 在数据项旁显示所属企业名。 */
+export function CompanyNameTag({ companyId, className = "" }: { companyId?: string | null; className?: string }) {
+ const getCompanyName = useCompanyName();
+ return (
+
+
+ {getCompanyName(companyId)}
+
+ );
+}
diff --git a/frontend/src/lib/company-scope.tsx b/frontend/src/lib/company-scope.tsx
index 0b2fb11..d075add 100644
--- a/frontend/src/lib/company-scope.tsx
+++ b/frontend/src/lib/company-scope.tsx
@@ -107,3 +107,17 @@ export function useScopeEffect(callback: () => void, deps: unknown[] = []) {
}, [companyId, ...deps]);
}
+/**
+ * 根据企业 ID 查找企业名称。
+ *
+ * 在"全部企业"模式下,各页面数据项需要显示所属企业名,
+ * 此 hook 利用 Context 中已加载的企业列表进行映射。
+ */
+export function useCompanyName(): (companyId: string | undefined | null) => string {
+ const { companies } = useCompanyScope();
+ return (companyId: string | undefined | null) => {
+ if (!companyId) return "—";
+ return companies.find((c) => c.id === companyId)?.name ?? companyId.slice(0, 8);
+ };
+}
+
| |