Files
smart-crop-ui/crop-x/docs/开发项目规范.md

15 KiB
Raw Blame History

开发项目规范

pathland-information/archive/statisticsname统计分析页面开发经验

总体开发经验总结

在实现统计分析页面过程中我们遵循了以下8条核心开发规范确保代码质量、可维护性和用户体验的一致性。

1. shadcn 样式系统优先原则

经验总结:

  • 优先使用shadcn的语义化颜色类bg-cardbg-background替代硬编码的Tailwind CSS颜色
  • 避免使用 bg-red-500 等具体颜色值,改用 bg-red-50 dark:bg-red-950 等语义化类
  • 统计卡片使用 bg-green-50 dark:bg-green-950 等主题感知的背景色

最佳实践:

// ✅ 推荐写法
<Card className="p-4 bg-green-50 dark:bg-green-950">
<Card className="bg-card hover:bg-muted">

// ❌ 避免写法
<Card className="p-4 bg-green-100">
<Card className="bg-white hover:bg-gray-100">

2. 标签组件样式精确还原原则

经验总结:

  • 严格按照参考文件实现标签的边框和颜色样式
  • 使用 style 属性精确控制颜色确保1:1还原视觉效果
  • 不同类型的标签有特定的样式特征需要保持一致

关键实现:

// 土壤类型标签:前缀彩色圆点
<div className="w-2 h-2 rounded-full mr-2" style={{ backgroundColor: type.color }} />

// 种植模式标签前缀emoji + 固定绿色边框
<span className="mr-1">{mode.emoji}</span>
style={{
  backgroundColor: filters.plantingModes.includes(mode.key) ? '#16a34a' : 'transparent',
  borderColor: '#16a34a',
}}

// 自定义标签:纯色边框背景
style={{
  backgroundColor: filters.tags.includes(tag.name) ? tag.color : 'transparent',
  borderColor: tag.color,
}}

3. 最小化修改原则

经验总结:

  • 严格遵循参考文件的功能边界,不添加多余功能
  • 保持与原有系统的功能一致性
  • 避免过度设计,专注核心功能实现

实施要点:

  • 只实现参考文件中明确展示的功能
  • 保持相同的用户交互流程
  • 维持原有的数据结构和逻辑

4. 暗色主题全面支持原则

经验总结:

  • 所有组件都必须支持暗色主题切换
  • 使用 dark: 前缀提供暗色模式样式
  • 确保在暗色主题下的可读性和视觉效果

实现模式:

// 统计卡片暗色主题
<Card className="p-4 bg-green-50 dark:bg-green-950">
  <div className="text-2xl text-green-600 dark:text-green-400">

// 背景和边框暗色主题
<Card className="bg-card hover:bg-muted">
<Card className="border-blue-200 dark:border-blue-800">

5. useReducer 状态管理架构原则

经验总结:

  • 使用useReducer实现复杂状态管理避免prop drilling
  • 通过dispatch实现跨组件状态同步
  • 集中化状态逻辑,提高代码可维护性

架构模式:

// Reducer定义
export interface LandStatisticsState {
  fields: Land[];
  filters: FilterCondition;
  statistics: StatisticsResult | null;
  chartType: 'bar' | 'pie';
}

// Action类型定义
export type LandStatisticsAction =
  | { type: 'SET_FIELDS'; payload: Land[] }
  | { type: 'UPDATE_FILTER'; payload: { key: keyof FilterCondition; value: any } }
  | { type: 'SET_STATISTICS'; payload: StatisticsResult | null };

// 状态同步使用
const handleFilterChange = (key: keyof FilterCondition, value: any) => {
  dispatch({ type: 'UPDATE_FILTER', payload: { key, value } });
};

6. 模块化组件架构原则

经验总结:

  • 每个页面建立独立的components文件夹
  • 按功能职责拆分组件,确保单一职责
  • 组件间通过props和回调函数通信

目录结构示例:

src/app/(app)/land-information/archive/statistics/
├── page.tsx                              # 主页面
└── components/
    ├── landStatisticsReducer.tsx         # 状态管理
    ├── FilterPanel.tsx                   # 筛选面板
    ├── StatisticsResults.tsx             # 统计结果
    └── UsageExamples.tsx                 # 使用示例

7. 完整依赖引用实现原则

经验总结:

  • 仔细分析参考文件的import依赖确保完整实现
  • 将所有引用的组件都实现在components目录中
  • 保持与参考文件相同的组件结构和功能

依赖检查清单:

  • UI组件Card, Button, Badge, Input, Label等
  • 图标组件lucide-react图标
  • 图表组件recharts相关组件
  • 工具函数toast通知等

8. 1:1 功能还原实现原则

经验总结:

  • 严格按照参考文件的功能逻辑实现
  • 保持相同的用户交互体验
  • 确保数据流和业务逻辑的一致性

关键实现要点:

  • 筛选条件的多选逻辑
  • 数据统计的计算方法
  • 图表切换和显示逻辑
  • 数据导出功能

开发工具和最佳实践

推荐工具链

  • 状态管理React useReducer
  • UI组件库shadcn/ui
  • 样式系统Tailwind CSS + 语义化颜色
  • 图表库Recharts
  • 图标库Lucide React
  • 通知系统Sonner

代码质量保证

  • TypeScript严格类型检查
  • ESLint代码规范检查
  • 组件props类型定义完整
  • 状态管理逻辑清晰可维护

测试数据管理

  • localStorage数据持久化
  • 完整的测试数据覆盖所有业务场景
  • 数据初始化和清理机制完善

通过遵循这些开发规范,我们可以确保代码的一致性、可维护性和用户体验的统一性。


pathland-information/archive/statisticsname统计分析页面开发经验与问题解决

问题1图表横轴显示不完整

问题描述:

  • 初始实现中,图表只显示有数据的土壤类型和种植模式
  • 没有数据的项目在横轴上不显示,导致图表看起来不完整

原始需求分析:

  • 土壤类型分布应显示所有定义的土壤类型即使数量为0
  • 种植模式分布应显示所有定义的种植模式,提供完整的分类视图

解决方案:

  • 修改数据计算逻辑,从"基于筛选结果生成数据"改为"基于所有定义的分类生成数据"
  • 使用 state.soilTypes.map()state.plantingModes.map() 确保显示所有定义的分类

代码改进对比:

// ❌ 初始实现(只显示有数据的分类)
const soilTypeMap = new Map<string, { count: number; area: number }>();
filteredFields.forEach(f => {
  const current = soilTypeMap.get(f.soilType) || { count: 0, area: 0 };
  soilTypeMap.set(f.soilType, {
    count: current.count + 1,
    area: current.area + f.area,
  });
});
const soilTypeDistribution = Array.from(soilTypeMap.entries()).map(([key, value]) => ({
  name: state.soilTypes.find(s => s.key === key)?.name || key,
  count: value.count,
  area: value.area,
  color: state.soilTypes.find(s => s.key === key)?.color || '#6b7280',
}));

// ✅ 最终实现显示所有定义的分类包括数量为0的
const soilTypeDistribution = state.soilTypes.map(soilType => {
  const count = filteredFields.filter(f => f.soilType === soilType.key).length;
  const area = filteredFields
    .filter(f => f.soilType === soilType.key)
    .reduce((sum, f) => sum + f.area, 0);
  return {
    name: soilType.name,
    count,
    area,
    color: soilType.color,
  };
});

问题2标签字体粗细不符合视觉要求

问题描述:

  • 筛选标签(土壤类型、种植模式、自定义标签)的字体过粗
  • 用户反馈需要调整为细字体,以匹配参考文件的视觉效果

原始需求分析:

  • 参考文件显示的是细字效果,需要精确还原视觉体验
  • 字体粗细影响整体UI的美观和专业度

解决方案:

  • 给所有Badge组件添加 font-light 类名
  • 保持其他样式(颜色、边框、悬停效果)不变,只调整字体粗细

代码改进:

// ❌ 初始实现
<Badge
  key={type.id}
  variant={filters.soilTypes.includes(type.key) ? 'default' : 'outline'}
  className="cursor-pointer"
  style={{ backgroundColor: filters.soilTypes.includes(type.key) ? type.color : 'transparent' }}
>
  {type.name}
</Badge>

// ✅ 最终实现(添加字体细体)
<Badge
  key={type.id}
  variant={filters.soilTypes.includes(type.key) ? 'default' : 'outline'}
  className="cursor-pointer font-light"
  style={{ backgroundColor: filters.soilTypes.includes(type.key) ? type.color : 'transparent' }}
>
  {type.name}
</Badge>

问题3测试数据覆盖不完整影响演示效果

问题描述:

  • localStorage中存在旧数据导致某些土壤类型和种植模式没有对应的地块数据
  • 部分图表项目显示为空或缺失,影响演示效果和用户体验

原始需求分析:

  • 所有土壤类型和种植模式都应该有对应的测试数据
  • 确保图表能完整展示所有分类的统计数据即使是0也要显示
  • 为用户提供完整的演示环境

解决方案:

  • 创建完整的测试数据集覆盖所有7种土壤类型和5种种植模式
  • loadData 函数中初始化这些测试数据,确保首次访问时有完整数据
  • 通过localStorage持久化确保数据在页面刷新后仍然存在

测试数据设计原则:

const testFields = [
  {
    id: '1',
    code: 'TD001',
    name: '东区沙质土试验田',
    area: 85.5,
    location: '东区1号地块',
    soilType: 'sandy',        // 沙质土
    plantingMode: 'conventional', // 传统种植
    tags: ['有机种植', '高产示范', '滴灌设施'],
    // ...其他完整字段
  },
  // 总计10个地块确保每个土壤类型和种植模式都有覆盖
  // 沙质土(2个)、黏质土(2个)、壤质土(2个)、泥炭土(1个)、石灰质土(1个)、粉质土(1个)、岩石土(1个)
  // 传统种植(3个)、有机种植(3个)、温室种植(2个)、水培种植(1个)、气培种植(1个)
];

问题4语义化颜色类使用存在不一致

问题描述:

  • 部分组件仍使用硬编码的Tailwind颜色类
  • 没有充分利用shadcn的语义化颜色系统
  • 在暗色主题下可能存在兼容性问题

原始需求分析:

  • 优先使用 bg-gray 等语义化颜色类
  • 避免写死的Tailwind CSS样式提高主题一致性
  • 建立统一的颜色使用标准

解决方案:

  • 全面检查并替换硬编码颜色为语义化颜色类
  • 统计卡片使用 bg-green-50 dark:bg-green-950 等主题感知背景色
  • 确保在暗色主题下的可读性和视觉效果一致性

颜色使用改进:

// ❌ 不一致的硬编码实现
<Card className="p-4 bg-green-100">
<div className="text-green-600">
<Card className="bg-white hover:bg-gray-100">

// ✅ 统一的语义化颜色实现
<Card className="p-4 bg-green-50 dark:bg-green-950">
<div className="text-2xl text-green-600 dark:text-green-400">
<Card className="bg-card hover:bg-muted">
<Card className="border-blue-200 dark:border-blue-800">

问题5多组件状态同步和数据管理复杂性

问题描述:

  • 多个组件之间需要共享状态使用prop传递会导致代码复杂且难以维护
  • 数据更新时容易出现状态不一致的问题
  • 缺乏集中化的状态管理机制

原始需求分析:

  • 使用useReducer实现集中化状态管理
  • 确保组件间数据同步的可靠性和性能
  • 简化组件间的通信逻辑

解决方案:

  • 设计完整的状态管理架构包括状态接口、Action类型和Reducer函数
  • 通过dispatch实现跨组件状态更新避免prop drilling
  • 使用localStorage进行数据持久化确保页面刷新后状态保持
  • 建立清晰的数据流和状态更新模式

状态管理架构设计:

// 完整的状态接口定义
export interface LandStatisticsState {
  fields: Land[];
  tags: LandTag[];
  soilTypes: SoilType[];
  plantingModes: PlantingMode[];
  filters: FilterCondition;
  statistics: StatisticsResult | null;
  chartType: 'bar' | 'pie';
}

// 细粒度的Action类型定义
export type LandStatisticsAction =
  | { type: 'SET_FIELDS'; payload: Land[] }
  | { type: 'SET_TAGS'; payload: LandTag[] }
  | { type: 'SET_SOIL_TYPES'; payload: SoilType[] }
  | { type: 'SET_PLANTING_MODES'; payload: PlantingMode[] }
  | { type: 'SET_FILTERS'; payload: FilterCondition }
  | { type: 'UPDATE_FILTER'; payload: { key: keyof FilterCondition; value: any } }
  | { type: 'TOGGLE_ARRAY_FILTER'; payload: { key: 'soilTypes' | 'plantingModes' | 'tags'; value: string } }
  | { type: 'CLEAR_FILTERS' }
  | { type: 'SET_STATISTICS'; payload: StatisticsResult | null }
  | { type: 'SET_CHART_TYPE'; payload: 'bar' | 'pie' };

// 跨组件状态同步实现
const handleFilterChange = (key: keyof FilterCondition, value: any) => {
  dispatch({ type: 'UPDATE_FILTER', payload: { key, value } });
};

const handleToggleArrayFilter = (key: 'soilTypes' | 'plantingModes' | 'tags', value: string) => {
  const currentArray = state.filters[key];
  const newArray = currentArray.includes(value)
    ? currentArray.filter(v => v !== value)
    : [...currentArray, value];
  dispatch({ type: 'TOGGLE_ARRAY_FILTER', payload: { key, value } });
};

开发经验对比总结

与原始要求的差异分析

原始要求 实际实现 差异说明 解决过程
使用shadcn语义化样式 完全实现 + 统一规范 需要建立统一的使用标准 全面替换硬编码颜色,建立语义化颜色使用指南
1:1还原标签样式 精确还原 + 字体优化 字体粗细需要调整以匹配视觉 添加font-light类名保持样式一致性
不动无关内容 完全遵循 严格保持功能边界,不添加多余功能 只实现参考文件中的明确功能
暗色主题支持 全面支持 需要系统化处理所有UI组件 使用dark:前缀系统化处理暗色主题
useReducer状态管理 架构实现 + 最佳实践 需要设计状态同步机制和数据持久化 建立完整的状态管理架构和同步机制
模块化组件 完全拆分 需要合理的组件职责划分和通信机制 按功能领域拆分组件通过props和回调通信
完整依赖引用 1:1还原 需要仔细分析引用关系和依赖完整性 建立依赖检查清单,确保所有引用组件完整实现
1:1功能还原 完整实现 需要精确还原业务逻辑和用户体验 严格对照参考文件实现所有功能

关键学习点和改进

  1. 数据完整性思维:不仅要实现功能,还要考虑数据的完整性和演示效果的完整性

    • 学会了从用户体验角度思考数据展示的完整性
    • 理解了即使count为0也应该显示的重要性
  2. 细节精确把控:字体粗细、颜色、边框等视觉细节需要精确还原

    • 培养了对UI细节的敏感度
    • 掌握了通过用户反馈快速迭代优化的方法
  3. 状态管理设计useReducer不仅是技术选择更是架构设计决策

    • 深入理解了状态管理的架构设计原则
    • 掌握了跨组件状态同步的最佳实践
  4. 渐进式优化:在开发过程中根据反馈不断调整和改进

    • 学会了灵活应对开发过程中的需求变化
    • 建立了基于反馈的快速响应机制
  5. 文档化习惯:将开发过程中的经验和教训记录下来,形成知识积累

    • 认识到文档化对团队协作和知识传承的重要性
    • 建立了完整的开发规范文档体系