feat(scope): add company scope switcher — two views (by-task all companies / by-company all tasks)

- CompanyScopeContext + Provider with localStorage persistence
- Sidebar company selector (desktop + mobile)
- apiFetch auto-injects company_id on GET requests
- Dashboard summary API supports company_id filter
- Milestones/Financial/DigitalTwins pages use scope instead of manual input
- HealthHeatmap/HealthTrends components react to scope changes
This commit is contained in:
selfrelease
2026-07-20 07:47:53 +08:00
parent 8b8926bde3
commit e81aa6828e
10 changed files with 306 additions and 53 deletions
@@ -4,6 +4,7 @@ import { useEffect, useState } from "react";
import { Building2, Heart, AlertTriangle, FileText, TrendingUp, TrendingDown, Minus } from "lucide-react";
import Link from "next/link";
import { getDashboardSummary, type DashboardSummary } from "@/lib/dashboard";
import { useCompanyScope } from "@/lib/company-scope";
import { LoadingSpinner } from "@/components/shared/LoadingSpinner";
import { EmptyState } from "@/components/shared/EmptyState";
import { HealthScoreBadge } from "@/components/shared/HealthScoreBadge";
@@ -13,6 +14,7 @@ import { HealthHeatmap, HealthTrends } from "@/components/dashboard/HealthHeatma
* 投资人端 — 驾驶舱首页。
*/
export default function InvestorDashboardPage() {
const { companyName } = useCompanyScope();
const [summary, setSummary] = useState<DashboardSummary | null>(null);
const [isLoading, setIsLoading] = useState(true);
@@ -79,8 +81,8 @@ export default function InvestorDashboardPage() {
return (
<div className="space-y-6">
<div>
<h1 className="text-2xl font-bold text-foreground"></h1>
<p className="mt-1 text-sm text-muted-foreground">Portfolio </p>
<h1 className="text-2xl font-bold text-foreground">{companyName ? `${companyName} — 企业驾驶舱` : "投资机构驾驶舱"}</h1>
<p className="mt-1 text-sm text-muted-foreground">{companyName ? "单企业健康度与风险概览" : "Portfolio 全局健康度与风险概览"}</p>
</div>
{/* KPI 卡片 */}