Files
video/app/lib/services/invite_service.dart
2026-10-15 20:36:59 +08:00

82 lines
3.1 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import '../core/network/api_client.dart';
import '../core/network/endpoints.dart';
/// 推广归因服务(三段式自建方案):
/// 1. 分享口令(剪贴板解析,准确率 100%)——主路径
/// 2. H5 中间页点击埋点 + 首启模糊匹配——辅助路径(本类 reportMatch)
/// 3. 注册页邀请码手填——兜底
class InviteService {
InviteService._();
/// 口令格式:#短视频邀请码XXXXXXXX#(邀请码 8 位大写字母数字,与服务端生成规则一致)
static final RegExp _commandRe = RegExp(r'#短视频邀请码([0-9A-Z]{8})#');
/// 从剪贴板文本解析邀请口令,未命中返回 null
static String? parseInviteCommand(String? text) {
if (text == null || text.isEmpty) return null;
return _commandRe.firstMatch(text)?.group(1);
}
/// 生成推广文案(邀请页"复制推广文案",口令包裹其中供被邀请人首启解析)
static String buildShareText({required String inviteCode, required String inviteUrl}) {
return '【短视频】精彩短视频刷不停,新人注册立送体验会员!\n'
'① 点击链接下载:$inviteUrl\n'
'② 或复制本段文字,打开 App 自动绑定我的邀请\n'
'#短视频邀请码$inviteCode#';
}
/// 首启模糊归因上报(无口令时的辅助路径);
/// 命中结果由服务端按 device_id 缓存,注册时自动带出;失败不阻塞启动
static Future<String?> reportMatch(String deviceId) async {
try {
final data = await ApiClient.post<Map<String, dynamic>>(
Endpoints.inviteMatch,
data: {'device_id': deviceId},
);
if (data['matched'] == true) return data['invite_code'] as String?;
} catch (_) {
// 归因失败不影响正常启动
}
return null;
}
/// 我的邀请(邀请码/推广链接/统计,对应《03-接口文档》9.1)
static Future<ReferralInfo> fetchMyReferral() async {
final data = await ApiClient.get<Map<String, dynamic>>(Endpoints.referralMe);
return ReferralInfo.fromJson(data);
}
}
/// 我的邀请信息
class ReferralInfo {
ReferralInfo({
required this.inviteCode,
required this.inviteUrl,
required this.eligible,
required this.totalInvitees,
required this.activatedCount,
required this.rewardPointsTotal,
required this.rebateAssetsTotal,
});
final String inviteCode;
final String inviteUrl;
/// 是否具备奖励资格(会员)
final bool eligible;
final int totalInvitees;
final int activatedCount;
final int rewardPointsTotal;
final double rebateAssetsTotal;
factory ReferralInfo.fromJson(Map<String, dynamic> json) => ReferralInfo(
inviteCode: (json['invite_code'] as String?) ?? '',
inviteUrl: (json['invite_url'] as String?) ?? '',
eligible: (json['eligible'] as bool?) ?? false,
totalInvitees: (json['total_invitees'] as num?)?.toInt() ?? 0,
activatedCount: (json['activated_count'] as num?)?.toInt() ?? 0,
rewardPointsTotal: (json['reward_points_total'] as num?)?.toInt() ?? 0,
rebateAssetsTotal: (json['rebate_assets_total'] as num?)?.toDouble() ?? 0,
);
}