父史诗: 史诗005 - 供应链可视化大屏实现 docs/prd/epic-005-supply-chain-visualization.md
Ready for Review
As a 前端开发者 I want 统一的供应链数据Context和动态路由架构 so that 我可以通过路由参数动态加载4套组合大屏数据,实现组件复用和统一数据管理
Scope: 扩展ThemeContext为SupplyChainContext,创建统一数据结构,实现路由参数解析,配置动态路由
src/client/home/pages/SupplyChainDashboards/context/目录下创建SupplyChainContext.tsxDashboardTypeSupplyChainDataLocationPointMetricDataSupplyChainNetworkPopupDatasrc/client/home/routes.tsx中的路由配置/supply-chain/:dashboardTypesrc/client/home/pages/SupplyChainDashboards/context/SupplyChainContext.tsxsrc/client/home/routes.tsxsrc/share/types.ts (共享类型)tests/unit/client/home/pages/SupplyChainDashboards/context//supply-chain/grain-oil/supply-chain/:dashboardType// 组合类型定义
type DashboardType = 'grain-oil' | 'seed-fruit' | 'livestock-aquaculture' | 'fresh-food-salt';
// 产业类型定义(继承自现有ThemeContext)
type IndustryType = "粮食" | "油脂" | "种业" | "果蔬" | "畜牧" | "水产" | "鲜食" | "泛盐";
// 定位点坐标接口
interface LocationPoint {
id: string;
type: 'base' | 'chain';
x: number;
y: number;
industry: IndustryType;
name?: string;
data?: Record<string, any>;
}
// 关键指标数据接口
interface MetricData {
id: string;
label: string;
value: string | number;
unit?: string;
industry: IndustryType;
}
// 供应链网络数据接口
interface SupplyChainNetwork {
connections: Array<{
from: string;
to: string;
type: string;
}>;
nodes: Record<string, LocationPoint>;
}
// 弹出框数据接口
interface PopupData {
id: string;
title: string;
content: string;
position: { x: number; y: number };
industry: IndustryType;
}
// 供应链数据接口
interface SupplyChainData {
// 组合名称
name: string;
// 支持的产业
industries: IndustryType[];
// 定位点数据
mapPoints: Record<IndustryType, LocationPoint[]>;
// 关键指标数据
keyMetrics: Record<IndustryType, MetricData[]>;
// 供应链网络数据
supplyChainNetwork: Record<IndustryType, SupplyChainNetwork>;
// 弹出框数据
popupData: Record<IndustryType, PopupData[]>;
}
// 扩展的Context接口
interface SupplyChainContextType {
// 当前组合类型
currentDashboard: DashboardType;
// 当前产业
currentIndustry: IndustryType;
// 主题色
themeColor: string;
// 当前组合数据
currentData: SupplyChainData | null;
// 加载状态
isLoading: boolean;
// 错误信息
error: string | null;
// 设置方法
setDashboard: (dashboard: DashboardType) => void;
setIndustry: (industry: IndustryType) => void;
// 数据加载方法
loadDashboardData: (dashboard: DashboardType) => Promise<void>;
// 刷新数据
refreshData: () => Promise<void>;
}
// 路由参数配置
const supplyChainRoutes = [
{
path: '/supply-chain/:dashboardType',
component: SupplyChainDashboard,
// 参数验证
validate: (params: { dashboardType: string }) => {
const validTypes: DashboardType[] = ['grain-oil', 'seed-fruit', 'livestock-aquaculture', 'fresh-food-salt'];
return validTypes.includes(params.dashboardType as DashboardType);
},
// 默认参数
defaultParams: { dashboardType: 'grain-oil' }
}
];
使用@tanstack/react-query进行服务端状态管理,实现数据获取、缓存和同步:
// React Query配置
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 5 * 60 * 1000, // 5分钟
gcTime: 10 * 60 * 1000, // 10分钟
},
},
});
// 数据查询Hook
const useSupplyChainData = (dashboardType: DashboardType) => {
return useQuery({
queryKey: ['supply-chain', dashboardType],
queryFn: () => loadStaticData(dashboardType),
enabled: !!dashboardType,
});
};
基于现有粮食-油脂大屏数据和PRD中的坐标数据,定义4套组合的静态数据:
粮食-油脂组合: 使用现有GrainOilDashboard中的数据
种业-果蔬组合:
畜牧-水产组合:
鲜食-泛盐组合:
// 静态数据定义
const grainOilData: SupplyChainData = {
name: '粮食-油脂组合',
industries: ['粮食', '油脂'],
mapPoints: {
'粮食': [
{ id: 'grain-base1', type: 'base', x: 1142.89, y: 717.84, industry: '粮食' },
{ id: 'grain-base2', type: 'base', x: 1664.25, y: 530.82, industry: '粮食' },
{ id: 'grain-base3', type: 'base', x: 1435, y: 527.14, industry: '粮食' },
{ id: 'grain-base4', type: 'base', x: 1203.07, y: 514.31, industry: '粮食' },
{ id: 'grain-chain1', type: 'chain', x: 1273.12, y: 551.14, industry: '粮食' },
{ id: 'grain-chain2', type: 'chain', x: 1403, y: 597.5, industry: '粮食' },
{ id: 'grain-chain3', type: 'chain', x: 1694.25, y: 645.5, industry: '粮食' },
{ id: 'grain-chain4', type: 'chain', x: 1237.87, y: 761.84, industry: '粮食' }
],
'油脂': [
{ id: 'oil-base1', type: 'base', x: 985, y: 610.22, industry: '油脂' },
{ id: 'oil-base2', type: 'base', x: 1125.81, y: 409.52, industry: '油脂' },
{ id: 'oil-base3', type: 'base', x: 1229.57, y: 570, industry: '油脂' },
{ id: 'oil-base4', type: 'base', x: 1445, y: 560.35, industry: '油脂' },
{ id: 'oil-chain1', type: 'chain', x: 949.08, y: 680.31, industry: '油脂' },
{ id: 'oil-chain2', type: 'chain', x: 1178.36, y: 418.4, industry: '油脂' },
{ id: 'oil-chain3', type: 'chain', x: 1307.42, y: 551.47, industry: '油脂' },
{ id: 'oil-chain4', type: 'chain', x: 1403.37, y: 603.77, industry: '油脂' }
]
},
keyMetrics: {
'粮食': [
{ id: 'grain-metric1', label: '加工能力达', value: '200', unit: '万吨/年', industry: '粮食' },
{ id: 'grain-metric2', label: '自建优质水稻基地', value: '15', unit: '万亩', industry: '粮食' },
{ id: 'grain-metric3', label: '辐射带动面积', value: '20', unit: '万亩', industry: '粮食' }
],
'油脂': [
{ id: 'oil-metric1', label: '加工能力达', value: '150', unit: '万吨/年', industry: '油脂' },
{ id: 'oil-metric2', label: '自建油料基地', value: '10', unit: '万亩', industry: '油脂' },
{ id: 'oil-metric3', label: '辐射带动面积', value: '18', unit: '万亩', industry: '油脂' }
]
},
supplyChainNetwork: {
'粮食': {
connections: [
{ from: 'grain-base1', to: 'grain-chain1', type: 'supply' },
{ from: 'grain-base2', to: 'grain-chain2', type: 'supply' },
{ from: 'grain-base3', to: 'grain-chain3', type: 'supply' },
{ from: 'grain-base4', to: 'grain-chain4', type: 'supply' }
],
nodes: {
'grain-base1': { id: 'grain-base1', type: 'base', x: 1142.89, y: 717.84, industry: '粮食' },
'grain-base2': { id: 'grain-base2', type: 'base', x: 1664.25, y: 530.82, industry: '粮食' },
'grain-base3': { id: 'grain-base3', type: 'base', x: 1435, y: 527.14, industry: '粮食' },
'grain-base4': { id: 'grain-base4', type: 'base', x: 1203.07, y: 514.31, industry: '粮食' },
'grain-chain1': { id: 'grain-chain1', type: 'chain', x: 1273.12, y: 551.14, industry: '粮食' },
'grain-chain2': { id: 'grain-chain2', type: 'chain', x: 1403, y: 597.5, industry: '粮食' },
'grain-chain3': { id: 'grain-chain3', type: 'chain', x: 1694.25, y: 645.5, industry: '粮食' },
'grain-chain4': { id: 'grain-chain4', type: 'chain', x: 1237.87, y: 761.84, industry: '粮食' }
}
},
'油脂': {
connections: [
{ from: 'oil-base1', to: 'oil-chain1', type: 'supply' },
{ from: 'oil-base2', to: 'oil-chain2', type: 'supply' },
{ from: 'oil-base3', to: 'oil-chain3', type: 'supply' },
{ from: 'oil-base4', to: 'oil-chain4', type: 'supply' }
],
nodes: {
'oil-base1': { id: 'oil-base1', type: 'base', x: 985, y: 610.22, industry: '油脂' },
'oil-base2': { id: 'oil-base2', type: 'base', x: 1125.81, y: 409.52, industry: '油脂' },
'oil-base3': { id: 'oil-base3', type: 'base', x: 1229.57, y: 570, industry: '油脂' },
'oil-base4': { id: 'oil-base4', type: 'base', x: 1445, y: 560.35, industry: '油脂' },
'oil-chain1': { id: 'oil-chain1', type: 'chain', x: 949.08, y: 680.31, industry: '油脂' },
'oil-chain2': { id: 'oil-chain2', type: 'chain', x: 1178.36, y: 418.4, industry: '油脂' },
'oil-chain3': { id: 'oil-chain3', type: 'chain', x: 1307.42, y: 551.47, industry: '油脂' },
'oil-chain4': { id: 'oil-chain4', type: 'chain', x: 1403.37, y: 603.77, industry: '油脂' }
}
}
},
popupData: {
'粮食': [
{
id: 'grain-popup1',
title: '源头',
content: '江汉大米核心示范基地荆门/荆州/黄冈/孝感',
position: { x: 717.28, y: 273.13 },
industry: '粮食',
metrics: [
{ label: '辐射带动:', value: '>20', unit: '万亩' },
{ label: '自建基地规模:', value: '6~15', unit: '万亩' }
]
}
],
'油脂': [
{
id: 'oil-popup1',
title: '源头',
content: '油脂核心示范基地',
position: { x: 814.45, y: 464.02 },
industry: '油脂',
metrics: [
{ label: '辐射带动:', value: '>18', unit: '万亩' },
{ label: '自建基地规模:', value: '5~10', unit: '万亩' }
]
}
]
}
};
const seedFruitData: SupplyChainData = {
name: '种业-果蔬组合',
industries: ['种业', '果蔬'],
mapPoints: {
'种业': [
{ id: 'seed-base1', type: 'base', x: 1142.89, y: 717.84, industry: '种业' },
{ id: 'seed-base2', type: 'base', x: 1664.25, y: 530.82, industry: '种业' },
{ id: 'seed-base3', type: 'base', x: 1435, y: 527.14, industry: '种业' },
{ id: 'seed-base4', type: 'base', x: 1203.07, y: 514.31, industry: '种业' },
{ id: 'seed-chain1', type: 'chain', x: 1273.12, y: 551.14, industry: '种业' },
{ id: 'seed-chain2', type: 'chain', x: 1403, y: 597.5, industry: '种业' },
{ id: 'seed-chain3', type: 'chain', x: 1694.25, y: 645.5, industry: '种业' },
{ id: 'seed-chain4', type: 'chain', x: 1237.87, y: 761.84, industry: '种业' }
],
'果蔬': [
{ id: 'fruit-base1', type: 'base', x: 985, y: 610.22, industry: '果蔬' },
{ id: 'fruit-base2', type: 'base', x: 1125.81, y: 409.52, industry: '果蔬' },
{ id: 'fruit-base3', type: 'base', x: 1229.57, y: 570, industry: '果蔬' },
{ id: 'fruit-base4', type: 'base', x: 1445, y: 560.35, industry: '果蔬' },
{ id: 'fruit-chain1', type: 'chain', x: 949.08, y: 680.31, industry: '果蔬' }
]
},
keyMetrics: {
'种业': [
{ id: 'seed-metric1', label: '良种繁育能力', value: '50', unit: '万公斤/年', industry: '种业' },
{ id: 'seed-metric2', label: '自建育种基地', value: '8', unit: '万亩', industry: '种业' },
{ id: 'seed-metric3', label: '辐射带动面积', value: '15', unit: '万亩', industry: '种业' }
],
'果蔬': [
{ id: 'fruit-metric1', label: '加工能力达', value: '80', unit: '万吨/年', industry: '果蔬' },
{ id: 'fruit-metric2', label: '自建果蔬基地', value: '12', unit: '万亩', industry: '果蔬' },
{ id: 'fruit-metric3', label: '辐射带动面积', value: '25', unit: '万亩', industry: '果蔬' }
]
},
supplyChainNetwork: {
'种业': {
connections: [
{ from: 'seed-base1', to: 'seed-chain1', type: 'supply' },
{ from: 'seed-base2', to: 'seed-chain2', type: 'supply' },
{ from: 'seed-base3', to: 'seed-chain3', type: 'supply' },
{ from: 'seed-base4', to: 'seed-chain4', type: 'supply' }
],
nodes: {
'seed-base1': { id: 'seed-base1', type: 'base', x: 1142.89, y: 717.84, industry: '种业' },
'seed-base2': { id: 'seed-base2', type: 'base', x: 1664.25, y: 530.82, industry: '种业' },
'seed-base3': { id: 'seed-base3', type: 'base', x: 1435, y: 527.14, industry: '种业' },
'seed-base4': { id: 'seed-base4', type: 'base', x: 1203.07, y: 514.31, industry: '种业' },
'seed-chain1': { id: 'seed-chain1', type: 'chain', x: 1273.12, y: 551.14, industry: '种业' },
'seed-chain2': { id: 'seed-chain2', type: 'chain', x: 1403, y: 597.5, industry: '种业' },
'seed-chain3': { id: 'seed-chain3', type: 'chain', x: 1694.25, y: 645.5, industry: '种业' },
'seed-chain4': { id: 'seed-chain4', type: 'chain', x: 1237.87, y: 761.84, industry: '种业' }
}
},
'果蔬': {
connections: [
{ from: 'fruit-base1', to: 'fruit-chain1', type: 'supply' },
{ from: 'fruit-base2', to: 'fruit-chain1', type: 'supply' },
{ from: 'fruit-base3', to: 'fruit-chain1', type: 'supply' },
{ from: 'fruit-base4', to: 'fruit-chain1', type: 'supply' }
],
nodes: {
'fruit-base1': { id: 'fruit-base1', type: 'base', x: 985, y: 610.22, industry: '果蔬' },
'fruit-base2': { id: 'fruit-base2', type: 'base', x: 1125.81, y: 409.52, industry: '果蔬' },
'fruit-base3': { id: 'fruit-base3', type: 'base', x: 1229.57, y: 570, industry: '果蔬' },
'fruit-base4': { id: 'fruit-base4', type: 'base', x: 1445, y: 560.35, industry: '果蔬' },
'fruit-chain1': { id: 'fruit-chain1', type: 'chain', x: 949.08, y: 680.31, industry: '果蔬' }
}
}
},
popupData: {
'种业': [
{
id: 'seed-popup1',
title: '源头',
content: '种业核心示范基地',
position: { x: 717.28, y: 273.13 },
industry: '种业',
metrics: [
{ label: '辐射带动:', value: '>15', unit: '万亩' },
{ label: '自建基地规模:', value: '4~8', unit: '万亩' }
]
}
],
'果蔬': [
{
id: 'fruit-popup1',
title: '源头',
content: '果蔬核心示范基地',
position: { x: 814.45, y: 464.02 },
industry: '果蔬',
metrics: [
{ label: '辐射带动:', value: '>25', unit: '万亩' },
{ label: '自建基地规模:', value: '8~12', unit: '万亩' }
]
}
]
}
};
const livestockAquacultureData: SupplyChainData = {
name: '畜牧-水产组合',
industries: ['畜牧', '水产'],
mapPoints: {
'畜牧': [
{ id: 'livestock-base1', type: 'base', x: 1203.07, y: 514.31, industry: '畜牧' },
{ id: 'livestock-chain1', type: 'chain', x: 1273.12, y: 551.14, industry: '畜牧' },
{ id: 'livestock-chain2', type: 'chain', x: 1403, y: 597.5, industry: '畜牧' },
{ id: 'livestock-chain3', type: 'chain', x: 1694.25, y: 645.5, industry: '畜牧' },
{ id: 'livestock-chain4', type: 'chain', x: 1237.87, y: 761.84, industry: '畜牧' }
],
'水产': [
{ id: 'aquaculture-base1', type: 'base', x: 1445, y: 560.35, industry: '水产' },
{ id: 'aquaculture-chain1', type: 'chain', x: 949.08, y: 680.31, industry: '水产' },
{ id: 'aquaculture-chain2', type: 'chain', x: 1178.36, y: 418.4, industry: '水产' },
{ id: 'aquaculture-chain3', type: 'chain', x: 1307.42, y: 551.47, industry: '水产' },
{ id: 'aquaculture-chain4', type: 'chain', x: 1403.37, y: 603.77, industry: '水产' }
]
},
keyMetrics: {
'畜牧': [
{ id: 'livestock-metric1', label: '养殖规模', value: '100', unit: '万头/年', industry: '畜牧' },
{ id: 'livestock-metric2', label: '自建养殖基地', value: '20', unit: '万亩', industry: '畜牧' },
{ id: 'livestock-metric3', label: '辐射带动面积', value: '30', unit: '万亩', industry: '畜牧' }
],
'水产': [
{ id: 'aquaculture-metric1', label: '养殖规模', value: '50', unit: '万吨/年', industry: '水产' },
{ id: 'aquaculture-metric2', label: '自建养殖基地', value: '15', unit: '万亩', industry: '水产' },
{ id: 'aquaculture-metric3', label: '辐射带动面积', value: '22', unit: '万亩', industry: '水产' }
]
},
supplyChainNetwork: {
'畜牧': {
connections: [
{ from: 'livestock-base1', to: 'livestock-chain1', type: 'supply' },
{ from: 'livestock-base1', to: 'livestock-chain2', type: 'supply' },
{ from: 'livestock-base1', to: 'livestock-chain3', type: 'supply' },
{ from: 'livestock-base1', to: 'livestock-chain4', type: 'supply' }
],
nodes: {
'livestock-base1': { id: 'livestock-base1', type: 'base', x: 1203.07, y: 514.31, industry: '畜牧' },
'livestock-chain1': { id: 'livestock-chain1', type: 'chain', x: 1273.12, y: 551.14, industry: '畜牧' },
'livestock-chain2': { id: 'livestock-chain2', type: 'chain', x: 1403, y: 597.5, industry: '畜牧' },
'livestock-chain3': { id: 'livestock-chain3', type: 'chain', x: 1694.25, y: 645.5, industry: '畜牧' },
'livestock-chain4': { id: 'livestock-chain4', type: 'chain', x: 1237.87, y: 761.84, industry: '畜牧' }
}
},
'水产': {
connections: [
{ from: 'aquaculture-base1', to: 'aquaculture-chain1', type: 'supply' },
{ from: 'aquaculture-base1', to: 'aquaculture-chain2', type: 'supply' },
{ from: 'aquaculture-base1', to: 'aquaculture-chain3', type: 'supply' },
{ from: 'aquaculture-base1', to: 'aquaculture-chain4', type: 'supply' }
],
nodes: {
'aquaculture-base1': { id: 'aquaculture-base1', type: 'base', x: 1445, y: 560.35, industry: '水产' },
'aquaculture-chain1': { id: 'aquaculture-chain1', type: 'chain', x: 949.08, y: 680.31, industry: '水产' },
'aquaculture-chain2': { id: 'aquaculture-chain2', type: 'chain', x: 1178.36, y: 418.4, industry: '水产' },
'aquaculture-chain3': { id: 'aquaculture-chain3', type: 'chain', x: 1307.42, y: 551.47, industry: '水产' },
'aquaculture-chain4': { id: 'aquaculture-chain4', type: 'chain', x: 1403.37, y: 603.77, industry: '水产' }
}
}
},
popupData: {
'畜牧': [
{
id: 'livestock-popup1',
title: '源头',
content: '畜牧核心示范基地',
position: { x: 717.28, y: 273.13 },
industry: '畜牧',
metrics: [
{ label: '辐射带动:', value: '>30', unit: '万亩' },
{ label: '自建基地规模:', value: '15~20', unit: '万亩' }
]
}
],
'水产': [
{
id: 'aquaculture-popup1',
title: '源头',
content: '水产核心示范基地',
position: { x: 814.45, y: 464.02 },
industry: '水产',
metrics: [
{ label: '辐射带动:', value: '>22', unit: '万亩' },
{ label: '自建基地规模:', value: '10~15', unit: '万亩' }
]
}
]
}
};
const freshFoodSaltData: SupplyChainData = {
name: '鲜食-泛盐组合',
industries: ['鲜食', '泛盐'],
mapPoints: {
'鲜食': [
{ id: 'fresh-base1', type: 'base', x: 1203.07, y: 514.31, industry: '鲜食' },
{ id: 'fresh-chain1', type: 'chain', x: 1273.12, y: 551.14, industry: '鲜食' },
{ id: 'fresh-chain2', type: 'chain', x: 1403, y: 597.5, industry: '鲜食' },
{ id: 'fresh-chain3', type: 'chain', x: 1694.25, y: 645.5, industry: '鲜食' },
{ id: 'fresh-chain4', type: 'chain', x: 1237.87, y: 761.84, industry: '鲜食' }
],
'泛盐': [
{ id: 'salt-base1', type: 'base', x: 1445, y: 560.35, industry: '泛盐' },
{ id: 'salt-chain1', type: 'chain', x: 949.08, y: 680.31, industry: '泛盐' },
{ id: 'salt-chain2', type: 'chain', x: 1178.36, y: 418.4, industry: '泛盐' },
{ id: 'salt-chain3', type: 'chain', x: 1319.74, y: 441.51, industry: '泛盐' },
{ id: 'salt-chain4', type: 'chain', x: 1403.37, y: 603.77, industry: '泛盐' }
]
},
keyMetrics: {
'鲜食': [
{ id: 'fresh-metric1', label: '加工能力达', value: '60', unit: '万吨/年', industry: '鲜食' },
{ id: 'fresh-metric2', label: '自建鲜食基地', value: '8', unit: '万亩', industry: '鲜食' },
{ id: 'fresh-metric3', label: '辐射带动面积', value: '18', unit: '万亩', industry: '鲜食' }
],
'泛盐': [
{ id: 'salt-metric1', label: '加工能力达', value: '40', unit: '万吨/年', industry: '泛盐' },
{ id: 'salt-metric2', label: '自建盐业基地', value: '6', unit: '万亩', industry: '泛盐' },
{ id: 'salt-metric3', label: '辐射带动面积', value: '12', unit: '万亩', industry: '泛盐' }
]
},
supplyChainNetwork: {
'鲜食': {
connections: [
{ from: 'fresh-base1', to: 'fresh-chain1', type: 'supply' },
{ from: 'fresh-base1', to: 'fresh-chain2', type: 'supply' },
{ from: 'fresh-base1', to: 'fresh-chain3', type: 'supply' },
{ from: 'fresh-base1', to: 'fresh-chain4', type: 'supply' }
],
nodes: {
'fresh-base1': { id: 'fresh-base1', type: 'base', x: 1203.07, y: 514.31, industry: '鲜食' },
'fresh-chain1': { id: 'fresh-chain1', type: 'chain', x: 1273.12, y: 551.14, industry: '鲜食' },
'fresh-chain2': { id: 'fresh-chain2', type: 'chain', x: 1403, y: 597.5, industry: '鲜食' },
'fresh-chain3': { id: 'fresh-chain3', type: 'chain', x: 1694.25, y: 645.5, industry: '鲜食' },
'fresh-chain4': { id: 'fresh-chain4', type: 'chain', x: 1237.87, y: 761.84, industry: '鲜食' }
}
},
'泛盐': {
connections: [
{ from: 'salt-base1', to: 'salt-chain1', type: 'supply' },
{ from: 'salt-base1', to: 'salt-chain2', type: 'supply' },
{ from: 'salt-base1', to: 'salt-chain3', type: 'supply' },
{ from: 'salt-base1', to: 'salt-chain4', type: 'supply' }
],
nodes: {
'salt-base1': { id: 'salt-base1', type: 'base', x: 1445, y: 560.35, industry: '泛盐' },
'salt-chain1': { id: 'salt-chain1', type: 'chain', x: 949.08, y: 680.31, industry: '泛盐' },
'salt-chain2': { id: 'salt-chain2', type: 'chain', x: 1178.36, y: 418.4, industry: '泛盐' },
'salt-chain3': { id: 'salt-chain3', type: 'chain', x: 1319.74, y: 441.51, industry: '泛盐' },
'salt-chain4': { id: 'salt-chain4', type: 'chain', x: 1403.37, y: 603.77, industry: '泛盐' }
}
}
},
popupData: {
'鲜食': [
{
id: 'fresh-popup1',
title: '源头',
content: '鲜食核心示范基地',
position: { x: 717.28, y: 273.13 },
industry: '鲜食',
metrics: [
{ label: '辐射带动:', value: '>18', unit: '万亩' },
{ label: '自建基地规模:', value: '5~8', unit: '万亩' }
]
}
],
'泛盐': [
{
id: 'salt-popup1',
title: '源头',
content: '泛盐核心示范基地',
position: { x: 814.45, y: 464.02 },
industry: '泛盐',
metrics: [
{ label: '辐射带动:', value: '>12', unit: '万亩' },
{ label: '自建基地规模:', value: '3~6', unit: '万亩' }
]
}
]
}
};
// 静态数据加载函数
const loadStaticData = async (dashboardType: DashboardType): Promise<SupplyChainData> => {
// 模拟API延迟
await new Promise(resolve => setTimeout(resolve, 500));
// 返回对应组合的静态数据
switch (dashboardType) {
case 'grain-oil':
return grainOilData;
case 'seed-fruit':
return seedFruitData;
case 'livestock-aquaculture':
return livestockAquacultureData;
case 'fresh-food-salt':
return freshFoodSaltData;
default:
throw new Error(`Unknown dashboard type: ${dashboardType}`);
}
};
queryClient.prefetchQuery在路由切换前预加载目标组合数据tests/unit/client/home/pages/SupplyChainDashboards/context/| Date | Version | Description | Author |
|---|---|---|---|
| 2025-11-15 | 1.0 | 初始故事创建,基于架构重构需求 | Claude |
| 2025-11-15 | 1.1 | 集成React Query和静态数据mock,更新数据加载策略 | Claude |
| 2025-11-15 | 1.2 | 从PRD提取4套组合的完整定位点坐标数据,完善静态数据定义 | Claude |
| 2025-11-15 | 1.3 | 从figma-jsx文档提取所有组合的完整定位点数据,包含完整的TypeScript数据定义 | Claude |
| 2025-11-15 | 1.4 | 数据提取完成:从现有组件和figma-jsx文档提取完整的关键指标数据、供应链网络数据和弹出框数据 | Claude |
src/client/home/pages/SupplyChainDashboards/context/SupplyChainContext.tsx - 统一数据Context实现src/client/home/pages/SupplyChainDashboards/SupplyChainDashboard.tsx - 动态路由组件src/client/home/routes.tsx - 动态路由配置src/client/home/pages/SupplyChainDashboards/context/ThemeContext.tsx - 保持原有功能src/client/home/index.tsx - React Query配置src/client/api.ts - API客户端配置src/client/home/pages/SupplyChainDashboards/components/SupplyChainMap.tsxsrc/client/home/pages/SupplyChainDashboards/components/SupplyChainModel.tsxsrc/client/home/pages/SupplyChainDashboards/components/KeyMetrics.tsxsrc/client/home/pages/SupplyChainDashboards/components/PopupInfoBox.tsxsrc/client/home/pages/SupplyChainDashboards/components/layout/Navigation.tsxsrc/client/home/pages/SupplyChainDashboards/components/layout/SupplyChainBackground.tsxsrc/client/home/pages/SupplyChainDashboards/components/layout/BackgroundGrid.tsxsrc/client/home/pages/SupplyChainDashboards/components/layout/HeaderBar.tsx