flutter/lib/pages/my/merchant/income.dart

465 lines
14 KiB
Dart

import 'package:flutter/material.dart';
import 'package:loopin/api/shop_api.dart';
import 'package:loopin/service/http.dart';
import '../../../behavior/custom_scroll_behavior.dart';
class SellerRevenue extends StatefulWidget {
const SellerRevenue({super.key});
@override
State<SellerRevenue> createState() => _SellerRevenueState();
}
class _SellerRevenueState extends State<SellerRevenue> {
// 分页内容
int pageNum = 1;
final int pageSize = 10;
bool isLoadingMore = false;
bool isRefreshing = false;
List<Map<String, dynamic>> revenueList = [];
int totalRecords = 0; // 添加总记录数
// 营收统计数据
double totalRevenue = 1000.00;
double pendingCount = 17;
double settledCount = 30;
late ScrollController scrollController = ScrollController();
@override
void initState() {
super.initState();
// 监听滚动事件
scrollController.addListener(_scrollListener);
// 获取营收摘要
getRevenueInfo();
// 获取初始流水列表
getRevenueList(false);
}
@override
void dispose() {
scrollController.removeListener(_scrollListener);
scrollController.dispose();
super.dispose();
}
// 滚动监听
void _scrollListener() {
if (scrollController.position.pixels >=
scrollController.position.maxScrollExtent - 50 && // 添加一个阈值,提前加载
!isLoadingMore &&
!isRefreshing &&
revenueList.isNotEmpty &&
revenueList.length < totalRecords) { // 确保有数据且未加载完所有数据时才加载更多
getRevenueList(true);
}
}
// 获取营收摘要
void getRevenueInfo() async {
try {
final res = await Http.post(ShopApi.revenueList, data: {});
if (res['code'] == 200 && res['data'] != null) {
final data = res['data'];
totalRevenue = data['moneyIn'] ?? 0.00;
pendingCount = data['credited']?? 0.00;
settledCount = data['pending'] ?? 0.00;
}
} catch (e) {
print('获取营收摘要: $e');
}
}
// 获取流水列表
void getRevenueList(bool loadMore) async {
if (isLoadingMore || isRefreshing) return;
setState(() {
if (!loadMore) {
pageNum = 1; // 重置为第一页
isRefreshing = true;
revenueList = [];
totalRecords = 0; // 重置总记录数
} else {
isLoadingMore = true;
}
});
try {
final res = await Http.post(ShopApi.revenueList, data: {
'current': pageNum, // 当前页码
'size': pageSize,
});
if (res['code'] == 200 && res['data'] != null) {
final data = res['data'];
final List<Map<String, dynamic>> newRevenues = List<Map<String, dynamic>>.from(data['records'] ?? []);
final int total = data['total'];
debugPrint(data.toString(), wrapWidth: 1024);
setState(() {
if (loadMore) {
revenueList.addAll(newRevenues);
} else {
revenueList = newRevenues;
}
totalRecords = total;
if (newRevenues.isNotEmpty && revenueList.length < total) {
pageNum++; // 增加页码
isLoadingMore = false; // 重置加载状态,允许再次加载
} else {
isLoadingMore = false; // 没有更多数据
}
isRefreshing = false;
});
}
} catch (e) {
print('获取营收列表失败: $e');
setState(() {
isLoadingMore = false;
isRefreshing = false;
});
}
}
// 刷新数据时重置分页状态
void _refreshData() {
setState(() {
pageNum = 1;
isLoadingMore = false;
totalRecords = 0;
});
getRevenueList(false);
}
// 构建营收项
Widget _buildRevenueItem(Map<String, dynamic> revenue) {
return Container(
margin: EdgeInsets.only(bottom: 10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
// 第一列:用户
Expanded(
flex: 1,
child: Text(
revenue['changeDesc']??'未知',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Colors.black,
),
overflow: TextOverflow.ellipsis,
),
),
// 第二列:流水明细
Expanded(
flex: 1,
child: Text(
'${revenue['changeType'] == '1' ? '+' : '-'}${revenue['changeAmount']}',
style: TextStyle(
fontSize: 14,
color: revenue['changeType'] == '1' ? Colors.red : Colors.green,
),
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.center,
),
),
// 第三列:流水日期
Expanded(
flex: 1,
child: Text(
revenue['createTime'] ?? '日期',
style: TextStyle(
fontSize: 12,
color: Colors.black,
),
textAlign: TextAlign.right,
),
),
],
),
);
}
// 构建顶部营收面板
Widget _buildRevenuePanel() {
return Container(
margin: EdgeInsets.symmetric(horizontal: 12.0),
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
color: Color(0xFF4477FC),
borderRadius: BorderRadius.circular(6),
boxShadow: [
BoxShadow(
color: Colors.black.withAlpha(15),
blurRadius: 10,
offset: Offset(0, 2),
),
],
),
child: Column(
children: [
// 总入账
Text(
'总入账',
style: TextStyle(
fontSize: 14,
color: Colors.white,
),
),
SizedBox(height: 8),
Text(
'¥$totalRevenue',
style: TextStyle(
fontSize: 28,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
SizedBox(height: 20),
// 待入账和已入账
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Column(
children: [
Text(
'待入账',
style: TextStyle(
fontSize: 14,
color: Colors.white,
),
),
SizedBox(height: 4),
Text(
'$pendingCount',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
],
),
Container(
width: 1,
height: 30,
color: Colors.white,
),
Column(
children: [
Text(
'已入账',
style: TextStyle(
fontSize: 14,
color: Colors.white,
),
),
SizedBox(height: 4),
Text(
'$settledCount',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
],
),
],
),
],
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor:Color(0xFFF8F8F8),
body: Stack(
children: [
// 背景图片 - 从顶部开始
Positioned.fill(
child: Image.asset(
'assets/images/income_bg.png',
fit: BoxFit.contain,
alignment: Alignment.topCenter,
),
),
// 主要内容区域
Column(
children: [
// AppBar区域
Container(
height: kToolbarHeight + MediaQuery.of(context).padding.top,
child: AppBar(
title: Text(
'商家营收',
style: TextStyle(
fontSize: 18,
color: Colors.white,
),
),
centerTitle: true,
backgroundColor: Colors.transparent,
elevation: 0,
iconTheme: IconThemeData(color: Colors.white),
),
),
// 营收面板
SizedBox(height: 10),
_buildRevenuePanel(),
SizedBox(height: 10),
// 流水明细
Expanded(
child: Container(
color: Colors.white,
margin: EdgeInsets.symmetric(horizontal: 12.0),
child: Column(
children: [
// 流水明细标题
Container(
padding: EdgeInsets.only(
left: 12.0,
right: 12.0,
top: 10.0,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
flex: 1,
child: Text(
'来源',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
),
Expanded(
flex: 1,
child: Text(
'流水明细',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.black,
),
textAlign: TextAlign.center,
),
),
Expanded(
flex: 1,
child: Text(
'流水日期',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.black,
),
textAlign: TextAlign.right,
),
),
],
),
),
SizedBox(height: 10),
// 流水列表区域
Expanded(
child: Container(
margin: EdgeInsets.symmetric(horizontal: 12.0),
child: RefreshIndicator(
onRefresh: () async {
_refreshData();
},
child: ScrollConfiguration(
behavior: CustomScrollBehavior().copyWith(scrollbars: false),
child: revenueList.isEmpty && !isRefreshing
? emptyTip()
: Container(
child: ListView.builder(
padding: EdgeInsets.zero,
controller: scrollController,
physics: AlwaysScrollableScrollPhysics(),
itemCount: revenueList.length + (isLoadingMore ? 1 : 0),
itemBuilder: (context, index) {
if (index == revenueList.length) {
return _buildLoadMoreIndicator();
}
return _buildRevenueItem(revenueList[index]);
},
),
),
),
),
),
),
],
),
),
),
],
),
],
),
);
}
// 加载更多指示器
Widget _buildLoadMoreIndicator() {
return Padding(
padding: EdgeInsets.symmetric(vertical: 15.0),
child: Center(
child: isLoadingMore
? Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(strokeWidth: 2),
),
SizedBox(width: 10),
Text('加载中...', style: TextStyle(color: Colors.grey)),
],
)
: revenueList.length >= totalRecords
? Text('没有更多数据了', style: TextStyle(color: Colors.grey))
: SizedBox(), // 如果还有数据但不在加载中,不显示任何内容
),
);
}
Widget emptyTip() {
return Container(
width: double.infinity,
padding: EdgeInsets.all(12.0),
color: Colors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
'assets/images/empty.png',
width: 100.0,
errorBuilder: (context, error, stackTrace) {
return Icon(Icons.receipt_long, size: 60, color: Colors.grey);
},
),
SizedBox(height: 10),
Text(
'还没有营收记录~',
style: TextStyle(color: Colors.grey, fontSize: 12.0),
)
],
),
);
}
}