优化套餐显示逻辑新增多语言
This commit is contained in:
parent
a3b7c418b1
commit
89c7334caf
@ -231,7 +231,15 @@
|
||||
"expand": "Expand",
|
||||
"collapse": "Collapse",
|
||||
"confirmPurchase": "Confirm Purchase",
|
||||
"confirmPurchaseDesc": "Are you sure you want to purchase this package?"
|
||||
"confirmPurchaseDesc": "Are you sure you want to purchase this package?",
|
||||
"timeUnit": {
|
||||
"oneWeek": "1 Week",
|
||||
"oneMonth": "1 Month",
|
||||
"oneQuarter": "1 Quarter",
|
||||
"halfYear": "6 Months",
|
||||
"oneYear": "1 Year",
|
||||
"days": "{count} Days"
|
||||
}
|
||||
},
|
||||
"orderStatus": {
|
||||
"title": "Order Status",
|
||||
|
||||
@ -284,7 +284,15 @@
|
||||
"expand": "Expandir",
|
||||
"collapse": "Colapsar",
|
||||
"confirmPurchase": "Confirmar Compra",
|
||||
"confirmPurchaseDesc": "¿Está seguro de que desea comprar este paquete?"
|
||||
"confirmPurchaseDesc": "¿Está seguro de que desea comprar este paquete?",
|
||||
"timeUnit": {
|
||||
"oneWeek": "1 Semana",
|
||||
"oneMonth": "1 Mes",
|
||||
"oneQuarter": "1 Trimestre",
|
||||
"halfYear": "6 Meses",
|
||||
"oneYear": "1 Año",
|
||||
"days": "{count} Días"
|
||||
}
|
||||
},
|
||||
"orderStatus": {
|
||||
"title": "Estado del Pedido",
|
||||
|
||||
@ -228,7 +228,15 @@
|
||||
"expand": "Laienda",
|
||||
"collapse": "Sulge",
|
||||
"confirmPurchase": "Kinnita Ost",
|
||||
"confirmPurchaseDesc": "Kas olete kindel, et soovite selle paketi osta?"
|
||||
"confirmPurchaseDesc": "Kas olete kindel, et soovite selle paketi osta?",
|
||||
"timeUnit": {
|
||||
"oneWeek": "1 nädal",
|
||||
"oneMonth": "1 kuu",
|
||||
"oneQuarter": "1 kvartal",
|
||||
"halfYear": "6 kuud",
|
||||
"oneYear": "1 aasta",
|
||||
"days": "{count} päeva"
|
||||
}
|
||||
},
|
||||
"orderStatus": {
|
||||
"title": "Tellimuse olek",
|
||||
|
||||
@ -245,7 +245,15 @@
|
||||
"collapse": "折りたたむ",
|
||||
"confirmPurchase": "購入を確認",
|
||||
"confirmPurchaseDesc": "このパッケージを購入してもよろしいですか?",
|
||||
"subscriptionPrivacyInfo": "サブスクリプションとプライバシー情報"
|
||||
"subscriptionPrivacyInfo": "サブスクリプションとプライバシー情報",
|
||||
"timeUnit": {
|
||||
"oneWeek": "1週間",
|
||||
"oneMonth": "1ヶ月",
|
||||
"oneQuarter": "1四半期",
|
||||
"halfYear": "6ヶ月",
|
||||
"oneYear": "1年",
|
||||
"days": "{count}日"
|
||||
}
|
||||
},
|
||||
"orderStatus": {
|
||||
"title": "注文状態",
|
||||
|
||||
@ -246,7 +246,15 @@
|
||||
"expand": "Развернуть",
|
||||
"collapse": "Свернуть",
|
||||
"confirmPurchase": "Подтвердить покупку",
|
||||
"confirmPurchaseDesc": "Вы уверены, что хотите приобрести этот пакет?"
|
||||
"confirmPurchaseDesc": "Вы уверены, что хотите приобрести этот пакет?",
|
||||
"timeUnit": {
|
||||
"oneWeek": "1 Неделя",
|
||||
"oneMonth": "1 Месяц",
|
||||
"oneQuarter": "1 Квартал",
|
||||
"halfYear": "6 Месяцев",
|
||||
"oneYear": "1 Год",
|
||||
"days": "{count} Дней"
|
||||
}
|
||||
},
|
||||
"orderStatus": {
|
||||
"title": "Статус заказа",
|
||||
|
||||
@ -294,7 +294,15 @@
|
||||
"collapse": "收起",
|
||||
"confirmPurchase": "确认购买",
|
||||
"confirmPurchaseDesc": "您确定要购买此套餐吗?",
|
||||
"subscriptionPrivacyInfo": "订阅和隐私信息"
|
||||
"subscriptionPrivacyInfo": "订阅和隐私信息",
|
||||
"timeUnit": {
|
||||
"oneWeek": "一周",
|
||||
"oneMonth": "一个月",
|
||||
"oneQuarter": "一个季度",
|
||||
"halfYear": "半年",
|
||||
"oneYear": "一年",
|
||||
"days": "{count}天"
|
||||
}
|
||||
},
|
||||
"orderStatus": {
|
||||
"title": "订单状态",
|
||||
|
||||
@ -231,7 +231,15 @@
|
||||
"expand": "展開",
|
||||
"collapse": "收起",
|
||||
"confirmPurchase": "確認購買",
|
||||
"confirmPurchaseDesc": "您確定要購買此套餐嗎?"
|
||||
"confirmPurchaseDesc": "您確定要購買此套餐嗎?",
|
||||
"timeUnit": {
|
||||
"oneWeek": "一週",
|
||||
"oneMonth": "一個月",
|
||||
"oneQuarter": "一季度",
|
||||
"halfYear": "半年",
|
||||
"oneYear": "一年",
|
||||
"days": "{count}天"
|
||||
}
|
||||
},
|
||||
"home": {
|
||||
"welcome": "歡迎使用 BearVPN",
|
||||
|
||||
@ -749,6 +749,25 @@ class AppTranslationsPurchaseMembership {
|
||||
|
||||
/// 确认购买描述
|
||||
String get confirmPurchaseDesc => 'purchaseMembership.confirmPurchaseDesc'.tr;
|
||||
|
||||
/// 时间单位:一周
|
||||
String get oneWeek => 'purchaseMembership.timeUnit.oneWeek'.tr;
|
||||
|
||||
/// 时间单位:一个月
|
||||
String get oneMonth => 'purchaseMembership.timeUnit.oneMonth'.tr;
|
||||
|
||||
/// 时间单位:一个季度
|
||||
String get oneQuarter => 'purchaseMembership.timeUnit.oneQuarter'.tr;
|
||||
|
||||
/// 时间单位:半年
|
||||
String get halfYear => 'purchaseMembership.timeUnit.halfYear'.tr;
|
||||
|
||||
/// 时间单位:一年
|
||||
String get oneYear => 'purchaseMembership.timeUnit.oneYear'.tr;
|
||||
|
||||
/// 时间单位:天数
|
||||
String days(int count) =>
|
||||
'purchaseMembership.timeUnit.days'.trParams({'count': count.toString()});
|
||||
}
|
||||
|
||||
/// 订单状态模块的翻译类
|
||||
|
||||
@ -372,20 +372,26 @@ class KRPurchaseMembershipController extends GetxController {
|
||||
}
|
||||
|
||||
/// 获取套餐价格
|
||||
/// discount: 0 表示无折扣(原价),其他值表示折扣百分比
|
||||
double kr_getPlanPrice(KRPackageListItem plan, {int? discountIndex}) {
|
||||
if (discountIndex != null &&
|
||||
discountIndex >= 0 &&
|
||||
discountIndex < plan.kr_discount.length) {
|
||||
// 计算折扣价格
|
||||
final discount = plan.kr_discount[discountIndex];
|
||||
// 如果 discount 是 0,则表示原价(100%)
|
||||
final discountRate = discount.kr_discount == 0 ? 100.0 : discount.kr_discount.toDouble();
|
||||
return (plan.kr_unitPrice / 100) *
|
||||
discount.kr_quantity *
|
||||
(discount.kr_discount / 100);
|
||||
(discountRate / 100);
|
||||
}
|
||||
return plan.kr_unitPrice / 100;
|
||||
}
|
||||
|
||||
/// 获取时间字符串
|
||||
/// 根据 quantity 和 unit_time 转换成多语言描述
|
||||
/// Day: 7天 -> "一周",30天 -> "一个月",90天 -> "一个季度",180天 -> "半年",365天 -> "一年"
|
||||
/// Month: 3月 -> "一个季度",6月 -> "半年",12月 -> "一年"
|
||||
String kr_getTimeStr(KRPackageListItem plan, {int? discountIndex}) {
|
||||
final quantity = discountIndex != null &&
|
||||
discountIndex >= 0 &&
|
||||
@ -393,25 +399,52 @@ class KRPurchaseMembershipController extends GetxController {
|
||||
? plan.kr_discount[discountIndex].kr_quantity
|
||||
: 1;
|
||||
|
||||
if (plan.kr_unitTime == 'Month') {
|
||||
return AppTranslations.kr_purchaseMembership.month(quantity);
|
||||
// 如果是 Day 单位,需要转换为对应的描述
|
||||
if (plan.kr_unitTime == 'Day') {
|
||||
switch (quantity) {
|
||||
case 7:
|
||||
return AppTranslations.kr_purchaseMembership.oneWeek;
|
||||
case 30:
|
||||
return AppTranslations.kr_purchaseMembership.oneMonth;
|
||||
case 90:
|
||||
return AppTranslations.kr_purchaseMembership.oneQuarter;
|
||||
case 180:
|
||||
return AppTranslations.kr_purchaseMembership.halfYear;
|
||||
case 365:
|
||||
return AppTranslations.kr_purchaseMembership.oneYear;
|
||||
default:
|
||||
return AppTranslations.kr_purchaseMembership.days(quantity);
|
||||
}
|
||||
} else if (plan.kr_unitTime == 'Month') {
|
||||
// 月份也需要转换
|
||||
switch (quantity) {
|
||||
case 1:
|
||||
return AppTranslations.kr_purchaseMembership.oneMonth;
|
||||
case 3:
|
||||
return AppTranslations.kr_purchaseMembership.oneQuarter;
|
||||
case 6:
|
||||
return AppTranslations.kr_purchaseMembership.halfYear;
|
||||
case 12:
|
||||
return AppTranslations.kr_purchaseMembership.oneYear;
|
||||
default:
|
||||
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 '';
|
||||
}
|
||||
|
||||
/// 获取折扣文本
|
||||
/// discount: 0 或 100 表示原价(无折扣),其他值表示折扣百分比
|
||||
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) {
|
||||
// 折扣值为 0 或 100 都表示原价,不需要显示折扣
|
||||
if (discount.kr_discount == 0 || discount.kr_discount == 100) {
|
||||
return '';
|
||||
}
|
||||
// 计算折扣百分比(例如:95% 显示为 -5%)
|
||||
// 计算折扣百分比(例如:97% 显示为 -3%)
|
||||
final discountPercent = 100 - discount.kr_discount;
|
||||
return '-${discountPercent}%';
|
||||
}
|
||||
|
||||
@ -172,6 +172,14 @@ class KRPurchaseMembershipView extends GetView<KRPurchaseMembershipController> {
|
||||
itemBuilder: (context, index) {
|
||||
final plan = controller.kr_plans[controller.kr_selectedPlanIndex.value];
|
||||
final discountIndex = plan.kr_discount.isEmpty ? null : index;
|
||||
|
||||
// 如果是 Day 单位且 quantity 是 1(一天),则不显示
|
||||
if (discountIndex != null &&
|
||||
plan.kr_unitTime == 'Day' &&
|
||||
plan.kr_discount[discountIndex].kr_quantity == 1) {
|
||||
return SizedBox.shrink();
|
||||
}
|
||||
|
||||
return _kr_buildPlanOptionCard(
|
||||
plan,
|
||||
controller.kr_selectedPlanIndex.value,
|
||||
@ -695,42 +703,37 @@ class KRPurchaseMembershipView extends GetView<KRPurchaseMembershipController> {
|
||||
],
|
||||
),
|
||||
SizedBox(height: 6.h),
|
||||
if (discountIndex != null && plan.kr_discount.isNotEmpty) ...[
|
||||
if (discountIndex != null &&
|
||||
plan.kr_discount.isNotEmpty &&
|
||||
plan.kr_discount[discountIndex].kr_discount != 0 &&
|
||||
plan.kr_discount[discountIndex].kr_discount != 100) ...[
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 8.w,
|
||||
vertical: 2.h
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: plan.kr_discount[discountIndex].kr_discount < 100
|
||||
? Colors.red.withOpacity(0.08)
|
||||
: Colors.transparent,
|
||||
color: Colors.red.withOpacity(0.08),
|
||||
borderRadius: BorderRadius.circular(4.r),
|
||||
border: plan.kr_discount[discountIndex].kr_discount < 100
|
||||
? Border.all(
|
||||
color: Colors.red.withOpacity(0.2),
|
||||
width: 1,
|
||||
)
|
||||
: null,
|
||||
boxShadow: plan.kr_discount[discountIndex].kr_discount < 100
|
||||
? [
|
||||
BoxShadow(
|
||||
color: Colors.red.withOpacity(0.05),
|
||||
blurRadius: 4,
|
||||
offset: Offset(0, 2),
|
||||
spreadRadius: 0,
|
||||
),
|
||||
]
|
||||
: null,
|
||||
border: Border.all(
|
||||
color: Colors.red.withOpacity(0.2),
|
||||
width: 1,
|
||||
),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.red.withOpacity(0.05),
|
||||
blurRadius: 4,
|
||||
offset: Offset(0, 2),
|
||||
spreadRadius: 0,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Text(
|
||||
controller.kr_getDiscountText(plan, discountIndex),
|
||||
style: KrAppTextStyle(
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: plan.kr_discount[discountIndex].kr_discount < 100
|
||||
? Colors.red.withOpacity(0.9)
|
||||
: Colors.transparent,
|
||||
color: Colors.red.withOpacity(0.9),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@ -44,14 +44,9 @@ class HttpUtil {
|
||||
|
||||
/// 对dio进行配置
|
||||
void initDio() {
|
||||
Loggy.initLoggy(logPrinter: _KRSimpleLogPrinter());
|
||||
_dio.interceptors.add(LoggyDioInterceptor(requestBody: true));
|
||||
// 不使用 Loggy,改用自定义简洁拦截器
|
||||
_dio.interceptors.add(_KRSimpleHttpInterceptor());
|
||||
_dio.options.baseUrl = AppConfig.getInstance().baseUrl;
|
||||
// 添加日志拦截器
|
||||
_dio.interceptors.add(LoggyDioInterceptor(
|
||||
requestBody: true,
|
||||
responseBody: true,
|
||||
));
|
||||
|
||||
// 设置连接超时时间
|
||||
_dio.options.connectTimeout = const Duration(seconds: 60);
|
||||
@ -246,55 +241,70 @@ class HttpUtil {
|
||||
}
|
||||
}
|
||||
|
||||
/// 拦截器
|
||||
/// 拦截器(简洁格式,无边框)
|
||||
class MyInterceptor extends Interceptor {
|
||||
@override
|
||||
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
|
||||
KRLogUtil.kr_d(
|
||||
'>>> Request │ ${options.method} │ ${options.uri}\n'
|
||||
'╔ Headers\n'
|
||||
'║ ${options.headers}\n'
|
||||
'╚════════════════════════════════════════════════════════════════════════════════════════╝\n'
|
||||
'╔ Body\n'
|
||||
'║ ${options.data}\n'
|
||||
'╚════════════════════════════════════════════════════════════════════════════════════════╝',
|
||||
tag: 'DioLoggy');
|
||||
print('>>> Request │ ${options.method} │ ${options.uri}');
|
||||
if (options.data != null) {
|
||||
print('Body: ${options.data}');
|
||||
}
|
||||
handler.next(options);
|
||||
}
|
||||
|
||||
@override
|
||||
void onResponse(Response response, ResponseInterceptorHandler handler) {
|
||||
KRLogUtil.kr_d(
|
||||
'<<< Response │ ${response.requestOptions.method} │ ${response.statusCode} ${response.statusMessage} │ ${response.requestOptions.uri}\n'
|
||||
'╔ Body\n'
|
||||
'║ ${response.data}\n'
|
||||
'╚════════════════════════════════════════════════════════════════════════════════════════╝',
|
||||
tag: 'DioLoggy');
|
||||
print('<<< Response │ ${response.requestOptions.method} │ ${response.statusCode} ${response.statusMessage} │ ${response.requestOptions.uri}');
|
||||
if (response.data != null) {
|
||||
print('Body: ${response.data}');
|
||||
}
|
||||
handler.next(response);
|
||||
}
|
||||
|
||||
@override
|
||||
void onError(DioException err, ErrorInterceptorHandler handler) {
|
||||
KRLogUtil.kr_e(
|
||||
'<<< Error │ ${err.requestOptions.method} │ ${err.requestOptions.uri}\n'
|
||||
'╔ Error Type\n'
|
||||
'║ ${err.type}\n'
|
||||
'╚════════════════════════════════════════════════════════════════════════════════════════╝\n'
|
||||
'╔ Error Message\n'
|
||||
'║ ${err.message}\n'
|
||||
'╚════════════════════════════════════════════════════════════════════════════════════════╝\n'
|
||||
'╔ Response Data\n'
|
||||
'║ ${err.response?.data}\n'
|
||||
'╚════════════════════════════════════════════════════════════════════════════════════════╝',
|
||||
tag: 'DioLoggy');
|
||||
print('<<< Error │ ${err.requestOptions.method} │ ${err.requestOptions.uri}');
|
||||
print('Error Type: ${err.type}');
|
||||
if (err.message != null) {
|
||||
print('Error Message: ${err.message}');
|
||||
}
|
||||
if (err.response?.data != null) {
|
||||
print('Response Data: ${err.response?.data}');
|
||||
}
|
||||
handler.next(err);
|
||||
}
|
||||
}
|
||||
|
||||
/// 自定义简洁日志打印机(无边框符号)
|
||||
class _KRSimpleLogPrinter extends LoggyPrinter {
|
||||
/// 自定义简洁 HTTP 拦截器(无边框符号)
|
||||
class _KRSimpleHttpInterceptor extends Interceptor {
|
||||
@override
|
||||
void onLog(LogRecord record) {
|
||||
print(record.message);
|
||||
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
|
||||
print('>>> Request │ ${options.method} │ ${options.uri}');
|
||||
if (options.data != null) {
|
||||
print('Body: ${options.data}');
|
||||
}
|
||||
handler.next(options);
|
||||
}
|
||||
|
||||
@override
|
||||
void onResponse(Response response, ResponseInterceptorHandler handler) {
|
||||
print('<<< Response │ ${response.requestOptions.method} │ ${response.statusCode} ${response.statusMessage} │ ${response.requestOptions.uri}');
|
||||
if (response.data != null) {
|
||||
print('Body: ${response.data}');
|
||||
}
|
||||
handler.next(response);
|
||||
}
|
||||
|
||||
@override
|
||||
void onError(DioException err, ErrorInterceptorHandler handler) {
|
||||
print('<<< Error │ ${err.requestOptions.method} │ ${err.requestOptions.uri}');
|
||||
print('Error Type: ${err.type}');
|
||||
if (err.message != null) {
|
||||
print('Error Message: ${err.message}');
|
||||
}
|
||||
if (err.response?.data != null) {
|
||||
print('Response Data: ${err.response?.data}');
|
||||
}
|
||||
handler.next(err);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user