You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中从Cart Bloc获取商品ID并合并数量生成指定结构

问题需求

需要从Cart Bloc的商品列表中提取productID,并与购物车数量合并,生成如下格式的JSON结构:

"aos": [
    {
      "product_id": 10,
      "quantity": 1
    },
    {
      "product_id": 11,
      "quantity": 2
    }
  ]

此前尝试将Map编码为JSON,但无法访问每个商品的id,需在Bloc架构下实现该需求。

相关代码

Checkout Screen代码

class CheckoutScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // final List<dynamic> aos;
    return Scaffold(
        appBar: AppBar(
          backgroundColor: buttonBG,
        ),
        body: Column(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const ShippingAddress(),
            const SizedBox(height: 20),
            BlocBuilder<CartBloc, CartState>(
              builder: (context, state) {
                if (state is CartLoaded) {
                  Map aos = state.cart.productQuantity(state.cart.products);
                  var pio = aos.keys.toList();
                  String productInstance = json.encode(pio);
                  debugPrint(productInstance);
                  return Expanded(
                    child: SizedBox(
                      height: 400,
                      child: ListView.builder(
                        itemCount: aos.keys.length,
                        itemBuilder: (BuildContext context, int index) {
                          final pIndex = aos.keys.elementAt(index);
                          final qIndex = aos.values.elementAt(index);
                          return ProductCard.summary(
                            product: pIndex,
                            quantity: qIndex,
                          );
                        },
                      ),
                    ),
                  );
                }
                return const Text('Something went wrong');
              },
            ),
          ],
        ));
  }
}

CartModel代码

import 'package:afia4_shopping_app/logic/models/product_models.dart';
import 'package:equatable/equatable.dart';

class Cart extends Equatable {
  final List<ProductModel> products;

  const Cart({this.products = const <ProductModel>[]});

  @override
  List<Object?> get props => [products];

  Map productQuantity(products) {
    var quantity = {};

    products.forEach((product) {
      if (!quantity.containsKey(product)) {
        quantity[product] = 1;
      } else {
        quantity[product] += 1;
      }
    });

    return quantity;
  }

}

CartBloc代码

class CartBloc extends Bloc<CartEvent, CartState> {
  CartBloc() : super(CartLoading()) {
    on<LoadCart>(_onLoadCart);
    on<AddProduct>(_onAddProduct);
    on<RemoveProduct>(_onRemoveProduct);
  }

  void _onLoadCart(
    LoadCart event,
    Emitter<CartState> emit,
  ) async {
    emit(CartLoading());
    try {
      await Future<void>.delayed(const Duration(seconds: 1));
      emit(CartLoaded());
    } catch (_) {
      emit(CartError());
    }
  }

  void _onAddProduct(
    AddProduct event,
    Emitter<CartState> emit,
  ) {
    if (state is CartLoaded) {
      try {
        emit(
          CartLoaded(
            cart: Cart(
              products: List.from((state as CartLoaded).cart.products)
                ..add(event.product),
            ),
          ),
        );
      } on Exception {
        emit(CartError());
      }
    }
  }

  void _onRemoveProduct(
    RemoveProduct event,
    Emitter<CartState> emit,
  ) {
    if (state is CartLoaded) {
      try {
        emit(
          CartLoaded(
            cart: Cart(
              products: List.from((state as CartLoaded).cart.products)
                ..remove(event.product),
            ),
          ),
        );
      } on Exception {
        emit(CartError());
      }
    }
  }
}

ProductModel代码

class ProductModel {
  ProductModel(
      {this.name,
      this.id,
  });

  String? name;
  int? id;


  factory ProductModel.fromJson(Map<String, dynamic> json) => ProductModel(
      name: json["name"],
      id: json["id"],


  Map<String, dynamic> toJson() => {
        "name": name,
        "id": id
      };

List<ProductModel> productsFromJson(String str) => List<ProductModel>.from(
    json.decode(str).map((x) => ProductModel.fromJson(x)));

String productsToJson(List<ProductModel> data) =>
    json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
}
解决方案

1. 修复CartModel的数量统计逻辑

原productQuantity方法用ProductModel对象作为Map的key,这会导致无法直接提取商品id,且对象比较可能出现异常。修改为用商品id作为key来统计数量:

// 修改Cart类中的productQuantity方法
Map<int, int> productQuantity() {
  final quantity = <int, int>{};

  for (final product in products) {
    if (product.id == null) continue; // 处理id为空的情况
    final productId = product.id!;
    quantity[productId] = (quantity[productId] ?? 0) + 1;
  }

  return quantity;
}

这里指定了Map的泛型<int, int>,让类型更安全,同时直接使用当前Cart类的products属性,不需要再传参。

2. 在CheckoutScreen中生成目标结构

在BlocBuilder中,通过修改后的productQuantity获取id和数量的映射,再转换成目标格式的列表,最后编码为JSON:

BlocBuilder<CartBloc, CartState>(
  builder: (context, state) {
    if (state is CartLoaded) {
      // 获取id-数量的映射
      final quantityMap = state.cart.productQuantity();
      // 生成目标aos列表
      final aos = quantityMap.entries.map((entry) {
        return {
          "product_id": entry.key,
          "quantity": entry.value,
        };
      }).toList();
      // 编码为JSON字符串
      final aosJson = json.encode({"aos": aos});
      debugPrint(aosJson); // 打印验证结构

      return Expanded(
        child: SizedBox(
          height: 400,
          child: ListView.builder(
            itemCount: quantityMap.length,
            itemBuilder: (BuildContext context, int index) {
              final entry = quantityMap.entries.elementAt(index);
              // 根据id找到对应的商品(如果需要展示商品信息)
              final product = state.cart.products.firstWhere(
                (p) => p.id == entry.key,
                orElse: () => ProductModel(),
              );
              return ProductCard.summary(
                product: product,
                quantity: entry.value,
              );
            },
          ),
        ),
      );
    }
    return const Text('Something went wrong');
  },
)

3. 修复CartBloc的初始加载逻辑

原_onLoadCart方法中emit(CartLoaded())没有传递cart参数,会导致空指针问题,修改为传递默认空购物车:

void _onLoadCart(
  LoadCart event,
  Emitter<CartState> emit,
) async {
  emit(CartLoading());
  try {
    await Future<void>.delayed(const Duration(seconds: 1));
    emit(const CartLoaded(cart: Cart())); // 传递默认空Cart
  } catch (_) {
    emit(CartError());
  }
}

通过以上修改,就能正确生成你需要的JSON结构,同时解决无法访问商品id的问题。

内容的提问来源于stack exchange,提问作者pythonGo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 23:06:24