library; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; import 'package:loopin/service/http.dart'; import 'package:loopin/api/shop_api.dart'; import 'package:shirne_dialog/shirne_dialog.dart'; import 'package:timer_count_down/timer_count_down.dart'; import 'package:loopin/utils/wxsdk.dart'; import '../../behavior/custom_scroll_behavior.dart'; import '../../utils/lifecycle_handler.dart'; class SellerOrderDetail extends StatefulWidget { const SellerOrderDetail({super.key}); @override State createState() => _SellerOrderDetailState(); } class _SellerOrderDetailState extends State with SingleTickerProviderStateMixin { late String _orderId; dynamic orderGoodsInfo; int _initialSeconds = 30 * 60; // 存储初始秒数 bool _countdownFinished = false; // 新增标志位,用于跟踪倒计时是否结束 bool _isLoading = true; // 添加加载状态 @override void initState() { super.initState(); _orderId = Get.arguments['orderId'] ?? ''; getOrderDetail(orderId: _orderId); LifecycleHandler.onAppResumed = _onAppResumed; } @override void dispose() { LifecycleHandler.onAppResumed = null; super.dispose(); } void _onAppResumed() { print('App回到前台,刷新订单状态,订单Id${_orderId}'); getOrderDetail(orderId: _orderId); // 刷新订单详情数据 _showPaymentResultDialog(); // 展示支付结果弹框 } // 获取订单状态 void getOrderRealStatus({required String orderId}) async { try { final res = await Http.get('${ShopApi.goodsOrderStatus}/$orderId'); Get.toNamed('/myOrder'); } catch (e) { print('报错-------------->${e}'); } } // 获取订单详情信息,包含商品参数 void getOrderDetail({required String orderId}) async { try { setState(() { _isLoading = true; }); final res = await Http.get('${ShopApi.goodsOrderDetail}/$orderId'); print('订单详情-------------->${res['data']}'); setState(() { orderGoodsInfo = res['data']; _isLoading = false; }); } catch (e) { setState(() { _isLoading = false; }); MyDialog.toast('获取订单详情失败'); } } // 取消订单 void _cancelOrder() async { try { final res = await Http.post('${ShopApi.cancelGoodsOrder}/$_orderId'); getOrderDetail(orderId: _orderId); // 刷新订单详情数据 } catch (e) { MyDialog.toast('取消订单失败'); } } // 显示支付结果弹框 void _showPaymentResultDialog() { showDialog( context: context, barrierDismissible: false, barrierColor: Colors.black54, builder: (BuildContext context) { return Dialog( backgroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16.0), ), child: Padding( padding: const EdgeInsets.all(20.0), child: Column( mainAxisSize: MainAxisSize.min, children: [ // 图标 Container( width: 60, height: 60, decoration: BoxDecoration( color: Color(0xFFFFF8E6), shape: BoxShape.circle, ), child: Icon( Icons.payment, size: 32, color: Color(0xFFFFA500), ), ), SizedBox(height: 16), // 标题 Text( '支付确认', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: Colors.black87, ), ), SizedBox(height: 8), // 描述 Text( '请确认您的支付状态', style: TextStyle( fontSize: 14, color: Colors.grey[600], ), textAlign: TextAlign.center, ), SizedBox(height: 24), // 按钮区域 Row( children: [ // 支付遇到问题按钮 Expanded( child: OutlinedButton( onPressed: () { Navigator.of(context).pop(); getOrderRealStatus(orderId: _orderId); // 主动再次拉取订单状态 }, style: OutlinedButton.styleFrom( backgroundColor: Colors.white, foregroundColor: Colors.grey[700], side: BorderSide(color: Colors.grey[300]!), padding: EdgeInsets.symmetric(vertical: 12), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), child: Text('支付遇到问题'), ), ), SizedBox(width: 12), // 支付完成按钮 Expanded( child: ElevatedButton( onPressed: () { Navigator.of(context).pop(); getOrderRealStatus(orderId: _orderId); // 同时主动拉取订单状态 }, style: ElevatedButton.styleFrom( backgroundColor: Color(0xFFFF5000), foregroundColor: Colors.white, padding: EdgeInsets.symmetric(vertical: 12), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), child: Text('支付完成'), ), ), ], ), ], ), ), ); }, ); } // 获取订单状态文本 String getOrderStatusText(int status) { switch (status) { case 0: return '待付款'; case 1: return '待核销'; case 2: return '已完成'; case 3: return '已关闭'; case 4: return '退款中'; case 5: return '已退款'; case 6: return '已取消'; default: return '未知状态'; } } // 获取订单状态颜色 Color getOrderStatusColor(int status) { switch (status) { case 0: return Colors.grey; case 1: return Colors.blue; case 2: return Colors.green; case 3: return Colors.red; case 4: return Colors.orange; case 5: return Colors.grey; case 6: return Colors.grey; default: return Colors.black; } } // 获取商品信息列表 List getProductInfoList() { // 优先使用 items 字段 if (orderGoodsInfo?['items'] != null && orderGoodsInfo!['items'] is List) { return orderGoodsInfo!['items']; } // 如果 items 为空,使用 productInfo 字段 if (orderGoodsInfo?['productInfo'] != null && orderGoodsInfo!['productInfo'] is List) { return orderGoodsInfo!['productInfo']; } // 如果都为空,返回空列表 return []; } // 获取第一个商品信息 dynamic getFirstProductInfo() { final productList = getProductInfoList(); return productList.isNotEmpty ? productList[0] : null; } // 构建商品图片 Widget _buildProductImage(dynamic productInfo) { final picUrl = productInfo?['pic']; if (picUrl == null || picUrl.isEmpty) { return Container( width: 80.0, height: 80.0, decoration: BoxDecoration( color: Colors.grey[100], borderRadius: BorderRadius.circular(8.0), ), child: Icon( Icons.shopping_bag_outlined, size: 40.0, color: Colors.grey[400], ), ); } return Image.network( picUrl, width: 80.0, height: 80.0, fit: BoxFit.cover, errorBuilder: (context, error, stackTrace) { return Container( width: 80.0, height: 80.0, decoration: BoxDecoration( color: Colors.grey[100], borderRadius: BorderRadius.circular(8.0), ), child: Icon( Icons.shopping_bag_outlined, size: 40.0, color: Colors.grey[400], ), ); }, loadingBuilder: (context, child, loadingProgress) { if (loadingProgress == null) return child; return Container( width: 80.0, height: 80.0, decoration: BoxDecoration( color: Colors.grey[100], borderRadius: BorderRadius.circular(8.0), ), child: Center( child: CircularProgressIndicator( value: loadingProgress.expectedTotalBytes != null ? loadingProgress.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes! : null, ), ), ); }, ); } // 构建商品列表 Widget _buildProductList() { final productList = getProductInfoList(); if (productList.isEmpty) { return Padding( padding: const EdgeInsets.symmetric(vertical: 16.0), child: Text( '暂无商品信息', style: TextStyle(color: Colors.grey, fontSize: 14), ), ); } return Column( children: productList.map((product) { return Padding( padding: const EdgeInsets.only(bottom: 12.0), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildProductImage(product), SizedBox(width: 10.0), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( product?['productName']?.toString() ?? '未知商品', maxLines: 2, overflow: TextOverflow.ellipsis, style: TextStyle(fontSize: 14), ), SizedBox(height: 8), Row( children: [ Text( '¥${product?['salePrice']?.toString() ?? '0.00'}', style: TextStyle(color: Colors.red, fontWeight: FontWeight.bold), ), Spacer(), Text( 'x${product?['buyNum']?.toString() ?? '1'}', style: TextStyle(color: Colors.grey), ), ], ), ], ), ) ], ), ); }).toList(), ); } // 构建底部按钮 Widget buildBottomButtons() { if (orderGoodsInfo == null) return SizedBox.shrink(); int orderStatus = orderGoodsInfo?['status'] ?? 0; switch (orderStatus) { case 0: // 待付款 return Row( mainAxisAlignment: MainAxisAlignment.end, children: [ ElevatedButton( onPressed: () { // 取消订单逻辑 _cancelOrder(); }, style: ButtonStyle( backgroundColor: WidgetStateProperty.all(Colors.white), foregroundColor: WidgetStateProperty.all(Colors.black87), side: WidgetStateProperty.all(BorderSide(color: Colors.grey[300]!)), ), child: const Text('取消订单'), ), const SizedBox(width: 10.0), ElevatedButton( onPressed: () { // 打开微信小程序的某个页面地址,如pages/index/index Wxsdk.openMiniApp(orderId: _orderId); }, style: ButtonStyle( backgroundColor: WidgetStateProperty.all(Color(0xff07c160)), foregroundColor: WidgetStateProperty.all(Colors.white), ), child: const Text('去支付'), ), ], ); case 1: // 待核销 return Row( mainAxisAlignment: MainAxisAlignment.end, children: [ const SizedBox(width: 10.0), ElevatedButton( onPressed: () {}, style: ButtonStyle( backgroundColor: WidgetStateProperty.all(Color(0xFFFF5000)), foregroundColor: WidgetStateProperty.all(Colors.white), ), child: const Text('待核销'), ), ], ); case 2: // 已完成 return Row( mainAxisAlignment: MainAxisAlignment.end, children: [ const SizedBox(width: 10.0), ElevatedButton( onPressed: () {}, style: ButtonStyle( backgroundColor: WidgetStateProperty.all(Colors.green), foregroundColor: WidgetStateProperty.all(Colors.white), ), child: const Text('已完成'), ), ], ); case 3: // 已关闭 return Row( mainAxisAlignment: MainAxisAlignment.end, children: [ const SizedBox(width: 10.0), ElevatedButton( onPressed: () {}, style: ButtonStyle( backgroundColor: WidgetStateProperty.all(Colors.grey), foregroundColor: WidgetStateProperty.all(Colors.white), ), child: const Text('已关闭'), ), ], ); case 4: // 退款中 return Row( mainAxisAlignment: MainAxisAlignment.end, children: [ const SizedBox(width: 10.0), ElevatedButton( onPressed: () {}, style: ButtonStyle( backgroundColor: WidgetStateProperty.all(Colors.orange), foregroundColor: WidgetStateProperty.all(Colors.white), ), child: const Text('退款中'), ), ], ); case 5: // 已退款 return Row( mainAxisAlignment: MainAxisAlignment.end, children: [ const SizedBox(width: 10.0), ElevatedButton( onPressed: () {}, style: ButtonStyle( backgroundColor: WidgetStateProperty.all(Colors.grey), foregroundColor: WidgetStateProperty.all(Colors.white), ), child: const Text('已退款'), ), ], ); case 6: // 已取消 return Row( mainAxisAlignment: MainAxisAlignment.end, children: [ const SizedBox(width: 10.0), ElevatedButton( onPressed: () {}, style: ButtonStyle( backgroundColor: WidgetStateProperty.all(Colors.grey), foregroundColor: WidgetStateProperty.all(Colors.white), ), child: const Text('已取消'), ), ], ); default: return SizedBox.shrink(); } } Widget emptyTip() { return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Image.asset( 'assets/images/empty.png', width: 100.0, ), SizedBox(height: 16), Text( '还没有订单信息~', style: TextStyle(color: Colors.grey, fontSize: 12.0), ) ], ); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.grey[50], appBar: AppBar( backgroundColor: Color(0xFFFF5000), foregroundColor: Colors.white, title: Text('订单详情'), titleSpacing: 1.0, ), body: _isLoading ? Center(child: CircularProgressIndicator()) : orderGoodsInfo == null ? emptyTip() : ScrollConfiguration( behavior: CustomScrollBehavior().copyWith(scrollbars: false), child: ListView( physics: BouncingScrollPhysics(), padding: EdgeInsets.all(10.0), children: [ if (orderGoodsInfo?['status'] == 0) // 修正:应该是 status 而不是 orderStatus Container( padding: EdgeInsets.all(12.0), margin: EdgeInsets.only(bottom: 10.0), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(15.0), boxShadow: [ BoxShadow( color: Colors.black.withAlpha(10), offset: Offset(0.0, 1.0), blurRadius: 1.0, spreadRadius: 0.0, ), ], ), child: Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.info, size: 16.0, color: Colors.orange, ), SizedBox(width: 4), Text( getOrderStatusText(orderGoodsInfo?['status'] ?? 0), style: TextStyle(color: Colors.orange), ), SizedBox(width: 4), Text( _countdownFinished ? '倒计时已结束' : '剩余 ', style: TextStyle(color: Colors.grey), ), if (!_countdownFinished) Countdown( seconds: _initialSeconds, build: (_, double time) { int m = ((time % 3600) ~/ 60).toInt(); int s = (time % 60).toInt(); String formatted = "${m.toString().padLeft(2, '0')}:${s.toString().padLeft(2, '0')}"; return Text( formatted, style: TextStyle(color: Colors.red, fontWeight: FontWeight.bold), ); }, interval: Duration(seconds: 1), onFinished: () { print("倒计时结束"); _cancelOrder(); setState(() { _countdownFinished = true; }); }, ), ], ), SizedBox(height: 4), Text( _countdownFinished ? '订单已自动取消' : '超过30分钟未支付,订单将自动取消', style: TextStyle(color: Colors.grey, fontSize: 12.0), ), ], ), ), // 商品信息 Container( margin: EdgeInsets.only(bottom: 10.0), padding: EdgeInsets.all(10.0), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(15.0), boxShadow: [ BoxShadow( color: Colors.black.withAlpha(10), offset: Offset(0.0, 1.0), blurRadius: 1.0, spreadRadius: 0.0, ), ], ), child: Column( children: [ Row( children: [ Spacer(), Text( getOrderStatusText(orderGoodsInfo?['status'] ?? 0), style: TextStyle( color: getOrderStatusColor(orderGoodsInfo?['status'] ?? 0), fontWeight: FontWeight.bold, ), ) ], ), SizedBox(height: 10), _buildProductList(), ], ), ), // 订单信息 Container( margin: EdgeInsets.only(bottom: 10.0), padding: EdgeInsets.all(10.0), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(15.0), boxShadow: [ BoxShadow( color: Colors.black.withAlpha(10), offset: Offset(0.0, 1.0), blurRadius: 1.0, spreadRadius: 0.0, ), ], ), child: Column( children: [ Row( children: [ Text( '订单信息', style: TextStyle(fontSize: 15.0, fontWeight: FontWeight.bold), ), Spacer(), InkWell( child: Icon( Icons.copy, color: Colors.grey, size: 18.0, ), onTap: () async { await Clipboard.setData(ClipboardData(text: _orderId)); MyDialog.toast('订单已复制到剪切板', icon: Icon(Icons.check_circle)); }, ) ], ), SizedBox(height: 10), Column( children: [ _buildOrderInfoRow('订单号', orderGoodsInfo?['orderId']?.toString() ?? ''), _buildOrderInfoRow('下单时间', orderGoodsInfo?['createTime']?.toString() ?? ''), _buildOrderInfoRow('购买数量', _calculateTotalQuantity().toString()), _buildOrderInfoRow('订单金额', '¥${orderGoodsInfo?['totalAmount']?.toString() ?? '0.00'}'), _buildOrderInfoRow('实付金额', '¥${orderGoodsInfo?['payAmount']?.toString() ?? '0.00'}'), ], ) ], ), ), ], ), ), // 底部固定按钮 bottomNavigationBar: orderGoodsInfo == null ? null : SafeArea( minimum: const EdgeInsets.all(10), child: Container( height: 60.0, color: Colors.white, padding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0), child: buildBottomButtons(), ), ), ); } // 计算总购买数量 int _calculateTotalQuantity() { final productList = getProductInfoList(); int total = 0; for (var product in productList) { total += (product?['buyNum'] as int? ?? 0); } return total; } Widget _buildOrderInfoRow(String label, String value) { return Padding( padding: const EdgeInsets.symmetric(vertical: 6.0), child: Row( children: [ Text( label, style: TextStyle(color: Colors.grey, fontSize: 13), ), Spacer(), Text(value, style: TextStyle(fontSize: 13)), ], ), ); } }