Files
slogan/app/lib/features/member/member_provider.dart
T
admin b53c57e02d Add 'app/' from commit 'a11a66886941bba128d89c1124115e1b1c87a128'
git-subtree-dir: app
git-subtree-mainline: 6ebd902c6b
git-subtree-split: a11a668869
2026-08-04 14:59:55 +08:00

135 lines
4.1 KiB
Dart

import 'dart:convert';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../core/auth/auth_provider.dart';
/// 会员 provider:会员状态/套餐/下单/轮询/领奖
class MemberInfo {
final bool isVip;
final String expireAt;
final String planName;
final List<String> benefits;
const MemberInfo({
required this.isVip,
required this.expireAt,
required this.planName,
required this.benefits,
});
factory MemberInfo.fromJson(Map<String, dynamic> e) => MemberInfo(
isVip: e['is_vip'] as bool? ?? false,
expireAt: e['expire_at'] as String? ?? '',
planName: e['plan_name'] as String? ?? '',
benefits: (e['benefits'] as List<dynamic>? ?? []).cast<String>(),
);
}
/// 权益 key → 文案
const benefitLabels = {
'effect_unlimited': '无限效果图',
'ai_priority': '优先 AI 方案',
'cps_commission_x15': '返现加成 1.5x',
'store_discount': '门店折扣',
};
List<String> benefitTexts(MemberInfo m) =>
m.benefits.map((b) => benefitLabels[b] ?? b).toList();
class MemberNotifier extends AsyncNotifier<MemberInfo> {
@override
Future<MemberInfo> build() async {
final api = ref.read(apiClientProvider);
final data = await api.get<Map<String, dynamic>>('/member/status');
return MemberInfo.fromJson(data);
}
Future<void> refresh() async {
state = await AsyncValue.guard(build);
}
/// 领取广告激励(服务端限频);adType: effect_extra | vip_trial
/// 返回当日剩余次数;超出限频抛 ApiException
Future<int> claimReward(String adType) async {
final api = ref.read(apiClientProvider);
final data =
await api.post<Map<String, dynamic>>('/ad/reward/claim', {'ad_type': adType});
await refresh(); // vip_trial 可能开通体验会员
return (data['reward']?['remaining_today'] as num?)?.toInt() ?? 0;
}
}
final memberProvider =
AsyncNotifierProvider<MemberNotifier, MemberInfo>(MemberNotifier.new);
class MemberPlan {
final int id;
final String name;
final int priceFen;
final int durationDays;
final List<String> features;
const MemberPlan({
required this.id,
required this.name,
required this.priceFen,
required this.durationDays,
required this.features,
});
factory MemberPlan.fromJson(Map<String, dynamic> e) => MemberPlan(
id: (e['id'] as num).toInt(),
name: e['name'] as String? ?? '',
priceFen: (e['price_fen'] as num?)?.toInt() ?? 0,
durationDays: (e['duration_days'] as num?)?.toInt() ?? 30,
features: _parseFeatures(e['features'] as String? ?? ''),
);
static List<String> _parseFeatures(String s) {
try {
return (jsonDecode(s) as List<dynamic>).cast<String>();
} catch (_) {
return const [];
}
}
String get priceText =>
${(priceFen / 100).toStringAsFixed(priceFen % 100 == 0 ? 0 : 1)}';
}
final memberPlanProvider = FutureProvider<List<MemberPlan>>((ref) async {
final api = ref.read(apiClientProvider);
final data = await api.get<Map<String, dynamic>>('/member/plan/list');
final list = data['list'] as List<dynamic>? ?? [];
return list
.map((e) => MemberPlan.fromJson(e as Map<String, dynamic>))
.toList();
});
class OrderResult {
final String orderNo;
final String payUrl;
const OrderResult({required this.orderNo, required this.payUrl});
}
/// 创建支付订单(后端调虎皮棋下单,返回收银台 URL)
Future<OrderResult> createMemberOrder(WidgetRef ref, int planId) async {
final api = ref.read(apiClientProvider);
final data =
await api.post<Map<String, dynamic>>('/member/order/create', {'plan_id': planId});
return OrderResult(
orderNo: data['order_no'] as String? ?? '',
payUrl: data['pay_url'] as String? ?? '',
);
}
/// 订单状态(支付页 2s 轮询):pending | paid | closed
Future<String> fetchOrderStatus(WidgetRef ref, String orderNo) async {
final api = ref.read(apiClientProvider);
final data = await api.get<Map<String, dynamic>>('/member/order/status',
query: {'order_no': orderNo});
return data['status'] as String? ?? '';
}