feat(client): pay 支付领域模型 + PaymentApi + 支付流控制器(轮询 activated)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
This commit is contained in:
@@ -91,12 +91,14 @@ class ApiClient {
|
||||
Never _throwFromResponse(http.Response resp) {
|
||||
String zh = '操作失败 (HTTP ${resp.statusCode})';
|
||||
String en = 'Request failed (HTTP ${resp.statusCode})';
|
||||
String? code;
|
||||
try {
|
||||
final b = jsonDecode(resp.body) as Map<String, dynamic>;
|
||||
zh = b['message_zh'] as String? ?? zh;
|
||||
en = b['message_en'] as String? ?? en;
|
||||
code = b['code'] as String?;
|
||||
} catch (_) {}
|
||||
throw AuthApiException(statusCode: resp.statusCode, messageZh: zh, messageEn: en);
|
||||
throw AuthApiException(statusCode: resp.statusCode, messageZh: zh, messageEn: en, code: code);
|
||||
}
|
||||
|
||||
void dispose() => _client.close();
|
||||
|
||||
@@ -14,12 +14,16 @@ class AuthApiException implements Exception {
|
||||
required this.statusCode,
|
||||
required this.messageZh,
|
||||
required this.messageEn,
|
||||
this.code,
|
||||
});
|
||||
|
||||
final int statusCode;
|
||||
final String messageZh;
|
||||
final String messageEn;
|
||||
|
||||
/// 服务端 apierr 的机器码(如 CURRENCY_MISMATCH),旧调用点可空。
|
||||
final String? code;
|
||||
|
||||
@override
|
||||
String toString() => 'AuthApiException($statusCode): $messageZh';
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
// payment_api.dart — /v1/pay 代理端点封装(JWT 经 ApiClient 自动注入)。
|
||||
import '../models/payment.dart';
|
||||
import 'api_client.dart';
|
||||
|
||||
class PaymentApi {
|
||||
PaymentApi(this._c);
|
||||
final ApiClient _c;
|
||||
|
||||
Future<List<PayCatalogItem>> catalog() async {
|
||||
final body = await _c.getJson('/v1/pay/catalog');
|
||||
final items = (body['items'] as List<dynamic>?) ?? const [];
|
||||
return [for (final it in items) PayCatalogItem.fromJson(it as Map<String, dynamic>)];
|
||||
}
|
||||
|
||||
Future<PayOrder> createOrder({
|
||||
required String sku,
|
||||
required String method,
|
||||
Map<String, String>? metadata,
|
||||
}) async =>
|
||||
PayOrder.fromJson(await _c.postJson('/v1/pay/orders', {
|
||||
'sku': sku,
|
||||
'method': method,
|
||||
if (metadata != null && metadata.isNotEmpty) 'metadata': metadata,
|
||||
}));
|
||||
|
||||
Future<PayOrderStatus> orderStatus(String orderNo) async =>
|
||||
PayOrderStatus.fromJson(await _c.getJson('/v1/pay/orders/$orderNo'));
|
||||
|
||||
Future<PayOrder> retry(String orderNo, {required String method, Map<String, String>? metadata}) async =>
|
||||
PayOrder.fromJson(await _c.postJson('/v1/pay/orders/$orderNo/retry', {
|
||||
'method': method,
|
||||
if (metadata != null && metadata.isNotEmpty) 'metadata': metadata,
|
||||
}));
|
||||
|
||||
Future<void> cancel(String orderNo) async {
|
||||
await _c.postJson('/v1/pay/orders/$orderNo/cancel');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user