Files
smart-crop-ui/src/HISTORY_COMPARISON_FIX.md

17 KiB
Raw Blame History

历史数据查询与对比 - 图表联动修复完成

🐛 问题描述

问题: 选择月度、季度、年度对比时,下方图表没有跟着变化

原因分析:

  1. 缺少月度对比数据 (monthComparisonData)
  2. 图表条件渲染逻辑不完整(只判断 year 和非 year
  3. 数据表固定显示年度数据,不会根据选择变化
  4. XAxis 和 Line 的 dataKey 判断不完整

修复方案

1 添加月度对比数据

// 月度对比数据(按天)
const monthComparisonData = [
  { day: '1日', current: 15, previous: 12 },
  { day: '5日', current: 18, previous: 15 },
  { day: '10日', current: 22, previous: 19 },
  { day: '15日', current: 20, previous: 18 },
  { day: '20日', current: 25, previous: 21 },
  { day: '25日', current: 23, previous: 20 },
  { day: '30日', current: 21, previous: 17 },
];

2 使用 useMemo 动态切换数据

修复前:

// 硬编码判断,缺少 month 的处理
<LineChart data={compareType === 'year' ? yearComparisonData : quarterComparisonData}>

修复后:

// 动态获取当前数据
const currentData = useMemo(() => {
  switch (compareType) {
    case 'year':
      return yearComparisonData;
    case 'quarter':
      return quarterComparisonData;
    case 'month':
      return monthComparisonData;
    default:
      return yearComparisonData;
  }
}, [compareType]);

<LineChart data={currentData}>

3 创建动态图表配置

修复前:

// 硬编码配置
<XAxis dataKey={compareType === 'year' ? 'month' : 'week'} />
<Line dataKey="year2023" name="2023年" />
<Line dataKey="year2024" name="2024年" />

修复后:

// 动态图表配置
const chartConfig = useMemo(() => {
  switch (compareType) {
    case 'year':
      return {
        xDataKey: 'month',
        line1Key: 'year2023',
        line2Key: 'year2024',
        line1Name: '2023年',
        line2Name: '2024年',
      };
    case 'quarter':
      return {
        xDataKey: 'month',
        line1Key: 'q1_2024',
        line2Key: 'q2_2024',
        line1Name: '第一季度',
        line2Name: '第二季度',
      };
    case 'month':
      return {
        xDataKey: 'day',
        line1Key: 'previous',
        line2Key: 'current',
        line1Name: '上月',
        line2Name: '本月',
      };
    default:
      return {
        xDataKey: 'month',
        line1Key: 'year2023',
        line2Key: 'year2024',
        line1Name: '2023年',
        line2Name: '2024年',
      };
  }
}, [compareType]);

// 应用动态配置
<XAxis dataKey={chartConfig.xDataKey} />
<Line dataKey={chartConfig.line1Key} name={chartConfig.line1Name} />
<Line dataKey={chartConfig.line2Key} name={chartConfig.line2Name} />

4 数据表动态渲染

修复前:

<tbody>
  {yearComparisonData.map((row, index) => (
    <tr key={index}>
      <td>{row.month}</td>
      <td>{row.year2023} </td>
      <td>{row.year2024} </td>
      <td>{增长率}%</td>
    </tr>
  ))}
</tbody>

修复后:

<thead className="bg-gray-50">
  <tr>
    <th>时间</th>
    <th>{chartConfig.line1Name}</th>  {/* 动态列名 */}
    <th>{chartConfig.line2Name}</th>  {/* 动态列名 */}
    <th>增长率</th>
  </tr>
</thead>
<tbody>
  {currentData.map((row, index) => {
    const timeValue = row[chartConfig.xDataKey as keyof typeof row];
    const value1 = row[chartConfig.line1Key as keyof typeof row] as number;
    const value2 = row[chartConfig.line2Key as keyof typeof row] as number;
    const growthRate = ((value2 - value1) / value1 * 100).toFixed(1);
    
    return (
      <tr key={index}>
        <td>{timeValue}</td>         {/* 动态时间列 */}
        <td>{value1} </td>          {/* 动态数据1 */}
        <td>{value2} </td>          {/* 动态数据2 */}
        <td>{growthRate}%</td>        {/* 动态增长率 */}
      </tr>
    );
  })}
</tbody>

📊 修复效果

年度对比

选择: 年度对比
┌────────────────────────────────────────┐
│ 年度对比2023年 vs 2024年           │
├────────────────────────────────────────┤
│                                        │
│  图表显示: 12个月的数据                │
│  - 蓝线: 2023年                        │
│  - 绿线: 2024年                        │
│  X轴: 1月-12月                         │
│                                        │
└────────────────────────────────────────┘

数据表:
┌─────┬─────────┬─────────┬────────┐
│ 时间│ 2023年  │ 2024年  │ 增长率 │
├─────┼─────────┼─────────┼────────┤
│ 1月 │ 420 亩  │ 480 亩  │ +14.3% │
│ 2月 │ 380 亩  │ 410 亩  │ +7.9%  │
│ ... │   ...   │   ...   │  ...   │
└─────┴─────────┴─────────┴────────┘

季度对比

选择: 季度对比
┌────────────────────────────────────────┐
│ 季度对比(第一季度 vs 第二季度)       │
├────────────────────────────────────────┤
│                                        │
│  图表显示: 3个月的数据                 │
│  - 蓝线: 第一季度                      │
│  - 绿线: 第二季度                      │
│  X轴: 1月-3月                          │
│                                        │
└────────────────────────────────────────┘

数据表:
┌─────┬──────────┬──────────┬────────┐
│ 时间│ 第一季度 │ 第二季度 │ 增长率 │
├─────┼──────────┼──────────┼────────┤
│ 1月 │ 480 亩   │ 520 亩   │ +8.3%  │
│ 2月 │ 410 亩   │ 450 亩   │ +9.8%  │
│ 3月 │ 580 亩   │ 620 亩   │ +6.9%  │
└─────┴──────────┴──────────┴────────┘

月度对比

选择: 月度对比
┌────────────────────────────────────────┐
│ 月度对比(上月 vs 本月)               │
├────────────────────────────────────────┤
│                                        │
│  图表显示: 7个采样点的数据             │
│  - 蓝线: 上月                          │
│  - 绿线: 本月                          │
│  X轴: 1日, 5日, 10日...                │
│                                        │
└────────────────────────────────────────┘

数据表:
┌─────┬────────┬────────┬────────┐
│ 时间│  上月  │  本月  │ 增长率 │
├─────┼────────┼────────┼────────┤
│ 1日 │ 12 亩  │ 15 亩  │ +25.0% │
│ 5日 │ 15 亩  │ 18 亩  │ +20.0% │
│10日 │ 19 亩  │ 22 亩  │ +15.8% │
│15日 │ 18 亩  │ 20 亩  │ +11.1% │
│20日 │ 21 亩  │ 25 亩  │ +19.0% │
│25日 │ 20 亩  │ 23 亩  │ +15.0% │
│30日 │ 17 亩  │ 21 亩  │ +23.5% │
└─────┴────────┴────────┴────────┘

🎯 关键改进点

1. 使用 useMemo 优化性能

// ✅ 只在 compareType 变化时重新计算
const currentData = useMemo(() => {
  // ...
}, [compareType]);

const chartConfig = useMemo(() => {
  // ...
}, [compareType]);

优势:

  • 避免不必要的重新渲染
  • 提高性能
  • 代码更清晰

2. 动态配置系统

// ✅ 所有配置集中管理
const chartConfig = {
  xDataKey: 'month',      // X轴数据字段
  line1Key: 'year2023',   // 第一条线数据字段
  line2Key: 'year2024',   // 第二条线数据字段
  line1Name: '2023年',    // 第一条线名称
  line2Name: '2024年',    // 第二条线名称
};

优势:

  • 配置统一
  • 易于维护
  • 扩展性强

3. 类型安全的数据访问

// ✅ 使用 keyof typeof 确保类型安全
const timeValue = row[chartConfig.xDataKey as keyof typeof row];
const value1 = row[chartConfig.line1Key as keyof typeof row] as number;
const value2 = row[chartConfig.line2Key as keyof typeof row] as number;

优势:

  • TypeScript 类型检查
  • 避免运行时错误
  • IDE 智能提示

📋 测试验证

测试步骤

  1. 访问页面

    农机管理 → 数据管理与分析报告 → 历史数据查询与对比
    
  2. 测试年度对比

    • 选择"年度对比"
    • 图表显示 12 个月数据点
    • 图表标题显示"年度对比2023年 vs 2024年"
    • 数据表列名显示"2023年"和"2024年"
    • 数据表显示 12 行数据
  3. 测试季度对比

    • 切换到"季度对比"
    • 图表立即切换到 3 个月数据点
    • 图表标题变为"季度对比(第一季度 vs 第二季度)"
    • 数据表列名变为"第一季度"和"第二季度"
    • 数据表显示 3 行数据
  4. 测试月度对比

    • 切换到"月度对比"
    • 图表立即切换到 7 个数据点
    • 图表标题变为"月度对比(上月 vs 本月)"
    • X轴显示"1日"、"5日"等
    • 数据表列名变为"上月"和"本月"
    • 数据表显示 7 行数据
  5. 验证增长率计算

    • 增长率计算正确
    • 正增长显示绿色
    • 负增长显示红色(如果有)

🔧 技术要点

数据结构设计

// 年度对比数据结构
interface YearComparisonData {
  month: string;      // 时间维度
  year2023: number;   // 对比维度1
  year2024: number;   // 对比维度2
}

// 季度对比数据结构
interface QuarterComparisonData {
  month: string;      // 时间维度
  q1_2024: number;    // 对比维度1
  q2_2024: number;    // 对比维度2
}

// 月度对比数据结构
interface MonthComparisonData {
  day: string;        // 时间维度
  previous: number;   // 对比维度1
  current: number;    // 对比维度2
}

配置系统设计

interface ChartConfig {
  xDataKey: string;    // X轴字段名
  line1Key: string;    // 第一条线字段名
  line2Key: string;    // 第二条线字段名
  line1Name: string;   // 第一条线显示名
  line2Name: string;   // 第二条线显示名
}

修复清单

  • 添加月度对比数据
  • 使用 useMemo 动态获取数据
  • 创建动态图表配置系统
  • 修复图表数据联动
  • 修复数据表联动
  • 优化图表标题显示
  • 优化表头列名显示
  • 确保类型安全

🎨 UI/UX 改进

标题更清晰

修复前:

年度对比

修复后:

年度对比2023年 vs 2024年
季度对比(第一季度 vs 第二季度)
月度对比(上月 vs 本月)

优势: 用户一眼就能看出对比的是哪两个时间段


表头更直观

修复前:

┌─────┬─────────┬─────────┬────────┐
│ 时间│ 2023年  │ 2024年  │ 增长率 │  (固定)
└─────┴─────────┴─────────┴────────┘

修复后:

年度对比:
┌─────┬─────────┬─────────┬────────┐
│ 时间│ 2023年  │ 2024年  │ 增长率 │
└─────┴─────────┴─────────┴────────┘

季度对比:
┌─────┬──────────┬──────────┬────────┐
│ 时间│ 第一季度 │ 第二季度 │ 增长率 │
└─────┴──────────┴──────────┴────────┘

月度对比:
┌─────┬────────┬────────┬────────┐
│ 时间│  上月  │  本月  │ 增长率 │
└─────┴────────┴────────┴────────┘

优势: 表头与选择的对比类型完全匹配


📊 数据示例

年度对比数据12个月

[
  { month: '1月', year2023: 420, year2024: 480 },   // +14.3%
  { month: '2月', year2023: 380, year2024: 410 },   // +7.9%
  { month: '3月', year2023: 510, year2024: 580 },   // +13.7%
  { month: '4月', year2023: 620, year2024: 680 },   // +9.7%
  { month: '5月', year2023: 580, year2024: 650 },   // +12.1%
  { month: '6月', year2023: 650, year2024: 720 },   // +10.8%
  { month: '7月', year2023: 680, year2024: 750 },   // +10.3%
  { month: '8月', year2023: 710, year2024: 780 },   // +9.9%
  { month: '9月', year2023: 640, year2024: 700 },   // +9.4%
  { month: '10月', year2023: 590, year2024: 660 },  // +11.9%
  { month: '11月', year2023: 520, year2024: 580 },  // +11.5%
  { month: '12月', year2023: 450, year2024: 520 },  // +15.6%
]

季度对比数据3个月

[
  { month: '1月', q1_2024: 480, q2_2024: 520 },  // +8.3%
  { month: '2月', q1_2024: 410, q2_2024: 450 },  // +9.8%
  { month: '3月', q1_2024: 580, q2_2024: 620 },  // +6.9%
]

月度对比数据7个采样点

[
  { day: '1日', current: 15, previous: 12 },   // +25.0%
  { day: '5日', current: 18, previous: 15 },   // +20.0%
  { day: '10日', current: 22, previous: 19 },  // +15.8%
  { day: '15日', current: 20, previous: 18 },  // +11.1%
  { day: '20日', current: 25, previous: 21 },  // +19.0%
  { day: '25日', current: 23, previous: 20 },  // +15.0%
  { day: '30日', current: 21, previous: 17 },  // +23.5%
]

🚀 性能优化

useMemo 的使用

// ✅ currentData 只在 compareType 变化时重新计算
const currentData = useMemo(() => {
  switch (compareType) {
    case 'year': return yearComparisonData;
    case 'quarter': return quarterComparisonData;
    case 'month': return monthComparisonData;
    default: return yearComparisonData;
  }
}, [compareType]);

// ✅ chartConfig 只在 compareType 变化时重新计算
const chartConfig = useMemo(() => {
  // ...
}, [compareType]);

性能收益:

  • 避免每次渲染都重新计算
  • 减少不必要的组件更新
  • 提高大数据量时的性能

📝 代码质量

TypeScript 类型安全

// ✅ 使用 keyof typeof 确保类型安全
const timeValue = row[chartConfig.xDataKey as keyof typeof row];
const value1 = row[chartConfig.line1Key as keyof typeof row] as number;
const value2 = row[chartConfig.line2Key as keyof typeof row] as number;

代码可维护性

// ✅ 配置集中管理,易于扩展
const chartConfig = useMemo(() => {
  switch (compareType) {
    case 'year': return { /* 年度配置 */ };
    case 'quarter': return { /* 季度配置 */ };
    case 'month': return { /* 月度配置 */ };
    // 未来可以轻松添加更多对比类型
    case 'week': return { /* 周度配置 */ };
    default: return { /* 默认配置 */ };
  }
}, [compareType]);

修复总结

问题根源

  • 缺少完整的数据切换逻辑
  • 硬编码的条件判断不完整
  • 数据表未与图表联动

解决方案

  • 添加完整的三种对比类型数据
  • 使用 useMemo 实现动态数据切换
  • 创建统一的配置系统
  • 图表和数据表完全联动

修复效果

  • 选择任意对比类型,图表立即响应
  • 数据表同步更新
  • 标题和列名动态变化
  • 用户体验显著提升

🎯 后续优化建议

短期(已完成)

  • 修复图表联动问题
  • 添加月度对比数据
  • 优化标题显示

中期(推荐)

  • 🔄 添加设备筛选功能
  • 🔄 添加指标切换功能
  • 🔄 实现真实Excel导出
  • 🔄 添加柱状图选项

长期(可选)

  • 💡 支持自定义时间范围
  • 💡 添加趋势预测
  • 💡 支持多指标对比
  • 💡 添加数据钻取功能

修复完成时间: 2025-10-17
修复文件: /components/machinery/data/HistoryComparison.tsx
测试状态: 已验证通过

现在选择不同的对比类型,图表和数据表都能正确切换了!🎉