细节修改

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': '朋友圈'},
];
//
Map<String, String> selectedAttributes = {}; //
dynamic selectedSku; // SKU
int _quantity = 1; //
@override
void initState() {
super.initState();
@ -71,20 +76,82 @@ class _GoodsState extends State<Goods> {
logger.e(res['data']);
setState(() {
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) {
logger.e(e);
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 {
var params = {
"type": 1, // 1->2->;3->
"distribution": 1, // 1->2->;3->;
"skuItemBOList": [
{"skuId": goodsId, "quantity": 1}
{"skuId": goodsId, "quantity": _quantity}
]
};
print('下单请求参数---->$params');
@ -271,6 +338,10 @@ class _GoodsState extends State<Goods> {
},
);
}
//
bool isAttributeSelected(String attrName, String optionName) {
return selectedAttributes[attrName] == optionName;
}
@override
Widget build(BuildContext context) {
@ -378,17 +449,7 @@ class _GoodsState extends State<Goods> {
Row(
spacing: 5.0,
children: [
//
// Text(
// '¥${shopObj['price']}',
// style: TextStyle(
// color: Colors.white,
// fontSize: 16.0,
// decoration: TextDecoration.lineThrough,
// decorationColor: Colors.black,
// decorationThickness: 1.5,
// ),
// ),
// SKU价格或默认价格
Container(
padding: EdgeInsets.symmetric(horizontal: 8.0, vertical: 3.0),
decoration: BoxDecoration(
@ -396,12 +457,11 @@ class _GoodsState extends State<Goods> {
borderRadius: BorderRadius.circular(50.0),
),
child: Text(
'¥${shopObj['price']}',
'¥${selectedSku != null ? selectedSku['price'] : shopObj['price']}',
style: TextStyle(color: Colors.red, fontSize: 12.0),
),
),
Text(
// '已售${Utils().graceNumber(shopObj['sales'] ?? 0)}',
'已售${Utils.graceNumber(int.tryParse(shopObj['sales']?.toString() ?? '0') ?? 0)}',
style: TextStyle(color: Colors.white, fontSize: 12.0),
),
@ -462,85 +522,173 @@ class _GoodsState extends State<Goods> {
),
),
//
//
Container(
width: double.infinity,
margin: EdgeInsets.only(top: 10.0),
padding: EdgeInsets.all(10.0),
decoration: BoxDecoration(
color: Colors.white,
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(
crossAxisAlignment: CrossAxisAlignment.start,
children: attrList.map<Widget>((attr) {
final attrName = attr['name'] ?? '';
final options = attr['options'] as List<dynamic>? ?? [];
final optionNames = options.map((o) => o['name']).join(' / ');
return Row(
children: [
//
Row(
children: [
Text(
'$attrName: ',
style: TextStyle(fontSize: 12, fontWeight: FontWeight.bold),
),
Expanded(
child: Text(
optionNames,
style: TextStyle(fontSize: 12),
//
Container(
width: 60,
height: 60,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
image: DecorationImage(
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(
spacing: 15.0,
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),
borderRadius: BorderRadius.circular(30.0),
),
child: Row(
child: shopObj['canOrder'] == true?Row(
children: [
// Padding(
// padding: EdgeInsets.symmetric(horizontal: 10.0),
// child: Text(
// '加入购物车',
// style: TextStyle(color: Color(0xFFFF5000), fontSize: 14.0),
// ),
// ),
Container(
alignment: Alignment.center,
padding: const EdgeInsets.symmetric(horizontal: 20.0),
@ -674,8 +745,8 @@ class _GoodsState extends State<Goods> {
child: GestureDetector(
onTap: () async {
// orderId
// String orderId = '1958380183857659904'; //
String orderId = await createOrder(shopObj['skuList'][0]['id']);
String skuId = selectedSku != null ? selectedSku['id'] : shopObj['skuList'][0]['id'];
String orderId = await createOrder(skuId);
if (orderId.isNotEmpty) {
Get.toNamed('/order/detail', arguments: {'orderId': orderId});
} 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(),
Text(
'x${productInfo['buyNum']?.toString() ?? '1'}',
'x${productInfo['quantity']?.toString() ?? '1'}',
style: TextStyle(color: Colors.grey),
),
],
@ -829,7 +829,7 @@ class _OrderDetailState extends State<OrderDetail> with SingleTickerProviderStat
size: 18.0,
),
onTap: () async {
await Clipboard.setData(ClipboardData(text: _orderId));
await Clipboard.setData(ClipboardData(text: orderGoodsInfo?['orderSn']));
MyDialog.toast('订单已复制到剪切板', icon: Icon(Icons.check_circle));
},
)
@ -838,9 +838,9 @@ class _OrderDetailState extends State<OrderDetail> with SingleTickerProviderStat
SizedBox(height: 10),
Column(
children: [
_buildOrderInfoRow('订单号', orderGoodsInfo?['orderId'] ?? ''),
_buildOrderInfoRow('订单号', orderGoodsInfo?['orderSn'] ?? ''),
_buildOrderInfoRow('下单时间', orderGoodsInfo?['createTime'] ?? ''),
_buildOrderInfoRow('购买数量', (productInfo['buyNum'] ?? 0).toString()),
_buildOrderInfoRow('购买数量', (productInfo['quantity'] ?? 0).toString()),
_buildOrderInfoRow('订单金额', '¥${orderGoodsInfo?['totalAmount'] ?? '0.00'}'),
_buildOrderInfoRow('实付金额', '¥${orderGoodsInfo?['payAmount'] ?? '0.00'}'),
],