ar_tourism_flutter_unity/lib/pages/mine/history.dart
2025-05-14 17:04:13 +08:00

503 lines
15 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.

import 'package:flutter/material.dart';
import '../../components/appbar.dart';
import '../../apis/app.dart';
import '../../components/emptyState.dart';
class GradientUnderlineTabIndicator extends Decoration {
final double borderSide;
final EdgeInsetsGeometry insets;
final List<Color> gradientColors;
const GradientUnderlineTabIndicator({
this.borderSide = 3.0,
this.insets = const EdgeInsets.symmetric(horizontal: 10.0),
this.gradientColors = const [Color(0xFF80DAA4), Color(0xFF79DDED)],
});
@override
BoxPainter createBoxPainter([VoidCallback? onChanged]) {
return _GradientUnderlinePainter(
borderSide: borderSide,
insets: insets,
gradientColors: gradientColors,
);
}
}
class _GradientUnderlinePainter extends BoxPainter {
final double borderSide;
final EdgeInsetsGeometry insets;
final List<Color> gradientColors;
_GradientUnderlinePainter({
required this.borderSide,
required this.insets,
required this.gradientColors,
});
@override
void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) {
final Rect rect = offset & configuration.size!;
final TextDirection textDirection = configuration.textDirection!;
final Rect indicator = insets.resolve(textDirection).deflateRect(rect);
final Paint paint = Paint()
..shader = LinearGradient(
colors: gradientColors,
begin: Alignment.centerLeft,
end: Alignment.centerRight,
).createShader(Rect.fromLTWH(
indicator.left,
indicator.bottom - borderSide,
indicator.width,
borderSide,
))
..style = PaintingStyle.fill;
canvas.drawRect(
Rect.fromLTWH(
indicator.left,
indicator.bottom - borderSide,
indicator.width,
borderSide,
),
paint,
);
}
}
// 订单信息模型
class OrderInfo {
final int id;
final String orderInfoId;
final int orderId;
final String workName;
final String workStatus;
final String city;
final String scenic;
final String source;
final String status;
final String workAddress; // 添加workAddress字段
OrderInfo({
required this.id,
required this.orderInfoId,
required this.orderId,
required this.workName,
required this.workStatus,
required this.city,
required this.scenic,
required this.source,
required this.status,
required this.workAddress, // 添加到构造函数
});
factory OrderInfo.fromJson(Map<String, dynamic> json) {
return OrderInfo(
id: json['id'] ?? 0,
orderInfoId: json['orderInfoId'] ?? '',
orderId: json['orderId'] ?? 0,
workName: json['workName'] ?? '',
workStatus: json['workStatus']?.toString() ?? '',
city: json['city'] ?? '',
scenic: json['scenic'] ?? '',
source: json['source'] ?? '',
status: json['status']?.toString() ?? '',
workAddress: json['workAddress'] ?? '', // 从JSON中解析workAddress
);
}
}
// 订单模型
class Order {
final int orderId;
final String createTime;
final String startTime;
final String endTime;
final double money;
final String status;
final List<OrderInfo> orderInfoList;
final String? remainTimeString; // 添加剩余时间字段
Order({
required this.orderId,
required this.createTime,
required this.startTime,
required this.endTime,
required this.money,
required this.status,
required this.orderInfoList,
this.remainTimeString, // 可空字段
});
factory Order.fromJson(Map<String, dynamic> json) {
return Order(
orderId: json['orderId'] ?? 0,
createTime: json['createTime'] ?? '',
startTime: json['startTime'] ?? '',
endTime: json['endTime'] ?? '',
money: (json['money'] ?? 0).toDouble(),
status: json['status']?.toString() ?? '',
orderInfoList: (json['orderInfoList'] as List?)
?.map((e) => OrderInfo.fromJson(e))
.toList() ?? [],
remainTimeString: json['remainTimeString'], // 从JSON中解析剩余时间
);
}
}
class HistoryPage extends StatefulWidget {
const HistoryPage({super.key});
@override
State<HistoryPage> createState() => _HistoryPageState();
}
class _HistoryPageState extends State<HistoryPage>
with SingleTickerProviderStateMixin {
late TabController _tabController;
List<Order> _data = [];
bool _isLoading = false;
@override
void initState() {
super.initState();
_tabController = TabController(length: 4, vsync: this);
_loadOrders();
}
Future<void> _loadOrders() async {
setState(() {
_isLoading = true;
});
try {
final result = await userApi.getOrder();
print("历史订单列表result:$result");
if (result['code'] == 200) {
setState(() {
_data = (result['rows'] as List)
.map((item) => Order.fromJson(item))
.toList();
});
} else {
// 处理错误情况
debugPrint("获取订单失败: ${result['msg']}");
}
} catch (e) {
debugPrint("获取订单异常: $e");
} finally {
setState(() {
_isLoading = false;
});
}
}
@override
void dispose() {
_tabController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: const CustomAppBar(title: '历史订单'),
body: Container(
decoration: const BoxDecoration(color: Color(0xff0C0C16)),
child: Column(
children: [
_buildTabBar(),
Expanded(
child: TabBarView(
controller: _tabController,
children: [
_buildOrderList(null),
_buildOrderList('3'), // 展示中
_buildOrderList('0'), // 未展示
_buildOrderList('2'), // 已停止
],
),
),
],
),
),
);
}
Widget _buildTabBar() {
return Container(
color: const Color(0xFF1F212E),
child: TabBar(
controller: _tabController,
tabs: const [
Tab(text: '全部'),
Tab(text: '展示中'),
Tab(text: '未展示'),
Tab(text: '已停止'),
],
indicator: const GradientUnderlineTabIndicator(
borderSide: 3.0,
insets: EdgeInsets.symmetric(horizontal: 10.0),
gradientColors: [Color(0xFF80DAA4), Color(0xFF79DDED)],
),
labelColor: Colors.white,
unselectedLabelColor: Colors.grey,
),
);
}
Widget _buildOrderList(String? status) {
if (_isLoading) {
return const Center(child: CircularProgressIndicator());
}
final filteredOrders = status == null
? _data
: _data.where((order) => order.status == status).toList();
if (filteredOrders.isEmpty) {
return const EmptyState(message: '暂无订单数据');
}
return RefreshIndicator(
onRefresh: _loadOrders,
child: ListView.builder(
itemCount: filteredOrders.length,
itemBuilder: (context, index) {
final order = filteredOrders[index];
return _buildOrderCard(order);
},
),
);
}
Widget _buildOrderCard(Order order) {
if (order.orderInfoList.isEmpty) return const SizedBox();
return GestureDetector(
onTap: () {
// 添加详细的日志打印
print('准备传递的订单数据:');
print('orderId: ${order.orderId}');
print("订单状态(status): ${order.status} (${_getStatusText(order.status)})");
print('orderInfoId: ${order.orderInfoList[0].orderInfoId}');
print('createTime: ${order.createTime}');
print('money: ${order.money}');
print('order: ${order}');
print('orderInfoList长度: ${order.orderInfoList.length}');
print('order.remainTimeString: ${order.remainTimeString}');
Navigator.pushNamed(context, '/historyDetail', arguments: order);
},
child: Container(
margin: const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: const Color(0xFF1F212E),
borderRadius: BorderRadius.circular(8),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 订单头部信息(只显示一次)
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
_formatDateTime(order.createTime),
style: const TextStyle(
fontSize: 12,
color: Color(0xffC1C1C1),
),
),
Text(
_getStatusText(order.status),
style: TextStyle(
fontSize: 12,
color: _getStatusColor(order.status),
),
),
],
),
const SizedBox(height: 12),
// 循环展示 orderInfoList
ListView.separated(
shrinkWrap: true, // 重要使ListView适应内容高度
physics: const NeverScrollableScrollPhysics(), // 禁用滚动
itemCount: order.orderInfoList.length,
separatorBuilder: (context, index) => const Padding(
padding: EdgeInsets.symmetric(vertical: 8),
child: Divider(
color: Color(0xFF2A2C37),
height: 1,
),
),
itemBuilder: (context, index) {
final orderInfo = order.orderInfoList[index];
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// orderInfo.workAddress
ClipRRect(
borderRadius: BorderRadius.circular(4),
child: Image.network(
orderInfo.workAddress, // 使用workAddress作为图片URL
width: 60,
height: 83,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) {
return Container(
width: 60,
height: 83,
color: const Color(0xFF1F212E),
child: const Center(
child: Icon(
Icons.image_not_supported,
color: Colors.grey,
size: 24,
),
),
);
},
loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) return child;
return Container(
width: 60,
height: 83,
color: const Color(0xFF1F212E),
child: const Center(
child: CircularProgressIndicator(
strokeWidth: 2,
),
),
);
},
),
),
const SizedBox(width: 8),
Expanded(
child: SizedBox(
height: 83,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
orderInfo.workName,
style: const TextStyle(
fontSize: 14,
color: Colors.white,
),
),
Text(
_getWorkStatusText(orderInfo.workStatus),
style: TextStyle(
fontSize: 12,
color: _getWorkStatusColor(orderInfo.workStatus),
),
),
Text(
"展示时间:${_formatDateTime(order.startTime)}",
style: const TextStyle(
fontSize: 12,
color: Color(0xffC1C1C1),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"展示位置:${orderInfo.scenic}",
style: const TextStyle(
fontSize: 12,
color: Color(0xffC1C1C1),
),
),
// 只在最后一个项目显示总金额
if (index == order.orderInfoList.length - 1)
Text(
"${order.money / 1000}",
style: const TextStyle(
fontSize: 16,
color: Color(0xffF42845),
),
),
],
),
],
),
),
),
],
);
},
),
],
),
),
);
}
String _formatDateTime(String dateTimeStr) {
try {
final dateTime = DateTime.parse(dateTimeStr);
return "${dateTime.year}-${dateTime.month.toString().padLeft(2, '0')}-${dateTime.day.toString().padLeft(2, '0')} 12:00:00";
} catch (e) {
return "$dateTimeStr 12:00:00";
}
}
String _getStatusText(String status) {
switch (status) {
case '0':
return '未展示';
case '2':
return '已停止';
case '3':
return '展示中';
default:
return '';
}
}
Color _getStatusColor(String status) {
switch (status) {
case '3':
return const Color(0xff78E7A4);
case '2':
return const Color(0xffDE8D3D);
case '0':
return const Color(0xff79B7FF);
default:
return Colors.grey;
}
}
String _getWorkStatusText(String workStatus) {
switch (workStatus) {
case '3':
return '审核成功';
case '4':
return '审核失败';
default:
return '审核中';
}
}
Color _getWorkStatusColor(String workStatus) {
switch (workStatus) {
case '3': // 审核成功
return const Color(0xff78E7A4);
case '4': // 审核失败
return const Color(0xffF42845);
default: // 审核中
return const Color(0xff79B7FF);
}
}
}