flutter/lib/pages/order/detail.dart
cuiyouliang be7a137b07 1、订单修改
2、增加好友视频
2025-09-05 10:55:38 +08:00

630 lines
21 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

library;
import 'dart:async';
import 'dart:convert';
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 'package:loopin/utils/index.dart';
import '../../behavior/custom_scroll_behavior.dart';
import '../../utils/lifecycle_handler.dart';
class OrderDetail extends StatefulWidget {
const OrderDetail({super.key});
@override
State<OrderDetail> createState() => _OrderDetailState();
}
class _OrderDetailState extends State<OrderDetail> with SingleTickerProviderStateMixin {
late String _orderId;
dynamic orderGoodsInfo;
int _initialSeconds = 30 * 60;// 存储初始秒数
bool _countdownFinished = false; // 新增标志位,用于跟踪倒计时是否结束
@override
void initState() {
super.initState();
_orderId = Get.arguments;
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}');
}
}
// 获取订单详情信息,包含商品参数
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();
}
}
// 取消订单
void _cancelOrder() async {
print('取消订单: $_orderId');
try {
final res = await Http.post('${ShopApi.cancelGoodsOrder}/$_orderId');
print('取消订单成功-------------->${res}');
getOrderDetail(orderId: _orderId); // 刷新订单详情数据
} catch (e) {
print('取消订单失败-------------->${e}');
}
}
// 显示支付结果弹框
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();
// getOrderDetail(orderId: _orderId);
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('支付完成'),
),
),
],
),
],
),
),
);
},
).then((value) {
});
}
// 获取订单状态文本
String getOrderStatusText(int status) {
switch (status) {
case 0:
return '待支付';
case 1:
return '支付中';
case 2:
return '已支付';
case 3:
return '已取消';
case 4:
return '已退款';
case 10:
return '无效订单';
default:
return '未知状态';
}
}
// 获取订单状态颜色
Color getOrderStatusColor(int status) {
switch (status) {
case 0:
return Colors.orange;
case 1:
return Colors.blue;
case 2:
return Colors.green;
case 3:
case 4:
case 10:
return Colors.grey;
default:
return Colors.black;
}
}
// 构建底部按钮
Widget buildBottomButtons() {
if (orderGoodsInfo == null) return SizedBox.shrink();
int orderStatus = orderGoodsInfo?['orderStatus'] ?? 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),
),
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: [
ElevatedButton(
onPressed: () {
// 刷新订单状态
getOrderDetail(orderId: _orderId);
},
style: ButtonStyle(
backgroundColor: WidgetStateProperty.all(Colors.blue),
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(Color(0xFFFF5000)),
foregroundColor: WidgetStateProperty.all(Colors.white),
),
child: const Text('已支付'),
),
],
);
case 3: // 已取消
case 10: // 无效订单
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 4: // 已退款
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('已退款'),
),
],
);
default:
return SizedBox.shrink();
}
}
Widget emptyTip() {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 5.0,
children: [
Image.asset(
'assets/images/empty.png',
width: 100.0,
),
Text(
'还没有订单信息~',
style: TextStyle(color: Colors.grey, fontSize: 12.0),
)
],
);
}
@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(
backgroundColor: Color(0xFFFF5000),
foregroundColor: Colors.white,
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')}";
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,
),
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),
),
],
),
],
),
)
],
),
],
),
),
// 订单信息
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,
),
onTap: ()async {
await Clipboard.setData(ClipboardData(text: _orderId));
MyDialog.toast('订单已复制到剪切板', icon: Icon(Icons.check_circle));
},
)
],
),
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: 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(),
),
),
);
}
}