初始化提交
This commit is contained in:
Executable
+506
@@ -0,0 +1,506 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:kaer_with_panels/app/services/api_service/kr_subscribe_api.dart';
|
||||
import 'package:kaer_with_panels/app/model/response/kr_package_list.dart';
|
||||
import 'package:kaer_with_panels/app/utils/kr_common_util.dart';
|
||||
import 'package:kaer_with_panels/app/localization/app_translations.dart';
|
||||
import 'package:kaer_with_panels/app/utils/kr_log_util.dart';
|
||||
|
||||
import '../../../common/app_run_data.dart';
|
||||
import '../../../model/response/kr_already_subscribe.dart';
|
||||
import '../../../model/response/kr_payment_methods.dart';
|
||||
import '../../../routes/app_pages.dart';
|
||||
import '../../../services/api_service/kr_api.user.dart';
|
||||
import '../../../utils/kr_event_bus.dart';
|
||||
|
||||
/// 会员购买控制器
|
||||
/// 负责处理会员套餐选择、支付方式选择和订阅流程
|
||||
class KRPurchaseMembershipController extends GetxController {
|
||||
// 注入的服务
|
||||
final KRSubscribeApi _kr_subscribeApi = KRSubscribeApi();
|
||||
|
||||
// 事件监听器
|
||||
Worker? _kr_eventWorker;
|
||||
|
||||
// UI 状态
|
||||
final RxBool kr_isLoading = false.obs;
|
||||
final RxString kr_errorMessage = ''.obs;
|
||||
final RxString kr_userEmail = ''.obs;
|
||||
final RxBool kr_showPlanSelector = false.obs; // 是否显示套餐选择器
|
||||
|
||||
// 数据状态
|
||||
final RxList<KRPackageListItem> kr_plans = <KRPackageListItem>[].obs;
|
||||
final RxList<KRPaymentMethod> kr_paymentMethods = <KRPaymentMethod>[].obs;
|
||||
final RxInt kr_selectedPlanIndex = 0.obs;
|
||||
final RxInt kr_selectedPaymentMethodIndex = (-1).obs;
|
||||
final RxInt kr_selectedDiscountIndex = (-1).obs;
|
||||
|
||||
// 已订阅套餐列表
|
||||
var _kr_alreadySubscribe = <KRAlreadySubscribe>[];
|
||||
|
||||
/// 描述是否展开
|
||||
final kr_isDescriptionExpanded = false.obs;
|
||||
|
||||
/// 当前余额
|
||||
var _kr_balance = 0;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
kr_initializeData();
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
_kr_eventWorker?.dispose();
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
/// 初始化数据
|
||||
Future<void> kr_initializeData() async {
|
||||
kr_userEmail.value = KRAppRunData.getInstance().kr_account.toString();
|
||||
await kr_getPackageList();
|
||||
|
||||
// 监听所有支付相关消息
|
||||
_kr_eventWorker = KREventBus().kr_listenMessages(
|
||||
[KRMessageType.kr_payment, KRMessageType.kr_subscribe_update],
|
||||
_kr_handleMessage,
|
||||
);
|
||||
}
|
||||
|
||||
/// 处理消息
|
||||
Future<void> _kr_handleMessage(KRMessageData message) async {
|
||||
switch (message.kr_type) {
|
||||
case KRMessageType.kr_payment:
|
||||
await _iniUserInfo();
|
||||
// 只更新支付方式显示,因为支付方式标题中包含余额信息
|
||||
if (kr_paymentMethods.isNotEmpty) {
|
||||
final balanceMethodIndex = kr_paymentMethods
|
||||
.indexWhere((method) => method.platform == 'balance');
|
||||
if (balanceMethodIndex != -1) {
|
||||
// 触发支付方式列表更新
|
||||
kr_paymentMethods.refresh();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case KRMessageType.kr_subscribe_update:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取套餐列表和支付方式
|
||||
Future<void> kr_getPackageList() async {
|
||||
kr_isLoading.value = true;
|
||||
kr_selectedPlanIndex.value = 0; // 重置套餐选择
|
||||
kr_selectedDiscountIndex.value = -1; // 重置折扣选择
|
||||
kr_selectedPaymentMethodIndex.value = -1; // 重置支付方式选择
|
||||
|
||||
await _iniUserInfo();
|
||||
await kr_getAlreadySubscribe();
|
||||
await kr_fetchPackages();
|
||||
await kr_fetchPaymentMethods();
|
||||
|
||||
// 根据套餐数量决定是否显示套餐选择器
|
||||
kr_showPlanSelector.value = kr_plans.length > 1;
|
||||
|
||||
kr_isLoading.value = false;
|
||||
}
|
||||
|
||||
/// 初始化用户信息
|
||||
Future<void> _iniUserInfo() async {
|
||||
final either0 = await KRUserApi().kr_getUserInfo();
|
||||
either0.fold(
|
||||
(error) {
|
||||
KRLogUtil.kr_e(error.msg, tag: 'AppRunData');
|
||||
},
|
||||
(userInfo) async {
|
||||
_kr_balance = userInfo.balance;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// 获取用户已订阅套餐
|
||||
Future<void> kr_getAlreadySubscribe() async {
|
||||
final either = await _kr_subscribeApi.kr_getAlreadySubscribe();
|
||||
either.fold(
|
||||
(error) => KRCommonUtil.kr_showToast(error.msg),
|
||||
(alreadySubscribe) {
|
||||
_kr_alreadySubscribe = alreadySubscribe;
|
||||
KRLogUtil.kr_i(
|
||||
'已订阅套餐: ${_kr_alreadySubscribe.map((e) => e.subscribeId).toList()}',
|
||||
tag: 'PurchaseMembershipController');
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// 获取套餐列表
|
||||
Future<void> kr_fetchPackages() async {
|
||||
final either = await _kr_subscribeApi.kr_getPackageListList();
|
||||
either.fold(
|
||||
(error) => KRCommonUtil.kr_showToast(error.msg),
|
||||
(packageList) {
|
||||
kr_plans.value = packageList.kr_list;
|
||||
// 默认选择第一个套餐
|
||||
if (kr_plans.isNotEmpty) {
|
||||
kr_selectedPlanIndex.value = 0;
|
||||
kr_initializeSelection(kr_plans.first);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// 获取支付方式列表
|
||||
Future<void> kr_fetchPaymentMethods() async {
|
||||
final either = await _kr_subscribeApi.kr_getPaymentMethods();
|
||||
either.fold(
|
||||
(error) => KRCommonUtil.kr_showToast(error.msg),
|
||||
(paymentMethods) {
|
||||
kr_paymentMethods.value = paymentMethods;
|
||||
|
||||
// 检查当前选择的套餐价格是否小于等于余额
|
||||
if (kr_plans.isNotEmpty) {
|
||||
final selectedPlan = kr_plans[kr_selectedPlanIndex.value];
|
||||
final selectedPrice = kr_getPlanPrice(selectedPlan,
|
||||
discountIndex: kr_selectedDiscountIndex.value);
|
||||
|
||||
// 查找余额支付方式的索引
|
||||
final balanceMethodIndex = paymentMethods
|
||||
.indexWhere((method) => method.platform == 'balance');
|
||||
|
||||
// 如果找到余额支付方式且余额足够,默认选择余额支付
|
||||
if (balanceMethodIndex != -1 && selectedPrice <= _kr_balance / 100) {
|
||||
kr_selectPaymentMethod(balanceMethodIndex);
|
||||
} else {
|
||||
// 查找第一个非余额支付方式
|
||||
final nonBalanceMethodIndex = paymentMethods
|
||||
.indexWhere((method) => method.platform != 'balance');
|
||||
if (nonBalanceMethodIndex != -1) {
|
||||
kr_selectPaymentMethod(nonBalanceMethodIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// 获取支付方式显示标题
|
||||
String kr_getPaymentMethodTitle(KRPaymentMethod method) {
|
||||
if (method.platform == 'balance') {
|
||||
return '${method.name}(¥${(_kr_balance / 100).toStringAsFixed(2)})';
|
||||
}
|
||||
return method.name;
|
||||
}
|
||||
|
||||
/// 选择套餐
|
||||
void kr_selectPlan(int planIndex, {int? discountIndex}) {
|
||||
if (planIndex >= 0 && planIndex < kr_plans.length) {
|
||||
kr_selectedPlanIndex.value = planIndex;
|
||||
|
||||
// 确保折扣索引有效
|
||||
if (discountIndex != null) {
|
||||
final plan = kr_plans[planIndex];
|
||||
if (discountIndex >= 0 && discountIndex < plan.kr_discount.length) {
|
||||
kr_selectedDiscountIndex.value = discountIndex;
|
||||
} else {
|
||||
// 如果传入的折扣索引无效,但有折扣选项,则默认选择第一个
|
||||
if (plan.kr_discount.isNotEmpty) {
|
||||
kr_selectedDiscountIndex.value = 0;
|
||||
} else {
|
||||
kr_selectedDiscountIndex.value = -1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 如果没有传入折扣索引,但有折扣选项,则默认选择第一个
|
||||
final plan = kr_plans[planIndex];
|
||||
if (plan.kr_discount.isNotEmpty) {
|
||||
kr_selectedDiscountIndex.value = 0;
|
||||
} else {
|
||||
kr_selectedDiscountIndex.value = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// 重置支付方式选择
|
||||
kr_selectedPaymentMethodIndex.value = -1;
|
||||
|
||||
// 重新判断应该选择的支付方式
|
||||
_kr_updatePaymentMethodSelection();
|
||||
|
||||
// 更新UI状态
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
/// 更新支付方式选择
|
||||
void _kr_updatePaymentMethodSelection() {
|
||||
if (kr_plans.isEmpty || kr_paymentMethods.isEmpty) return;
|
||||
|
||||
final selectedPlan = kr_plans[kr_selectedPlanIndex.value];
|
||||
final selectedPrice = kr_getPlanPrice(selectedPlan,
|
||||
discountIndex: kr_selectedDiscountIndex.value);
|
||||
|
||||
// 查找余额支付方式的索引
|
||||
final balanceMethodIndex =
|
||||
kr_paymentMethods.indexWhere((method) => method.platform == 'balance');
|
||||
|
||||
// 如果找到余额支付方式且余额足够,选择余额支付
|
||||
if (balanceMethodIndex != -1 && selectedPrice <= _kr_balance / 100) {
|
||||
kr_selectPaymentMethod(balanceMethodIndex);
|
||||
} else {
|
||||
// 查找第一个非余额支付方式
|
||||
final nonBalanceMethodIndex = kr_paymentMethods
|
||||
.indexWhere((method) => method.platform != 'balance');
|
||||
if (nonBalanceMethodIndex != -1) {
|
||||
kr_selectPaymentMethod(nonBalanceMethodIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 选择支付方式
|
||||
void kr_selectPaymentMethod(int index) {
|
||||
if (index >= 0 && index < kr_paymentMethods.length) {
|
||||
kr_selectedPaymentMethodIndex.value = index;
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取当前选中的数量
|
||||
int kr_getSelectedQuantity() {
|
||||
final selectedPlan = kr_plans[kr_selectedPlanIndex.value];
|
||||
if (kr_selectedDiscountIndex.value >= 0 &&
|
||||
kr_selectedDiscountIndex.value < selectedPlan.kr_discount.length) {
|
||||
return selectedPlan
|
||||
.kr_discount[kr_selectedDiscountIndex.value].kr_quantity;
|
||||
}
|
||||
return 1; // 默认数量为1
|
||||
}
|
||||
|
||||
/// 开始订阅流程
|
||||
Future<void> kr_startSubscription() async {
|
||||
if (!kr_validateSubscriptionData()) return;
|
||||
|
||||
kr_errorMessage.value = '';
|
||||
|
||||
try {
|
||||
await kr_processPurchaseAndCheckout();
|
||||
} catch (e) {
|
||||
kr_errorMessage.value = '订阅失败: ${e.toString()}';
|
||||
}
|
||||
}
|
||||
|
||||
/// 验证订阅数据
|
||||
bool kr_validateSubscriptionData() {
|
||||
if (kr_plans.isEmpty) {
|
||||
KRCommonUtil.kr_showToast('没有可用的套餐');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (kr_selectedPaymentMethodIndex.value < 0 ||
|
||||
kr_selectedPaymentMethodIndex.value >= kr_paymentMethods.length) {
|
||||
KRCommonUtil.kr_showToast('请选择支付方式');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 处理购买和结账流程
|
||||
Future<void> kr_processPurchaseAndCheckout() async {
|
||||
final selectedPlan = kr_plans[kr_selectedPlanIndex.value];
|
||||
final selectedPaymentMethod =
|
||||
kr_paymentMethods[kr_selectedPaymentMethodIndex.value];
|
||||
|
||||
// 获取选中的数量
|
||||
final quantity = kr_getSelectedQuantity();
|
||||
|
||||
// 判断是续订还是新购
|
||||
final isRenewal = _kr_alreadySubscribe
|
||||
.any((subscribe) => subscribe.subscribeId == selectedPlan.kr_id);
|
||||
|
||||
final subscribeId = isRenewal
|
||||
? _kr_alreadySubscribe
|
||||
.firstWhere(
|
||||
(subscribe) => subscribe.subscribeId == selectedPlan.kr_id)
|
||||
.userSubscribeId
|
||||
: 0;
|
||||
|
||||
// 根据判断结果调用不同的接口
|
||||
final purchaseEither = isRenewal
|
||||
? await _kr_subscribeApi.kr_renewal(
|
||||
subscribeId,
|
||||
quantity,
|
||||
selectedPaymentMethod.id,
|
||||
'',
|
||||
)
|
||||
: await _kr_subscribeApi.kr_purchase(
|
||||
selectedPlan.kr_id,
|
||||
quantity,
|
||||
selectedPaymentMethod.id,
|
||||
'',
|
||||
);
|
||||
|
||||
purchaseEither.fold(
|
||||
(error) => KRCommonUtil.kr_showToast(error.msg),
|
||||
(order) async {
|
||||
// 所有支付方式都需要调用 checkout 接口
|
||||
final checkoutEither = await _kr_subscribeApi.kr_checkout(order);
|
||||
checkoutEither.fold(
|
||||
(error) => KRCommonUtil.kr_showToast(error.msg),
|
||||
(uri) => Get.toNamed(
|
||||
Routes.KR_ORDER_STATUS,
|
||||
arguments: {
|
||||
'url': uri,
|
||||
'order': order,
|
||||
'payment_type': selectedPaymentMethod.platform,
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// 获取套餐价格
|
||||
double kr_getPlanPrice(KRPackageListItem plan, {int? discountIndex}) {
|
||||
if (discountIndex != null &&
|
||||
discountIndex >= 0 &&
|
||||
discountIndex < plan.kr_discount.length) {
|
||||
// 计算折扣价格
|
||||
final discount = plan.kr_discount[discountIndex];
|
||||
return (plan.kr_unitPrice / 100) *
|
||||
discount.kr_quantity *
|
||||
(discount.kr_discount / 100);
|
||||
}
|
||||
return plan.kr_unitPrice / 100;
|
||||
}
|
||||
|
||||
/// 获取时间字符串
|
||||
String kr_getTimeStr(KRPackageListItem plan, {int? discountIndex}) {
|
||||
final quantity = discountIndex != null &&
|
||||
discountIndex >= 0 &&
|
||||
discountIndex < plan.kr_discount.length
|
||||
? plan.kr_discount[discountIndex].kr_quantity
|
||||
: 1;
|
||||
|
||||
if (plan.kr_unitTime == 'Month') {
|
||||
return AppTranslations.kr_purchaseMembership.month(quantity);
|
||||
} else if (plan.kr_unitTime == 'Year') {
|
||||
return AppTranslations.kr_purchaseMembership.year(quantity);
|
||||
} else if (plan.kr_unitTime == 'Day') {
|
||||
return AppTranslations.kr_purchaseMembership.day(quantity);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/// 获取折扣文本
|
||||
String kr_getDiscountText(KRPackageListItem plan, int discountIndex) {
|
||||
if (discountIndex >= 0 && discountIndex < plan.kr_discount.length) {
|
||||
final discount = plan.kr_discount[discountIndex];
|
||||
// 折扣值为 100 表示原价,不需要显示折扣
|
||||
if (discount.kr_discount == 100) {
|
||||
return '';
|
||||
}
|
||||
// 计算折扣百分比(例如:95% 显示为 -5%)
|
||||
final discountPercent = 100 - discount.kr_discount;
|
||||
return '-${discountPercent}%';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/// 获取套餐总选项数
|
||||
int kr_getTotalOptionsCount(KRPackageListItem plan) {
|
||||
// 确保折扣列表不为空
|
||||
if (plan.kr_discount.isEmpty) {
|
||||
return 1; // 如果没有折扣选项,至少返回1个选项
|
||||
}
|
||||
return plan.kr_discount.length;
|
||||
}
|
||||
|
||||
/// 初始化选择
|
||||
void kr_initializeSelection(KRPackageListItem plan) {
|
||||
if (plan.kr_discount.isNotEmpty) {
|
||||
// 默认选择第一个选项
|
||||
kr_selectedDiscountIndex.value = 0;
|
||||
} else {
|
||||
// 如果没有选项,设置为 -1
|
||||
kr_selectedDiscountIndex.value = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取当前选中套餐的描述
|
||||
String kr_getSelectedPlanDescription() {
|
||||
if (kr_selectedPlanIndex.value >= kr_plans.length) return '';
|
||||
final plan = kr_plans[kr_selectedPlanIndex.value];
|
||||
return plan.kr_description.kr_features
|
||||
.map((feature) => feature.kr_label)
|
||||
.join('、');
|
||||
}
|
||||
|
||||
/// 获取当前选中套餐的特性标题列表
|
||||
List<String> kr_getSelectedPlanFeatureLabels() {
|
||||
if (kr_selectedPlanIndex.value >= kr_plans.length) return [];
|
||||
final plan = kr_plans[kr_selectedPlanIndex.value];
|
||||
return plan.kr_description.kr_features
|
||||
.map((feature) => feature.kr_label)
|
||||
.toList();
|
||||
}
|
||||
|
||||
/// 获取当前选中套餐的详细信息
|
||||
List<KRFeature> kr_getSelectedPlanFeatures() {
|
||||
if (kr_selectedPlanIndex.value >= kr_plans.length) return [];
|
||||
final plan = kr_plans[kr_selectedPlanIndex.value];
|
||||
return plan.kr_description.kr_features;
|
||||
}
|
||||
|
||||
/// 判断当前选中的套餐是否是续订
|
||||
bool kr_isRenewal() {
|
||||
if (kr_plans.isEmpty || _kr_alreadySubscribe.isEmpty) return false;
|
||||
final selectedPlan = kr_plans[kr_selectedPlanIndex.value];
|
||||
return _kr_alreadySubscribe
|
||||
.any((subscribe) => subscribe.subscribeId == selectedPlan.kr_id);
|
||||
}
|
||||
|
||||
/// 获取当前选中套餐的订阅按钮文字
|
||||
String kr_getSubscribeButtonText() {
|
||||
if (kr_plans.isEmpty) return '';
|
||||
|
||||
final selectedPlan = kr_plans[kr_selectedPlanIndex.value];
|
||||
final isRenewal = _kr_alreadySubscribe
|
||||
.any((subscribe) => subscribe.subscribeId == selectedPlan.kr_id);
|
||||
|
||||
return isRenewal
|
||||
? AppTranslations.kr_purchaseMembership.renewNow
|
||||
: AppTranslations.kr_purchaseMembership.startSubscription;
|
||||
}
|
||||
|
||||
/// 切换描述展开状态
|
||||
void kr_toggleDescriptionExpanded() {
|
||||
kr_isDescriptionExpanded.value = !kr_isDescriptionExpanded.value;
|
||||
}
|
||||
|
||||
/// 获取流量限制显示文本
|
||||
String kr_getTrafficLimitText(KRPackageListItem plan) {
|
||||
KRLogUtil.kr_i('原始流量值: ${plan.kr_traffic}', tag: 'TrafficLimit');
|
||||
if (plan.kr_traffic == 0) {
|
||||
return AppTranslations.kr_purchaseMembership.unlimitedTraffic;
|
||||
}
|
||||
// 将字节转换为GB
|
||||
final trafficInGB = plan.kr_traffic / (1024 * 1024 * 1024);
|
||||
KRLogUtil.kr_i('转换为GB后的值: $trafficInGB', tag: 'TrafficLimit');
|
||||
|
||||
if (trafficInGB < 1) {
|
||||
return '${(trafficInGB * 1024).toStringAsFixed(0)}MB';
|
||||
} else if (trafficInGB < 1024) {
|
||||
return '${trafficInGB.toStringAsFixed(0)}GB';
|
||||
} else {
|
||||
return '${(trafficInGB / 1024).toStringAsFixed(1)}TB';
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取设备限制显示文本
|
||||
String kr_getDeviceLimitText(KRPackageListItem plan) {
|
||||
if (plan.kr_deviceLimit == 0) {
|
||||
return AppTranslations.kr_purchaseMembership.unlimitedDevices;
|
||||
}
|
||||
return AppTranslations.kr_purchaseMembership
|
||||
.devices(plan.kr_deviceLimit.toString());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user