# Story 005.002: 统一数据Context和路由架构

**父史诗**: 史诗005 - 供应链可视化大屏实现
docs/prd/epic-005-supply-chain-visualization.md

## Status
Ready for Review

## Story
**As a** 前端开发者
**I want** 统一的供应链数据Context和动态路由架构
**so that** 我可以通过路由参数动态加载4套组合大屏数据，实现组件复用和统一数据管理

**Scope**: 扩展ThemeContext为SupplyChainContext，创建统一数据结构，实现路由参数解析，配置动态路由

## Acceptance Criteria
1. **扩展ThemeContext为SupplyChainContext** - 创建统一的供应链数据Context，支持4套组合和8个产业的数据管理
2. **创建统一数据结构** - 定义定位点坐标、关键指标、供应链网络数据的统一接口
3. **实现路由参数解析** - 通过React Router的useParams获取当前组合类型，动态加载对应数据
4. **配置动态路由** - 在现有路由配置中添加4套组合的动态路由参数
5. **优化数据加载机制** - 实现数据缓存和动态加载，支持路由切换时的性能优化

## Tasks / Subtasks
- [x] 扩展ThemeContext为SupplyChainContext (AC: #1)
  - [x] 在`src/client/home/pages/SupplyChainDashboards/context/`目录下创建SupplyChainContext.tsx
  - [x] 扩展现有ThemeContext接口，添加组合类型和统一数据管理
  - [x] 实现组合切换和产业切换的状态管理
  - [x] 添加数据加载和缓存机制
- [x] 创建统一数据结构 (AC: #2)
  - [x] 定义组合类型接口：`DashboardType`
  - [x] 定义供应链数据接口：`SupplyChainData`
  - [x] 定义定位点坐标接口：`LocationPoint`
  - [x] 定义关键指标接口：`MetricData`
  - [x] 定义供应链网络接口：`SupplyChainNetwork`
  - [x] 定义弹出框数据接口：`PopupData`
- [x] 实现路由参数解析 (AC: #3)
  - [x] 分析现有路由配置结构
  - [x] 实现useParams获取组合类型
  - [x] 创建路由参数解析工具函数
  - [x] 添加参数验证和错误处理
- [x] 配置动态路由 (AC: #4)
  - [x] 修改`src/client/home/routes.tsx`中的路由配置
  - [x] 添加4套组合的动态路由：`/supply-chain/:dashboardType`
  - [x] 配置路由参数验证和默认值
  - [x] 集成到现有导航系统
- [x] 集成React Query和静态数据mock (AC: #5)
  - [x] 配置React Query QueryClient
  - [x] 创建静态数据mock文件，包含4套组合的完整数据定义
  - [x] 从PRD提取所有定位点坐标数据
  - [x] 实现useSupplyChainData查询Hook
  - [x] 集成React Query到SupplyChainContext
  - [x] 实现数据预加载和缓存策略
  - [x] 添加加载状态和错误处理
  - [x] 优化路由切换性能
  - [x] 实现数据懒加载机制
- [ ] 集成测试和验证 (AC: #1-#5)
  - [ ] 编写Context单元测试
  - [ ] 测试路由参数解析功能
  - [ ] 验证数据加载性能
  - [ ] 测试组合切换功能

## Dev Notes

### 技术栈和前端架构 [Source: architecture/tech-stack.md#前端框架]
- **前端框架**: React 19.1.0 + TypeScript
- **状态管理**: React Context (本地状态) + React Query (服务端状态)
- **路由管理**: React Router
- **样式系统**: Tailwind CSS 4.1.11
- **构建工具**: Vite 7.0.0
- **数据获取**: @tanstack/react-query 5.83.0 [Source: architecture/tech-stack.md#状态管理]

### 项目结构指导 [Source: architecture/source-tree.md#前端应用]
- **Context位置**: `src/client/home/pages/SupplyChainDashboards/context/SupplyChainContext.tsx`
- **路由配置**: `src/client/home/routes.tsx`
- **类型定义**: `src/share/types.ts` (共享类型)
- **测试位置**: `tests/unit/client/home/pages/SupplyChainDashboards/context/`

### 组件架构模式 [Source: architecture/component-architecture.md#前端组件架构]
- **Context设计**: 遵循现有React Context模式，提供类型安全的接口
- **状态管理**: 使用useState和useReducer管理本地状态
- **数据流**: 单向数据流，通过Context Provider传递数据
- **错误处理**: 统一的错误边界和加载状态管理

### 现有ThemeContext分析 [Source: src/client/home/pages/SupplyChainDashboards/context/ThemeContext.tsx]
- **当前状态**: 已实现产业类型定义和主题色管理
- **扩展点**: 需要添加组合类型、数据加载、路由集成功能
- **兼容性**: 保持现有ThemeContext接口不变，向后兼容

### 现有路由配置分析 [Source: src/client/home/routes.tsx]
- **当前路由**: 已有静态路由`/supply-chain/grain-oil`
- **扩展策略**: 改为动态路由`/supply-chain/:dashboardType`
- **参数验证**: 需要添加路由参数验证和默认值处理

### 统一数据结构设计 [Source: docs/prd/epic-005-supply-chain-visualization.md#统一数据Context设计]
```typescript
// 组合类型定义
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>;
}
```

### 路由配置设计
```typescript
// 路由参数配置
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' }
  }
];
```

### 数据集成策略 [Source: architecture/component-architecture.md#技术栈配置]

#### 1. React Query集成
使用@tanstack/react-query进行服务端状态管理，实现数据获取、缓存和同步：

```typescript
// 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,
  });
};
```

#### 2. 静态数据mock定义 [Source: docs/prd/epic-005-supply-chain-visualization.md#Stories]
基于现有粮食-油脂大屏数据和PRD中的坐标数据，定义4套组合的静态数据：

**粮食-油脂组合**: 使用现有GrainOilDashboard中的数据

**种业-果蔬组合**:
- **种业定位点坐标**:
  - base1[1142.89,717.84], base2[1664.25,530.82], base3[1435,527.14], base4[1203.07,514.31]
  - chain1[1273.12,551.14], chain2[1403,597.5], chain3[1694.25,645.5], chain4[1237.87,761.84]
- **果蔬定位点坐标**:
  - base1[985,610.22], base2[1125.81,409.52], base3[1229.57,570], base4[1445,560.35]
  - chain1[949.08,680.31]

**畜牧-水产组合**:
- **畜牧定位点坐标**:
  - base1[1203.07,514.31]
  - chain1[1273.12,551.14], chain2[1403,597.5], chain3[1694.25,645.5], chain4[1237.87,761.84]
- **水产定位点坐标**:
  - base1[1445,560.35]
  - chain1[949.08,680.31], chain2[1178.36,418.4], chain3[1307.42,551.47], chain4[1403.37,603.77]

**鲜食-泛盐组合**:
- **鲜食定位点坐标**:
  - base1[1203.07,514.31]
  - chain1[1273.12,551.14], chain2[1403,597.5], chain3[1694.25,645.5], chain4[1237.87,761.84]
- **泛盐定位点坐标**:
  - base1[1445,560.35]
  - chain1[949.08,680.31], chain2[1178.36,418.4], chain3[1319.74,441.51], chain4[1403.37,603.77]

#### 3. 静态数据定义和加载策略 [Source: docs/figma-jsx/*.md]

```typescript
// 静态数据定义
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}`);
  }
};
```

#### 4. React Query性能优化
- **数据预加载**: 使用`queryClient.prefetchQuery`在路由切换前预加载目标组合数据
- **缓存机制**: React Query自动管理缓存，减少重复加载
- **懒加载**: 复杂组件按需加载
- **错误重试**: React Query内置错误重试机制
- **乐观更新**: 支持数据更新时的乐观UI更新

### 兼容性要求
- [ ] 现有ThemeContext功能保持不变
- [ ] 现有路由配置向后兼容
- [ ] 现有组件无需修改即可使用新Context
- [ ] 性能指标满足要求（加载时间<3秒）

### 性能要求 [Source: docs/prd/epic-005-supply-chain-visualization.md#性能验收]
- **Context初始化时间**: < 100ms
- **数据加载时间**: < 2秒
- **路由切换响应时间**: < 1秒
- **内存使用**: 合理，支持数据缓存

### 测试标准要求 [Source: architecture/testing-strategy.md#单元测试]
- **测试框架**: Vitest + Testing Library
- **测试位置**: `tests/unit/client/home/pages/SupplyChainDashboards/context/`
- **覆盖率目标**: ≥ 85%
- **测试类型**: Context功能测试、路由参数测试、数据加载测试

## Testing
### 测试策略
- **测试类型**: 单元测试 + 集成测试
- **测试范围**: Context功能、路由参数解析、数据加载机制
- **测试工具**: Vitest + Testing Library + React Router Testing Library
- **测试数据**: 使用工厂模式创建测试数据

### 测试验证点
- Context正确初始化和状态管理
- 路由参数正确解析和验证
- React Query数据加载和缓存机制正常工作
- 静态数据mock正确返回
- 组合切换功能正常
- 错误处理和加载状态正确
- 性能指标满足要求

### 测试用例
- 验证SupplyChainContext初始状态
- 测试组合切换功能
- 验证路由参数解析
- 测试React Query数据加载和缓存
- 验证静态数据mock正确性
- 验证错误处理机制
- 测试性能指标

## Change Log
| 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 |

## Dev Agent Record

### Agent Model Used
- Claude Sonnet 4.5 (model ID: 'claude-sonnet-4-5-20250929')

### Debug Log References
- 代码检查和分析完成于 2025-11-16
- 发现实际实现已基本完成，主要功能已实现

### Completion Notes List
1. **SupplyChainContext已实现** - 包含完整的TypeScript接口定义和4套组合的静态数据
2. **动态路由已配置** - 使用React Router的useParams获取组合类型参数
3. **React Query集成完成** - 数据加载、缓存和状态管理已实现
4. **组件结构完整** - SupplyChainDashboard组件已集成所有子组件
5. **向后兼容保持** - 现有ThemeContext功能保持不变

### File List
#### 新创建/修改的文件
- `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.tsx`
- `src/client/home/pages/SupplyChainDashboards/components/SupplyChainModel.tsx`
- `src/client/home/pages/SupplyChainDashboards/components/KeyMetrics.tsx`
- `src/client/home/pages/SupplyChainDashboards/components/PopupInfoBox.tsx`
- `src/client/home/pages/SupplyChainDashboards/components/layout/Navigation.tsx`
- `src/client/home/pages/SupplyChainDashboards/components/layout/SupplyChainBackground.tsx`
- `src/client/home/pages/SupplyChainDashboards/components/layout/BackgroundGrid.tsx`
- `src/client/home/pages/SupplyChainDashboards/components/layout/HeaderBar.tsx`

## QA Results
- **功能完整性**: ✅ 主要功能已实现
- **代码质量**: ✅ TypeScript类型安全，React Query集成良好
- **性能**: ✅ 数据缓存和懒加载机制已实现
- **兼容性**: ✅ 向后兼容现有功能
- **测试覆盖**: ⚠️ 缺少单元测试和集成测试
- **文档**: ✅ 代码注释和接口文档完整