Files
2026-09-15 15:44:13 +07:00

99 lines
3.9 KiB
Dart

import 'package:dio/dio.dart';
import 'package:hgdj/tools_base/net/base_resp_bean.dart';
import 'package:hgdj/tools_base/net/http_manager.dart';
import 'package:uuid/uuid.dart';
/// 购买相关接口
class BuyService {
/// /product/buy 一律带 X-Request-ID。
/// [requestId] 由调用方持有时才是幂等键:一笔业务被拆成多次请求时(如短剧「充值成功后
/// 自动补一次解锁」)复用同一个 id,服务端直接回首次结果,不会重复扣费。
/// 不传就现生成一个,只作服务端链路追踪用——连点下单由 PayManager 的全屏 loading 挡着
static Options _idempotent(String? requestId) => Options(
headers: {'X-Request-ID': requestId ?? const Uuid().v4()},
);
///购买视频 [productType] 见 PayManager 的 ProductType
///[contentID] 子内容ID(短剧买单集时传这一集的 id,productID 仍是剧 id)
///[checkoutContextId] 付费墙下发的结算上下文,服务端据此对账/归因
///[requestId] 幂等键,见 [_idempotent];不传则自动生成一个仅供追踪的 id
///[jsonTransformation] 需要把返回体解析成模型时传,不传则 data 为原始 json
static Future<BaseRespBean> buyVideo(
String? productID,
int? productType, {
String? couponId, // 优惠卷ID
int? goldVideoCouponNum, //金币视频抵用券金币面值,
String? serviceId, // 裸聊服务ID
String? source, // 来源页面标识
String? contentID,
String? checkoutContextId,
String? requestId,
Function(Map<String, dynamic> json)? jsonTransformation,
}) async {
final param = <String, dynamic>{
'productID': productID,
'productType': productType,
'contentID': contentID,
'checkoutContextId': checkoutContextId,
'couponId': couponId,
'goldVideoCouponNum': goldVideoCouponNum,
'serviceId': serviceId,
'source': source,
'isH5': false,
};
param.removeWhere((k, v) => v == null);
return httpManager.fetchResponseByPOST(
'/product/buy',
param: param,
options: _idempotent(requestId),
jsonTransformation: jsonTransformation,
);
}
///金币购买vip
///[finalPayStatus]: 预售业务,true 付尾款, false 付预定款;null 非预售业务;
///[couponId] 金币加赠券券id
///[source] 来源页面标识
///[experimentId]/[experimentVariant]/[sessionId] VIP 卡皮 A/B:与 /mine/topay 对齐回传
///[requestId] 幂等键,见 [_idempotent]
static Future<BaseRespBean> buyVip(int? productType, String? productID,
String? productName, int? discountedPrice,
{String? couponId = "",
bool? finalPayStatus,
String? source,
String? experimentId,
String? experimentVariant,
String? sessionId,
String? mediaId,
String? contentId,
String? checkoutContextId,
String? requestId}) async {
final param = <String, dynamic>{
'productType': productType,
'productID': productID,
'productName': productName,
'discountedPrice': discountedPrice,
'couponId': couponId,
'finalPayStatus': finalPayStatus,
'source': source,
// 短剧付费墙开卡归因,字段名与 /mine/topay 那套对齐
'mediaId': mediaId,
'contentId': contentId,
'checkoutContextId': checkoutContextId,
// 空值不传,避免参数错误(DISABLED / 无实验时上游不填)
'experimentId': (experimentId != null && experimentId.isNotEmpty)
? experimentId
: null,
'experimentVariant':
(experimentVariant != null && experimentVariant.isNotEmpty)
? experimentVariant
: null,
'sessionId':
(sessionId != null && sessionId.isNotEmpty) ? sessionId : null,
};
param.removeWhere((k, v) => v == null);
return httpManager.fetchResponseByPOST('/product/buy',
param: param, options: _idempotent(requestId));
}
}