From c23f939c490e789082e900732b43b7905511d343 Mon Sep 17 00:00:00 2001 From: cuiyouliang <799699717@qq.com> Date: Fri, 12 Sep 2025 15:45:53 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AE=A2=E5=8D=95=E8=81=94=E8=B0=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/api/shop_api.dart | 2 +- lib/pages/goods/detail.dart | 2 +- lib/pages/index/index.dart | 2 +- lib/pages/order/detail.dart | 700 ++++++++++++++++++++---------------- lib/pages/order/seller.dart | 449 ++++++++++++++++------- 5 files changed, 714 insertions(+), 441 deletions(-) diff --git a/lib/api/shop_api.dart b/lib/api/shop_api.dart index 36f8845..1521438 100644 --- a/lib/api/shop_api.dart +++ b/lib/api/shop_api.dart @@ -28,7 +28,7 @@ class ShopApi { static const String cancelGoodsOrder= '/app/order/cancel'; // app端我的订单 - static const String myOrderList= '/oms/order/list'; + static const String myOrderList= '/app/order/page'; // 商家营收摘要 static const String revenueInfo= '/app/merchant/account/statistic'; diff --git a/lib/pages/goods/detail.dart b/lib/pages/goods/detail.dart index fc2e1b6..e4b5d47 100644 --- a/lib/pages/goods/detail.dart +++ b/lib/pages/goods/detail.dart @@ -675,7 +675,7 @@ class _GoodsState extends State { // String orderId = '1958380183857659904'; //测试数据 String orderId = await createOrder(shopObj['skuList'][0]['id']); if (orderId.isNotEmpty) { - Get.toNamed('/order/detail', arguments: orderId); + Get.toNamed('/order/detail', arguments: {'orderId': orderId}); } else { MyDialog.toast('生成订单失败', icon: const Icon(Icons.warning), style: ToastStyle(backgroundColor: Colors.red.withAlpha(200))); } diff --git a/lib/pages/index/index.dart b/lib/pages/index/index.dart index 9cfe351..b546909 100644 --- a/lib/pages/index/index.dart +++ b/lib/pages/index/index.dart @@ -160,7 +160,7 @@ class _IndexPageState extends State with SingleTickerProviderStateMix } }, onTabChanged: (index) { - logger.w("当前选中tab: $index"); + logger.w("当前选中ssssstab: $index"); }, dynamicTabs: tabs, tabAlignment: TabAlignment.start, diff --git a/lib/pages/order/detail.dart b/lib/pages/order/detail.dart index 5c839fc..9f0bc9b 100644 --- a/lib/pages/order/detail.dart +++ b/lib/pages/order/detail.dart @@ -1,7 +1,4 @@ library; -import 'dart:async'; -import 'dart:convert'; - import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; @@ -10,8 +7,6 @@ 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 'package:loopin/utils/index.dart'; - import '../../behavior/custom_scroll_behavior.dart'; import '../../utils/lifecycle_handler.dart'; @@ -25,77 +20,72 @@ class OrderDetail extends StatefulWidget { class _OrderDetailState extends State with SingleTickerProviderStateMixin { late String _orderId; dynamic orderGoodsInfo; - int _initialSeconds = 30 * 60;// 存储初始秒数 + int _initialSeconds = 30 * 60; // 存储初始秒数 bool _countdownFinished = false; // 新增标志位,用于跟踪倒计时是否结束 + bool _isLoading = true; // 添加加载状态 @override void initState() { super.initState(); - _orderId = Get.arguments; + _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); // 刷新订单详情数据 - getOrderRealStatus(orderId: _orderId); // 同时主动拉取订单状态 _showPaymentResultDialog(); // 展示支付结果弹框 } + // 获取订单状态 void getOrderRealStatus({required String orderId}) async { - try { - final res = await Http.get('${ShopApi.goodsOrderStatus}/$orderId'); - // transState - var orderStatus = res['data']['transState']; - - print('状态-------------->${orderStatus}'); - // orderStatus - setState(() { - orderGoodsInfo['orderStatus'] = orderStatus; - }); - if (orderStatus == 2) { // 已支付 - MyDialog.toast('支付成功'); - } - } catch (e) { - print('报错-------------->${e}'); + try { + final res = await Http.get('${ShopApi.goodsOrderStatus}/$orderId'); + Get.toNamed('/sellerOrder'); + } catch (e) { + print('报错-------------->${e}'); } } // 获取订单详情信息,包含商品参数 void getOrderDetail({required String orderId}) async { - try { - final res = await Http.get('${ShopApi.goodsOrderDetail}/$orderId'); - print('订单详情-------------->${res['data']}'); - setState(() { - orderGoodsInfo = res['data']; // 注意取 data 部分 - }); - } catch (e) { - Get.back(); - } + 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 { - print('取消订单: $_orderId'); - try { - final res = await Http.post('${ShopApi.cancelGoodsOrder}/$_orderId'); - print('取消订单成功-------------->${res}'); - getOrderDetail(orderId: _orderId); // 刷新订单详情数据 - } catch (e) { - print('取消订单失败-------------->${e}'); - } + try { + final res = await Http.post('${ShopApi.cancelGoodsOrder}/$_orderId'); + getOrderDetail(orderId: _orderId); // 刷新订单详情数据 + } catch (e) { + MyDialog.toast('取消订单失败'); + } } - // 显示支付结果弹框 void _showPaymentResultDialog() { - showDialog( context: context, barrierDismissible: false, @@ -157,7 +147,6 @@ class _OrderDetailState extends State with SingleTickerProviderStat child: OutlinedButton( onPressed: () { Navigator.of(context).pop(); - // getOrderDetail(orderId: _orderId); getOrderRealStatus(orderId: _orderId); // 主动再次拉取订单状态 }, style: OutlinedButton.styleFrom( @@ -199,26 +188,26 @@ class _OrderDetailState extends State with SingleTickerProviderStat ), ); }, - ).then((value) { - - }); + ); } // 获取订单状态文本 String getOrderStatusText(int status) { switch (status) { case 0: - return '待支付'; + return '待付款'; case 1: - return '支付中'; + return '待核销'; case 2: - return '已支付'; + return '已完成'; case 3: - return '已取消'; + return '已关闭'; case 4: + return '退款中'; + case 5: return '已退款'; - case 10: - return '无效订单'; + case 6: + return '已取消'; default: return '未知状态'; } @@ -228,20 +217,86 @@ class _OrderDetailState extends State with SingleTickerProviderStat Color getOrderStatusColor(int status) { switch (status) { case 0: - return Colors.orange; + return Colors.grey; case 1: return Colors.blue; case 2: return Colors.green; case 3: + return Colors.red; case 4: - case 10: + return Colors.orange; + case 5: + return Colors.grey; + case 6: return Colors.grey; default: return Colors.black; } } + // 构建商品图片 + Widget _buildProductImage() { + final productInfo = orderGoodsInfo?['productInfo'][0]; + 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 buildBottomButtons() { if (orderGoodsInfo == null) return SizedBox.shrink(); @@ -249,7 +304,7 @@ class _OrderDetailState extends State with SingleTickerProviderStat int orderStatus = orderGoodsInfo?['orderStatus'] ?? 0; switch (orderStatus) { - case 0: // 待支付 + case 0: // 待付款 return Row( mainAxisAlignment: MainAxisAlignment.end, children: [ @@ -261,6 +316,7 @@ class _OrderDetailState extends State with SingleTickerProviderStat style: ButtonStyle( backgroundColor: WidgetStateProperty.all(Colors.white), foregroundColor: WidgetStateProperty.all(Colors.black87), + side: WidgetStateProperty.all(BorderSide(color: Colors.grey[300]!)), ), child: const Text('取消订单'), ), @@ -279,70 +335,79 @@ class _OrderDetailState extends State with SingleTickerProviderStat ], ); - case 1: // 支付中 - return Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - ElevatedButton( - onPressed: () { - // 刷新订单状态 - getOrderDetail(orderId: _orderId); - }, - style: ButtonStyle( - backgroundColor: WidgetStateProperty.all(Colors.blue), - foregroundColor: WidgetStateProperty.all(Colors.white), - ), - child: const Text('支付中'), - ), - ], - ); - - case 2: // 已支付 + case 1: // 待核销 return Row( mainAxisAlignment: MainAxisAlignment.end, children: [ const SizedBox(width: 10.0), ElevatedButton( - onPressed: () { - }, + onPressed: () {}, style: ButtonStyle( backgroundColor: WidgetStateProperty.all(Color(0xFFFF5000)), foregroundColor: WidgetStateProperty.all(Colors.white), ), - child: const Text('已支付'), + child: const Text('待核销'), ), ], ); - case 3: // 已取消 - case 10: // 无效订单 + case 2: // 已完成 return Row( mainAxisAlignment: MainAxisAlignment.end, children: [ const SizedBox(width: 10.0), ElevatedButton( - onPressed: () { - - }, + onPressed: () {}, style: ButtonStyle( - backgroundColor: WidgetStateProperty.all(Color(0xFFFF5000)), + backgroundColor: WidgetStateProperty.all(Colors.green), foregroundColor: WidgetStateProperty.all(Colors.white), ), - child: const Text('已取消'), + child: const Text('已完成'), ), ], ); - case 4: // 已退款 + case 3: // 已关闭 return Row( mainAxisAlignment: MainAxisAlignment.end, children: [ const SizedBox(width: 10.0), ElevatedButton( - onPressed: () { - }, + onPressed: () {}, style: ButtonStyle( - backgroundColor: WidgetStateProperty.all(Color(0xFFFF5000)), + 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('已退款'), @@ -350,6 +415,22 @@ class _OrderDetailState extends State with SingleTickerProviderStat ], ); + 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(); } @@ -358,12 +439,12 @@ class _OrderDetailState extends State with SingleTickerProviderStat Widget emptyTip() { return Column( mainAxisAlignment: MainAxisAlignment.center, - spacing: 5.0, children: [ Image.asset( 'assets/images/empty.png', width: 100.0, ), + SizedBox(height: 16), Text( '还没有订单信息~', style: TextStyle(color: Colors.grey, fontSize: 12.0), @@ -374,22 +455,6 @@ class _OrderDetailState extends State with SingleTickerProviderStat @override Widget build(BuildContext context) { - if (orderGoodsInfo == null) { - return Scaffold( - backgroundColor: Colors.grey[50], - appBar: AppBar( - backgroundColor: Color(0xFFFF5000), - foregroundColor: Colors.white, - title: Text('订单详情'), - titleSpacing: 1.0, - ), - body: Center(child: CircularProgressIndicator()), - ); - } - - int orderStatus = orderGoodsInfo?['orderStatus'] ?? 0; - bool showCountdown = orderStatus == 0; // 只有待支付状态显示倒计时 - return Scaffold( backgroundColor: Colors.grey[50], appBar: AppBar( @@ -398,232 +463,235 @@ class _OrderDetailState extends State with SingleTickerProviderStat title: Text('订单详情'), titleSpacing: 1.0, ), - body: ScrollConfiguration( - behavior: CustomScrollBehavior().copyWith(scrollbars: false), - child: ListView( - physics: BouncingScrollPhysics(), - padding: EdgeInsets.all(10.0), - children: [ - if (showCountdown) - Column( - spacing: 5.0, - children: [ - Text.rich( - TextSpan(style: TextStyle(fontFamily: 'Arial'), children: [ - WidgetSpan( - child: Icon( - Icons.info, - size: 16.0, - )), - TextSpan(text: getOrderStatusText(orderStatus)), - TextSpan(text: _countdownFinished ? '倒计时已结束' : ' 剩余 '), - if (!_countdownFinished) - WidgetSpan( - alignment: PlaceholderAlignment.middle, - child: Countdown( - seconds: _initialSeconds, // 直接使用30分钟的秒数 - 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')}"; + 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?['orderStatus'] == 0) + 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?['orderStatus']), + 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: const TextStyle(color: Colors.red), - ); - }, - interval: const Duration(seconds: 1), - onFinished: () { - print("倒计时结束"); - _cancelOrder(); - setState(() { - _countdownFinished = true; // 倒计时结束时更新标志位 - }); - }, - ), - ), - ]), - ), - Text( - _countdownFinished - ? '订单已自动取消' - : '超过30分钟未支付,订单将自动取消', - style: TextStyle(color: Colors.grey, fontSize: 12.0), - ), - SizedBox( - height: 10.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( - spacing: 10.0, - children: [ - Row( - children: [ - Spacer(), - Text( - getOrderStatusText(orderStatus), - style: TextStyle(color: getOrderStatusColor(orderStatus)), - ) - ], - ), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - spacing: 10.0, - children: [ - Image.network( - '${orderGoodsInfo?['productInfo'][0]['pic']}', - width: 80.0, - ), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - spacing: 5.0, - children: [ - Text( - '${orderGoodsInfo?['productInfo'][0]['productName']}', - maxLines: 2, - overflow: TextOverflow.ellipsis, + 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: [ - Text( - '¥${orderGoodsInfo?['productInfo'][0]['salePrice']}', - style: TextStyle(color: Colors.red), - ), Spacer(), Text( - 'x${orderGoodsInfo?['productInfo'][0]['buyNum'] ?? 1}', - style: TextStyle(color: Colors.grey), - ), + getOrderStatusText(orderGoodsInfo?['orderStatus']), + style: TextStyle( + color: getOrderStatusColor(orderGoodsInfo?['orderStatus']), + fontWeight: FontWeight.bold, + ), + ) + ], + ), + SizedBox(height: 10), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildProductImage(), + SizedBox(width: 10.0), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '${orderGoodsInfo?['productInfo'][0]['productName']}', + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: TextStyle(fontSize: 14), + ), + SizedBox(height: 8), + Row( + children: [ + Text( + '¥${orderGoodsInfo?['productInfo'][0]['salePrice']}', + style: TextStyle(color: Colors.red, fontWeight: FontWeight.bold), + ), + Spacer(), + Text( + 'x${orderGoodsInfo?['productInfo'][0]['buyNum'] ?? 1}', + style: TextStyle(color: Colors.grey), + ), + ], + ), + ], + ), + ) ], ), ], ), - ) - ], - ), - ], - ), - ), - // 订单信息 - 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( - spacing: 10.0, - children: [ - Row( - children: [ - Text( - '订单信息', - style: TextStyle(fontSize: 15.0, fontWeight: FontWeight.bold), ), - Spacer(), - InkWell( - child: Icon( - Icons.copy, - color: Colors.grey, - size: 14.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, + ), + ], ), - onTap: ()async { - await Clipboard.setData(ClipboardData(text: _orderId)); - MyDialog.toast('订单已复制到剪切板', icon: Icon(Icons.check_circle)); - }, - ) + 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'] ?? ''), + _buildOrderInfoRow('下单时间', orderGoodsInfo?['createTime'] ?? ''), + _buildOrderInfoRow('购买数量', (orderGoodsInfo?['productInfo'][0]['buyNum'] ?? 0).toString()), + _buildOrderInfoRow('订单金额', '¥${orderGoodsInfo?['totalAmount'] ?? '0.00'}'), + _buildOrderInfoRow('实付金额', '¥${orderGoodsInfo?['payAmount'] ?? '0.00'}'), + ], + ) + ], + ), + ), ], ), - Column( - spacing: 5.0, - children: [ - Row( - children: [ - Text( - '订单号', - style: TextStyle(color: Colors.grey), - ), - Spacer(), - Text(orderGoodsInfo?['orderId'] ?? '', style: TextStyle(fontSize: 12.0)), - ], - ), - Row( - children: [ - Text( - '下单时间', - style: TextStyle(color: Colors.grey), - ), - Spacer(), - Text(orderGoodsInfo?['createTime'] ?? '', style: TextStyle(fontSize: 12.0)), - ], - ), - Row( - children: [ - Text( - '购买数量', - style: TextStyle(color: Colors.grey), - ), - Spacer(), - Text((orderGoodsInfo?['productInfo'][0]['buyNum'] ?? 0).toString(), - style: TextStyle(fontSize: 12.0)), - ], - ), - Row( - children: [ - Text( - '订单金额', - style: TextStyle(color: Colors.grey), - ), - Spacer(), - Text('¥${orderGoodsInfo?['totalAmount']??'0.00'}', style: TextStyle(fontSize: 12.0)), - ], - ), - Row( - children: [ - Text( - '实付金额', - style: TextStyle(color: Colors.grey), - ), - Spacer(), - Text('¥${orderGoodsInfo?['payAmount']??'0.00'}', style: TextStyle(fontSize: 12.0)), - ], - ), - ], - ) - ], + ), + // 底部固定按钮 + 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(), ), ), - ], - ), - ), - // 底部固定按钮 - bottomNavigationBar: SafeArea( - minimum: const EdgeInsets.all(10), - child: Container( - height: 50.0, - color: Colors.white, - padding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0), - child: buildBottomButtons(), - ), + ); + } + + 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)), + ], ), ); } diff --git a/lib/pages/order/seller.dart b/lib/pages/order/seller.dart index 1b7c183..87aebc6 100644 --- a/lib/pages/order/seller.dart +++ b/lib/pages/order/seller.dart @@ -3,7 +3,9 @@ library; import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:loopin/utils/wxsdk.dart'; import 'package:loopin/api/shop_api.dart'; +import 'package:loopin/components/my_toast.dart'; import 'package:loopin/service/http.dart'; import '../../behavior/custom_scroll_behavior.dart'; @@ -17,19 +19,37 @@ class Seller extends StatefulWidget { class _SellerState extends State with SingleTickerProviderStateMixin { GlobalKey scaffoldKey = GlobalKey(); - // 分页内容 - int pageNum = 1; + // 分页内容 - 为每个Tab单独存储数据 final int pageSize = 10; bool isLoadingMore = false; bool isRefreshing = false; - List> pageOrderList = []; + // 为每个Tab单独存储状态 + List> _allOrders = []; + List> _pendingPaymentOrders = []; + List> _pendingVerificationOrders = []; + List> _completedOrders = []; + List> _closedOrders = []; + List> _refundingOrders = []; + List> _refundedOrders = []; + List> _cancelledOrders = []; + + // 每个Tab的分页状态 + Map _pageNums = {}; + Map _totalCounts = {}; + Map _hasMoreData = {}; + Map _isLoading = {}; + + // 订单状态:0->待付款;1->待核销;2->已完成;3->已关闭;4->退款中;5->已退款 6->已取消 精确匹配 List tabList = [ - {'id': 0, 'name': "全部"}, // 0表示全部 - {'id': 4, 'name': "已退款", 'badge': 1}, // 4对应已退款 - {'id': 2, 'name': "待核销", 'badge': 1}, // 2对待核销 - {'id': 3, 'name': "已完成"}, // 3对已完成 - {'id': 5, 'name': "取消"} // 5对取消 + {'id': '', 'name': "全部", 'index': 0}, + {'id': 0, 'name': "待付款", 'index': 1}, + {'id': 1, 'name': "待核销", 'index': 2}, + {'id': 2, 'name': "已完成", 'index': 3}, + {'id': 3, 'name': "已关闭", 'index': 4}, + {'id': 4, 'name': "退款中", 'index': 5}, + {'id': 5, 'name': "已退款", 'index': 6}, + {'id': 6, 'name': "已取消", 'index': 7} ]; late ScrollController scrollController = ScrollController(); @@ -38,6 +58,14 @@ class _SellerState extends State with SingleTickerProviderStateMixin { @override void initState() { super.initState(); + // 初始化分页状态 + for (var tab in tabList) { + _pageNums[tab['index']] = 1; + _totalCounts[tab['index']] = 0; + _hasMoreData[tab['index']] = true; + _isLoading[tab['index']] = false; + } + // 监听滚动事件 scrollController.addListener(_scrollListener); // 监听tab切换事件 @@ -55,89 +83,207 @@ class _SellerState extends State with SingleTickerProviderStateMixin { super.dispose(); } + // 获取当前Tab的订单列表 + List> _getCurrentOrderList() { + final currentIndex = tabController.index; + switch (currentIndex) { + case 0: return _allOrders; + case 1: return _pendingPaymentOrders; + case 2: return _pendingVerificationOrders; + case 3: return _completedOrders; + case 4: return _closedOrders; + case 5: return _refundingOrders; + case 6: return _refundedOrders; + case 7: return _cancelledOrders; + default: return _allOrders; + } + } + + // 设置当前Tab的订单列表 + void _setCurrentOrderList(List> orders, bool loadMore) { + final currentIndex = tabController.index; + setState(() { + switch (currentIndex) { + case 0: + if (loadMore) { + _allOrders.addAll(orders); + } else { + _allOrders = orders; + } + break; + case 1: + if (loadMore) { + _pendingPaymentOrders.addAll(orders); + } else { + _pendingPaymentOrders = orders; + } + break; + case 2: + if (loadMore) { + _pendingVerificationOrders.addAll(orders); + } else { + _pendingVerificationOrders = orders; + } + break; + case 3: + if (loadMore) { + _completedOrders.addAll(orders); + } else { + _completedOrders = orders; + } + break; + case 4: + if (loadMore) { + _closedOrders.addAll(orders); + } else { + _closedOrders = orders; + } + break; + case 5: + if (loadMore) { + _refundingOrders.addAll(orders); + } else { + _refundingOrders = orders; + } + break; + case 6: + if (loadMore) { + _refundedOrders.addAll(orders); + } else { + _refundedOrders = orders; + } + break; + case 7: + if (loadMore) { + _cancelledOrders.addAll(orders); + } else { + _cancelledOrders = orders; + } + break; + } + }); + } + // 滚动监听 void _scrollListener() { - if (scrollController.position.pixels == scrollController.position.maxScrollExtent && !isLoadingMore) { + final currentIndex = tabController.index; + if (scrollController.position.pixels == scrollController.position.maxScrollExtent && + !_isLoading[currentIndex]! && + _hasMoreData[currentIndex]!) { getOrderList(true); } } // Tab切换监听 void _tabChanged() { - if (tabController.indexIsChanging) { - // 切换tab时重新加载数据 - getOrderList(false); + if (tabController.index != tabController.previousIndex) { + // 如果当前Tab没有数据,则加载数据 + final currentOrders = _getCurrentOrderList(); + if (currentOrders.isEmpty) { + getOrderList(false); + } } } // 获取订单列表 void getOrderList(bool loadMore) async { - if (isLoadingMore || isRefreshing) return; + final currentIndex = tabController.index; + final currentTab = tabList[currentIndex]; + + if (_isLoading[currentIndex]! || isRefreshing) return; setState(() { if (!loadMore) { - pageNum = 1; // 重置为第一页 + _pageNums[currentIndex] = 1; isRefreshing = true; - pageOrderList = []; } else { - isLoadingMore = true; + _isLoading[currentIndex] = true; } }); try { - final currentTab = tabList[tabController.index]; final status = currentTab['id']; final res = await Http.post(ShopApi.myOrderList, data: { - 'current': pageNum, // 当前页码 + 'current': _pageNums[currentIndex], // 当前页码 'size': pageSize, - // 'orderStatus': status == 0 ? '' : status.toString(), // 0表示全部,传空字符串 + 'status': status == '' ? '' : status.toString(), }); if (res['code'] == 200 && res['data'] != null) { final data = res['data']; final List> newOrders = List>.from(data['records'] ?? []); final int total = data['total'] ?? 0; - final int currentPage = data['current'] ?? 1; - final int pages = data['pages'] ?? 1; + debugPrint(data.toString(), wrapWidth: 1024); + + // 更新当前Tab的数据 + _setCurrentOrderList(newOrders, loadMore); + + // 更新分页状态 - 使用total总数判断 setState(() { - if (loadMore) { - pageOrderList.addAll(newOrders); - } else { - pageOrderList = newOrders; - } + // 更新总数 + _totalCounts[currentIndex] = total; - // 分页逻辑 - if (newOrders.isNotEmpty && currentPage < pages) { - pageNum = currentPage + 1; // 下一页 - isLoadingMore = true; - } else { - isLoadingMore = false; // 没有更多数据 + // 判断是否还有更多数据 + final currentOrderCount = _getCurrentOrderList().length; + _hasMoreData[currentIndex] = currentOrderCount < total; + + // 如果有更多数据,增加页码 + if (_hasMoreData[currentIndex]!) { + _pageNums[currentIndex] = _pageNums[currentIndex]! + 1; } }); } } catch (e) { print('获取订单列表失败: $e'); setState(() { - isLoadingMore = false; + _hasMoreData[currentIndex] = false; }); } finally { setState(() { isRefreshing = false; + _isLoading[currentIndex] = false; }); } } // 刷新数据时重置分页状态 void _refreshData() { + final currentIndex = tabController.index; setState(() { - pageNum = 1; - isLoadingMore = false; + _pageNums[currentIndex] = 1; + _totalCounts[currentIndex] = 0; + _isLoading[currentIndex] = false; + _hasMoreData[currentIndex] = true; }); getOrderList(false); } + // 获取付款文案 + String _getPaymentText(dynamic status) { + int statusCode = status is String ? int.tryParse(status) ?? 0 : (status is int ? status : 0); + + switch (statusCode) { + case 0: // 待付款 + return '待付款: '; + case 1: // 待核销 + return '已付款: '; + case 2: // 已完成 + return '实付款: '; + case 3: // 已关闭 + return '订单金额: '; + case 4: // 退款中 + return '实付款: '; + case 5: // 已退款 + return '退款金额: '; + case 6: // 已取消 + return '订单金额: '; + default: + return '金额: '; + } + } + // 构建订单项Widget Widget _buildOrderItem(Map order) { return GestureDetector( @@ -170,7 +316,7 @@ class _SellerState extends State with SingleTickerProviderStateMixin { width: 25.0, ), ), - Text(order['shopName'] ?? '商家名称'), + Text(order['items'][0]['tenantName'] ?? '商家名称'), Icon( Icons.arrow_forward_ios_rounded, color: Colors.grey, @@ -198,9 +344,9 @@ class _SellerState extends State with SingleTickerProviderStateMixin { color: Colors.grey[200], borderRadius: BorderRadius.circular(4.0), ), - child: item['image'] != null && item['image'].isNotEmpty + child: order['items'][0]['pic'] != null && order['items'][0]['pic'].isNotEmpty ? Image.network( - item['image'], + order['items'][0]['pic'], width: 80.0, height: 80.0, fit: BoxFit.cover, @@ -226,7 +372,7 @@ class _SellerState extends State with SingleTickerProviderStateMixin { Row( children: [ Text( - '¥${item['price'] ?? '0'}', + '¥${item['salePrice'] ?? '0'}', style: TextStyle(color: Colors.red, fontSize: 16), ), Spacer(), @@ -254,7 +400,7 @@ class _SellerState extends State with SingleTickerProviderStateMixin { Spacer(), Text.rich( TextSpan(children: [ - TextSpan(text: '实付款: '), + TextSpan(text: _getPaymentText(order['status'])), // 根据状态获取文案 TextSpan( text: '¥${order['totalAmount'] ?? '0'}', style: TextStyle(color: Colors.red, fontSize: 16), @@ -266,7 +412,7 @@ class _SellerState extends State with SingleTickerProviderStateMixin { ), SizedBox(height: 10), // 根据状态显示不同的按钮 - _buildActionButtons(order['status']), + _buildActionButtons(order), ], ), ), @@ -282,15 +428,19 @@ class _SellerState extends State with SingleTickerProviderStateMixin { int statusCode = status is String ? int.tryParse(status) ?? 0 : (status is int ? status : 0); switch (statusCode) { - case 1: + case 0: return '待付款'; - case 2: + case 1: return '待核销'; - case 3: + case 2: return '已完成'; + case 3: + return '已关闭'; case 4: - return '已退款'; + return '退款中'; case 5: + return '已退款'; + case 6: return '已取消'; default: return '未知状态'; @@ -302,39 +452,44 @@ class _SellerState extends State with SingleTickerProviderStateMixin { int statusCode = status is String ? int.tryParse(status) ?? 0 : (status is int ? status : 0); switch (statusCode) { + case 0: + return Colors.grey; case 1: - return Colors.orange; - case 2: return Colors.blue; - case 3: + case 2: return Colors.green; - case 4: + case 3: return Colors.red; + case 4: + return Colors.orange; case 5: return Colors.grey; + case 6: + return Colors.grey; default: return Colors.black; } } // 构建操作按钮 - Widget _buildActionButtons(dynamic status) { + Widget _buildActionButtons(dynamic orderObject) { // 处理字符串或数字类型的状态 + var status = orderObject['status']; + var orderId = orderObject['id']; int statusCode = status is String ? int.tryParse(status) ?? 0 : (status is int ? status : 0); - switch (statusCode) { - case 1: // 待付款 + case 0: // 待付款 return Row( mainAxisAlignment: MainAxisAlignment.end, children: [ ElevatedButton( - onPressed: () => _cancelOrder(), + onPressed: () => _cancelOrder(orderId), style: ButtonStyle(backgroundColor: WidgetStateProperty.all(Colors.white)), child: Text('取消订单'), ), SizedBox(width: 10), ElevatedButton( - onPressed: () => _payOrder(), + onPressed: () => _payOrder(orderId), style: ButtonStyle( backgroundColor: WidgetStateProperty.all(Color(0xff07c160)), foregroundColor: WidgetStateProperty.all(Colors.white), @@ -343,30 +498,13 @@ class _SellerState extends State with SingleTickerProviderStateMixin { ), ], ); - case 2: // 待核销 + case 1: // 待核销 return Row( mainAxisAlignment: MainAxisAlignment.end, - children: [ - ElevatedButton( - onPressed: () => _contactCustomerService(), - style: ButtonStyle( - backgroundColor: WidgetStateProperty.all(Color(0xFFFCBE13)), - foregroundColor: WidgetStateProperty.all(Colors.white), - ), - child: Text('联系客服'), - ), - ], ); - case 3: // 已完成 + case 2: // 已完成 return Row( mainAxisAlignment: MainAxisAlignment.end, - children: [ - ElevatedButton( - onPressed: () => _deleteOrder(), - style: ButtonStyle(backgroundColor: WidgetStateProperty.all(Colors.white)), - child: Text('删除订单'), - ), - ], ); default: return SizedBox.shrink(); @@ -374,20 +512,64 @@ class _SellerState extends State with SingleTickerProviderStateMixin { } // 订单操作的方法 - void _cancelOrder() { - // 取消订单逻辑 + void _cancelOrder(String orderId) async { + try { + final res = await Http.post('${ShopApi.cancelGoodsOrder}/$orderId'); + print('取消订单成功-------------->${res}'); + + if (res['code'] == 200) { + MyToast().tip( + title: '订单已取消', + position: 'center', + type: 'success', + ); + // 刷新所有相关的tab + _refreshAllRelatedTabs(); + } + } catch (e) { + print('取消订单失败-------------->${e}'); + } } - void _payOrder() { - // 支付订单逻辑 + // 刷新所有相关的tab + void _refreshAllRelatedTabs() { + // 需要刷新的tab索引:全部(0)、待付款(1)、已取消(7) + List tabsToRefresh = [0, 1, 7]; + + for (int tabIndex in tabsToRefresh) { + _resetTabData(tabIndex); + + // 如果当前正在查看这个tab,立即刷新数据 + if (tabController.index == tabIndex) { + getOrderList(false); + } + } } - void _contactCustomerService() { - // 联系客服逻辑 + void _payOrder(_orderId) { + // 打开微信小程序的某个页面地址,如pages/index/index + Wxsdk.openMiniApp(orderId: _orderId); } - void _deleteOrder() { - // 删除订单逻辑 + // 重置指定tab的数据 + void _resetTabData(int index) { + setState(() { + _pageNums[index] = 1; + _totalCounts[index] = 0; + _isLoading[index] = false; + _hasMoreData[index] = true; + + switch (index) { + case 0: _allOrders = []; break; + case 1: _pendingPaymentOrders = []; break; + case 2: _pendingVerificationOrders = []; break; + case 3: _completedOrders = []; break; + case 4: _closedOrders = []; break; + case 5: _refundingOrders = []; break; + case 6: _refundedOrders = []; break; + case 7: _cancelledOrders = []; break; + } + }); } @override @@ -398,51 +580,51 @@ class _SellerState extends State with SingleTickerProviderStateMixin { appBar: AppBar( titleSpacing: 1.0, title: Text( - '商家订单', + '我的订单', style: TextStyle(fontSize: 18), ), bottom: PreferredSize( preferredSize: Size.fromHeight(45.0), - child: Row(children: [ - Expanded( + child: Container( + height: 45.0, + alignment: Alignment.centerLeft, child: TabBar( controller: tabController, + tabAlignment: TabAlignment.start, + isScrollable: true, + padding: EdgeInsets.only(left: 0), + indicatorPadding: EdgeInsets.zero, + labelPadding: EdgeInsets.symmetric(horizontal: 10.0), tabs: tabList .map((item) => Container( + constraints: BoxConstraints(minWidth: 70), alignment: Alignment.center, - height: 45.0, child: Badge.count( backgroundColor: Colors.red, offset: Offset(14, -4), count: item['badge'] ?? 0, - isLabelVisible: item['badge'] != null ? true : false, + isLabelVisible: item['badge'] != null && item['badge'] > 0, child: Text( item['name'], style: TextStyle(fontSize: 16), overflow: TextOverflow.ellipsis, - softWrap: false, ), ), )) .toList(), - isScrollable: false, - overlayColor: WidgetStateProperty.all(Colors.transparent), - unselectedLabelColor: Colors.black87, - labelColor: Color(0xFFFF5000), - indicator: UnderlineTabIndicator( - borderRadius: BorderRadius.circular(10.0), - borderSide: BorderSide(color: Color(0xFFFF5000), width: 2.0), - ), - indicatorSize: TabBarIndicatorSize.tab, - unselectedLabelStyle: TextStyle(fontSize: 16.0, fontFamily: 'Microsoft YaHei'), - labelStyle: TextStyle(fontSize: 18.0, fontFamily: 'Microsoft YaHei', fontWeight: FontWeight.w700), - dividerHeight: 0, - padding: EdgeInsets.symmetric(horizontal: 10.0), - labelPadding: EdgeInsets.symmetric(horizontal: 10.0), - indicatorPadding: EdgeInsets.symmetric(horizontal: 15.0, vertical: 5.0), - ), - ), - ]), + overlayColor: WidgetStateProperty.all(Colors.transparent), + unselectedLabelColor: Colors.black87, + labelColor: Color(0xFFFF5000), + indicator: UnderlineTabIndicator( + borderRadius: BorderRadius.circular(10.0), + borderSide: BorderSide(color: Color(0xFFFF5000), width: 2.0), + ), + indicatorSize: TabBarIndicatorSize.label, + unselectedLabelStyle: TextStyle(fontSize: 16.0, fontFamily: 'Microsoft YaHei'), + labelStyle: TextStyle(fontSize: 16.0, fontFamily: 'Microsoft YaHei', fontWeight: FontWeight.w700), + dividerHeight: 0, + ), + ), ), ), body: TabBarView( @@ -456,20 +638,28 @@ class _SellerState extends State with SingleTickerProviderStateMixin { behavior: CustomScrollBehavior().copyWith(scrollbars: false), child: Container( color: Colors.grey[50], - child: pageOrderList.isEmpty && !isRefreshing - ? emptyTip() - : ListView.builder( - controller: scrollController, - physics: AlwaysScrollableScrollPhysics(), - padding: EdgeInsets.all(10.0), - itemCount: pageOrderList.length + (isLoadingMore ? 1 : 0), - itemBuilder: (context, index) { - if (index == pageOrderList.length) { - return _buildLoadMoreIndicator(); - } - return _buildOrderItem(pageOrderList[index]); - }, - ), + child: Builder( + builder: (context) { + final currentOrders = _getOrderListByIndex(index); + final isLoading = _isLoading[index] ?? false; + final hasMoreData = _hasMoreData[index] ?? false; + + return currentOrders.isEmpty && !isRefreshing + ? emptyTip() + : ListView.builder( + controller: scrollController, + physics: AlwaysScrollableScrollPhysics(), + padding: EdgeInsets.all(10.0), + itemCount: currentOrders.length + (hasMoreData ? 1 : 0), + itemBuilder: (context, itemIndex) { + if (itemIndex == currentOrders.length) { + return _buildLoadMoreIndicator(isLoading); + } + return _buildOrderItem(currentOrders[itemIndex]); + }, + ); + } + ), ), ), ); @@ -478,12 +668,27 @@ class _SellerState extends State with SingleTickerProviderStateMixin { ); } + // 根据索引获取订单列表 + List> _getOrderListByIndex(int index) { + switch (index) { + case 0: return _allOrders; + case 1: return _pendingPaymentOrders; + case 2: return _pendingVerificationOrders; + case 3: return _completedOrders; + case 4: return _closedOrders; + case 5: return _refundingOrders; + case 6: return _refundedOrders; + case 7: return _cancelledOrders; + default: return _allOrders; + } + } + // 加载更多指示器 - Widget _buildLoadMoreIndicator() { + Widget _buildLoadMoreIndicator(bool isLoading) { return Padding( padding: EdgeInsets.symmetric(vertical: 15.0), child: Center( - child: isLoadingMore + child: isLoading ? Row( mainAxisAlignment: MainAxisAlignment.center, children: [ @@ -503,7 +708,7 @@ class _SellerState extends State with SingleTickerProviderStateMixin { Widget emptyTip() { return Container( - width: double.infinity, // 覆盖整个页面宽度 + width: double.infinity, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [