浏览代码

[feat]1.增加关闭自动续订

云天逵 6 月之前
父节点
当前提交
7609a28295

二进制
assets/images/icon_auto_renewal_not_sign.webp


二进制
assets/images/icon_mine_auto_renewal.webp


+ 9 - 0
assets/string/base/string.xml

@@ -11,6 +11,9 @@
     <string name="tutorials">使用教程</string>
     <string name="personal_profile">个人档案</string>
     <string name="feedback">意见反馈</string>
+
+    <string name="auto_renewal_management">自动续费管理</string>
+
     <string name="about_us">关于我们</string>
     <!--    投诉举报-->
     <string name="complaint_report">投诉举报</string>
@@ -482,4 +485,10 @@
 
     <string name="dialog_cancel">取消</string>
     <string name="dialog_confirm">确定</string>
+    <string name="dialog_close">确认关闭</string>
+    <string name="auto_renewal_no_service">当前未开通自动续费服务</string>
+    <string name="auto_renewal_tip_dialog_desc">关闭自动续费后,下个周期将无法继续享受会员服务</string>
+    <string name="auto_renewal_item_title">自动续费服务</string>
+    <string name="auto_renewal_item_button_desc">关闭续订</string>
+
 </resources>

+ 14 - 0
lib/data/api/atmob_api.dart

@@ -61,6 +61,7 @@ import 'package:keyboard/data/api/response/keyboard_love_index_response.dart';
 import 'package:keyboard/data/api/response/keyboard_meme_explain_response.dart';
 import 'package:keyboard/data/api/response/keyboard_prologue_list_response.dart';
 import 'package:keyboard/data/api/response/login_response.dart';
+import 'package:keyboard/data/api/response/member_agreement_check_response.dart';
 import 'package:keyboard/data/api/response/member_new_user_response.dart';
 import 'package:keyboard/data/api/response/new_user_get_character_response.dart';
 import 'package:keyboard/data/api/response/order_pay_response.dart';
@@ -347,4 +348,17 @@ abstract class AtmobApi {
   @POST("/project/keyboard/v1/intimacy/future/week")
   Future<BaseResponse<ZodiacLoveIntimacyResponse>>
   getZodiacLoveIntimacyFutureWeek(@Body() AppBaseRequest request);
+
+
+  ///检查当前是否有生效中的支付宝签约协议
+  @POST("/project/keyboard/v1/member/agreement/check")
+  Future<BaseResponse<MemberAgreementCheckResponse>> memberAgreementCheck(
+    @Body() AppBaseRequest request,
+  );
+
+  ///解约支付宝签约协议
+  @POST("/project/keyboard/v1/member/agreement/unSign")
+  Future<BaseResponse> memberAgreementUnSign(
+    @Body() AppBaseRequest request,
+  );
 }

+ 67 - 0
lib/data/api/atmob_api.g.dart

@@ -1648,6 +1648,73 @@ class _AtmobApi implements AtmobApi {
     return _value;
   }
 
+  @override
+  Future<BaseResponse<MemberAgreementCheckResponse>> memberAgreementCheck(
+    AppBaseRequest request,
+  ) async {
+    final _extra = <String, dynamic>{};
+    final queryParameters = <String, dynamic>{};
+    final _headers = <String, dynamic>{};
+    final _data = <String, dynamic>{};
+    _data.addAll(request.toJson());
+    final _options = _setStreamType<BaseResponse<MemberAgreementCheckResponse>>(
+      Options(method: 'POST', headers: _headers, extra: _extra)
+          .compose(
+            _dio.options,
+            '/project/keyboard/v1/member/agreement/check',
+            queryParameters: queryParameters,
+            data: _data,
+          )
+          .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)),
+    );
+    final _result = await _dio.fetch<Map<String, dynamic>>(_options);
+    late BaseResponse<MemberAgreementCheckResponse> _value;
+    try {
+      _value = BaseResponse<MemberAgreementCheckResponse>.fromJson(
+        _result.data!,
+        (json) =>
+            MemberAgreementCheckResponse.fromJson(json as Map<String, dynamic>),
+      );
+    } on Object catch (e, s) {
+      errorLogger?.logError(e, s, _options);
+      rethrow;
+    }
+    return _value;
+  }
+
+  @override
+  Future<BaseResponse<dynamic>> memberAgreementUnSign(
+    AppBaseRequest request,
+  ) async {
+    final _extra = <String, dynamic>{};
+    final queryParameters = <String, dynamic>{};
+    final _headers = <String, dynamic>{};
+    final _data = <String, dynamic>{};
+    _data.addAll(request.toJson());
+    final _options = _setStreamType<BaseResponse<dynamic>>(
+      Options(method: 'POST', headers: _headers, extra: _extra)
+          .compose(
+            _dio.options,
+            '/project/keyboard/v1/member/agreement/unSign',
+            queryParameters: queryParameters,
+            data: _data,
+          )
+          .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)),
+    );
+    final _result = await _dio.fetch<Map<String, dynamic>>(_options);
+    late BaseResponse<dynamic> _value;
+    try {
+      _value = BaseResponse<dynamic>.fromJson(
+        _result.data!,
+        (json) => json as dynamic,
+      );
+    } on Object catch (e, s) {
+      errorLogger?.logError(e, s, _options);
+      rethrow;
+    }
+    return _value;
+  }
+
   RequestOptions _setStreamType<T>(RequestOptions requestOptions) {
     if (T != dynamic &&
         !(requestOptions.responseType == ResponseType.bytes ||

+ 14 - 0
lib/data/api/response/member_agreement_check_response.dart

@@ -0,0 +1,14 @@
+import 'package:json_annotation/json_annotation.dart';
+
+part 'member_agreement_check_response.g.dart';
+
+@JsonSerializable()
+class MemberAgreementCheckResponse {
+  @JsonKey(name: "exist")
+  bool exist;
+
+  MemberAgreementCheckResponse(this.exist);
+
+  factory MemberAgreementCheckResponse.fromJson(Map<String, dynamic> json) =>
+      _$MemberAgreementCheckResponseFromJson(json);
+}

+ 15 - 0
lib/data/api/response/member_agreement_check_response.g.dart

@@ -0,0 +1,15 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'member_agreement_check_response.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+MemberAgreementCheckResponse _$MemberAgreementCheckResponseFromJson(
+  Map<String, dynamic> json,
+) => MemberAgreementCheckResponse(json['exist'] as bool);
+
+Map<String, dynamic> _$MemberAgreementCheckResponseToJson(
+  MemberAgreementCheckResponse instance,
+) => <String, dynamic>{'exist': instance.exist};

+ 24 - 1
lib/data/repository/store_repository.dart

@@ -5,6 +5,7 @@ import 'package:keyboard/data/api/response/order_pay_response.dart';
 import 'package:keyboard/utils/http_handler.dart';
 import 'package:get/get.dart';
 import '../../base/app_base_request.dart';
+import '../../di/get_it.dart';
 import '../../utils/async_util.dart';
 import '../../utils/atmob_log.dart';
 import '../../utils/error_handler.dart';
@@ -12,6 +13,7 @@ import '../../utils/payment_status_manager.dart';
 import '../api/request/order_pay_request.dart';
 import '../api/request/order_status_request.dart';
 import '../api/response/item_retention_response.dart';
+import '../api/response/member_agreement_check_response.dart';
 import '../api/response/member_new_user_response.dart';
 import '../bean/character_info.dart';
 import '../bean/goods_info.dart';
@@ -40,6 +42,8 @@ class StoreRepository {
 
   RxList<CharacterInfo> get charactersList => _charactersList;
 
+  final RxBool hasAutoRenewal = false.obs;
+
   StoreRepository(this.atmobApi, this.accountRepository) {
     print('$tag....init');
     refreshNewDiscountGoodsInfoList();
@@ -60,7 +64,6 @@ class StoreRepository {
     goodsInfoFuture?.catchError((error) {
       ErrorHandler.toastError(error);
     });
-
   }
 
   Future<ItemListResponse> getGoodsInfoList() async {
@@ -123,4 +126,24 @@ class StoreRepository {
         .getItemRetention(AppBaseRequest())
         .then(HttpHandler.handle(true));
   }
+
+  /// 检查当前是否有生效中的支付宝签约协议
+  Future<MemberAgreementCheckResponse> checkMemberAgreement() async {
+    return await atmobApi
+        .memberAgreementCheck(AppBaseRequest())
+        .then(HttpHandler.handle(true))
+        .then((response) {
+          hasAutoRenewal.value = response.exist;
+          return response;
+        });
+  }
+
+  /// 解约支付宝签约协议
+  Future<void> unSignMemberAgreement() async {
+    return await atmobApi
+        .memberAgreementUnSign(AppBaseRequest())
+        .then(HttpHandler.handle(true));
+  }
+
+  static StoreRepository getInstance() => getIt.get<StoreRepository>();
 }

+ 7 - 0
lib/di/get_it.config.dart

@@ -34,6 +34,7 @@ import '../dialog/custom_character/custom_character_add_controller.dart'
 import '../dialog/login/login_dialog_controller.dart' as _i798;
 import '../handler/wechat_login_service.dart' as _i495;
 import '../module/about/about_controller.dart' as _i256;
+import '../module/auto_renewal/auto_renewal_controller.dart' as _i929;
 import '../module/browser/browser_controller.dart' as _i923;
 import '../module/change/birthday/change_birthday_controller.dart' as _i1057;
 import '../module/change/character/change_character_controller.dart' as _i84;
@@ -460,6 +461,12 @@ extension GetItInjectableX on _i174.GetIt {
         gh<_i779.PaymentStatusManager>(),
       ),
     );
+    gh.factory<_i929.AutoRenewalController>(
+      () => _i929.AutoRenewalController(
+        gh<_i83.AccountRepository>(),
+        gh<_i987.StoreRepository>(),
+      ),
+    );
     gh.factory<_i731.MainController>(
       () => _i731.MainController(
         gh<_i83.AccountRepository>(),

+ 101 - 101
lib/dialog/tips_dialog.dart

@@ -24,123 +24,123 @@ class TipsDialog {
       backType: SmartBackType.block,
       clickMaskDismiss: true,
       maskColor: ColorName.black70,
+      alignment: Alignment.center,
       builder: (_) {
-        return Scaffold(
-          backgroundColor: Colors.transparent,
-          body: Column(
-            crossAxisAlignment: CrossAxisAlignment.center,
-            mainAxisAlignment: MainAxisAlignment.center,
-            children: [
-              Container(
-                width: double.infinity,
-                margin: EdgeInsets.symmetric(horizontal: 31.w),
-                decoration: ShapeDecoration(
-                  color: Colors.white,
-                  shape: RoundedRectangleBorder(
-                    borderRadius: BorderRadius.circular(20.r),
-                  ),
+        return Column(
+          crossAxisAlignment: CrossAxisAlignment.center,
+          mainAxisAlignment: MainAxisAlignment.center,
+          children: [
+            Container(
+              width: double.infinity,
+              margin: EdgeInsets.symmetric(horizontal: 31.w),
+              decoration: ShapeDecoration(
+                color: Colors.white,
+                shape: RoundedRectangleBorder(
+                  borderRadius: BorderRadius.circular(20.r),
                 ),
-                child: Stack(
-                  children: [
-                    Container(
-                      padding: EdgeInsets.symmetric(
-                        horizontal: 16.w,
-                        vertical: 24.h,
-                      ),
-                      child: Column(
-                        mainAxisSize: MainAxisSize.min,
-                        crossAxisAlignment: CrossAxisAlignment.center,
-                        mainAxisAlignment: MainAxisAlignment.center,
-                        children: [
-                          Text(
-                            title ?? "",
-                            style: Styles.getTextStyleBlack204W500(16.sp),
-                          ),
-                          SizedBox(height: 16.h),
-                          Text(
-                            desc ?? "",
-                            style: Styles.getTextStyleBlack204W400(14.sp),
-                          ),
-                          SizedBox(height: 20.h),
-                          Row(
-                            mainAxisAlignment: MainAxisAlignment.spaceBetween,
-                            children: [
-                              Expanded(
-                                child: GestureDetector(
-                                  onTap: () {
-                                    if (btnCancel != null) {
-                                      btnCancel();
-                                    }
-                                    SmartDialog.dismiss();
-                                  },
-                                  child: Container(
-                                    height: 48.h,
-                                    alignment: Alignment.center,
-                                    decoration: ShapeDecoration(
-                                      color: const Color(0xFFF5F4F9),
-                                      shape: RoundedRectangleBorder(
-                                        borderRadius: BorderRadius.circular(
-                                          31.r,
-                                        ),
+              ),
+              child: Stack(
+                children: [
+                  Container(
+                    padding: EdgeInsets.symmetric(
+                      horizontal: 16.w,
+                      vertical: 24.h,
+                    ),
+                    child: Column(
+                      mainAxisSize: MainAxisSize.min,
+                      crossAxisAlignment: CrossAxisAlignment.center,
+                      mainAxisAlignment: MainAxisAlignment.center,
+                      children: [
+                        Text(
+                          title ?? "",
+                          style: Styles.getTextStyleBlack204W500(16.sp),
+                        ),
+                        SizedBox(height: 16.h),
+                        Text(
+                          desc ?? "",
+                          style: Styles.getTextStyleBlack204W400(14.sp),
+                        ),
+                        SizedBox(height: 20.h),
+                        Row(
+                          mainAxisAlignment: MainAxisAlignment.spaceBetween,
+                          children: [
+                            Expanded(
+                              child: GestureDetector(
+                                onTap: () {
+                                  if (btnCancel != null) {
+                                    btnCancel();
+                                  }
+                                  SmartDialog.dismiss();
+                                },
+                                child: Container(
+                                  height: 48.h,
+                                  alignment: Alignment.center,
+                                  decoration: ShapeDecoration(
+                                    color: const Color(0xFFF5F4F9),
+                                    shape: RoundedRectangleBorder(
+                                      borderRadius: BorderRadius.circular(
+                                        31.r,
                                       ),
                                     ),
-                                    child: Text(
-                                      btnCancelText ?? "",
-                                      style: Styles.getTextStyleBlack204W500(
-                                        16.sp,
-                                      ),
+                                  ),
+                                  child: Text(
+                                    btnCancelText ?? "",
+                                    style: TextStyle(
+                                      color: Color(0xFF949396),
+                                      fontSize: 16.sp,
+                                      fontWeight: FontWeight.w500,
                                     ),
                                   ),
                                 ),
                               ),
-                              SizedBox(width: 16.w),
-                              Expanded(
-                                child: GestureDetector(
-                                  onTap: () {
-                                    if (btnConfirm != null) {
-                                      btnConfirm();
-                                    }
-                                    SmartDialog.dismiss(tag: tag);
-                                  },
-                                  child: Container(
-                                    height: 48.h,
-                                    alignment: Alignment.center,
-                                    decoration:
-                                        Styles.getActivateButtonDecoration(
-                                          31.r,
-                                        ),
-                                    child: Text(
-                                      btnConfirmText ?? "",
-                                      style: Styles.getTextStyleWhiteW500(
-                                        16.sp,
-                                      ),
+                            ),
+                            SizedBox(width: 16.w),
+                            Expanded(
+                              child: GestureDetector(
+                                onTap: () {
+                                  if (btnConfirm != null) {
+                                    btnConfirm();
+                                  }
+                                  SmartDialog.dismiss(tag: tag);
+                                },
+                                child: Container(
+                                  height: 48.h,
+                                  alignment: Alignment.center,
+                                  decoration:
+                                  Styles.getActivateButtonDecoration(
+                                    31.r,
+                                  ),
+                                  child: Text(
+                                    btnConfirmText ?? "",
+                                    style: Styles.getTextStyleWhiteW500(
+                                      16.sp,
                                     ),
                                   ),
                                 ),
                               ),
-                            ],
-                          ),
-                        ],
-                      ),
-                    ),
-                    Positioned(
-                      right: 14.w,
-                      top: 14.h,
-                      child: GestureDetector(
-                        onTap: () {
-                          SmartDialog.dismiss();
-                        },
-                        child: Assets.images.iconCustomDialogClose.image(
-                          width: 24.w,
-                          height: 24.h,
+                            ),
+                          ],
                         ),
+                      ],
+                    ),
+                  ),
+                  Positioned(
+                    right: 14.w,
+                    top: 14.h,
+                    child: GestureDetector(
+                      onTap: () {
+                        SmartDialog.dismiss();
+                      },
+                      child: Assets.images.iconCustomDialogClose.image(
+                        width: 24.w,
+                        height: 24.h,
                       ),
                     ),
-                  ],
-                ),
+                  ),
+                ],
               ),
-            ],
-          ),
+            ),
+          ],
         );
       },
     );

+ 91 - 0
lib/module/auto_renewal/auto_renewal_controller.dart

@@ -0,0 +1,91 @@
+import 'package:flutter/cupertino.dart';
+import 'package:get/get.dart';
+import 'package:injectable/injectable.dart';
+import 'package:keyboard/base/base_controller.dart';
+import 'package:keyboard/data/repository/account_repository.dart';
+import 'package:keyboard/resource/string.gen.dart';
+import 'package:keyboard/utils/toast_util.dart';
+
+import '../../data/repository/store_repository.dart';
+import '../../dialog/tips_dialog.dart';
+import '../../utils/atmob_log.dart';
+import '../../utils/http_handler.dart';
+
+@injectable
+class AutoRenewalController extends BaseController {
+  final tag = "AutoRenewalController";
+
+  final AccountRepository accountRepository;
+  final StoreRepository storeRepository;
+
+  RxBool get hasAutoRenewal => storeRepository.hasAutoRenewal;
+
+  AutoRenewalController(this.accountRepository, this.storeRepository) {
+    AtmobLog.d(tag, '$tag....init');
+    checkMemberAgreement();
+  }
+
+  @override
+  void onInit() {
+    super.onInit();
+
+    AtmobLog.d(tag, '$tag....onInit');
+  }
+
+  @override
+  void onReady() {
+    super.onReady();
+    AtmobLog.d(tag, '$tag....onReady');
+  }
+
+  @override
+  void onClose() {
+    super.onClose();
+    AtmobLog.d(tag, '$tag....onClose');
+  }
+
+  void clickBack() {
+    Get.back();
+
+  }
+
+  void clickUnSignAutoRenewal(){
+    TipsDialog.show(
+      title: StringName.tipsDialogTitle,
+      desc: StringName.autoRenewalTipDialogDesc,
+      btnConfirmText: StringName.dialogCancel,
+      btnCancelText: StringName.dialogClose,
+      btnCancel: () {
+        unSignAutoRenewal();
+      },
+    );
+  }
+
+  Future<void> unSignAutoRenewal() async {
+    AtmobLog.d(tag, '$tag....unSignAutoRenewal');
+    try {
+      await storeRepository.unSignMemberAgreement();
+      ToastUtil.show("已关闭自动续费服务");
+      checkMemberAgreement();
+    } catch (error) {
+      if (error is ServerErrorException) {
+        ToastUtil.show(error.message);
+      } else {
+        ToastUtil.show("请重试");
+      }
+    }
+  }
+
+  Future<void> checkMemberAgreement() async {
+    AtmobLog.d(tag, '$tag....checkMemberAgreement');
+    try {
+      await storeRepository.checkMemberAgreement();
+    } catch (error) {
+      if (error is ServerErrorException) {
+        ToastUtil.show(error.message);
+      } else {
+        debugPrint("checkMemberAgreement failed: $error");
+      }
+    }
+  }
+}

+ 117 - 0
lib/module/auto_renewal/auto_renewal_page.dart

@@ -0,0 +1,117 @@
+import 'package:flutter/Material.dart';
+import 'package:flutter/src/widgets/framework.dart';
+import 'package:flutter_screenutil/flutter_screenutil.dart';
+import 'package:keyboard/base/base_controller.dart';
+import 'package:keyboard/base/base_page.dart';
+import 'package:get/get.dart';
+import 'package:keyboard/module/auto_renewal/auto_renewal_controller.dart';
+import 'package:keyboard/resource/assets.gen.dart';
+
+import '../../resource/string.gen.dart';
+import '../../router/app_pages.dart';
+import '../../utils/styles.dart';
+import '../../widget/commonAppBar.dart';
+
+class AutoRenewalPage extends BasePage<AutoRenewalController> {
+  const AutoRenewalPage({super.key});
+
+  static start() {
+    Get.toNamed(RoutePath.autoRenewal);
+  }
+
+  @override
+  Color backgroundColor() {
+    return const Color(0xFFF6F5FA);
+  }
+
+  @override
+  bool immersive() {
+    return true;
+  }
+
+  @override
+  Widget buildBody(BuildContext context) {
+    return Scaffold(
+      backgroundColor: backgroundColor(),
+      appBar: CommonAppBar(
+        title: StringName.autoRenewalManagement,
+        backgroundColor: () {
+          return Colors.transparent;
+        },
+        onBack: () {
+          controller.clickBack();
+        },
+      ),
+      body: Obx(() {
+        return SizedBox(
+          width: double.infinity,
+          child:
+          controller.hasAutoRenewal.value
+              ? _hasAutoRenewal()
+              : _notAutoRenewal(),
+        );
+      }),
+    );
+  }
+
+  Widget _notAutoRenewal() {
+    return Column(
+      crossAxisAlignment: CrossAxisAlignment.center,
+      children: [
+        SizedBox(height: 200.h),
+        Assets.images.iconAutoRenewalNotSign.image(width: 96.w, height: 96.w),
+        Text(
+          StringName.autoRenewalNoService,
+          style: Styles.getTextStyleBlack204W400(14.sp),
+        ),
+      ],
+    );
+  }
+
+  Widget _hasAutoRenewal() {
+    return Container(
+      margin: EdgeInsets.only(left: 16.w, right: 16.w),
+      padding: EdgeInsets.only(left: 16.w, right: 10.w, top: 8.h, bottom: 8.h),
+      decoration: ShapeDecoration(
+        color: Colors.white,
+        shape: RoundedRectangleBorder(
+          borderRadius: BorderRadius.circular(12.r),
+        ),
+      ),
+      child: Row(
+        mainAxisAlignment: MainAxisAlignment.spaceBetween,
+        children: [
+          Text(
+            StringName.autoRenewalManagement,
+            style: Styles.getTextStyleBlack204W400(14.sp),
+          ),
+          Material(
+            color: Colors.transparent,
+            child: InkWell(
+              borderRadius: BorderRadius.circular(12.r),
+              onTap: () {
+                controller.clickUnSignAutoRenewal();
+              },
+              child: Container(
+                padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 8.h),
+                decoration: ShapeDecoration(
+                  shape: RoundedRectangleBorder(
+                    side: BorderSide(
+                        width: 1.w, color: const Color(0xFFD0D1D6)),
+                    borderRadius: BorderRadius.circular(12.r),
+                  ),
+                ),
+                child: Text(
+                  StringName.autoRenewalItemButtonDesc,
+                  style: Styles.getTextStyleBlack204W400(14.sp),
+                  textAlign: TextAlign.center,
+                ),
+              ),
+            ),
+          )
+
+        ],
+      ),
+    );
+  }
+}

+ 12 - 0
lib/module/mine/mine_controller.dart

@@ -7,6 +7,7 @@ import 'package:keyboard/base/base_controller.dart';
 import 'package:keyboard/data/api/response/user_info_response.dart';
 import 'package:keyboard/data/bean/member_info.dart';
 import 'package:keyboard/module/about/about_page.dart';
+import 'package:keyboard/module/auto_renewal/auto_renewal_page.dart';
 import 'package:keyboard/module/feedback/feedback_controller.dart';
 import 'package:keyboard/module/feedback/feedback_page.dart';
 import 'package:keyboard/module/user_info/user_info_page.dart';
@@ -120,6 +121,17 @@ class MineController extends BaseController {
     UserProfilePage.start();
   }
 
+  clickAutoRenewal(){
+    debugPrint('clickAutoRenewal');
+    if(isLogin){
+      AutoRenewalPage.start();
+    }else{
+      ToastUtil.show('请先登录');
+      LoginDialog.show();
+      return;
+    }
+  }
+
   clickFeedback(FeedbackType type) {
 
     if (isLogin) {

+ 30 - 18
lib/module/mine/mine_view.dart

@@ -1,3 +1,5 @@
+import 'dart:io';
+
 import 'package:flutter/material.dart';
 import 'package:flutter_screenutil/flutter_screenutil.dart';
 import 'package:keyboard/base/base_view.dart';
@@ -53,9 +55,9 @@ class MineView extends BaseView<MineController> {
       child: Column(
         children: [
           baseFunctionButton(
-            text: StringName.onlineCustomerService,
-            funIcon: Assets.images.iconMineOnlineCustomerService.path,
-            onTap: controller.clickOnlineCustomerService,
+            text: StringName.personalProfile,
+            funIcon: Assets.images.iconMinePersonalProfile.path,
+            onTap: controller.clickPersonalProfile,
           ),
 
           baseFunctionButton(
@@ -65,24 +67,34 @@ class MineView extends BaseView<MineController> {
           ),
 
           baseFunctionButton(
-            text: StringName.personalProfile,
-            funIcon: Assets.images.iconMinePersonalProfile.path,
-            onTap: controller.clickPersonalProfile,
+            text: StringName.onlineCustomerService,
+            funIcon: Assets.images.iconMineOnlineCustomerService.path,
+            onTap: controller.clickOnlineCustomerService,
           ),
 
+          if (Platform.isAndroid)
+            baseFunctionButton(
+              text: StringName.autoRenewalManagement,
+              funIcon: Assets.images.iconMineAutoRenewal.path,
+              onTap: controller.clickAutoRenewal,
+            ),
+
           baseFunctionButton(
             text: StringName.feedback,
             funIcon: Assets.images.iconMineFeedback.path,
-            onTap: (){controller.clickFeedback(FeedbackType.feedback);},
+            onTap: () {
+              controller.clickFeedback(FeedbackType.feedback);
+            },
           ),
 
           baseFunctionButton(
             text: StringName.complaintReport,
             funIcon: Assets.images.iconMineComplaint.path,
-            onTap: (){controller.clickFeedback(FeedbackType.complaint);},
+            onTap: () {
+              controller.clickFeedback(FeedbackType.complaint);
+            },
           ),
 
-
           baseFunctionButton(
             text: StringName.aboutUs,
             funIcon: Assets.images.iconMineAbout.path,
@@ -102,15 +114,15 @@ class MineView extends BaseView<MineController> {
           children: [
             controller.isLogin
                 ? Assets.images.iconMineUserLogged.image(
-              width: 56.r,
-              height: 56.r,
-              fit: BoxFit.contain,
-            )
+                  width: 56.r,
+                  height: 56.r,
+                  fit: BoxFit.contain,
+                )
                 : Assets.images.iconMineUserNoLogin.image(
-              width: 56.r,
-              height: 56.r,
-              fit: BoxFit.contain,
-            ),
+                  width: 56.r,
+                  height: 56.r,
+                  fit: BoxFit.contain,
+                ),
             SizedBox(width: 12.r),
             Text(
               controller.getUserName(),
@@ -150,7 +162,7 @@ class MineView extends BaseView<MineController> {
         onTap: controller.clickVip,
 
         child: Container(
-          padding: EdgeInsets.only(left: 15.w, right: 15.w,bottom: 88.w),
+          padding: EdgeInsets.only(left: 15.w, right: 15.w, bottom: 88.w),
           width: 326.w,
           child: Row(
             crossAxisAlignment: CrossAxisAlignment.end,

+ 10 - 0
lib/resource/assets.gen.dart

@@ -377,6 +377,10 @@ class $AssetsImagesGen {
   AssetGenImage get iconArrowRight =>
       const AssetGenImage('assets/images/icon_arrow_right.webp');
 
+  /// File path: assets/images/icon_auto_renewal_not_sign.webp
+  AssetGenImage get iconAutoRenewalNotSign =>
+      const AssetGenImage('assets/images/icon_auto_renewal_not_sign.webp');
+
   /// File path: assets/images/icon_black_back.webp
   AssetGenImage get iconBlackBack =>
       const AssetGenImage('assets/images/icon_black_back.webp');
@@ -884,6 +888,10 @@ class $AssetsImagesGen {
   AssetGenImage get iconMineArrow =>
       const AssetGenImage('assets/images/icon_mine_arrow.webp');
 
+  /// File path: assets/images/icon_mine_auto_renewal.webp
+  AssetGenImage get iconMineAutoRenewal =>
+      const AssetGenImage('assets/images/icon_mine_auto_renewal.webp');
+
   /// File path: assets/images/icon_mine_back_arrow.webp
   AssetGenImage get iconMineBackArrow =>
       const AssetGenImage('assets/images/icon_mine_back_arrow.webp');
@@ -1363,6 +1371,7 @@ class $AssetsImagesGen {
     iconAquarius,
     iconAries,
     iconArrowRight,
+    iconAutoRenewalNotSign,
     iconBlackBack,
     iconBlackBackArrow,
     iconCancer,
@@ -1480,6 +1489,7 @@ class $AssetsImagesGen {
     iconMemberRetainClose,
     iconMineAbout,
     iconMineArrow,
+    iconMineAutoRenewal,
     iconMineBackArrow,
     iconMineComplaint,
     iconMineFeedback,

+ 12 - 0
lib/resource/string.gen.dart

@@ -10,6 +10,7 @@ class StringName {
   static final String tutorials = 'tutorials'.tr; // 使用教程
   static final String personalProfile = 'personal_profile'.tr; // 个人档案
   static final String feedback = 'feedback'.tr; // 意见反馈
+  static final String autoRenewalManagement = 'auto_renewal_management'.tr; // 自动续费管理
   static final String aboutUs = 'about_us'.tr; // 关于我们
   static final String complaintReport = 'complaint_report'.tr; // 投诉举报
   static final String mineAccountLoggedDesc = 'mine_account_logged_desc'.tr; // 用户
@@ -359,6 +360,11 @@ class StringName {
   static final String zodiacLoveIntimacyFutureWeekTab = 'zodiac_love_intimacy_future_week_tab'.tr; // 未来一周
   static final String dialogCancel = 'dialog_cancel'.tr; // 取消
   static final String dialogConfirm = 'dialog_confirm'.tr; // 确定
+  static final String dialogClose = 'dialog_close'.tr; // 确认关闭
+  static final String autoRenewalNoService = 'auto_renewal_no_service'.tr; // 当前未开通自动续费服务
+  static final String autoRenewalTipDialogDesc = 'auto_renewal_tip_dialog_desc'.tr; // 关闭自动续费后,下个周期将无法继续享受会员服务
+  static final String autoRenewalItemTitle = 'auto_renewal_item_title'.tr; // 自动续费服务
+  static final String autoRenewalItemButtonDesc = 'auto_renewal_item_button_desc'.tr; // 关闭续订
 }
 class StringMultiSource {
   StringMultiSource._();
@@ -372,6 +378,7 @@ class StringMultiSource {
       'tutorials': '使用教程',
       'personal_profile': '个人档案',
       'feedback': '意见反馈',
+      'auto_renewal_management': '自动续费管理',
       'about_us': '关于我们',
       'complaint_report': '投诉举报',
       'mine_account_logged_desc': '用户',
@@ -721,6 +728,11 @@ class StringMultiSource {
       'zodiac_love_intimacy_future_week_tab': '未来一周',
       'dialog_cancel': '取消',
       'dialog_confirm': '确定',
+      'dialog_close': '确认关闭',
+      'auto_renewal_no_service': '当前未开通自动续费服务',
+      'auto_renewal_tip_dialog_desc': '关闭自动续费后,下个周期将无法继续享受会员服务',
+      'auto_renewal_item_title': '自动续费服务',
+      'auto_renewal_item_button_desc': '关闭续订',
     },
   };
 }

+ 8 - 0
lib/router/app_pages.dart

@@ -37,6 +37,8 @@ import 'package:keyboard/module/user_profile/user_profile_controller.dart';
 
 import '../di/get_it.dart';
 import '../module/about/about_page.dart';
+import '../module/auto_renewal/auto_renewal_controller.dart';
+import '../module/auto_renewal/auto_renewal_page.dart';
 import '../module/browser/browser_page.dart';
 import '../module/change/character/change_character_page.dart';
 import '../module/change/gender/change_gender_page.dart';
@@ -144,6 +146,9 @@ abstract class RoutePath {
 
   // 键盘使用教程引导-视频教程页
   static const keyboardTutorialVideo = '/keyboardTutorialVideo';
+
+  ///自动续费查询页
+  static const autoRenewal  = '/autoRenewal';
 }
 
 class AppBinding extends Bindings {
@@ -204,6 +209,7 @@ class AppBinding extends Bindings {
     lazyPut(() => getIt.get<ZodiacLoveFutureWeekController>());
 
     lazyPut(() => getIt.get<DeleteProfileConfirmController>());
+    lazyPut(() => getIt.get<AutoRenewalController>());
   }
 
   void lazyPut<S>(InstanceBuilderCallback<S> builder) {
@@ -266,4 +272,6 @@ final generalPages = [
     name: RoutePath.keyboardTutorialVideo,
     page: () => KeyboardTutorialVideoPage(),
   ),
+
+  GetPage(name: RoutePath.autoRenewal, page: () => AutoRenewalPage()),
 ];