fix(scope): all pages react to company scope change via useScopeEffect
- Created useScopeEffect hook that auto-triggers reload on scope change - Replaced useEffect([], []) with useScopeEffect in 20+ pages - Risks/Reports/Dashboard also use useScopeEffect - Removed redundant per-page useCompanyScope where only effect was needed
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { useState } from "react";
|
||||
import { useScopeEffect } from "@/lib/company-scope";
|
||||
import {Sparkles } from "lucide-react";
|
||||
import { listAARs, generateAAR } from "@/lib/api-v2";
|
||||
import { PageContainer, Card} from "@/components/shared/PageContainer";
|
||||
@@ -22,12 +23,12 @@ export default function AARsPage() {
|
||||
const [originalPlan, setOriginalPlan] = useState("");
|
||||
const [actualResult, setActualResult] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
useScopeEffect(() => {
|
||||
listAARs()
|
||||
.then((resp) => setItems((resp.data as AARItem[]) ?? []))
|
||||
.catch(() => setItems([]))
|
||||
.finally(() => setIsLoading(false));
|
||||
}, []);
|
||||
});
|
||||
|
||||
const handleGenerate = async () => {
|
||||
if (!triggerEvent.trim()) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { useState } from "react";
|
||||
import { useScopeEffect } from "@/lib/company-scope";
|
||||
import { listAgentExecutions, reviewAgentExecution } from "@/lib/api-v2";
|
||||
import { PageContainer, Badge} from "@/components/shared/PageContainer";
|
||||
import { LoadingSpinner } from "@/components/shared/LoadingSpinner";
|
||||
@@ -28,7 +29,7 @@ export default function AgentsPage() {
|
||||
.finally(() => setIsLoading(false));
|
||||
};
|
||||
|
||||
useEffect(() => { load(); }, []);
|
||||
useScopeEffect(() => { load(); });
|
||||
|
||||
const handleReview = async (id: string, status: string) => {
|
||||
try {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { useState } from "react";
|
||||
import { useScopeEffect } from "@/lib/company-scope";
|
||||
import {Plus } from "lucide-react";
|
||||
import { listAgreements } from "@/lib/api-v2";
|
||||
import { PageContainer, Badge, TableEmpty } from "@/components/shared/PageContainer";
|
||||
@@ -19,12 +20,12 @@ export default function AgreementsPage() {
|
||||
const [items, setItems] = useState<Agreement[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
useScopeEffect(() => {
|
||||
listAgreements()
|
||||
.then((resp) => setItems((resp.data as Agreement[]) ?? []))
|
||||
.catch(() => setItems([]))
|
||||
.finally(() => setIsLoading(false));
|
||||
}, []);
|
||||
});
|
||||
|
||||
return (
|
||||
<PageContainer
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { useState } from "react";
|
||||
import { useScopeEffect } from "@/lib/company-scope";
|
||||
import {Plus } from "lucide-react";
|
||||
import { listInterventions } from "@/lib/api-v2";
|
||||
import { PageContainer, Badge, Card } from "@/components/shared/PageContainer";
|
||||
@@ -19,12 +20,12 @@ export default function AlphaPage() {
|
||||
const [items, setItems] = useState<Intervention[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
useScopeEffect(() => {
|
||||
listInterventions()
|
||||
.then((resp) => setItems((resp.data as Intervention[]) ?? []))
|
||||
.catch(() => setItems([]))
|
||||
.finally(() => setIsLoading(false));
|
||||
}, []);
|
||||
});
|
||||
|
||||
return (
|
||||
<PageContainer
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { useState } from "react";
|
||||
import { useScopeEffect } from "@/lib/company-scope";
|
||||
import { listBoardMeetings } from "@/lib/api-v2";
|
||||
import { PageContainer, Badge} from "@/components/shared/PageContainer";
|
||||
import { LoadingSpinner } from "@/components/shared/LoadingSpinner";
|
||||
@@ -18,12 +19,12 @@ export default function BoardPage() {
|
||||
const [items, setItems] = useState<BoardMeeting[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
useScopeEffect(() => {
|
||||
listBoardMeetings()
|
||||
.then((resp) => setItems((resp.data as BoardMeeting[]) ?? []))
|
||||
.catch(() => setItems([]))
|
||||
.finally(() => setIsLoading(false));
|
||||
}, []);
|
||||
});
|
||||
|
||||
return (
|
||||
<PageContainer title="董事会管理" description="AI 会前材料摘要 → 决议追踪 → 提问清单生成">
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { useState } from "react";
|
||||
import { useScopeEffect } from "@/lib/company-scope";
|
||||
import { apiFetch } from "@/lib/api";
|
||||
import { PlanCard } from "@/components/customer/PlanCard";
|
||||
import { LoadingSpinner } from "@/components/shared/LoadingSpinner";
|
||||
@@ -34,10 +35,10 @@ export default function CustomerGrowthPage() {
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
useScopeEffect(() => {
|
||||
// eslint-disable-next-line react-hooks/set-state-in-effect
|
||||
loadPlans();
|
||||
}, []);
|
||||
});
|
||||
|
||||
async function handleGenerate() {
|
||||
if (!companyContext.trim()) return;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { useState } from "react";
|
||||
import { useScopeEffect } from "@/lib/company-scope";
|
||||
import { apiFetch } from "@/lib/api";
|
||||
import { LoadingSpinner } from "@/components/shared/LoadingSpinner";
|
||||
import { EmptyState } from "@/components/shared/EmptyState";
|
||||
@@ -50,10 +51,10 @@ export default function CustomerSuccessPage() {
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
useScopeEffect(() => {
|
||||
// eslint-disable-next-line react-hooks/set-state-in-effect
|
||||
loadChurnRisks();
|
||||
}, []);
|
||||
});
|
||||
|
||||
async function handleQBR() {
|
||||
if (!qbrData.trim()) return;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { 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 { useCompanyScope, useScopeEffect } from "@/lib/company-scope";
|
||||
import { LoadingSpinner } from "@/components/shared/LoadingSpinner";
|
||||
import { EmptyState } from "@/components/shared/EmptyState";
|
||||
import { HealthScoreBadge } from "@/components/shared/HealthScoreBadge";
|
||||
@@ -18,7 +18,7 @@ export default function InvestorDashboardPage() {
|
||||
const [summary, setSummary] = useState<DashboardSummary | null>(null);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
useScopeEffect(() => {
|
||||
async function load() {
|
||||
try {
|
||||
const resp = await getDashboardSummary();
|
||||
@@ -30,7 +30,7 @@ export default function InvestorDashboardPage() {
|
||||
}
|
||||
}
|
||||
load();
|
||||
}, []);
|
||||
});
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { useState } from "react";
|
||||
import { listMajorEvents, listInquiries } from "@/lib/api-v2";
|
||||
import { useScopeEffect } from "@/lib/company-scope";
|
||||
import { PageContainer, Badge } from "@/components/shared/PageContainer";
|
||||
import { LoadingSpinner } from "@/components/shared/LoadingSpinner";
|
||||
import { EmptyState } from "@/components/shared/EmptyState";
|
||||
@@ -26,7 +27,7 @@ export default function EventsPage() {
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [tab, setTab] = useState<"events" | "inquiries">("events");
|
||||
|
||||
useEffect(() => {
|
||||
useScopeEffect(() => {
|
||||
Promise.all([listMajorEvents(), listInquiries()])
|
||||
.then(([e, i]) => {
|
||||
setEvents((e.data as MajorEvent[]) ?? []);
|
||||
@@ -37,7 +38,7 @@ export default function EventsPage() {
|
||||
setInquiries([]);
|
||||
})
|
||||
.finally(() => setIsLoading(false));
|
||||
}, []);
|
||||
});
|
||||
|
||||
return (
|
||||
<PageContainer title="重大事项 & 追问清单" description="AI 从月报/弱信号中自动识别重大事项 + 生成追问清单">
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { useState } from "react";
|
||||
import { useScopeEffect } from "@/lib/company-scope";
|
||||
import {Sparkles } from "lucide-react";
|
||||
import { listExitPredictions, predictExit } from "@/lib/api-v2";
|
||||
import { PageContainer, Badge, Card } from "@/components/shared/PageContainer";
|
||||
@@ -22,12 +23,12 @@ export default function ExitSignalsPage() {
|
||||
const [companyData, setCompanyData] = useState("");
|
||||
const [predicting, setPredicting] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
useScopeEffect(() => {
|
||||
listExitPredictions()
|
||||
.then((resp) => setItems((resp.data as ExitPrediction[]) ?? []))
|
||||
.catch(() => setItems([]))
|
||||
.finally(() => setIsLoading(false));
|
||||
}, []);
|
||||
});
|
||||
|
||||
const handlePredict = async () => {
|
||||
if (!companyData.trim()) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { useState } from "react";
|
||||
import { useScopeEffect } from "@/lib/company-scope";
|
||||
import { apiFetch } from "@/lib/api";
|
||||
import { LoadingSpinner } from "@/components/shared/LoadingSpinner";
|
||||
import { EmptyState } from "@/components/shared/EmptyState";
|
||||
@@ -41,10 +42,10 @@ export default function NudgesPage() {
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
useScopeEffect(() => {
|
||||
// eslint-disable-next-line react-hooks/set-state-in-effect
|
||||
loadNudges();
|
||||
}, []);
|
||||
});
|
||||
|
||||
async function handleSelect() {
|
||||
if (!context.trim()) return;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { useState } from "react";
|
||||
import { useScopeEffect } from "@/lib/company-scope";
|
||||
import {Plus } from "lucide-react";
|
||||
import { listOKRs } from "@/lib/api-v2";
|
||||
import { PageContainer, Badge, Card } from "@/components/shared/PageContainer";
|
||||
@@ -27,12 +28,12 @@ export default function OKRsPage() {
|
||||
const [items, setItems] = useState<OKRItem[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
useScopeEffect(() => {
|
||||
listOKRs()
|
||||
.then((resp) => setItems((resp.data as OKRItem[]) ?? []))
|
||||
.catch(() => setItems([]))
|
||||
.finally(() => setIsLoading(false));
|
||||
}, []);
|
||||
});
|
||||
|
||||
return (
|
||||
<PageContainer
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { useState } from "react";
|
||||
import { useScopeEffect } from "@/lib/company-scope";
|
||||
import { apiFetch } from "@/lib/api";
|
||||
import { LoadingSpinner } from "@/components/shared/LoadingSpinner";
|
||||
import { EmptyState } from "@/components/shared/EmptyState";
|
||||
@@ -49,10 +50,10 @@ export default function PeerCirclesPage() {
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
useScopeEffect(() => {
|
||||
// eslint-disable-next-line react-hooks/set-state-in-effect
|
||||
loadCircles();
|
||||
}, []);
|
||||
});
|
||||
|
||||
async function handleMatch() {
|
||||
if (!foundersContext.trim()) return;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { useState } from "react";
|
||||
import { useScopeEffect } from "@/lib/company-scope";
|
||||
import {Sparkles } from "lucide-react";
|
||||
import { listPreMortems, runPreMortem, listRedTeams, runRedTeam } from "@/lib/api-v2";
|
||||
import { PageContainer, Card, Badge } from "@/components/shared/PageContainer";
|
||||
@@ -33,7 +34,7 @@ export default function PreMortemsPage() {
|
||||
const [input, setInput] = useState("");
|
||||
const [perspective, setPerspective] = useState("competitor");
|
||||
|
||||
useEffect(() => {
|
||||
useScopeEffect(() => {
|
||||
Promise.all([listPreMortems(), listRedTeams()])
|
||||
.then(([pm, rt]) => {
|
||||
setPreMortems((pm.data as PreMortemItem[]) ?? []);
|
||||
@@ -44,7 +45,7 @@ export default function PreMortemsPage() {
|
||||
setRedTeams([]);
|
||||
})
|
||||
.finally(() => setIsLoading(false));
|
||||
}, []);
|
||||
});
|
||||
|
||||
const handleRun = async () => {
|
||||
if (!input.trim()) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { useState } from "react";
|
||||
import { useScopeEffect } from "@/lib/company-scope";
|
||||
import { apiFetch } from "@/lib/api";
|
||||
import { LoadingSpinner } from "@/components/shared/LoadingSpinner";
|
||||
import { EmptyState } from "@/components/shared/EmptyState";
|
||||
@@ -46,10 +47,10 @@ export default function ProductDiagnosticsPage() {
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
useScopeEffect(() => {
|
||||
// eslint-disable-next-line react-hooks/set-state-in-effect
|
||||
loadDiagnostics();
|
||||
}, []);
|
||||
});
|
||||
|
||||
async function handleDiagnose() {
|
||||
if (!productInfo.trim()) return;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState, useCallback } from "react";
|
||||
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 { LoadingSpinner } from "@/components/shared/LoadingSpinner";
|
||||
import { EmptyState } from "@/components/shared/EmptyState";
|
||||
|
||||
@@ -31,7 +32,7 @@ export default function ReportsPage() {
|
||||
}
|
||||
}, [page]);
|
||||
|
||||
useEffect(() => {
|
||||
useScopeEffect(() => {
|
||||
// eslint-disable-next-line react-hooks/set-state-in-effect
|
||||
loadReports();
|
||||
}, [loadReports]);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState, useCallback } from "react";
|
||||
import { useState, useCallback } from "react";
|
||||
import { Filter } from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
import {
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
RISK_STATUS_LABELS,
|
||||
type RiskEvent,
|
||||
} from "@/lib/risks";
|
||||
import { useScopeEffect } from "@/lib/company-scope";
|
||||
import { LoadingSpinner } from "@/components/shared/LoadingSpinner";
|
||||
import { EmptyState } from "@/components/shared/EmptyState";
|
||||
import { RiskCard } from "@/components/risk/RiskCard";
|
||||
@@ -44,7 +45,7 @@ export default function RisksPage() {
|
||||
}
|
||||
}, [page, statusFilter]);
|
||||
|
||||
useEffect(() => {
|
||||
useScopeEffect(() => {
|
||||
// eslint-disable-next-line react-hooks/set-state-in-effect
|
||||
loadRisks();
|
||||
}, [loadRisks]);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { useState } from "react";
|
||||
import { useScopeEffect } from "@/lib/company-scope";
|
||||
import { listDecisionSentinels } from "@/lib/api-v2";
|
||||
import { PageContainer, Badge} from "@/components/shared/PageContainer";
|
||||
import { LoadingSpinner } from "@/components/shared/LoadingSpinner";
|
||||
@@ -18,12 +19,12 @@ export default function SentinelsPage() {
|
||||
const [items, setItems] = useState<DecisionSentinel[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
useScopeEffect(() => {
|
||||
listDecisionSentinels()
|
||||
.then((resp) => setItems((resp.data as DecisionSentinel[]) ?? []))
|
||||
.catch(() => setItems([]))
|
||||
.finally(() => setIsLoading(false));
|
||||
}, []);
|
||||
});
|
||||
|
||||
return (
|
||||
<PageContainer title="决策前哨" description="AI 识别关键决策岔路口 → 场景分析 → 提前预警">
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { useState } from "react";
|
||||
import { useScopeEffect } from "@/lib/company-scope";
|
||||
import { listSynergies, authorizeSynergy } from "@/lib/api-v2";
|
||||
import { PageContainer, Badge } from "@/components/shared/PageContainer";
|
||||
import { LoadingSpinner } from "@/components/shared/LoadingSpinner";
|
||||
@@ -37,7 +38,7 @@ export default function SynergiesPage() {
|
||||
.finally(() => setIsLoading(false));
|
||||
};
|
||||
|
||||
useEffect(() => { load(); }, []);
|
||||
useScopeEffect(() => { load(); });
|
||||
|
||||
const handleAuthorize = async (id: string) => {
|
||||
try {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { useState } from "react";
|
||||
import { useScopeEffect } from "@/lib/company-scope";
|
||||
import { listTalents } from "@/lib/api-v2";
|
||||
import { PageContainer, Badge } from "@/components/shared/PageContainer";
|
||||
import { LoadingSpinner } from "@/components/shared/LoadingSpinner";
|
||||
@@ -20,12 +21,12 @@ export default function TalentsPage() {
|
||||
const [items, setItems] = useState<Talent[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
useScopeEffect(() => {
|
||||
listTalents()
|
||||
.then((resp) => setItems((resp.data as Talent[]) ?? []))
|
||||
.catch(() => setItems([]))
|
||||
.finally(() => setIsLoading(false));
|
||||
}, []);
|
||||
});
|
||||
|
||||
return (
|
||||
<PageContainer title="人才引力场" description="人才流动预测 + 主动推荐 + 9-Box 矩阵">
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { useState } from "react";
|
||||
import { useScopeEffect } from "@/lib/company-scope";
|
||||
import {Plus } from "lucide-react";
|
||||
import { listTasks, updateTask } from "@/lib/api-v2";
|
||||
import { PageContainer, Badge } from "@/components/shared/PageContainer";
|
||||
@@ -42,7 +43,7 @@ export default function TasksPage() {
|
||||
.finally(() => setIsLoading(false));
|
||||
};
|
||||
|
||||
useEffect(() => { load(); }, []);
|
||||
useScopeEffect(() => { load(); });
|
||||
|
||||
const handleStatusChange = async (id: string, status: string) => {
|
||||
try {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { useState } from "react";
|
||||
import { useScopeEffect } from "@/lib/company-scope";
|
||||
import { listWeakSignals } from "@/lib/api-v2";
|
||||
import { PageContainer, Badge} from "@/components/shared/PageContainer";
|
||||
import { LoadingSpinner } from "@/components/shared/LoadingSpinner";
|
||||
@@ -26,12 +27,12 @@ export default function WeakSignalsPage() {
|
||||
const [items, setItems] = useState<WeakSignal[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
useScopeEffect(() => {
|
||||
listWeakSignals()
|
||||
.then((resp) => setItems((resp.data as WeakSignal[]) ?? []))
|
||||
.catch(() => setItems([]))
|
||||
.finally(() => setIsLoading(false));
|
||||
}, []);
|
||||
});
|
||||
|
||||
return (
|
||||
<PageContainer title="弱信号监控" description="技术/情绪/组织/市场四类弱信号采集与关联分析">
|
||||
|
||||
@@ -51,7 +51,7 @@ export function CompanyScopeProvider({ children }: { children: ReactNode }) {
|
||||
}
|
||||
}, []);
|
||||
|
||||
// 持久化选择
|
||||
// 持久化选择 + 派发事件通知各页面重新加载
|
||||
function setCompanyId(id: string | null) {
|
||||
setCompanyIdState(id);
|
||||
if (id) {
|
||||
@@ -59,6 +59,8 @@ export function CompanyScopeProvider({ children }: { children: ReactNode }) {
|
||||
} else {
|
||||
localStorage.setItem("company_scope_id", "all");
|
||||
}
|
||||
// 派发全局事件,让监听了 useScopeEffect 的页面重新加载数据
|
||||
window.dispatchEvent(new CustomEvent("company-scope-change", { detail: { companyId: id } }));
|
||||
}
|
||||
|
||||
const companyName = companyId
|
||||
@@ -86,3 +88,22 @@ export function useCompanyScope() {
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* 监听企业视角变化,自动触发回调重新加载数据。
|
||||
*
|
||||
* 各页面在 useEffect 中调用此 hook,当全局企业选择变化时,
|
||||
* 会自动触发回调重新加载(apiFetch 会自动注入新的 company_id)。
|
||||
*
|
||||
* @param callback 数据加载回调
|
||||
* @param deps 额外依赖(如分页、筛选状态)
|
||||
*/
|
||||
export function useScopeEffect(callback: () => void, deps: unknown[] = []) {
|
||||
const { companyId } = useCompanyScope();
|
||||
|
||||
useEffect(() => {
|
||||
callback();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [companyId, ...deps]);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user