From 89c7334caf25409a2a023320f578381b634bf214 Mon Sep 17 00:00:00 2001 From: Rust Date: Sat, 18 Oct 2025 15:25:28 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=A5=97=E9=A4=90=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E9=80=BB=E8=BE=91=E6=96=B0=E5=A2=9E=E5=A4=9A=E8=AF=AD?= =?UTF-8?q?=E8=A8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/translations/strings_en.i18n.json | 10 ++- assets/translations/strings_es.i18n.json | 10 ++- assets/translations/strings_et.i18n.json | 10 ++- assets/translations/strings_ja.i18n.json | 10 ++- assets/translations/strings_ru.i18n.json | 10 ++- assets/translations/strings_zh.i18n.json | 10 ++- assets/translations/strings_zh_Hant.i18n.json | 10 ++- lib/app/localization/app_translations.dart | 19 ++++ .../kr_purchase_membership_controller.dart | 49 +++++++++-- .../views/kr_purchase_membership_view.dart | 49 ++++++----- lib/app/network/http_util.dart | 88 +++++++++++-------- 11 files changed, 198 insertions(+), 77 deletions(-) diff --git a/assets/translations/strings_en.i18n.json b/assets/translations/strings_en.i18n.json index 3471185..c305154 100755 --- a/assets/translations/strings_en.i18n.json +++ b/assets/translations/strings_en.i18n.json @@ -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", diff --git a/assets/translations/strings_es.i18n.json b/assets/translations/strings_es.i18n.json index 9a45ebd..f46b7b6 100755 --- a/assets/translations/strings_es.i18n.json +++ b/assets/translations/strings_es.i18n.json @@ -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", diff --git a/assets/translations/strings_et.i18n.json b/assets/translations/strings_et.i18n.json index b7a18b5..31a6e75 100755 --- a/assets/translations/strings_et.i18n.json +++ b/assets/translations/strings_et.i18n.json @@ -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", diff --git a/assets/translations/strings_ja.i18n.json b/assets/translations/strings_ja.i18n.json index b668ece..adc30f7 100755 --- a/assets/translations/strings_ja.i18n.json +++ b/assets/translations/strings_ja.i18n.json @@ -245,7 +245,15 @@ "collapse": "折りたたむ", "confirmPurchase": "購入を確認", "confirmPurchaseDesc": "このパッケージを購入してもよろしいですか?", - "subscriptionPrivacyInfo": "サブスクリプションとプライバシー情報" + "subscriptionPrivacyInfo": "サブスクリプションとプライバシー情報", + "timeUnit": { + "oneWeek": "1週間", + "oneMonth": "1ヶ月", + "oneQuarter": "1四半期", + "halfYear": "6ヶ月", + "oneYear": "1年", + "days": "{count}日" + } }, "orderStatus": { "title": "注文状態", diff --git a/assets/translations/strings_ru.i18n.json b/assets/translations/strings_ru.i18n.json index d986f03..2e0801b 100755 --- a/assets/translations/strings_ru.i18n.json +++ b/assets/translations/strings_ru.i18n.json @@ -246,7 +246,15 @@ "expand": "Развернуть", "collapse": "Свернуть", "confirmPurchase": "Подтвердить покупку", - "confirmPurchaseDesc": "Вы уверены, что хотите приобрести этот пакет?" + "confirmPurchaseDesc": "Вы уверены, что хотите приобрести этот пакет?", + "timeUnit": { + "oneWeek": "1 Неделя", + "oneMonth": "1 Месяц", + "oneQuarter": "1 Квартал", + "halfYear": "6 Месяцев", + "oneYear": "1 Год", + "days": "{count} Дней" + } }, "orderStatus": { "title": "Статус заказа", diff --git a/assets/translations/strings_zh.i18n.json b/assets/translations/strings_zh.i18n.json index 6e6648d..9bce732 100755 --- a/assets/translations/strings_zh.i18n.json +++ b/assets/translations/strings_zh.i18n.json @@ -294,7 +294,15 @@ "collapse": "收起", "confirmPurchase": "确认购买", "confirmPurchaseDesc": "您确定要购买此套餐吗?", - "subscriptionPrivacyInfo": "订阅和隐私信息" + "subscriptionPrivacyInfo": "订阅和隐私信息", + "timeUnit": { + "oneWeek": "一周", + "oneMonth": "一个月", + "oneQuarter": "一个季度", + "halfYear": "半年", + "oneYear": "一年", + "days": "{count}天" + } }, "orderStatus": { "title": "订单状态", diff --git a/assets/translations/strings_zh_Hant.i18n.json b/assets/translations/strings_zh_Hant.i18n.json index 99e7612..e77cb8a 100755 --- a/assets/translations/strings_zh_Hant.i18n.json +++ b/assets/translations/strings_zh_Hant.i18n.json @@ -231,7 +231,15 @@ "expand": "展開", "collapse": "收起", "confirmPurchase": "確認購買", - "confirmPurchaseDesc": "您確定要購買此套餐嗎?" + "confirmPurchaseDesc": "您確定要購買此套餐嗎?", + "timeUnit": { + "oneWeek": "一週", + "oneMonth": "一個月", + "oneQuarter": "一季度", + "halfYear": "半年", + "oneYear": "一年", + "days": "{count}天" + } }, "home": { "welcome": "歡迎使用 BearVPN", diff --git a/lib/app/localization/app_translations.dart b/lib/app/localization/app_translations.dart index 1cbd24e..eff9817 100755 --- a/lib/app/localization/app_translations.dart +++ b/lib/app/localization/app_translations.dart @@ -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()}); } /// 订单状态模块的翻译类 diff --git a/lib/app/modules/kr_purchase_membership/controllers/kr_purchase_membership_controller.dart b/lib/app/modules/kr_purchase_membership/controllers/kr_purchase_membership_controller.dart index c17f1ad..7e15751 100755 --- a/lib/app/modules/kr_purchase_membership/controllers/kr_purchase_membership_controller.dart +++ b/lib/app/modules/kr_purchase_membership/controllers/kr_purchase_membership_controller.dart @@ -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}%'; } diff --git a/lib/app/modules/kr_purchase_membership/views/kr_purchase_membership_view.dart b/lib/app/modules/kr_purchase_membership/views/kr_purchase_membership_view.dart index 9750a1b..4a0be7f 100755 --- a/lib/app/modules/kr_purchase_membership/views/kr_purchase_membership_view.dart +++ b/lib/app/modules/kr_purchase_membership/views/kr_purchase_membership_view.dart @@ -172,6 +172,14 @@ class KRPurchaseMembershipView extends GetView { 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 { ], ), 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), ), ), ), diff --git a/lib/app/network/http_util.dart b/lib/app/network/http_util.dart index 9b63be4..9b3eea2 100755 --- a/lib/app/network/http_util.dart +++ b/lib/app/network/http_util.dart @@ -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); } }