1. 结算页面架构设计
电商结算页面是用户购物旅程的最后一环,也是转化率的关键节点。一个优秀的结算实现需要兼顾数据完整性、计算准确性和操作流畅性。在Flutter for OpenHarmony项目中,我们采用分层架构设计:
数据层:包含Address、Coupon和Order三个核心模型类,负责数据的存储和基础逻辑。这一层的特点是纯Dart实现,不包含任何UI代码,确保业务逻辑的可测试性。
业务逻辑层:由CheckoutFlow类主导,处理地址选择、优惠券应用、积分抵扣等业务规则。这一层需要特别注意金额计算的精确性,所有涉及货币的操作都应使用定点数计算而非浮点数。
表现层:由多个Widget组成,包括地址选择列表、优惠券卡片、价格明细等。这一层的关键是状态管理,我们采用经典的setState方式实现局部刷新,避免不必要的重建。
提示:在真实项目中,建议将价格计算逻辑放在服务端进行二次验证,防止客户端被篡改导致资损。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心数据模型实现
2.1 地址管理模型
Address类不只是简单的数据容器,它包含了完整的地址业务逻辑:
dart复制class Address {
// ...字段定义见原始代码...
// 增强版地址验证
bool get isValid {
return name.isNotEmpty &&
phone.length == 11 &&
province.isNotEmpty &&
city.isNotEmpty &&
district.isNotEmpty &&
detail.isNotEmpty;
}
// 地址对比方法
bool isSameAs(Address other) {
return province == other.province &&
city == other.city &&
district == other.district &&
detail == other.detail;
}
// 转换为Map用于持久化
Map<String, dynamic> toMap() {
return {
'id': id,
'name': name,
'phone': phone,
'province': province,
'city': city,
'district': district,
'detail': detail,
'isDefault': isDefault,
'tag': tag,
};
}
// 从Map恢复对象
factory Address.fromMap(Map<String, dynamic> map) {
return Address(
id: map['id'],
name: map['name'],
phone: map['phone'],
province: map['province'],
city: map['city'],
district: map['district'],
detail: map['detail'],
isDefault: map['isDefault'] ?? false,
tag: map['tag'],
);
}
}
关键增强点:
- 增加了isValid验证方法,确保地址数据完整
- 添加isSameAs方法用于地址去重比较
- 实现toMap/fromMap支持本地持久化
- 保持不可变性(immutable)避免意外修改
2.2 优惠券模型进阶实现
Coupon类需要处理更复杂的业务规则:
dart复制class Coupon {
// ...基础字段见原始代码...
// 检查优惠券是否适用于当前订单
bool isApplicable(double orderAmount) {
if (!isValid) return false;
return orderAmount >= minOrderAmount;
}
// 计算优惠金额
double calculateDiscount(double orderAmount) {
if (!isApplicable(orderAmount)) return 0;
switch (type) {
case CouponType.percentage:
return orderAmount * value / 100;
case CouponType.fixed:
return value;
case CouponType.freeShipping:
return 10; // 假设固定运费10元
}
}
// 有效期剩余天数
int get remainingDays {
final now = DateTime.now();
return expiresAt.difference(now).inDays;
}
}
业务规则增强:
- 增加适用性检查,确保订单满足最低金额要求
- 独立计算折扣金额的方法,便于单元测试
- 添加剩余天数显示,提升用户体验
- 严格处理边界情况(如过期券、已使用券)
3. 结算流程深度实现
3.1 价格计算引擎
结算核心是准确计算最终价格,我们需要处理多种优惠叠加的场景:
dart复制class CheckoutCalculator {
final double subtotal;
final Address? address;
final Coupon? coupon;
final int usedPoints;
// 运费计算策略
static const double shippingFee = 10.0;
static const double freeShippingThreshold = 99.0;
CheckoutCalculator({
required this.subtotal,
this.address,
this.coupon,
this.usedPoints = 0,
});
// 计算运费
double get shippingCost {
if (coupon?.type == CouponType.freeShipping) return 0;
if (subtotal >= freeShippingThreshold) return 0;
return shippingFee;
}
// 计算优惠券折扣
double get couponDiscount {
if (coupon == null) return 0;
return coupon!.calculateDiscount(subtotal);
}
// 计算积分抵扣(1积分=0.01元)
double get pointsDiscount {
return usedPoints * 0.01;
}
// 计算最终总价
double calculateTotal() {
double total = subtotal;
// 应用优惠券
total -= couponDiscount;
// 应用积分
total -= pointsDiscount;
// 添加运费
total += shippingCost;
// 确保不为负
return total.clamp(0, double.infinity);
}
}
计算策略说明:
- 运费策略:满99包邮,否则固定10元运费
- 优惠券优先应用,积分抵扣在后
- 严格使用clamp防止负价格
- 每个计算步骤独立,便于测试和维护
3.2 状态管理方案
结算页面需要管理多个交互状态:
dart复制class CheckoutState extends ChangeNotifier {
Address? _selectedAddress;
Coupon? _selectedCoupon;
int _usedPoints = 0;
final List<Address> addresses;
final List<Coupon> coupons;
CheckoutState({
required this.addresses,
required this.coupons,
});
// 地址选择
Address? get selectedAddress => _selectedAddress;
set selectedAddress(Address? value) {
_selectedAddress = value;
notifyListeners();
}
// 优惠券选择
Coupon? get selectedCoupon => _selectedCoupon;
set selectedCoupon(Coupon? value) {
_selectedCoupon = value;
notifyListeners();
}
// 积分使用
int get usedPoints => _usedPoints;
set usedPoints(int value) {
_usedPoints = value.clamp(0, maxUsablePoints);
notifyListeners();
}
// 计算最大可用积分(不超过订单金额)
int get maxUsablePoints {
final calculator = CheckoutCalculator(
subtotal: cartSubtotal,
coupon: _selectedCoupon,
);
final maxDiscount = calculator.calculateTotal();
return (maxDiscount * 100).toInt();
}
}
状态管理特点:
- 使用ChangeNotifier实现细粒度更新
- 自动计算最大可用积分,防止超额使用
- 所有setter都触发通知,简化UI更新
- 业务规则集中在状态类中
4. UI实现与交互优化
4.1 地址选择组件增强
地址列表需要支持添加、编辑和默认设置:
dart复制class AddressSelection extends StatelessWidget {
final List<Address> addresses;
final Address? selectedAddress;
final ValueChanged<Address> onSelected;
final VoidCallback onAddNew;
const AddressSelection({
super.key,
required this.addresses,
this.selectedAddress,
required this.onSelected,
required
