在这里插入图片描述

1. 这个功能解决什么问题

资产健康度帮助管理者"直观了解"井盖资产状态,核心价值体现在以下维度:

  • 健康度分层展示:将井盖资产状态划分为优秀、良好、一般、较差四个等级,实现状态标准化
  • 可视化呈现:通过饼图直观展示不同健康等级资产的占比,降低数据理解成本
  • 数据模拟能力:支持固定比例的模拟数据配置,便于功能调试和演示
  • 视觉体验优化:定制饼图颜色、中心圆尺寸、页面布局,提升用户视觉体验

这个页面是典型的"数据可视化"场景,适合做 PieChart + PieChartSectionData 的最佳实践示例。

2. 相关文件一览

  • lib/feature_pages.dartAssetHealthPage):核心页面文件,包含资产健康度页面的UI布局、饼图配置和数据渲染逻辑

3. 饼图数据配置

AssetHealthPage 核心是通过 PieChartData 配置资产健康度分布数据,关键配置项说明:

  • sections:饼图扇区数组,每个扇区对应一个健康等级
  • value:扇区数值,代表该等级资产的占比/数量
  • color:扇区颜色,通过色彩区分不同健康等级
  • centerSpaceRadius:中心空白圆半径,优化饼图视觉效果
  • sectionsSpace:扇区间距,避免扇区粘连,提升可读性
final pie = PieChartData(
  sections: [
    PieChartSectionData(value: 45, color: Colors.green, title: '优秀'),
    PieChartSectionData(value: 30, color: Colors.blue, title: '良好'),
    PieChartSectionData(value: 15, color: Colors.orange, title: '一般'),
    PieChartSectionData(value: 10, color: Colors.red, title: '较差'),
  ],
  centerSpaceRadius: 38,
  sectionsSpace: 2,
);

上述代码中:

  • 优秀等级占比45%,使用绿色(视觉上代表健康、正常)
  • 良好等级占比30%,使用蓝色(代表稳定、无风险)
  • 一般等级占比15%,使用橙色(轻度警示)
  • 较差等级占比10%,使用红色(高风险警示)
  • 中心圆半径设为38,既保留饼图完整性,又避免视觉拥挤
  • 扇区间距设为2,保证各扇区边界清晰

4. 页面布局

资产健康度页面采用多层嵌套布局,核心设计思路:

  • 外层Padding:给页面整体预留12px边距,避免内容贴边
  • Card组件:包裹核心内容,增加阴影和圆角,提升视觉层次
  • 内层Padding:给Card内部内容预留12px边距,优化内容与容器的间距
  • Column纵向布局:分离标题和饼图,保证内容结构清晰
  • 固定高度SizedBox:限制饼图高度为260px,避免布局自适应导致的抖动
Padding(
  padding: const EdgeInsets.all(12),
  child: Card(
    child: Padding(
      padding: const EdgeInsets.all(12),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          const Text('资产健康度分布'),
          const SizedBox(height: 12),
          SizedBox(height: 260, child: PieChart(pie)),
        ],
      ),
    ),
  ),
)

布局细节优化说明:

  • crossAxisAlignment: CrossAxisAlignment.start:让标题左对齐,符合用户阅读习惯
  • SizedBox(height: 12):标题与饼图之间预留12px间距,避免内容紧凑
  • PieChart(pie):将配置好的饼图数据传入组件,完成可视化渲染

5. 完整页面代码(工程真实内容)

完整的资产健康度页面包含页面骨架和核心逻辑,关键组成部分:

  • StatelessWidget:页面为静态展示型,使用无状态组件提升性能
  • Scaffold:基础页面骨架,包含AppBar和body
  • AppBar:设置页面标题,提供导航返回能力
  • 嵌套布局:延续上述的Padding+Card+Column布局逻辑
class AssetHealthPage extends StatelessWidget {
  const AssetHealthPage({super.key});

  
  Widget build(BuildContext context) {
    final pie = PieChartData(
      sections: [
        PieChartSectionData(value: 45, color: Colors.green, title: '优秀'),
        PieChartSectionData(value: 30, color: Colors.blue, title: '良好'),
      ],
      centerSpaceRadius: 38,
      sectionsSpace: 2,
    );

    return Scaffold(
      appBar: AppBar(title: const Text('资产健康度')),
      body: Padding(
        padding: const EdgeInsets.all(12),
        child: Card(
          child: Padding(
            padding: const EdgeInsets.all(12),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                const Text('资产健康度分布'),
                const SizedBox(height: 12),
                SizedBox(height: 260, child: PieChart(pie)),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

代码精简说明:

  • 上述代码仅保留优秀、良好两个扇区示例,减少代码长度
  • 核心布局结构完整保留,确保页面渲染逻辑不变
  • 无状态组件特性:页面数据无动态变化,无需维护状态,简化代码

6. 资产健康度数据模型

为实现资产健康度数据的规范化管理,设计完整的数据模型体系,核心设计原则:

  • 完整性:覆盖资产健康度全维度信息
  • 可扩展性:支持新增字段和关联数据
  • 类型安全:使用枚举和自定义类,避免类型错误
  • 可追溯性:记录创建时间、更新时间、检查时间等关键时间节点

6.1 核心健康度数据模型

AssetHealthData 是核心数据模型,包含资产健康度的全量信息,关键字段说明:

  • 基础信息:id、assetId、assetName、assetType,标识资产唯一身份
  • 健康状态:healthLevel(等级)、healthScore(得分)、scoreChange(得分变化)
  • 检查记录:lastInspection(上次检查)、nextInspection(下次检查)
  • 关联数据:metrics(健康指标)、issues(健康问题)
class AssetHealthData {
  final String id;
  final String assetId;
  final String assetName;
  final String assetType;
  final HealthLevel healthLevel;
  final double healthScore;
  final double previousScore;
  final double scoreChange;
  final DateTime lastInspection;
  final DateTime? nextInspection;
  final List<HealthMetric> metrics;

字段设计细节:

  • healthScore:浮点型,支持精确到小数点后多位的健康得分
  • previousScore:记录上一次得分,用于计算变化趋势
  • nextInspection:可空类型,部分资产可能暂无下次检查计划
  • metrics:健康指标列表,支持多维度健康评估
  final List<HealthIssue> issues;
  final Map<String, dynamic> properties;
  final DateTime createdAt;
  final DateTime? lastUpdated;

  const AssetHealthData({
    required this.id,
    required this.assetId,
    required this.assetName,
    required this.assetType,
    required this.healthLevel,
    required this.healthScore,
    required this.previousScore,
    required this.scoreChange,
    required this.lastInspection,
    this.nextInspection,
    required this.metrics,
    required this.issues,
    required this.properties,
    required this.createdAt,
    this.lastUpdated,
  });
}

补充字段说明:

  • issues:健康问题列表,记录资产存在的具体问题
  • properties:扩展属性,支持存储自定义的资产属性
  • createdAt:数据创建时间,必填项,确保数据可追溯
  • lastUpdated:可空类型,首次创建时暂无更新时间

6.2 健康指标数据模型

HealthMetric 用于描述资产的具体健康指标,设计要点:

  • 量化指标:name(名称)、value(数值)、maxValue(最大值)、unit(单位)
  • 状态标识:status(指标状态),快速判断指标是否正常
  • 时间维度:measuredAt(测量时间),记录指标采集时间
class HealthMetric {
  final String name;
  final double value;
  final double maxValue;
  final String unit;
  final HealthStatus status;
  final String? description;
  final DateTime measuredAt;

  const HealthMetric({
    required this.name,
    required this.value,
    required this.maxValue,
    required this.unit,
    required this.status,
    this.description,
    required this.measuredAt,
  });
}

指标设计细节:

  • maxValue:用于计算指标达标率(value/maxValue)
  • description:可空类型,非必填的指标说明
  • HealthStatus:枚举类型,限定指标状态为正常/警告/严重

6.3 健康问题数据模型

HealthIssue 用于跟踪资产的健康问题,核心设计:

  • 问题标识:id、title、description,清晰描述问题
  • 严重程度:severity,区分低/中/高/紧急四个等级
  • 状态管理:status,记录问题的处理状态(未处理/处理中/已解决/已关闭)
  • 时间跟踪:detectedAt(发现时间)、resolvedAt(解决时间)
class HealthIssue {
  final String id;
  final String title;
  final String description;
  final IssueSeverity severity;
  final IssueStatus status;
  final DateTime detectedAt;
  final DateTime? resolvedAt;
  final String? resolvedBy;
  final List<String> attachments;

问题管理细节:

  • resolvedBy:记录解决人,便于责任追溯
  • attachments:附件列表,支持存储问题相关的图片/文档路径
  • metadata:扩展元数据,支持自定义问题属性
  final Map<String, dynamic> metadata;

  const HealthIssue({
    required this.id,
    required this.title,
    required this.description,
    required this.severity,
    required this.status,
    required this.detectedAt,
    this.resolvedAt,
    this.resolvedBy,
    this.attachments = const [],
    this.metadata = const {},
  });
}

默认值设计:

  • attachments:默认空数组,避免空指针
  • metadata:默认空Map,简化初始化

6.4 枚举类型定义

枚举类型用于限定字段取值范围,提升代码类型安全,设计说明:

  • HealthLevel:资产健康等级,对应饼图的四个扇区
  • HealthStatus:指标状态,用于单个健康指标的状态判断
  • IssueSeverity:问题严重程度,用于问题优先级排序
  • IssueStatus:问题处理状态,用于问题生命周期管理
enum HealthLevel {
  excellent,
  good,
  fair,
  poor,
}

enum HealthStatus {
  normal,
  warning,
  critical,
}

枚举命名规范:

  • 使用小写+下划线命名法,符合Dart枚举命名规范
  • 命名语义化,excellent(优秀)、fair(一般)、critical(严重)等直观易懂
enum IssueSeverity {
  low,
  medium,
  high,
  critical,
}

enum IssueStatus {
  open,
  inProgress,
  resolved,
  closed,
}

状态流转设计:

  • IssueStatus 遵循问题处理流程:open → inProgress → resolved → closed
  • 覆盖问题从发现到关闭的全生命周期

7. 资产健康度状态管理

使用Provider实现资产健康度数据的状态管理,核心优势:

  • 响应式更新:数据变化时自动刷新UI
  • 数据共享:跨组件共享健康度数据
  • 统一管理:集中处理数据加载、过滤、刷新逻辑
  • 状态隔离:将数据逻辑与UI逻辑分离,提升代码可维护性

7.1 状态管理基础类

AssetHealthProvider 继承 ChangeNotifier,核心状态字段说明:

  • _healthData:资产健康度数据列表,存储全量数据
  • _healthDistribution:健康等级分布统计,用于饼图渲染
  • _loading:加载状态,控制加载中UI展示
  • _error:错误信息,记录数据加载失败原因
  • _selectedFilter:选中的过滤条件,用于数据筛选
class AssetHealthProvider extends ChangeNotifier {
  List<AssetHealthData> _healthData = [];
  Map<HealthLevel, int> _healthDistribution = {};
  bool _loading = false;
  String? _error;
  DateTime? _lastRefreshTime;
  HealthLevel? _selectedFilter;

  List<AssetHealthData> get healthData => _healthData;
  Map<HealthLevel, int> get healthDistribution => _healthDistribution;
  bool get loading => _loading;
  String? get error => _error;

状态访问设计:

  • 私有字段(下划线开头):防止外部直接修改状态
  • 公开getter方法:提供只读访问,保证状态修改的可控性
  • 关键状态:_lastRefreshTime 记录最后刷新时间,用于数据时效性判断
  DateTime? get lastRefreshTime => _lastRefreshTime;
  HealthLevel? get selectedFilter => _selectedFilter;

  Future<void> loadHealthData() async {
    _loading = true;
    _error = null;
    notifyListeners();

    try {
      await Future.delayed(const Duration(seconds: 1));
      
      _healthData = _generateMockHealthData();
      _calculateHealthDistribution();
      _lastRefreshTime = DateTime.now();
      
      _loading = false;
      notifyListeners();
    } catch (e) {
      _error = e.toString();
      _loading = false;
      notifyListeners();
    }
  }

数据加载逻辑:

  • 加载前:设置loading为true,清空错误信息,通知UI刷新
  • 模拟延迟:使用Future.delayed模拟网络请求延迟(1秒)
  • 数据生成:调用_generateMockHealthData生成模拟数据
  • 分布计算:调用_calculateHealthDistribution统计健康等级分布
  • 异常处理:捕获所有异常,记录错误信息,恢复loading状态

7.2 状态操作方法

状态管理类提供丰富的操作方法,核心功能:

  • 过滤:setFilter设置健康等级过滤条件
  • 刷新:refreshData重新加载数据
  • 数据筛选:filteredHealthData返回过滤后的数据集
  • 分布计算:_calculateHealthDistribution统计各等级资产数量
  void setFilter(HealthLevel? level) {
    _selectedFilter = level;
    notifyListeners();
  }

  Future<void> refreshData() async {
    await loadHealthData();
  }

  List<AssetHealthData> get filteredHealthData {
    if (_selectedFilter == null) return _healthData;
    return _healthData.where((data) => data.healthLevel == _selectedFilter).toList();
  }

  void _calculateHealthDistribution() {
    _healthDistribution.clear();
    for (final level in HealthLevel.values) {
      _healthDistribution[level] = _healthData.where((data) => data.healthLevel == level).length;
    }
  }

方法设计细节:

  • setFilter:修改过滤条件后立即通知UI刷新
  • refreshData:复用loadHealthData方法,简化代码
  • filteredHealthData:使用getter方法,实现过滤数据的实时计算
  • _calculateHealthDistribution:遍历所有健康等级,统计对应资产数量

7.3 模拟数据生成

_generateMockHealthData 用于生成模拟数据,设计要点:

  • 随机数种子:固定种子(42)保证生成数据的一致性
  • 资产类型多样化:包含井盖、管道、阀门等多种资产类型
  • 健康得分区间:60-100分,符合健康度评估的常规区间
  • 得分变化:previousScore在当前得分±10分范围内,模拟得分波动
  List<AssetHealthData> _generateMockHealthData() {
    final assetTypes = ['井盖', '管道', '阀门', '泵站', '检查井'];
    final rng = Random(42);
    
    return List.generate(50, (index) {
      final assetType = assetTypes[index % assetTypes.length];
      final healthScore = 60.0 + rng.nextDouble() * 40.0;
      final previousScore = healthScore + (rng.nextInt(21) - 10);
      final healthLevel = _getHealthLevel(healthScore);
      
      return AssetHealthData(
        id: 'HEALTH_${index.toString().padLeft(3, '0')}',
        assetId: 'ASSET_${index.toString().padLeft(3, '0')}',
        assetName: '${assetType}${index + 1}',
        assetType: assetType,
        healthLevel: healthLevel,
        healthScore: healthScore,

模拟数据细节:

  • 资产ID格式化:补零到3位,保证ID格式统一(如HEALTH_001)
  • 资产名称:资产类型+序号,便于识别(如井盖1、管道2)
  • 得分限制:previousScore通过clamp方法限制在0-100分范围内
  • 健康等级:通过_getHealthLevel方法根据得分自动判定
        previousScore: previousScore.clamp(0.0, 100.0),
        scoreChange: healthScore - previousScore,
        lastInspection: DateTime.now().subtract(Duration(days: rng.nextInt(30))),
        nextInspection: DateTime.now().add(Duration(days: 30 + rng.nextInt(30))),
        metrics: _generateMockMetrics(rng),
        issues: _generateMockIssues(healthLevel, rng),
        properties: {
          'location': '位置${index + 1}',
          'installationDate': DateTime(2015 + rng.nextInt(8)).toIso8601String(),
          'manufacturer': ['厂家A', '厂家B', '厂家C'][index % 3],
        },
        createdAt: DateTime.now().subtract(Duration(days: rng.nextInt(365))),
        lastUpdated: DateTime.now(),
      );
    });
  }

扩展数据模拟:

  • 检查时间:lastInspection随机生成30天内的日期,nextInspection生成30-60天后的日期
  • 扩展属性:包含位置、安装日期、生产厂家等资产基础信息
  • 创建时间:随机生成一年内的日期,模拟历史数据
  • 关联数据:调用_generateMockMetrics和_generateMockIssues生成指标和问题数据

7.4 辅助数据生成

7.4.1 健康指标模拟

_generateMockMetrics 生成模拟健康指标,设计说明:

  • 指标类型固定:结构完整性、密封性能、承载能力三个核心指标
  • 数值区间:根据指标特性设置不同的数值范围
  • 状态随机:部分指标状态随机为正常/警告,模拟真实场景
  List<HealthMetric> _generateMockMetrics(Random rng) {
    return [
      HealthMetric(
        name: '结构完整性',
        value: 70 + rng.nextDouble() * 30,
        maxValue: 100,
        unit: '%',
        status: rng.nextBool() ? HealthStatus.normal : HealthStatus.warning,
        measuredAt: DateTime.now(),
      ),
      HealthMetric(
        name: '密封性能',
        value: 60 + rng.nextDouble() * 40,
        maxValue: 100,
        unit: '%',
        status: rng.nextBool() ? HealthStatus.normal : HealthStatus.warning,
        measuredAt: DateTime.now(),
      ),

指标数值设计:

  • 结构完整性:70-100%,代表资产结构基本稳定
  • 密封性能:60-100%,波动范围更大,模拟密封性能的不稳定性
  • 承载能力:80-100kg,保持较高水平,符合井盖基础安全要求
      HealthMetric(
        name: '承载能力',
        value: 80 + rng.nextDouble() * 20,
        maxValue: 100,
        unit: 'kg',
        status: HealthStatus.normal,
        measuredAt: DateTime.now(),
      ),
    ];
  }
7.4.2 健康问题模拟

_generateMockIssues 根据健康等级生成模拟问题,设计逻辑:

  • 优秀等级:无问题,返回空列表
  • 良好等级:1个问题
  • 一般等级:2个问题
  • 较差等级:3个问题
  • 问题严重程度:随机分配,模拟真实场景
  List<HealthIssue> _generateMockIssues(HealthLevel level, Random rng) {
    if (level == HealthLevel.excellent) return [];
    
    final issueCount = level == HealthLevel.poor ? 3 : level == HealthLevel.fair ? 2 : 1;
    return List.generate(issueCount, (index) {
      return HealthIssue(
        id: 'ISSUE_${DateTime.now().millisecondsSinceEpoch}_$index',
        title: '健康问题 ${index + 1}',
        description: '检测到的健康问题描述',
        severity: IssueSeverity.values[index % IssueSeverity.values.length],
        status: IssueStatus.open,
        detectedAt: DateTime.now().subtract(Duration(hours: rng.nextInt(24))),

问题数据细节:

  • 问题ID:时间戳+索引,保证唯一性
  • 发现时间:24小时内随机时间,模拟近期发现的问题
  • 附件:默认包含1张图片附件,模拟现场拍照记录
  • 元数据:包含优先级信息,便于问题排序处理
        attachments: ['attachment_${index}_1.jpg'],
        metadata: {
          'priority': ['high', 'medium', 'low'][index % 3],
        },
      );
    });
  }
7.4.3 健康等级判定

_getHealthLevel 根据得分自动判定健康等级,判定规则:

  • 90分及以上:优秀(excellent)
  • 75-89分:良好(good)
  • 60-74分:一般(fair)
  • 60分以下:较差(poor)
  HealthLevel _getHealthLevel(double score) {
    if (score >= 90) return HealthLevel.excellent;
    if (score >= 75) return HealthLevel.good;
    if (score >= 60) return HealthLevel.fair;
    return HealthLevel.poor;
  }
}

判定规则设计:

  • 区间划分合理,符合常规的健康度评估标准
  • 边界值包含(>=),避免区间重叠或遗漏
  • 按得分从高到低判断,逻辑清晰易读

8. 高级资产健康度组件

高级资产健康度组件在基础页面的基础上扩展了更多功能,核心增强点:

  • 状态管理集成:结合Provider实现数据的响应式加载和展示
  • 过滤功能:支持按健康等级筛选资产
  • 刷新功能:提供手动刷新数据的入口
  • 加载状态:展示加载中、空数据等状态
  • 数据概览:新增健康度统计卡片,展示核心指标

8.1 组件基础结构

AdvancedAssetHealthWidget 为有状态组件,核心生命周期逻辑:

  • initState:组件初始化时加载数据
  • build:根据Provider状态渲染不同UI
  • 状态监听:使用Consumer监听Provider数据变化
class AdvancedAssetHealthWidget extends StatefulWidget {
  const AdvancedAssetHealthWidget({super.key});

  
  State<AdvancedAssetHealthWidget> createState() => _AdvancedAssetHealthWidgetState();
}

class _AdvancedAssetHealthWidgetState extends State<AdvancedAssetHealthWidget> {
  
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) {
      final provider = Provider.of<AssetHealthProvider>(context, listen: false);
      provider.loadHealthData();
    });
  }

初始化逻辑:

  • addPostFrameCallback:确保在组件构建完成后再加载数据
  • listen: false:初始化时不监听状态变化,避免不必要的重建
  • 自动加载:组件初始化后自动加载数据,提升用户体验
  
  Widget build(BuildContext context) {
    return Consumer<AssetHealthProvider>(
      builder: (context, provider, child) {
        return Scaffold(
          appBar: AppBar(
            title: const Text('资产健康度'),
            actions: [
              IconButton(
                onPressed: () => _showFilterDialog(context, provider),
                icon: const Icon(Icons.filter_list),
              ),
              IconButton(
                onPressed: provider.refreshData,
                icon: const Icon(Icons.refresh),
              ),
            ],
          ),

AppBar设计:

  • 过滤按钮:打开过滤弹窗,选择健康等级
  • 刷新按钮:触发数据刷新,更新资产健康度数据
  • 图标选择:使用系统内置图标,保证视觉一致性
          body: provider.loading
              ? const Center(child: CircularProgressIndicator())
              : provider.healthData.isEmpty
                  ? const Center(child: Text('暂无健康度数据'))
                  : _buildContent(context, provider),
        );
      },
    );
  }

状态UI处理:

  • 加载中:展示CircularProgressIndicator,提示用户数据加载中
  • 空数据:展示友好的空数据提示,提升用户体验
  • 正常状态:调用_buildContent构建核心内容

8.2 核心内容构建

_buildContent 构建组件的核心内容,布局结构:

  • RefreshIndicator:支持下拉刷新,提升交互体验
  • Column纵向布局:从上到下依次展示概览卡片、过滤栏、饼图、资产列表
  • Expanded:资产列表使用Expanded,占满剩余空间
  Widget _buildContent(BuildContext context, AssetHealthProvider provider) {
    return RefreshIndicator(
      onRefresh: provider.refreshData,
      child: Column(
        children: [
          _buildSummaryCard(context, provider),
          const SizedBox(height: 8),
          _buildFilterBar(context, provider),
          const SizedBox(height: 8),
          _buildHealthChart(context, provider),
          const SizedBox(height: 8),
          Expanded(
            child: _buildAssetList(context, provider),
          ),
        ],
      ),
    );
  }

布局间距设计:

  • 各模块之间设置8px间距,保证页面呼吸感
  • RefreshIndicator包裹整个内容,支持下拉刷新所有数据
  • Expanded保证资产列表在屏幕剩余空间内滚动

8.3 概览卡片组件

_buildSummaryCard 展示健康度核心统计信息,设计要点:

  • 关键指标:总资产数、优秀资产数、平均得分
  • 卡片样式:使用Card组件,增加圆角和阴影
  • 布局:Row+Expanded实现三列等宽布局
  • 样式:使用主题文本样式,保证视觉一致性
  Widget _buildSummaryCard(BuildContext context, AssetHealthProvider provider) {
    final totalAssets = provider.healthData.length;
    final excellentAssets = provider.healthDistribution[HealthLevel.excellent] ?? 0;
    final averageScore = provider.healthData.fold(0.0, (sum, data) => sum + data.healthScore) / totalAssets;
    
    return Card(
      margin: const EdgeInsets.all(16),
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          children: [
            Text(
              '健康度概览',
              style: Theme.of(context).textTheme.titleLarge?.copyWith(
                fontWeight: FontWeight.bold,
              ),
            ),
            const SizedBox(height: 12),

统计计算逻辑:

  • fold 方法计算所有资产健康得分的总和,再除以总数得到平均分
  • 空值处理:优秀资产数使用?? 0,避免空指针
  • 文本样式:使用主题的titleLarge样式,加粗显示标题
            Row(
              children: [
                Expanded(
                  child: _buildSummaryItem(
                    context,
                    '总资产数',
                    '$totalAssets',
                    Colors.blue,
                  ),
                ),
                const SizedBox(width: 12),
                Expanded(
                  child: _buildSummaryItem(
                    context,
                    '优秀资产',
                    '$excellentAssets',
                    Colors.green,
                  ),
                ),
                const SizedBox(width: 12),
                Expanded(
                  child: _buildSummaryItem(
                    context,
                    '平均得分',
                    '${averageScore.toStringAsFixed(1)}',
                    Colors.orange,
                  ),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }

概览项设计:

  • 三列等宽布局,保证视觉平衡
  • 不同指标使用不同颜色,增强区分度
  • 平均分保留1位小数,保证数据精度和可读性

8.4 健康度饼图组件

_buildHealthChart 重构饼图组件,增强数据展示能力,核心优化:

  • 动态数据:基于Provider的健康分布数据生成饼图
  • 扇区标题:包含等级名称和数量,提升信息密度
  • 图例展示:新增Wrap布局的图例,便于查看各等级数量
  • 颜色匹配:使用与健康等级对应的颜色,保证视觉一致性
  Widget _buildHealthChart(BuildContext context, AssetHealthProvider provider) {
    final distribution = provider.healthDistribution;
    final sections = HealthLevel.values.map((level) {
      final count = distribution[level] ?? 0;
      final color = _getHealthLevelColor(level);
      return PieChartSectionData(
        value: count.toDouble(),
        color: color,
        title: '${_getHealthLevelDisplayName(level)}\n$count',
        titleStyle: const TextStyle(
          color: Colors.white,
          fontSize: 12,
          fontWeight: FontWeight.bold,
        ),
      );
    }).toList();

饼图配置优化:

  • 中心圆半径增大到60,提升视觉效果
  • 扇区标题样式统一:白色、12号字体、加粗
  • 动态生成扇区:遍历所有健康等级,保证数据完整
    final pieData = PieChartData(
      sections: sections,
      centerSpaceRadius: 60,
      sectionsSpace: 2,
    );

    return Card(
      margin: const EdgeInsets.symmetric(horizontal: 16),
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              '健康度分布',
              style: Theme.of(context).textTheme.titleMedium?.copyWith(
                fontWeight: FontWeight.bold,
              ),
            ),
            const SizedBox(height: 12),

饼图容器设计:

  • 固定高度200px,保证饼图展示效果
  • Card包裹,与页面其他模块视觉风格统一
  • 内边距16px,保证内容与容器的间距
            SizedBox(
              height: 200,
              child: PieChart(pieData),
            ),
            const SizedBox(height: 12),
            Wrap(
              spacing: 16,
              runSpacing: 8,
              children: HealthLevel.values.map((level) {
                final count = distribution[level] ?? 0;
                final color = _getHealthLevelColor(level);
                return Row(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    Container(
                      width: 12,
                      height: 12,
                      decoration: BoxDecoration(
                        color: color,
                        shape: BoxShape.circle,
                      ),
                    ),
                    const SizedBox(width: 6),
                    Text(
                      '${_getHealthLevelDisplayName(level)}: $count',
                      style: TextStyle(
                        color: Colors.grey.shade600,
                        fontSize: 12,
                      ),
                    ),
                  ],
                );
              }).toList(),
            ),
          ],
        ),
      ),
    );
  }
}

图例设计:

  • Wrap布局:自动换行,适配不同屏幕宽度
  • 圆形色块:12px直径的圆形,与饼图扇区颜色一致
  • 文字说明:等级名称+数量,使用灰色600,12号字体,保证可读性
  • 间距设置:水平间距16px,垂直间距8px,优化布局

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐