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

22 KiB
Raw Blame History

📊 历史数据查询与对比功能 - 完整性检查报告

🎯 需求对照检查

已实现功能

需求项 状态 实现情况
用户灵活选择设备 部分实现 有设备筛选器,但未连接实际数据
灵活选择时间范围 ⚠️ 部分实现 有对比类型选择,但缺少自定义时间范围
灵活选择指标 部分实现 有指标选择器,但未实现切换逻辑
时间对比功能 已实现 支持年度、季度、月度对比
折线图可视化 已实现 使用Recharts折线图展示
柱状图可视化 未实现 只有折线图,缺少柱状图
数据导出Excel ⚠️ 占位实现 按钮存在但只是alert提示
增长率计算 已实现 自动计算并显示增长率

📋 详细功能分析

1 设备选择功能 ⚠️

当前状态:

<Select>
  <SelectTrigger>
    <SelectValue placeholder="全部设备" />
  </SelectTrigger>
  <SelectContent>
    <SelectItem value="all">全部设备</SelectItem>
    <SelectItem value="m1">约翰迪尔拖拉机</SelectItem>
    <SelectItem value="m2">久保田收割机</SelectItem>
  </SelectContent>
</Select>

问题:

  • 没有 valueonValueChange 绑定
  • 设备列表是硬编码的,未从存储加载
  • 选择设备后不会过滤数据

需要改进:

  • 从 machineryStorage 加载实际设备列表
  • 添加状态管理和数据筛选逻辑
  • 选择设备后更新图表和表格数据

2 时间范围选择 ⚠️

当前状态:

<Select value={compareType} onValueChange={setCompareType}>
  <SelectItem value="year">年度对比</SelectItem>
  <SelectItem value="quarter">季度对比</SelectItem>
  <SelectItem value="month">月度对比</SelectItem>
</Select>

问题:

  • 只能选择对比类型,不能选择具体的时间范围
  • 缺少"本年vs去年"这样的快捷选项
  • 没有自定义时间段选择器

需要改进:

  • 添加时间范围选择器(开始时间、结束时间)
  • 添加快捷选项:"本年vs去年"、"本季度vs去年同期"
  • 支持自定义对比周期

3 指标选择功能 ⚠️

当前状态:

<Select>
  <SelectTrigger>
    <SelectValue placeholder="作业面积" />
  </SelectTrigger>
  <SelectContent>
    <SelectItem value="area">作业面积</SelectItem>
    <SelectItem value="efficiency">作业效率</SelectItem>
    <SelectItem value="cost">作业成本</SelectItem>
    <SelectItem value="quality">作业质量</SelectItem>
  </SelectContent>
</Select>

问题:

  • 没有状态绑定,选择后不会更新
  • 图表数据没有根据指标切换
  • Y轴标签没有根据指标变化

需要改进:

  • 添加指标状态管理
  • 根据选择的指标切换图表数据
  • 动态更新Y轴标签和单位

4 时间对比功能

当前状态:

// 年度对比
{ month: '1月', year2023: 420, year2024: 480 }

// 季度对比
{ week: '第1周', q1: 120, q2: 135 }

优点:

  • 支持多种对比维度
  • 数据结构清晰
  • 自动切换对比周期

可以改进:

  • 添加更多快捷对比选项
  • 支持自定义对比周期

5 可视化图表 ⚠️

当前状态:

<LineChart data={compareType === 'year' ? yearComparisonData : quarterComparisonData}>
  <Line dataKey="year2023" name="2023年" />
  <Line dataKey="year2024" name="2024年" />
</LineChart>

优点:

  • 折线图实现完整
  • 图例清晰
  • 响应式设计

问题:

  • 只有折线图,缺少柱状图
  • 不支持图表类型切换
  • 缺少面积图等其他图表类型

需要改进:

  • 添加柱状图选项
  • 添加图表类型切换器
  • 支持组合图表(折线+柱状)

6 数据导出 ⚠️

当前状态:

const exportToExcel = () => {
  alert('导出Excel功能');
};

问题:

  • 只是一个占位符
  • 没有实际的导出逻辑
  • 不能真正导出Excel文件

需要改进:

  • 实现真实的Excel导出功能
  • 包含图表和数据表
  • 支持自定义导出格式

🔧 需要完善的功能

优先级1: 高(核心功能)

1. 设备选择与数据联动

const [selectedMachinery, setSelectedMachinery] = useState('all');
const [machinery, setMachinery] = useState<MachineryRecord[]>([]);

useEffect(() => {
  // 加载农机列表
  const machineryData = machineryStorage.getAllMachinery();
  setMachinery(machineryData);
}, []);

// 根据选择的设备过滤数据
const filteredData = useMemo(() => {
  if (selectedMachinery === 'all') return allData;
  return allData.filter(item => item.machineryId === selectedMachinery);
}, [selectedMachinery, allData]);

2. 指标切换功能

const [selectedMetric, setSelectedMetric] = useState('area');

const metricConfig = {
  area: { label: '作业面积', unit: '亩' },
  efficiency: { label: '作业效率', unit: '亩/小时' },
  cost: { label: '作业成本', unit: '元' },
  quality: { label: '作业质量', unit: '分' },
};

// 根据指标获取数据
const getMetricValue = (item: OperationData, metric: string) => {
  switch (metric) {
    case 'area': return item.area;
    case 'efficiency': return item.area / item.duration;
    case 'cost': return item.cost;
    case 'quality': return item.quality;
    default: return 0;
  }
};

3. 柱状图选项

const [chartType, setChartType] = useState<'line' | 'bar'>('line');

<div className="flex gap-2 mb-4">
  <Button 
    variant={chartType === 'line' ? 'default' : 'outline'}
    onClick={() => setChartType('line')}
  >
    折线图
  </Button>
  <Button 
    variant={chartType === 'bar' ? 'default' : 'outline'}
    onClick={() => setChartType('bar')}
  >
    柱状图
  </Button>
</div>

{chartType === 'line' ? (
  <LineChart data={comparisonData}>
    {/* 折线图 */}
  </LineChart>
) : (
  <BarChart data={comparisonData}>
    {/* 柱状图 */}
  </BarChart>
)}

优先级2: 中(增强功能)

4. 自定义时间范围

const [customTimeRange, setCustomTimeRange] = useState({
  period1: { start: '', end: '' },
  period2: { start: '', end: '' },
});

<div className="grid grid-cols-2 gap-4">
  <div>
    <h4>对比周期1</h4>
    <Input type="date" value={customTimeRange.period1.start} />
    <Input type="date" value={customTimeRange.period1.end} />
  </div>
  <div>
    <h4>对比周期2</h4>
    <Input type="date" value={customTimeRange.period2.start} />
    <Input type="date" value={customTimeRange.period2.end} />
  </div>
</div>

5. 快捷时间对比

const quickComparisons = [
  { label: '本年 vs 去年', value: 'year-to-year' },
  { label: '本月 vs 上月', value: 'month-to-month' },
  { label: '本季度 vs 去年同期', value: 'quarter-yoy' },
];

<Select>
  <SelectTrigger>
    <SelectValue placeholder="选择对比周期" />
  </SelectTrigger>
  <SelectContent>
    {quickComparisons.map(option => (
      <SelectItem key={option.value} value={option.value}>
        {option.label}
      </SelectItem>
    ))}
  </SelectContent>
</Select>

6. Excel导出功能

import * as XLSX from 'xlsx';

const exportToExcel = () => {
  const worksheet = XLSX.utils.json_to_sheet(comparisonData);
  const workbook = XLSX.utils.book_new();
  XLSX.utils.book_append_sheet(workbook, worksheet, '对比数据');
  
  const fileName = `历史数据对比_${new Date().toLocaleDateString()}.xlsx`;
  XLSX.writeFile(workbook, fileName);
};

优先级3: 低(优化功能)

7. 多指标对比

const [selectedMetrics, setSelectedMetrics] = useState(['area', 'efficiency']);

// 支持选择多个指标同时展示
<LineChart data={comparisonData}>
  {selectedMetrics.map(metric => (
    <Line 
      key={metric}
      dataKey={metric}
      name={metricConfig[metric].label}
      stroke={colors[metric]}
    />
  ))}
</LineChart>

8. 趋势分析

// 添加趋势分析卡片
<Card className="p-6">
  <h3>趋势分析</h3>
  <div className="grid grid-cols-3 gap-4">
    <div>
      <div className="text-sm text-muted-foreground">平均增长率</div>
      <div className="text-2xl text-green-600">+12.5%</div>
    </div>
    <div>
      <div className="text-sm text-muted-foreground">最大增幅</div>
      <div className="text-2xl text-blue-600">+20.3%</div>
    </div>
    <div>
      <div className="text-sm text-muted-foreground">趋势预测</div>
      <div className="text-2xl">📈 上升</div>
    </div>
  </div>
</Card>

📊 功能完善建议

建议1: 完善数据联动

// 完整的数据筛选逻辑
const filteredData = useMemo(() => {
  let data = allOperationData;
  
  // 按设备筛选
  if (selectedMachinery !== 'all') {
    data = data.filter(item => item.machineryId === selectedMachinery);
  }
  
  // 按时间范围筛选
  data = data.filter(item => {
    const itemDate = new Date(item.date);
    return itemDate >= startDate && itemDate <= endDate;
  });
  
  return data;
}, [selectedMachinery, startDate, endDate, allOperationData]);

// 按指标聚合数据
const aggregatedData = useMemo(() => {
  return aggregateByPeriod(filteredData, compareType, selectedMetric);
}, [filteredData, compareType, selectedMetric]);

建议2: 增强图表功能

// 图表类型切换
<Tabs value={chartType} onValueChange={setChartType}>
  <TabsList>
    <TabsTrigger value="line">折线图</TabsTrigger>
    <TabsTrigger value="bar">柱状图</TabsTrigger>
    <TabsTrigger value="area">面积图</TabsTrigger>
  </TabsList>
  
  <TabsContent value="line">
    <LineChart data={comparisonData}>
      {/* 折线图配置 */}
    </LineChart>
  </TabsContent>
  
  <TabsContent value="bar">
    <BarChart data={comparisonData}>
      {/* 柱状图配置 */}
    </BarChart>
  </TabsContent>
  
  <TabsContent value="area">
    <AreaChart data={comparisonData}>
      {/* 面积图配置 */}
    </AreaChart>
  </TabsContent>
</Tabs>

建议3: 实现真实Excel导出

const exportToExcel = () => {
  // 准备数据
  const exportData = comparisonData.map(row => ({
    '时间': row.month || row.week,
    [period1Label]: row.period1,
    [period2Label]: row.period2,
    '增长率': `${((row.period2 - row.period1) / row.period1 * 100).toFixed(1)}%`,
  }));
  
  // 创建工作表
  const worksheet = XLSX.utils.json_to_sheet(exportData);
  
  // 设置列宽
  worksheet['!cols'] = [
    { wch: 10 },
    { wch: 15 },
    { wch: 15 },
    { wch: 12 },
  ];
  
  // 创建工作簿
  const workbook = XLSX.utils.book_new();
  XLSX.utils.book_append_sheet(workbook, worksheet, '历史数据对比');
  
  // 导出文件
  const fileName = `历史数据对比_${selectedMetric}_${new Date().toLocaleDateString()}.xlsx`;
  XLSX.writeFile(workbook, fileName);
  
  // 显示成功提示
  toast.success('数据已成功导出!');
};

功能完善清单

核心功能(必须)

  • 设备选择器连接实际数据
  • 指标切换功能实现
  • 添加柱状图选项
  • 实现真实Excel导出
  • 添加时间范围选择器

增强功能(推荐)

  • 添加"本年vs去年"快捷选项
  • 支持自定义对比周期
  • 图表类型切换(折线/柱状/面积)
  • 多指标同时对比
  • 趋势分析功能

优化功能(可选)

  • 数据钻取功能
  • 预测分析
  • 同比环比分析
  • 导出包含图表的PDF

🎯 实施计划

Phase 1: 核心功能完善2-3小时

任务:

  1. 设备选择器数据联动
  2. 指标切换功能
  3. 添加柱状图
  4. Excel导出功能

预期结果:

  • 所有选择器都能正常工作
  • 数据根据选择实时更新
  • 支持折线图和柱状图
  • 可以导出Excel文件

Phase 2: 时间对比增强1-2小时

任务:

  1. 添加快捷时间对比选项
  2. 实现自定义时间范围
  3. 完善对比逻辑

预期结果:

  • 支持"本年vs去年"等快捷选项
  • 可以自定义对比任意两个时间段
  • 对比结果准确可靠

Phase 3: 可视化优化1小时

任务:

  1. 添加更多图表类型
  2. 优化图表样式
  3. 添加趋势分析

预期结果:

  • 支持多种图表类型
  • 图表美观易读
  • 提供数据洞察

📝 代码示例

完整的HistoryComparison组件改进版

import { useState, useMemo, useEffect } from 'react';
import { Card } from '../../ui/card';
import { Button } from '../../ui/button';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../ui/select';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '../../ui/tabs';
import { 
  LineChart, Line, BarChart, Bar, 
  XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer 
} from 'recharts';
import { Download, Calendar, TrendingUp, BarChart3 } from 'lucide-react';
import { machineryStorage } from '../../../lib/machineryStorage';
import { MachineryRecord } from '../../../types/machinery';
import * as XLSX from 'xlsx';
import { toast } from 'sonner';

export function HistoryComparison() {
  // 状态管理
  const [compareType, setCompareType] = useState('year');
  const [selectedMachinery, setSelectedMachinery] = useState('all');
  const [selectedMetric, setSelectedMetric] = useState('area');
  const [chartType, setChartType] = useState<'line' | 'bar'>('line');
  const [machinery, setMachinery] = useState<MachineryRecord[]>([]);
  
  // 加载农机列表
  useEffect(() => {
    const machineryData = machineryStorage.getAllMachinery();
    setMachinery(machineryData);
  }, []);
  
  // 指标配置
  const metricConfig = {
    area: { label: '作业面积', unit: '亩' },
    efficiency: { label: '作业效率', unit: '亩/小时' },
    cost: { label: '作业成本', unit: '元' },
    quality: { label: '作业质量', unit: '分' },
  };
  
  // 模拟数据(实际应该从后端或存储加载)
  const yearComparisonData = [
    { month: '1月', year2023: 420, year2024: 480 },
    { month: '2月', year2023: 380, year2024: 410 },
    // ...
  ];
  
  // Excel导出
  const exportToExcel = () => {
    const exportData = yearComparisonData.map(row => ({
      '时间': row.month,
      '2023年': row.year2023,
      '2024年': row.year2024,
      '增长率': `${((row.year2024 - row.year2023) / row.year2023 * 100).toFixed(1)}%`,
    }));
    
    const worksheet = XLSX.utils.json_to_sheet(exportData);
    const workbook = XLSX.utils.book_new();
    XLSX.utils.book_append_sheet(workbook, worksheet, '历史数据对比');
    
    XLSX.writeFile(workbook, `历史数据对比_${new Date().toLocaleDateString()}.xlsx`);
    toast.success('数据已成功导出!');
  };
  
  return (
    <div className="space-y-6">
      {/* 标题和导出按钮 */}
      <div className="flex items-center justify-between">
        <div>
          <h2 className="text-green-800">历史数据查询与对比</h2>
          <p className="text-muted-foreground">多维度历史数据对比分析</p>
        </div>
        <Button onClick={exportToExcel}>
          <Download className="w-4 h-4 mr-2" />
          导出Excel
        </Button>
      </div>

      {/* 查询条件 */}
      <Card className="p-6">
        <h3 className="mb-4">查询条件</h3>
        <div className="grid grid-cols-1 md:grid-cols-4 gap-4">
          {/* 对比类型 */}
          <div>
            <label className="text-sm mb-2 block">对比类型</label>
            <Select value={compareType} onValueChange={setCompareType}>
              <SelectTrigger>
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="year">年度对比</SelectItem>
                <SelectItem value="quarter">季度对比</SelectItem>
                <SelectItem value="month">月度对比</SelectItem>
                <SelectItem value="year-to-year">本年 vs 去年</SelectItem>
              </SelectContent>
            </Select>
          </div>

          {/* 设备筛选 */}
          <div>
            <label className="text-sm mb-2 block">设备筛选</label>
            <Select value={selectedMachinery} onValueChange={setSelectedMachinery}>
              <SelectTrigger>
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="all">全部设备</SelectItem>
                {machinery.map(m => (
                  <SelectItem key={m.id} value={m.id}>
                    {m.name}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
          </div>

          {/* 指标选择 */}
          <div>
            <label className="text-sm mb-2 block">指标选择</label>
            <Select value={selectedMetric} onValueChange={setSelectedMetric}>
              <SelectTrigger>
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                {Object.entries(metricConfig).map(([key, config]) => (
                  <SelectItem key={key} value={key}>
                    {config.label}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
          </div>

          {/* 查询按钮 */}
          <div className="flex items-end">
            <Button className="w-full">
              <Calendar className="w-4 h-4 mr-2" />
              查询
            </Button>
          </div>
        </div>
      </Card>

      {/* 图表类型切换 */}
      <Card className="p-6">
        <div className="flex items-center justify-between mb-4">
          <h3>
            {compareType === 'year' ? '年度对比' : compareType === 'quarter' ? '季度对比' : '月度对比'}
            - {metricConfig[selectedMetric].label}
          </h3>
          <div className="flex gap-2">
            <Button
              variant={chartType === 'line' ? 'default' : 'outline'}
              size="sm"
              onClick={() => setChartType('line')}
            >
              <TrendingUp className="w-4 h-4 mr-1" />
              折线图
            </Button>
            <Button
              variant={chartType === 'bar' ? 'default' : 'outline'}
              size="sm"
              onClick={() => setChartType('bar')}
            >
              <BarChart3 className="w-4 h-4 mr-1" />
              柱状图
            </Button>
          </div>
        </div>
        
        <ResponsiveContainer width="100%" height={400}>
          {chartType === 'line' ? (
            <LineChart data={yearComparisonData}>
              <CartesianGrid strokeDasharray="3 3" />
              <XAxis dataKey="month" />
              <YAxis />
              <Tooltip />
              <Legend />
              <Line type="monotone" dataKey="year2023" stroke="#3b82f6" strokeWidth={2} name="2023年" />
              <Line type="monotone" dataKey="year2024" stroke="#10b981" strokeWidth={2} name="2024年" />
            </LineChart>
          ) : (
            <BarChart data={yearComparisonData}>
              <CartesianGrid strokeDasharray="3 3" />
              <XAxis dataKey="month" />
              <YAxis />
              <Tooltip />
              <Legend />
              <Bar dataKey="year2023" fill="#3b82f6" name="2023年" />
              <Bar dataKey="year2024" fill="#10b981" name="2024年" />
            </BarChart>
          )}
        </ResponsiveContainer>
      </Card>

      {/* 对比数据表 */}
      <Card className="p-6">
        <h3 className="mb-4">对比数据详情</h3>
        <div className="overflow-x-auto">
          <table className="w-full">
            <thead className="bg-gray-50">
              <tr>
                <th className="px-4 py-2 text-left text-sm">时间</th>
                <th className="px-4 py-2 text-right text-sm">2023</th>
                <th className="px-4 py-2 text-right text-sm">2024</th>
                <th className="px-4 py-2 text-right text-sm">增长率</th>
              </tr>
            </thead>
            <tbody>
              {yearComparisonData.map((row, index) => (
                <tr key={index} className="border-t">
                  <td className="px-4 py-2 text-sm">{row.month}</td>
                  <td className="px-4 py-2 text-sm text-right">
                    {row.year2023} {metricConfig[selectedMetric].unit}
                  </td>
                  <td className="px-4 py-2 text-sm text-right">
                    {row.year2024} {metricConfig[selectedMetric].unit}
                  </td>
                  <td className={`px-4 py-2 text-sm text-right ${
                    row.year2024 > row.year2023 ? 'text-green-600' : 'text-red-600'
                  }`}>
                    {((row.year2024 - row.year2023) / row.year2023 * 100).toFixed(1)}%
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </Card>
    </div>
  );
}

总结

当前状态

优点:

  • 基础框架完整
  • UI设计合理
  • 基本的对比功能可用

不足:

  • 缺少数据联动
  • 指标切换未实现
  • 只有折线图
  • Excel导出是占位符
  • 缺少自定义时间范围

完善建议

优先级排序:

  1. : 数据联动、指标切换、柱状图
  2. : Excel导出、时间范围选择
  3. : 高级可视化、趋势分析

预计工作量: 4-6小时完成核心功能


文档版本: v1.0
检查日期: 2025-10-17
状态: ⚠️ 需要完善核心功能

总体评价: 基础框架良好,但需要完善数据联动、图表类型和导出功能才能满足完整需求。