在这里插入图片描述

订单列表是用户查看购买历史和订单状态的重要页面。用户在这里可以查看所有订单、按状态筛选、查看订单详情、进行售后操作等。一个好的订单列表实现需要清晰的分类、准确的状态显示和便捷的操作方式。本文将详细讲解如何在 Flutter for OpenHarmony 项目中实现一个功能完整的订单列表页面,包括订单分类、状态筛选、订单展示和交互操作等功能。

消息数据模型

消息系统是用户与应用交互的重要方式。Message 类定义了消息的结构。

// 消息类型枚举
enum MessageType {
  system,      // 系统消息
  order,       // 订单消息
  promotion,   // 促销活动
  service,     // 客服消息
}

class Message {
  const Message({
    required this.id,          // 消息ID
    required this.title,       // 消息标题
    required this.content,     // 消息内容
    required this.type,        // 消息类型
    required this.createdAt,   // 创建时间
    this.isRead = false,       // 是否已读
    this.imageUrl,             // 消息图片URL
  });

  final String id;
  final String title;
  final String content;
  final MessageType type;
  final DateTime createdAt;
  final bool isRead;
  final String? imageUrl;

  // 获取消息类型的显示文本
  String get typeText {
    switch (type) {
      case MessageType.system:
        return '系统消息';
      case MessageType.order:
        return '订单消息';
      case MessageType.promotion:
        return '促销活动';
      case MessageType.service:
        return '客服消息';
    }
  }
}

这个消息模型展示了如何管理消息:

消息类型:

  • 系统消息:应用系统通知
  • 订单消息:订单状态更新
  • 促销活动:营销推广信息
  • 客服消息:客服支持信息

消息属性:

  • 包含消息的基本信息(ID、标题、内容)
  • 记录消息的创建时间
  • 标记消息是否已读
  • 支持消息配图

显示优化:

  • typeText 属性返回用户友好的消息类型文本

订单列表页面结构

订单列表页面需要支持多种视图和筛选方式。

class OrdersPage extends StatefulWidget {
  const OrdersPage({super.key});

  
  State<OrdersPage> createState() => _OrdersPageState();
}

class _OrdersPageState extends State<OrdersPage>
    with SingleTickerProviderStateMixin {
  // Tab控制器
  late TabController _tabController;

  // 订单状态过滤
  OrderStatus? _selectedStatus;

  
  void initState() {
    super.initState();
    // 初始化Tab控制器,共5个Tab
    _tabController = TabController(length: 5, vsync: this);
  }

  
  void dispose() {
    _tabController.dispose();
    super.dispose();
  }

  
  Widget build(BuildContext context) {
    final appState = AppStateScope.of(context);

    return Scaffold(
      appBar: AppBar(
        title: const Text('我的订单'),
        // Tab栏
        bottom: TabBar(
          controller: _tabController,
          tabs: const [
            Tab(text: '全部'),
            Tab(text: '待付款'),
            Tab(text: '待发货'),
            Tab(text: '待收货'),
            Tab(text: '已完成'),
          ],
        ),
      ),
      body: AnimatedBuilder(
        animation: appState,
        builder: (context, _) {
          return TabBarView(
            controller: _tabController,
            children: [
              // 全部订单
              _buildOrderList(appState.orders),
              // 待付款订单
              _buildOrderList(
                appState.orders
                    .where((o) => o.status == OrderStatus.pending)
                    .toList(),
              ),
              // 待发货订单
              _buildOrderList(
                appState.orders
                    .where((o) => o.status == OrderStatus.paid)
                    .toList(),
              ),
              // 待收货订单
              _buildOrderList(
                appState.orders
                    .where((o) => o.status == OrderStatus.shipped)
                    .toList(),
              ),
              // 已完成订单
              _buildOrderList(
                appState.orders
                    .where((o) => o.status == OrderStatus.delivered)
                    .toList(),
              ),
            ],
          );
        },
      ),
    );
  }

  // 构建订单列表
  Widget _buildOrderList(List<Order> orders) {
    if (orders.isEmpty) {
      return const Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Icon(Icons.shopping_bag_outlined, size: 64, color: Colors.grey),
            SizedBox(height: 16),
            Text('暂无订单'),
          ],
        ),
      );
    }

    return ListView.builder(
      padding: const EdgeInsets.all(12),
      itemCount: orders.length,
      itemBuilder: (context, index) {
        final order = orders[index];
        return _buildOrderCard(order);
      },
    );
  }

  // 构建订单卡片
  Widget _buildOrderCard(Order order) {
    return Card(
      margin: const EdgeInsets.only(bottom: 12),
      child: Padding(
        padding: const EdgeInsets.all(12),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            // 订单头部:订单号和状态
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                Text(
                  '订单号:${order.id}',
                  style: Theme.of(context).textTheme.bodySmall,
                ),
                Container(
                  padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
                  decoration: BoxDecoration(
                    color: _getStatusColor(order.status),
                    borderRadius: BorderRadius.circular(4),
                  ),
                  child: Text(
                    order.statusText,
                    style: const TextStyle(
                      color: Colors.white,
                      fontSize: 12,
                    ),
                  ),
                ),
              ],
            ),
            const SizedBox(height: 12),
            
            // 订单项目
            if (order.items.isNotEmpty)
              Column(
                children: order.items.map((item) {
                  return Padding(
                    padding: const EdgeInsets.only(bottom: 8),
                    child: Row(
                      children: [
                        // 商品图片
                        ClipRRect(
                          borderRadius: BorderRadius.circular(4),
                          child: Image.network(
                            item.product.imageUrl,
                            width: 48,
                            height: 48,
                            fit: BoxFit.contain,
                            errorBuilder: (_, __, ___) =>
                                const SizedBox(width: 48, height: 48),
                          ),
                        ),
                        const SizedBox(width: 8),
                        // 商品信息
                        Expanded(
                          child: Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                              Text(
                                item.product.title,
                                maxLines: 1,
                                overflow: TextOverflow.ellipsis,
                                style: Theme.of(context).textTheme.bodySmall,
                              ),
                              Text(
                                ${item.priceUsd.toStringAsFixed(2)} x${item.quantity}',
                                style: Theme.of(context).textTheme.bodySmall,
                              ),
                            ],
                          ),
                        ),
                      ],
                    ),
                  );
                }).toList(),
              ),
            const Divider(),
            
            // 订单总价
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                Text(
                  '合计:',
                  style: Theme.of(context).textTheme.bodySmall,
                ),
                Text(
                  ${order.totalUsd.toStringAsFixed(2)}',
                  style: Theme.of(context).textTheme.titleSmall?.copyWith(
                    fontWeight: FontWeight.bold,
                  ),
                ),
              ],
            ),
            const SizedBox(height: 12),
            
            // 操作按钮
            Row(
              mainAxisAlignment: MainAxisAlignment.end,
              children: [
                TextButton(
                  onPressed: () {
                    // 查看订单详情
                  },
                  child: const Text('详情'),
                ),
                const SizedBox(width: 8),
                if (order.status == OrderStatus.pending)
                  ElevatedButton(
                    onPressed: () {
                      // 去支付
                    },
                    child: const Text('支付'),
                  ),
                if (order.status == OrderStatus.shipped)
                  ElevatedButton(
                    onPressed: () {
                      // 确认收货
                    },
                    child: const Text('确认收货'),
                  ),
              ],
            ),
          ],
        ),
      ),
    );
  }

  // 获取订单状态对应的颜色
  Color _getStatusColor(OrderStatus status) {
    switch (status) {
      case OrderStatus.pending:
        return Colors.orange;
      case OrderStatus.paid:
        return Colors.blue;
      case OrderStatus.shipped:
        return Colors.purple;
      case OrderStatus.delivered:
        return Colors.green;
      case OrderStatus.cancelled:
        return Colors.grey;
      case OrderStatus.refunding:
        return Colors.red;
      case OrderStatus.refunded:
        return Colors.red;
    }
  }
}

这个订单列表页面展示了如何组织和展示订单:

Tab分类:

  • 全部订单
  • 待付款订单
  • 待发货订单
  • 待收货订单
  • 已完成订单

订单筛选:

  • 使用 where 方法按状态筛选
  • 动态生成不同状态的订单列表
  • 支持多种筛选维度

空状态处理:

  • 当没有订单时显示友好提示
  • 显示购物袋图标和"暂无订单"文本
  • 改善用户体验

订单卡片设计

订单卡片需要清晰地展示订单信息和操作选项。

// 订单卡片的关键部分

// 1. 订单头部
Row(
  mainAxisAlignment: MainAxisAlignment.spaceBetween,
  children: [
    // 订单号
    Text('订单号:${order.id}'),
    // 订单状态标签
    Container(
      padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
      decoration: BoxDecoration(
        color: _getStatusColor(order.status),
        borderRadius: BorderRadius.circular(4),
      ),
      child: Text(
        order.statusText,
        style: const TextStyle(color: Colors.white, fontSize: 12),
      ),
    ),
  ],
)

// 2. 订单项目列表
Column(
  children: order.items.map((item) {
    return Row(
      children: [
        // 商品图片
        Image.network(item.product.imageUrl, width: 48, height: 48),
        // 商品信息
        Expanded(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(item.product.title),
              Text(${item.priceUsd} x${item.quantity}'),
            ],
          ),
        ),
      ],
    );
  }).toList(),
)

// 3. 订单总价
Row(
  mainAxisAlignment: MainAxisAlignment.spaceBetween,
  children: [
    Text('合计:'),
    Text(${order.totalUsd.toStringAsFixed(2)}'),
  ],
)

// 4. 操作按钮
Row(
  mainAxisAlignment: MainAxisAlignment.end,
  children: [
    TextButton(onPressed: () {}, child: const Text('详情')),
    if (order.status == OrderStatus.pending)
      ElevatedButton(onPressed: () {}, child: const Text('支付')),
  ],
)

这个订单卡片设计展示了如何组织订单信息:

信息层次:

  • 订单号和状态在顶部,便于快速识别
  • 订单项目在中间,显示购买的商品
  • 订单总价在下方,突出重要信息
  • 操作按钮在底部,便于用户操作

视觉设计:

  • 使用颜色标签表示订单状态
  • 使用分隔线分隔不同部分
  • 使用合理的间距提高可读性

交互设计:

  • 提供查看详情的选项
  • 根据订单状态显示不同的操作按钮
  • 待付款订单显示支付按钮
  • 待收货订单显示确认收货按钮

订单状态管理

订单状态需要在应用状态中管理。

// 在AppState中管理订单
class AppState extends ChangeNotifier {
  // 订单列表
  final List<Order> _orders = [];
  List<Order> get orders => List.unmodifiable(_orders);

  // 添加订单
  void addOrder(Order order) {
    _orders.insert(0, order);  // 新订单插入到列表开头
    notifyListeners();
  }

  // 更新订单状态
  void updateOrderStatus(String orderId, OrderStatus status) {
    final index = _orders.indexWhere((o) => o.id == orderId);
    if (index >= 0) {
      final order = _orders[index];
      // 创建新的订单对象(不可变性)
      _orders[index] = Order(
        id: order.id,
        items: order.items,
        status: status,
        createdAt: order.createdAt,
        totalUsd: order.totalUsd,
        shippingAddress: order.shippingAddress,
        trackingNumber: order.trackingNumber,
        paidAt: order.paidAt,
        shippedAt: order.shippedAt,
        deliveredAt: order.deliveredAt,
      );
      notifyListeners();
    }
  }

  // 获取特定状态的订单
  List<Order> getOrdersByStatus(OrderStatus status) {
    return _orders.where((o) => o.status == status).toList();
  }

  // 获取订单统计信息
  Map<OrderStatus, int> getOrderStats() {
    final stats = <OrderStatus, int>{};
    for (final order in _orders) {
      stats[order.status] = (stats[order.status] ?? 0) + 1;
    }
    return stats;
  }
}

这个订单状态管理展示了如何管理订单:

订单操作:

  • addOrder 添加新订单到列表开头
  • updateOrderStatus 更新订单状态
  • getOrdersByStatus 按状态获取订单
  • getOrderStats 获取订单统计信息

不可变性:

  • 创建新的订单对象而不是修改现有对象
  • 确保状态的可追踪性
  • 支持时间旅行调试

通知机制:

  • 每次修改后调用 notifyListeners()
  • 所有监听的组件自动更新

订单筛选和搜索

用户可能需要按多个条件筛选订单。

// 订单筛选逻辑
class OrderFilter {
  // 按状态筛选
  static List<Order> filterByStatus(
    List<Order> orders,
    OrderStatus status,
  ) {
    return orders.where((o) => o.status == status).toList();
  }

  // 按日期范围筛选
  static List<Order> filterByDateRange(
    List<Order> orders,
    DateTime startDate,
    DateTime endDate,
  ) {
    return orders
        .where((o) => o.createdAt.isAfter(startDate) && 
                      o.createdAt.isBefore(endDate))
        .toList();
  }

  // 按金额范围筛选
  static List<Order> filterByAmountRange(
    List<Order> orders,
    double minAmount,
    double maxAmount,
  ) {
    return orders
        .where((o) => o.totalUsd >= minAmount && o.totalUsd <= maxAmount)
        .toList();
  }

  // 搜索订单号
  static List<Order> searchByOrderId(
    List<Order> orders,
    String keyword,
  ) {
    return orders
        .where((o) => o.id.contains(keyword))
        .toList();
  }

  // 组合筛选
  static List<Order> filter(
    List<Order> orders, {
    OrderStatus? status,
    DateTime? startDate,
    DateTime? endDate,
    double? minAmount,
    double? maxAmount,
    String? keyword,
  }) {
    var result = orders;

    if (status != null) {
      result = filterByStatus(result, status);
    }

    if (startDate != null && endDate != null) {
      result = filterByDateRange(result, startDate, endDate);
    }

    if (minAmount != null && maxAmount != null) {
      result = filterByAmountRange(result, minAmount, maxAmount);
    }

    if (keyword != null && keyword.isNotEmpty) {
      result = searchByOrderId(result, keyword);
    }

    return result;
  }
}

这个订单筛选展示了如何实现灵活的筛选:

单一筛选:

  • 按状态筛选
  • 按日期范围筛选
  • 按金额范围筛选
  • 按订单号搜索

组合筛选:

  • 支持多个条件同时筛选
  • 链式调用实现复杂筛选
  • 灵活的筛选组合

订单统计和分析

应用可以提供订单统计信息。

// 订单统计
class OrderStats {
  // 计算订单总数
  static int getTotalOrders(List<Order> orders) {
    return orders.length;
  }

  // 计算待付款订单数
  static int getPendingOrders(List<Order> orders) {
    return orders.where((o) => o.status == OrderStatus.pending).length;
  }

  // 计算总消费金额
  static double getTotalSpent(List<Order> orders) {
    return orders.fold(0, (sum, o) => sum + o.totalUsd);
  }

  // 计算平均订单金额
  static double getAverageOrderAmount(List<Order> orders) {
    if (orders.isEmpty) return 0;
    return getTotalSpent(orders) / orders.length;
  }

  // 获取最近30天的订单
  static List<Order> getRecentOrders(List<Order> orders, int days) {
    final cutoffDate = DateTime.now().subtract(Duration(days: days));
    return orders.where((o) => o.createdAt.isAfter(cutoffDate)).toList();
  }
}

这个订单统计展示了如何分析订单数据:

统计指标:

  • 订单总数
  • 待付款订单数
  • 总消费金额
  • 平均订单金额
  • 最近订单

数据分析:

  • 帮助用户了解购买情况
  • 为营销提供数据支持
  • 改善用户体验

总结

订单列表的实现涉及多个重要的技术点。首先是消息系统的设计,支持多种消息类型。其次是订单列表页面的实现,支持Tab分类和状态筛选。再次是订单卡片的设计,清晰地展示订单信息。最后是订单状态管理和筛选功能,提供灵活的订单查询和分析。

这种设计确保了订单列表的功能完整性和用户体验的流畅性。用户可以轻松查看订单、筛选订单、进行订单操作,整个流程自然而直观。


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

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐