购物车页面代码如下,包含了ui设计和对应的api_service代码:
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:shopping_app/api/api_service.dart';
import 'package:shopping_app/models/cart_item.dart';
import 'package:shopping_app/models/product.dart';
class ShoppingCartPage extends StatefulWidget {
const ShoppingCartPage({Key? key}) : super(key: key);
@override
_ShoppingCartPageState createState() => _ShoppingCartPageState();
}
class _ShoppingCartPageState extends State {
late List<List> cartList;
late double totalPrice;
@override
void initState() {
super.initState();
_getShoppingCart();
}
Future _getShoppingCart() async {
try {
List jsonData = await ApiService.getShoppingCart();
setState(() {
cartList = jsonData[0]
.map((cartJson) =>
CartItem.fromJson(cartJson, Product.fromJson(cartJson[1])))
.toList()
.fold<List<List>>([], (prev, cur) {
if (prev.isNotEmpty && prev.last.first.cartId == cur.cartId) {
prev.last.add(cur);
} else {
prev.add([cur]);
}
return prev;
});
totalPrice = jsonData[1];
});
} catch (e) {
Fluttertoast.showToast(msg: "获取购物车失败,请检查网络连接");
}
}
Future _updateCartItem(CartItem item, int quantity) async {
try {
dynamic jsonData =
await ApiService.updateCart(item.product.productId, quantity);
setState(() {
totalPrice = jsonData[0];
item.quantity = jsonData[1]['quantity'];
item.price = jsonData[1]['price'];
});
} catch (e) {
Fluttertoast.showToast(msg: "更新购物车失败,请检查网络连接");
}
}
Future _deleteCartItem(CartItem item) async {
try {
dynamic jsonData =
await ApiService.deleteCart(item.product.productId);
setState(() {
totalPrice = jsonData;
cartList.forEach((group) => group.remove(item));
cartList.removeWhere((group) => group.isEmpty);
});
} catch (e) {
Fluttertoast.showToast(msg: "删除购物车商品失败,请检查网络连接");
}
}
Widget _buildCartItem(CartItem item) {
return GestureDetector(
onTap: () async {
int? result = await showDialog(
context: context,
builder: (context) => _buildQuantityDialog(item),
);
if (result != null) {
await _updateCartItem(item, result);
}
},
child: Container(
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 15),
decoration: BoxDecoration(
border: Border(bottom: BorderSide(color: Colors.grey.shade300)),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: 80,
height: 100,
margin: EdgeInsets.only(right: 10),
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(item.product.imageUrl),
fit: BoxFit.cover,
),
),
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(item.product.name,
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
overflow: TextOverflow.ellipsis),
SizedBox(height: 5),
Row(
children: [
Text("单价:"),
Text(
"¥${item.product.price}",
style: TextStyle(
color: Colors.red, fontWeight: FontWeight.bold),
),
],
),
SizedBox(height: 5),
Row(
children: [
Text("数量:"),
Text(item.quantity.toString(),
style: TextStyle(fontWeight: FontWeight.bold)),
],
),
],
),
),
GestureDetector(
onTap: () async {
bool? confirm =
await showDialog(context: context, builder: (context) {
return AlertDialog(
title: Text("确认删除?"),
content: Text("您确定要从购物车中删除此商品吗?"),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(false),
child: Text("取消"),
),
TextButton(
onPressed: () => Navigator.of(context).pop(true),
child: Text("删除"),
),
],
);
});
if (confirm == true) {
await _deleteCartItem(item);
}
},
child: Icon(
Icons.delete_outline,
size: 20,
color: Colors.grey.shade500,
),
),
],
),
),
);
}
Widget _buildQuantityDialog(CartItem item) {
return AlertDialog(
title: Text("修改数量"),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("当前数量:${item.quantity}"),
Text("单价:${item.product.price}元"),
],
),
SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("数量:"),
SizedBox(
width: 120,
child: TextField(
keyboardType: TextInputType.number,
controller: TextEditingController(
text: item.quantity.toString()),
decoration: InputDecoration(
border: OutlineInputBorder(),
contentPadding: EdgeInsets.symmetric(horizontal: 10),
),
),
),
],
),
],
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(null),
child: Text("取消"),
),
TextButton(
onPressed: () {
String text =
(context.findWidgetThatIsScrollable()!.controller as TextEditingController)
.text;
int quantity = int.tryParse(text) ?? 0;
if (quantity <= 0) {
Fluttertoast.showToast(msg: "数量必须为正整数");
} else {
Navigator.of(context).pop(quantity);
}
},
child: Text("确定"),
),
],
);
}
Widget _buildCheckoutButton() {
return ElevatedButton(
onPressed: () async {
List addressList = await ApiService.getAddresses();
bool? result = await showDialog(
context: context,
builder: (context) => _buildPaymentDialog(addressList),
);
if (result == true) {
// 结算
try {
await ApiService.submitOrder(1013, "支付宝");
Fluttertoast.showToast(msg: "结算成功!");
_getShoppingCart();
} catch (e) {
Fluttertoast.showToast(msg: "结算失败,请检查网络连接");
}
}
},
child: Text("结算"),
);
}
Widget _buildPaymentDialog(List addressList) {
return AlertDialog(
title: Text("结算"),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text("选择收货地址:"),
SizedBox(height: 10),
...addressList.map((address) {
return RadioListTile(
title: Text("${address['name']} ${address['phone']}"),
subtitle: Text("${address['country']} ${address['provience']} ${address['city']} ${address['district']} ${address['addressLine']}"),
value: address,
groupValue: null,
onChanged: null,
);
}).toList(),
SizedBox(height: 20),
Text("选择支付方式:"),
SizedBox(height: 10),
Row(
children: [
Radio(
value: "支付宝",
groupValue: null,
onChanged: null,
),
Text("支付宝"),
],
),
Row(
children: [
Radio(
value: "微信",
groupValue: null,
onChanged: null,
),
Text("微信"),
],
),
],
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(false),
child: Text("取消"),
),
TextButton(
onPressed: () => Navigator.of(context).pop(true),
child: Text("结算"),
),
],
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("购物车"),
),
body: cartList == null
? Center(child: CircularProgressIndicator())
: cartList.isEmpty
? Center(child: Text("购物车为空"))
: Column(
children: [
Expanded(
child: ListView.builder(
itemCount: cartList.length,
itemBuilder: (context, index) {
return Column(
children: [
Container(
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 15),
color: Colors.grey.shade100,
child: Row(
children: [
Icon(Icons.location_on, size: 16),
SizedBox(width: 5),
Text(
"收货地址",
style: TextStyle(fontWeight: FontWeight.bold),
),
SizedBox(width: 10),
Text(
"东北石油大学",
),
],
),
),
...cartList[index].map(_buildCartItem),
],
);
},
),
),
Container(
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 15),
decoration: BoxDecoration(
border: Border(top: BorderSide(color: Colors.grey.shade300)),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("合计:¥$totalPrice"),
_buildCheckoutButton(),
],
),
),
],
),
);
}
}
class CartItem {
late int cartId;
late int quantity;
late double price;
late Product product;
CartItem.fromJson(Map<String, dynamic> json, Product product)
: cartId = jso