| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296 |
- import 'package:flutter/material.dart';
- import 'package:flutter_riverpod/flutter_riverpod.dart';
- import 'package:go_router/go_router.dart';
- import '../../../core/l10n/app_localizations.dart';
- import '../../../core/theme/app_colors.dart';
- import '../../../core/utils/number_format.dart';
- import '../../../data/models/asset/withdraw_record.dart';
- import '../../../providers/withdraw_provider.dart';
- import '../../widgets/common/app_refresh_indicator.dart';
- class WithdrawHistoryScreen extends ConsumerStatefulWidget {
- const WithdrawHistoryScreen({super.key});
- @override
- ConsumerState<WithdrawHistoryScreen> createState() =>
- _WithdrawHistoryScreenState();
- }
- class _WithdrawHistoryScreenState
- extends ConsumerState<WithdrawHistoryScreen> {
- @override
- void initState() {
- super.initState();
- Future.microtask(() {
- ref.read(withdrawHistoryProvider.notifier).refresh();
- });
- }
- @override
- Widget build(BuildContext context) {
- final state = ref.watch(withdrawHistoryProvider);
- final notifier = ref.read(withdrawHistoryProvider.notifier);
- final isDark = Theme.of(context).brightness == Brightness.dark;
- return Scaffold(
- // 原型:灰色页面背景,item 白色卡片浮于上
- backgroundColor:
- isDark ? AppColors.darkBg : AppColors.lightBgSecondary,
- appBar: AppBar(
- backgroundColor:
- isDark ? AppColors.darkBg : AppColors.lightBg,
- leading: IconButton(
- icon: const Icon(Icons.chevron_left, size: 28),
- onPressed: () => context.pop(),
- ),
- title: Text(AppLocalizations.of(context)!.withdrawRecord,
- style: const TextStyle(fontSize: 17, fontWeight: FontWeight.w600)),
- centerTitle: true,
- ),
- body: _buildBody(context, state, notifier),
- );
- }
- Widget _buildBody(BuildContext context, WithdrawHistoryState state,
- WithdrawHistoryNotifier notifier) {
- final cs = Theme.of(context).colorScheme;
- if (state.isLoading && state.records.isEmpty) {
- return const Center(child: CircularProgressIndicator());
- }
- if (state.errorMessage != null && state.records.isEmpty) {
- return AppRefreshIndicator(
- onRefresh: notifier.refresh,
- child: SingleChildScrollView(
- physics: const AlwaysScrollableScrollPhysics(),
- child: Center(
- child: Column(
- mainAxisSize: MainAxisSize.min,
- children: [
- const SizedBox(height: 120),
- Text(state.errorMessage!,
- style: TextStyle(
- color: cs.onSurface.withAlpha(153), fontSize: 14)),
- const SizedBox(height: 16),
- ElevatedButton(
- onPressed: notifier.refresh, child: Text(AppLocalizations.of(context)!.retry)),
- ],
- ),
- ),
- ),
- );
- }
- if (state.records.isEmpty) {
- return AppRefreshIndicator(
- onRefresh: notifier.refresh,
- child: SingleChildScrollView(
- physics: const AlwaysScrollableScrollPhysics(),
- child: Center(
- child: Padding(
- padding: const EdgeInsets.symmetric(vertical: 120),
- child: Text(AppLocalizations.of(context)!.noRecord,
- style: TextStyle(
- color: cs.onSurface.withAlpha(120), fontSize: 14)),
- ),
- ),
- ),
- );
- }
- return AppRefreshIndicator(
- onRefresh: notifier.refresh,
- child: NotificationListener<ScrollNotification>(
- onNotification: (n) {
- if (n is ScrollEndNotification &&
- n.metrics.pixels >= n.metrics.maxScrollExtent - 100) {
- notifier.loadMore();
- }
- return false;
- },
- child: ListView.builder(
- padding: const EdgeInsets.fromLTRB(16, 12, 16, 32),
- itemCount: state.records.length + (state.hasMore ? 1 : 0),
- itemBuilder: (_, i) {
- if (i >= state.records.length) {
- return const Padding(
- padding: EdgeInsets.symmetric(vertical: 16),
- child: Center(
- child: CircularProgressIndicator(strokeWidth: 2)),
- );
- }
- final record = state.records[i];
- return _RecordItem(
- record: record,
- onCancel: record.canCancel
- ? () => notifier.cancelWithdraw(record.id)
- : null,
- );
- },
- ),
- ),
- );
- }
- }
- // ── 提币记录条目(对齐原型 record-item)────────────────────────────
- class _RecordItem extends StatelessWidget {
- const _RecordItem({
- required this.record,
- this.onCancel,
- });
- final WithdrawRecord record;
- final VoidCallback? onCancel;
- String _localizedStatus(AppLocalizations l10n) {
- switch (record.status) {
- case '0': return l10n.withdrawStatusReviewing;
- case '1': return l10n.withdrawStatusReleasing;
- case '2': return l10n.withdrawStatusFailed;
- case '3': return l10n.withdrawStatusSuccess;
- case '4': return l10n.withdrawStatusCancelled;
- default: return l10n.unknown;
- }
- }
- @override
- Widget build(BuildContext context) {
- final cs = Theme.of(context).colorScheme;
- final isDark = Theme.of(context).brightness == Brightness.dark;
- final isTransfer = record.isTransfer;
- final baseCoin = record.coin?.baseCoinDisplay.isNotEmpty == true
- ? record.coin!.baseCoinDisplay
- : (record.coin?.coinName.isNotEmpty == true
- ? record.coin!.coinName
- : 'USDT');
- final coinUnit = baseCoin;
- final l10n = AppLocalizations.of(context)!;
- final direction = isTransfer ? '$baseCoin ${l10n.internalTransfer}' : '$baseCoin ${l10n.onChainWithdraw}';
- final network = isTransfer ? l10n.internalLabel : (record.coin?.networkName ?? '');
- // 内部转账用 transferAmount(JSON: amount),链上提币用 amount(JSON: totalAmount)
- final rawAmount = isTransfer ? record.transferAmount : record.amount;
- final amountDouble = double.tryParse(rawAmount) ?? 0;
- final amountStr = formatAmount(amountDouble);
- Color statusColor;
- switch (record.status) {
- case '3':
- statusColor = AppColors.rise;
- break;
- case '2':
- statusColor = AppColors.fall;
- break;
- case '4':
- statusColor = cs.onSurface.withAlpha(120);
- break;
- default:
- statusColor = AppColors.warning;
- }
- return GestureDetector(
- behavior: HitTestBehavior.opaque,
- onTap: () => context.push(
- '/asset/withdraw/detail?isTransfer=$isTransfer',
- extra: record,
- ),
- child: Container(
- margin: const EdgeInsets.only(bottom: 10),
- decoration: BoxDecoration(
- color: isDark ? AppColors.darkBgSecondary : AppColors.lightBg,
- borderRadius: BorderRadius.circular(12),
- boxShadow: isDark
- ? null
- : [
- BoxShadow(
- color: Colors.black.withAlpha(13),
- blurRadius: 2,
- offset: const Offset(0, 1),
- )
- ],
- ),
- padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- // ── 上行:方向 + 金额 ──────────────────────────────
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- Text(
- direction,
- style: TextStyle(
- color: cs.onSurface,
- fontSize: 12,
- fontWeight: FontWeight.w600,
- ),
- ),
- Text(
- '-$amountStr $coinUnit',
- style: TextStyle(
- color: cs.onSurface,
- fontSize: 14,
- fontWeight: FontWeight.w700,
- ),
- ),
- ],
- ),
- const SizedBox(height: 6),
- // ── 下行:时间(左)+ 网络(居中)+ 状态(右)────────────
- Row(
- children: [
- Expanded(
- child: Text(
- record.createTime,
- style: TextStyle(
- color: cs.onSurface.withAlpha(100), fontSize: 10),
- ),
- ),
- if (network.isNotEmpty)
- Text(
- network,
- style: TextStyle(
- color: cs.onSurface.withAlpha(100), fontSize: 10),
- ),
- Expanded(
- child: Row(
- mainAxisAlignment: MainAxisAlignment.end,
- children: [
- Text(
- _localizedStatus(l10n),
- style: TextStyle(
- color: statusColor,
- fontSize: 10,
- fontWeight: FontWeight.w500,
- ),
- ),
- if (onCancel != null) ...[
- const SizedBox(width: 10),
- GestureDetector(
- onTap: onCancel,
- child: Text(
- AppLocalizations.of(context)!.cancel,
- style: TextStyle(
- color: AppColors.brand,
- fontSize: 10,
- fontWeight: FontWeight.w500,
- ),
- ),
- ),
- ],
- ],
- ),
- ),
- ],
- ),
- ],
- ),
- ),
- );
- }
- }
|