细节修改

This commit is contained in:
Seven Tsui 2025-09-19 17:56:34 +08:00
parent 1d5b68d7ad
commit a777aca121
2 changed files with 237 additions and 166 deletions

View File

@ -46,6 +46,11 @@ class _GoodsState extends State<Goods> {
{'icon': 'assets/images/share-pyq.png', 'label': '朋友圈'}, {'icon': 'assets/images/share-pyq.png', 'label': '朋友圈'},
]; ];
//
Map<String, String> selectedAttributes = {}; //
dynamic selectedSku; // SKU
int _quantity = 1; //
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@ -71,20 +76,82 @@ class _GoodsState extends State<Goods> {
logger.e(res['data']); logger.e(res['data']);
setState(() { setState(() {
shopObj = res['data']; // data shopObj = res['data']; // data
// SKU为第一个
if (shopObj != null && shopObj['skuList'] != null && shopObj['skuList'].isNotEmpty) {
// selectedSku = shopObj['skuList'][0];
//
dynamic attr = shopObj['productAttr'];
List<dynamic> attrList = [];
if (!Utils.isEmpty(attr)) {
attrList = jsonDecode(attr);
}
//
selectedAttributes.clear();
//
for (var attr in attrList) {
final attrName = attr['name'] ?? '';
final options = attr['options'] as List<dynamic>? ?? [];
if (options.isNotEmpty) {
final firstOption = options[0]['name'] ?? '';
selectedAttributes[attrName] = firstOption;
}
}
//
locateSelectedSku();
}
}); });
} catch (e) { } catch (e) {
logger.e(e); logger.e(e);
Get.back(); Get.back();
} }
} }
// SKU
void locateSelectedSku() {
if (shopObj != null && shopObj['skuList'] != null) {
for (var sku in shopObj['skuList']) {
try {
final spData = jsonDecode(sku['spData'] ?? '{}');
bool match = true;
//
selectedAttributes.forEach((key, value) {
if (spData[key] != value) {
match = false;
}
});
if (match) {
setState(() {
selectedSku = sku;
});
print('333333333333333333');
print(sku);
break;
}
} catch (e) {
logger.e('解析spData错误: $e');
}
}
}
}
//
void handleAttributeSelect(String attrName, String optionName) {
setState(() {
selectedAttributes[attrName] = optionName;
locateSelectedSku(); // SKU
});
}
/// ///
createOrder(String goodsId) async { createOrder(String goodsId) async {
var params = { var params = {
"type": 1, // 1->2->;3-> "type": 1, // 1->2->;3->
"distribution": 1, // 1->2->;3->; "distribution": 1, // 1->2->;3->;
"skuItemBOList": [ "skuItemBOList": [
{"skuId": goodsId, "quantity": 1} {"skuId": goodsId, "quantity": _quantity}
] ]
}; };
print('下单请求参数---->$params'); print('下单请求参数---->$params');
@ -271,6 +338,10 @@ class _GoodsState extends State<Goods> {
}, },
); );
} }
//
bool isAttributeSelected(String attrName, String optionName) {
return selectedAttributes[attrName] == optionName;
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -378,17 +449,7 @@ class _GoodsState extends State<Goods> {
Row( Row(
spacing: 5.0, spacing: 5.0,
children: [ children: [
// // SKU价格或默认价格
// Text(
// '¥${shopObj['price']}',
// style: TextStyle(
// color: Colors.white,
// fontSize: 16.0,
// decoration: TextDecoration.lineThrough,
// decorationColor: Colors.black,
// decorationThickness: 1.5,
// ),
// ),
Container( Container(
padding: EdgeInsets.symmetric(horizontal: 8.0, vertical: 3.0), padding: EdgeInsets.symmetric(horizontal: 8.0, vertical: 3.0),
decoration: BoxDecoration( decoration: BoxDecoration(
@ -396,12 +457,11 @@ class _GoodsState extends State<Goods> {
borderRadius: BorderRadius.circular(50.0), borderRadius: BorderRadius.circular(50.0),
), ),
child: Text( child: Text(
'¥${shopObj['price']}', '¥${selectedSku != null ? selectedSku['price'] : shopObj['price']}',
style: TextStyle(color: Colors.red, fontSize: 12.0), style: TextStyle(color: Colors.red, fontSize: 12.0),
), ),
), ),
Text( Text(
// '已售${Utils().graceNumber(shopObj['sales'] ?? 0)}',
'已售${Utils.graceNumber(int.tryParse(shopObj['sales']?.toString() ?? '0') ?? 0)}', '已售${Utils.graceNumber(int.tryParse(shopObj['sales']?.toString() ?? '0') ?? 0)}',
style: TextStyle(color: Colors.white, fontSize: 12.0), style: TextStyle(color: Colors.white, fontSize: 12.0),
), ),
@ -462,85 +522,173 @@ class _GoodsState extends State<Goods> {
), ),
), ),
//
// //
Container( Container(
width: double.infinity,
margin: EdgeInsets.only(top: 10.0), margin: EdgeInsets.only(top: 10.0),
padding: EdgeInsets.all(10.0), padding: EdgeInsets.all(10.0),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: BorderRadius.circular(15.0), borderRadius: BorderRadius.circular(15.0),
), ),
// child: Column(
// spacing: 10.0,
// children: [
// Row(
// spacing: 5.0,
// children: [
// Icon(
// Icons.timer,
// size: 16.0,
// ),
// Expanded(
// child: Text(
// '本商品请于2025.01.25前进行核销',
// style: TextStyle(fontSize: 12.0),
// ),
// ),
// ],
// ),
// Row(
// spacing: 5.0,
// children: [
// Icon(
// Icons.house_outlined,
// size: 16.0,
// ),
// Expanded(
// child: Text(
// '营业时间7x24',
// style: TextStyle(fontSize: 12.0),
// ),
// ),
// ],
// ),
// Row(
// spacing: 5.0,
// children: [
// Icon(
// Icons.location_on,
// size: 16.0,
// ),
// Expanded(
// child: Text(
// '河北省唐山市玉田县',
// style: TextStyle(fontSize: 12.0),
// ),
// ),
// ],
// ),
// ],
// ),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: attrList.map<Widget>((attr) { children: [
final attrName = attr['name'] ?? ''; //
final options = attr['options'] as List<dynamic>? ?? []; Row(
final optionNames = options.map((o) => o['name']).join(' / ');
return Row(
children: [ children: [
Text( //
'$attrName: ', Container(
style: TextStyle(fontSize: 12, fontWeight: FontWeight.bold), width: 60,
), height: 60,
Expanded( decoration: BoxDecoration(
child: Text( borderRadius: BorderRadius.circular(8),
optionNames, image: DecorationImage(
style: TextStyle(fontSize: 12), image: NetworkImage(selectedSku['pic'] != null ? selectedSku['pic'] : shopObj['pic']),
fit: BoxFit.cover,
),
), ),
), ),
SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'¥${selectedSku != null ? selectedSku['price'] : shopObj['price']}',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.red,
),
),
SizedBox(height: 4),
Text(
'库存: ${selectedSku != null ? selectedSku['stock'] : shopObj['stock']}',
style: TextStyle(
fontSize: 12,
color: Colors.grey[600],
),
),
],
),
),
//
Row(
children: [
//
GestureDetector(
onTap: () {
setState(() {
if (_quantity > 1) {
_quantity--;
}
});
},
child: Container(
width: 28,
height: 28,
decoration: BoxDecoration(
color: _quantity > 1 ? Colors.grey[200] : Colors.grey[100],
borderRadius: BorderRadius.circular(4),
border: Border.all(color: Colors.grey[300]!),
),
child: Icon(
Icons.remove,
size: 16,
color: _quantity > 1 ? Colors.black : Colors.grey[400],
),
),
),
SizedBox(width: 8),
//
Container(
width: 40,
alignment: Alignment.center,
child: Text(
'$_quantity',
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.bold,
),
),
),
SizedBox(width: 8),
//
GestureDetector(
onTap: () {
setState(() {
final maxStock = selectedSku != null ? selectedSku['stock'] : shopObj['stock'];
if (_quantity < maxStock) {
_quantity++;
}
});
},
child: Container(
width: 28,
height: 28,
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.circular(4),
border: Border.all(color: Colors.grey[300]!),
),
child: Icon(
Icons.add,
size: 16,
),
),
),
],
),
], ],
); ),
}).toList(), Divider(height: 20, color: Colors.grey[200]),
//
...attrList.map<Widget>((attr) {
final attrName = attr['name'] ?? '';
final options = attr['options'] as List<dynamic>? ?? [];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'$attrName:',
style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold),
),
SizedBox(height: 8),
Wrap(
spacing: 8,
runSpacing: 8,
children: options.map<Widget>((option) {
final optionName = option['name'] ?? '';
final isSelected = isAttributeSelected(attrName, optionName);
return GestureDetector(
onTap: () => handleAttributeSelect(attrName, optionName),
child: Container(
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 6),
decoration: BoxDecoration(
color: isSelected ? Color(0xFFFFF0F0) : Colors.grey[200],
borderRadius: BorderRadius.circular(20),
border: isSelected ? Border.all(color: Color(0xFFFF5000), width: 1) : null,
),
child: Text(
optionName,
style: TextStyle(
fontSize: 12,
color: isSelected ? Color(0xFFFF5000) : Colors.black87,
),
),
),
);
}).toList(),
),
SizedBox(height: 12),
],
);
}).toList(),
],
), ),
), ),
// //
@ -576,77 +724,7 @@ class _GoodsState extends State<Goods> {
child: Row( child: Row(
spacing: 15.0, spacing: 15.0,
children: [ children: [
// Column( //
// mainAxisAlignment: MainAxisAlignment.center,
// children: [
// Icon(
// Icons.store,
// color: Color(0xFFFF5000),
// size: 18.0,
// ),
// Text(
// '店铺',
// style: TextStyle(fontSize: 12.0),
// )
// ],
// ),
//
// GestureDetector(
// onTap: () async {
// //
// logger.i('联系客服:$shopObj');
// final res = await ImService.instance.getConversation(conversationID: 'c2c_${shopObj['tenantId']}');
// V2TimConversation conversation = res.data;
// logger.i(conversation.toLogString());
// if (res.success) {
// //
// V2TimUserFullInfo? sellerInfo;
// final resIm = await ImService.instance.otherInfo(shopObj['tenantId']);
// if (resIm.success && resIm.data != null) {
// sellerInfo = resIm.data!;
// logger.i(sellerInfo!.toLogString());
// } else {
// logger.e(resIm.desc);
// }
// conversation.showName = conversation.showName ?? sellerInfo!.nickName;
// Get.toNamed('/chat', arguments: conversation);
// } else {
// MyDialog.toast(res.desc, icon: const Icon(Icons.warning), style: ToastStyle(backgroundColor: Colors.red.withAlpha(200)));
// }
// },
// child: Column(
// mainAxisAlignment: MainAxisAlignment.center,
// children: [
// Icon(
// Icons.child_care_outlined,
// size: 18.0,
// ),
// Text(
// '联系商家',
// style: TextStyle(fontSize: 12.0),
// )
// ],
// ),
// )
// Column(
// mainAxisAlignment: MainAxisAlignment.center,
// children: [
// Badge.count(
// backgroundColor: Color(0xFFFF5000),
// count: 6,
// child: Icon(
// Icons.shopping_cart_outlined,
// size: 18.0,
// ),
// ),
// Text(
// '购物车',
// style: TextStyle(fontSize: 12.0),
// )
// ],
// ),
], ],
), ),
), ),
@ -658,15 +736,8 @@ class _GoodsState extends State<Goods> {
color: Color(0xFFFFEBEB), color: Color(0xFFFFEBEB),
borderRadius: BorderRadius.circular(30.0), borderRadius: BorderRadius.circular(30.0),
), ),
child: Row( child: shopObj['canOrder'] == true?Row(
children: [ children: [
// Padding(
// padding: EdgeInsets.symmetric(horizontal: 10.0),
// child: Text(
// '加入购物车',
// style: TextStyle(color: Color(0xFFFF5000), fontSize: 14.0),
// ),
// ),
Container( Container(
alignment: Alignment.center, alignment: Alignment.center,
padding: const EdgeInsets.symmetric(horizontal: 20.0), padding: const EdgeInsets.symmetric(horizontal: 20.0),
@ -674,8 +745,8 @@ class _GoodsState extends State<Goods> {
child: GestureDetector( child: GestureDetector(
onTap: () async { onTap: () async {
// orderId // orderId
// String orderId = '1958380183857659904'; // String skuId = selectedSku != null ? selectedSku['id'] : shopObj['skuList'][0]['id'];
String orderId = await createOrder(shopObj['skuList'][0]['id']); String orderId = await createOrder(skuId);
if (orderId.isNotEmpty) { if (orderId.isNotEmpty) {
Get.toNamed('/order/detail', arguments: {'orderId': orderId}); Get.toNamed('/order/detail', arguments: {'orderId': orderId});
} else { } else {
@ -689,7 +760,7 @@ class _GoodsState extends State<Goods> {
), ),
), ),
], ],
), ):null,
), ),
], ],
), ),

View File

@ -784,7 +784,7 @@ class _OrderDetailState extends State<OrderDetail> with SingleTickerProviderStat
), ),
Spacer(), Spacer(),
Text( Text(
'x${productInfo['buyNum']?.toString() ?? '1'}', 'x${productInfo['quantity']?.toString() ?? '1'}',
style: TextStyle(color: Colors.grey), style: TextStyle(color: Colors.grey),
), ),
], ],
@ -829,7 +829,7 @@ class _OrderDetailState extends State<OrderDetail> with SingleTickerProviderStat
size: 18.0, size: 18.0,
), ),
onTap: () async { onTap: () async {
await Clipboard.setData(ClipboardData(text: _orderId)); await Clipboard.setData(ClipboardData(text: orderGoodsInfo?['orderSn']));
MyDialog.toast('订单已复制到剪切板', icon: Icon(Icons.check_circle)); MyDialog.toast('订单已复制到剪切板', icon: Icon(Icons.check_circle));
}, },
) )
@ -838,9 +838,9 @@ class _OrderDetailState extends State<OrderDetail> with SingleTickerProviderStat
SizedBox(height: 10), SizedBox(height: 10),
Column( Column(
children: [ children: [
_buildOrderInfoRow('订单号', orderGoodsInfo?['orderId'] ?? ''), _buildOrderInfoRow('订单号', orderGoodsInfo?['orderSn'] ?? ''),
_buildOrderInfoRow('下单时间', orderGoodsInfo?['createTime'] ?? ''), _buildOrderInfoRow('下单时间', orderGoodsInfo?['createTime'] ?? ''),
_buildOrderInfoRow('购买数量', (productInfo['buyNum'] ?? 0).toString()), _buildOrderInfoRow('购买数量', (productInfo['quantity'] ?? 0).toString()),
_buildOrderInfoRow('订单金额', '¥${orderGoodsInfo?['totalAmount'] ?? '0.00'}'), _buildOrderInfoRow('订单金额', '¥${orderGoodsInfo?['totalAmount'] ?? '0.00'}'),
_buildOrderInfoRow('实付金额', '¥${orderGoodsInfo?['payAmount'] ?? '0.00'}'), _buildOrderInfoRow('实付金额', '¥${orderGoodsInfo?['payAmount'] ?? '0.00'}'),
], ],