22 KiB
22 KiB
📊 历史数据查询与对比功能 - 完整性检查报告
🎯 需求对照检查
✅ 已实现功能
| 需求项 | 状态 | 实现情况 |
|---|---|---|
| 用户灵活选择设备 | ✅ 部分实现 | 有设备筛选器,但未连接实际数据 |
| 灵活选择时间范围 | ⚠️ 部分实现 | 有对比类型选择,但缺少自定义时间范围 |
| 灵活选择指标 | ✅ 部分实现 | 有指标选择器,但未实现切换逻辑 |
| 时间对比功能 | ✅ 已实现 | 支持年度、季度、月度对比 |
| 折线图可视化 | ✅ 已实现 | 使用Recharts折线图展示 |
| 柱状图可视化 | ❌ 未实现 | 只有折线图,缺少柱状图 |
| 数据导出Excel | ⚠️ 占位实现 | 按钮存在,但只是alert提示 |
| 增长率计算 | ✅ 已实现 | 自动计算并显示增长率 |
📋 详细功能分析
1️⃣ 设备选择功能 ⚠️
当前状态:
<Select>
<SelectTrigger>
<SelectValue placeholder="全部设备" />
</SelectTrigger>
<SelectContent>
<SelectItem value="all">全部设备</SelectItem>
<SelectItem value="m1">约翰迪尔拖拉机</SelectItem>
<SelectItem value="m2">久保田收割机</SelectItem>
</SelectContent>
</Select>
问题:
- ❌ 没有
value和onValueChange绑定 - ❌ 设备列表是硬编码的,未从存储加载
- ❌ 选择设备后不会过滤数据
需要改进:
- ✅ 从 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小时)
任务:
- 设备选择器数据联动
- 指标切换功能
- 添加柱状图
- Excel导出功能
预期结果:
- ✅ 所有选择器都能正常工作
- ✅ 数据根据选择实时更新
- ✅ 支持折线图和柱状图
- ✅ 可以导出Excel文件
Phase 2: 时间对比增强(1-2小时)
任务:
- 添加快捷时间对比选项
- 实现自定义时间范围
- 完善对比逻辑
预期结果:
- ✅ 支持"本年vs去年"等快捷选项
- ✅ 可以自定义对比任意两个时间段
- ✅ 对比结果准确可靠
Phase 3: 可视化优化(1小时)
任务:
- 添加更多图表类型
- 优化图表样式
- 添加趋势分析
预期结果:
- ✅ 支持多种图表类型
- ✅ 图表美观易读
- ✅ 提供数据洞察
📝 代码示例
完整的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导出是占位符
- ❌ 缺少自定义时间范围
完善建议
优先级排序:
- 高: 数据联动、指标切换、柱状图
- 中: Excel导出、时间范围选择
- 低: 高级可视化、趋势分析
预计工作量: 4-6小时完成核心功能
文档版本: v1.0
检查日期: 2025-10-17
状态: ⚠️ 需要完善核心功能
总体评价: 基础框架良好,但需要完善数据联动、图表类型和导出功能才能满足完整需求。