已完成用户APP首期功能开发

交付用户端首期页面、配套接口、后台资源及测试文档。用户APP构建、静态分析和三个管理后台构建通过;完整测试仍有2项失败,后端模型注释检查未通过,详见交付记录。
This commit is contained in:
czl231
2026-09-13 00:57:32 +08:00
parent a0a4bb1218
commit 3ef33b531d
793 changed files with 40959 additions and 1204 deletions

View File

@@ -0,0 +1,74 @@
// 功能描述充值创建前持久化及到账恢复不将支付拉起视作到账版本1.0.0。
import '../repositories/client_repository.dart';
import '../../domain/models/recharge.dart';
import 'recharge_draft_store.dart';
import 'api_client.dart';
/// 单个页面使用一个实例;所有网络写入前确认存储所属账号。
class RechargeFlow {
RechargeFlow(this.repository, this.store);
final ClientRepository repository;
final RechargeDraftStore store;
bool _busy = false;
Future<Map<String, Object?>> create(PendingRecharge draft) async {
if (_busy) throw StateError('充值正在处理中');
_busy = true;
try {
final owner = await repository.rechargeDraftOwner();
final previous = await store.read(owner);
if (previous != null &&
(previous.request != draft.request ||
previous.amount != draft.amount ||
previous.channel != draft.channel ||
previous.payType != draft.payType)) {
throw StateError('请先查询待确认充值');
}
if (previous != null) {
// 重试先读取入账事实,避免到账后再次拉起原支付参数。
try {
final result = await repository.rechargeResult(previous.request);
if (result.amount != previous.amount || result.channel != previous.channel) {
throw StateError('充值结果与原请求不一致');
}
if (await repository.rechargeDraftOwner() != owner) throw StateError('充值账户已切换');
if (result.credited) return {'recharge_status': 23};
} on ApiException catch (error) {
// 明确不存在才允许使用相同请求重发,网络异常不能推断订单不存在。
if (error.code != 1112) rethrow;
}
}
await store.write(owner, draft);
if (await repository.rechargeDraftOwner() != owner) throw StateError('充值账户已切换');
return await repository.createRecharge(
request: draft.request,
amount: draft.amount,
channel: draft.channel,
payType: draft.payType,
);
} finally {
_busy = false;
}
}
/// 未到账、查询失败或业务关联异常均保留原请求,方便再次核对。
Future<RechargeRecord?> recover() async {
if (_busy) throw StateError('充值正在处理中');
_busy = true;
try {
final owner = await repository.rechargeDraftOwner();
final draft = await store.read(owner);
if (draft == null) return null;
if (await repository.rechargeDraftOwner() != owner) throw StateError('充值账户已切换');
final result = await repository.rechargeResult(draft.request);
if (result.amount != draft.amount || result.channel != draft.channel) {
throw StateError('充值结果与原请求不一致');
}
if (await repository.rechargeDraftOwner() != owner) throw StateError('充值账户已切换');
if (result.credited) await store.delete(owner);
return result;
} finally {
_busy = false;
}
}
}