Explorar o código

Merge remote-tracking branch 'origin/dev' into dev

# Conflicts:
#	packages/cs_resources/lib/generated/assets.dart
liukai hai 2 semanas
pai
achega
11822521d2
Modificáronse 91 ficheiros con 2153 adicións e 97 borrados
  1. 1 1
      app/android/app/build.gradle
  2. 4 0
      app/devtools_options.yaml
  3. 4 0
      packages/cpt_auth/devtools_options.yaml
  4. 4 0
      packages/cpt_community/devtools_options.yaml
  5. 4 0
      packages/cpt_facility/devtools_options.yaml
  6. 4 0
      packages/cpt_form/devtools_options.yaml
  7. 4 0
      packages/cpt_main/devtools_options.yaml
  8. 4 0
      packages/cpt_notice_board/devtools_options.yaml
  9. 4 0
      packages/cpt_payment/devtools_options.yaml
  10. 4 0
      packages/cpt_profile/devtools_options.yaml
  11. 4 0
      packages/cpt_property/devtools_options.yaml
  12. 130 0
      packages/cpt_property/lib/components/bottomDialog.dart
  13. 399 0
      packages/cpt_property/lib/modules/ioan/property_ioan_page.dart
  14. 39 0
      packages/cpt_property/lib/modules/ioan/property_ioan_state.dart
  15. 137 0
      packages/cpt_property/lib/modules/ioan/property_ioan_vm.dart
  16. 3 3
      packages/cpt_property/lib/modules/ioan/vm/property_ioan_vm.g.dart
  17. 157 2
      packages/cpt_property/lib/modules/news/page/property_news_page.dart
  18. 49 0
      packages/cpt_property/lib/modules/news/page/property_news_state.dart
  19. 71 0
      packages/cpt_property/lib/modules/news/repository/property_news_repository.dart
  20. 29 0
      packages/cpt_property/lib/modules/news/repository/property_news_repository.g.dart
  21. 122 3
      packages/cpt_property/lib/modules/news/vm/property_news_vm.dart
  22. 3 3
      packages/cpt_property/lib/modules/news/vm/property_news_vm.g.dart
  23. 9 9
      packages/cpt_property/lib/modules/ioan/page/property_ioan_page.dart
  24. 2 2
      packages/cpt_property/lib/modules/ioan/vm/property_ioan_vm.dart
  25. 27 0
      packages/cpt_property/lib/modules/news_detail/property_news_detail_vm.g.dart
  26. 20 9
      packages/cpt_property/lib/modules/property/page/property_page.dart
  27. 62 40
      packages/cpt_property/lib/modules/property/vm/property_vm.dart
  28. 1 1
      packages/cpt_property/lib/modules/property/vm/property_vm.g.dart
  29. 126 2
      packages/cpt_property/lib/modules/rent/page/property_rent_page.dart
  30. 49 0
      packages/cpt_property/lib/modules/rent/page/property_rent_state.dart
  31. 70 0
      packages/cpt_property/lib/modules/rent/repository/property_rent_repository.dart
  32. 29 0
      packages/cpt_property/lib/modules/rent/repository/property_rent_repository.g.dart
  33. 92 3
      packages/cpt_property/lib/modules/rent/vm/property_rent_vm.dart
  34. 3 3
      packages/cpt_property/lib/modules/rent/vm/property_rent_vm.g.dart
  35. 106 2
      packages/cpt_property/lib/modules/sale/page/property_sale_page.dart
  36. 49 0
      packages/cpt_property/lib/modules/sale/page/property_sale_state.dart
  37. 70 0
      packages/cpt_property/lib/modules/sale/repository/property_sale_repository.dart
  38. 29 0
      packages/cpt_property/lib/modules/sale/repository/property_sale_repository.g.dart
  39. 90 3
      packages/cpt_property/lib/modules/sale/vm/property_sale_vm.dart
  40. 3 3
      packages/cpt_property/lib/modules/sale/vm/property_sale_vm.g.dart
  41. 9 1
      packages/cpt_property/lib/router/page/property_page_router.dart
  42. 20 0
      packages/cpt_property/lib/router/page/property_page_router.gr.dart
  43. 6 0
      packages/cpt_property/pubspec.yaml
  44. 4 0
      packages/cpt_rewards/devtools_options.yaml
  45. 4 0
      packages/cpt_services/devtools_options.yaml
  46. 4 0
      packages/cs_domain/devtools_options.yaml
  47. 14 7
      packages/cs_domain/lib/generated/json/base/json_convert_content.dart
  48. 4 0
      packages/cs_initializer/devtools_options.yaml
  49. 4 0
      packages/cs_plugin_basic/devtools_options.yaml
  50. 4 0
      packages/cs_plugin_platform/devtools_options.yaml
  51. BIN=BIN
      packages/cs_resources/assets/community/camera.webp
  52. BIN=BIN
      packages/cs_resources/assets/community/comments.webp
  53. BIN=BIN
      packages/cs_resources/assets/community/follow_add.webp
  54. BIN=BIN
      packages/cs_resources/assets/community/garage_sale.webp
  55. BIN=BIN
      packages/cs_resources/assets/community/like.webp
  56. BIN=BIN
      packages/cs_resources/assets/community/like_active.webp
  57. BIN=BIN
      packages/cs_resources/assets/community/nes_feed.webp
  58. BIN=BIN
      packages/cs_resources/assets/community/share.webp
  59. BIN=BIN
      packages/cs_resources/assets/property/advice_pic.webp
  60. BIN=BIN
      packages/cs_resources/assets/property/advice_pic@2x.png
  61. BIN=BIN
      packages/cs_resources/assets/property/approval.webp
  62. BIN=BIN
      packages/cs_resources/assets/property/approval@2x.png
  63. BIN=BIN
      packages/cs_resources/assets/property/collection.webp
  64. BIN=BIN
      packages/cs_resources/assets/property/collection_active.webp
  65. BIN=BIN
      packages/cs_resources/assets/property/conveyancing_lawyer.webp
  66. BIN=BIN
      packages/cs_resources/assets/property/conveyancing_lawyer@2x.png
  67. BIN=BIN
      packages/cs_resources/assets/property/home_equity_loans.webp
  68. BIN=BIN
      packages/cs_resources/assets/property/home_equity_loans@2x.png
  69. BIN=BIN
      packages/cs_resources/assets/property/home_loan_bg.webp
  70. BIN=BIN
      packages/cs_resources/assets/property/home_loan_bg@2x.png
  71. BIN=BIN
      packages/cs_resources/assets/property/ioan.webp
  72. BIN=BIN
      packages/cs_resources/assets/property/ioan@2x.png
  73. BIN=BIN
      packages/cs_resources/assets/property/new_home_loans.webp
  74. BIN=BIN
      packages/cs_resources/assets/property/new_home_loans@2x.png
  75. BIN=BIN
      packages/cs_resources/assets/property/news-item-bg.webp
  76. BIN=BIN
      packages/cs_resources/assets/property/news.webp
  77. BIN=BIN
      packages/cs_resources/assets/property/news@2x.png
  78. BIN=BIN
      packages/cs_resources/assets/property/our_partners.webp
  79. BIN=BIN
      packages/cs_resources/assets/property/our_partners@2x.png
  80. BIN=BIN
      packages/cs_resources/assets/property/overseas_home_loan.webp
  81. BIN=BIN
      packages/cs_resources/assets/property/overseas_home_loan@2x.png
  82. BIN=BIN
      packages/cs_resources/assets/property/refinancing.webp
  83. BIN=BIN
      packages/cs_resources/assets/property/refinancing@2x.png
  84. BIN=BIN
      packages/cs_resources/assets/property/rent.webp
  85. BIN=BIN
      packages/cs_resources/assets/property/rent@2x.png
  86. BIN=BIN
      packages/cs_resources/assets/property/sale.webp
  87. BIN=BIN
      packages/cs_resources/assets/property/sale@2x.png
  88. 1 0
      packages/cs_resources/pubspec.yaml
  89. 1 0
      packages/cs_router/lib/path/router_path.dart
  90. 26 0
      packages/cs_shared/lib/utils/color_utils.dart
  91. 35 0
      packages/cs_shared/lib/utils/util.dart

+ 1 - 1
app/android/app/build.gradle

@@ -49,7 +49,7 @@ android {
     }
 
     defaultConfig {
-        applicationId "com.hongyegroup.property_management"
+        applicationId "com.hongyegroup.proanperty_management"
         minSdkVersion 21
         targetSdkVersion 34
         versionCode 100          //Android打包上线记得要加固并重新签名再传

+ 4 - 0
app/devtools_options.yaml

@@ -0,0 +1,4 @@
+description: This file stores settings for Dart & Flutter DevTools.
+documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
+extensions:
+  - provider: true

+ 4 - 0
packages/cpt_auth/devtools_options.yaml

@@ -0,0 +1,4 @@
+description: This file stores settings for Dart & Flutter DevTools.
+documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
+extensions:
+  - provider: true

+ 4 - 0
packages/cpt_community/devtools_options.yaml

@@ -0,0 +1,4 @@
+description: This file stores settings for Dart & Flutter DevTools.
+documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
+extensions:
+  - provider: true

+ 4 - 0
packages/cpt_facility/devtools_options.yaml

@@ -0,0 +1,4 @@
+description: This file stores settings for Dart & Flutter DevTools.
+documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
+extensions:
+  - provider: true

+ 4 - 0
packages/cpt_form/devtools_options.yaml

@@ -0,0 +1,4 @@
+description: This file stores settings for Dart & Flutter DevTools.
+documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
+extensions:
+  - provider: true

+ 4 - 0
packages/cpt_main/devtools_options.yaml

@@ -0,0 +1,4 @@
+description: This file stores settings for Dart & Flutter DevTools.
+documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
+extensions:
+  - provider: true

+ 4 - 0
packages/cpt_notice_board/devtools_options.yaml

@@ -0,0 +1,4 @@
+description: This file stores settings for Dart & Flutter DevTools.
+documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
+extensions:
+  - provider: true

+ 4 - 0
packages/cpt_payment/devtools_options.yaml

@@ -0,0 +1,4 @@
+description: This file stores settings for Dart & Flutter DevTools.
+documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
+extensions:
+  - provider: true

+ 4 - 0
packages/cpt_profile/devtools_options.yaml

@@ -0,0 +1,4 @@
+description: This file stores settings for Dart & Flutter DevTools.
+documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
+extensions:
+  - provider: true

+ 4 - 0
packages/cpt_property/devtools_options.yaml

@@ -0,0 +1,4 @@
+description: This file stores settings for Dart & Flutter DevTools.
+documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
+extensions:
+  - provider: true

+ 130 - 0
packages/cpt_property/lib/components/bottomDialog.dart

@@ -0,0 +1,130 @@
+
+import 'package:flutter/material.dart';
+import 'package:cs_resources/generated/l10n.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:cs_resources/theme/app_colors_theme.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/no_shadow_scroll_behavior.dart';
+import 'package:widgets/widget_export.dart';
+
+class BottomDialog extends StatelessWidget {
+  String? title;
+  String? message;
+  Widget? Function(BuildContext)? messageBuilder;
+  VoidCallback confirmAction;
+  VoidCallback? cancelAction;
+  bool isShowCancelBtn;
+  String? confirmTxt;
+  String? cancelTxt;
+  final double? minHeight;
+  final double? maxHeight;
+
+  BottomDialog({
+    this.title,
+    this.message,
+    Widget Function(BuildContext)? this.messageBuilder,
+    required this.confirmAction,
+    this.cancelAction,
+    this.isShowCancelBtn = true,
+    this.confirmTxt,
+    this.cancelTxt,
+    minHeight,
+    maxHeight,
+    Key? key,
+  }): minHeight = minHeight?? 0,
+      maxHeight = maxHeight?? 300,
+        super(key:key);
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      width: double.infinity,
+      padding: const EdgeInsets.only(top: 30),
+      constraints: BoxConstraints(
+        minHeight: minHeight!,
+        maxHeight: maxHeight!,
+      ),
+      decoration: BoxDecoration(
+        color: context.appColors.whiteSecondBG,
+        borderRadius: const BorderRadius.only(
+          topLeft: Radius.circular(0),
+          topRight: Radius.circular(0),
+        ),
+      ),
+      child: Column(
+        children: [
+          Scrollbar(
+            child: ScrollConfiguration(
+              behavior: NoShadowScrollBehavior(),
+              child: SingleChildScrollView(
+                child: messageBuilder?.call(context) ??
+                  MyTextView(
+                    message!,
+                    fontSize: 18,
+                    textColor: context.appColors.textBlack,
+                    isFontRegular: true,
+                    textAlign: TextAlign.center,
+                    paddingLeft: 30,
+                    paddingRight: 30,
+                  ),
+              ),
+            ),
+          ).constrained(maxHeight: maxHeight! - 60),
+          Row(
+            children: [
+              const SizedBox(width: 18),
+              Visibility(
+                visible: isShowCancelBtn,
+                child: Expanded(
+                    flex: 1,
+                    child: InkWell(
+                      onTap: () {
+                        onCancel();
+                        cancelAction?.call();
+                      },
+                      child: MyTextView(
+                        cancelTxt ?? S.current.no,
+                        fontSize: 16,
+                        isFontMedium: true,
+                        paddingTop: 13,
+                        marginRight: 15,
+                        paddingBottom: 13,
+                        textAlign: TextAlign.center,
+                        textColor: Colors.white,
+                        backgroundColor: context.appColors.orangeBG,
+                        cornerRadius: 7,
+                      ),
+                    )),
+              ),
+              Expanded(
+                  flex: 1,
+                  child: InkWell(
+                    onTap: () async {
+                      onCancel();
+                      confirmAction();
+                    },
+                    child: MyTextView(
+                      confirmTxt ?? S.current.yes,
+                      fontSize: 16,
+                      paddingTop: 13,
+                      paddingBottom: 13,
+                      isFontMedium: true,
+                      textAlign: TextAlign.center,
+                      textColor: Colors.white,
+                      backgroundColor: context.appColors.btnBgDefault,
+                      cornerRadius: 7,
+                    ),
+                  )),
+              const SizedBox(width: 18),
+            ],
+          ).marginOnly(bottom: 30, top: 28),
+        ],
+      ),
+    );
+  }
+
+  //取消弹框
+  void onCancel() async {
+    SmartDialog.dismiss();
+  }
+}

+ 399 - 0
packages/cpt_property/lib/modules/ioan/property_ioan_page.dart

@@ -0,0 +1,399 @@
+import 'package:cpt_property/components/bottomDialog.dart';
+import 'package:cs_resources/generated/assets.dart';
+import 'package:flutter/material.dart';
+import 'package:auto_route/auto_route.dart';
+import 'package:hooks_riverpod/hooks_riverpod.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:router/ext/auto_router_extensions.dart';
+import 'package:shared/utils/color_utils.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/my_text_view.dart';
+
+import '../../../router/page/property_page_router.dart';
+import 'property_ioan_vm.dart';
+
+@RoutePage()
+class PropertyIoanPage extends HookConsumerWidget {
+  const PropertyIoanPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance({BuildContext? context}) {
+    if (context != null) {
+      context.router.push(const PropertyIoanPageRoute());
+    } else {
+      appRouter.push(const PropertyIoanPageRoute());
+    }
+  }
+
+  Widget _buildContentTopAdviceSection(BuildContext context,WidgetRef ref, _vm){
+    return Column(
+      children: [
+        MyTextView(
+          "YY Home",
+          textColor: ColorUtils.string2Color('#000000'),
+          fontSize: 27,
+          fontWeight: FontWeight.w500,
+          textAlign: TextAlign.center,
+        ),
+        MyTextView(
+          "Find the best home loan for you",
+          textColor: ColorUtils.string2Color('#000000'),
+          fontSize: 16,
+          fontWeight: FontWeight.w400,
+          marginBottom: 14,
+          textAlign: TextAlign.center,
+        ),
+        Container(
+          width: double.infinity,
+          height: 210,
+          decoration: BoxDecoration(
+            borderRadius: BorderRadius.circular(0),
+            color: ColorUtils.string2Color('#FEFEFE'),
+            image: const DecorationImage(
+              image: AssetImage('packages/cs_resources/${Assets.propertyHomeLoanBg}'), // 使用包中的资源
+              fit: BoxFit.cover,
+            ),
+          ),
+          child: Column(
+            children: [
+              MyTextView(
+                "YY Home exclusive rates:",
+                textColor: ColorUtils.string2Color('#FEFEFE'),
+                fontSize: 15,
+                boxWidth: 237,
+                boxHeight: 35,
+                alignment: Alignment.center,
+                textAlign: TextAlign.center,
+                marginTop: 5.5,
+                backgroundColor: ColorUtils.string2Color('#4161D0')
+              ),
+              Expanded(
+                child: Row(
+                  mainAxisAlignment: MainAxisAlignment.center,
+                  children: [
+                    Container(
+                        width: 105,
+                        height: 105,
+                        padding: const EdgeInsets.all(5),
+                        color: ColorUtils.string2Color('#4161D0'),
+                        child: Column(
+                          mainAxisAlignment: MainAxisAlignment.center,
+                          crossAxisAlignment: CrossAxisAlignment.center,
+                          children: [
+                            MyTextView(
+                              _vm.state.lowestFloatingRate,
+                              textColor: ColorUtils.string2Color('#FEFEFE'),
+                              fontSize: 30,
+                            ),
+                            MyTextView(
+                              "Lowest Floating Rate",
+                              textColor: ColorUtils.string2Color('#FEFEFE'),
+                              fontSize: 14,
+                              textAlign: TextAlign.center,
+                            ),
+                          ]
+                        )
+                    ),
+                    Container(
+                        width: 105,
+                        height: 105,
+                        padding: const EdgeInsets.all(5),
+                        color: ColorUtils.string2Color('#4161D0'),
+                        margin: const EdgeInsets.only(left: 18),
+                        child: Column(
+                            mainAxisAlignment: MainAxisAlignment.center,
+                            crossAxisAlignment: CrossAxisAlignment.center,
+                            children: [
+                              MyTextView(
+                                _vm.state.lowestFixedRate,
+                                textColor: ColorUtils.string2Color('#FEFEFE'),
+                                fontSize: 30,
+                              ),
+                              MyTextView(
+                                "Lowest Floating Rate",
+                                textColor: ColorUtils.string2Color('#FEFEFE'),
+                                fontSize: 14,
+                                textAlign: TextAlign.center,
+                              ),
+                            ]
+                        )
+                    ),
+                  ],
+                ),
+              ),
+            ],
+          ),
+        ),
+        MyTextView(
+          "Check out what others are offering:",
+          textColor: ColorUtils.string2Color('#FEFEFE'),
+          fontSize: 15,
+          boxWidth: double.infinity,
+          boxHeight: 40.5,
+          alignment: Alignment.center,
+          textAlign: TextAlign.center,
+          backgroundColor: ColorUtils.string2Color('#4161D0'),
+        ),
+
+        const SizedBox(height: 20),
+
+        Row(
+          mainAxisAlignment: MainAxisAlignment.start,
+          children: [
+            MyLoadImage(
+              Assets.propertyAdvicePic,
+              width: 132,
+              // height: 122.5,
+            ),
+            Expanded(
+              child: Container(
+                // color: Colors.red,
+                padding: const EdgeInsets.only(left: 50,right: 20),
+                child: Column(
+                  // mainAxisAlignment: MainAxisAlignment.end,
+                  crossAxisAlignment: CrossAxisAlignment.start,
+                  children: [
+                    Row(
+                      mainAxisAlignment: MainAxisAlignment.center,
+                      children: [
+                        MyTextView(
+                          "Floating",
+                          textColor: ColorUtils.string2Color('#000000'),
+                          fontSize: 14,
+                          textAlign: TextAlign.center,
+                        ),
+                        MyTextView(
+                          "Fixed",
+                          textColor: ColorUtils.string2Color('#000000'),
+                          fontSize: 14,
+                          textAlign: TextAlign.center,
+                          marginLeft: 47.5,
+                        ),
+                      ],
+                    ),
+                    // const SizedBox(height: 10),
+
+                    Expanded(child: Column(
+                      mainAxisAlignment: MainAxisAlignment.center,
+                      children: [
+                        Row(
+                          mainAxisAlignment: MainAxisAlignment.center,
+                          children: [
+                            MyTextView(
+                              "3.08%",
+                              textColor: ColorUtils.string2Color('#000000'),
+                              fontSize: 16,
+                              textAlign: TextAlign.center,
+                              fontWeight: FontWeight.w500,
+                              marginLeft: 20,
+                            ),
+                            MyTextView(
+                              "2.50%",
+                              textColor: ColorUtils.string2Color('#000000'),
+                              fontSize: 16,
+                              textAlign: TextAlign.center,
+                              fontWeight: FontWeight.w500,
+                              marginLeft: 47.5,
+                            ),
+                          ],
+                        ),
+                        Row(
+                          mainAxisAlignment: MainAxisAlignment.center,
+                          children: [
+                            MyTextView(
+                              "3.08%",
+                              textColor: ColorUtils.string2Color('#000000'),
+                              fontSize: 16,
+                              textAlign: TextAlign.center,
+                              fontWeight: FontWeight.w500,
+                              marginLeft: 20,
+                            ),
+                            MyTextView(
+                              "2.50%",
+                              textColor: ColorUtils.string2Color('#000000'),
+                              fontSize: 16,
+                              textAlign: TextAlign.center,
+                              fontWeight: FontWeight.w500,
+                              marginLeft: 47.5,
+                            ),
+                          ],
+                        ).marginOnly(top: 15),
+                        Row(
+                          mainAxisAlignment: MainAxisAlignment.center,
+                          children: [
+                            MyTextView(
+                              "3.08%",
+                              textColor: ColorUtils.string2Color('#000000'),
+                              fontSize: 16,
+                              textAlign: TextAlign.center,
+                              fontWeight: FontWeight.w500,
+                              marginLeft: 20,
+                            ),
+                            MyTextView(
+                              "2.50%",
+                              textColor: ColorUtils.string2Color('#000000'),
+                              fontSize: 16,
+                              textAlign: TextAlign.center,
+                              fontWeight: FontWeight.w500,
+                              marginLeft: 47.5,
+                            ),
+                          ],
+                        ).marginOnly(top: 15),
+                      ],
+                    ))
+
+
+                  ],
+                ),
+              ),
+            ),
+          ],
+        ).constrained(height: 160),
+      ],
+    );
+  }
+
+  Widget _buildContentMiddleTextSection(BuildContext context,WidgetRef ref, _vm) {
+    return Column(
+        children: [
+          MyTextView(
+            "The right advice to help you choose the best package in the market!",
+            textColor: ColorUtils.string2Color('#000000'),
+            fontSize: 18,
+            fontWeight: FontWeight.w500,
+            marginTop: 20,
+            marginBottom: 20,
+            textAlign: TextAlign.center,
+          ),
+          MyTextView(
+            "-No Hidden Fees, We Are Out ToHelp You!-Interest Savings With Lowest RatesGuarantee-One-Stop Access to All The BanksPackages",
+            textColor: ColorUtils.string2Color('#000000'),
+            fontSize: 15,
+            textAlign: TextAlign.center,
+            marginBottom: 20,
+          ),
+        ],
+    );
+  }
+
+  Widget _buildContentOfferSection(BuildContext context,WidgetRef ref, _vm) {
+    final offerTextInfoList = _vm.state.offerTextInfoList.map((value) => value).toList();
+    return Container(
+      width: double.infinity,
+      child: Column(
+        children: [
+          MyTextView(
+           "What do we offer?",
+            textColor: ColorUtils.string2Color('#000000'),
+            fontSize: 18,
+            fontWeight: FontWeight.w500,
+            marginTop: 16.5,
+            marginBottom: 16.5,
+          ),
+          Wrap(
+            children: List.generate(offerTextInfoList.length, (index){
+              return Container(
+                width: MediaQuery.of(context).size.width / 2 - 100,
+                margin: const EdgeInsets.only(right: 15,bottom: 15),
+                padding: const EdgeInsets.only(left: 15,right: 15,top:15,bottom:15,),
+                // decoration: BoxDecoration(
+                //   borderRadius: BorderRadius.circular(10),
+                //   color: ColorUtils.string2Color('#F5F5F5'),
+                // ),
+                child: Column(
+                  children: [
+                    MyLoadImage(
+                      offerTextInfoList[index]["icon"],
+                      width: offerTextInfoList[index]["iconWidth"],
+                      height: offerTextInfoList[index]["iconHeight"],
+                    ),
+                    const SizedBox(height: 13,),
+                    MyTextView(
+                      offerTextInfoList[index]["title"],
+                      fontSize: 15,
+                      textColor: ColorUtils.string2Color('#000000'),
+                      textAlign: TextAlign.center,
+                    ),
+                  ]
+                ),
+              );
+            }),
+          ),
+        ]
+      ),
+    );
+  }
+
+  Widget _buildContentBottomPartnersSection(BuildContext context,WidgetRef ref, _vm) {
+    return Column(
+      mainAxisAlignment: MainAxisAlignment.center,
+      crossAxisAlignment: CrossAxisAlignment.center,
+      children: [
+        MyTextView(
+          "Our Partners",
+          textColor: ColorUtils.string2Color('#000000'),
+          fontSize: 18,
+          fontWeight: FontWeight.w500,
+          marginBottom: 16.5,
+        ),
+        MyLoadImage(Assets.propertyOurPartners,),
+      ],
+    );
+  }
+
+  Widget _buildCotentBox(BuildContext context,WidgetRef ref, _vm) {
+    return Column(
+      children: [
+        _buildContentTopAdviceSection(context, ref, _vm),
+        const SizedBox(height: 15,),
+        _buildContentMiddleTextSection(context, ref, _vm),
+        const SizedBox(height: 15,),
+        _buildContentOfferSection(context, ref, _vm),
+        const SizedBox(height: 15,),
+        _buildContentBottomPartnersSection(context, ref, _vm),
+      ],
+    );
+  }
+
+
+  @override
+  Widget build(BuildContext context, WidgetRef ref) {
+    final _vm = ref.read(propertyIoanVmProvider.notifier);
+
+    return Scaffold(
+      backgroundColor: ColorUtils.string2Color("#F2F3F6"),
+      // appBar: AppBar(title: Text("资产")),
+      body: Column(
+        children: [
+          Expanded(
+            child: SingleChildScrollView(
+              child: Padding(
+                  padding: const EdgeInsets.only(left: 15,right: 15,top: 15),
+                  child: _buildCotentBox(context, ref, _vm),
+              )
+            )
+          ),
+          Container(
+            height: 50,
+            color: ColorUtils.string2Color('#4161D0'),
+            child: Row(
+              mainAxisAlignment: MainAxisAlignment.center,
+              children: [
+                // MyLoadImage(Assets.propertyIoanItemBg,width: 60,height: 50,),
+                const SizedBox(width: 10,),
+                MyTextView(
+                  "Request a Quote",
+                  fontSize: 16,
+                  textColor: Colors.white,
+                ),
+              ],
+            ),
+          ).onTap((){
+            _vm.handlerRequestQuote(context);
+          })
+        ],
+      ),
+    );
+  }
+}

+ 39 - 0
packages/cpt_property/lib/modules/ioan/property_ioan_state.dart

@@ -0,0 +1,39 @@
+/// YApi QuickType插件生成,具体参考文档:https://plugins.jetbrains.com/plugin/18847-yapi-quicktype/documentation
+
+import 'dart:convert';
+
+PropertyIoanState propertyIoanStateFromJson(String str) => PropertyIoanState.fromJson(json.decode(str));
+
+String propertyIoanStateToJson(PropertyIoanState data) => json.encode(data.toJson());
+
+class PropertyIoanState {
+    PropertyIoanState({
+        required this.offerTextInfoList,
+        required this.lowestFloatingRate,
+        required this.othersOfferingPic,
+        required this.lowestFixedRate,
+        required this.othersOfferingInfoList,
+    });
+
+    List<dynamic> offerTextInfoList;
+    String lowestFloatingRate;
+    String othersOfferingPic;
+    String lowestFixedRate;
+    List<dynamic> othersOfferingInfoList;
+
+    factory PropertyIoanState.fromJson(Map<dynamic, dynamic> json) => PropertyIoanState(
+        offerTextInfoList: List<dynamic>.from(json["offerTextInfoList"].map((x) => x)),
+        lowestFloatingRate: json["lowestFloatingRate"],
+        othersOfferingPic: json["othersOfferingPic"],
+        lowestFixedRate: json["lowestFixedRate"],
+        othersOfferingInfoList: List<dynamic>.from(json["othersOfferingInfoList"].map((x) => x)),
+    );
+
+    Map<dynamic, dynamic> toJson() => {
+        "offerTextInfoList": List<dynamic>.from(offerTextInfoList.map((x) => x)),
+        "lowestFloatingRate": lowestFloatingRate,
+        "othersOfferingPic": othersOfferingPic,
+        "lowestFixedRate": lowestFixedRate,
+        "othersOfferingInfoList": List<dynamic>.from(othersOfferingInfoList.map((x) => x)),
+    };
+}

+ 137 - 0
packages/cpt_property/lib/modules/ioan/property_ioan_vm.dart

@@ -0,0 +1,137 @@
+
+import 'package:cs_resources/generated/assets.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:plugin_platform/engine/dialog/dialog_engine.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:riverpod_annotation/riverpod_annotation.dart';
+import 'package:shared/utils/color_utils.dart';
+import 'package:shared/utils/log_utils.dart';
+import 'package:widgets/my_text_view.dart';
+import '../../components/bottomDialog.dart';
+import './property_ioan_state.dart';
+
+part 'property_ioan_vm.g.dart';
+
+@riverpod
+class PropertyIoanVm extends _$PropertyIoanVm {
+  PropertyIoanState initState() {
+    return PropertyIoanState(
+        lowestFloatingRate: "3.79%",
+        lowestFixedRate: "2.48%",
+        othersOfferingPic: "",
+        othersOfferingInfoList: [
+          {
+            "floating": "3.08%",
+            "fixed": "3.79%",
+          },
+          {
+            "floating": "3.08%",
+            "fixed": "3.79%",
+          }
+        ],
+        offerTextInfoList: [
+            {
+              "title": "New HomeLoans",
+              "icon": Assets.propertyNewHomeLoans,
+              "iconWidth": 46.0,
+              "iconHeight": 42.5
+            },
+            {
+              "title": "Refinancing",
+              "icon": Assets.propertyRefinancing,
+              "iconWidth": 37.0,
+              "iconHeight": 41.5
+            },
+            {
+              "title": "Home EquityLoans",
+              "icon": Assets.propertyHomeEquityLoans,
+              "iconWidth": 41.5,
+              "iconHeight": 42.5
+            },
+            {
+              "title": "ConveyancingLawyer",
+              "icon": Assets.propertyConveyancingLawyer,
+              "iconWidth": 42.0,
+              "iconHeight": 42.0
+            },
+            {
+              "title": "Approval in Principle",
+              "icon": Assets.propertyApproval,
+              "iconWidth": 41.0,
+              "iconHeight": 39.0
+            },
+            {
+              "title": "OverseasHome Loan",
+              "icon": Assets.propertyOverseasHomeLoan,
+              "iconWidth": 36.0,
+              "iconHeight": 39.0
+            }
+        ]
+    );
+  }
+
+  @override
+  PropertyIoanState build(){
+    // 引入数据仓库
+    // propertyIoanRepository = ref.read(propertyIoanRepositoryProvider);
+    // 初始化状态
+    PropertyIoanState state = initState();
+    // 初始化列表数据
+    return state;
+  }
+
+  requestQuoteConfirmAction(){
+    Log.d("点击了确定");
+    DialogEngine.dismiss(tag: "requestQuote");
+  }
+
+  requestQuoteCancelAction(){
+    Log.d("点击了取消");
+  }
+
+  handlerRequestQuote(BuildContext context) async {
+    Log.d("点击了请求报价");
+    ToastEngine.show("暂未开放");
+    await DialogEngine.show(
+      tag: "requestQuote",
+      position: DialogPosition.bottom,
+      widget: BottomDialog(
+        confirmAction: requestQuoteConfirmAction,
+        cancelAction: requestQuoteCancelAction,
+        messageBuilder: (context) {
+          return Container(
+            padding: const EdgeInsets.only(left: 15,right: 15),
+            child: Column(
+              mainAxisAlignment: MainAxisAlignment.start,
+              crossAxisAlignment: CrossAxisAlignment.start,
+              children: [
+                MyTextView(
+                  "Submit Request?",
+                  textColor: ColorUtils.string2Color('#000000'),
+                  textAlign: TextAlign.left,
+                  fontWeight: FontWeight.w500,
+                  fontSize: 21,
+                  // maxLines: 5,
+                  marginBottom: 20,
+                ),
+                MyTextView(
+                  "A mortgage specialist will be incontact to help you compare theatest housing loan rates and tosecure the best package that suitsyour need",
+                  textColor: ColorUtils.string2Color('#666666'),
+                  textAlign: TextAlign.left,
+                  // maxLines: 5,
+                ),
+                MyTextView(
+                  "This is a complementary servicebrought to you by YY Home",
+                  textColor: ColorUtils.string2Color('#666666'),
+                  textAlign: TextAlign.left,
+                  // maxLines: 5,
+                  marginTop: 15,
+                ),
+              ]
+            )
+          );
+        },
+      ),
+    );
+  }
+}

+ 3 - 3
packages/cpt_property/lib/modules/ioan/vm/property_ioan_vm.g.dart

@@ -6,12 +6,12 @@ part of 'property_ioan_vm.dart';
 // RiverpodGenerator
 // **************************************************************************
 
-String _$propertyIoanVmHash() => r'e543d5bc121950c3301766873f79a84632d07887';
+String _$propertyIoanVmHash() => r'0a144f8492752958fa349425ff3a3e2fe631b733';
 
 /// See also [PropertyIoanVm].
 @ProviderFor(PropertyIoanVm)
 final propertyIoanVmProvider =
-    AutoDisposeNotifierProvider<PropertyIoanVm, void>.internal(
+    AutoDisposeNotifierProvider<PropertyIoanVm, PropertyIoanState>.internal(
   PropertyIoanVm.new,
   name: r'propertyIoanVmProvider',
   debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
@@ -21,6 +21,6 @@ final propertyIoanVmProvider =
   allTransitiveDependencies: null,
 );
 
-typedef _$PropertyIoanVm = AutoDisposeNotifier<void>;
+typedef _$PropertyIoanVm = AutoDisposeNotifier<PropertyIoanState>;
 // ignore_for_file: type=lint
 // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package

+ 157 - 2
packages/cpt_property/lib/modules/news/page/property_news_page.dart

@@ -1,7 +1,14 @@
+import 'package:cpt_property/modules/property/page/property_page.dart';
 import 'package:flutter/material.dart';
 import 'package:auto_route/auto_route.dart';
 import 'package:hooks_riverpod/hooks_riverpod.dart';
 import 'package:router/ext/auto_router_extensions.dart';
+import 'package:shared/utils/log_utils.dart';
+import 'package:shared/utils/util.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/widget_export.dart';
+import 'package:cs_resources/generated/assets.dart';
 
 import '../../../router/page/property_page_router.dart';
 import '../vm/property_news_vm.dart';
@@ -19,14 +26,162 @@ class PropertyNewsPage extends HookConsumerWidget {
     }
   }
 
+  Widget _buildItemLeftSection(BuildContext context,WidgetRef ref, item, _vm) {
+    return Container(
+      // color: Colors.blue,
+      width: 100,
+      // height: 117.5,
+      child: Center(
+        child: MyLoadImage(
+          item['pic'],
+          placeholderPath: Assets.propertyNewsItemBg,
+          width: 60.5,
+          height: 50.5,
+        ),
+      )
+    ).marginOnly(right: 17.5).constrained(
+      minHeight: 117.5,
+    );
+  }
+
+  Widget _buildItemRightSection(BuildContext context,WidgetRef ref, item, _vm) {
+
+    // 使用 ref.select 监听 list 中 item 的 Map 对象中的 isCollection 字段
+    final isCollection = ref.watch(propertyNewsVmProvider.select((state) {
+      final curItem = state.list.firstWhere(
+            (valueItem) => valueItem['id'] == item['id'],
+        orElse: () => {'isCollection': false},
+      );
+      return curItem['isCollection'] as bool;
+    }));
+
+    return Container(
+      color: Colors.white,
+      padding: const EdgeInsets.only(left:5, top: 10.5, bottom: 10.5),
+      child: Container(
+        child: Stack(
+          children: [
+            Column(
+              mainAxisAlignment: MainAxisAlignment.start,
+              crossAxisAlignment: CrossAxisAlignment.start,
+              children: [
+                Row(
+                  children: [
+                    Expanded(
+                      child: Text(
+                        item['title'],
+                        maxLines: 2, // 设置最大行数为2
+                        overflow: TextOverflow.ellipsis, // 超出部分用省略号表示
+                        style: const TextStyle(fontSize: 16.0, color: Colors.black, fontWeight: FontWeight.w400), // 设置字体大小
+                      ),
+                    )
+                  ],
+                ),
+                const SizedBox(height: 10.5),
+                Row(
+                  children: [
+                    Expanded(
+                      child: Text(
+                        item['description'],
+                        maxLines: 2, // 设置最大行数为2
+                        overflow: TextOverflow.ellipsis, // 超出部分用省略号表示
+                        style: const TextStyle(fontSize: 12.0, color: Colors.black), // 设置字体大小
+                      ),
+                    )
+                  ]
+                ),
+                const SizedBox(height: 12.5),
+                Row(
+                    children: [
+                      Expanded(
+                        child: Text(
+                          Utils.getTimeAgo(item['time']),
+                          maxLines: 1, // 设置最大行数为2
+                          overflow: TextOverflow.ellipsis, // 超出部分用省略号表示
+                          style: const TextStyle(fontSize: 12.0, color: Colors.black), // 设置字体大小
+                        ),
+                      )
+                    ]
+                ),
+              ],
+            ),
+            Positioned(
+              right: 5,
+              bottom: 0,
+              child: MyAssetImage(isCollection? Assets.propertyCollectionActive:Assets.propertyCollection,width:22,height: 20.5,).onTap((){
+                Log.d("点击了收藏按钮");
+                _vm.handlerCollection(item, isCollection);
+              }),
+            ),
+          ],
+        ).constrained(
+          minHeight: 96.5,
+        ),
+      ),
+    );
+  }
+
+  // listitem
+  Widget _buildNewsItem(BuildContext context,WidgetRef ref, item, _vm) {
+    return Row(
+      mainAxisAlignment: MainAxisAlignment.center,
+      crossAxisAlignment: CrossAxisAlignment.center,
+      mainAxisSize: MainAxisSize.max,
+      children: [
+        Container(
+          width: MediaQuery.of(context).size.width - 30,
+          margin: const EdgeInsets.only(left: 15,right: 15,top: 12.5),
+          child: Row(
+            mainAxisAlignment: MainAxisAlignment.start,
+            crossAxisAlignment: CrossAxisAlignment.start,
+            children: [
+              _buildItemLeftSection(context, ref, item, _vm),
+              Expanded(child: _buildItemRightSection(context, ref, item, _vm)),
+            ],
+          ),
+        ).constrained(
+          minHeight: 117.5,
+        ),
+      ],
+    ).onTap((){
+      // 去详情
+      _vm.goNewsDetail(item);
+    });
+  }
+
+  // list
+  Widget _buildNewsList(BuildContext context, WidgetRef ref, _vm) {
+    // List items = List.generate(20, (index) => "Item $index");
+    // List items = _vm.state.list.fromJson();
+    List itemsList = _vm.state.list.toList();
+    return ListView.builder(
+      itemCount: itemsList.length,
+      itemBuilder: (context, index) {
+        return _buildNewsItem(context, ref, itemsList[index], _vm);
+      },
+    );
+  }
+
   @override
   Widget build(BuildContext context, WidgetRef ref) {
     final _vm = ref.read(propertyNewsVmProvider.notifier);
 
     return Scaffold(
       // appBar: AppBar(title: Text("资产")),
-      body: Center(
-        child: Text("房屋news的主页面"),
+      body: Container(
+        child: EasyRefresh(
+          // 上拉加载
+          onLoad: () async{
+            Log.d("----onLoad");
+            _vm.onLoadData();
+          },
+          // 下拉刷新
+          onRefresh: () async{
+            Log.d("----onRefresh");
+            _vm.refreshListData();
+          },
+          child: _buildNewsList(context, ref, _vm),
+        )
       ),
     );
   }

+ 49 - 0
packages/cpt_property/lib/modules/news/page/property_news_state.dart

@@ -0,0 +1,49 @@
+/// YApi QuickType插件生成,具体参考文档:https://plugins.jetbrains.com/plugin/18847-yapi-quicktype/documentation
+
+import 'dart:convert';
+
+PropertyNewsState propertyNewsStateFromJson(String str) => PropertyNewsState.fromJson(json.decode(str));
+
+String propertyNewsStateToJson(PropertyNewsState data) => json.encode(data.toJson());
+
+class PropertyNewsState {
+    PropertyNewsState({
+        required this.curPage,
+        required this.pageSize,
+        required this.list,
+        required this.filterCount,
+    });
+
+    int curPage;
+    int pageSize;
+    List<Map<String, dynamic>> list;
+    int filterCount;
+
+    factory PropertyNewsState.fromJson(Map<dynamic, dynamic> json) => PropertyNewsState(
+        curPage: json["curPage"],
+        pageSize: json["pageSize"],
+        list: List<Map<String, dynamic>>.from(json["list"].map((x) => x)),
+        filterCount: json["filterCount"],
+    );
+
+    Map<dynamic, dynamic> toJson() => {
+        "curPage": curPage,
+        "pageSize": pageSize,
+        "list": List<dynamic>.from(list.map((x) => x)),
+        "filterCount": filterCount,
+    };
+
+    PropertyNewsState copyWith({
+    int? curPage,
+    int? pageSize,
+    List<Map<String, dynamic>>? list,
+    int? filterCount,
+  }) {
+    return PropertyNewsState(
+      curPage: curPage ?? this.curPage,
+      pageSize: pageSize ?? this.pageSize,
+      list: list ?? this.list,
+      filterCount: filterCount ?? this.filterCount,
+    );
+  }
+}

+ 71 - 0
packages/cpt_property/lib/modules/news/repository/property_news_repository.dart

@@ -0,0 +1,71 @@
+import 'package:domain/constants/api_constants.dart';
+import 'package:domain/entity/server_time.dart';
+import 'package:plugin_platform/platform_export.dart';
+import 'package:plugin_platform/http/dio_engine.dart';
+import 'package:plugin_platform/http/http_result.dart';
+import 'package:riverpod_annotation/riverpod_annotation.dart';
+import 'package:shared/utils/util.dart';
+
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:plugin_basic/provider/http_provider/http_provider.dart';
+
+import '../page/property_news_state.dart';
+
+part 'property_news_repository.g.dart';
+
+@Riverpod(keepAlive: true)
+PropertyNewsRepository propertyNewsRepository(Ref ref) {
+  final dioEngine = ref.watch(dioEngineProvider);
+  return PropertyNewsRepository(dioEngine: dioEngine);
+}
+
+/*
+ * 数据仓库
+ */
+class PropertyNewsRepository {
+  DioEngine dioEngine;
+
+  PropertyNewsRepository({required this.dioEngine});
+
+  Future<HttpResult<Object>> fetchPropertyNewsList(
+      Map<String, dynamic>? data, {
+        CancelToken? cancelToken,
+      }) async {
+    Map<String, dynamic> params = {};
+
+    // if (!Utils.isEmpty(type)) {
+    //   params["type"] = type!;
+    // }
+
+    params = data!;
+
+
+    Map<String, String> headers = {};
+
+    headers["Content-Type"] = "application/x-www-form-urlencoded";
+    headers["Accept"] = "application/x.yyjobs-api.v1+json";
+
+    final result = await dioEngine.requestNetResult(
+      // ApiConstants.apiServerTime, // api 地址
+      '/index.php/api/employee/extra/time', // api 地址
+      params: params,
+      headers: headers,
+      method: HttpMethod.GET,
+      isShowLoadingDialog: true,  //是否展示默认的Loading弹窗
+      networkDebounce: true,   //是否防抖防止重复请求
+      cancelToken: cancelToken,
+    );
+
+    //根据返回的结果,封装原始数据为Bean/Entity对象
+    if (result.isSuccess) {
+      //重新赋值data或list
+      final json = result.getDataJson();
+      var data = PropertyNewsState.fromJson(json!);
+      //重新赋值data或list
+      return result.convert<PropertyNewsState>(data: data);
+    }
+    return result.convert();
+  }
+
+
+}

+ 29 - 0
packages/cpt_property/lib/modules/news/repository/property_news_repository.g.dart

@@ -0,0 +1,29 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'property_news_repository.dart';
+
+// **************************************************************************
+// RiverpodGenerator
+// **************************************************************************
+
+String _$propertyNewsRepositoryHash() =>
+    r'4dd4722df0ea770dabbf9417faa00ffa6f6f5044';
+
+/// See also [propertyNewsRepository].
+@ProviderFor(propertyNewsRepository)
+final propertyNewsRepositoryProvider =
+    Provider<PropertyNewsRepository>.internal(
+  propertyNewsRepository,
+  name: r'propertyNewsRepositoryProvider',
+  debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
+      ? null
+      : _$propertyNewsRepositoryHash,
+  dependencies: null,
+  allTransitiveDependencies: null,
+);
+
+@Deprecated('Will be removed in 3.0. Use Ref instead')
+// ignore: unused_element
+typedef PropertyNewsRepositoryRef = ProviderRef<PropertyNewsRepository>;
+// ignore_for_file: type=lint
+// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package

+ 122 - 3
packages/cpt_property/lib/modules/news/vm/property_news_vm.dart

@@ -1,14 +1,133 @@
-
+import 'package:plugin_platform/http/http_result.dart';
 import 'package:riverpod_annotation/riverpod_annotation.dart';
-
+import 'package:shared/utils/log_utils.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import '../page/property_news_state.dart';
+import '../repository/property_news_repository.dart';
 part 'property_news_vm.g.dart';
 
 @riverpod
 class PropertyNewsVm extends _$PropertyNewsVm {
+  late PropertyNewsRepository propertyNewsRepository;
+  PropertyNewsState initState() {
+    return PropertyNewsState(
+      curPage: 1,
+      pageSize: 10,
+      list: [
+        {
+          "id": 1,
+          "title": "fkladsfk fldask fldsakfllfkaslsd",
+          "description": "fsklfdsk罚款乱收费上课了发送卡",
+          "time": "2024-02-15 12:00:00",
+          "isCollection": true,
+          "pic": ""
+        },
+        {
+          "id": 2,
+          "title": "JHKFDSAJKjfkdsfjkasjkjklfajfkajifwoqirujweiqofjndsaikfniasdhfiasdhfiadshfifjadslfjkdlsafjlkadsj",
+          "description": "oifosjf fjdskafj hjiwehfriohjfiash",
+          "time": "2024-10-16 12:00:00",
+          "isCollection": false,
+          "pic": ""
+        },
+      ],
+      filterCount: 2,
+    );
+  }
 
   @override
-  void build(){
+  PropertyNewsState build() {
+    // 引入数据仓库
+    propertyNewsRepository = ref.read(propertyNewsRepositoryProvider);
+    // 初始化状态
+    PropertyNewsState state = initState();
+    // 初始化列表数据
+    return state;
+  }
+
+  // 初始化页面数据
+  initPageData() {
+    Log.d("----property_news_vm-----initPageData");
+    refreshListData();
+  }
+
+  // 上拉加载
+  Future onLoadData() async {
+    Log.d("----property_news_vm-----initListData");
+    // await Future.delayed(const Duration(seconds: 2));
+    // if(state.list.length >= state.filterCount){
+    //   return;
+    // }else {
+    //   int curPage = state.curPage + 1;
+    //   state = state.copyWith(curPage: curPage,);
+    //   getListData();
+    // }
+    getListData();
+  }
+
+  // 获取list 列表数据
+  void getListData<T>() async {
+    Log.d("加载listData数据---------------start-----");
+    try {
+      //请求网络
+      Map<String, dynamic>  params = {
+        "curPage": state.curPage,
+        "pageSize": state.pageSize,
+      };
+      Log.d("请求参数------$params");
+      final result = await propertyNewsRepository.fetchPropertyNewsList(params);
+      Log.d("请求完成结果------${result.data}");
+      //校验成功失败
+      if (result.isSuccess) {
+        // state = state.copyWith(serverTime: result.data);
+        state = state;
+        ToastEngine.show("获取数据成功");
+      } else {
+        ToastEngine.show(result.errorMsg ?? "Network Load Error");
+      }
+    } catch (e) {
+      ToastEngine.show("Error: $e");
+    }
+  }
+
+
+  // 下拉刷新
+  Future refreshListData() async {
+    Log.d("----property_news_vm-----refreshListData ");
+
+    // await Future.delayed(const Duration(seconds: 2));
+
+    state = state.copyWith(curPage: 1, pageSize: 10);
+    // ref.invalidateSelf();
+    // ref.invalidate(propertyNewsVmProvider);
+    getListData();
 
   }
 
+  // 去新闻详情页
+  void goNewsDetail(String item) {
+    Log.d("goNewsDetail");
+    // PropertyPage.startInstance(context: context, item: item);
+  }
+
+  // 收藏/取消收藏
+  void handlerCollection(curItem, bool isCollection){
+
+    List<Map<String, dynamic>> newList = state.list.map((item) {
+        if(item['id'] == curItem['id']){
+          return {
+            ...item,
+            'isCollection': !isCollection
+          };
+        }
+        return item;
+    }).toList();
+    // Log.d("handlerCollection $newList");
+    state = state.copyWith(list: newList);
+    if(isCollection){
+      ToastEngine.show("取消收藏");
+    }else {
+      ToastEngine.show("收藏成功");
+    }
+  }
 }

+ 3 - 3
packages/cpt_property/lib/modules/news/vm/property_news_vm.g.dart

@@ -6,12 +6,12 @@ part of 'property_news_vm.dart';
 // RiverpodGenerator
 // **************************************************************************
 
-String _$propertyNewsVmHash() => r'f18922e4ca3d2a59ba6f2504064b9bb073719979';
+String _$propertyNewsVmHash() => r'9f9fe61ce917e7f3098de28310a19171f9e8c457';
 
 /// See also [PropertyNewsVm].
 @ProviderFor(PropertyNewsVm)
 final propertyNewsVmProvider =
-    AutoDisposeNotifierProvider<PropertyNewsVm, void>.internal(
+    AutoDisposeNotifierProvider<PropertyNewsVm, PropertyNewsState>.internal(
   PropertyNewsVm.new,
   name: r'propertyNewsVmProvider',
   debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
@@ -21,6 +21,6 @@ final propertyNewsVmProvider =
   allTransitiveDependencies: null,
 );
 
-typedef _$PropertyNewsVm = AutoDisposeNotifier<void>;
+typedef _$PropertyNewsVm = AutoDisposeNotifier<PropertyNewsState>;
 // ignore_for_file: type=lint
 // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package

+ 9 - 9
packages/cpt_property/lib/modules/ioan/page/property_ioan_page.dart

@@ -5,32 +5,32 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
 import 'package:router/ext/auto_router_extensions.dart';
 import 'package:widgets/my_load_image.dart';
 
-import '../../../router/page/property_page_router.dart';
-import '../vm/property_ioan_vm.dart';
+import '../../router/page/property_page_router.dart';
+import './property_news_detail_vm.dart';
 
 @RoutePage()
-class PropertyIoanPage extends HookConsumerWidget {
-  const PropertyIoanPage({Key? key}) : super(key: key);
+class PropertyNewsDetailPage extends HookConsumerWidget {
+  const PropertyNewsDetailPage({Key? key}) : super(key: key);
 
   //启动当前页面
   static void startInstance({BuildContext? context}) {
     if (context != null) {
-      context.router.push(const PropertyIoanPageRoute());
+      context.router.push(const PropertyNewsPageRoute());
     } else {
-      appRouter.push(const PropertyIoanPageRoute());
+      appRouter.push(const PropertyNewsPageRoute());
     }
   }
 
   @override
   Widget build(BuildContext context, WidgetRef ref) {
-    final _vm = ref.read(propertyIoanVmProvider.notifier);
+    final _vm = ref.read(propertyNewsDetailVmProvider.notifier);
 
     return Scaffold(
-      // appBar: AppBar(title: Text("资产")),
+      appBar: AppBar(title: Text("新闻详情页面")),
       body: Column(
         children: [
           MyAssetImage(
-            Assets.propertyIoan2x,
+            Assets.propertyIoan,
             width: 100,
             height: 100,
           ),

+ 2 - 2
packages/cpt_property/lib/modules/ioan/vm/property_ioan_vm.dart

@@ -1,10 +1,10 @@
 
 import 'package:riverpod_annotation/riverpod_annotation.dart';
 
-part 'property_ioan_vm.g.dart';
+part 'property_news_detail_vm.g.dart';
 
 @riverpod
-class PropertyIoanVm extends _$PropertyIoanVm {
+class PropertyNewsDetailVm extends _$PropertyNewsDetailVm {
 
   @override
   void build(){

+ 27 - 0
packages/cpt_property/lib/modules/news_detail/property_news_detail_vm.g.dart

@@ -0,0 +1,27 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'property_news_detail_vm.dart';
+
+// **************************************************************************
+// RiverpodGenerator
+// **************************************************************************
+
+String _$propertyNewsDetailVmHash() =>
+    r'd98d5adf806094583866cf55bd2f3d339ae2e837';
+
+/// See also [PropertyNewsDetailVm].
+@ProviderFor(PropertyNewsDetailVm)
+final propertyNewsDetailVmProvider =
+    AutoDisposeNotifierProvider<PropertyNewsDetailVm, void>.internal(
+  PropertyNewsDetailVm.new,
+  name: r'propertyNewsDetailVmProvider',
+  debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
+      ? null
+      : _$propertyNewsDetailVmHash,
+  dependencies: null,
+  allTransitiveDependencies: null,
+);
+
+typedef _$PropertyNewsDetailVm = AutoDisposeNotifier<void>;
+// ignore_for_file: type=lint
+// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package

+ 20 - 9
packages/cpt_property/lib/modules/property/page/property_page.dart

@@ -2,9 +2,11 @@ import 'package:flutter/material.dart';
 import 'package:auto_route/auto_route.dart';
 import 'package:hooks_riverpod/hooks_riverpod.dart';
 import 'package:router/ext/auto_router_extensions.dart';
+import 'package:shared/utils/color_utils.dart';
 import 'package:shared/utils/log_utils.dart';
 import 'package:widgets/my_load_image.dart';
 import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_text_view.dart';
 
 import '../../../router/page/property_page_router.dart';
 import '../vm/property_vm.dart';
@@ -25,6 +27,8 @@ class PropertyPage extends HookConsumerWidget {
   // 顶部tab 切换
   Widget _buildTopSection(BuildContext context, WidgetRef ref, _vm) {
     final topSectionsData = _vm.topSectionsData;
+    // 监听 curIdx 的变化
+    final curIdx = ref.watch(propertyVmProvider.select((value) => value.curIdx));
     return Container(
       color: Colors.white,
       child: Center(
@@ -33,12 +37,13 @@ class PropertyPage extends HookConsumerWidget {
           crossAxisAlignment: CrossAxisAlignment.center,
           children: List.generate(topSectionsData.length, (index) {
             final item = topSectionsData[index];
-            return Container(
+            return Flexible(
+              flex: 1,
               child: Column(
                 children: [
                   MyAssetImage(
                     item['icon'],
-                    width: 70,
+                    width: MediaQuery.of(context).size.width / topSectionsData.length - 36,
                     height: 70,
                   ).onTap(
                     () {
@@ -46,10 +51,16 @@ class PropertyPage extends HookConsumerWidget {
                     },
                     type: ClickType.throttle,
                   ),
-                  TextButton(
-                    onPressed: () {
-                    },
-                    child: Text(item['title']),
+                  SizedBox.fromSize(size: const Size(0, 9)),
+                  Text(
+                    item['title'],
+                    maxLines: 1, // 设置最大行数为2
+                    overflow: TextOverflow.ellipsis, // 超出部分用省略号表示
+                    style: TextStyle(
+                        fontSize: 13.0,
+                        color: curIdx == index ? ColorUtils.string2Color('#4161D0'):Colors.black,
+                        fontWeight: FontWeight.w500
+                    ), // 设置字体大小
                   ),
                 ],
               ),
@@ -67,9 +78,9 @@ class PropertyPage extends HookConsumerWidget {
       length: 4,
       child: Scaffold(
           appBar: AppBar(
-            title: Text("Property"),
+            title: const Text("Property"),
             bottomOpacity: 0.0, // 取消下横线
-            titleTextStyle: TextStyle(color: Colors.black),
+            titleTextStyle: const TextStyle(color: Colors.black),
           ),
           body: Row(
             children: [
@@ -77,7 +88,7 @@ class PropertyPage extends HookConsumerWidget {
                 child: Column(
                   children: [
                     _buildTopSection(context, ref, _vm),
-                    Expanded(
+                    const Expanded(
                       child: AutoRouter(),
                     )
                   ],

+ 62 - 40
packages/cpt_property/lib/modules/property/vm/property_vm.dart

@@ -1,10 +1,11 @@
 
 import 'package:cs_resources/generated/assets.dart';
 import 'package:flutter/cupertino.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
 import 'package:riverpod_annotation/riverpod_annotation.dart';
 import 'package:shared/utils/log_utils.dart';
 
-import '../../ioan/page/property_ioan_page.dart';
+import '../../ioan/property_ioan_page.dart';
 import '../../news/page/property_news_page.dart';
 import '../../rent/page/property_rent_page.dart';
 import '../../sale/page/property_sale_page.dart';
@@ -13,16 +14,46 @@ part 'property_vm.g.dart';
 
 
 class PropertyVmState {
-  List<Map<String, dynamic>> topSectionsData;
+  List<Map<String, dynamic>>? topSectionsData;
+  int? curIdx;
+
   PropertyVmState({
-    required this.topSectionsData,
-  });
+    List<Map<String, dynamic>>? topSectionsData,
+    this.curIdx = 0,
+  }) : topSectionsData = topSectionsData?? [
+    {
+      "title": "Ioan",
+      "icon": Assets.propertyIoan,
+      "pageStartInstanceFn": PropertyIoanPage.startInstance,
+      "page": const PropertyIoanPage(),
+    },
+    {
+      "title": "News",
+      "icon": Assets.propertyNews,
+      "pageStartInstanceFn": PropertyNewsPage.startInstance,
+      "page": const PropertyNewsPage(),
+    },
+    {
+      "title": "Sale",
+      "icon": Assets.propertySale,
+      "pageStartInstanceFn": PropertySalePage.startInstance,
+      "page": const PropertySalePage(),
+    },
+    {
+      "title": "Rent",
+      "icon": Assets.propertyRent,
+      "pageStartInstanceFn": PropertyRentPage.startInstance,
+      "page": const PropertyRentPage(),
+    },
+  ];
 
-  PropertyVmState CopyWith({
-    required List<Map<String, dynamic>> topSectionsData,
-  }){
+  PropertyVmState copyWith({
+    List<Map<String, dynamic>>? topSectionsData,
+    int? curIdx = 0,
+  }) {
     return PropertyVmState(
       topSectionsData: topSectionsData ?? this.topSectionsData,
+      curIdx: curIdx ?? 0,
     );
   }
 }
@@ -32,48 +63,39 @@ class PropertyVm extends _$PropertyVm {
   get topSectionsData => state.topSectionsData;
 
   PropertyVmState initState() {
-    return PropertyVmState(
-      topSectionsData: [
-        {
-          "title": "Sale",
-          "icon": Assets.propertySale2x,
-          "pageStartInstanceFn": PropertySalePage.startInstance,
-          "page": const PropertySalePage(),
-        },
-        {
-          "title": "Rent",
-          "icon": Assets.propertyRent2x,
-          "pageStartInstanceFn": PropertyRentPage.startInstance,
-          "page": const PropertyRentPage(),
-        },
-        {
-          "title": "Ioan",
-          "icon": Assets.propertyIoan2x,
-          "pageStartInstanceFn": PropertyIoanPage.startInstance,
-          "page": const PropertyIoanPage(),
-        },
-        {
-          "title": "News",
-          "icon": Assets.propertyNews2x,
-          "pageStartInstanceFn": PropertyNewsPage.startInstance,
-          "page": const PropertyNewsPage(),
-        }
-      ],
-    );
+    return PropertyVmState();
   }
 
   @override
   PropertyVmState build(){
     final state = initState();
+    Log.d("--------------------------build---------------------");
+
+    // 初始时导航到子路由
+    WidgetsBinding.instance.addPostFrameCallback((_) {
+      switchPage(state.curIdx ?? 0, null, true);
+    });
+
     return state;
   }
 
   // 页面切换
-  switchPage(int index, context){
-    final _topSectionsData = state.topSectionsData;
-    Log.d("当前页面${_topSectionsData[index]['pageStartInstanceFn']}");
-    final pageStartInstanceFn = _topSectionsData[index]['pageStartInstanceFn'] as Function({BuildContext? context});
-    pageStartInstanceFn(context:context);
+  switchPage(int index,BuildContext? context, [bool? isFirstInitSwitch] ){
+    if(state.curIdx != index){
+      state = state.copyWith(curIdx: index);
+      final List<Map<String, dynamic>>? topSectionsData = state.topSectionsData;
+      // Log.d("当前页面${topSectionsData?[index]['pageStartInstanceFn']}");
+      final pageStartInstanceFn = topSectionsData?[index]['pageStartInstanceFn'] as Function({BuildContext? context});
+      pageStartInstanceFn(context:context);
+    }else {
+      if(isFirstInitSwitch??false){
+        final List<Map<String, dynamic>>? topSectionsData = state.topSectionsData;
+        // Log.d("当前页面${topSectionsData?[index]['pageStartInstanceFn']}");
+        final pageStartInstanceFn = topSectionsData?[index]['pageStartInstanceFn'] as Function({BuildContext? context});
+        pageStartInstanceFn(context:context);
+      }
+    }
   }
 
 }
+

+ 1 - 1
packages/cpt_property/lib/modules/property/vm/property_vm.g.dart

@@ -6,7 +6,7 @@ part of 'property_vm.dart';
 // RiverpodGenerator
 // **************************************************************************
 
-String _$propertyVmHash() => r'f98e7cc04acc4620ceeab7bf45bdc1459648e4b3';
+String _$propertyVmHash() => r'9b08b5e83d2b45f67b653daf60bb66bacb9c47ed';
 
 /// See also [PropertyVm].
 @ProviderFor(PropertyVm)

+ 126 - 2
packages/cpt_property/lib/modules/rent/page/property_rent_page.dart

@@ -1,7 +1,14 @@
+import 'package:cpt_property/modules/property/page/property_page.dart';
 import 'package:flutter/material.dart';
 import 'package:auto_route/auto_route.dart';
 import 'package:hooks_riverpod/hooks_riverpod.dart';
 import 'package:router/ext/auto_router_extensions.dart';
+import 'package:shared/utils/log_utils.dart';
+import 'package:shared/utils/color_utils.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/widget_export.dart';
+import 'package:cs_resources/generated/assets.dart';
 
 import '../../../router/page/property_page_router.dart';
 import '../vm/property_rent_vm.dart';
@@ -19,14 +26,131 @@ class PropertyRentPage extends HookConsumerWidget {
     }
   }
 
+  Widget _buildItemLeftSection(BuildContext context,WidgetRef ref, item, _vm) {
+    return Container(
+      // color: Colors.blue,
+      child:
+      Text(item['title'],
+        style: const TextStyle(fontSize: 16.0, color: Colors.black, fontWeight: FontWeight.w400), // 设置字体大小
+      ),
+    ).marginOnly(right: 17.5);
+  }
+
+  Widget _buildItemRightSection(BuildContext context,WidgetRef ref, item, _vm) {
+
+    return Container(
+      color: Colors.white,
+      child: TextButton(
+        onPressed: (){},
+        style: TextButton.styleFrom(
+          foregroundColor: Colors.black,
+          backgroundColor: ColorUtils.string2Color('#EFF3FF'), // 背景颜色
+          // minimumSize: const Size(71, 30), // 最小宽度和高度
+          padding: const EdgeInsets.symmetric(horizontal: 17.5, vertical: 7.5), // 内边距
+          shape: RoundedRectangleBorder(
+            borderRadius: BorderRadius.circular(5), // 圆角
+            side: BorderSide(
+              color: ColorUtils.string2Color('#EFF3FF'),
+              width: 1.0,
+            ), // 边框
+          ),
+        ),
+        child: Container(
+          height: 44,
+          child: Column(
+            mainAxisAlignment: MainAxisAlignment.center,
+            children: [
+              Text(
+                item['price'],
+                style: const TextStyle(
+                  fontSize: 17, // 字体大小
+                  fontWeight: FontWeight.bold, // 字体粗细
+                ),
+              ),
+              Text(
+                item['unit'],
+                style: const TextStyle(
+                  fontSize: 12, // 字体大小
+                  fontWeight: FontWeight.normal, // 字体粗细
+                ),
+              ),
+            ],
+          ),
+        ),
+      ),
+    );
+  }
+
+  // listitem
+  Widget _buildRentItem(BuildContext context,WidgetRef ref, item, _vm) {
+    return Container(
+      // color: Colors.red,
+      child: Row(
+        mainAxisAlignment: MainAxisAlignment.center,
+        crossAxisAlignment: CrossAxisAlignment.center,
+        mainAxisSize: MainAxisSize.max,
+        children: [
+          Container(
+            width: MediaQuery.of(context).size.width - 30,
+            height: 100,
+            margin: const EdgeInsets.only(left: 15,right: 15,top: 12.5),
+            child: Row(
+              mainAxisAlignment: MainAxisAlignment.start,
+              crossAxisAlignment: CrossAxisAlignment.center,
+              children: [
+                Expanded(child: _buildItemLeftSection(context, ref, item, _vm)),
+                Container(
+                  width: 100,
+                  child: _buildItemRightSection(context, ref, item, _vm),
+                ),
+              ],
+            ),
+          ).constrained(
+            minHeight: 117.5,
+          ),
+        ],
+      ).onTap((){
+        // 去详情
+        _vm.goNewsDetail(item);
+      }),
+    ).border(color: ColorUtils.string2Color('C9C9C9FF'), bottom: 0.5);
+  }
+
+  // list
+  Widget _buildRentList(BuildContext context, WidgetRef ref, _vm) {
+    List itemsList = _vm.state.list.toList();
+    return ListView.builder(
+      itemCount: itemsList.length,
+      itemBuilder: (context, index) {
+        return _buildRentItem(context, ref, itemsList[index], _vm);
+      },
+    );
+  }
+
   @override
   Widget build(BuildContext context, WidgetRef ref) {
     final _vm = ref.read(propertyRentVmProvider.notifier);
 
     return Scaffold(
       // appBar: AppBar(title: Text("资产")),
-      body: Center(
-        child: Text("房屋rent的主页面"),
+      body: Container(
+          child: EasyRefresh(
+            // 上拉加载
+            onLoad: () async{
+              Log.d("----onLoad");
+              _vm.onLoadData();
+            },
+            // 下拉刷新
+            onRefresh: () async{
+              Log.d("----onRefresh");
+              _vm.refreshListData();
+            },
+            child: Container(
+                color: Colors.white,
+                margin: const EdgeInsets.only(top: 5),
+                child: _buildRentList(context, ref, _vm)
+            ),
+          )
       ),
     );
   }

+ 49 - 0
packages/cpt_property/lib/modules/rent/page/property_rent_state.dart

@@ -0,0 +1,49 @@
+/// YApi QuickType插件生成,具体参考文档:https://plugins.jetbrains.com/plugin/18847-yapi-quicktype/documentation
+
+import 'dart:convert';
+
+PropertyRentState propertyRentStateFromJson(String str) => PropertyRentState.fromJson(json.decode(str));
+
+String propertyRentStateToJson(PropertyRentState data) => json.encode(data.toJson());
+
+class PropertyRentState {
+  PropertyRentState({
+    required this.curPage,
+    required this.pageSize,
+    required this.list,
+    required this.filterCount,
+  });
+
+  int curPage;
+  int pageSize;
+  List<Map<String, dynamic>> list;
+  int filterCount;
+
+  factory PropertyRentState.fromJson(Map<dynamic, dynamic> json) => PropertyRentState(
+    curPage: json["curPage"],
+    pageSize: json["pageSize"],
+    list: List<Map<String, dynamic>>.from(json["list"].map((x) => x)),
+    filterCount: json["filterCount"],
+  );
+
+  Map<dynamic, dynamic> toJson() => {
+    "curPage": curPage,
+    "pageSize": pageSize,
+    "list": List<dynamic>.from(list.map((x) => x)),
+    "filterCount": filterCount,
+  };
+
+  PropertyRentState copyWith({
+    int? curPage,
+    int? pageSize,
+    List<Map<String, dynamic>>? list,
+    int? filterCount,
+  }) {
+    return PropertyRentState(
+      curPage: curPage ?? this.curPage,
+      pageSize: pageSize ?? this.pageSize,
+      list: list ?? this.list,
+      filterCount: filterCount ?? this.filterCount,
+    );
+  }
+}

+ 70 - 0
packages/cpt_property/lib/modules/rent/repository/property_rent_repository.dart

@@ -0,0 +1,70 @@
+import 'package:domain/constants/api_constants.dart';
+import 'package:domain/entity/server_time.dart';
+import 'package:plugin_platform/platform_export.dart';
+import 'package:plugin_platform/http/dio_engine.dart';
+import 'package:plugin_platform/http/http_result.dart';
+import 'package:riverpod_annotation/riverpod_annotation.dart';
+import 'package:shared/utils/util.dart';
+
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:plugin_basic/provider/http_provider/http_provider.dart';
+
+import '../page/property_rent_state.dart';
+part 'property_rent_repository.g.dart';
+
+@Riverpod(keepAlive: true)
+PropertyRentRepository propertyRentRepository(Ref ref) {
+  final dioEngine = ref.watch(dioEngineProvider);
+  return PropertyRentRepository(dioEngine: dioEngine);
+}
+
+/*
+ * 数据仓库
+ */
+class PropertyRentRepository {
+  DioEngine dioEngine;
+
+  PropertyRentRepository({required this.dioEngine});
+
+  Future<HttpResult<Object>> fetchPropertyNewsList(
+      Map<String, dynamic>? data, {
+        CancelToken? cancelToken,
+      }) async {
+    Map<String, dynamic> params = {};
+
+    // if (!Utils.isEmpty(type)) {
+    //   params["type"] = type!;
+    // }
+
+    params = data!;
+
+
+    Map<String, String> headers = {};
+
+    headers["Content-Type"] = "application/x-www-form-urlencoded";
+    headers["Accept"] = "application/x.yyjobs-api.v1+json";
+
+    final result = await dioEngine.requestNetResult(
+      // ApiConstants.apiServerTime, // api 地址
+      '/index.php/api/employee/extra/time', // api 地址
+      params: params,
+      headers: headers,
+      method: HttpMethod.GET,
+      isShowLoadingDialog: true,  //是否展示默认的Loading弹窗
+      networkDebounce: true,   //是否防抖防止重复请求
+      cancelToken: cancelToken,
+    );
+
+    //根据返回的结果,封装原始数据为Bean/Entity对象
+    if (result.isSuccess) {
+      //重新赋值data或list
+      final json = result.getDataJson();
+      var data = PropertyRentState.fromJson(json!);
+      //重新赋值data或list
+      return result.convert<PropertyRentState>(data: data);
+    }
+    return result.convert();
+  }
+
+
+}

+ 29 - 0
packages/cpt_property/lib/modules/rent/repository/property_rent_repository.g.dart

@@ -0,0 +1,29 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'property_rent_repository.dart';
+
+// **************************************************************************
+// RiverpodGenerator
+// **************************************************************************
+
+String _$propertyRentRepositoryHash() =>
+    r'1086503553f2392faaca5dc570bd1ff82c72d570';
+
+/// See also [propertyRentRepository].
+@ProviderFor(propertyRentRepository)
+final propertyRentRepositoryProvider =
+    Provider<PropertyRentRepository>.internal(
+  propertyRentRepository,
+  name: r'propertyRentRepositoryProvider',
+  debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
+      ? null
+      : _$propertyRentRepositoryHash,
+  dependencies: null,
+  allTransitiveDependencies: null,
+);
+
+@Deprecated('Will be removed in 3.0. Use Ref instead')
+// ignore: unused_element
+typedef PropertyRentRepositoryRef = ProviderRef<PropertyRentRepository>;
+// ignore_for_file: type=lint
+// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package

+ 92 - 3
packages/cpt_property/lib/modules/rent/vm/property_rent_vm.dart

@@ -1,13 +1,102 @@
-
+import 'package:plugin_platform/http/http_result.dart';
 import 'package:riverpod_annotation/riverpod_annotation.dart';
-
+import 'package:shared/utils/log_utils.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import '../page/property_rent_state.dart';
+import '../repository/property_rent_repository.dart';
 part 'property_rent_vm.g.dart';
 
 @riverpod
 class PropertyRentVm extends _$PropertyRentVm {
+  late PropertyRentRepository propertyRentRepository;
+  PropertyRentState initState() {
+    return PropertyRentState(
+      curPage: 1,
+      pageSize: 10,
+      list: [
+        {
+          "id": 1,
+          "title": "Jul 2024  Blk XX #XX to XX 1,100 - 1,200 sqft",
+          "price": "\$4000",
+          "unit": "per month",
+        },
+        {
+          "id": 2,
+          "title": "Jul 2024  Blk XX #XX to XX 1,100 - 1,200 sqft",
+          "price": "\$4000",
+          "unit": "per month",
+        },
+      ],
+      filterCount: 2,
+    );
+  }
 
   @override
-  void build(){
+  PropertyRentState build() {
+    // 引入数据仓库
+    propertyRentRepository = ref.read(propertyRentRepositoryProvider);
+    // 初始化状态
+    PropertyRentState state = initState();
+    // 初始化列表数据
+    return state;
+  }
+
+  // 初始化页面数据
+  initPageData() {
+    Log.d("----property_news_vm-----initPageData");
+    refreshListData();
+  }
+
+  // 上拉加载
+  Future onLoadData() async {
+    Log.d("----property_news_vm-----initListData");
+    // await Future.delayed(const Duration(seconds: 2));
+    // if(state.list.length >= state.filterCount){
+    //   return;
+    // }else {
+    //   int curPage = state.curPage + 1;
+    //   state = state.copyWith(curPage: curPage,);
+    //   getListData();
+    // }
+    getListData();
+  }
+
+  // 获取list 列表数据
+  void getListData<T>() async {
+    Log.d("加载listData数据---------------start-----");
+    try {
+      //请求网络
+      Map<String, dynamic>  params = {
+        "curPage": state.curPage,
+        "pageSize": state.pageSize,
+      };
+      Log.d("请求参数------$params");
+      final result = await propertyRentRepository.fetchPropertyNewsList(params);
+      Log.d("请求完成结果------${result.data}");
+      //校验成功失败
+      if (result.isSuccess) {
+        // state = state.copyWith(serverTime: result.data);
+        state = state;
+        ToastEngine.show("获取数据成功");
+      } else {
+        ToastEngine.show(result.errorMsg ?? "Network Load Error");
+      }
+    } catch (e) {
+      ToastEngine.show("Error: $e");
+    }
+  }
+
+
+  // 下拉刷新
+  Future refreshListData() async {
+    Log.d("----property_news_vm-----refreshListData ");
+
+    // await Future.delayed(const Duration(seconds: 2));
+
+    state = state.copyWith(curPage: 1, pageSize: 10);
+    // ref.invalidateSelf();
+    // ref.invalidate(propertyNewsVmProvider);
+    getListData();
 
   }
 

+ 3 - 3
packages/cpt_property/lib/modules/rent/vm/property_rent_vm.g.dart

@@ -6,12 +6,12 @@ part of 'property_rent_vm.dart';
 // RiverpodGenerator
 // **************************************************************************
 
-String _$propertyRentVmHash() => r'7746ebd091e4bfe92688f58d8fe1aa74eb7c09fc';
+String _$propertyRentVmHash() => r'2efb6c1e46d069748a306631c5265d2bc62599c7';
 
 /// See also [PropertyRentVm].
 @ProviderFor(PropertyRentVm)
 final propertyRentVmProvider =
-    AutoDisposeNotifierProvider<PropertyRentVm, void>.internal(
+    AutoDisposeNotifierProvider<PropertyRentVm, PropertyRentState>.internal(
   PropertyRentVm.new,
   name: r'propertyRentVmProvider',
   debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
@@ -21,6 +21,6 @@ final propertyRentVmProvider =
   allTransitiveDependencies: null,
 );
 
-typedef _$PropertyRentVm = AutoDisposeNotifier<void>;
+typedef _$PropertyRentVm = AutoDisposeNotifier<PropertyRentState>;
 // ignore_for_file: type=lint
 // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package

+ 106 - 2
packages/cpt_property/lib/modules/sale/page/property_sale_page.dart

@@ -1,7 +1,14 @@
+import 'package:cpt_property/modules/property/page/property_page.dart';
 import 'package:flutter/material.dart';
 import 'package:auto_route/auto_route.dart';
 import 'package:hooks_riverpod/hooks_riverpod.dart';
 import 'package:router/ext/auto_router_extensions.dart';
+import 'package:shared/utils/log_utils.dart';
+import 'package:shared/utils/color_utils.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/widget_export.dart';
+import 'package:cs_resources/generated/assets.dart';
 
 import '../../../router/page/property_page_router.dart';
 import '../vm/property_sale_vm.dart';
@@ -19,14 +26,111 @@ class PropertySalePage extends HookConsumerWidget {
     }
   }
 
+  Widget _buildItemLeftSection(BuildContext context,WidgetRef ref, item, _vm) {
+    return Container(
+      // color: Colors.blue,
+        child:
+          Text(item['title'],
+          style: const TextStyle(fontSize: 16.0, color: Colors.black, fontWeight: FontWeight.w400), // 设置字体大小
+        ),
+    ).marginOnly(right: 17.5);
+  }
+
+  Widget _buildItemRightSection(BuildContext context,WidgetRef ref, item, _vm) {
+
+    return Container(
+      color: Colors.white,
+      child: TextButton(
+        onPressed: (){},
+        style: TextButton.styleFrom(
+          foregroundColor: Colors.black,
+          backgroundColor: ColorUtils.string2Color('#EFF3FF'), // 背景颜色
+          minimumSize: const Size(91.5, 44), // 最小宽度和高度
+          padding: const EdgeInsets.symmetric(horizontal: 11.0, vertical: 14), // 内边距
+          shape: RoundedRectangleBorder(
+            borderRadius: BorderRadius.circular(5), // 圆角
+            side: BorderSide(
+                color: ColorUtils.string2Color('#EFF3FF'),
+                width: 1.0,
+            ), // 边框
+          ),
+        ),
+        child: Text(item['price']),
+      ),
+    );
+  }
+
+  // listitem
+  Widget _buildSaleItem(BuildContext context,WidgetRef ref, item, _vm) {
+    return Container(
+      // color: Colors.red,
+      child: Row(
+        mainAxisAlignment: MainAxisAlignment.center,
+        crossAxisAlignment: CrossAxisAlignment.center,
+        mainAxisSize: MainAxisSize.max,
+        children: [
+          Container(
+            width: MediaQuery.of(context).size.width - 30,
+            height: 100,
+            margin: const EdgeInsets.only(left: 15,right: 15,top: 12.5),
+            child: Row(
+              mainAxisAlignment: MainAxisAlignment.start,
+              crossAxisAlignment: CrossAxisAlignment.center,
+              children: [
+                Expanded(child: _buildItemLeftSection(context, ref, item, _vm)),
+                Container(
+                  width: 100,
+                  child: _buildItemRightSection(context, ref, item, _vm),
+                  // child: TextButton(onPressed: (){}, child: Text("fdsfds")),
+                ),
+              ],
+            ),
+          ).constrained(
+            minHeight: 117.5,
+          ),
+        ],
+      ).onTap((){
+        // 去详情
+        _vm.goNewsDetail(item);
+      }),
+    ).border(color: ColorUtils.string2Color('C9C9C9FF'), bottom: 0.5);
+  }
+
+  // list
+  Widget _buildSaleList(BuildContext context, WidgetRef ref, _vm) {
+    List itemsList = _vm.state.list.toList();
+    return ListView.builder(
+      itemCount: itemsList.length,
+      itemBuilder: (context, index) {
+        return _buildSaleItem(context, ref, itemsList[index], _vm);
+      },
+    );
+  }
+
   @override
   Widget build(BuildContext context, WidgetRef ref) {
     final _vm = ref.read(propertySaleVmProvider.notifier);
 
     return Scaffold(
       // appBar: AppBar(title: Text("资产")),
-      body: Center(
-        child: Text("房屋sale的主页面"),
+      body: Container(
+          child: EasyRefresh(
+            // 上拉加载
+            onLoad: () async{
+              Log.d("----onLoad");
+              _vm.onLoadData();
+            },
+            // 下拉刷新
+            onRefresh: () async{
+              Log.d("----onRefresh");
+              _vm.refreshListData();
+            },
+            child: Container(
+                color: Colors.white,
+                margin: const EdgeInsets.only(top: 5),
+                child: _buildSaleList(context, ref, _vm)
+            ),
+          )
       ),
     );
   }

+ 49 - 0
packages/cpt_property/lib/modules/sale/page/property_sale_state.dart

@@ -0,0 +1,49 @@
+/// YApi QuickType插件生成,具体参考文档:https://plugins.jetbrains.com/plugin/18847-yapi-quicktype/documentation
+
+import 'dart:convert';
+
+PropertySaleState propertySaleStateFromJson(String str) => PropertySaleState.fromJson(json.decode(str));
+
+String propertySaleStateToJson(PropertySaleState data) => json.encode(data.toJson());
+
+class PropertySaleState {
+  PropertySaleState({
+    required this.curPage,
+    required this.pageSize,
+    required this.list,
+    required this.filterCount,
+  });
+
+  int curPage;
+  int pageSize;
+  List<Map<String, dynamic>> list;
+  int filterCount;
+
+  factory PropertySaleState.fromJson(Map<dynamic, dynamic> json) => PropertySaleState(
+    curPage: json["curPage"],
+    pageSize: json["pageSize"],
+    list: List<Map<String, dynamic>>.from(json["list"].map((x) => x)),
+    filterCount: json["filterCount"],
+  );
+
+  Map<dynamic, dynamic> toJson() => {
+    "curPage": curPage,
+    "pageSize": pageSize,
+    "list": List<dynamic>.from(list.map((x) => x)),
+    "filterCount": filterCount,
+  };
+
+  PropertySaleState copyWith({
+    int? curPage,
+    int? pageSize,
+    List<Map<String, dynamic>>? list,
+    int? filterCount,
+  }) {
+    return PropertySaleState(
+      curPage: curPage ?? this.curPage,
+      pageSize: pageSize ?? this.pageSize,
+      list: list ?? this.list,
+      filterCount: filterCount ?? this.filterCount,
+    );
+  }
+}

+ 70 - 0
packages/cpt_property/lib/modules/sale/repository/property_sale_repository.dart

@@ -0,0 +1,70 @@
+import 'package:domain/constants/api_constants.dart';
+import 'package:domain/entity/server_time.dart';
+import 'package:plugin_platform/platform_export.dart';
+import 'package:plugin_platform/http/dio_engine.dart';
+import 'package:plugin_platform/http/http_result.dart';
+import 'package:riverpod_annotation/riverpod_annotation.dart';
+import 'package:shared/utils/util.dart';
+
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:plugin_basic/provider/http_provider/http_provider.dart';
+
+import '../page/property_sale_state.dart';
+part 'property_sale_repository.g.dart';
+
+@Riverpod(keepAlive: true)
+PropertySaleRepository propertySaleRepository(Ref ref) {
+  final dioEngine = ref.watch(dioEngineProvider);
+  return PropertySaleRepository(dioEngine: dioEngine);
+}
+
+/*
+ * 数据仓库
+ */
+class PropertySaleRepository {
+  DioEngine dioEngine;
+
+  PropertySaleRepository({required this.dioEngine});
+
+  Future<HttpResult<Object>> fetchPropertyNewsList(
+      Map<String, dynamic>? data, {
+        CancelToken? cancelToken,
+      }) async {
+    Map<String, dynamic> params = {};
+
+    // if (!Utils.isEmpty(type)) {
+    //   params["type"] = type!;
+    // }
+
+    params = data!;
+
+
+    Map<String, String> headers = {};
+
+    headers["Content-Type"] = "application/x-www-form-urlencoded";
+    headers["Accept"] = "application/x.yyjobs-api.v1+json";
+
+    final result = await dioEngine.requestNetResult(
+      // ApiConstants.apiServerTime, // api 地址
+      '/index.php/api/employee/extra/time', // api 地址
+      params: params,
+      headers: headers,
+      method: HttpMethod.GET,
+      isShowLoadingDialog: true,  //是否展示默认的Loading弹窗
+      networkDebounce: true,   //是否防抖防止重复请求
+      cancelToken: cancelToken,
+    );
+
+    //根据返回的结果,封装原始数据为Bean/Entity对象
+    if (result.isSuccess) {
+      //重新赋值data或list
+      final json = result.getDataJson();
+      var data = PropertySaleState.fromJson(json!);
+      //重新赋值data或list
+      return result.convert<PropertySaleState>(data: data);
+    }
+    return result.convert();
+  }
+
+
+}

+ 29 - 0
packages/cpt_property/lib/modules/sale/repository/property_sale_repository.g.dart

@@ -0,0 +1,29 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'property_sale_repository.dart';
+
+// **************************************************************************
+// RiverpodGenerator
+// **************************************************************************
+
+String _$propertySaleRepositoryHash() =>
+    r'576b1e80b34d01e5983f264c64125501e88dc8f4';
+
+/// See also [propertySaleRepository].
+@ProviderFor(propertySaleRepository)
+final propertySaleRepositoryProvider =
+    Provider<PropertySaleRepository>.internal(
+  propertySaleRepository,
+  name: r'propertySaleRepositoryProvider',
+  debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
+      ? null
+      : _$propertySaleRepositoryHash,
+  dependencies: null,
+  allTransitiveDependencies: null,
+);
+
+@Deprecated('Will be removed in 3.0. Use Ref instead')
+// ignore: unused_element
+typedef PropertySaleRepositoryRef = ProviderRef<PropertySaleRepository>;
+// ignore_for_file: type=lint
+// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package

+ 90 - 3
packages/cpt_property/lib/modules/sale/vm/property_sale_vm.dart

@@ -1,13 +1,100 @@
-
+import 'package:plugin_platform/http/http_result.dart';
 import 'package:riverpod_annotation/riverpod_annotation.dart';
-
+import 'package:shared/utils/log_utils.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import '../page/property_sale_state.dart';
+import '../repository/property_sale_repository.dart';
 part 'property_sale_vm.g.dart';
 
 @riverpod
 class PropertySaleVm extends _$PropertySaleVm {
+  late PropertySaleRepository propertySaleRepository;
+  PropertySaleState initState() {
+    return PropertySaleState(
+      curPage: 1,
+      pageSize: 10,
+      list: [
+        {
+          "id": 1,
+          "title": "18 Sep 2024 BIK 39#09-XX 1337 psd 1001 sqft",
+          "price": "\$1.338 M",
+        },
+        {
+          "id": 2,
+          "title": "18 Sep 2024 BIK 39#09-XX 1337 psd 1001 sqft",
+          "price": "\$1.338 M",
+        },
+      ],
+      filterCount: 2,
+    );
+  }
 
   @override
-  void build(){
+  PropertySaleState build() {
+    // 引入数据仓库
+    propertySaleRepository = ref.read(propertySaleRepositoryProvider);
+    // 初始化状态
+    PropertySaleState state = initState();
+    // 初始化列表数据
+    return state;
+  }
+
+  // 初始化页面数据
+  initPageData() {
+    Log.d("----property_news_vm-----initPageData");
+    refreshListData();
+  }
+
+  // 上拉加载
+  Future onLoadData() async {
+    Log.d("----property_news_vm-----initListData");
+    // await Future.delayed(const Duration(seconds: 2));
+    // if(state.list.length >= state.filterCount){
+    //   return;
+    // }else {
+    //   int curPage = state.curPage + 1;
+    //   state = state.copyWith(curPage: curPage,);
+    //   getListData();
+    // }
+    getListData();
+  }
+
+  // 获取list 列表数据
+  void getListData<T>() async {
+    Log.d("加载listData数据---------------start-----");
+    try {
+      //请求网络
+      Map<String, dynamic>  params = {
+        "curPage": state.curPage,
+        "pageSize": state.pageSize,
+      };
+      Log.d("请求参数------$params");
+      final result = await propertySaleRepository.fetchPropertyNewsList(params);
+      Log.d("请求完成结果------${result.data}");
+      //校验成功失败
+      if (result.isSuccess) {
+        // state = state.copyWith(serverTime: result.data);
+        state = state;
+        ToastEngine.show("获取数据成功");
+      } else {
+        ToastEngine.show(result.errorMsg ?? "Network Load Error");
+      }
+    } catch (e) {
+      ToastEngine.show("Error: $e");
+    }
+  }
+
+
+  // 下拉刷新
+  Future refreshListData() async {
+    Log.d("----property_news_vm-----refreshListData ");
+
+    // await Future.delayed(const Duration(seconds: 2));
+
+    state = state.copyWith(curPage: 1, pageSize: 10);
+    // ref.invalidateSelf();
+    // ref.invalidate(propertyNewsVmProvider);
+    getListData();
 
   }
 

+ 3 - 3
packages/cpt_property/lib/modules/sale/vm/property_sale_vm.g.dart

@@ -6,12 +6,12 @@ part of 'property_sale_vm.dart';
 // RiverpodGenerator
 // **************************************************************************
 
-String _$propertySaleVmHash() => r'0f03c435057215656f637aef71c2458299f34fa3';
+String _$propertySaleVmHash() => r'f24b1a7b9cbe075d7ed60302ab0c1d170359729b';
 
 /// See also [PropertySaleVm].
 @ProviderFor(PropertySaleVm)
 final propertySaleVmProvider =
-    AutoDisposeNotifierProvider<PropertySaleVm, void>.internal(
+    AutoDisposeNotifierProvider<PropertySaleVm, PropertySaleState>.internal(
   PropertySaleVm.new,
   name: r'propertySaleVmProvider',
   debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
@@ -21,6 +21,6 @@ final propertySaleVmProvider =
   allTransitiveDependencies: null,
 );
 
-typedef _$PropertySaleVm = AutoDisposeNotifier<void>;
+typedef _$PropertySaleVm = AutoDisposeNotifier<PropertySaleState>;
 // ignore_for_file: type=lint
 // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package

+ 9 - 1
packages/cpt_property/lib/router/page/property_page_router.dart

@@ -4,8 +4,9 @@ import 'package:router/ext/auto_router_extensions.dart';
 import 'package:router/path/router_path.dart';
 
 import '../../modules/property/page/property_page.dart';
-import '../../modules/ioan/page/property_ioan_page.dart';
+import '../../modules/ioan/property_ioan_page.dart';
 import '../../modules/news/page/property_news_page.dart';
+import '../../modules/news_detail/property_news_detail_page.dart';
 import '../../modules/sale/page/property_sale_page.dart';
 import '../../modules/rent/page/property_rent_page.dart';
 
@@ -46,5 +47,12 @@ class PropertyPageRouter extends _$PropertyPageRouter {
         ),
       ]
     ),
+    // 新闻详情页面
+    CustomRoute(
+      page: PropertyNewsDetailPageRoute.page,
+      path: RouterPath.propertyNewsDetail,
+      transitionsBuilder: applySlideTransition,
+      children: const []
+    ),
   ];
 }

+ 20 - 0
packages/cpt_property/lib/router/page/property_page_router.gr.dart

@@ -21,6 +21,12 @@ abstract class _$PropertyPageRouter extends RootStackRouter {
         child: const PropertyIoanPage(),
       );
     },
+    PropertyNewsDetailPageRoute.name: (routeData) {
+      return AutoRoutePage<dynamic>(
+        routeData: routeData,
+        child: const PropertyNewsDetailPage(),
+      );
+    },
     PropertyNewsPageRoute.name: (routeData) {
       return AutoRoutePage<dynamic>(
         routeData: routeData,
@@ -63,6 +69,20 @@ class PropertyIoanPageRoute extends PageRouteInfo<void> {
 }
 
 /// generated route for
+/// [PropertyNewsDetailPage]
+class PropertyNewsDetailPageRoute extends PageRouteInfo<void> {
+  const PropertyNewsDetailPageRoute({List<PageRouteInfo>? children})
+      : super(
+          PropertyNewsDetailPageRoute.name,
+          initialChildren: children,
+        );
+
+  static const String name = 'PropertyNewsDetailPageRoute';
+
+  static const PageInfo<void> page = PageInfo<void>(name);
+}
+
+/// generated route for
 /// [PropertyNewsPage]
 class PropertyNewsPageRoute extends PageRouteInfo<void> {
   const PropertyNewsPageRoute({List<PageRouteInfo>? children})

+ 6 - 0
packages/cpt_property/pubspec.yaml

@@ -48,6 +48,9 @@ dependencies:
   # Hooks 简化 Riverpod 获取
   hooks_riverpod: ^2.5.1
 
+  # freezed 注解
+  freezed_annotation: ^2.2.0
+
 dev_dependencies:
   flutter_test:
     sdk: flutter
@@ -66,6 +69,9 @@ dev_dependencies:
   # AutoRouter 生成代码
   auto_route_generator: ^8.0.0
 
+  # json序列化
+  freezed: ^2.2.0
+
 
 flutter:
   uses-material-design: true

+ 4 - 0
packages/cpt_rewards/devtools_options.yaml

@@ -0,0 +1,4 @@
+description: This file stores settings for Dart & Flutter DevTools.
+documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
+extensions:
+  - provider: true

+ 4 - 0
packages/cpt_services/devtools_options.yaml

@@ -0,0 +1,4 @@
+description: This file stores settings for Dart & Flutter DevTools.
+documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
+extensions:
+  - provider: true

+ 4 - 0
packages/cs_domain/devtools_options.yaml

@@ -0,0 +1,4 @@
+description: This file stores settings for Dart & Flutter DevTools.
+documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
+extensions:
+  - provider: true

+ 14 - 7
packages/cs_domain/lib/generated/json/base/json_convert_content.dart

@@ -62,12 +62,14 @@ class JsonConvert {
     }
   }
 
-  List<T?>? convertList<T>(List<dynamic>? value, {EnumConvertFunction? enumConvert}) {
+  List<T?>? convertList<T>(List<dynamic>? value,
+      {EnumConvertFunction? enumConvert}) {
     if (value == null) {
       return null;
     }
     try {
-      return value.map((dynamic e) => _asT<T>(e, enumConvert: enumConvert)).toList();
+      return value.map((dynamic e) => _asT<T>(e, enumConvert: enumConvert))
+          .toList();
     } catch (e, stackTrace) {
       debugPrint('asT<$T> $e $stackTrace');
       if (onError != null) {
@@ -77,12 +79,14 @@ class JsonConvert {
     }
   }
 
-  List<T>? convertListNotNull<T>(dynamic value, {EnumConvertFunction? enumConvert}) {
+  List<T>? convertListNotNull<T>(dynamic value,
+      {EnumConvertFunction? enumConvert}) {
     if (value == null) {
       return null;
     }
     try {
-      return (value as List<dynamic>).map((dynamic e) => _asT<T>(e, enumConvert: enumConvert)!).toList();
+      return (value as List<dynamic>).map((dynamic e) =>
+      _asT<T>(e, enumConvert: enumConvert)!).toList();
     } catch (e, stackTrace) {
       debugPrint('asT<$T> $e $stackTrace');
       if (onError != null) {
@@ -130,7 +134,8 @@ class JsonConvert {
           return covertFunc(Map<String, dynamic>.from(value)) as T;
         }
       } else {
-        throw UnimplementedError('$type unimplemented,you can try running the app again');
+        throw UnimplementedError(
+            '$type unimplemented,you can try running the app again');
       }
     }
   }
@@ -138,7 +143,8 @@ class JsonConvert {
   //list is returned by type
   static M? _getListChildType<M>(List<Map<String, dynamic>> data) {
     if (<ServerTime>[] is M) {
-      return data.map<ServerTime>((Map<String, dynamic> e) => ServerTime.fromJson(e)).toList() as M;
+      return data.map<ServerTime>((Map<String, dynamic> e) =>
+          ServerTime.fromJson(e)).toList() as M;
     }
 
     debugPrint("$M not found");
@@ -151,7 +157,8 @@ class JsonConvert {
       return json;
     }
     if (json is List) {
-      return _getListChildType<M>(json.map((dynamic e) => e as Map<String, dynamic>).toList());
+      return _getListChildType<M>(
+          json.map((dynamic e) => e as Map<String, dynamic>).toList());
     } else {
       return jsonConvert.convert<M>(json);
     }

+ 4 - 0
packages/cs_initializer/devtools_options.yaml

@@ -0,0 +1,4 @@
+description: This file stores settings for Dart & Flutter DevTools.
+documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
+extensions:
+  - provider: true

+ 4 - 0
packages/cs_plugin_basic/devtools_options.yaml

@@ -0,0 +1,4 @@
+description: This file stores settings for Dart & Flutter DevTools.
+documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
+extensions:
+  - provider: true

+ 4 - 0
packages/cs_plugin_platform/devtools_options.yaml

@@ -0,0 +1,4 @@
+description: This file stores settings for Dart & Flutter DevTools.
+documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
+extensions:
+  - provider: true

BIN=BIN
packages/cs_resources/assets/community/camera.webp


BIN=BIN
packages/cs_resources/assets/community/comments.webp


BIN=BIN
packages/cs_resources/assets/community/follow_add.webp


BIN=BIN
packages/cs_resources/assets/community/garage_sale.webp


BIN=BIN
packages/cs_resources/assets/community/like.webp


BIN=BIN
packages/cs_resources/assets/community/like_active.webp


BIN=BIN
packages/cs_resources/assets/community/nes_feed.webp


BIN=BIN
packages/cs_resources/assets/community/share.webp


BIN=BIN
packages/cs_resources/assets/property/advice_pic.webp


BIN=BIN
packages/cs_resources/assets/property/advice_pic@2x.png


BIN=BIN
packages/cs_resources/assets/property/approval.webp


BIN=BIN
packages/cs_resources/assets/property/approval@2x.png


BIN=BIN
packages/cs_resources/assets/property/collection.webp


BIN=BIN
packages/cs_resources/assets/property/collection_active.webp


BIN=BIN
packages/cs_resources/assets/property/conveyancing_lawyer.webp


BIN=BIN
packages/cs_resources/assets/property/conveyancing_lawyer@2x.png


BIN=BIN
packages/cs_resources/assets/property/home_equity_loans.webp


BIN=BIN
packages/cs_resources/assets/property/home_equity_loans@2x.png


BIN=BIN
packages/cs_resources/assets/property/home_loan_bg.webp


BIN=BIN
packages/cs_resources/assets/property/home_loan_bg@2x.png


BIN=BIN
packages/cs_resources/assets/property/ioan.webp


BIN=BIN
packages/cs_resources/assets/property/ioan@2x.png


BIN=BIN
packages/cs_resources/assets/property/new_home_loans.webp


BIN=BIN
packages/cs_resources/assets/property/new_home_loans@2x.png


BIN=BIN
packages/cs_resources/assets/property/news-item-bg.webp


BIN=BIN
packages/cs_resources/assets/property/news.webp


BIN=BIN
packages/cs_resources/assets/property/news@2x.png


BIN=BIN
packages/cs_resources/assets/property/our_partners.webp


BIN=BIN
packages/cs_resources/assets/property/our_partners@2x.png


BIN=BIN
packages/cs_resources/assets/property/overseas_home_loan.webp


BIN=BIN
packages/cs_resources/assets/property/overseas_home_loan@2x.png


BIN=BIN
packages/cs_resources/assets/property/refinancing.webp


BIN=BIN
packages/cs_resources/assets/property/refinancing@2x.png


BIN=BIN
packages/cs_resources/assets/property/rent.webp


BIN=BIN
packages/cs_resources/assets/property/rent@2x.png


BIN=BIN
packages/cs_resources/assets/property/sale.webp


BIN=BIN
packages/cs_resources/assets/property/sale@2x.png


+ 1 - 0
packages/cs_resources/pubspec.yaml

@@ -29,6 +29,7 @@ flutter:
     - assets/base_service/
     - assets/property/
     - assets/auth/
+    - assets/community/
     - assets/main/
 
 

+ 1 - 0
packages/cs_router/lib/path/router_path.dart

@@ -52,6 +52,7 @@ class RouterPath {
   static const propertyNews = 'property/news';
   static const propertySale = 'property/sale';
   static const propertyRent = 'property/rent';
+  static const propertyNewsDetail = '/property_news_detail';
 
   //奖励
   static const rewards = '/rewards';

+ 26 - 0
packages/cs_shared/lib/utils/color_utils.dart

@@ -0,0 +1,26 @@
+import 'package:flutter/material.dart';
+class ColorUtils {
+  // 颜色值转换
+  static Color string2Color(String colorString) {
+    int? value = 0x00000000;
+    if (colorString.isNotEmpty) {
+      if (colorString[0] == '#') {
+        colorString = colorString.substring(1);
+      }
+      value = int.tryParse(colorString, radix: 16);
+      if (value != null) {
+        if (value < 0xFF000000) {
+          value += 0xFF000000;
+        }
+      }
+    }
+    return Color(value!);
+  }
+
+  static Color hexToColor(String hex) {
+    assert(RegExp(r'^#([0-9a-fA-F]{6})|([0-9a-fA-F]{8})$').hasMatch(hex), 'hex color must be #rrggbb or #rrggbbaa');
+    return Color(
+      int.parse(hex.substring(1), radix: 16) + (hex.length == 7 ? 0xff000000 : 0x00000000),
+    );
+  }
+}

+ 35 - 0
packages/cs_shared/lib/utils/util.dart

@@ -136,4 +136,39 @@ class Utils {
     return greeting;
   }
 
+  /// 将时间转化为 多久之前
+  static String getTimeAgo(String? dateTimeStr) {
+    if (dateTimeStr == null || dateTimeStr.isEmpty) {
+      return 'Unknown time'; // 或者返回其他默认值
+    }
+
+    DateTime? dateTime;
+    try {
+      dateTime = DateTime.parse(dateTimeStr);
+    } catch (e) {
+      return 'Invalid date format'; // 或者返回其他默认值
+    }
+
+    if (dateTime == null) {
+      return 'Unknown time'; // 或者返回其他默认值
+    }
+
+    final now = DateTime.now();
+    final difference = now.difference(dateTime);
+
+    if (difference.inHours < 1) {
+      return "${difference.inMinutes} minutes ago";
+    } else if (difference.inHours < 24) {
+      return "${difference.inHours} hours ago";
+    } else if (difference.inDays < 7) {
+      return "${difference.inDays} days ago";
+    } else if (difference.inDays < 30) {
+      return "${(difference.inDays / 7).floor()} weeks ago";
+    } else if (difference.inDays < 365) {
+      return "${(difference.inDays / 30).floor()} months ago";
+    } else {
+      return "${(difference.inDays / 365).floor()} years ago";
+    }
+  }
+
 }