Browse Source

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

liukai 6 days ago
parent
commit
866e7f60e3
37 changed files with 1625 additions and 787 deletions
  1. 114 119
      packages/cpt_community/lib/components/garage_card.dart
  2. 6 9
      packages/cpt_community/lib/components/newsfeed_card_content.dart
  3. 64 66
      packages/cpt_community/lib/components/newsfeed_card_footer.dart
  4. 53 66
      packages/cpt_community/lib/modules/community/community_page.dart
  5. 1 1
      packages/cpt_community/lib/modules/community/community_vm.g.dart
  6. 4 2
      packages/cpt_community/lib/modules/community/news/news_page.dart
  7. 2 0
      packages/cpt_community/lib/modules/community/news/news_vm.dart
  8. 1 1
      packages/cpt_community/lib/modules/community/news/news_vm.g.dart
  9. 224 29
      packages/cpt_community/lib/modules/community/newsfeed_detail/newsfeed_detail_page.dart
  10. 45 5
      packages/cpt_community/lib/modules/community/newsfeed_detail/newsfeed_detail_state.dart
  11. 129 4
      packages/cpt_community/lib/modules/community/newsfeed_detail/newsfeed_detail_vm.dart
  12. 1 1
      packages/cpt_community/lib/modules/community/newsfeed_detail/newsfeed_detail_vm.g.dart
  13. 2 7
      packages/cpt_community/lib/modules/garage/for_rent/for_rent_vm.dart
  14. 1 1
      packages/cpt_community/lib/modules/garage/for_rent/for_rent_vm.g.dart
  15. 51 44
      packages/cpt_community/lib/modules/garage/for_sale/for_sale_page.dart
  16. 28 11
      packages/cpt_community/lib/modules/garage/for_sale/for_sale_state.dart
  17. 159 105
      packages/cpt_community/lib/modules/garage/for_sale/for_sale_vm.dart
  18. 1 1
      packages/cpt_community/lib/modules/garage/for_sale/for_sale_vm.g.dart
  19. 52 66
      packages/cpt_community/lib/modules/garage/garage_page.dart
  20. 1 1
      packages/cpt_community/lib/modules/garage/garage_vm.g.dart
  21. 91 3
      packages/cpt_community/lib/modules/garage/garagesale_detail/garagesale_detail_page.dart
  22. 36 0
      packages/cpt_community/lib/modules/garage/garagesale_detail/garagesale_detail_state.dart
  23. 96 0
      packages/cpt_community/lib/modules/garage/garagesale_detail/garagesale_detail_vm.dart
  24. 27 0
      packages/cpt_community/lib/modules/garage/garagesale_detail/garagesale_detail_vm.g.dart
  25. 1 1
      packages/cpt_main/lib/modules/feedback/history/feedback_history.dart
  26. 22 18
      packages/cpt_property/lib/modules/news/page/property_news_page.dart
  27. 3 3
      packages/cpt_property/lib/modules/news/page/property_news_state.dart
  28. 45 15
      packages/cpt_property/lib/modules/news/vm/property_news_vm.dart
  29. 10 6
      packages/cpt_property/lib/modules/property/page/property_page.dart
  30. 32 18
      packages/cpt_property/lib/modules/rent/page/property_rent_page.dart
  31. 42 26
      packages/cpt_property/lib/modules/rent/page/property_rent_state.dart
  32. 1 1
      packages/cpt_property/lib/modules/rent/repository/property_rent_repository.dart
  33. 100 51
      packages/cpt_property/lib/modules/rent/vm/property_rent_vm.dart
  34. 40 30
      packages/cpt_property/lib/modules/sale/page/property_sale_page.dart
  35. 41 26
      packages/cpt_property/lib/modules/sale/page/property_sale_state.dart
  36. 1 1
      packages/cpt_property/lib/modules/sale/repository/property_sale_repository.dart
  37. 98 49
      packages/cpt_property/lib/modules/sale/vm/property_sale_vm.dart

+ 114 - 119
packages/cpt_community/lib/components/garage_card.dart

@@ -45,131 +45,126 @@ class GarageCard extends StatelessWidget {
 
   @override
   Widget build(BuildContext context) {
-    return Container(
-      // height: cardHeight,
-      child: Expanded(
-        child: Column(
+    return Column(
+      children: [
+        // 图片
+        Row(
+          mainAxisAlignment: MainAxisAlignment.center,
+          crossAxisAlignment: CrossAxisAlignment.center,
           children: [
-            // 图片
-            Row(
-              mainAxisAlignment: MainAxisAlignment.center,
-              crossAxisAlignment: CrossAxisAlignment.center,
-              children: [
-                Expanded(
-                  child: ClipRRect(
-                    borderRadius: const BorderRadius.only(topLeft: Radius.circular(8), topRight: Radius.circular(8),),
-                    child: MyLoadImage(
-                      itemObj['goods_img'],
-                      width: 166.5,
-                      height: 102.5,
-                      isCircle: false,
-                      fit: BoxFit.cover,
-                    ).onTap(() {
-                      // 点击头像
-                      // onTap?.call();
-                    }),
-                  ),
-                ),
-              ],
-            ),
-            // 标题
-            Padding(
-              padding: const EdgeInsets.only(left: 10, right: 10, top: 12, bottom: 12),
-              child: Row(
-                mainAxisAlignment: MainAxisAlignment.center,
-                children: [
-                  Expanded(
-                    child: MyTextView(
-                      itemObj['title'],
-                      maxLines: 1,
-                      isTextEllipsis: true,
-                      textAlign: TextAlign.left,
-                      textColor: context.appColors.textBlack,
-                      fontSize: 16,
-                      isFontRegular: true,
-                    ),
-                  ),
-                ],
+            Expanded(
+              child: ClipRRect(
+                borderRadius: const BorderRadius.only(topLeft: Radius.circular(8), topRight: Radius.circular(8),),
+                child: MyLoadImage(
+                  itemObj['goods_img'],
+                  width: 166.5,
+                  height: 102.5,
+                  isCircle: false,
+                  fit: BoxFit.cover,
+                ).onTap(() {
+                  // 点击头像
+                  // onTap?.call();
+                }),
               ),
             ),
-            // 价格 及 收藏
-            Padding(
-              padding: const EdgeInsets.only(left: 10, right: 10,top: 10, bottom: 10),
-              child: Row(
-                mainAxisAlignment: MainAxisAlignment.spaceAround,
-                crossAxisAlignment: CrossAxisAlignment.center,
-                children: [
-                  Expanded(
-                    child: MyTextView(
-                      itemObj['price'],
-                      maxLines: 1,
-                      isTextEllipsis: true,
-                      textAlign: TextAlign.start,
-                      textColor: ColorUtils.string2Color('#4161D0'),
-                      fontSize: 18,
-                      isFontMedium: true,
-                    ),
-                  ),
-                  // 动态的 收藏数
-                  CollectionWidget(
-                      collectionNum: itemObj['collection_num'],
-                      isCollection: itemObj['isCollection'],
-                      onClickColleciotn: onClickColleciotn,
-                  ),
-                ],
+          ],
+        ),
+        // 标题
+        Padding(
+          padding: const EdgeInsets.only(left: 10, right: 10, top: 12, bottom: 12),
+          child: Row(
+            mainAxisAlignment: MainAxisAlignment.center,
+            children: [
+              Expanded(
+                child: MyTextView(
+                  itemObj['title'],
+                  maxLines: 1,
+                  isTextEllipsis: true,
+                  textAlign: TextAlign.left,
+                  textColor: context.appColors.textBlack,
+                  fontSize: 16,
+                  isFontRegular: true,
+                ),
               ),
-            ),
-            // 发布人信息
-            Expanded(
-              child: Padding(
-                padding: const EdgeInsets.only(left: 10, right: 10),
-                child: Row(
-                  mainAxisAlignment: MainAxisAlignment.spaceAround,
-                  crossAxisAlignment: CrossAxisAlignment.center,
-                  children: [
-                    MyLoadImage(
-                      itemObj['publisher_avator'],
-                      width: 30,
-                      height: 30,
-                      isCircle: true,
-                    ),
-                    Expanded(
-                      child: Column(
-                        mainAxisAlignment: MainAxisAlignment.center,
-                        crossAxisAlignment: CrossAxisAlignment.start,
-                        mainAxisSize: MainAxisSize.max,
-                        children: [
-                          MyTextView(
-                            itemObj['publisher'],
-                            maxLines: 1,
-                            isTextEllipsis: true,
-                            textAlign: TextAlign.start,
-                            marginLeft: 13,
-                            fontSize: 12,
-                            textColor: ColorUtils.string2Color('#2956B7'),
-                            isFontRegular: true,
-                          ),
-                          MyTextView(
-                            itemObj['publish_time'],
-                            maxLines: 1,
-                            isTextEllipsis: true,
-                            textAlign: TextAlign.start,
-                            marginLeft: 13,
-                            marginTop: 5,
-                            fontSize: 10,
-                            textColor: context.appColors.textBlack,
-                            isFontRegular: true,
-                          ),
-                        ]
-                      )
-                    ),
-                  ]
-                )
+            ],
+          ),
+        ),
+        // 价格 及 收藏
+        Padding(
+          padding: const EdgeInsets.only(left: 10, right: 10,top: 10, bottom: 10),
+          child: Row(
+            mainAxisAlignment: MainAxisAlignment.spaceAround,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              Expanded(
+                child: MyTextView(
+                  itemObj['price'],
+                  maxLines: 1,
+                  isTextEllipsis: true,
+                  textAlign: TextAlign.start,
+                  textColor: ColorUtils.string2Color('#4161D0'),
+                  fontSize: 18,
+                  isFontMedium: true,
+                ),
               ),
-            )
-          ],
+              // 动态的 收藏数
+              CollectionWidget(
+                  collectionNum: itemObj['collection_num'],
+                  isCollection: itemObj['isCollection'],
+                  onClickColleciotn: onClickColleciotn,
+              ),
+            ],
+          ),
         ),
-      ),
+        // 发布人信息
+        Expanded(
+          child: Padding(
+            padding: const EdgeInsets.only(left: 10, right: 10),
+            child: Row(
+              mainAxisAlignment: MainAxisAlignment.spaceAround,
+              crossAxisAlignment: CrossAxisAlignment.center,
+              children: [
+                MyLoadImage(
+                  itemObj['publisher_avator'],
+                  width: 30,
+                  height: 30,
+                  isCircle: true,
+                ),
+                Expanded(
+                  child: Column(
+                    mainAxisAlignment: MainAxisAlignment.center,
+                    crossAxisAlignment: CrossAxisAlignment.start,
+                    mainAxisSize: MainAxisSize.max,
+                    children: [
+                      MyTextView(
+                        itemObj['publisher'],
+                        maxLines: 1,
+                        isTextEllipsis: true,
+                        textAlign: TextAlign.start,
+                        marginLeft: 13,
+                        fontSize: 12,
+                        textColor: ColorUtils.string2Color('#2956B7'),
+                        isFontRegular: true,
+                      ),
+                      MyTextView(
+                        itemObj['publish_time'],
+                        maxLines: 1,
+                        isTextEllipsis: true,
+                        textAlign: TextAlign.start,
+                        marginLeft: 13,
+                        marginTop: 5,
+                        fontSize: 10,
+                        textColor: context.appColors.textBlack,
+                        isFontRegular: true,
+                      ),
+                    ]
+                  )
+                ),
+              ]
+            )
+          ),
+        )
+      ],
     );
   }
 }

+ 6 - 9
packages/cpt_community/lib/components/newsfeed_card_content.dart

@@ -29,15 +29,12 @@ class NewsFeedCardContent extends StatelessWidget {
       child: Column(
         children: [
           Expanded(
-            child: Container(
-              // color: Colors.red,
-              child: MyTextView(
-                content,
-                textColor: ColorUtils.string2Color('#000000'),
-                fontSize: 15,
-                maxLines: 3,
-                isTextEllipsis: true,
-              ),
+            child: MyTextView(
+              content,
+              textColor: ColorUtils.string2Color('#000000'),
+              fontSize: 15,
+              maxLines: 3,
+              isTextEllipsis: true,
             ),
           ),
           const SizedBox(height: 12),

+ 64 - 66
packages/cpt_community/lib/components/newsfeed_card_footer.dart

@@ -39,72 +39,70 @@ class NewsFeedCardFooter extends StatelessWidget {
       width: double.infinity,
       padding: const EdgeInsets.symmetric(horizontal: 16),
       // color: Colors.red,
-      child: Expanded(
-        child:  Row(
-          mainAxisAlignment: MainAxisAlignment.spaceBetween,
-          children: [
-            Container(
-              height: 40,
-              padding: const EdgeInsets.all(8),
-              child: Row(
-                children: [
-                  const MyAssetImage(Assets.communityLike, width: 16,height: 16,),
-                  MyTextView(
-                    'Like',
-                    textColor: ColorUtils.string2Color('#767676'),
-                    fontSize: 14,
-                    isFontRegular: true,
-                    textAlign: TextAlign.left,
-                    marginLeft: 8,
-                  ),
-                ],
-              ),
-            ).onTap((){
-              Log.d("点击了like");
-              onLike?.call();
-            }),
-            Container(
-              height: 40,
-              padding: const EdgeInsets.all(8),
-              child: Row(
-                children: [
-                  const MyAssetImage(Assets.communityComments, width: 16,height: 16,),
-                  MyTextView(
-                    'Comments',
-                    textColor: ColorUtils.string2Color('#767676'),
-                    fontSize: 14,
-                    isFontRegular: true,
-                    textAlign: TextAlign.left,
-                    marginLeft: 8,
-                  ),
-                ],
-              ),
-            ).onTap((){
-              Log.d("点击了comments");
-              onComment?.call();
-            }),
-            Container(
-              height: 40,
-              padding: const EdgeInsets.all(8),
-              child: Row(
-                children: [
-                  const MyAssetImage(Assets.communityShare, width: 16,height: 16,),
-                  MyTextView(
-                    'Share',
-                    textColor: ColorUtils.string2Color('#767676'),
-                    fontSize: 14,
-                    isFontRegular: true,
-                    textAlign: TextAlign.left,
-                    marginLeft: 8,
-                  ),
-                ],
-              ),
-            ).onTap((){
-              Log.d("点击了share");
-              onShare?.call();
-            }),
-          ]
-        ),
+      child: Row(
+        mainAxisAlignment: MainAxisAlignment.spaceBetween,
+        children: [
+          Container(
+            height: 40,
+            padding: const EdgeInsets.all(8),
+            child: Row(
+              children: [
+                const MyAssetImage(Assets.communityLike, width: 16,height: 16,),
+                MyTextView(
+                  'Like',
+                  textColor: ColorUtils.string2Color('#767676'),
+                  fontSize: 14,
+                  isFontRegular: true,
+                  textAlign: TextAlign.left,
+                  marginLeft: 8,
+                ),
+              ],
+            ),
+          ).onTap((){
+            Log.d("点击了like");
+            onLike?.call();
+          }),
+          Container(
+            height: 40,
+            padding: const EdgeInsets.all(8),
+            child: Row(
+              children: [
+                const MyAssetImage(Assets.communityComments, width: 16,height: 16,),
+                MyTextView(
+                  'Comments',
+                  textColor: ColorUtils.string2Color('#767676'),
+                  fontSize: 14,
+                  isFontRegular: true,
+                  textAlign: TextAlign.left,
+                  marginLeft: 8,
+                ),
+              ],
+            ),
+          ).onTap((){
+            Log.d("点击了comments");
+            onComment?.call();
+          }),
+          Container(
+            height: 40,
+            padding: const EdgeInsets.all(8),
+            child: Row(
+              children: [
+                const MyAssetImage(Assets.communityShare, width: 16,height: 16,),
+                MyTextView(
+                  'Share',
+                  textColor: ColorUtils.string2Color('#767676'),
+                  fontSize: 14,
+                  isFontRegular: true,
+                  textAlign: TextAlign.left,
+                  marginLeft: 8,
+                ),
+              ],
+            ),
+          ).onTap((){
+            Log.d("点击了share");
+            onShare?.call();
+          }),
+        ]
       )
     );
   }

+ 53 - 66
packages/cpt_community/lib/modules/community/community_page.dart

@@ -160,7 +160,7 @@ class CommunityPage extends HookConsumerWidget {
         final topSectionsData = vm.topSectionsData;
         int curTagIdx = 0;
         return Container(
-          color: Colors.white,
+          color: context.appColors.whiteBG,
           padding: const EdgeInsets.only(top: 23, bottom: 30),
           child: Center(
             child: Row(
@@ -169,44 +169,41 @@ class CommunityPage extends HookConsumerWidget {
               crossAxisAlignment: CrossAxisAlignment.center,
               children: List.generate(topSectionsData.length, (index) {
                 final item = topSectionsData[index];
-                return Flexible(
-                  flex: 1,
-                  child: Column(
-                    children: [
-                      Container(
+                return Column(
+                  children: [
+                    Container(
+                      width: MediaQuery.of(context).size.width / topSectionsData.length - 36,
+                      height: 70,
+                      decoration: BoxDecoration(
+                        // color: currentTabIdx == index ? ColorUtils.string2Color('#E6F2FF') : Colors.white,
+                        shape: BoxShape.circle, // 设置为圆形
+                        boxShadow: index == curTagIdx ? [
+                          BoxShadow(
+                            color: context.appColors.tabLightBlueShadow, // 设置阴影颜色
+                            blurRadius: 5, // 设置模糊半径
+                            spreadRadius: 0.05, // 控制阴影扩散
+                            offset: const Offset(0, 4), // 设置阴影偏移量
+                          ),                          ] : [],// 未选中时无阴影,
+                      ),
+                      child: MyAssetImage(
+                        item['icon'],
                         width: MediaQuery.of(context).size.width / topSectionsData.length - 36,
                         height: 70,
-                        decoration: BoxDecoration(
-                          // color: currentTabIdx == index ? ColorUtils.string2Color('#E6F2FF') : Colors.white,
-                          shape: BoxShape.circle, // 设置为圆形
-                          boxShadow: index == curTagIdx ? [
-                            BoxShadow(
-                              color: context.appColors.tabLightBlueShadow, // 设置阴影颜色
-                              blurRadius: 5, // 设置模糊半径
-                              spreadRadius: 0.05, // 控制阴影扩散
-                              offset: const Offset(0, 4), // 设置阴影偏移量
-                            ),                          ] : [],// 未选中时无阴影,
-                        ),
-                        child: MyAssetImage(
-                          item['icon'],
-                          width: MediaQuery.of(context).size.width / topSectionsData.length - 36,
-                          height: 70,
-                        ).onTap(() {
-                            vm.handlerChangeCommunityType(context,index);
-                          },
-                          type: ClickType.throttle,
-                        ),
-                      ),
-                      SizedBox.fromSize(size: const Size(0, 9)),
-                      MyTextView(
-                        item['title'],
-                        fontSize: 15,
-                        textColor: index == curTagIdx ? ColorUtils.string2Color('#4161D0'):Colors.black,
-                        textAlign: TextAlign.center,
-                        isFontMedium: true,
+                      ).onTap(() {
+                          vm.handlerChangeCommunityType(context,index);
+                        },
+                        type: ClickType.throttle,
                       ),
-                    ],
-                  ),
+                    ),
+                    SizedBox.fromSize(size: const Size(0, 9)),
+                    MyTextView(
+                      item['title'],
+                      fontSize: 15,
+                      textColor: index == curTagIdx ? ColorUtils.string2Color('#4161D0'):Colors.black,
+                      textAlign: TextAlign.center,
+                      isFontMedium: true,
+                    ),
+                  ],
                 ).marginOnly(left: 18, right: 18, top: 10, bottom: 10);
               }),
             ),
@@ -241,37 +238,27 @@ class CommunityPage extends HookConsumerWidget {
             children: [
               const MyAssetImage(Assets.communityNesFeed, width: 45,height: 45,),
              Expanded(
-                child: Row(
-                  children: [
-                    Expanded(
-                      child: Container(
-                        // height: 65.5,
-                        // color: Colors.blue,
-                        child: MyTextView(
-                          "What’s on your mind?",
-                          textColor: ColorUtils.string2Color('#000000'),
-                          fontSize: 15,
-                          marginLeft: 15,
-                          alignment: Alignment.centerLeft,
-                          textAlign: TextAlign.left,
-                          backgroundColor: ColorUtils.string2Color('#ffffff'),
-                          maxLines: 1,
-                          isFontMedium: true,
-                        ),
-                      ),
-                    ),
-                    const MyAssetImage(
-                      Assets.communityCamera,
-                      width: 21,
-                      height: 16.5,
-                    ),
-                  ],
-                ).onTap((){
-                  vm.handlerGotoPost(context);
-                }),
-              ),
+               child: MyTextView(
+                 "What’s on your mind?",
+                 textColor: ColorUtils.string2Color('#000000'),
+                 fontSize: 15,
+                 marginLeft: 15,
+                 alignment: Alignment.centerLeft,
+                 textAlign: TextAlign.left,
+                 backgroundColor: ColorUtils.string2Color('#ffffff'),
+                 maxLines: 1,
+                 isFontMedium: true,
+               ),
+             ),
+             const MyAssetImage(
+               Assets.communityCamera,
+               width: 21,
+               height: 16.5,
+             ),
             ],
-          ),
+          ).onTap((){
+            vm.handlerGotoPost(context);
+          }),
         );
       }
 

+ 1 - 1
packages/cpt_community/lib/modules/community/community_vm.g.dart

@@ -6,7 +6,7 @@ part of 'community_vm.dart';
 // RiverpodGenerator
 // **************************************************************************
 
-String _$communityVmHash() => r'5d1bae55bf25ed93006f6e35a20a27627183f458';
+String _$communityVmHash() => r'e91467ce00b36b9645967931640efb4cc5674ce1';
 
 /// See also [CommunityVm].
 @ProviderFor(CommunityVm)

+ 4 - 2
packages/cpt_community/lib/modules/community/news/news_page.dart

@@ -131,7 +131,7 @@ class NewsPage extends HookConsumerWidget {
   }
 
   Widget _buildNewsItem(BuildContext context, WidgetRef ref, item, vm){
-    return Container(
+    return SizedBox(
       width: double.infinity,
       //   color: Colors.yellow,
       child: Stack(
@@ -211,7 +211,9 @@ class NewsPage extends HookConsumerWidget {
           )
         ],
       ),
-    );
+    ).onTap((){
+      vm.handlerClickActionBtn(null, item);
+    });
   }
 
   Widget _buildNewsFeedList(BuildContext context, WidgetRef ref, vm){

+ 2 - 0
packages/cpt_community/lib/modules/community/news/news_vm.dart

@@ -183,6 +183,8 @@ class NewsVm extends _$NewsVm {
         handlerGotoDetail(id);
         break;
       default:
+        Log.d("点击了卡片");
+        handlerGotoDetail(id);
         break;
     }
   }

+ 1 - 1
packages/cpt_community/lib/modules/community/news/news_vm.g.dart

@@ -6,7 +6,7 @@ part of 'news_vm.dart';
 // RiverpodGenerator
 // **************************************************************************
 
-String _$newsVmHash() => r'f5a5a082bc85c87229ff78e9b20eef1acb230831';
+String _$newsVmHash() => r'7c7cba9acfb0bfeb01c95fa0859e531d9b95ef4c';
 
 /// See also [NewsVm].
 @ProviderFor(NewsVm)

+ 224 - 29
packages/cpt_community/lib/modules/community/newsfeed_detail/newsfeed_detail_page.dart

@@ -1,16 +1,22 @@
 import 'package:cpt_community/router/page/community_page_router.dart';
+import 'package:cs_resources/generated/assets.dart';
 import 'package:cs_resources/theme/app_colors_theme.dart';
 import 'package:flutter/material.dart';
 import 'package:auto_route/auto_route.dart';
 import 'package:flutter_hooks/flutter_hooks.dart';
 import 'package:hooks_riverpod/hooks_riverpod.dart';
+import 'package:plugin_basic/provider/app_config/app_config.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/ext/ex_widget.dart';
+import 'package:widgets/load_state_layout.dart';
 import 'package:widgets/my_appbar.dart';
 import 'package:widgets/my_button.dart';
+import 'package:widgets/my_load_image.dart';
 import 'package:widgets/my_text_view.dart';
+import 'package:widgets/widget_export.dart';
+import 'package:widgets/my_button.dart';
 
 import '../../../components/newfeed_card_header.dart';
 import '../../../components/newsfeed_card_content.dart';
@@ -40,7 +46,7 @@ class NewsfeedDetailPage extends HookConsumerWidget {
     final state = ref.watch(newsfeedDetailVmProvider);
     useEffect((){
       // 组件挂载时执行 - 执行接口请求
-      // Future.microtask(() => vm.fetchList());
+      Future.microtask(() => vm.initPageData(id: id));
       return () {
         // 组件卸载时执行
       };
@@ -55,28 +61,102 @@ class NewsfeedDetailPage extends HookConsumerWidget {
       ),
       backgroundColor: ColorUtils.string2Color("#F2F3F6"),
       body: Column(
-        children: [
-          _buildTopCard(context, ref),
-         // 评论区域
-          Expanded(child: _buildCommentListCard(context, ref)),
-         //  底部 like comments 按钮区
-          Container(
-            color: ColorUtils.string2Color("#2956B7"),
-            child: Row(
-              children: [
-                Expanded(
-                  child: MyButton(
-                    minHeight: 50,
-                    text: 'Like',
-                    textColor: Colors.white,
-                    onPressed: () {},
-                  )
-                )
-              ]
-            )
-          )
-        ],
-      ),
+          mainAxisSize: MainAxisSize.max,
+          children:[
+              Expanded(
+                child: EasyRefresh(
+                  // 上拉加载
+                  onLoad: () async{
+                    Log.d("----onLoad");
+                    vm.loadMore();
+                  },
+                  // 下拉刷新
+                  onRefresh: () async{
+                    Log.d("----onRefresh");
+                    vm.onRefresh();
+                  },
+                  child: LoadStateLayout(
+                    state: state.loadingState,
+                    errorMessage: state.errorMessage,
+                    errorRetry: () {
+                      vm.retryRequest();
+                    },
+                    successSliverWidget: [
+                      SliverList(
+                        delegate: SliverChildListDelegate(
+                            [
+                            _buildTopCard(context, ref),
+                            ConstrainedBox(
+                              constraints: BoxConstraints(
+                                minHeight: MediaQuery.of(context).size.height - 250 - 150,
+                              ),
+                              child: _buildCommentListCard(context, ref),
+                            )
+                          ]
+                        ),
+                      )
+                    ],
+                  ),
+                ),
+              ),
+              SafeArea(
+                child: Visibility(
+                  visible: state.loadingState == LoadState.State_Success,
+                  child: Container(
+                    height: 60,
+                    width: MediaQuery.of(context).size.width,
+                    color: ColorUtils.string2Color("#4161D0"),
+                    child: Row(
+                        mainAxisAlignment: MainAxisAlignment.spaceBetween,
+                        crossAxisAlignment: CrossAxisAlignment.center,
+                        children: [
+                          Expanded(
+                                child: Row(
+                                  mainAxisAlignment: MainAxisAlignment.center,
+                                  crossAxisAlignment: CrossAxisAlignment.center,
+                                  children: [
+                                    MyLoadImage(
+                                      Assets.communityLike,
+                                      width: 16.5,
+                                      height: 16.5,
+                                    ),
+                                    const SizedBox(width: 10,),
+                                    MyTextView(
+                                      "Like",
+                                      textColor: context.appColors.whiteBG,
+                                      fontSize: 14,
+                                      isFontRegular: true,
+                                    ),
+                                  ],
+                                ),
+                          ),
+                          Expanded(
+                            child: Row(
+                              mainAxisAlignment: MainAxisAlignment.center,
+                              crossAxisAlignment: CrossAxisAlignment.center,
+                              children: [
+                                MyLoadImage(
+                                  Assets.communityComments,
+                                  width: 17.5,
+                                  height: 16.5,
+                                ),
+                                const SizedBox(width: 10,),
+                                MyTextView(
+                                  "Comment",
+                                  textColor: context.appColors.whiteBG,
+                                  fontSize: 14,
+                                  isFontRegular: true,
+                                ),
+                              ],
+                            ),
+                          ),
+                        ]
+                    )
+                  ),
+                ),
+              )
+          ]
+      )
     );
   }
 
@@ -153,11 +233,16 @@ class NewsfeedDetailPage extends HookConsumerWidget {
   }
 
   Widget _buildCommentListCard(BuildContext context,  WidgetRef ref){
+    final vm = ref.read(newsfeedDetailVmProvider.notifier);
     return Container(
       color: Colors.white,
       margin: const EdgeInsets.only(left: 15, right: 15,top: 18,bottom: 18),
+      padding: const EdgeInsets.only(bottom: 30),
       child: Column(
+        crossAxisAlignment: CrossAxisAlignment.start,
+        mainAxisAlignment: MainAxisAlignment.start,
         children: [
+          // 总评论数 总收藏数等
           Row(
             children: [
               Expanded(
@@ -167,17 +252,58 @@ class NewsfeedDetailPage extends HookConsumerWidget {
                     children: [
                       MyTextView('Comments', textColor: ColorUtils.string2Color("#2956B7"), fontSize: 15, isFontLight: true,),
                       const SizedBox(width: 5,),
-                      MyTextView('95', textColor: ColorUtils.string2Color("#2956B7"), fontSize: 15, isFontLight: true,),
+                      MyTextView('(95)', textColor: ColorUtils.string2Color("#2956B7"), fontSize: 15, isFontLight: true,),
                     ]
                   )
                 )
-              )
+              ),
+             // 收藏数
+             Expanded(
+                 child: Container(
+                   padding: const EdgeInsets.only(right: 20),
+                   child: Row(
+                     mainAxisAlignment: MainAxisAlignment.end,
+                     children: [
+                       const MyAssetImage(
+                         Assets.communityLikeActive,
+                         width: 15,
+                         height: 15,
+                       ),
+                       const SizedBox(width: 5,),
+                       MyTextView(
+                         '105K',
+                         textColor: ColorUtils.string2Color("#767676"),
+                         fontSize: 14,
+                         isFontLight: true,
+                       ),
+                     ],
+                   ),
+                 ),
+             )
             ],
           ),
-          const Expanded(
-            child:  Row(
-              children: [
-                 Text("fsdf"),
+
+          // 分割线
+          Container(
+            height: 1,
+            color: ColorUtils.string2Color("#E6E6E6"),
+          ),
+
+          Padding(
+            padding: const EdgeInsets.only(top: 16),
+            child: Column(
+              children: (vm.state.list.isNotEmpty )? vm.state.list.asMap().entries.map((entry) {
+                final item = entry.value;
+                final index = entry.key;
+                final lastIdx = vm.state.list.length - 1;
+                return _buildCommentItem(context, ref, item, index, lastIdx);
+              }).toList(): [
+                Center(
+                  child: SizedBox(
+                    height: 200,
+                    child: MyTextView("NO DATA"),
+                  ),
+                )
               ],
             ),
           ),
@@ -185,4 +311,73 @@ class NewsfeedDetailPage extends HookConsumerWidget {
       ),
     ).borderRadius(all:8);
   }
+
+
+  Widget _buildCommentItem(BuildContext context, WidgetRef ref, item, index, lastIdx){
+    final vm = ref.read(newsfeedDetailVmProvider.notifier);
+    final state = ref.watch(newsfeedDetailVmProvider);
+    return Container(
+      padding: const EdgeInsets.only(left: 20,right: 20),
+      margin:  EdgeInsets.only(top: index> 0? 16: 0),
+      child: Row(
+        mainAxisAlignment: MainAxisAlignment.start,
+        crossAxisAlignment: CrossAxisAlignment.start,
+        mainAxisSize: MainAxisSize.max,
+        children: [
+          MyLoadImage(
+            item['avator'],
+            width: 43,
+            height: 43,
+            isCircle: true,
+            fit: BoxFit.cover,
+          ).onTap(() {
+            // 点击头像
+            // onTap?.call();
+          }),
+          Expanded(
+            child: Container(
+              padding: const EdgeInsets.only(left:15, right: 0),
+              // color: Colors.red,
+              child: Column(
+                mainAxisAlignment: MainAxisAlignment.start,
+                crossAxisAlignment: CrossAxisAlignment.start,
+                children: [
+                  MyTextView(
+                    item['userName'],
+                    isFontRegular: true,
+                    fontSize: 14,
+                    textColor: ColorUtils.string2Color('#2956B7'),
+                    maxLines: 1,
+                    isTextEllipsis: true,
+                  ),
+                  MyTextView(
+                    item['time'],
+                    isFontLight: true,
+                    fontSize: 12,
+                    marginTop: 10,
+                    textColor: ColorUtils.string2Color('#767676'),
+                    maxLines: 1,
+                    isTextEllipsis: true,
+                  ),
+                  MyTextView(
+                    item['content'],
+                    isFontLight: true,
+                    fontSize: 15,
+                    marginTop: 10,
+                    textColor: ColorUtils.string2Color('#000000'),
+                    maxLines: null,
+                    isTextEllipsis: false,
+                  ),
+
+                 const SizedBox(height: 15,),
+                 // 分割线
+                  index!=lastIdx?Container(height: 1, color: ColorUtils.string2Color('#E6E6E6')):const SizedBox.shrink(),
+                ],
+              ),
+            ),
+          ),
+        ],
+      ),
+    );
+  }
 }

+ 45 - 5
packages/cpt_community/lib/modules/community/newsfeed_detail/newsfeed_detail_state.dart

@@ -1,27 +1,67 @@
+import 'package:widgets/load_state_layout.dart';
+
 class NewsfeedDetailState {
+  //页面 LoadView 状态的展示
+  LoadState loadingState;
+  String? errorMessage;
+
   int? curPage;
-  int? pageSize;
-  int? filterCount;
+  int? pageSize = 10;
+  int? filterCount = 0;
   Map<String, dynamic> detailInfo;
+  List<Map<String, dynamic>> list; // 评论列表
 
   NewsfeedDetailState({
-    this.curPage,
-    this.pageSize,
-    this.filterCount,
+    this.loadingState = LoadState.State_Loading,
+    String? errorMessage,
+    this.curPage = 1,
+    this.pageSize = 10,
+    this.filterCount = 0,
     required this.detailInfo,
+    required this.list,
   });
 
   NewsfeedDetailState copyWith({
+    LoadState? loadingState,
+    String? errorMessage,
     int? curPage,
     int? pageSize,
     int? filterCount,
     Map<String, dynamic>? detailInfo,
+    List<Map<String, dynamic>>? list,
   }) {
     return NewsfeedDetailState(
+      loadingState: loadingState ?? this.loadingState,
+      errorMessage: errorMessage ?? this.errorMessage,
       curPage: curPage ?? this.curPage,
       pageSize: pageSize ?? this.pageSize,
       filterCount: filterCount ?? this.filterCount,
       detailInfo: detailInfo ?? this.detailInfo,
+      list: list ?? this.list,
+    );
+  }
+
+  Map<String, dynamic> toMap() {
+    return {
+      'loadingState': this.loadingState,
+      'errorMessage': this.errorMessage,
+      'curPage': this.curPage,
+      'pageSize': this.pageSize,
+      'filterCount': this.filterCount,
+      'detailInfo': this.detailInfo,
+      'list': this.list,
+    };
+  }
+
+  factory NewsfeedDetailState.fromMap(Map<String, dynamic> map) {
+    return NewsfeedDetailState(
+      loadingState: map['loadingState'] as LoadState,
+      errorMessage: map['errorMessage'] as String,
+      curPage: map['curPage'] as int,
+      pageSize: map['pageSize'] as int,
+      filterCount: map['filterCount'] as int,
+      detailInfo: map['detailInfo'] as Map<String, dynamic>,
+      list: map['list'] as List<Map<String, dynamic>>,
     );
   }
 }

+ 129 - 4
packages/cpt_community/lib/modules/community/newsfeed_detail/newsfeed_detail_vm.dart

@@ -4,6 +4,8 @@ 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 'package:widgets/load_state_layout.dart';
+import 'package:widgets/widget_export.dart';
 
 import 'newsfeed_detail_state.dart';
 import 'newsfeed_detail_page.dart';
@@ -12,12 +14,16 @@ part 'newsfeed_detail_vm.g.dart';
 
 @riverpod
 class NewsfeedDetailVm extends _$NewsfeedDetailVm {
+  bool _needShowPlaceholder = true; //是否展示LoadingView
 
-   initState() {
+  // Refresh 控制器
+  final EasyRefreshController refreshController = EasyRefreshController(
+    controlFinishRefresh: true,  //允许刷新
+    controlFinishLoad: true,   //允许加载
+  );
+
+  NewsfeedDetailState initState() {
     return NewsfeedDetailState(
-      curPage: 1,
-      pageSize: 10,
-      filterCount: 0,
       detailInfo: {
         'id':1,
         'avator': Assets.communityCamera,
@@ -41,6 +47,15 @@ class NewsfeedDetailVm extends _$NewsfeedDetailVm {
           ]
         }
       },
+      list: [
+        {
+          'userId': 1,
+          'userName': 'William Jefferson',
+          'avator': Assets.communityCamera,
+          'time': 'June 17,2016 at 7:23 p.m.',
+          'content': 'She said YES and our lives changed.Thank you all for coming to my propose today.We hope everyone can ……[More]'
+        },
+      ],
     );
   }
 
@@ -56,5 +71,115 @@ class NewsfeedDetailVm extends _$NewsfeedDetailVm {
     // Log.d("---------444-----------------build---------------${state.detailInfo}------");
     return state;
   }
+
+//刷新页面状态
+  void changeLoadingState(LoadState loadState, String? errorMsg) {
+    state = state.copyWith(
+        loadingState: loadState,
+        errorMessage: errorMsg
+    );
+  }
+
+  // 初始化页面数据
+  initPageData({int? id}) {
+    Log.d("----property_news_vm-----initPageData   ${state.loadingState}");
+    onRefresh(id: id);
+  }
+
+  // 上拉加载 更多
+  Future loadMore({int? id}) async {
+    Log.d("----property_news_vm-----loadMore");
+    // 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();
+    // }
+    // 检查 curPage 是否为 null,并初始化为 1
+    int newCurPage = state.curPage ?? 1;
+    state = state.copyWith(curPage: ++newCurPage);
+    getListData();
+  }
+
+
+  // 下拉刷新
+  Future onRefresh({int? id}) async {
+    Log.d("----property_news_vm-----onRefresh ");
+
+    // await Future.delayed(const Duration(seconds: 2));
+    state = state.copyWith(curPage: 1);
+    getListData();
+  }
+
+  // 重试请求
+  Future retryRequest() async {
+    state = state.copyWith(curPage: 1);
+    _needShowPlaceholder = true;
+    getListData();
+  }
+
+
+  // 获取list 列表数据
+  Future getListData<T>({int? id}) async {
+    if (_needShowPlaceholder) {
+      changeLoadingState(LoadState.State_Loading, null);
+    }
+
+    Log.d("加载listData数据---------------start--${state.curPage}---");
+    //   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;
+    //   handleList(listResult.data?.rows);
+    //       ToastEngine.show("获取数据成功");
+    //     } else {
+    //   errorMessage = listResult.errorMsg;
+    //   changeLoadingState(LoadState.State_Error);
+    //       ToastEngine.show(result.errorMsg ?? "Network Load Error");
+    //     }
+    //   } catch (e) {
+    //     ToastEngine.show("Error: $e");
+    //   }
+
+    await Future.delayed(const Duration(milliseconds: 1500));
+    final List<Map<String, dynamic>> listData = [
+      {
+        'userId': 1,
+        'userName': 'William Jefferson',
+        'avator': Assets.communityCamera,
+        'time': 'June 17,2016 at 7:23 p.m.',
+        'content': 'She said YES and our lives changed.Thank you all for coming to my propose today.We hope everyone can ……[More]'
+      },
+    ];
+
+    if (state.curPage == 1) {
+      //刷新的方式
+      state = state.copyWith(list: listData);
+      refreshController.finishRefresh();
+      // //更新展示的状态
+      changeLoadingState(LoadState.State_Success, null);
+    } else {
+      //加载更多
+      final allList = state.list;
+      allList.addAll(listData);
+      refreshController.finishLoad();
+      state = state.copyWith(list: allList);
+    }
+
+    // 最后赋值
+    _needShowPlaceholder = false;
+  }
+
 }
 

+ 1 - 1
packages/cpt_community/lib/modules/community/newsfeed_detail/newsfeed_detail_vm.g.dart

@@ -6,7 +6,7 @@ part of 'newsfeed_detail_vm.dart';
 // RiverpodGenerator
 // **************************************************************************
 
-String _$newsfeedDetailVmHash() => r'058d92cd086572a5cc7e16f57db7d89405bf3c2f';
+String _$newsfeedDetailVmHash() => r'15c13988ecaa1ad67c48ed04ad73b7d2119d51b8';
 
 /// See also [NewsfeedDetailVm].
 @ProviderFor(NewsfeedDetailVm)

+ 2 - 7
packages/cpt_community/lib/modules/garage/for_rent/for_rent_vm.dart

@@ -65,11 +65,6 @@ class ForrentVm extends _$ForrentVm {
     return state;
   }
 
-  // 设置当前的 tabsRouter 和 pageController
-  Future setTabsRouterAndPageController(dynamic tabsRouter, dynamic pageController) async{
-    Log.d("setTabsRouterAndPageController---:$tabsRouter");
-  }
-
 // 上拉加载
   Future onLoadData() async {
     Log.d("----Forrent_vm-----initListData");
@@ -86,7 +81,7 @@ class ForrentVm extends _$ForrentVm {
 
   // 获取list 列表数据
   void getListData<T>() async {
-    Log.d("加载listData数据---------------start-----");
+    Log.d(" for_rent 加载listData数据---------------start-----");
     try {
       //请求网络
       Map<String, dynamic>  params = {
@@ -112,7 +107,7 @@ class ForrentVm extends _$ForrentVm {
 
   // 下拉刷新
   Future refreshListData() async {
-    Log.d("----property_forrent_vm-----refreshListData ");
+    Log.d("----for_rent_vm-----refreshListData ");
 
     // await Future.delayed(const Duration(seconds: 2));
 

+ 1 - 1
packages/cpt_community/lib/modules/garage/for_rent/for_rent_vm.g.dart

@@ -6,7 +6,7 @@ part of 'for_rent_vm.dart';
 // RiverpodGenerator
 // **************************************************************************
 
-String _$forrentVmHash() => r'be5b4f8c70608acb43dcdf0a5562a821168feaca';
+String _$forrentVmHash() => r'f78ccc11870dc6ed5673ad45950ed7be10e9bb72';
 
 /// See also [ForrentVm].
 @ProviderFor(ForrentVm)

+ 51 - 44
packages/cpt_community/lib/modules/garage/for_sale/for_sale_page.dart

@@ -7,6 +7,7 @@ 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/load_state_layout.dart';
 import 'package:widgets/my_button.dart';
 import 'package:widgets/my_load_image.dart';
 import 'package:widgets/ext/ex_widget.dart';
@@ -36,6 +37,16 @@ class ForsalePage extends HookConsumerWidget {
   @override
   Widget build(BuildContext context, WidgetRef ref) {
     final vm = ref.read(forsaleVmProvider.notifier);
+    final state = ref.watch(forsaleVmProvider);
+    useEffect(() {
+      // 组件挂载时执行 - 执行接口请求
+      Future.microtask(() => vm.initPageData());
+      return () {
+        // 组件卸载时执行
+        Log.d("garage_forsale_page 组件卸载时执行");
+      };
+    }, []);
+
     return Scaffold(
       // appBar: MyAppBar.appBar(
       //   context,
@@ -43,33 +54,52 @@ class ForsalePage extends HookConsumerWidget {
       //   backgroundColor: context.appColors.whiteBG,
       // ),
       backgroundColor: ColorUtils.string2Color("#F2F3F6"),
-      body: Column(
-        children: [
-            Expanded(
-              child: EasyRefresh(
-                // 上拉加载
-                onLoad: () async{
-                  Log.d("----onLoad");
-                  vm.onLoadData();
-                },
-                // 下拉刷新
-                onRefresh: () async{
-                  Log.d("----onRefresh");
-                  vm.refreshListData();
-                },
-                child: Padding(
-                  padding: const EdgeInsets.all(15.0),
-                  child: _buildForsaleFeedList(context, ref, vm),
+      body: SizedBox(
+        width: double.infinity,
+        height: double.infinity,
+        child: EasyRefresh(
+          // 上拉加载
+          onLoad: () async{
+            Log.d("----onLoad");
+            vm.loadMore();
+          },
+          // 下拉刷新
+          onRefresh: () async{
+            Log.d("----onRefresh");
+            vm.onRefresh();
+          },
+          child: LoadStateLayout(
+            state: state.loadingState,
+            errorMessage: state.errorMessage,
+            errorRetry: () {
+              vm.retryRequest();
+            },
+            successSliverWidget:[
+              SliverGrid(
+                gridDelegate:  const SliverGridDelegateWithFixedCrossAxisCount(
+                  crossAxisCount: 2, // 每行显示两个项目
+                  mainAxisSpacing: 15,
+                  crossAxisSpacing: 15,
+                  childAspectRatio: 0.78, // 宽高比
+                ),
+                delegate: SliverChildBuilderDelegate(
+                      (context, index) {
+                    return  _buildForsaleItem(context, ref, state.list[index], vm).onTap((){
+                      vm.handlerGotoDetail(state.list[index]['id']);
+                    });
+                  },
+                  childCount: state.list.length,
                 ),
               ),
-            )
-        ],
-      )
+            ],
+          ),
+        ).marginOnly(left: 15,right: 15,top: 15,bottom: 15)
+      ),
     );
   }
 
   Widget _buildForsaleItem(BuildContext context, WidgetRef ref, item, vm){
-    return Container(
+    return SizedBox(
       width: double.infinity,
       child: Container(
         decoration: BoxDecoration(
@@ -104,27 +134,4 @@ class ForsalePage extends HookConsumerWidget {
       ),
     );
   }
-
-  Widget _buildForsaleFeedList(BuildContext context, WidgetRef ref, vm){
-    final itemList = vm.state.list?? [];
-    if(itemList.isEmpty){
-      return const Center(child: Text('No Data'));
-    }else {
-      List itemsList = vm.state.list.toList();
-      return GridView.builder(
-        gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
-          crossAxisCount: 2, // 每行显示两个项目
-          mainAxisSpacing: 15,
-          crossAxisSpacing: 15,
-          childAspectRatio: 0.78, // 宽高比
-        ),
-        key: UniqueKey(),
-        itemCount: itemsList.length,
-        itemBuilder: (context, index) {
-          return _buildForsaleItem(context, ref, itemsList[index], vm);
-        },
-      );
-    }
-    // return Text("879424");
-  }
 }

+ 28 - 11
packages/cpt_community/lib/modules/garage/for_sale/for_sale_state.dart

@@ -1,30 +1,43 @@
+import 'package:widgets/load_state_layout.dart';
+
 class ForsaleState {
   int? activeTabIndex =0;
-  int? curPage =0;
-  int? pageSize =10;
-  int? filterCount =0;
+  //页面 LoadView 状态的展示
+  LoadState loadingState;
+  String? errorMessage;
+
+  int? curPage;
+  int? pageSize = 10;
+  int? filterCount = 0;
+  List<Map<String, dynamic>> list;
+
   List<String>? tabsList = ['For Sale', 'For Rent'];
-  List<Map<String, dynamic>>? list = [];
 
   ForsaleState({
     this.activeTabIndex,
-    this.curPage,
-    this.pageSize,
-    this.filterCount,
+    this.loadingState = LoadState.State_Loading,
+    String? errorMessage,
+    this.curPage = 1,
+    this.pageSize = 10,
+    this.filterCount = 0,
+    required this.list,
     this.tabsList,
-    this.list,
   });
 
   ForsaleState copyWith({
     int? activeTabIndex,
+    LoadState? loadingState,
+    String? errorMessage,
     int? curPage,
     int? pageSize,
     int? filterCount,
-    List<String>? tabsList,
     List<Map<String, dynamic>>? list,
+    List<String>? tabsList,
   }) {
     return ForsaleState(
       activeTabIndex: activeTabIndex ?? this.activeTabIndex,
+      loadingState: loadingState ?? this.loadingState,
+      errorMessage: errorMessage ?? this.errorMessage,
       curPage: curPage ?? this.curPage,
       pageSize: pageSize ?? this.pageSize,
       filterCount: filterCount ?? this.filterCount,
@@ -36,22 +49,26 @@ class ForsaleState {
   Map<String, dynamic> toMap() {
     return {
       'activeTabIndex': this.activeTabIndex,
+      'loadingState': this.loadingState,
+      'errorMessage': this.errorMessage,
       'curPage': this.curPage,
       'pageSize': this.pageSize,
       'filterCount': this.filterCount,
-      'tabsList': this.tabsList,
       'list': this.list,
+      'tabsList': this.tabsList,
     };
   }
 
   factory ForsaleState.fromMap(Map<String, dynamic> map) {
     return ForsaleState(
       activeTabIndex: map['activeTabIndex'] as int,
+      loadingState: map['loadingState'] as LoadState,
+      errorMessage: map['errorMessage'] as String,
       curPage: map['curPage'] as int,
       pageSize: map['pageSize'] as int,
       filterCount: map['filterCount'] as int,
-      tabsList: map['tabsList'] as List<String>,
       list: map['list'] as List<Map<String, dynamic>>,
+      tabsList: map['tabsList'] as List<String>,
     );
   }
 }

+ 159 - 105
packages/cpt_community/lib/modules/garage/for_sale/for_sale_vm.dart

@@ -4,6 +4,8 @@ import 'package:plugin_platform/engine/toast/toast_engine.dart';
 import 'package:riverpod_annotation/riverpod_annotation.dart';
 import 'package:router/ext/auto_router_extensions.dart';
 import 'package:shared/utils/log_utils.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/widget_export.dart';
 
 import '../../../router/page/community_page_router.dart';
 import '../garagesale_detail/garagesale_detail_page.dart';
@@ -15,76 +17,17 @@ part 'for_sale_vm.g.dart';
 @riverpod
 class ForsaleVm extends _$ForsaleVm {
   late ForsaleRepository ForsaleRepositoryInstance;
+  bool _needShowPlaceholder = true; //是否展示LoadingView
+
+  // Refresh 控制器
+  final EasyRefreshController refreshController = EasyRefreshController(
+    controlFinishRefresh: true,  //允许刷新
+    controlFinishLoad: true,   //允许加载
+  );
+
   ForsaleState initState() {
     return ForsaleState(
-      list: [
-          {
-            'id':1,
-            'goods_img':  'https://img.alicdn.com/tfs/TB1h.o9O4MPMeJjy1XaXXcSsFXa-640-360.jpg',
-            'title': 'Electronic keyboard',
-            'price': '\$66',
-            'isCollection': true,
-            'collection_num': 12,
-            'publisher': 'William Jefferson',
-            'publish_time': 'June 17,2016 at 7:23 p.m.',
-            'publisher_avator': Assets.communityCamera
-          },
-          {
-            'id':2,
-            'goods_img':  'https://img.alicdn.com/tfs/TB1h.o9O4MPMeJjy1XaXXcSsFXa-640-360.jpg',
-            'title': 'Electronic keyboard',
-            'price': '\$88',
-            'isCollection': false,
-            'collection_num': 12,
-            'publisher': 'William Jefferson',
-            'publish_time': 'June 17,2016 at 7:23 p.m.',
-            'publisher_avator': Assets.communityCamera
-          },
-          {
-            'id':3,
-            'goods_img':  'https://img.alicdn.com/tfs/TB1h.o9O4MPMeJjy1XaXXcSsFXa-640-360.jpg',
-            'title': 'Electronic keyboard',
-            'price': '\$66',
-            'isCollection': true,
-            'collection_num': 12,
-            'publisher': 'William Jefferson',
-            'publish_time': 'June 17,2016 at 7:23 p.m.',
-            'publisher_avator': Assets.communityCamera
-          },
-          {
-            'id':4,
-            'goods_img':  'https://img.alicdn.com/tfs/TB1h.o9O4MPMeJjy1XaXXcSsFXa-640-360.jpg',
-            'title': 'Electronic keyboard',
-            'price': '\$88',
-            'isCollection': false,
-            'collection_num': 12,
-            'publisher': 'William Jefferson',
-            'publish_time': 'June 17,2016 at 7:23 p.m.',
-            'publisher_avator': Assets.communityCamera
-          },
-          {
-            'id':5,
-            'goods_img':  'https://img.alicdn.com/tfs/TB1h.o9O4MPMeJjy1XaXXcSsFXa-640-360.jpg',
-            'title': 'Electronic keyboard',
-            'price': '\$66',
-            'isCollection': true,
-            'collection_num': 12,
-            'publisher': 'William Jefferson',
-            'publish_time': 'June 17,2016 at 7:23 p.m.',
-            'publisher_avator': Assets.communityCamera
-          },
-          {
-            'id':6,
-            'goods_img':  'https://img.alicdn.com/tfs/TB1h.o9O4MPMeJjy1XaXXcSsFXa-640-360.jpg',
-            'title': 'Electronic keyboard',
-            'price': '\$88',
-            'isCollection': false,
-            'collection_num': 12,
-            'publisher': 'William Jefferson',
-            'publish_time': 'June 17,2016 at 7:23 p.m.',
-            'publisher_avator': Assets.communityCamera
-          },
-      ]
+      list: []
     );
   }
 
@@ -98,14 +41,24 @@ class ForsaleVm extends _$ForsaleVm {
     return state;
   }
 
-   // 设置当前的 tabsRouter 和 pageController
-  Future setTabsRouterAndPageController(dynamic tabsRouter, dynamic pageController) async{
-    Log.d("setTabsRouterAndPageController---:$tabsRouter");
+
+ //刷新页面状态
+  void changeLoadingState(LoadState loadState, String? errorMsg) {
+    state = state.copyWith(
+        loadingState: loadState,
+        errorMessage: errorMsg
+    );
+  }
+
+  // 初始化页面数据
+  initPageData() {
+    Log.d("----for_sale_vm-----initPageData   ${state.loadingState}");
+    onRefresh();
   }
 
-// 上拉加载
-  Future onLoadData() async {
-    Log.d("----Forsale_vm-----initListData");
+  // 上拉加载 更多
+  Future loadMore() async {
+    Log.d("----for_sale_vm-----loadMore");
     // await Future.delayed(const Duration(seconds: 2));
     // if(state.list.length >= state.filterCount){
     //   return;
@@ -114,46 +67,147 @@ class ForsaleVm extends _$ForsaleVm {
     //   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 ForsaleRepositoryInstance.fetchForsaleList(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");
-    }
+    // 检查 curPage 是否为 null,并初始化为 1
+    int newCurPage = state.curPage ?? 1;
+    state = state.copyWith(curPage: ++newCurPage);
+    getListData();
   }
 
 
   // 下拉刷新
-  Future refreshListData() async {
-    Log.d("----property_news_vm-----refreshListData ");
+  Future onRefresh() async {
+    Log.d("----forsale_vm-----onRefresh ");
 
     // await Future.delayed(const Duration(seconds: 2));
+    state = state.copyWith(curPage: 1);
+    getListData();
+  }
 
-    state = state.copyWith(curPage: 1, pageSize: 10);
-    // ref.invalidateSelf();
-    // ref.invalidate(ForsaleVmProvider);
+  // 重试请求
+  Future retryRequest() async {
+    state = state.copyWith(curPage: 1);
+    _needShowPlaceholder = true;
     getListData();
+  }
+
+
+  // 获取list 列表数据
+  Future getListData<T>() async {
+    if (_needShowPlaceholder) {
+      changeLoadingState(LoadState.State_Loading, null);
+    }
+
+    Log.d("for_sale加载listData数据---------------start--${state.curPage}---");
+    //   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;
+    //   handleList(listResult.data?.rows);
+    //       ToastEngine.show("获取数据成功");
+    //     } else {
+    //   errorMessage = listResult.errorMsg;
+    //   changeLoadingState(LoadState.State_Error);
+    //       ToastEngine.show(result.errorMsg ?? "Network Load Error");
+    //     }
+    //   } catch (e) {
+    //     ToastEngine.show("Error: $e");
+    //   }
+
+    await Future.delayed(const Duration(milliseconds: 1500));
+    final List<Map<String, dynamic>> listData = [
+      {
+        'id':1,
+        'goods_img':  'https://img.alicdn.com/tfs/TB1h.o9O4MPMeJjy1XaXXcSsFXa-640-360.jpg',
+        'title': 'Electronic keyboard',
+        'price': '\$66',
+        'isCollection': true,
+        'collection_num': 12,
+        'publisher': 'William Jefferson',
+        'publish_time': 'June 17,2016 at 7:23 p.m.',
+        'publisher_avator': Assets.communityCamera
+      },
+      {
+        'id':2,
+        'goods_img':  'https://img.alicdn.com/tfs/TB1h.o9O4MPMeJjy1XaXXcSsFXa-640-360.jpg',
+        'title': 'Electronic keyboard',
+        'price': '\$88',
+        'isCollection': false,
+        'collection_num': 12,
+        'publisher': 'William Jefferson',
+        'publish_time': 'June 17,2016 at 7:23 p.m.',
+        'publisher_avator': Assets.communityCamera
+      },
+      {
+        'id':3,
+        'goods_img':  'https://img.alicdn.com/tfs/TB1h.o9O4MPMeJjy1XaXXcSsFXa-640-360.jpg',
+        'title': 'Electronic keyboard',
+        'price': '\$66',
+        'isCollection': true,
+        'collection_num': 12,
+        'publisher': 'William Jefferson',
+        'publish_time': 'June 17,2016 at 7:23 p.m.',
+        'publisher_avator': Assets.communityCamera
+      },
+      {
+        'id':4,
+        'goods_img':  'https://img.alicdn.com/tfs/TB1h.o9O4MPMeJjy1XaXXcSsFXa-640-360.jpg',
+        'title': 'Electronic keyboard',
+        'price': '\$88',
+        'isCollection': false,
+        'collection_num': 12,
+        'publisher': 'William Jefferson',
+        'publish_time': 'June 17,2016 at 7:23 p.m.',
+        'publisher_avator': Assets.communityCamera
+      },
+      {
+        'id':5,
+        'goods_img':  'https://img.alicdn.com/tfs/TB1h.o9O4MPMeJjy1XaXXcSsFXa-640-360.jpg',
+        'title': 'Electronic keyboard',
+        'price': '\$66',
+        'isCollection': true,
+        'collection_num': 12,
+        'publisher': 'William Jefferson',
+        'publish_time': 'June 17,2016 at 7:23 p.m.',
+        'publisher_avator': Assets.communityCamera
+      },
+      {
+        'id':6,
+        'goods_img':  'https://img.alicdn.com/tfs/TB1h.o9O4MPMeJjy1XaXXcSsFXa-640-360.jpg',
+        'title': 'Electronic keyboard',
+        'price': '\$88',
+        'isCollection': false,
+        'collection_num': 12,
+        'publisher': 'William Jefferson',
+        'publish_time': 'June 17,2016 at 7:23 p.m.',
+        'publisher_avator': Assets.communityCamera
+      },
+    ];
+
+    if (state.curPage == 1) {
+      //刷新的方式
+      state = state.copyWith(list: listData);
+      refreshController.finishRefresh();
+      // //更新展示的状态
+      changeLoadingState(LoadState.State_Success, null);
+    } else {
+      //加载更多
+      final allList = state.list;
+      allList.addAll(listData);
+      refreshController.finishLoad();
+      state = state.copyWith(list: allList);
+    }
 
+    // 最后赋值
+    _needShowPlaceholder = false;
   }
 
 

+ 1 - 1
packages/cpt_community/lib/modules/garage/for_sale/for_sale_vm.g.dart

@@ -6,7 +6,7 @@ part of 'for_sale_vm.dart';
 // RiverpodGenerator
 // **************************************************************************
 
-String _$forsaleVmHash() => r'a63dd5772509b90fac8ede5ec692e01754dc6a22';
+String _$forsaleVmHash() => r'89584f53f63c61a6ab88d62359d9123d245db921';
 
 /// See also [ForsaleVm].
 @ProviderFor(ForsaleVm)

+ 52 - 66
packages/cpt_community/lib/modules/garage/garage_page.dart

@@ -64,37 +64,27 @@ class GaragePage extends HookConsumerWidget {
         children: [
           const MyAssetImage(Assets.communityNesFeed, width: 45,height: 45,),
           Expanded(
-            child: Row(
-              children: [
-                Expanded(
-                  child: Container(
-                    // height: 65.5,
-                    // color: Colors.blue,
-                    child: MyTextView(
-                      "Sell Item",
-                      textColor: ColorUtils.string2Color('#000000'),
-                      fontSize: 15,
-                      marginLeft: 15,
-                      alignment: Alignment.centerLeft,
-                      textAlign: TextAlign.left,
-                      backgroundColor: ColorUtils.string2Color('#ffffff'),
-                      maxLines: 1,
-                      isFontMedium: true,
-                    ),
-                  ),
-                ),
-                const MyAssetImage(
-                  Assets.communityCamera,
-                  width: 21,
-                  height: 16.5,
-                ),
-              ],
-            ).onTap((){
-              vm.handlerGotoPost(context);
-            }),
+            child: MyTextView(
+              "Sell Item",
+              textColor: ColorUtils.string2Color('#000000'),
+              fontSize: 15,
+              marginLeft: 15,
+              alignment: Alignment.centerLeft,
+              textAlign: TextAlign.left,
+              backgroundColor: ColorUtils.string2Color('#ffffff'),
+              maxLines: 1,
+              isFontMedium: true,
+            ),
+          ),
+          const MyAssetImage(
+            Assets.communityCamera,
+            width: 21,
+            height: 16.5,
           ),
         ],
-      ),
+      ).onTap((){
+        vm.handlerGotoPost(context);
+      }),
     );
   }
 
@@ -226,12 +216,11 @@ class GaragePage extends HookConsumerWidget {
       // )
     );
   }
-
   Widget _buildTopSection(BuildContext context, WidgetRef ref, vm) {
     final topSectionsData = vm.topSectionsData;
     int curTagIdx = 1;
     return Container(
-      color: Colors.white,
+      color: context.appColors.whiteBG,
       padding: const EdgeInsets.only(top: 23, bottom: 30),
       child: Center(
         child: Row(
@@ -240,44 +229,41 @@ class GaragePage extends HookConsumerWidget {
           crossAxisAlignment: CrossAxisAlignment.center,
           children: List.generate(topSectionsData.length, (index) {
             final item = topSectionsData[index];
-            return Flexible(
-              flex: 1,
-              child: Column(
-                children: [
-                  Container(
+            return Column(
+              children: [
+                Container(
+                  width: MediaQuery.of(context).size.width / topSectionsData.length - 36,
+                  height: 70,
+                  decoration: BoxDecoration(
+                    // color: currentTabIdx == index ? ColorUtils.string2Color('#E6F2FF') : Colors.white,
+                    shape: BoxShape.circle, // 设置为圆形
+                    boxShadow: index == curTagIdx ? [
+                      BoxShadow(
+                        color: context.appColors.tabLightBlueShadow, // 设置阴影颜色
+                        blurRadius: 5, // 设置模糊半径
+                        spreadRadius: 0.05, // 控制阴影扩散
+                        offset: const Offset(0, 4), // 设置阴影偏移量
+                      ),                          ] : [],// 未选中时无阴影,
+                  ),
+                  child: MyAssetImage(
+                    item['icon'],
                     width: MediaQuery.of(context).size.width / topSectionsData.length - 36,
                     height: 70,
-                    decoration: BoxDecoration(
-                      // color: currentTabIdx == index ? ColorUtils.string2Color('#E6F2FF') : Colors.white,
-                      shape: BoxShape.circle, // 设置为圆形
-                      boxShadow: index == curTagIdx ? [
-                        BoxShadow(
-                          color: context.appColors.tabLightBlueShadow, // 设置阴影颜色
-                          blurRadius: 5, // 设置模糊半径
-                          spreadRadius: 0.05, // 控制阴影扩散
-                          offset: const Offset(0, 4), // 设置阴影偏移量
-                        ),                          ] : [],// 未选中时无阴影,
-                    ),
-                    child: MyAssetImage(
-                      item['icon'],
-                      width: MediaQuery.of(context).size.width / topSectionsData.length - 36,
-                      height: 70,
-                    ).onTap(() {
-                      vm.handlerChangeCommunityType(context,index);
-                    },
-                      type: ClickType.throttle,
-                    ),
-                  ),
-                  SizedBox.fromSize(size: const Size(0, 9)),
-                  MyTextView(
-                    item['title'],
-                    fontSize: 15,
-                    textColor: index == curTagIdx ? ColorUtils.string2Color('#4161D0'):Colors.black,
-                    textAlign: TextAlign.center,
-                    isFontMedium: true,
+                  ).onTap(() {
+                    vm.handlerChangeCommunityType(context,index);
+                  },
+                    type: ClickType.throttle,
                   ),
-                ],
-              ),
+                ),
+                SizedBox.fromSize(size: const Size(0, 9)),
+                MyTextView(
+                  item['title'],
+                  fontSize: 15,
+                  textColor: index == curTagIdx ? ColorUtils.string2Color('#4161D0'):Colors.black,
+                  textAlign: TextAlign.center,
+                  isFontMedium: true,
+                ),
+              ],
             ).marginOnly(left: 18, right: 18, top: 10, bottom: 10);
           }),
         ),

+ 1 - 1
packages/cpt_community/lib/modules/garage/garage_vm.g.dart

@@ -6,7 +6,7 @@ part of 'garage_vm.dart';
 // RiverpodGenerator
 // **************************************************************************
 
-String _$garageVmHash() => r'04b50f6dd914e6c44422b4ca33154dddf07e4cd0';
+String _$garageVmHash() => r'53e595921392246928dd52b89af9151234dd2f6f';
 
 /// See also [GarageVm].
 @ProviderFor(GarageVm)

+ 91 - 3
packages/cpt_community/lib/modules/garage/garagesale_detail/garagesale_detail_page.dart

@@ -1,10 +1,15 @@
+import 'package:cpt_community/modules/garage/garagesale_detail/garagesale_detail_vm.dart';
 import 'package:cpt_community/router/page/community_page_router.dart';
 import 'package:cs_resources/theme/app_colors_theme.dart';
 import 'package:flutter/material.dart';
 import 'package:auto_route/auto_route.dart';
+import 'package:flutter_hooks/flutter_hooks.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:widgets/load_state_layout.dart';
 import 'package:widgets/my_appbar.dart';
+import 'package:widgets/my_text_view.dart';
 
 @RoutePage()
 class GaragesaleDetailPage extends HookConsumerWidget {
@@ -24,7 +29,16 @@ class GaragesaleDetailPage extends HookConsumerWidget {
 
   @override
   Widget build(BuildContext context, WidgetRef ref) {
-    // final viewModel = ref.watch(newsfeedPostVmProvider.notifier);
+    final state = ref.watch(garagesaleDetailVmProvider);
+    final vm = ref.read(garagesaleDetailVmProvider.notifier);
+
+    useEffect((){
+      // 组件挂载时执行 - 执行接口请求
+      Future.microtask(() => vm.initPageData());
+      return () {
+        // 组件卸载时执行
+      };
+    },[]);
 
     return Scaffold(
       appBar: MyAppBar.appBar(
@@ -33,8 +47,82 @@ class GaragesaleDetailPage extends HookConsumerWidget {
         backgroundColor: context.appColors.whiteBG,
       ),
       backgroundColor: context.appColors.backgroundDefault,
-      body: Center(
-        child: Text("GaragesaleDetail"),
+      body: Column(
+        children: [
+          Expanded(
+            child: LoadStateLayout(
+              state: state.loadingState,
+              errorMessage: state.errorMessage,
+              errorRetry: () {
+                vm.retryRequest();
+              },
+              successWidget: SingleChildScrollView(
+                scrollDirection: Axis.vertical,
+                physics: const BouncingScrollPhysics(),
+                clipBehavior: Clip.none,
+                child: _buildContentBox(context, ref),
+              ),
+            ),
+          ),
+          // 底部联系信息
+          Visibility(
+            visible: state.loadingState == LoadState.State_Success,
+            child: _buildBottomConcatInfo(context, ref),
+          )
+        ],
+      ),
+    );
+  }
+
+
+  Widget _buildContentBox(BuildContext context, WidgetRef ref) {
+    final vm = ref.read(garagesaleDetailVmProvider.notifier);
+    return Column(
+      children: [
+        Container(
+          color: context.appColors.whiteBG,
+          child: Column(
+            children: [
+              Container(
+                color: context.appColors.whiteBG,
+                child: Column(
+                  children: [
+                    Container(
+                      color: context.appColors.whiteBG,
+                      child: Column(
+                        children: [
+                          Container(
+                            color: context.appColors.whiteBG,
+                          )
+                        ]
+                      )
+                    )
+                  ]
+                )
+              )
+            ]
+          )
+        )
+      ]
+    );
+  }
+
+  Widget _buildBottomConcatInfo(BuildContext context, WidgetRef ref) {
+    return 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,
+            isFontMedium: true,
+          ),
+        ],
       ),
     );
   }

+ 36 - 0
packages/cpt_community/lib/modules/garage/garagesale_detail/garagesale_detail_state.dart

@@ -0,0 +1,36 @@
+import 'package:widgets/load_state_layout.dart';
+
+class GarageDetailState {
+  //页面 LoadView 状态的展示
+  LoadState loadingState;
+  String? errorMessage;
+
+  final int? id;
+  final String? type;  // forsale  forrent
+
+  Map<String, dynamic> datas;
+
+  GarageDetailState({
+    this.loadingState = LoadState.State_Loading,
+    this.errorMessage,
+    this.id,
+    this.type,
+    required this.datas,
+  });
+
+  GarageDetailState copyWith({
+    Map<String, dynamic>? datas,
+    LoadState? loadingState,
+    String? errorMessage,
+    int? id,
+    String? type,
+  }) {
+    return GarageDetailState(
+      loadingState: loadingState ?? this.loadingState,
+      errorMessage: errorMessage ?? this.errorMessage,
+      id: id ?? this.id,
+      type: type ?? this.type,
+      datas: datas?? this.datas,
+    );
+  }
+}

+ 96 - 0
packages/cpt_community/lib/modules/garage/garagesale_detail/garagesale_detail_vm.dart

@@ -0,0 +1,96 @@
+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:router/ext/auto_router_extensions.dart';
+import 'package:shared/utils/log_utils.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/widget_export.dart';
+
+import '../../../router/page/community_page_router.dart';
+// import 'garagesale_detail_respository.dart';
+import 'garagesale_detail_state.dart';
+
+part 'garagesale_detail_vm.g.dart';
+
+@riverpod
+class GaragesaleDetailVm extends _$GaragesaleDetailVm {
+  // late GaragesaleDetailRepository GaragesaleDetailRepositoryInstance;
+  bool _needShowPlaceholder = true; //是否展示LoadingView
+
+  // Refresh 控制器
+  final EasyRefreshController refreshController = EasyRefreshController(
+    controlFinishRefresh: true,  //允许刷新
+    controlFinishLoad: true,   //允许加载
+  );
+
+  GarageDetailState initState() {
+    return GarageDetailState(
+        datas: {}
+    );
+  }
+
+  @override
+  GarageDetailState build(){
+    // 引入数据仓库
+    // GaragesaleDetailRepositoryInstance = ref.read(newsRepositoryProvider);
+    final state = initState();
+    Log.d("--------------------------build---------------------");
+
+    return state;
+  }
+
+
+  //刷新页面状态
+  void changeLoadingState(LoadState loadState, String? errorMsg) {
+    state = state.copyWith(
+        loadingState: loadState,
+        errorMessage: errorMsg
+    );
+  }
+
+  // 重试请求
+  Future retryRequest() async {
+    _needShowPlaceholder = true;
+    getDetailData();
+  }
+
+  // 初始化页面数据
+  initPageData() {
+    Log.d("----property_news_vm-----initPageData   ${state.loadingState}");
+    getDetailData();
+  }
+
+  Future getDetailData<T>() async {
+    if (_needShowPlaceholder) {
+      changeLoadingState(LoadState.State_Loading, null);
+    }
+
+    //   try {
+    //     //请求网络
+    //     Map<String, dynamic>  params = {
+    //       "curPage": state.curPage,
+    //       "pageSize": state.pageSize,
+    //     };
+    //     Log.d("请求参数------$params");
+
+    await Future.delayed(const Duration(milliseconds: 1500));
+
+    final Map<String, dynamic> detailData = {
+      'id':1,
+      'goods_img':  'https://img.alicdn.com/tfs/TB1h.o9O4MPMeJjy1XaXXcSsFXa-640-360.jpg',
+      'title': 'Electronic keyboard',
+      'price': '\$66',
+      'isCollection': true,
+      'collection_num': 12,
+      'publisher': 'William Jefferson',
+    };
+
+    state.copyWith(datas: detailData);
+
+    changeLoadingState(LoadState.State_Success, null);
+
+    // 最后赋值
+    _needShowPlaceholder = false;
+  }
+}

+ 27 - 0
packages/cpt_community/lib/modules/garage/garagesale_detail/garagesale_detail_vm.g.dart

@@ -0,0 +1,27 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'garagesale_detail_vm.dart';
+
+// **************************************************************************
+// RiverpodGenerator
+// **************************************************************************
+
+String _$garagesaleDetailVmHash() =>
+    r'810ff95bc99588570cbd676b2bb8d48c6b162118';
+
+/// See also [GaragesaleDetailVm].
+@ProviderFor(GaragesaleDetailVm)
+final garagesaleDetailVmProvider =
+    AutoDisposeNotifierProvider<GaragesaleDetailVm, GarageDetailState>.internal(
+  GaragesaleDetailVm.new,
+  name: r'garagesaleDetailVmProvider',
+  debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
+      ? null
+      : _$garagesaleDetailVmHash,
+  dependencies: null,
+  allTransitiveDependencies: null,
+);
+
+typedef _$GaragesaleDetailVm = AutoDisposeNotifier<GarageDetailState>;
+// 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

+ 1 - 1
packages/cpt_main/lib/modules/feedback/history/feedback_history.dart

@@ -51,7 +51,7 @@ class FeedbackHistoryScreen extends HookConsumerWidget {
                   },
                   childCount: state.datas.length,
                 ))
-          ],
+            ],
         ),
       ).marginOnly(top: 5, bottom: 5),
     );

+ 22 - 18
packages/cpt_property/lib/modules/news/page/property_news_page.dart

@@ -1,6 +1,7 @@
 import 'package:cpt_property/modules/property/page/property_page.dart';
 import 'package:flutter/material.dart';
 import 'package:auto_route/auto_route.dart';
+import 'package:flutter_hooks/flutter_hooks.dart';
 import 'package:hooks_riverpod/hooks_riverpod.dart';
 import 'package:router/ext/auto_router_extensions.dart';
 import 'package:shared/utils/log_utils.dart';
@@ -47,7 +48,6 @@ class PropertyNewsPage extends HookConsumerWidget {
   }
 
   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(
@@ -157,26 +157,23 @@ class PropertyNewsPage extends HookConsumerWidget {
     });
   }
 
-  // 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);
     final state = ref.watch(propertyNewsVmProvider);
+    useEffect(() {
+      // 组件挂载时执行 - 执行接口请求
+      Future.microtask(() => _vm.initPageData());
+      return () {
+        // 组件卸载时执行
+        Log.d("property_news_page 组件卸载时执行");
+      };
+    }, []);
+
     return Scaffold(
       // appBar: AppBar(title: Text("资产")),
-      body: Container(
+      body: SizedBox(
         width: double.infinity,
         height: double.infinity,
         child: EasyRefresh(
@@ -184,12 +181,12 @@ class PropertyNewsPage extends HookConsumerWidget {
           // 上拉加载
           onLoad: () async{
             Log.d("----onLoad");
-            _vm.onLoadData();
+            _vm.loadMore();
           },
           // 下拉刷新
           onRefresh: () async{
             Log.d("----onRefresh");
-            _vm.refreshListData();
+            _vm.onRefresh();
           },
           child: LoadStateLayout(
             state: state.loadingState,
@@ -198,10 +195,17 @@ class PropertyNewsPage extends HookConsumerWidget {
               _vm.retryRequest();
             },
             successSliverWidget: [
-              _buildNewsList(context, ref, _vm)
+                SliverList(
+                  delegate: SliverChildBuilderDelegate(
+                        (context, index){
+                          return _buildNewsItem(context, ref, state.list[index], _vm);
+                        },
+                    childCount: state.list.length
+                  )
+                )
             ],
           ),
-        )
+        ).marginOnly(top: 5, bottom: 5)
       ),
     );
   }

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

@@ -17,9 +17,9 @@ class PropertyNewsState {
     PropertyNewsState({
         this.loadingState = LoadState.State_Loading,
         String? errorMessage,
-        this.curPage,
-        this.pageSize,
-        this.filterCount,
+        this.curPage = 1,
+        this.pageSize = 10,
+        this.filterCount = 0,
         required this.list,
     });
 

+ 45 - 15
packages/cpt_property/lib/modules/news/vm/property_news_vm.dart

@@ -23,9 +23,7 @@ class PropertyNewsVm extends _$PropertyNewsVm {
 
   PropertyNewsState initState() {
     return PropertyNewsState(
-      list: [
-
-      ],
+      list: [],
     );
   }
 
@@ -50,12 +48,12 @@ class PropertyNewsVm extends _$PropertyNewsVm {
   // 初始化页面数据
   initPageData() {
     Log.d("----property_news_vm-----initPageData");
-    refreshListData();
+    onRefresh();
   }
 
-  // 上拉加载
-  Future onLoadData() async {
-    Log.d("----property_news_vm-----initListData");
+  // 上拉加载 更多
+  Future loadMore() async {
+    Log.d("----property_news_vm-----loadMore");
     // await Future.delayed(const Duration(seconds: 2));
     // if(state.list.length >= state.filterCount){
     //   return;
@@ -72,8 +70,8 @@ class PropertyNewsVm extends _$PropertyNewsVm {
 
 
   // 下拉刷新
-  Future refreshListData() async {
-    Log.d("----property_news_vm-----refreshListData ");
+  Future onRefresh() async {
+    Log.d("----property_news_vm-----onRefresh ");
 
     // await Future.delayed(const Duration(seconds: 2));
     state = state.copyWith(curPage: 1);
@@ -89,12 +87,12 @@ class PropertyNewsVm extends _$PropertyNewsVm {
 
 
   // 获取list 列表数据
-  void getListData<T>() async {
+  Future getListData<T>() async {
     if (_needShowPlaceholder) {
       changeLoadingState(LoadState.State_Loading, null);
     }
 
-    Log.d("加载listData数据---------------start-----");
+    Log.d("加载listData数据---------------start--${state.curPage}---");
     //   try {
     //     //请求网络
     //     Map<String, dynamic>  params = {
@@ -108,8 +106,11 @@ class PropertyNewsVm extends _$PropertyNewsVm {
     //     if (result.isSuccess) {
     //       // state = state.copyWith(serverTime: result.data);
     //       state = state;
+    //   handleList(listResult.data?.rows);
     //       ToastEngine.show("获取数据成功");
     //     } else {
+    //   errorMessage = listResult.errorMsg;
+    //   changeLoadingState(LoadState.State_Error);
     //       ToastEngine.show(result.errorMsg ?? "Network Load Error");
     //     }
     //   } catch (e) {
@@ -140,17 +141,13 @@ class PropertyNewsVm extends _$PropertyNewsVm {
       //刷新的方式
       state = state.copyWith(list: listData);
       refreshController.finishRefresh();
-
       //更新展示的状态
       changeLoadingState(LoadState.State_Success, null);
     } else {
       //加载更多
       final allList = state.list;
       allList.addAll(listData);
-      state.list.addAll(listData);
-
       refreshController.finishLoad();
-
       state = state.copyWith(list: allList);
     }
 
@@ -185,4 +182,37 @@ class PropertyNewsVm extends _$PropertyNewsVm {
       ToastEngine.show("收藏成功");
     }
   }
+
+
+
+// 处理数据与展示的逻辑
+// void handleList(List<JobAppliedListSGRows>? list) {
+//   if (list != null && list.isNotEmpty) {
+//     //有数据,判断是刷新还是加载更多的数据
+//     if (_curPage == 1) {
+//       //刷新的方式
+//       state.list.clear();
+//       state.list.addAll(list);
+//       refreshController.finishRefresh();
+//
+//       //更新展示的状态
+//       changeLoadingState(LoadState.State_Success);
+//     } else {
+//       //加载更多
+//       state.list.addAll(list);
+//       refreshController.finishLoad();
+//       update();
+//     }
+//   } else {
+//     if (_curPage == 1) {
+//       //展示无数据的布局
+//       state.list.clear();
+//       changeLoadingState(LoadState.State_Empty);
+//       refreshController.finishRefresh();
+//     } else {
+//       //展示加载完成,没有更多数据了
+//       refreshController.finishLoad(IndicatorResult.noMore);
+//     }
+//   }
+// }
 }

+ 10 - 6
packages/cpt_property/lib/modules/property/page/property_page.dart

@@ -30,17 +30,21 @@ class PropertyPage extends HookConsumerWidget {
   Widget _buildTopSection(BuildContext context, WidgetRef ref, _vm, tabsRouter) {
     final topSectionsData = _vm.topSectionsData;
     final currentTabIdx = tabsRouter.activeIndex;
-    return Container(
-      color: Colors.white,
-      child: Center(
+    return Center(
+      child: Container(
+        color: context.appColors.whiteBG,
+        width: MediaQuery.of(context).size.width,
+        padding: const EdgeInsets.only(top: 25, bottom: 25),
         child: Row(
           mainAxisAlignment: MainAxisAlignment.center,
           crossAxisAlignment: CrossAxisAlignment.center,
+          mainAxisSize: MainAxisSize.max,
           children: List.generate(topSectionsData.length, (index) {
             final item = topSectionsData[index];
-            return Flexible(
-              flex: 1,
+            return Expanded(
               child: Column(
+                mainAxisSize: MainAxisSize.max,
+                mainAxisAlignment: MainAxisAlignment.spaceAround,
                 children: [
                   Container(
                     width: MediaQuery.of(context).size.width / topSectionsData.length - 36,
@@ -78,7 +82,7 @@ class PropertyPage extends HookConsumerWidget {
                   ),
                 ],
               ),
-            ).marginOnly(left: 18, right: 18, top: 10, bottom: 10);
+            );
           }),
         ),
       ),

+ 32 - 18
packages/cpt_property/lib/modules/rent/page/property_rent_page.dart

@@ -1,11 +1,13 @@
 import 'package:cpt_property/modules/property/page/property_page.dart';
 import 'package:flutter/material.dart';
 import 'package:auto_route/auto_route.dart';
+import 'package:flutter_hooks/flutter_hooks.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/load_state_layout.dart';
 import 'package:widgets/my_load_image.dart';
 import 'package:widgets/my_text_view.dart';
 import 'package:widgets/widget_export.dart';
@@ -116,39 +118,51 @@ class PropertyRentPage extends HookConsumerWidget {
     ).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);
-
+    final state = ref.watch(propertyRentVmProvider);
+    useEffect(() {
+      // 组件挂载时执行 - 执行接口请求
+      Future.microtask(() => _vm.initPageData());
+      return () {
+        // 组件卸载时执行
+        Log.d("property_rent_page 组件卸载时执行");
+      };
+    }, []);
     return Scaffold(
       // appBar: AppBar(title: Text("资产")),
-      body: Container(
+      body: SizedBox(
+          width: double.infinity,
+          height: double.infinity,
           child: EasyRefresh(
             // 上拉加载
             onLoad: () async{
               Log.d("----onLoad");
-              _vm.onLoadData();
+              _vm.loadMore();
             },
             // 下拉刷新
             onRefresh: () async{
               Log.d("----onRefresh");
-              _vm.refreshListData();
+              _vm.onRefresh();
             },
-            child: Container(
-                color: Colors.white,
-                margin: const EdgeInsets.only(top: 5),
-                child: _buildRentList(context, ref, _vm)
+            child: LoadStateLayout(
+              state: state.loadingState,
+              errorMessage: state.errorMessage,
+              errorRetry: () {
+                _vm.retryRequest();
+              },
+              successSliverWidget: [
+                SliverList(
+                  delegate: SliverChildBuilderDelegate(
+                    (context, index) {
+                      return _buildRentItem(context, ref, state.list[index], _vm);
+                    },
+                    childCount: state.list.length
+                  ),
+                )
+              ],
             ),
           )
       ),

+ 42 - 26
packages/cpt_property/lib/modules/rent/page/property_rent_state.dart

@@ -2,48 +2,64 @@
 
 import 'dart:convert';
 
-PropertyRentState propertyRentStateFromJson(String str) => PropertyRentState.fromJson(json.decode(str));
-
-String propertyRentStateToJson(PropertyRentState data) => json.encode(data.toJson());
+import 'package:widgets/load_state_layout.dart';
 
 class PropertyRentState {
+  //页面 LoadView 状态的展示
+  LoadState loadingState;
+  String? errorMessage;
+
+  int? curPage;
+  int? pageSize = 10;
+  int? filterCount = 0;
+  List<Map<String, dynamic>> list;
+
   PropertyRentState({
-    required this.curPage,
-    required this.pageSize,
+    this.loadingState = LoadState.State_Loading,
+    String? errorMessage,
+    this.curPage = 1,
+    this.pageSize = 10,
+    this.filterCount = 0,
     required this.list,
-    required this.filterCount,
   });
+  Map<String, dynamic> toMap() {
+    return {
+      'loadingState': this.loadingState,
+      'errorMessage': this.errorMessage,
+      'curPage': this.curPage,
+      'pageSize': this.pageSize,
+      'filterCount': this.filterCount,
+      'list': this.list,
+    };
+  }
 
-  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,
-  };
+  factory PropertyRentState.fromMap(Map<String, dynamic> map) {
+    return PropertyRentState(
+      loadingState: map['loadingState'] as LoadState,
+      errorMessage: map['errorMessage'] as String,
+      curPage: map['curPage'] as int,
+      pageSize: map['pageSize'] as int,
+      filterCount: map['filterCount'] as int,
+      list: map['list'] as List<Map<String, dynamic>>,
+    );
+  }
 
   PropertyRentState copyWith({
+    LoadState? loadingState,
+    String? errorMessage,
     int? curPage,
     int? pageSize,
-    List<Map<String, dynamic>>? list,
     int? filterCount,
+    List<Map<String, dynamic>>? list,
   }) {
     return PropertyRentState(
+      loadingState: loadingState ?? this.loadingState,
+      errorMessage: errorMessage ?? this.errorMessage,
       curPage: curPage ?? this.curPage,
       pageSize: pageSize ?? this.pageSize,
-      list: list ?? this.list,
       filterCount: filterCount ?? this.filterCount,
+      list: list ?? this.list,
     );
   }
+
 }

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

@@ -59,7 +59,7 @@ class PropertyRentRepository {
     if (result.isSuccess) {
       //重新赋值data或list
       final json = result.getDataJson();
-      var data = PropertyRentState.fromJson(json!);
+      var data = PropertyRentState.fromMap(json!);
       //重新赋值data或list
       return result.convert<PropertyRentState>(data: data);
     }

+ 100 - 51
packages/cpt_property/lib/modules/rent/vm/property_rent_vm.dart

@@ -2,6 +2,8 @@ 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 'package:widgets/load_state_layout.dart';
+import 'package:widgets/widget_export.dart';
 import '../page/property_rent_state.dart';
 import '../repository/property_rent_repository.dart';
 part 'property_rent_vm.g.dart';
@@ -9,25 +11,17 @@ part 'property_rent_vm.g.dart';
 @riverpod
 class PropertyRentVm extends _$PropertyRentVm {
   late PropertyRentRepository propertyRentRepository;
+  bool _needShowPlaceholder = true; //是否展示LoadingView
+
+  // Refresh 控制器
+  final EasyRefreshController refreshController = EasyRefreshController(
+    controlFinishRefresh: true,  //允许刷新
+    controlFinishLoad: true,   //允许加载
+  );
+
   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,
+      list: [],
     );
   }
 
@@ -41,15 +35,23 @@ class PropertyRentVm extends _$PropertyRentVm {
     return state;
   }
 
+  //刷新页面状态
+  void changeLoadingState(LoadState loadState, String? errorMsg) {
+    state = state.copyWith(
+        loadingState: loadState,
+        errorMessage: errorMsg
+    );
+  }
+
   // 初始化页面数据
   initPageData() {
     Log.d("----property_news_vm-----initPageData");
-    refreshListData();
+    onRefresh();
   }
 
-  // 上拉加载
-  Future onLoadData() async {
-    Log.d("----property_news_vm-----initListData");
+  // 上拉加载 更多
+  Future loadMore() async {
+    Log.d("----property_news_vm-----loadMore");
     // await Future.delayed(const Duration(seconds: 2));
     // if(state.list.length >= state.filterCount){
     //   return;
@@ -58,46 +60,93 @@ class PropertyRentVm extends _$PropertyRentVm {
     //   state = state.copyWith(curPage: curPage,);
     //   getListData();
     // }
+    // 检查 curPage 是否为 null,并初始化为 1
+    int newCurPage = state.curPage ?? 1;
+    state = state.copyWith(curPage: ++newCurPage);
     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 ");
+  Future onRefresh() async {
+    Log.d("----property_news_vm-----onRefresh ");
 
     // await Future.delayed(const Duration(seconds: 2));
+    state = state.copyWith(curPage: 1);
+    getListData();
+  }
 
-    state = state.copyWith(curPage: 1, pageSize: 10);
-    // ref.invalidateSelf();
-    // ref.invalidate(propertyNewsVmProvider);
+  // 重试请求
+  Future retryRequest() async {
+    state = state.copyWith(curPage: 1);
+    _needShowPlaceholder = true;
     getListData();
+  }
+
+
+  // 获取list 列表数据
+  Future getListData<T>() async {
+    if (_needShowPlaceholder) {
+      changeLoadingState(LoadState.State_Loading, null);
+    }
+
+    Log.d("加载listData数据---------------start--${state.curPage}---");
+    //   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;
+    //   handleList(listResult.data?.rows);
+    //       ToastEngine.show("获取数据成功");
+    //     } else {
+    //   errorMessage = listResult.errorMsg;
+    //   changeLoadingState(LoadState.State_Error);
+    //       ToastEngine.show(result.errorMsg ?? "Network Load Error");
+    //     }
+    //   } catch (e) {
+    //     ToastEngine.show("Error: $e");
+    //   }
+
+    await Future.delayed(const Duration(milliseconds: 1500));
+    final List<Map<String, dynamic>> listData = [
+      {
+        "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",
+      },
+    ];
+
+    if (state.curPage == 1) {
+      //刷新的方式
+      state = state.copyWith(list: listData);
+      refreshController.finishRefresh();
+      //更新展示的状态
+      changeLoadingState(LoadState.State_Success, null);
+    } else {
+      //加载更多
+      final allList = state.list;
+      allList.addAll(listData);
+      refreshController.finishLoad();
+      state = state.copyWith(list: allList);
+    }
 
+    // 最后赋值
+    _needShowPlaceholder = false;
   }
 
 }

+ 40 - 30
packages/cpt_property/lib/modules/sale/page/property_sale_page.dart

@@ -1,11 +1,13 @@
 import 'package:cpt_property/modules/property/page/property_page.dart';
 import 'package:flutter/material.dart';
 import 'package:auto_route/auto_route.dart';
+import 'package:flutter_hooks/flutter_hooks.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/load_state_layout.dart';
 import 'package:widgets/my_load_image.dart';
 import 'package:widgets/my_text_view.dart';
 import 'package:widgets/widget_export.dart';
@@ -104,42 +106,50 @@ class PropertySalePage extends HookConsumerWidget {
     ).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);
+    final state = ref.watch(propertySaleVmProvider);
+    useEffect(() {
+      // 组件挂载时执行 - 执行接口请求
+      Future.microtask(() => _vm.initPageData());
+      return () {
+        // 组件卸载时执行
+        Log.d("property_sale_page 组件卸载时执行");
+      };
+    }, []);
 
     return Scaffold(
       // appBar: AppBar(title: Text("资产")),
-      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)
-            ),
-          )
-      ),
+      body: EasyRefresh(
+        // 上拉加载
+        onLoad: () async{
+          Log.d("----onLoad");
+          _vm.loadMore();
+        },
+        // 下拉刷新
+        onRefresh: () async{
+          Log.d("----onRefresh");
+          _vm.onRefresh();
+        },
+        child: LoadStateLayout(
+          state: state.loadingState,
+          errorMessage: state.errorMessage,
+          errorRetry: () {
+            _vm.retryRequest();
+          },
+          successSliverWidget: [
+            SliverList(
+              delegate: SliverChildBuilderDelegate(
+                  (context, index){
+                    return _buildSaleItem(context, ref, state.list[index], _vm);
+                  },
+                  childCount: state.list.length
+                )
+              )
+          ],
+        ),
+      ).marginOnly(top: 5, bottom: 5),
     );
   }
 }

+ 41 - 26
packages/cpt_property/lib/modules/sale/page/property_sale_state.dart

@@ -2,48 +2,63 @@
 
 import 'dart:convert';
 
-PropertySaleState propertySaleStateFromJson(String str) => PropertySaleState.fromJson(json.decode(str));
-
-String propertySaleStateToJson(PropertySaleState data) => json.encode(data.toJson());
+import 'package:widgets/load_state_layout.dart';
 
 class PropertySaleState {
-  PropertySaleState({
-    required this.curPage,
-    required this.pageSize,
-    required this.list,
-    required this.filterCount,
-  });
+  //页面 LoadView 状态的展示
+  LoadState loadingState;
+  String? errorMessage;
 
-  int curPage;
-  int pageSize;
+  int? curPage;
+  int? pageSize = 10;
+  int? filterCount = 0;
   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"],
-  );
+  PropertySaleState({
+    this.loadingState = LoadState.State_Loading,
+    String? errorMessage,
+    this.curPage = 1,
+    this.pageSize = 10,
+    this.filterCount = 0,
+    required this.list,
+  });
 
-  Map<dynamic, dynamic> toJson() => {
-    "curPage": curPage,
-    "pageSize": pageSize,
-    "list": List<dynamic>.from(list.map((x) => x)),
-    "filterCount": filterCount,
-  };
+  Map<String, dynamic> toMap() {
+    return {
+      'loadingState': this.loadingState,
+      'errorMessage': this.errorMessage,
+      'curPage': this.curPage,
+      'pageSize': this.pageSize,
+      'filterCount': this.filterCount,
+      'list': this.list,
+    };
+  }
+  factory PropertySaleState.fromMap(Map<String, dynamic> map) {
+    return PropertySaleState(
+      loadingState: map['loadingState'] as LoadState,
+      errorMessage: map['errorMessage'] as String,
+      curPage: map['curPage'] as int,
+      pageSize: map['pageSize'] as int,
+      filterCount: map['filterCount'] as int,
+      list: map['list'] as List<Map<String, dynamic>>,
+    );
+  }
 
   PropertySaleState copyWith({
+    LoadState? loadingState,
+    String? errorMessage,
     int? curPage,
     int? pageSize,
-    List<Map<String, dynamic>>? list,
     int? filterCount,
+    List<Map<String, dynamic>>? list,
   }) {
     return PropertySaleState(
+      loadingState: loadingState ?? this.loadingState,
+      errorMessage: errorMessage ?? this.errorMessage,
       curPage: curPage ?? this.curPage,
       pageSize: pageSize ?? this.pageSize,
-      list: list ?? this.list,
       filterCount: filterCount ?? this.filterCount,
+      list: list ?? this.list,
     );
   }
 }

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

@@ -59,7 +59,7 @@ class PropertySaleRepository {
     if (result.isSuccess) {
       //重新赋值data或list
       final json = result.getDataJson();
-      var data = PropertySaleState.fromJson(json!);
+      var data = PropertySaleState.fromMap(json!);
       //重新赋值data或list
       return result.convert<PropertySaleState>(data: data);
     }

+ 98 - 49
packages/cpt_property/lib/modules/sale/vm/property_sale_vm.dart

@@ -2,6 +2,8 @@ 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 'package:widgets/load_state_layout.dart';
+import 'package:widgets/widget_export.dart';
 import '../page/property_sale_state.dart';
 import '../repository/property_sale_repository.dart';
 part 'property_sale_vm.g.dart';
@@ -9,23 +11,17 @@ part 'property_sale_vm.g.dart';
 @riverpod
 class PropertySaleVm extends _$PropertySaleVm {
   late PropertySaleRepository propertySaleRepository;
+  bool _needShowPlaceholder = true; //是否展示LoadingView
+
+  // Refresh 控制器
+  final EasyRefreshController refreshController = EasyRefreshController(
+    controlFinishRefresh: true,  //允许刷新
+    controlFinishLoad: true,   //允许加载
+  );
+
   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,
+      list: [],
     );
   }
 
@@ -39,15 +35,23 @@ class PropertySaleVm extends _$PropertySaleVm {
     return state;
   }
 
+  //刷新页面状态
+  void changeLoadingState(LoadState loadState, String? errorMsg) {
+    state = state.copyWith(
+        loadingState: loadState,
+        errorMessage: errorMsg
+    );
+  }
+
   // 初始化页面数据
   initPageData() {
     Log.d("----property_news_vm-----initPageData");
-    refreshListData();
+    onRefresh();
   }
 
-  // 上拉加载
-  Future onLoadData() async {
-    Log.d("----property_news_vm-----initListData");
+  // 上拉加载 更多
+  Future loadMore() async {
+    Log.d("----property_news_vm-----loadMore");
     // await Future.delayed(const Duration(seconds: 2));
     // if(state.list.length >= state.filterCount){
     //   return;
@@ -56,46 +60,91 @@ class PropertySaleVm extends _$PropertySaleVm {
     //   state = state.copyWith(curPage: curPage,);
     //   getListData();
     // }
+    // 检查 curPage 是否为 null,并初始化为 1
+    int newCurPage = state.curPage ?? 1;
+    state = state.copyWith(curPage: ++newCurPage);
     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 ");
+  Future onRefresh() async {
+    Log.d("----property_news_vm-----onRefresh ");
 
     // await Future.delayed(const Duration(seconds: 2));
+    state = state.copyWith(curPage: 1);
+    getListData();
+  }
 
-    state = state.copyWith(curPage: 1, pageSize: 10);
-    // ref.invalidateSelf();
-    // ref.invalidate(propertyNewsVmProvider);
+  // 重试请求
+  Future retryRequest() async {
+    state = state.copyWith(curPage: 1);
+    _needShowPlaceholder = true;
     getListData();
+  }
+
+
+  // 获取list 列表数据
+  Future getListData<T>() async {
+    if (_needShowPlaceholder) {
+      changeLoadingState(LoadState.State_Loading, null);
+    }
+
+    Log.d("加载listData数据---------------start--${state.curPage}---");
+    //   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;
+    //   handleList(listResult.data?.rows);
+    //       ToastEngine.show("获取数据成功");
+    //     } else {
+    //   errorMessage = listResult.errorMsg;
+    //   changeLoadingState(LoadState.State_Error);
+    //       ToastEngine.show(result.errorMsg ?? "Network Load Error");
+    //     }
+    //   } catch (e) {
+    //     ToastEngine.show("Error: $e");
+    //   }
+
+    await Future.delayed(const Duration(milliseconds: 1500));
+    final List<Map<String, dynamic>> listData = [
+      {
+        "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",
+      },
+    ];
+
+    if (state.curPage == 1) {
+      //刷新的方式
+      state = state.copyWith(list: listData);
+      refreshController.finishRefresh();
+      //更新展示的状态
+      changeLoadingState(LoadState.State_Success, null);
+    } else {
+      //加载更多
+      final allList = state.list;
+      allList.addAll(listData);
+      refreshController.finishLoad();
+      state = state.copyWith(list: allList);
+    }
 
+    // 最后赋值
+    _needShowPlaceholder = false;
   }
 
 }