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:
@@ -2,6 +2,7 @@
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { apiFetch } from "@/lib/api";
|
||||
import { useCompanyScope } from "@/lib/company-scope";
|
||||
import { LoadingSpinner } from "@/components/shared/LoadingSpinner";
|
||||
import { EmptyState } from "@/components/shared/EmptyState";
|
||||
import { DIMENSIONS_14 } from "@/components/health/HealthRadar";
|
||||
@@ -29,18 +30,20 @@ const LINE_COLORS = [
|
||||
|
||||
/** 健康度趋势对比图 — 按企业分组,每家企业一条折线。 */
|
||||
export function HealthTrends({ companyId }: { companyId?: string }) {
|
||||
const { companyId: scopeCompanyId } = useCompanyScope();
|
||||
const effectiveCompanyId = companyId ?? scopeCompanyId;
|
||||
const [data, setData] = useState<CompanyTrend[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
const path = companyId
|
||||
? `/dashboard/trends?company_id=${companyId}&months=6`
|
||||
const path = effectiveCompanyId
|
||||
? `/dashboard/trends?company_id=${effectiveCompanyId}&months=6`
|
||||
: "/dashboard/trends?months=6";
|
||||
apiFetch<CompanyTrend[]>(path)
|
||||
.then((res) => setData((res.data as CompanyTrend[]) || []))
|
||||
.catch(() => {})
|
||||
.finally(() => setLoading(false));
|
||||
}, [companyId]);
|
||||
}, [effectiveCompanyId]);
|
||||
|
||||
if (loading) return <LoadingSpinner />;
|
||||
if (!data.length) return <EmptyState title="暂无趋势数据" />;
|
||||
@@ -156,6 +159,8 @@ export function HealthTrends({ companyId }: { companyId?: string }) {
|
||||
);
|
||||
}
|
||||
export function HealthHeatmap({ companyId }: { companyId?: string }) {
|
||||
const { companyId: scopeCompanyId } = useCompanyScope();
|
||||
const effectiveCompanyId = companyId ?? scopeCompanyId;
|
||||
const [data, setData] = useState<HeatmapRow[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
@@ -163,11 +168,11 @@ export function HealthHeatmap({ companyId }: { companyId?: string }) {
|
||||
apiFetch<HeatmapRow[]>("/dashboard/heatmap")
|
||||
.then((res) => {
|
||||
const rows = (res.data as HeatmapRow[]) || [];
|
||||
setData(companyId ? rows.filter((r) => r.company_id === companyId) : rows);
|
||||
setData(effectiveCompanyId ? rows.filter((r) => r.company_id === effectiveCompanyId) : rows);
|
||||
})
|
||||
.catch(() => {})
|
||||
.finally(() => setLoading(false));
|
||||
}, [companyId]);
|
||||
}, [effectiveCompanyId]);
|
||||
|
||||
if (loading) return <LoadingSpinner />;
|
||||
if (!data.length) return <EmptyState title="暂无热力图数据" />;
|
||||
|
||||
Reference in New Issue
Block a user