Browse Source

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

# Conflicts:
#	packages/cpt_community/lib/modules/community/community_page.dart
#	packages/cpt_community/lib/modules/garage/garage_page.dart
liukai 3 months ago
parent
commit
375dd11ed5
80 changed files with 4353 additions and 1977 deletions
  1. 34 21
      packages/cpt_community/lib/components/garage_card.dart
  2. 3 2
      packages/cpt_community/lib/components/newfeed_card_header.dart
  3. 95 40
      packages/cpt_community/lib/components/newsfeed_card_content.dart
  4. 11 6
      packages/cpt_community/lib/components/newsfeed_card_footer.dart
  5. 177 142
      packages/cpt_community/lib/modules/community/community_page.dart
  6. 7 0
      packages/cpt_community/lib/modules/community/community_pageview_idx_data.dart
  7. 36 13
      packages/cpt_community/lib/modules/community/community_state.dart
  8. 139 24
      packages/cpt_community/lib/modules/community/community_vm.dart
  9. 1 1
      packages/cpt_community/lib/modules/community/community_vm.g.dart
  10. 2 2
      packages/cpt_community/lib/modules/community/customSilverHeaderTabs.dart
  11. 156 6
      packages/cpt_community/lib/modules/community/following/following_page.dart
  12. 39 14
      packages/cpt_community/lib/modules/community/following/following_state.dart
  13. 191 3
      packages/cpt_community/lib/modules/community/following/following_vm.dart
  14. 1 1
      packages/cpt_community/lib/modules/community/following/following_vm.g.dart
  15. 142 72
      packages/cpt_community/lib/modules/community/foryou/foryou_page.dart
  16. 22 18
      packages/cpt_community/lib/modules/community/foryou/foryou_state.dart
  17. 143 45
      packages/cpt_community/lib/modules/community/foryou/foryou_vm.dart
  18. 1 1
      packages/cpt_community/lib/modules/community/foryou/foryou_vm.g.dart
  19. 136 167
      packages/cpt_community/lib/modules/community/news/news_page.dart
  20. 23 18
      packages/cpt_community/lib/modules/community/news/news_state.dart
  21. 196 123
      packages/cpt_community/lib/modules/community/news/news_vm.dart
  22. 1 1
      packages/cpt_community/lib/modules/community/news/news_vm.g.dart
  23. 60 66
      packages/cpt_community/lib/modules/community/newsfeed_detail/newsfeed_detail_page.dart
  24. 7 13
      packages/cpt_community/lib/modules/community/newsfeed_detail/newsfeed_detail_vm.dart
  25. 1 1
      packages/cpt_community/lib/modules/community/newsfeed_detail/newsfeed_detail_vm.g.dart
  26. 69 14
      packages/cpt_community/lib/modules/community/newsfeed_tabs.dart
  27. 52 44
      packages/cpt_community/lib/modules/garage/for_rent/for_rent_page.dart
  28. 25 14
      packages/cpt_community/lib/modules/garage/for_rent/for_rent_state.dart
  29. 150 61
      packages/cpt_community/lib/modules/garage/for_rent/for_rent_vm.dart
  30. 1 1
      packages/cpt_community/lib/modules/garage/for_rent/for_rent_vm.g.dart
  31. 0 5
      packages/cpt_community/lib/modules/garage/for_sale/for_sale_state.dart
  32. 42 23
      packages/cpt_community/lib/modules/garage/for_sale/for_sale_vm.dart
  33. 1 1
      packages/cpt_community/lib/modules/garage/for_sale/for_sale_vm.g.dart
  34. 0 273
      packages/cpt_community/lib/modules/garage/garage_page.dart
  35. 0 71
      packages/cpt_community/lib/modules/garage/garage_repository.dart
  36. 0 72
      packages/cpt_community/lib/modules/garage/garage_state.dart
  37. 0 242
      packages/cpt_community/lib/modules/garage/garage_vm.dart
  38. 2 2
      packages/cpt_community/lib/modules/garage/garagesale_detail/garagesale_detail_page.dart
  39. 30 2
      packages/cpt_community/lib/modules/garage/garagesale_post/garagesale_post_page.dart
  40. 14 1
      packages/cpt_community/lib/modules/garage/garagesale_post/garagesale_post_state.dart
  41. 29 2
      packages/cpt_community/lib/modules/garage/garagesale_post/garagesale_post_vm.dart
  42. 1 1
      packages/cpt_community/lib/modules/garage/garagesale_post/garagesale_post_vm.g.dart
  43. 92 0
      packages/cpt_community/lib/modules/my_following/components/item_following.dart
  44. 64 0
      packages/cpt_community/lib/modules/my_following/components/search_cmp.dart
  45. 105 0
      packages/cpt_community/lib/modules/my_following/my_follow/my_follow_page.dart
  46. 39 0
      packages/cpt_community/lib/modules/my_following/my_follow/my_follow_state.dart
  47. 153 0
      packages/cpt_community/lib/modules/my_following/my_follow/my_follow_vm.dart
  48. 10 10
      packages/cpt_community/lib/modules/garage/garage_vm.g.dart
  49. 105 0
      packages/cpt_community/lib/modules/my_following/my_follower/my_follower_page.dart
  50. 39 0
      packages/cpt_community/lib/modules/my_following/my_follower/my_follower_state.dart
  51. 153 0
      packages/cpt_community/lib/modules/my_following/my_follower/my_follower_vm.dart
  52. 25 0
      packages/cpt_community/lib/modules/my_following/my_follower/my_follower_vm.g.dart
  53. 96 0
      packages/cpt_community/lib/modules/my_following/my_following_page.dart
  54. 30 0
      packages/cpt_community/lib/modules/my_following/my_following_state.dart
  55. 126 110
      packages/cpt_community/lib/modules/garage/garage_tabs.dart
  56. 33 0
      packages/cpt_community/lib/modules/my_following/my_following_vm.dart
  57. 10 11
      packages/cpt_community/lib/modules/garage/garage_repository.g.dart
  58. 109 8
      packages/cpt_community/lib/modules/my_posts/my_posts_forrent/my_posts_forrent_page.dart
  59. 0 0
      packages/cpt_community/lib/modules/my_posts/my_posts_forrent/my_posts_forrent_respository.dart
  60. 74 0
      packages/cpt_community/lib/modules/my_posts/my_posts_forrent/my_posts_forrent_state.dart
  61. 209 0
      packages/cpt_community/lib/modules/my_posts/my_posts_forrent/my_posts_forrent_vm.dart
  62. 26 0
      packages/cpt_community/lib/modules/my_posts/my_posts_forrent/my_posts_forrent_vm.g.dart
  63. 110 8
      packages/cpt_community/lib/modules/my_posts/my_posts_forsale/my_posts_forsale_page.dart
  64. 0 0
      packages/cpt_community/lib/modules/my_posts/my_posts_forsale/my_posts_forsale_respository.dart
  65. 74 0
      packages/cpt_community/lib/modules/my_posts/my_posts_forsale/my_posts_forsale_state.dart
  66. 257 0
      packages/cpt_community/lib/modules/my_posts/my_posts_forsale/my_posts_forsale_vm.dart
  67. 26 0
      packages/cpt_community/lib/modules/my_posts/my_posts_forsale/my_posts_forsale_vm.g.dart
  68. 13 2
      packages/cpt_community/lib/modules/my_posts/my_posts_page.dart
  69. 55 37
      packages/cpt_community/lib/modules/my_posts/my_posts_tabs.dart
  70. 24 3
      packages/cpt_community/lib/modules/my_posts/my_posts_vm.dart
  71. 3 3
      packages/cpt_community/lib/modules/my_posts/my_posts_vm.g.dart
  72. 16 0
      packages/cpt_community/lib/router/component/community_component_service.dart
  73. 32 20
      packages/cpt_community/lib/router/page/community_page_router.dart
  74. 60 20
      packages/cpt_community/lib/router/page/community_page_router.gr.dart
  75. 6 3
      packages/cpt_main/lib/modules/me/me_view_model.dart
  76. 15 15
      packages/cpt_property/lib/modules/ioan/property_ioan_page.dart
  77. 2 1
      packages/cpt_property/lib/modules/ioan/property_ioan_vm.dart
  78. 6 0
      packages/cs_router/lib/componentRouter/community_service.dart
  79. 11 2
      packages/cs_router/lib/path/router_path.dart
  80. 105 95
      packages/cs_widgets/lib/dialog/app_custom_dialog.dart

+ 34 - 21
packages/cpt_community/lib/components/garage_card.dart

@@ -24,10 +24,16 @@ import '../modules/garage/for_sale/for_sale_vm.dart';
 // 'publisher_avator': Assets.communityCamera,'
 
 
-
-
-
+// 定义一个 使用场景的 枚举
+enum GarageCardUseType {
+  // 默认
+  forSale,
+  forRent,
+  myPostsForSale,
+  myPostsForRent,
+}
 class GarageCard extends StatelessWidget {
+  GarageCardUseType? useType;
   Map<String, dynamic> itemObj;
   double? cardHeight;
   final Function()? onTap;
@@ -35,6 +41,7 @@ class GarageCard extends StatelessWidget {
 
   GarageCard({
     Key? key,
+    this.useType = GarageCardUseType.forSale,
     required this.itemObj,
     this.onTap,
     this.onClickColleciotn,
@@ -119,33 +126,39 @@ class GarageCard extends StatelessWidget {
         // 发布人信息
         Expanded(
           child: Padding(
-            padding: const EdgeInsets.only(left: 10, right: 10),
+            padding: EdgeInsets.only(left: (useType == GarageCardUseType.forSale || useType == GarageCardUseType.forRent)?10:0, right: 10),
             child: Row(
               mainAxisAlignment: MainAxisAlignment.spaceAround,
               crossAxisAlignment: CrossAxisAlignment.center,
               children: [
-                MyLoadImage(
-                  itemObj['publisher_avator'],
-                  width: 30,
-                  height: 30,
-                  isCircle: true,
-                ),
+                if (useType == GarageCardUseType.forSale || useType == GarageCardUseType.forRent)
+                  MyLoadImage(
+                    itemObj['publisher_avator'],
+                    width: 30,
+                    height: 30,
+                    isCircle: true,
+                  )
+                else
+                  const SizedBox.shrink(),
                 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,
-                      ),
+                      if (useType == GarageCardUseType.forSale || useType == GarageCardUseType.forRent)
+                        MyTextView(
+                          itemObj['publisher'],
+                          maxLines: 1,
+                          isTextEllipsis: true,
+                          textAlign: TextAlign.start,
+                          marginLeft: 13,
+                          fontSize: 12,
+                          textColor: ColorUtils.string2Color('#2956B7'),
+                          isFontRegular: true,
+                        )
+                      else
+                        const SizedBox.shrink(),
                       MyTextView(
                         itemObj['publish_time'],
                         maxLines: 1,
@@ -198,7 +211,7 @@ class CollectionWidget extends HookConsumerWidget {
         children: [
           MyTextView(
             '${collectionNumState.value}',
-            textColor: ColorUtils.string2Color('#000000'),
+            textColor: context.appColors.textBlack,
             fontSize: 14,
             isFontRegular: true,
             marginRight: 7,

+ 3 - 2
packages/cpt_community/lib/components/newfeed_card_header.dart

@@ -1,3 +1,4 @@
+import 'package:cs_resources/theme/app_colors_theme.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/widgets.dart';
 import 'package:shared/utils/color_utils.dart';
@@ -33,7 +34,7 @@ class NewsFeedCardHeader extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
     return Container(
-      padding: const EdgeInsets.only(left: 16,right: 60),
+      padding: const EdgeInsets.only(left: 16,right: 60,),
       child: Row(
         mainAxisAlignment: MainAxisAlignment.start,
         crossAxisAlignment: CrossAxisAlignment.start,
@@ -60,7 +61,7 @@ class NewsFeedCardHeader extends StatelessWidget {
                     title,
                     isFontMedium: true,
                     fontSize: 18,
-                    textColor: ColorUtils.string2Color('#000000'),
+                    textColor: context.appColors.textBlack,
                     maxLines: 1,
                     isTextEllipsis: true,
                   ),

+ 95 - 40
packages/cpt_community/lib/components/newsfeed_card_content.dart

@@ -1,6 +1,10 @@
+import 'package:cpt_community/components/comments_dialog.dart';
+import 'package:cs_resources/theme/app_colors_theme.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/widgets.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/my_load_image.dart';
 import 'package:widgets/my_text_view.dart';
 
@@ -14,54 +18,105 @@ import 'package:widgets/my_text_view.dart';
 // 'likeno': 12
 
 class NewsFeedCardContent extends StatelessWidget {
-  const NewsFeedCardContent({
+  final String content;
+  final List? imageUrls;
+  int? rowMaxImageNum=3;
+  int? textMaxLines = 3;
+  NewsFeedCardContent({
     Key? key,
     required this.content,
     this.imageUrls,
+    this.rowMaxImageNum = 3,
+    this.textMaxLines = 3
   }) : super(key: key);
 
-  final String content;
-  final List? imageUrls;
 
   @override
   Widget build(BuildContext context) {
-    return Container(
-      padding: const EdgeInsets.symmetric(horizontal: 16),
-      child: Column(
-        children: [
-          Expanded(
-            child: MyTextView(
-              content,
-              textColor: ColorUtils.string2Color('#000000'),
-              fontSize: 15,
-              maxLines: 3,
-              isTextEllipsis: true,
-            ),
-          ),
-          const SizedBox(height: 12),
-          // 图片
-          if (imageUrls != null && imageUrls!.isNotEmpty)
-             Container(
-               width: double.infinity,
-               height: 87,
-               child: Row(
-                 mainAxisAlignment: MainAxisAlignment.center,
-                 children: [
-                   for (var item in imageUrls!)
-                     Expanded(
-                       child: Container(
-                         // width: 87,
-                         // height: 87,
-                         // margin: const EdgeInsets.only(right: 30),
-                         margin: const EdgeInsets.only(left: 15,right: 18),
-                         color: ColorUtils.string2Color("#F2F3F6"),
-                       ),
-                     )
-                 ],
-               ),
-             )
-        ]
-      ),
+    List imageUrlsList = [];
+    if(imageUrls != null && imageUrls!.isNotEmpty){
+      // dart 取出 imageUrls 里面的前三张图片
+      imageUrlsList = imageUrls!.take(rowMaxImageNum!).toList();
+    }
+    int totalImageCount = imageUrls!.length;
+    int otherImageCount = imageUrls!.length - rowMaxImageNum!;
+    int rowActualImageCount = imageUrls!.length > rowMaxImageNum! ? rowMaxImageNum! : imageUrls!.length;
+    return LayoutBuilder(
+        builder: (BuildContext context, BoxConstraints constraints) {
+          final maxHeight = constraints.maxHeight;
+          final minHeight = constraints.minHeight;
+          final maxWidth = constraints.maxWidth;
+          Log.d("---maxHeight-----$maxHeight-- $minHeight  $maxWidth--");
+          return Container(
+            width: double.infinity,
+            padding: const EdgeInsets.symmetric(horizontal: 15),
+            child: Column(
+                children: [
+                  MyTextView(
+                    content,
+                    textColor: context.appColors.textBlack,
+                    fontSize: 15,
+                    maxLines: textMaxLines,
+                    isTextEllipsis: true,
+                  ),
+                  const SizedBox(height: 12),
+                  // 图片
+                  _buildImageSection(context,maxWidth - 15, imageUrlsList, totalImageCount,otherImageCount),
+                ]
+            )
+          );
+      }
     );
   }
+
+
+  Widget _buildImageSection(BuildContext context,double maxWidth, List? imageUrls, int totalImageCount, int otherImageCount) {
+    if (imageUrls != null && imageUrls!.isNotEmpty) {
+      final imageCount = imageUrls.length;
+      return SizedBox(
+        width: maxWidth,
+        height: 87,
+        child: Row(
+          mainAxisAlignment: MainAxisAlignment.spaceBetween,
+          children: List.generate(
+              imageUrls.length,
+              (index) => Container(
+                height: 87,
+                width: maxWidth/imageCount - 16 * (imageCount-1),
+                margin: EdgeInsets.only(right: (index!=imageCount-1) ? 16 : 0 ),
+                color: ColorUtils.string2Color("#F2F3F6"),
+                // color: Colors.red,
+                child:Stack(
+                    children: [
+                      MyLoadImage(
+                        imageUrls[index],
+                        width: maxWidth/imageCount - (16 * imageCount-1),
+                        height: 87,
+                        fit: BoxFit.cover,
+                        cornerRadius: 5,
+                      ),
+                      otherImageCount > 0 && index == imageCount-1 ?
+                        Positioned(
+                        bottom: 0,
+                        right: 0,
+                        child: Container(
+                          padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 2),
+                          color: context.appColors.textBlack.withOpacity(0.5),
+                          child: MyTextView(
+                            "+$otherImageCount",
+                            textColor: Colors.white,
+                            fontSize: 12,
+                          ),
+                        ),
+                      ): const SizedBox.shrink(),
+                    ]
+                  )
+              ),
+          )
+        )
+            );
+      } else {
+        return const SizedBox.shrink();
+      }
+    }
 }

+ 11 - 6
packages/cpt_community/lib/components/newsfeed_card_footer.dart

@@ -8,6 +8,9 @@ import 'package:widgets/ext/ex_widget.dart';
 import 'package:widgets/my_load_image.dart';
 import 'package:widgets/my_text_view.dart';
 
+
+import '../modules/community/community_page.dart';
+
 // 'id':1,
 // 'avator': Assets.communityCamera,
 // 'title': 'William Jefferson',
@@ -22,13 +25,15 @@ class NewsFeedCardFooter extends StatelessWidget {
   final VoidCallback? onLike;
   final VoidCallback? onComment;
   final VoidCallback? onShare;
+  final bool showShare;
 
   const NewsFeedCardFooter({
     Key? key,
     required this.isLike,
     this.onLike,
     this.onComment,
-    this.onShare
+    this.onShare,
+    this.showShare = false,
   })
   : super(key: key);
 
@@ -41,9 +46,9 @@ class NewsFeedCardFooter extends StatelessWidget {
       // color: Colors.red,
       child: Row(
         mainAxisAlignment: MainAxisAlignment.spaceBetween,
+        crossAxisAlignment: CrossAxisAlignment.center,
         children: [
           Container(
-            height: 40,
             padding: const EdgeInsets.all(8),
             child: Row(
               children: [
@@ -63,7 +68,6 @@ class NewsFeedCardFooter extends StatelessWidget {
             onLike?.call();
           }),
           Container(
-            height: 40,
             padding: const EdgeInsets.all(8),
             child: Row(
               children: [
@@ -79,11 +83,12 @@ class NewsFeedCardFooter extends StatelessWidget {
               ],
             ),
           ).onTap((){
-            Log.d("点击了comments");
+            // Log.d("点击了comments   ${tabsRouterKey.currentState?.controller?.activeIndex}");
+            // tabsRouterKey.currentState?.controller?.setActiveIndex(2);
             onComment?.call();
           }),
-          Container(
-            height: 40,
+          if(showShare)
+            Container(
             padding: const EdgeInsets.all(8),
             child: Row(
               children: [

+ 177 - 142
packages/cpt_community/lib/modules/community/community_page.dart

@@ -21,6 +21,9 @@ import 'newsfeed_tabs.dart';
 import 'community_vm.dart';
 import 'customSilverHeaderTabs.dart';
 
+final tabsRouterKey = GlobalKey<AutoTabsRouterState>();
+
+
 @RoutePage()
 class CommunityPage extends HookConsumerWidget {
     const CommunityPage({Key? key}) : super(key: key);
@@ -34,132 +37,107 @@ class CommunityPage extends HookConsumerWidget {
       }
     }
 
-    bool _isPreventScroll(ScrollNotification notification, WidgetRef ref){
-      // 检查当前页面是否是可见的
-      bool isDownOrUp = notification.metrics.axis == Axis.vertical;
-      if (notification is UserScrollNotification) {
-        // 检查滚动方向
-        switch (notification.direction) {
-          case ScrollDirection.forward:
-            print('Scrolling down');
-            break;
-          case ScrollDirection.reverse:
-            print('Scrolling up');
-            break;
-          case ScrollDirection.idle:
-            print('Scrolling stopped');
-            break;
-        }
-      } else if (notification is ScrollUpdateNotification) {
-        // 检查滚动位置变化
-        double currentScrollPosition = notification.metrics.pixels;
-        double maxScrollExtent = notification.metrics.maxScrollExtent;
-
-        // 判断是否满足某个条件
-        if (currentScrollPosition > 0 && currentScrollPosition < maxScrollExtent) {
-          print('Current scroll position: $currentScrollPosition');
-          // 在这里添加你的条件判断逻辑
-        }
-
-        // 只有当上下滚动时才拦截通知
-        if (isDownOrUp) {
-          final vm = ref.read(communityVmProvider.notifier);
-          final currentTabRouter = vm.state!.tabsRouter;
-          if(currentTabRouter!.activeIndex == 0){
-            return false;  // false 不拦截
-          }else {
-            return true;   // true 拦截
-          }
-        }
-      }
-      return false;
-    }
-
     @override
     Widget build(BuildContext context, WidgetRef ref) {
         final vm = ref.read(communityVmProvider.notifier);
-        BuildContext contextPage = context;
-        // 创建 GlobalKey
-        final _tabsRouterKey = GlobalKey<AutoTabsRouterState>();
+        final state = ref.watch(communityVmProvider);
 
-        // useEffect((){
-        //   Log.d("CommunityPage initState");
-        //   return () {
-        //     Log.d("CommunityPage dispose");
-        //   };
-        // },[]);
+        useEffect((){
+          Log.d("CommunityPage initState");
+          // 延迟监听
+          WidgetsBinding.instance?.addPostFrameCallback((timeStamp) {
+            if(tabsRouterKey.currentState?.controller != null){
+              tabsRouterKey.currentState?.controller?.addListener((){
+                vm.tabsRouterChange();
+              });
+            }
+          });
+
+          return (){
+            Log.d("CommunityPage dispose");
+            tabsRouterKey.currentState?.controller?.removeListener(vm.tabsRouterChange);
+          };
+        },[tabsRouterKey.currentState?.controller]);
 
         return Scaffold(
-            appBar: MyAppBar.appBar(
+            appBar: state.currentCategoryIdx == 0 ? MyAppBar.appBar(
               context,
               "Community",
-              backgroundColor: context.appColors.backgroundWhite,
+              backgroundColor: context.appColors.whiteBG,
+            ): MyAppBar.searchAppBar(
+              context,
+              actions: [
+                IconButton(
+                  icon: const Icon(Icons.search),
+                  onPressed: () {
+                    // do something
+                    vm.handlerChooseGarageCategory(context);
+                  },
+                ),
+              ],
+              backgroundColor: context.appColors.whiteBG,
             ),
-            backgroundColor: context.appColors.backgroundDefault,
-            body: NestedScrollView(
-              headerSliverBuilder: (context, innerBoxIsScrolled) {
-                return [
-                  SliverToBoxAdapter(
-                      child: Consumer(
-                        builder: (context, ref, _) {
-                          return _buildTopSection(context, ref, vm);
-                        },
-                      ),
-                  ),
-                  // SliverPersistentHeader(
-                  //   pinned: true, // 吸顶
-                  //   delegate: CustomSliverPersistentHeaderDelegate(
-                  //     child: _buildTabsSection(contextPage, ref),
-                  //   ),
-                  // ),
-                ];
-              },
-              body: NotificationListener<ScrollNotification>(
-                onNotification: (ScrollNotification notification) {
-                  // 是否拦截滚动  false 表示不拦截通知
-                  // return _isPreventScroll(notification, ref);
-                  return false;
+          backgroundColor: context.appColors.backgroundDefault,
+          body: AutoTabsRouter.pageView(
+            key: tabsRouterKey,
+            routes: const [
+              NewsPageRoute(),
+              FollowingPageRoute(),
+              ForyouPageRoute(),
+              ForsalePageRoute(),
+              ForrentPageRoute(),
+            ],
+            // physics: const NeverScrollableScrollPhysics(), // 禁止滚动
+            builder: (context, child, pageController) {
+              final tabsRouter = AutoTabsRouter.of(context);
+
+              return NestedScrollView(
+                headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
+                  return [
+                    // top 组件,转换为 Sliver 组件
+                    SliverToBoxAdapter(
+                      child: _buildTopSection(context, ref, vm, state),
+                    ),
+                    // tab 组件,使用 SliverPersistentHeader 实现吸顶
+                    // SliverPersistentHeader(
+                    //   pinned: true,
+                    //   delegate: CustomSliverPersistentHeaderDelegate(
+                    //     child: _buildTabsSection(context, ref, tabsRouter, vm, state),
+                    //   ),
+                    // ),
+                    // SliverToBoxAdapter(
+                    //   child: _buildPostSection(context, ref, vm, state),
+                    // ),
+                  ];
                 },
-                child: AutoTabsRouter.pageView(
-                  key: _tabsRouterKey,
-                  routes: const [
-                    NewsPageRoute(),
-                    FollowingPageRoute(),
-                    ForyouPageRoute()
+                body: Column(
+                  mainAxisSize: MainAxisSize.max,
+                  children: [
+                    _buildTabsSection(context, ref, tabsRouter, vm, state),
+                    _buildPostSection(context, ref, vm, state),
+                    Expanded(
+                        child: child
+                    ),
                   ],
-                  builder: (context, child, pageController) {
-                    final tabsRouter = AutoTabsRouter.of(context);
-                    // Log.d("autotabsrouter build  ${tabsRouter.activeIndex}");
-                    // Log.d("communityVmProvider.notifier state.tabsRouter.tabsRouter:  ${ref.read(communityVmProvider.notifier).state.tabsRouter}");
-                    // ref.read(communityVmProvider.notifier).state.tabsRouter = tabsRouter;
-                    // ref.read(communityVmProvider.notifier).state.pageController = pageController;
-                    // Log.d("communityVmProvider.notifier state.tabsRouter.tabsRouter.activeIndex:  ${ref.read(communityVmProvider.notifier).state.tabsRouter.activeIndex}");
-                    WidgetsBinding.instance.addPostFrameCallback((_) {
-                      vm.setTabsRouterAndPageController(tabsRouter, pageController);
-                    });
-
-                    return Column(
-                      mainAxisSize: MainAxisSize.max,
-                      children: [
-                        // tab 组件
-                        _buildTabsSection(contextPage, ref, tabsRouter),
-                        // post 组件
-                        _buildPostSection(context, ref, vm),
-                        Expanded(
-                          child: child,
-                        ),
-                      ],
-                    );
-                  },
-                ),
-              ),
-            )
+                ), // post 组件和其他内容
+              );
+            },
+          ),
         );
     }
 
-     Widget _buildTopSection(BuildContext context, WidgetRef ref, vm) {
+
+     Widget _buildTopSection(BuildContext context, WidgetRef ref, vm, state) {
         final topSectionsData = vm.topSectionsData;
+        // final currentPageIdx = tabsRouterKey.currentState?.controller?.activeIndex ?? 0;
         int curTagIdx = 0;
+        int currentPageIdx = state.currentPageViewIdx;
+        int newsfeedTabCount = state.newsFeedTabsList.length;
+        if(currentPageIdx >= newsfeedTabCount){
+          curTagIdx = 1;
+        }else {
+          curTagIdx = 0;
+        }
         return Container(
           color: context.appColors.whiteBG,
           padding: const EdgeInsets.only(top: 23, bottom: 30),
@@ -176,7 +154,6 @@ class CommunityPage extends HookConsumerWidget {
                       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(
@@ -184,14 +161,14 @@ class CommunityPage extends HookConsumerWidget {
                             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);
+                          vm.handlerSwitchNewsfeedOrGaragesale(index, context, null);
                         },
                         type: ClickType.throttle,
                       ),
@@ -212,24 +189,50 @@ class CommunityPage extends HookConsumerWidget {
         );
     }
 
-     Widget _buildTabsSection(BuildContext context, WidgetRef ref, tabsRouter){
-       final vm = ref.read(communityVmProvider.notifier);
-       final tabsList = ref.watch(communityVmProvider.select((state) => state.tabsList));
+     Widget _buildTabsSection(BuildContext context, WidgetRef ref, tabsRouter, vm, state){
+       int currentPageIndex = tabsRouter!.activeIndex ?? 0;
+       int newsfeedTabCount = state.newsFeedTabsList.length;
+
+       List<String> tabsList;
+       if(currentPageIndex < newsfeedTabCount){
+         // news feed
+         tabsList = state.newsFeedTabsList ?? [];
+       }else {
+         tabsList = state.garageSaleTabsList ?? [];
+       }
        return Container(
         width: double.infinity,
-        padding: const EdgeInsets.only(left: 15, right: 15,top: 14,bottom: 14),
+        padding: const EdgeInsets.only(left: 15, right: 15,top: 14,bottom: 12),
+        color: ColorUtils.string2Color('#F2F3F6'),
         child: NewsfeedTabs(
           key: UniqueKey(),
-          tabsList: tabsList!,
+          tabsList: tabsList,
             tabsRouter: tabsRouter,
-          onClickAction:(activeTabIdx){
-            vm.handlerChangeTab(activeTabIdx, tabsRouter);
+          onClickAction:(Map<String, dynamic>? params){
+            if (params != null) {
+              // 解构 params
+              final int? currentCatgoryIdx = params['currentCatgoryIdx'] as int?;
+              final int? tabIdx = params['tabIdx'] as int?;
+              vm.handlerChangeTab(tabIdx, tabsRouter, currentCatgoryIdx);
+            }
           }
         ),
       );
     }
 
-      Widget _buildPostSection(BuildContext context, WidgetRef ref, vm){
+      Widget _buildPostSection(BuildContext context, WidgetRef ref, vm, state){
+        int currentPageIndex = state.currentPageViewIdx;
+        int newsfeedTabCount = state.newsFeedTabsList.length;
+        if(currentPageIndex < newsfeedTabCount){
+          // news feed
+          return  _buildNewsFeedPost(context, ref, vm, state);
+        }else {
+          return  _buildGarageSalePost(context, ref, vm, state);
+        }
+
+      }
+
+      Widget _buildNewsFeedPost(BuildContext context, WidgetRef ref, vm, state){
         return Container(
           height: 65.5,
           width: double.infinity,
@@ -238,31 +241,63 @@ class CommunityPage extends HookConsumerWidget {
           child: Row(
             children: [
               const MyAssetImage(Assets.communityNesFeed, width: 45,height: 45,),
-             Expanded(
-               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,
-             ),
+              Expanded(
+                child: MyTextView(
+                  "What’s on your mind?",
+                  textColor: context.appColors.textBlack,
+                  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);
-
-            MyPostsPage.startInstance();
+            vm.handlerGotoNewsfeedPost(context);
           }),
         );
       }
 
+      Widget _buildGarageSalePost(BuildContext context, WidgetRef ref, vm, state){
+        return Container(
+          height: 65.5,
+          width: double.infinity,
+          padding: const EdgeInsets.only(left: 20, right: 20),
+          color: Colors.white,
+          child: Row(
+            children: [
+              const MyAssetImage(Assets.communityNesFeed, width: 45,height: 45,),
+              Expanded(
+                child: MyTextView(
+                  "Sell Item",
+                  textColor: context.appColors.textBlack,
+                  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.handlerGotoGaragePost(context);
+          }),
+        );
+      }
 }
+

+ 7 - 0
packages/cpt_community/lib/modules/community/community_pageview_idx_data.dart

@@ -0,0 +1,7 @@
+class CommunityPageViewIdxData {
+  static const int news = 0;
+  static const int following = 1;
+  static const int forYou = 2;
+  static const int forSale = 3;
+  static const int forRent = 4;
+}

+ 36 - 13
packages/cpt_community/lib/modules/community/community_state.dart

@@ -1,48 +1,71 @@
 import 'package:cpt_community/modules/community/community_page.dart';
 import 'package:cs_resources/generated/assets.dart';
 
-import '../garage/garage_page.dart';
 
 class CommunityVmState {
   List<Map<String, dynamic>>? topSectionsData;
-  List? tabsList = ["News", "Following", "For You"];
-  int currentTabIndex = 0;
+  List<String>? newsFeedTabsList;
+  List<String>? garageSaleTabsList;
+  int currentCategoryIdx = 0;   // 0: news feed, 1: garage sale
+  int currentPageViewIdx = 0;
+  int lastNewsfeedTabIdx = 0; // 上一次newsfeed 的 tabIdx
+  int lastGarageTabIdx = 0; // 上一次garagesale 的 tabIdx
   dynamic? tabsRouter;
   dynamic? pageController;
 
 
   CommunityVmState({
     List<Map<String, dynamic>>? topSectionsData,
-    required this.currentTabIndex,
-    this.tabsList,
+    required this.currentPageViewIdx,
+    currentCategoryIdx,
+    lastNewsfeedTabIdx,
+    lastGarageTabIdx,
+    newsFeedTabsList,
+    garageSaleTabsList,
     this.tabsRouter,
     this.pageController,
   }) : topSectionsData = topSectionsData?? [
     {
       "title": "News Feed",
       "icon": Assets.communityNesFeed,
-      "pageStartInstanceFn": CommunityPage.startInstance,
-      "page": const CommunityPage(),
     },
     {
       "title": "Garage Sale",
       "icon": Assets.communityGarageSale,
-      "pageStartInstanceFn": GaragePage.startInstance,
-      "page": const GaragePage(),
     },
+  ],
+        currentCategoryIdx = currentCategoryIdx?? 0,
+        lastGarageTabIdx = lastGarageTabIdx?? 0,
+        lastNewsfeedTabIdx = lastNewsfeedTabIdx?? 0,
+  newsFeedTabsList = newsFeedTabsList?? [
+    "News",
+    "Following",
+    "For You",
+  ],
+  garageSaleTabsList = garageSaleTabsList?? [
+    "For Sale",
+    "For Rent",
   ];
 
   CommunityVmState copyWith({
     List<Map<String, dynamic>>? topSectionsData,
-    List? tabsList,
-    int? currentTabIndex,
+    List<String>? newsFeedTabsList,
+    List<String>? garageSaleTabsList,
+    int? currentCategoryIdx,
+    int? currentPageViewIdx,
+    int? lastNewsfeedTabIdx,
+    int? lastGarageTabIdx,
     dynamic? tabsRouter,
     dynamic? pageController,
   }) {
     return CommunityVmState(
       topSectionsData: topSectionsData ?? this.topSectionsData,
-      tabsList: tabsList ?? this.tabsList,
-      currentTabIndex: currentTabIndex ?? this.currentTabIndex,
+      newsFeedTabsList: newsFeedTabsList ?? this.newsFeedTabsList,
+      garageSaleTabsList: garageSaleTabsList ?? this.garageSaleTabsList,
+      currentCategoryIdx: currentCategoryIdx ?? this.currentCategoryIdx,
+      currentPageViewIdx: currentPageViewIdx ?? this.currentPageViewIdx,
+      lastNewsfeedTabIdx: lastNewsfeedTabIdx ?? this.lastNewsfeedTabIdx,
+      lastGarageTabIdx: lastGarageTabIdx ?? this.lastGarageTabIdx,
       tabsRouter: tabsRouter ?? this.tabsRouter,
       pageController: pageController ?? this.pageController,
     );

+ 139 - 24
packages/cpt_community/lib/modules/community/community_vm.dart

@@ -1,14 +1,22 @@
 
-import 'package:cpt_community/modules/garage/garage_page.dart';
+import 'package:cpt_community/components/comments_dialog.dart';
 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/cupertino.dart';
+import 'package:plugin_platform/engine/dialog/dialog_engine.dart';
 import 'package:plugin_platform/engine/toast/toast_engine.dart';
 import 'package:riverpod_annotation/riverpod_annotation.dart';
 import 'package:router/path/router_path.dart';
 import 'package:shared/utils/log_utils.dart';
 import 'package:auto_route/auto_route.dart';
+import 'package:widgets/dialog/app_custom_dialog.dart';
+import 'package:widgets/my_checkbox_group.dart';
 
+import '../garage/garagesale_post/garagesale_post_page.dart';
+import '../my_following/my_following_page.dart';
+import '../my_posts/my_posts_page.dart';
+import 'community_page.dart';
 import 'community_state.dart';
 import 'newsfeed_post/newsfeed_post_page.dart';
 
@@ -18,19 +26,29 @@ part 'community_vm.g.dart';
 class CommunityVm extends _$CommunityVm {
   get topSectionsData => state.topSectionsData;
 
+
   CommunityVmState initState() {
     return CommunityVmState(
-      currentTabIndex: 0,
-      tabsList: ["News", "Following", "For You"],
+      currentCategoryIdx: 0,
+      currentPageViewIdx: 0,
+      lastGarageTabIdx: 0,
+      lastNewsfeedTabIdx: 0,
+      newsFeedTabsList: [
+        "News",
+        "Following",
+        "For You",
+      ],
+      garageSaleTabsList: [
+        "For Sale",
+        "For Rent",
+      ],
     );
   }
 
   @override
   CommunityVmState build(){
-
     final state = initState();
 
-
     // 第一帧渲染完成
 
     WidgetsBinding.instance?.addPostFrameCallback((timeStamp) {
@@ -41,37 +59,134 @@ class CommunityVm extends _$CommunityVm {
     return state;
   }
 
+  tabsRouterChange(){
+    Log.d("----tabsRouterChange---${tabsRouterKey.currentState?.controller?.activeIndex}-");
+    state = state.copyWith(currentPageViewIdx: tabsRouterKey.currentState?.controller?.activeIndex ?? 0);
+  }
 
   // 切换tab
-  handlerChangeTab(int index, tabsRouter) {
-    tabsRouter.setActiveIndex(index);
-    // state = state.copyWith(tabsRouter: tabsRouter ,activeTabIdx: index);
-    Log.d("community_vm handlerChangeTab--index:    $index");
+  handlerChangeTab(int tabIndex, TabsRouter? tabsRouter, int? categoryIdx) {
+    tabsRouter = (tabsRouter?? tabsRouterKey.currentState?.controller)!;
+    categoryIdx = categoryIdx ?? state.currentCategoryIdx;
+    if(categoryIdx == 0){
+      tabsRouter.setActiveIndex(tabIndex);
+    }else {
+      tabsRouter.setActiveIndex(state.newsFeedTabsList!.length + tabIndex);
+    }
+  }
+
+  // 切换news feed和garage sale
+  handlerSwitchNewsfeedOrGaragesale( int categoryIdx, BuildContext? context, TabsRouter? tabsRouter){
+    tabsRouter = (tabsRouter?? tabsRouterKey.currentState?.controller)!;
+    categoryIdx = categoryIdx;
+    if(categoryIdx == 0){
+      tabsRouter.setActiveIndex(state.lastNewsfeedTabIdx);
+    }else if (categoryIdx == 1){
+      tabsRouter.setActiveIndex(state.newsFeedTabsList!.length + state.lastGarageTabIdx);
+    }
   }
 
-  // 设置当前的 tabsRouter 和 pageController
-  setTabsRouterAndPageController(dynamic tabsRouter, dynamic pageController) {
-    Log.d("setTabsRouterAndPageController---:$tabsRouter");
-    state =  state.copyWith(tabsRouter: tabsRouter ,pageController: pageController, currentTabIndex: tabsRouter.activeIndex);
+  // 设置当前的cat类型
+  setCurrentCategoryIdx(BuildContext? context, int categoryIdx, int? lastNewsfeedTabIdx, int? lastGarageTabIdx){
+    state = state.copyWith(
+        currentCategoryIdx: categoryIdx,
+        lastNewsfeedTabIdx: lastNewsfeedTabIdx?? state.lastNewsfeedTabIdx,
+        lastGarageTabIdx: lastGarageTabIdx?? state.lastGarageTabIdx
+    );
   }
 
+  // 判断当前pageview 页面正处于显示状态
+  Future isCurrentPageViewShowing(int pageViewIdx) async{
+    // 延迟获取结果
+    bool isShowing = await Future.delayed(const Duration(milliseconds: 500), (){
+      return state.currentPageViewIdx == pageViewIdx;
+    });
+    return isShowing;
+  }
 
-  handlerChangeCommunityType(BuildContext context, int index){
-    if(index == 1){
-      Log.d("去往garage 页面");
-      // 跳转到 garage sale 页面
-      GaragePage.startInstance(context: context);
-      // AutoRouter.of(context).push(const GaragePageRoute());
-    }
+  // 选择 garage sale 导航栏点击 选择分类
+  handlerChooseGarageCategory(BuildContext context) async {
+    List<Map<String, dynamic>> categoryList = [
+      {
+        'id': '1',
+        'label': 'Kids',
+      },
+      {
+        'id': '2',
+        'label': 'Homeware',
+      },
+      {
+        'id': '3',
+        'label': 'Fashion',
+      },
+      {
+        'id': '4',
+        'label': 'Electronics',
+      },
+      {
+        'id': '5',
+        'label': 'Sports',
+      },
+      {
+        'id': '6',
+        'label': 'Furniture',
+      },
+      {
+        'id': '7',
+        'label': 'Others',
+      },
+    ];
+    await DialogEngine.show(
+        tag: "chooseGarageSaleCategory",
+        position: DialogPosition.center,
+        widget: AppCustomDialog(
+          message: '',
+          dialogWidth: MediaQuery.of(context).size.width * 0.8,
+          // contentBoxMaxHeight: 350,
+          // contentBoxMinHeight: 300,
+          confirmTxt: "Ok",
+          messageBuilder: (BuildContext context){
+            return Container(
+              color: context.appColors.textWhite,
+              child: Column(
+                mainAxisAlignment: MainAxisAlignment.start,
+                crossAxisAlignment: CrossAxisAlignment.start,
+                children: [
+                  MyCheckboxGroup(
+                      isSingleSelect: false,
+                      labelStyle: const TextStyle(
+                        fontSize: 16,
+                        fontWeight: FontWeight.w500,
+                      ),
+                      items: categoryList,
+                      onChanged: (List<Map<String, dynamic>> selectedItems){
+                        Log.d("----MyCheckboxGroup onChanged  $selectedItems");
+                      }
+                  )
+                ],
+              ),
+            );
+          },
+          isShowCancelBtn:false,
+          confirmAction: (){
+
+          },
+        )
+    );
   }
 
-  // 点击发布的按钮 跳转到发布的页面
-  void handlerGotoPost(context){
-    // ComponentServiceManager().communityService.startCommunityPage();
 
+  // 点击发布的按钮 跳转到 newsfeed 发布的页面
+  void handlerGotoNewsfeedPost(context){
     // AutoRouter.of(context).pushNamed(RouterPath.newsFeedPost);
-
     NewsfeedPostPage.startInstance();
+    // MyPostsPage.startInstance();
+    // MyFollowingPage.startInstance();
+  }
+
+  // 点击发布的按钮 跳转到garagesale 发布的页面
+  void handlerGotoGaragePost(context){
+    GaragesalePostPage.startInstance();
   }
 }
 

+ 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'e91467ce00b36b9645967931640efb4cc5674ce1';
+String _$communityVmHash() => r'c80426bfe35642b01862d16ebbd363a98137135f';
 
 /// See also [CommunityVm].
 @ProviderFor(CommunityVm)

+ 2 - 2
packages/cpt_community/lib/modules/community/customSilverHeaderTabs.dart

@@ -6,10 +6,10 @@ class CustomSliverPersistentHeaderDelegate extends SliverPersistentHeaderDelegat
    CustomSliverPersistentHeaderDelegate({required this.child});
 
    @override
-   double get minExtent => 50.0; // 最小高度
+   double get minExtent => 100.0; // 最小高度
 
    @override
-   double get maxExtent => 50.0; // 最大高度
+   double get maxExtent => 100.0; // 最大高度
 
    @override
    Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {

+ 156 - 6
packages/cpt_community/lib/modules/community/following/following_page.dart

@@ -6,6 +6,8 @@ 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';
 import 'package:widgets/my_text_view.dart';
@@ -13,6 +15,9 @@ import 'package:widgets/my_appbar.dart';
 import 'package:cs_resources/theme/app_colors_theme.dart';
 import 'package:widgets/widget_export.dart';
 
+import '../../../components/newfeed_card_header.dart';
+import '../../../components/newsfeed_card_content.dart';
+import '../../../components/newsfeed_card_footer.dart';
 import '../../../router/page/community_page_router.dart';
 import 'following_vm.dart';
 
@@ -31,19 +36,164 @@ class FollowingPage extends HookConsumerWidget {
 
   @override
   Widget build(BuildContext context, WidgetRef ref) {
-    return const Scaffold(
+    final vm = ref.read(followingVmProvider.notifier);
+    final state = ref.watch(followingVmProvider);
+    useEffect((){
+      // 组件挂载时执行 - 执行接口请求
+      Future.microtask(() => vm.initPageData());
+      return () {
+        // 组件卸载时执行
+      };
+    }, []);
+    return Scaffold(
       // appBar: MyAppBar.appBar(
       //   context,
       //   "following",
       //   backgroundColor: context.appColors.whiteBG,
       // ),
       // backgroundColor: ColorUtils.string2Color("#F2F3F6"),
-      body: Column(
-        mainAxisSize: MainAxisSize.max,
+        body: Column(
+          mainAxisSize: MainAxisSize.max,
+          children: [
+            Expanded(
+              child: EasyRefresh(
+                controller: vm.refreshController,
+                key: UniqueKey(),
+                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 _buildNewsItem(context, ref, state.list![index], vm);
+                          },
+                          childCount: state.list!.length
+                      ),
+                    )
+                  ],
+                ),
+              ),
+            )
+          ],
+        )
+    );
+  }
+
+  Widget _buildNewsItem(BuildContext context, WidgetRef ref, item, vm){
+    return Container(
+      margin: const EdgeInsets.only(left: 15, right: 15,top: 14,bottom: 14),
+      padding: const EdgeInsets.only(left: 15, right: 15,top: 17,bottom: 0),
+      // height: 280,
+      decoration: BoxDecoration(
+          color: context.appColors.textWhite,
+          borderRadius: BorderRadius.circular(10),
+          boxShadow: [
+            BoxShadow(
+              color: ColorUtils.string2Color("#E4E7EB").withOpacity(0.5),
+              spreadRadius: 0,
+              blurRadius: 4,
+              offset: const Offset(0, 4), // changes position of shadow
+            ),
+          ]
+      ),
+      child: Stack(
         children: [
-          Text("newspage-following"),
+          Column(
+              mainAxisAlignment: MainAxisAlignment.center,
+              crossAxisAlignment: CrossAxisAlignment.center,
+              children: [
+                // 卡片头部(头像 标题 时间)
+                Container(
+                  child: NewsFeedCardHeader(
+                    key: UniqueKey(),
+                    title: item['title'],
+                    avator: item['avator'],
+                    time: item['time'],
+                  ),
+                ),
+                const SizedBox(height: 15),
+                // 卡片中间 (文字和图片)
+                NewsFeedCardContent(
+                  key: UniqueKey(),
+                  content: item['content'],
+                  imageUrls: item['imageUrls'],
+                ),
+                const SizedBox(height: 16),
+                // // 卡片底部 (点赞 评论 分享)
+                Container(
+                  decoration: BoxDecoration(
+                    // color: Colors.white,
+                      border: Border(
+                        top: BorderSide(color: ColorUtils.string2Color('#EAEAEA'), width: 0.5),
+                      )
+                  ),
+                  padding: const EdgeInsets.only(top: 10, bottom: 15),
+                  child: NewsFeedCardFooter(
+                    key: UniqueKey(),
+                    isLike: item['isLike'],
+                    onLike: (){
+                      vm.handlerClickActionBtn('like', item);
+                    },
+                    onComment: (){
+                      vm.handlerClickActionBtn('comments', item);
+                    },
+                    onShare: (){
+                      vm.handlerClickActionBtn('share', item);
+                    },
+                  ),
+                ),
+              ]
+          ),
+          // 右上角 关注/取消关注 按钮
+          Visibility(
+            visible: !item['isFollow'],
+            child: Positioned(
+                right: 10,
+                top: -5,
+                child: Container(
+                  width: 83.5,
+                  height: 45.5,
+                  alignment: Alignment.center,
+                  // decoration: BoxDecoration(
+                  //   color:  ColorUtils.string2Color('#4161D0'),
+                  //   borderRadius: BorderRadius.circular(5),
+                  // ),
+                  child: MyButton(
+                    text: '+Follow',
+                    textColor: Colors.white,
+                    backgroundColor: ColorUtils.string2Color('#4161D0'),
+                    radius: 8,
+                    minHeight: 27.5,
+                    padding: const EdgeInsets.only(left: 5, right: 5,top:9,bottom:9),
+                    fontWeight: FontWeight.w400,
+                    fontSize: 14,
+                    onPressed: (){
+                      // Navigator.pop(context);
+                    },
+                  ),
+                )
+            ),
+          )
         ],
-      )
-    );
+      ),
+    ).constrained(
+      width: double.infinity,
+      // height: 580,
+      // minHeight: 300,
+    ).onTap((){
+      vm.handlerClickActionBtn(null, item);
+    });
   }
 }

+ 39 - 14
packages/cpt_community/lib/modules/community/following/following_state.dart

@@ -1,35 +1,60 @@
+import 'package:widgets/load_state_layout.dart';
+
 class FollowingState {
-  int? activeTabIndex =0;
-  int? curPage =0;
-  int? pageSize =10;
-  int? filterCount =0;
-  List<String>? tabsList = ['News', 'Following', 'For You'];
+  //页面 LoadView 状态的展示
+  LoadState loadingState;
+  String? errorMessage;
+  int? curPage;
+  int? pageSize = 10;
+  int? filterCount = 0;
   List<Map<String, dynamic>>? list = [];
 
   FollowingState({
-    this.activeTabIndex,
-    this.curPage,
-    this.pageSize,
-    this.filterCount,
-    this.tabsList,
+    this.loadingState = LoadState.State_Loading,
+    String? errorMessage,
+    this.curPage = 1,
+    this.pageSize = 10,
+    this.filterCount = 0,
     this.list,
   });
 
   FollowingState copyWith({
-    int? activeTabIndex,
+    LoadState? loadingState,
+    String? errorMessage,
     int? curPage,
     int? pageSize,
     int? filterCount,
-    List<String>? tabsList,
     List<Map<String, dynamic>>? list,
   }) {
     return FollowingState(
-      activeTabIndex: activeTabIndex ?? this.activeTabIndex,
+      loadingState: loadingState ?? this.loadingState,
+      errorMessage: errorMessage ?? this.errorMessage,
       curPage: curPage ?? this.curPage,
       pageSize: pageSize ?? this.pageSize,
       filterCount: filterCount ?? this.filterCount,
-      tabsList: tabsList ?? this.tabsList,
       list: list ?? this.list,
     );
   }
+
+  Map<String, dynamic> toMap() {
+    return {
+      'loadingState': this.loadingState,
+      'errorMessage': this.errorMessage,
+      'curPage': this.curPage,
+      'pageSize': this.pageSize,
+      'filterCount': this.filterCount,
+      'list': this.list,
+    };
+  }
+
+  factory FollowingState.fromMap(Map<String, dynamic> map) {
+    return FollowingState(
+      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>>,
+    );
+  }
 }

+ 191 - 3
packages/cpt_community/lib/modules/community/following/following_vm.dart

@@ -2,14 +2,27 @@ 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 '../community_pageview_idx_data.dart';
+import '../community_vm.dart';
 import 'following_state.dart';
 
 part 'following_vm.g.dart';
 
 @riverpod
 class FollowingVm extends _$FollowingVm {
+  bool _needShowPlaceholder = true; //是否展示LoadingView
+
+  // Refresh 控制器
+  final EasyRefreshController refreshController = EasyRefreshController(
+    controlFinishRefresh: true,  //允许刷新
+    controlFinishLoad: true,   //允许加载
+  );
 
   FollowingState initState() {
     return FollowingState(
@@ -103,8 +116,183 @@ class FollowingVm extends _$FollowingVm {
     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("----following_vm-----initPageData   ${state.loadingState}");
+    onRefresh();
+  }
+
+  // 上拉加载 更多
+  Future loadMore() async {
+    bool isShowing = await ref.read(communityVmProvider.notifier).isCurrentPageViewShowing(CommunityPageViewIdxData.following);
+    if(isShowing){
+      Log.d("----following_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();
+    }else {
+      refreshController.finishRefresh();
+    }
+  }
+
+
+  // 下拉刷新
+  Future onRefresh() async {
+    bool isShowing = await ref.read(communityVmProvider.notifier).isCurrentPageViewShowing(CommunityPageViewIdxData.following);
+    if(isShowing){
+      // 当前pageView 页面正处于显示状态
+      Log.d("----following_vm-----onRefresh ");
+      // await Future.delayed(const Duration(seconds: 2));
+      state = state.copyWith(curPage: 1);
+      getListData();
+    }else {
+      refreshController.finishRefresh();
+      // //更新展示的状态
+      changeLoadingState(LoadState.State_Success, null);
+    }
+  }
+
+  // 重试请求
+  Future retryRequest() async {
+    bool isShowing = await ref.read(communityVmProvider.notifier).isCurrentPageViewShowing(CommunityPageViewIdxData.following);
+    if(isShowing){
+      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,
+        'avator': 'https://img1.baidu.com/it/u=3890726495,1572750319&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500',
+        'title': 'William Jefferson',
+        'isFollow': false,
+        'content': 'She said YES and our lives changed.Thank you all for coming to my propose today.We hope everyone can ……[More]',
+        'imageUrls': ['https://img2.baidu.com/it/u=3489233687,2364672159&fm=253&fmt=auto&app=120&f=JPEG?w=507&h=500','https://img2.baidu.com/it/u=3489233687,2364672159&fm=253&fmt=auto&app=120&f=JPEG?w=507&h=500','https://img2.baidu.com/it/u=3489233687,2364672159&fm=253&fmt=auto&app=120&f=JPEG?w=507&h=500'],
+        'time': 'June 17,2016 at 7:23 p.m.',
+        'isLike': true,
+        'likeno': 12
+      },
+      {
+        'id':2,
+        'avator': 'https://img1.baidu.com/it/u=3890726495,1572750319&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500',
+        'title': 'William fdsaf的飞洒发生的',
+        'isFollow': true,
+        'content': 'She said YES and our lives changed.Thank you all for coming to my propose today.We hope everyone can ……[More]',
+        'imageUrls': [],
+        'time': 'June 17,2016 at 7:23 p.m.',
+        'isLike': true,
+        'likeno': 12
+      },
+      {
+        'id':3,
+        'avator': 'https://img1.baidu.com/it/u=3890726495,1572750319&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500',
+        'title': 'Fsjfkds  dfsk',
+        'isFollow': false,
+        'content': 'She said YES and our lives changed.Thank you all for coming to my propose today.We hope everyone can ……[More]',
+        'imageUrls': [],
+        'time': 'June 17,2016 at 7:23 p.m.',
+        'isLike': false,
+        'likeno': 12
+      },
+    ];
+
+    if (state.curPage == 1) {
+      //刷新的方式
+      state = state.copyWith(list: listData);
+      refreshController.finishRefresh();
+      // //更新展示的状态
+      changeLoadingState(LoadState.State_Success, null);
+    } else {
+      //加载更多
+      final allList = state.list;
+      allList?.addAll(listData);
+      state = state.copyWith(list: allList);
+      refreshController.finishLoad();
+
+    }
+
+    // 最后赋值
+    _needShowPlaceholder = false;
+  }
+
+
+  // 点击 like comments  share
+  void handlerClickActionBtn(String? actionStr, item){
+    final id = item['id'];
+    switch (actionStr) {
+      case 'like':
+        Log.d("点击了 点赞");
+        handlerGotoDetail(id);
+        break;
+      case 'comments':
+        Log.d("点击了 评论");
+        handlerGotoDetail(id);
+        break;
+      case 'share':
+        Log.d("点击了 分享");
+        handlerGotoDetail(id);
+        break;
+      default:
+        Log.d("点击了卡片");
+        handlerGotoDetail(id);
+        break;
+    }
+  }
+  // 去详情页面
+  void handlerGotoDetail(id){
+    Log.d("去详情页面");
+    appRouter.push(NewsfeedDetailPageRoute(id: id, type:'following'));
   }
 }

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

@@ -6,7 +6,7 @@ part of 'following_vm.dart';
 // RiverpodGenerator
 // **************************************************************************
 
-String _$followingVmHash() => r'be7245579d9695ebea090fdbd10ecc91a749954b';
+String _$followingVmHash() => r'836966b8501ded3f2ab058ef269e5fe3f2fd7db4';
 
 /// See also [FollowingVm].
 @ProviderFor(FollowingVm)

+ 142 - 72
packages/cpt_community/lib/modules/community/foryou/foryou_page.dart

@@ -6,6 +6,8 @@ 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';
 import 'package:widgets/my_text_view.dart';
@@ -13,6 +15,9 @@ import 'package:widgets/my_appbar.dart';
 import 'package:cs_resources/theme/app_colors_theme.dart';
 import 'package:widgets/widget_export.dart';
 
+import '../../../components/newfeed_card_header.dart';
+import '../../../components/newsfeed_card_content.dart';
+import '../../../components/newsfeed_card_footer.dart';
 import '../../../router/page/community_page_router.dart';
 import '../community_vm.dart';
 import 'foryou_vm.dart';
@@ -30,52 +35,18 @@ class ForyouPage extends HookConsumerWidget {
     }
   }
 
-  bool _isPreventScroll(ScrollNotification notification, WidgetRef ref){
-    // 检查当前页面是否是可见的
-    bool isDownOrUp = notification.metrics.axis == Axis.vertical;
-    if (notification is UserScrollNotification) {
-      // 检查滚动方向
-      switch (notification.direction) {
-        case ScrollDirection.forward:
-          print('Scrolling down');
-          break;
-        case ScrollDirection.reverse:
-          print('Scrolling up');
-          break;
-        case ScrollDirection.idle:
-          print('Scrolling stopped');
-          break;
-      }
-    } else if (notification is ScrollUpdateNotification) {
-      // 检查滚动位置变化
-      double currentScrollPosition = notification.metrics.pixels;
-      double maxScrollExtent = notification.metrics.maxScrollExtent;
-
-      // 判断是否满足某个条件
-      if (currentScrollPosition > 0 && currentScrollPosition < maxScrollExtent) {
-        print('Current scroll position: $currentScrollPosition');
-        // 在这里添加你的条件判断逻辑
-      }
-
-      // 只有当上下滚动时才拦截通知
-      if (isDownOrUp) {
-        final vm = ref.read(communityVmProvider.notifier);
-        final currentTabRouter = vm.state!.tabsRouter;
-        if(currentTabRouter!.activeIndex == 2){
-          return false;  // false 不拦截
-        }else {
-          Log.d("----news_page 滚动时---拦截了其他的");
-          return true;   // true 拦截
-        }
-      }
-    }
-    return false;
-  }
-
 
   @override
   Widget build(BuildContext context, WidgetRef ref) {
     final vm = ref.read(foryouVmProvider.notifier);
+    final state = ref.watch(foryouVmProvider);
+    useEffect((){
+      // 组件挂载时执行 - 执行接口请求
+      Future.microtask(() => vm.initPageData());
+      return () {
+        // 组件卸载时执行
+      };
+    }, []);
     return Scaffold(
       // appBar: MyAppBar.appBar(
       //   context,
@@ -87,26 +58,33 @@ class ForyouPage extends HookConsumerWidget {
           mainAxisSize: MainAxisSize.max,
           children: [
             Expanded(
-              child: NotificationListener<ScrollNotification>(
-                onNotification: (ScrollNotification notification) {
-                  // 是否拦截滚动  false 表示不拦截通知
-                  return _isPreventScroll(notification, ref);
-                  // return false;
+              child: EasyRefresh(
+                controller: vm.refreshController,
+                key: UniqueKey(),
+                onLoad: () async{
+                  Log.d("----onLoad");
+                  vm.loadMore();
                 },
-                child: EasyRefresh(
-                  key: UniqueKey(),
-                  controller: EasyRefreshController(),
-                  // 上拉加载
-                  onLoad: () async{
-                    Log.d("----onLoad");
-                    vm.onLoadData();
-                  },
-                  // 下拉刷新
-                  onRefresh: () async{
-                    Log.d("----onRefresh");
-                    vm.refreshListData();
+                onRefresh: () async{
+                  Log.d("----onRefresh");
+                  vm.onRefresh();
+                },
+                child: LoadStateLayout(
+                  state: state.loadingState,
+                  errorMessage: state.errorMessage,
+                  errorRetry: () {
+                    vm.retryRequest();
                   },
-                  child: _buildForyouList(context, ref, vm),
+                  successSliverWidget: [
+                    SliverList(
+                      delegate: SliverChildBuilderDelegate(
+                              (context, index){
+                            return _buildNewsItem(context, ref, state.list![index], vm);
+                          },
+                          childCount: state.list!.length
+                      ),
+                    )
+                  ],
                 ),
               ),
             )
@@ -116,18 +94,110 @@ class ForyouPage extends HookConsumerWidget {
   }
 
 
-  Widget _buildForyouList(BuildContext context, WidgetRef ref, ForyouVm vm) {
-
-    return ListView.builder(
-      itemCount: 3,
-      itemBuilder: (context, index) {
-        return _buildListItem(context, ref, vm, index);
-      },
-    );
-  }
-
-  Widget _buildListItem(BuildContext context, WidgetRef ref, ForyouVm vm, int index) {
-    return Text("list-item");
+  Widget _buildNewsItem(BuildContext context, WidgetRef ref, item, vm){
+    return Container(
+      margin: const EdgeInsets.only(left: 15, right: 15,top: 14,bottom: 14),
+      padding: const EdgeInsets.only(left: 15, right: 15,top: 17,bottom: 0),
+      // height: 280,
+      decoration: BoxDecoration(
+          color: context.appColors.textWhite,
+          borderRadius: BorderRadius.circular(10),
+          boxShadow: [
+            BoxShadow(
+              color: ColorUtils.string2Color("#E4E7EB").withOpacity(0.5),
+              spreadRadius: 0,
+              blurRadius: 4,
+              offset: const Offset(0, 4), // changes position of shadow
+            ),
+          ]
+      ),
+      child: Stack(
+        children: [
+          Column(
+              mainAxisAlignment: MainAxisAlignment.center,
+              crossAxisAlignment: CrossAxisAlignment.center,
+              children: [
+                // 卡片头部(头像 标题 时间)
+                Container(
+                  child: NewsFeedCardHeader(
+                    key: UniqueKey(),
+                    title: item['title'],
+                    avator: item['avator'],
+                    time: item['time'],
+                  ),
+                ),
+                const SizedBox(height: 15),
+                // 卡片中间 (文字和图片)
+                NewsFeedCardContent(
+                  key: UniqueKey(),
+                  content: item['content'],
+                  imageUrls: item['imageUrls'],
+                ),
+                const SizedBox(height: 16),
+                // // 卡片底部 (点赞 评论 分享)
+                Container(
+                  decoration: BoxDecoration(
+                    // color: Colors.white,
+                      border: Border(
+                        top: BorderSide(color: ColorUtils.string2Color('#EAEAEA'), width: 0.5),
+                      )
+                  ),
+                  padding: const EdgeInsets.only(top: 10, bottom: 15),
+                  child: NewsFeedCardFooter(
+                    key: UniqueKey(),
+                    isLike: item['isLike'],
+                    onLike: (){
+                      vm.handlerClickActionBtn('like', item);
+                    },
+                    onComment: (){
+                      vm.handlerClickActionBtn('comments', item);
+                    },
+                    onShare: (){
+                      vm.handlerClickActionBtn('share', item);
+                    },
+                  ),
+                ),
+              ]
+          ),
+          // 右上角 关注/取消关注 按钮
+          Visibility(
+            visible: !item['isFollow'],
+            child: Positioned(
+                right: 10,
+                top: -5,
+                child: Container(
+                  width: 83.5,
+                  height: 45.5,
+                  alignment: Alignment.center,
+                  // decoration: BoxDecoration(
+                  //   color:  ColorUtils.string2Color('#4161D0'),
+                  //   borderRadius: BorderRadius.circular(5),
+                  // ),
+                  child: MyButton(
+                    text: '+Follow',
+                    textColor: Colors.white,
+                    backgroundColor: ColorUtils.string2Color('#4161D0'),
+                    radius: 8,
+                    minHeight: 27.5,
+                    padding: const EdgeInsets.only(left: 5, right: 5,top:9,bottom:9),
+                    fontWeight: FontWeight.w400,
+                    fontSize: 14,
+                    onPressed: (){
+                      // Navigator.pop(context);
+                    },
+                  ),
+                )
+            ),
+          )
+        ],
+      ),
+    ).constrained(
+      width: double.infinity,
+      // height: 580,
+      // minHeight: 300,
+    ).onTap((){
+      vm.handlerClickActionBtn(null, item);
+    });
   }
 
 }

+ 22 - 18
packages/cpt_community/lib/modules/community/foryou/foryou_state.dart

@@ -1,56 +1,60 @@
+import 'package:widgets/load_state_layout.dart';
+
 class ForyouState {
-  int? activeTabIndex =0;
-  int? curPage =0;
-  int? pageSize =10;
-  int? filterCount =0;
-  List<String>? tabsList = ['News', 'Following', 'For You'];
+  //页面 LoadView 状态的展示
+  LoadState loadingState;
+  String? errorMessage;
+  int? curPage;
+  int? pageSize = 10;
+  int? filterCount = 0;
+
   List<Map<String, dynamic>>? list = [];
 
   ForyouState({
-    this.activeTabIndex,
-    this.curPage,
-    this.pageSize,
-    this.filterCount,
-    this.tabsList,
+    this.loadingState = LoadState.State_Loading,
+    String? errorMessage,
+    this.curPage = 1,
+    this.pageSize = 10,
+    this.filterCount = 0,
     this.list,
   });
 
   ForyouState copyWith({
-    int? activeTabIndex,
+    LoadState? loadingState,
+    String? errorMessage,
     int? curPage,
     int? pageSize,
     int? filterCount,
-    List<String>? tabsList,
     List<Map<String, dynamic>>? list,
   }) {
     return ForyouState(
-      activeTabIndex: activeTabIndex ?? this.activeTabIndex,
+      loadingState: loadingState ?? this.loadingState,
+      errorMessage: errorMessage ?? this.errorMessage,
       curPage: curPage ?? this.curPage,
       pageSize: pageSize ?? this.pageSize,
       filterCount: filterCount ?? this.filterCount,
-      tabsList: tabsList ?? this.tabsList,
       list: list ?? this.list,
     );
   }
 
   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,
     };
   }
 
   factory ForyouState.fromMap(Map<String, dynamic> map) {
     return ForyouState(
-      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>>,
     );
   }

+ 143 - 45
packages/cpt_community/lib/modules/community/foryou/foryou_vm.dart

@@ -4,8 +4,11 @@ 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 '../community_pageview_idx_data.dart';
 import '../community_vm.dart';
 import '../newsfeed_detail/newsfeed_detail_page.dart';
 import 'foryou_respository.dart';
@@ -16,6 +19,14 @@ part 'foryou_vm.g.dart';
 @riverpod
 class ForyouVm extends _$ForyouVm {
   late ForyouRepository ForyouRepositoryInstance;
+  bool _needShowPlaceholder = true; //是否展示LoadingView
+
+  // Refresh 控制器
+  final EasyRefreshController refreshController = EasyRefreshController(
+    controlFinishRefresh: true,  //允许刷新
+    controlFinishLoad: true,   //允许加载
+  );
+
   ForyouState initState() {
     return ForyouState(
         list: [
@@ -110,59 +121,144 @@ class ForyouVm extends _$ForyouVm {
     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
+    );
   }
 
-// 上拉加载
-  Future onLoadData() async {
-    Log.d("----Foryou_vm-----initListData");
-    // await Future.delayed(const Duration(seconds: 2));
-    // if(state.list.length >= state.filterCount){
-    //   return;
-    // }else {
-    //   int curPage = state.curPage + 1;
-    //   state = state.copyWith(curPage: curPage,);
-    //   getListData();
-    // }
-    // getListData();
+  // 初始化页面数据
+  initPageData() {
+    Log.d("----foryou_vm-----initPageData   ${state.loadingState}");
+    onRefresh();
   }
 
-  // 获取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 ForyouRepositoryInstance.fetchForyouList(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 loadMore() async {
+    bool isShowing = await ref.read(communityVmProvider.notifier).isCurrentPageViewShowing(CommunityPageViewIdxData.forYou);
+    if(isShowing){
+      Log.d("----foryou_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();
+    }else {
+      refreshController.finishRefresh();
     }
   }
 
 
   // 下拉刷新
-  Future refreshListData() async {
-    Log.d("----property_foryou_vm-----refreshListData ");
-    // await Future.delayed(const Duration(seconds: 2));
-    state = state.copyWith(curPage: 1, pageSize: 10);
-    // ref.invalidateSelf();
-    // ref.invalidate(NewsVmProvider);
-    getListData();
+  Future onRefresh() async {
+    bool isShowing = await ref.read(communityVmProvider.notifier).isCurrentPageViewShowing(CommunityPageViewIdxData.forYou);
+    if(isShowing){
+      // 当前pageView 页面正处于显示状态
+      Log.d("----forsale_vm-----onRefresh ");
+      // await Future.delayed(const Duration(seconds: 2));
+      state = state.copyWith(curPage: 1);
+      getListData();
+    }else {
+      refreshController.finishRefresh();
+      // //更新展示的状态
+      changeLoadingState(LoadState.State_Success, null);
+    }
+  }
+
+  // 重试请求
+  Future retryRequest() async {
+    bool isShowing = await ref.read(communityVmProvider.notifier).isCurrentPageViewShowing(CommunityPageViewIdxData.forYou);
+    if(isShowing){
+      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,
+        'avator': 'https://img1.baidu.com/it/u=3890726495,1572750319&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500',
+        'title': 'William Jefferson',
+        'isFollow': false,
+        'content': 'She said YES and our lives changed.Thank you all for coming to my propose today.We hope everyone can ……[More]',
+        'imageUrls': ['https://img2.baidu.com/it/u=3489233687,2364672159&fm=253&fmt=auto&app=120&f=JPEG?w=507&h=500','https://img2.baidu.com/it/u=3489233687,2364672159&fm=253&fmt=auto&app=120&f=JPEG?w=507&h=500','https://img2.baidu.com/it/u=3489233687,2364672159&fm=253&fmt=auto&app=120&f=JPEG?w=507&h=500'],
+        'time': 'June 17,2016 at 7:23 p.m.',
+        'isLike': true,
+        'likeno': 12
+      },
+      {
+        'id':2,
+        'avator': 'https://img1.baidu.com/it/u=3890726495,1572750319&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500',
+        'title': 'William fdsaf的飞洒发生的',
+        'isFollow': true,
+        'content': 'She said YES and our lives changed.Thank you all for coming to my propose today.We hope everyone can ……[More]',
+        'imageUrls': [],
+        'time': 'June 17,2016 at 7:23 p.m.',
+        'isLike': true,
+        'likeno': 12
+      },
+    ];
+
+    if (state.curPage == 1) {
+      //刷新的方式
+      state = state.copyWith(list: listData);
+      refreshController.finishRefresh();
+      // //更新展示的状态
+      changeLoadingState(LoadState.State_Success, null);
+    } else {
+      //加载更多
+      final allList = state.list;
+      allList?.addAll(listData);
+      state = state.copyWith(list: allList);
+      refreshController.finishLoad();
+
+    }
+
+    // 最后赋值
+    _needShowPlaceholder = false;
   }
 
 
@@ -183,12 +279,14 @@ class ForyouVm extends _$ForyouVm {
         handlerGotoDetail(id);
         break;
       default:
+        Log.d("点击了卡片");
+        handlerGotoDetail(id);
         break;
     }
   }
   // 去详情页面
   void handlerGotoDetail(id){
     Log.d("去详情页面");
-    appRouter.push(NewsfeedDetailPageRoute(id: id, type: 'foryou'));
+    appRouter.push(NewsfeedDetailPageRoute(id: id, type:'foryou'));
   }
 }

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

@@ -6,7 +6,7 @@ part of 'foryou_vm.dart';
 // RiverpodGenerator
 // **************************************************************************
 
-String _$foryouVmHash() => r'1a3b527200942273929797367266f303f3f9c6f5';
+String _$foryouVmHash() => r'f240ad571cf30541e4f6b79295d40a08aef7e750';
 
 /// See also [ForyouVm].
 @ProviderFor(ForyouVm)

+ 136 - 167
packages/cpt_community/lib/modules/community/news/news_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';
@@ -35,201 +36,169 @@ class NewsPage extends HookConsumerWidget {
     }
   }
 
-  bool _isPreventScroll(ScrollNotification notification, WidgetRef ref){
-    // 检查当前页面是否是可见的
-    bool isDownOrUp = notification.metrics.axis == Axis.vertical;
-
-
-    if (notification is ScrollUpdateNotification) {
-      // 检查滚动位置变化
-      double currentScrollPosition = notification.metrics.pixels;
-      double maxScrollExtent = notification.metrics.maxScrollExtent;
-
-      // 判断是否满足某个条件
-      if (currentScrollPosition > 0 && currentScrollPosition < maxScrollExtent) {
-        print('Current scroll position: $currentScrollPosition');
-        // 在这里添加你的条件判断逻辑
-      }
-
-      // 只有当上下滚动时才拦截通知
-      if (isDownOrUp) {
-        final vm = ref.read(communityVmProvider.notifier);
-        final currentTabRouter = vm.state!.tabsRouter;
-        if(currentTabRouter!.activeIndex == 0){
-          return false;  // false 不拦截
-        }else {
-          Log.d("----news_page 滚动时---拦截了其他的");
-          return true;   // true 拦截
-        }
-      }else {
-        return false;
-      }
-    }else if (notification is ScrollEndNotification) {
-      // 检查滚动位置变化
-      double currentScrollPosition = notification.metrics.pixels;
-      double maxScrollExtent = notification.metrics.maxScrollExtent;
-
-      // 判断是否满足某个条件
-      if (currentScrollPosition > 0 && currentScrollPosition < maxScrollExtent) {
-        print('Current scroll position: $currentScrollPosition');
-        // 在这里添加你的条件判断逻辑
-      }
-
-      // 只有当上下滚动时才拦截通知
-      if (isDownOrUp) {
-        final vm = ref.read(communityVmProvider.notifier);
-        final currentTabRouter = vm.state!.tabsRouter;
-        if(currentTabRouter!.activeIndex == 0){
-          return false;  // false 不拦截
-        }else {
-          Log.d("----news_page 滚动时---拦截了其他的");
-          return true;   // true 拦截
-        }
-      }else {
-        return true;
-      }
-    }else {
-      return false;
-    }
-    // return false;
-  }
-
 
   @override
   Widget build(BuildContext context, WidgetRef ref) {
     final vm = ref.read(newsVmProvider.notifier);
+    final state = ref.watch(newsVmProvider);
+    useEffect((){
+      // 组件挂载时执行 - 执行接口请求
+      Future.microtask(() => vm.initPageData());
+      return () {
+        // 组件卸载时执行
+      };
+    }, []);
+
     return Scaffold(
       // appBar: MyAppBar.appBar(
       //   context,
       //   "news",
       //   backgroundColor: context.appColors.whiteBG,
       // ),
-      // backgroundColor: ColorUtils.string2Color("#F2F3F6"),
-      body: NotificationListener<ScrollNotification>(
-        onNotification: (ScrollNotification notification) {
-          // 是否拦截滚动  false 表示不拦截通知
-          return _isPreventScroll(notification, ref);
-          // return false;
-        },
-        child: EasyRefresh(
-          controller: EasyRefreshController(),
-          key: UniqueKey(),
-          // 上拉加载
-          onLoad: () async{
-            Log.d("----onLoad");
-            vm.onLoadData();
-          },
-          // 下拉刷新
-          onRefresh: () async{
-            Log.d("----onRefresh");
-            vm.refreshListData();
-          },
-          child: _buildNewsFeedList(context, ref, vm),
-        ),
+      backgroundColor: ColorUtils.string2Color("#F2F3F6"),
+      body: Column(
+        mainAxisSize: MainAxisSize.max,
+        children: [
+          Expanded(
+            child: EasyRefresh(
+              controller: vm.refreshController,
+              key: UniqueKey(),
+              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 _buildNewsItem(context, ref, state.list![index], vm);
+                        },
+                        childCount: state.list!.length
+                    ),
+                  )
+                ],
+              ),
+            ),
+          )
+        ],
       )
     );
   }
 
   Widget _buildNewsItem(BuildContext context, WidgetRef ref, item, vm){
-    return SizedBox(
-      width: double.infinity,
-      //   color: Colors.yellow,
-      child: Stack(
-        children: [
-          Container(
-            margin: const EdgeInsets.only(left: 15, right: 15,top: 14,bottom: 14),
-            color: context.appColors.textWhite,
-            padding: const EdgeInsets.only(left: 15, right: 15,top: 17,bottom: 17),
-            height: 280,
-            child: Column(
+    return Container(
+        margin: const EdgeInsets.only(left: 15, right: 15,top: 14,bottom: 14),
+        padding: const EdgeInsets.only(left: 15, right: 15,top: 17,bottom: 0),
+        // height: 280,
+        decoration: BoxDecoration(
+          color: context.appColors.textWhite,
+          borderRadius: BorderRadius.circular(10),
+          boxShadow: [
+            BoxShadow(
+              color: ColorUtils.string2Color("#E4E7EB").withOpacity(0.5),
+              spreadRadius: 0,
+              blurRadius: 4,
+              offset: const Offset(0, 4), // changes position of shadow
+            ),
+          ]
+        ),
+        child: Stack(
+          children: [
+            Column(
                 mainAxisAlignment: MainAxisAlignment.center,
-                crossAxisAlignment: CrossAxisAlignment.start,
+                crossAxisAlignment: CrossAxisAlignment.center,
                 children: [
                   // 卡片头部(头像 标题 时间)
-                  NewsFeedCardHeader(
-                    key: UniqueKey(),
-                    title: item['title'],
-                    avator: item['avator'],
-                    time: item['time'],
+                  Container(
+                    child: NewsFeedCardHeader(
+                      key: UniqueKey(),
+                      title: item['title'],
+                      avator: item['avator'],
+                      time: item['time'],
+                    ),
                   ),
                   const SizedBox(height: 15),
                   // 卡片中间 (文字和图片)
-                  Expanded(
-                    child: NewsFeedCardContent(
-                      key: UniqueKey(),
-                      content: item['content'],
-                      imageUrls: item['imageUrls'],
-                    ),
+                  NewsFeedCardContent(
+                    key: UniqueKey(),
+                    content: item['content'],
+                    imageUrls: item['imageUrls'],
                   ),
-                  const SizedBox(height: 26),
+                  const SizedBox(height: 16),
                   // // 卡片底部 (点赞 评论 分享)
-                  NewsFeedCardFooter(
-                      key: UniqueKey(),
-                      isLike: item['isLike'],
-                      onLike: (){
-                        vm.handlerClickActionBtn('like', item);
-                      },
-                      onComment: (){
-                        vm.handlerClickActionBtn('comments', item);
-                      },
-                      onShare: (){
-                        vm.handlerClickActionBtn('share', item);
-                      },
+                  Container(
+                    decoration: BoxDecoration(
+                      // color: Colors.white,
+                      border: Border(
+                        top: BorderSide(color: ColorUtils.string2Color('#EAEAEA'), width: 0.5),
+                      )
+                    ),
+                    padding: const EdgeInsets.only(top: 10, bottom: 15),
+                    child: NewsFeedCardFooter(
+                        key: UniqueKey(),
+                        isLike: item['isLike'],
+                        onLike: (){
+                          vm.handlerClickActionBtn('like', item);
+                        },
+                        onComment: (){
+                          vm.handlerClickActionBtn('comments', item);
+                        },
+                        onShare: (){
+                          vm.handlerClickActionBtn('share', item);
+                        },
+                    ),
                   ),
                 ]
             ),
-          ),
-          // 右上角 关注/取消关注 按钮
-          Visibility(
-            visible: !item['isFollow'],
-            child: Positioned(
-              right: 40,
-              top: 35,
-              child: Container(
-                width: 83.5,
-                height: 45.5,
-                alignment: Alignment.center,
-                // decoration: BoxDecoration(
-                //   color:  ColorUtils.string2Color('#4161D0'),
-                //   borderRadius: BorderRadius.circular(5),
-                // ),
-                child: MyButton(
-                  text: '+Follow',
-                  textColor: Colors.white,
-                  backgroundColor: ColorUtils.string2Color('#4161D0'),
-                  radius: 8,
-                  minHeight: 27.5,
-                  padding: const EdgeInsets.only(left: 5, right: 5,top:9,bottom:9),
-                  fontWeight: FontWeight.w400,
-                  fontSize: 14,
-                  onPressed: (){
-                    // Navigator.pop(context);
-                  },
-                ),
-              )
-            ),
-          )
-        ],
-      ),
-    ).onTap((){
+            // 右上角 关注/取消关注 按钮
+            Visibility(
+              visible: !item['isFollow'],
+              child: Positioned(
+                  right: 10,
+                  top: -5,
+                  child: Container(
+                    width: 83.5,
+                    height: 45.5,
+                    alignment: Alignment.center,
+                    // decoration: BoxDecoration(
+                    //   color:  ColorUtils.string2Color('#4161D0'),
+                    //   borderRadius: BorderRadius.circular(5),
+                    // ),
+                    child: MyButton(
+                      text: '+Follow',
+                      textColor: Colors.white,
+                      backgroundColor: ColorUtils.string2Color('#4161D0'),
+                      radius: 8,
+                      minHeight: 27.5,
+                      padding: const EdgeInsets.only(left: 5, right: 5,top:9,bottom:9),
+                      fontWeight: FontWeight.w400,
+                      fontSize: 14,
+                      onPressed: (){
+                        // Navigator.pop(context);
+                      },
+                    ),
+                  )
+              ),
+            )
+          ],
+        ),
+      ).constrained(
+        width: double.infinity,
+        // height: 580,
+        // minHeight: 300,
+      ).onTap((){
       vm.handlerClickActionBtn(null, item);
     });
   }
 
-  Widget _buildNewsFeedList(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 ListView.builder(
-        key: UniqueKey(),
-        itemCount: itemsList.length,
-        itemBuilder: (context, index) {
-          return _buildNewsItem(context, ref, itemsList[index], vm);
-        },
-      );
-    }
-    // return Text("879424");
-  }
 }

+ 23 - 18
packages/cpt_community/lib/modules/community/news/news_state.dart

@@ -1,56 +1,61 @@
+import 'package:widgets/load_state_layout.dart';
+
 class NewsState {
-  int? activeTabIndex =0;
-  int? curPage =0;
-  int? pageSize =10;
-  int? filterCount =0;
-  List<String>? tabsList = ['News', 'Following', 'For You'];
+  //页面 LoadView 状态的展示
+  LoadState loadingState;
+  String? errorMessage;
+  int? curPage;
+  int? pageSize = 10;
+  int? filterCount = 0;
   List<Map<String, dynamic>>? list = [];
 
+
   NewsState({
-    this.activeTabIndex,
-    this.curPage,
-    this.pageSize,
-    this.filterCount,
-    this.tabsList,
+    this.loadingState = LoadState.State_Loading,
+    String? errorMessage,
+    this.curPage = 1,
+    this.pageSize = 10,
+    this.filterCount = 0,
     this.list,
   });
 
   NewsState 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 NewsState(
-      activeTabIndex: activeTabIndex ?? this.activeTabIndex,
+      loadingState: loadingState ?? this.loadingState,
+      errorMessage: errorMessage ?? this.errorMessage,
       curPage: curPage ?? this.curPage,
       pageSize: pageSize ?? this.pageSize,
       filterCount: filterCount ?? this.filterCount,
-      tabsList: tabsList ?? this.tabsList,
       list: list ?? this.list,
     );
   }
 
   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,
     };
   }
 
   factory NewsState.fromMap(Map<String, dynamic> map) {
     return NewsState(
-      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>>,
     );
   }

+ 196 - 123
packages/cpt_community/lib/modules/community/news/news_vm.dart

@@ -4,8 +4,11 @@ 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 '../community_pageview_idx_data.dart';
 import '../community_vm.dart';
 import '../newsfeed_detail/newsfeed_detail_page.dart';
 import 'news_respository.dart';
@@ -16,87 +19,17 @@ part 'news_vm.g.dart';
 @riverpod
 class NewsVm extends _$NewsVm {
   late NewsRepository NewsRepositoryInstance;
+  bool _needShowPlaceholder = true; //是否展示LoadingView
+
+  // Refresh 控制器
+  final EasyRefreshController refreshController = EasyRefreshController(
+    controlFinishRefresh: true,  //允许刷新
+    controlFinishLoad: true,   //允许加载
+  );
+
   NewsState initState() {
     return NewsState(
-      list: [
-          {
-            'id':1,
-            'avator': 'https://img1.baidu.com/it/u=3890726495,1572750319&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500',
-            'title': 'William Jefferson',
-            'isFollow': false,
-            'content': 'She said YES and our lives changed.Thank you all for coming to my propose today.We hope everyone can ……[More]',
-            'imageUrls': ['https://img2.baidu.com/it/u=3489233687,2364672159&fm=253&fmt=auto&app=120&f=JPEG?w=507&h=500','https://img2.baidu.com/it/u=3489233687,2364672159&fm=253&fmt=auto&app=120&f=JPEG?w=507&h=500','https://img2.baidu.com/it/u=3489233687,2364672159&fm=253&fmt=auto&app=120&f=JPEG?w=507&h=500'],
-            'time': 'June 17,2016 at 7:23 p.m.',
-            'isLike': true,
-            'likeno': 12
-          },
-          {
-            'id':2,
-            'avator': 'https://img1.baidu.com/it/u=3890726495,1572750319&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500',
-            'title': 'William fdsaf的飞洒发生的',
-            'isFollow': true,
-            'content': 'She said YES and our lives changed.Thank you all for coming to my propose today.We hope everyone can ……[More]',
-            'imageUrls': [],
-            'time': 'June 17,2016 at 7:23 p.m.',
-            'isLike': true,
-            'likeno': 12
-          },
-          {
-            'id':3,
-            'avator': 'https://img1.baidu.com/it/u=3890726495,1572750319&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500',
-            'title': 'Fsjfkds  dfsk',
-            'isFollow': false,
-            'content': 'She said YES and our lives changed.Thank you all for coming to my propose today.We hope everyone can ……[More]',
-            'imageUrls': [],
-            'time': 'June 17,2016 at 7:23 p.m.',
-            'isLike': false,
-            'likeno': 12
-          },
-          {
-            'id':4,
-            'avator': 'https://img1.baidu.com/it/u=3890726495,1572750319&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500',
-            'title': 'Fsjfkds  dfsk',
-            'isFollow': false,
-            'content': 'She said YES and our lives changed.Thank you all for coming to my propose today.We hope everyone can ……[More]',
-            'imageUrls': [],
-            'time': 'June 17,2016 at 7:23 p.m.',
-            'isLike': false,
-            'likeno': 12
-          },
-          {
-            'id':5,
-            'avator': 'https://img1.baidu.com/it/u=3890726495,1572750319&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500',
-            'title': 'Fsjfkds  dfsk',
-            'isFollow': false,
-            'content': 'She said YES and our lives changed.Thank you all for coming to my propose today.We hope everyone can ……[More]',
-            'imageUrls': [],
-            'time': 'June 17,2016 at 7:23 p.m.',
-            'isLike': false,
-            'likeno': 12
-          },
-          {
-            'id':6,
-            'avator': 'https://img1.baidu.com/it/u=3890726495,1572750319&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500',
-            'title': 'Fsjfkds  dfsk',
-            'isFollow': false,
-            'content': 'She said YES and our lives changed.Thank you all for coming to my propose today.We hope everyone can ……[More]',
-            'imageUrls': [],
-            'time': 'June 17,2016 at 7:23 p.m.',
-            'isLike': false,
-            'likeno': 12
-          },
-          {
-            'id':7,
-            'avator': 'https://img1.baidu.com/it/u=3890726495,1572750319&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500',
-            'title': '放大发大水',
-            'isFollow': false,
-            'content': 'She said YES and our lives changed.Thank you all for coming to my propose today.We hope everyone can ……[More]',
-            'imageUrls': [],
-            'time': 'June 17,2016 at 7:23 p.m.',
-            'isLike': false,
-            'likeno': 12
-          },
-      ]
+      list: []
     );
   }
 
@@ -110,59 +43,199 @@ class NewsVm extends _$NewsVm {
     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
+    );
   }
 
-// 上拉加载
-  Future onLoadData() async {
-    Log.d("----News_vm-----initListData");
-    // await Future.delayed(const Duration(seconds: 2));
-    // if(state.list.length >= state.filterCount){
-    //   return;
-    // }else {
-    //   int curPage = state.curPage + 1;
-    //   state = state.copyWith(curPage: curPage,);
-    //   getListData();
-    // }
-    // getListData();
+  // 初始化页面数据
+  initPageData() {
+    Log.d("----news_vm-----initPageData   ${state.loadingState}");
+    onRefresh();
   }
 
-  // 获取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 NewsRepositoryInstance.fetchNewsList(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 loadMore() async {
+    bool isShowing = await ref.read(communityVmProvider.notifier).isCurrentPageViewShowing(CommunityPageViewIdxData.news);
+    if(isShowing){
+      Log.d("----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();
+    }else {
+      refreshController.finishRefresh();
     }
   }
 
 
   // 下拉刷新
-  Future refreshListData() async {
-    Log.d("----property_news_vm-----refreshListData ");
-    // await Future.delayed(const Duration(seconds: 2));
-    state = state.copyWith(curPage: 1, pageSize: 10);
-    // ref.invalidateSelf();
-    // ref.invalidate(NewsVmProvider);
-    getListData();
+  Future onRefresh() async {
+    bool isShowing = await ref.read(communityVmProvider.notifier).isCurrentPageViewShowing(CommunityPageViewIdxData.news);
+    if(isShowing){
+      // 当前pageView 页面正处于显示状态
+      Log.d("----forsale_vm-----onRefresh ");
+      // await Future.delayed(const Duration(seconds: 2));
+      state = state.copyWith(curPage: 1);
+      getListData();
+    }else {
+      refreshController.finishRefresh();
+      // //更新展示的状态
+      changeLoadingState(LoadState.State_Success, null);
+    }
+  }
+
+  // 重试请求
+  Future retryRequest() async {
+    bool isShowing = await ref.read(communityVmProvider.notifier).isCurrentPageViewShowing(CommunityPageViewIdxData.news);
+    if(isShowing){
+      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,
+        'avator': 'https://img1.baidu.com/it/u=3890726495,1572750319&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500',
+        'title': 'William Jefferson',
+        'isFollow': false,
+        'content': 'She said YES and our lives changed.Thank you all for coming to my propose today.We hope everyone can ……[More]',
+        'imageUrls': ['https://img2.baidu.com/it/u=3489233687,2364672159&fm=253&fmt=auto&app=120&f=JPEG?w=507&h=500','https://img2.baidu.com/it/u=3489233687,2364672159&fm=253&fmt=auto&app=120&f=JPEG?w=507&h=500','https://img2.baidu.com/it/u=3489233687,2364672159&fm=253&fmt=auto&app=120&f=JPEG?w=507&h=500'],
+        'time': 'June 17,2016 at 7:23 p.m.',
+        'isLike': true,
+        'likeno': 12
+      },
+      {
+        'id':2,
+        'avator': 'https://img1.baidu.com/it/u=3890726495,1572750319&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500',
+        'title': 'William fdsaf的飞洒发生的',
+        'isFollow': true,
+        'content': 'She said YES and our lives changed.Thank you all for coming to my propose today.We hope everyone can ……[More]',
+        'imageUrls': [],
+        'time': 'June 17,2016 at 7:23 p.m.',
+        'isLike': true,
+        'likeno': 12
+      },
+      {
+        'id':3,
+        'avator': 'https://img1.baidu.com/it/u=3890726495,1572750319&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500',
+        'title': 'Fsjfkds  dfsk',
+        'isFollow': false,
+        'content': 'She said YES and our lives changed.Thank you all for coming to my propose today.We hope everyone can ……[More]',
+        'imageUrls': [],
+        'time': 'June 17,2016 at 7:23 p.m.',
+        'isLike': false,
+        'likeno': 12
+      },
+      {
+        'id':4,
+        'avator': 'https://img1.baidu.com/it/u=3890726495,1572750319&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500',
+        'title': 'Fsjfkds  dfsk',
+        'isFollow': false,
+        'content': 'She said YES and our lives changed.Thank you all for coming to my propose today.We hope everyone can ……[More]',
+        'imageUrls': [],
+        'time': 'June 17,2016 at 7:23 p.m.',
+        'isLike': false,
+        'likeno': 12
+      },
+      {
+        'id':5,
+        'avator': 'https://img1.baidu.com/it/u=3890726495,1572750319&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500',
+        'title': 'Fsjfkds  dfsk',
+        'isFollow': false,
+        'content': 'She said YES and our lives changed.Thank you all for coming to my propose today.We hope everyone can ……[More]',
+        'imageUrls': [],
+        'time': 'June 17,2016 at 7:23 p.m.',
+        'isLike': false,
+        'likeno': 12
+      },
+      {
+        'id':6,
+        'avator': 'https://img1.baidu.com/it/u=3890726495,1572750319&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500',
+        'title': 'Fsjfkds  dfsk',
+        'isFollow': false,
+        'content': 'She said YES and our lives changed.Thank you all for coming to my propose today.We hope everyone can ……[More]',
+        'imageUrls': [],
+        'time': 'June 17,2016 at 7:23 p.m.',
+        'isLike': false,
+        'likeno': 12
+      },
+      {
+        'id':7,
+        'avator': 'https://img1.baidu.com/it/u=3890726495,1572750319&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500',
+        'title': '放大发大水',
+        'isFollow': false,
+        'content': 'She said YES and our lives changed.Thank you all for coming to my propose today.We hope everyone can ……[More]',
+        'imageUrls': [],
+        'time': 'June 17,2016 at 7:23 p.m.',
+        'isLike': false,
+        'likeno': 12
+      },
+    ];
+
+    if (state.curPage == 1) {
+      //刷新的方式
+      state = state.copyWith(list: listData);
+      refreshController.finishRefresh();
+      // //更新展示的状态
+      changeLoadingState(LoadState.State_Success, null);
+    } else {
+      //加载更多
+      final allList = state.list;
+      allList?.addAll(listData);
+      state = state.copyWith(list: allList);
+      refreshController.finishLoad();
+
+    }
+
+    // 最后赋值
+    _needShowPlaceholder = false;
   }
 
 

+ 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'a4bd8d6b65e0e926c25f6e43a1b1af6f8e3656eb';
+String _$newsVmHash() => r'197df6ca3ce539149cb063cf70eecb32f94ae96a';
 
 /// See also [NewsVm].
 @ProviderFor(NewsVm)

+ 60 - 66
packages/cpt_community/lib/modules/community/newsfeed_detail/newsfeed_detail_page.dart

@@ -109,72 +109,66 @@ class NewsfeedDetailPage extends HookConsumerWidget {
   Widget _buildTopCard(BuildContext context, WidgetRef ref){
     final vm = ref.read(newsfeedDetailVmProvider.notifier);
     final state = ref.watch(newsfeedDetailVmProvider);
-    return Container(
-      width: double.infinity,
-      //   color: Colors.yellow,
-      child: Stack(
-        children: [
-          Container(
-            margin: const EdgeInsets.only(left: 15, right: 15,top: 14,bottom: 14),
-            color: Colors.white,
-            padding: const EdgeInsets.only(left: 15, right: 15,top: 17,bottom: 17),
-            height: 280,
-            child: Column(
-                mainAxisAlignment: MainAxisAlignment.center,
-                crossAxisAlignment: CrossAxisAlignment.start,
-                children: [
-                  // 卡片头部(头像 标题 时间)
-                  NewsFeedCardHeader(
-                    key: UniqueKey(),
-                    title: state?.detailInfo!['title'],
-                    avator: state?.detailInfo['avator'],
-                    time: state?.detailInfo['time'],
-                  ),
-                  const SizedBox(height: 15),
-                  // 卡片中间 (文字和图片)
-                  Expanded(
-                    child: NewsFeedCardContent(
-                      key: UniqueKey(),
-                      content: state.detailInfo['content'],
-                      imageUrls: state.detailInfo['imageUrls'],
-                    ),
-                  ),
-                  const SizedBox(height: 26),
-                ]
-            ),
+    return Stack(
+      children: [
+        Container(
+          margin: const EdgeInsets.only(left: 15, right: 15,top: 14,bottom: 14),
+          color: Colors.white,
+          padding: const EdgeInsets.only(left: 15, right: 15,top: 17,bottom: 17),
+          child: Column(
+              mainAxisAlignment: MainAxisAlignment.center,
+              crossAxisAlignment: CrossAxisAlignment.start,
+              children: [
+                // 卡片头部(头像 标题 时间)
+                NewsFeedCardHeader(
+                  key: UniqueKey(),
+                  title: state?.detailInfo!['title'],
+                  avator: state?.detailInfo['avator'],
+                  time: state?.detailInfo['time'],
+                ),
+                const SizedBox(height: 15),
+                // 卡片中间 (文字和图片)
+                NewsFeedCardContent(
+                  key: UniqueKey(),
+                  content: state.detailInfo['content'],
+                  imageUrls: state.detailInfo['imageUrls'],
+                    textMaxLines: 5000,
+                ),
+                const SizedBox(height: 26),
+              ]
           ),
-          // 右上角 关注/取消关注 按钮
-          Visibility(
-            visible: !state.detailInfo['isFollow'],
-            child: Positioned(
-                right: 40,
-                top: 35,
-                child: Container(
-                  width: 83.5,
-                  height: 45.5,
-                  alignment: Alignment.center,
-                  // decoration: BoxDecoration(
-                  //   color:  ColorUtils.string2Color('#4161D0'),
-                  //   borderRadius: BorderRadius.circular(5),
-                  // ),
-                  child: MyButton(
-                    text: '+Follow',
-                    textColor: Colors.white,
-                    backgroundColor: ColorUtils.string2Color('#4161D0'),
-                    radius: 8,
-                    minHeight: 27.5,
-                    padding: const EdgeInsets.only(left: 5, right: 5,top:9,bottom:9),
-                    fontWeight: FontWeight.w400,
-                    fontSize: 14,
-                    onPressed: (){
-                      // Navigator.pop(context);
-                    },
-                  ),
-                )
-            ),
-          )
-        ],
-      ),
+        ),
+        // 右上角 关注/取消关注 按钮
+        Visibility(
+          visible: !state.detailInfo['isFollow'],
+          child: Positioned(
+              right: 40,
+              top: 35,
+              child: Container(
+                width: 83.5,
+                height: 45.5,
+                alignment: Alignment.center,
+                // decoration: BoxDecoration(
+                //   color:  ColorUtils.string2Color('#4161D0'),
+                //   borderRadius: BorderRadius.circular(5),
+                // ),
+                child: MyButton(
+                  text: '+Follow',
+                  textColor: Colors.white,
+                  backgroundColor: ColorUtils.string2Color('#4161D0'),
+                  radius: 8,
+                  minHeight: 27.5,
+                  padding: const EdgeInsets.only(left: 5, right: 5,top:9,bottom:9),
+                  fontWeight: FontWeight.w400,
+                  fontSize: 14,
+                  onPressed: (){
+                    // Navigator.pop(context);
+                  },
+                ),
+              )
+          ),
+        )
+      ],
     );
   }
 
@@ -310,7 +304,7 @@ class NewsfeedDetailPage extends HookConsumerWidget {
                     isFontLight: true,
                     fontSize: 15,
                     marginTop: 10,
-                    textColor: ColorUtils.string2Color('#000000'),
+                    textColor: context.appColors.textBlack,
                     maxLines: null,
                     isTextEllipsis: false,
                   ),

+ 7 - 13
packages/cpt_community/lib/modules/community/newsfeed_detail/newsfeed_detail_vm.dart

@@ -48,23 +48,17 @@ class NewsfeedDetailVm extends _$NewsfeedDetailVm {
         'avator': 'https://p4.itc.cn/q_70/images03/20231121/ab826c4a7efe4c9aa93ca6e00f9e0986.jpeg',
         'title': 'William Jefferson',
         'content': 'She said YES and our lives changed.Thank you all for coming to my propose today.We hope everyone can ……[More]',
-        'imageUrls': ['https://img2.baidu.com/it/u=3489233687,2364672159&fm=253&fmt=auto&app=120&f=JPEG?w=507&h=500','https://img2.baidu.com/it/u=3489233687,2364672159&fm=253&fmt=auto&app=120&f=JPEG?w=507&h=500','https://img2.baidu.com/it/u=3489233687,2364672159&fm=253&fmt=auto&app=120&f=JPEG?w=507&h=500'],
+        'imageUrls': [
+          'https://img2.baidu.com/it/u=3489233687,2364672159&fm=253&fmt=auto&app=120&f=JPEG?w=507&h=500',
+          'https://img2.baidu.com/it/u=3489233687,2364672159&fm=253&fmt=auto&app=120&f=JPEG?w=507&h=500',
+          'https://img2.baidu.com/it/u=3489233687,2364672159&fm=253&fmt=auto&app=120&f=JPEG?w=507&h=500',
+          'https://img2.baidu.com/it/u=3489233687,2364672159&fm=253&fmt=auto&app=120&f=JPEG?w=507&h=500',
+          'https://img2.baidu.com/it/u=3489233687,2364672159&fm=253&fmt=auto&app=120&f=JPEG?w=507&h=500',
+        ],
         'time': 'June 17,2016 at 7:23 p.m.',
         'isLike': true,
         'isFollow': false,
         'likeno': 12,
-        'commentsInfo': {
-          'total': 12,
-          'list': [
-            {
-                'userId': 1,
-                'userName': 'William Jefferson',
-                'avator': 'https://iknow-pic.cdn.bcebos.com/d439b6003af33a87f27f0584d45c10385343b519',
-                '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]'
-            },
-          ]
-        }
       },
       list: [
         {

+ 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'217e81164b741aa69edebff0a8d3eee845dbbd0a';
+String _$newsfeedDetailVmHash() => r'2a36483461d9e5ca76e5f65ac524f0a972325735';
 
 /// See also [NewsfeedDetailVm].
 @ProviderFor(NewsfeedDetailVm)

+ 69 - 14
packages/cpt_community/lib/modules/community/newsfeed_tabs.dart

@@ -11,14 +11,14 @@ import 'package:widgets/ext/ex_widget.dart';
 import 'package:widgets/my_text_view.dart';
 import 'package:widgets/my_appbar.dart';
 
+import 'community_page.dart';
 import 'community_vm.dart';
-import '../garage/garage_vm.dart';
 
 class NewsfeedTabs extends HookConsumerWidget {
-  List tabsList;
+  List<String> tabsList;
   Widget? Function(BuildContext)? tabItemBuilder;
   dynamic? tabsRouter;
-  void Function(int)? onClickAction;
+  void Function(Map<String, dynamic>)? onClickAction;
   NewsfeedTabs({
     Key? key,
     required this.tabsList,
@@ -28,20 +28,74 @@ class NewsfeedTabs extends HookConsumerWidget {
   }) : super(key: key);
 
   Widget _buildTabItem(BuildContext context, WidgetRef ref, vm, item, index) {
-    // Log.d("NewsfeedTabs _buildTabItem index: ${vm.state.tabsList}");
-    // Log.d("NewsfeedTabs _buildTabItem index: ${vm.state.activeTabIdx}");
+    final providerCommunityState = ref.watch(communityVmProvider);
+    int lastNewsFeedTabIdx = 0;
+    int lastGarageTabIdx = 0;
+    final newsfeedTabCount = ref.read(communityVmProvider.notifier).state!.newsFeedTabsList!.length;
     // 监听 activeTabIdx 的变化
-    // final activeTabIdx = ref.watch(communityVmProvider.select((state) => state.activeTabIdx));
+    final activePageIdx = ref.watch(communityVmProvider.select((state) => state.currentPageViewIdx));
+    int currentCatgoryIdx = activePageIdx >= newsfeedTabCount? 1: 0;
 
-    final activeTabIdx = tabsRouter!.activeIndex;
 
-    // Log.d("NewsfeedTabs _buildTabItem activeTabIdx: $activeTabIdx");
+    int curTabIdx = 0;
+    // final activeTabIdx = tabsRouter!.activeIndex;
+    // final activeTabIdx = tabsRouterKey.currentState?.controller?.activeIndex ?? 0;
+
+    // 监听 currentPageViewIdx 的变化
+    ref.listen(communityVmProvider.select((state) => state.currentPageViewIdx), (oldValue, newValue){
+      // Log.d("--111--oldValue: $oldValue, newValue: $newValue---------------");
+      // Log.d("--111--lastNewsFeedTabIdx: $lastNewsFeedTabIdx, lastGarageTabIdx: $lastGarageTabIdx---------------");
+
+
+      if(oldValue! < newsfeedTabCount){
+        if( newValue >= newsfeedTabCount ){
+          // 由 newsfeed 切换到 garage sale  记录newsFeed 最后的 tabidx
+          lastNewsFeedTabIdx = oldValue;
+          lastGarageTabIdx = newValue - newsfeedTabCount;
+          currentCatgoryIdx = 1;
+          Log.d("-从newsfeed 切换到 garagesale-----------currentCatgoryIdx  $currentCatgoryIdx-------lastNewsFeedTabIdx: $lastNewsFeedTabIdx, lastGarageTabIdx: $lastGarageTabIdx---------------");
+        }else {
+          lastNewsFeedTabIdx = newValue;
+          lastGarageTabIdx = providerCommunityState.lastGarageTabIdx;
+        }
+      }
+
+      if(oldValue! >= newsfeedTabCount){
+        if(newValue < newsfeedTabCount){
+          // 由 garage sale 切换到 newsfeed  记录garage sale 最后的 tabidx
+          lastGarageTabIdx = oldValue - newsfeedTabCount;
+          lastNewsFeedTabIdx = newValue;
+          currentCatgoryIdx = 0;
+          Log.d("-从garagesale  切换到 newsfeed---------------currentCatgoryIdx  $currentCatgoryIdx------lastNewsFeedTabIdx: $lastNewsFeedTabIdx, lastGarageTabIdx: $lastGarageTabIdx---------------");
+
+        }else {
+          lastGarageTabIdx = newValue - newsfeedTabCount;
+          lastNewsFeedTabIdx = providerCommunityState.lastNewsfeedTabIdx;
+        }
+      }
+
+      // Log.d("-666---currentCatgoryIdx----$currentCatgoryIdx-----lastNewsFeedTabIdx: $lastNewsFeedTabIdx, lastGarageTabIdx: $lastGarageTabIdx---------------");
+      ref.read(communityVmProvider.notifier).setCurrentCategoryIdx(
+        context,
+        currentCatgoryIdx,
+        lastNewsFeedTabIdx,
+        lastGarageTabIdx,
+      );
+    });
+
+    if(activePageIdx >= newsfeedTabCount){
+      // garage sale
+      curTabIdx = activePageIdx - newsfeedTabCount;
+    }else {
+      // news feed
+      curTabIdx = activePageIdx;
+    }
     return Container(
-      width: MediaQuery.of(context).size.width / vm.state.tabsList.length - 30,
+      width: MediaQuery.of(context).size.width / tabsList.length - 30,
       height: 43,
       padding: const EdgeInsets.only(top: 10, bottom: 10, left: 10, right: 10),
-      decoration: index==activeTabIdx? BoxDecoration(
-        color: index==activeTabIdx? context.appColors.btnBgDefault: ColorUtils.string2Color("#F2F3F6"),
+      decoration: index==curTabIdx? BoxDecoration(
+        color: index==curTabIdx? context.appColors.btnBgDefault: ColorUtils.string2Color("#F2F3F6"),
         borderRadius: BorderRadius.circular(20),
         boxShadow: [
           BoxShadow(
@@ -62,11 +116,11 @@ class NewsfeedTabs extends HookConsumerWidget {
                 fontSize: 16,
                 textAlign: TextAlign.center,
                 isFontMedium: true,
-                textColor: index == activeTabIdx ? Colors.white :ColorUtils.string2Color("#000000"),
+                textColor: index == curTabIdx ? Colors.white :ColorUtils.string2Color("#000000"),
               ),
             ).onTap((){
-              print("newsfeed_tabs 中点击的tab index:  $index");
-              onClickAction?.call(index);
+              // Log.d("----currentCatgoryIdx----$currentCatgoryIdx-------");
+              onClickAction?.call({'currentCatgoryIdx':currentCatgoryIdx, 'tabIdx': index});
             }),
           ),
         ],
@@ -108,6 +162,7 @@ class NewsfeedTabs extends HookConsumerWidget {
       child: Row(
         mainAxisSize: MainAxisSize.max,
         mainAxisAlignment: MainAxisAlignment.center,
+        crossAxisAlignment: CrossAxisAlignment.center,
         children: _buildTabs(context, ref, vm),
       ).constrained(
           maxWidth:  MediaQuery.of(context).size.width

+ 52 - 44
packages/cpt_community/lib/modules/garage/for_rent/for_rent_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,15 @@ class ForrentPage extends HookConsumerWidget {
   @override
   Widget build(BuildContext context, WidgetRef ref) {
     final vm = ref.read(forrentVmProvider.notifier);
+    final state = ref.watch(forrentVmProvider);
+    useEffect(() {
+      // 组件挂载时执行 - 执行接口请求
+      Future.microtask(() => vm.initPageData());
+      return () {
+        // 组件卸载时执行
+        Log.d("garage_forsale_page 组件卸载时执行");
+      };
+    }, []);
     return Scaffold(
       // appBar: MyAppBar.appBar(
       //   context,
@@ -43,33 +53,53 @@ class ForrentPage 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: _buildForrentFeedList(context, ref, vm),
+      body: SizedBox(
+          width: double.infinity,
+          height: double.infinity,
+          child: EasyRefresh(
+            controller: vm.refreshController,
+            // 上拉加载
+            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  _buildForrentItem(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 _buildForrentItem(BuildContext context, WidgetRef ref, item, vm){
-    return Container(
+    return SizedBox(
       width: double.infinity,
       child: Container(
         decoration: BoxDecoration(
@@ -104,26 +134,4 @@ class ForrentPage extends HookConsumerWidget {
       ),
     );
   }
-
-  Widget _buildForrentFeedList(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 _buildForrentItem(context, ref, itemsList[index], vm);
-        },
-      );
-    }
-  }
 }

+ 25 - 14
packages/cpt_community/lib/modules/garage/for_rent/for_rent_state.dart

@@ -1,34 +1,43 @@
+import 'package:widgets/load_state_layout.dart';
+
 class ForrentState {
   int? activeTabIndex =0;
-  int? curPage =0;
-  int? pageSize =10;
-  int? filterCount =0;
-  List<String>? tabsList = ['For Sale', 'For Rent'];
-  List<Map<String, dynamic>>? list = [];
+  //页面 LoadView 状态的展示
+  LoadState loadingState;
+  String? errorMessage;
+
+  int? curPage;
+  int? pageSize = 10;
+  int? filterCount = 0;
+  List<Map<String, dynamic>> list;
+
 
   ForrentState({
     this.activeTabIndex,
-    this.curPage,
-    this.pageSize,
-    this.filterCount,
-    this.tabsList,
-    this.list,
+    this.loadingState = LoadState.State_Loading,
+    String? errorMessage,
+    this.curPage = 1,
+    this.pageSize = 10,
+    this.filterCount = 0,
+    required this.list,
   });
 
   ForrentState copyWith({
     int? activeTabIndex,
+    LoadState? loadingState,
+    String? errorMessage,
     int? curPage,
     int? pageSize,
     int? filterCount,
-    List<String>? tabsList,
     List<Map<String, dynamic>>? list,
   }) {
     return ForrentState(
       activeTabIndex: activeTabIndex ?? this.activeTabIndex,
+      loadingState: loadingState ?? this.loadingState,
+      errorMessage: errorMessage ?? this.errorMessage,
       curPage: curPage ?? this.curPage,
       pageSize: pageSize ?? this.pageSize,
       filterCount: filterCount ?? this.filterCount,
-      tabsList: tabsList ?? this.tabsList,
       list: list ?? this.list,
     );
   }
@@ -36,10 +45,11 @@ class ForrentState {
   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,
     };
   }
@@ -47,10 +57,11 @@ class ForrentState {
   factory ForrentState.fromMap(Map<String, dynamic> map) {
     return ForrentState(
       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>>,
     );
   }

+ 150 - 61
packages/cpt_community/lib/modules/garage/for_rent/for_rent_vm.dart

@@ -4,8 +4,12 @@ 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 '../../community/community_pageview_idx_data.dart';
+import '../../community/community_vm.dart';
 import '../garagesale_detail/garagesale_detail_page.dart';
 import 'for_rent_respository.dart';
 import 'for_rent_state.dart';
@@ -15,6 +19,14 @@ part 'for_rent_vm.g.dart';
 @riverpod
 class ForrentVm extends _$ForrentVm {
   late ForrentRepository ForrentRepositoryInstance;
+  bool _needShowPlaceholder = true; //是否展示LoadingView
+
+  // Refresh 控制器
+  final EasyRefreshController refreshController = EasyRefreshController(
+    controlFinishRefresh: true,  //允许刷新
+    controlFinishLoad: true,   //允许加载
+  );
+
   ForrentState initState() {
     return ForrentState(
         list: [
@@ -65,83 +77,160 @@ class ForrentVm extends _$ForrentVm {
     return state;
   }
 
-// 上拉加载
-  Future onLoadData() async {
-    Log.d("----Forrent_vm-----initListData");
-    // await Future.delayed(const Duration(seconds: 2));
-    // if(state.list.length >= state.filterCount){
-    //   return;
-    // }else {
-    //   int curPage = state.curPage + 1;
-    //   state = state.copyWith(curPage: curPage,);
-    //   getListData();
-    // }
-    // getListData();
+  //刷新页面状态
+  void changeLoadingState(LoadState loadState, String? errorMsg) {
+    state = state.copyWith(
+        loadingState: loadState,
+        errorMessage: errorMsg
+    );
   }
 
-  // 获取list 列表数据
-  void getListData<T>() async {
-    Log.d(" for_rent 加载listData数据---------------start-----");
-    try {
-      //请求网络
-      Map<String, dynamic>  params = {
-        "curPage": state.curPage,
-        "pageSize": state.pageSize,
-      };
-      Log.d("请求参数------$params");
-      final result = await ForrentRepositoryInstance.fetchForrentList(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");
+  // 初始化页面数据
+  initPageData() {
+    Log.d("----for_rent_vm-----initPageData   ${state.loadingState}");
+    onRefresh();
+  }
+
+  // 上拉加载 更多
+  Future loadMore() async {
+    bool isShowing = await ref.read(communityVmProvider.notifier).isCurrentPageViewShowing(CommunityPageViewIdxData.forRent);
+    if(isShowing){
+      Log.d("----for_rent_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();
+    }else {
+      refreshController.finishRefresh();
     }
   }
 
 
   // 下拉刷新
-  Future refreshListData() async {
-    Log.d("----for_rent_vm-----refreshListData ");
+  Future onRefresh() async {
+    bool isShowing = await ref.read(communityVmProvider.notifier).isCurrentPageViewShowing(CommunityPageViewIdxData.forRent);
+    if(isShowing){
+      // 当前pageView 页面正处于显示状态
+      Log.d("----for_rent_vm-----onRefresh ");
+      // await Future.delayed(const Duration(seconds: 2));
+      state = state.copyWith(curPage: 1);
+      getListData();
+    }else {
+      refreshController.finishRefresh();
+      // //更新展示的状态
+      changeLoadingState(LoadState.State_Success, null);
+    }
+  }
 
-    // await Future.delayed(const Duration(seconds: 2));
+  // 重试请求
+  Future retryRequest() async {
+    bool isShowing = await ref.read(communityVmProvider.notifier).isCurrentPageViewShowing(CommunityPageViewIdxData.forRent);
+    if(isShowing){
+      state = state.copyWith(curPage: 1);
+      _needShowPlaceholder = true;
+      getListData();
+    }
+  }
 
-    state = state.copyWith(curPage: 1, pageSize: 10);
-    // ref.invalidateSelf();
-    // ref.invalidate(ForrentVmProvider);
-    getListData();
 
-  }
+  // 获取list 列表数据
+  Future getListData<T>() async {
+    if (_needShowPlaceholder) {
+      changeLoadingState(LoadState.State_Loading, null);
+    }
 
+    Log.d("for_rent加载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://img2.baidu.com/it/u=3489233687,2364672159&fm=253&fmt=auto&app=120&f=JPEG?w=507&h=500',
+        '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': 'https://img1.baidu.com/it/u=3890726495,1572750319&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500'
+      },
+      {
+        'id':2,
+        'goods_img':  'https://img2.baidu.com/it/u=3489233687,2364672159&fm=253&fmt=auto&app=120&f=JPEG?w=507&h=500',
+        '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': 'https://img1.baidu.com/it/u=3890726495,1572750319&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500'
+      },
+      {
+        'id':3,
+        'goods_img':  'https://img2.baidu.com/it/u=3489233687,2364672159&fm=253&fmt=auto&app=120&f=JPEG?w=507&h=500',
+        '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': 'https://img1.baidu.com/it/u=3890726495,1572750319&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500'
+      },
+    ];
+
+    if (state.curPage == 1) {
+      //刷新的方式
+      state = state.copyWith(list: listData);
+      refreshController.finishRefresh();
+      // //更新展示的状态
+      changeLoadingState(LoadState.State_Success, null);
+    } else {
+      //加载更多
+      final allList = state.list;
+      allList?.addAll(listData);
+      state = state.copyWith(list: allList);
+      refreshController.finishLoad();
 
-  // 点击 like comments  share
-  void handlerClickActionBtn(String? actionStr, item){
-    final id = item['id'];
-    switch (actionStr) {
-      case 'like':
-        Log.d("点击了 点赞");
-        handlerGotoDetail(id);
-        break;
-      case 'comments':
-        Log.d("点击了 评论");
-        handlerGotoDetail(id);
-        break;
-      case 'share':
-        Log.d("点击了 分享");
-        handlerGotoDetail(id);
-        break;
-      default:
-        break;
     }
+
+    // 最后赋值
+    _needShowPlaceholder = false;
   }
+
   // 去详情页面
   void handlerGotoDetail(id){
     Log.d("去详情页面");
-    appRouter.push(GaragesaleDetailPageRoute(id: id, type: 'forrent'));
+    appRouter.push(GaragesaleDetailPageRoute(id: id, type: 'forRent'));
   }
 }

+ 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'af5558e48830e98846c341d151673ca5a92bb416';
+String _$forrentVmHash() => r'ead572c32c80262c0e4220328d537689f466acb8';
 
 /// See also [ForrentVm].
 @ProviderFor(ForrentVm)

+ 0 - 5
packages/cpt_community/lib/modules/garage/for_sale/for_sale_state.dart

@@ -11,7 +11,6 @@ class ForsaleState {
   int? filterCount = 0;
   List<Map<String, dynamic>> list;
 
-  List<String>? tabsList = ['For Sale', 'For Rent'];
 
   ForsaleState({
     this.activeTabIndex,
@@ -21,7 +20,6 @@ class ForsaleState {
     this.pageSize = 10,
     this.filterCount = 0,
     required this.list,
-    this.tabsList,
   });
 
   ForsaleState copyWith({
@@ -41,7 +39,6 @@ class ForsaleState {
       curPage: curPage ?? this.curPage,
       pageSize: pageSize ?? this.pageSize,
       filterCount: filterCount ?? this.filterCount,
-      tabsList: tabsList ?? this.tabsList,
       list: list ?? this.list,
     );
   }
@@ -55,7 +52,6 @@ class ForsaleState {
       'pageSize': this.pageSize,
       'filterCount': this.filterCount,
       'list': this.list,
-      'tabsList': this.tabsList,
     };
   }
 
@@ -68,7 +64,6 @@ class ForsaleState {
       pageSize: map['pageSize'] as int,
       filterCount: map['filterCount'] as int,
       list: map['list'] as List<Map<String, dynamic>>,
-      tabsList: map['tabsList'] as List<String>,
     );
   }
 }

+ 42 - 23
packages/cpt_community/lib/modules/garage/for_sale/for_sale_vm.dart

@@ -1,3 +1,4 @@
+import 'package:cpt_community/modules/community/community_vm.dart';
 import 'package:cs_resources/generated/assets.dart';
 import 'package:flutter/cupertino.dart';
 import 'package:plugin_platform/engine/toast/toast_engine.dart';
@@ -8,6 +9,8 @@ import 'package:widgets/load_state_layout.dart';
 import 'package:widgets/widget_export.dart';
 
 import '../../../router/page/community_page_router.dart';
+import '../../community/community_page.dart';
+import '../../community/community_pageview_idx_data.dart';
 import '../garagesale_detail/garagesale_detail_page.dart';
 import 'for_sale_respository.dart';
 import 'for_sale_state.dart';
@@ -19,6 +22,7 @@ class ForsaleVm extends _$ForsaleVm {
   late ForsaleRepository ForsaleRepositoryInstance;
   bool _needShowPlaceholder = true; //是否展示LoadingView
 
+
   // Refresh 控制器
   final EasyRefreshController refreshController = EasyRefreshController(
     controlFinishRefresh: true,  //允许刷新
@@ -58,36 +62,51 @@ class ForsaleVm extends _$ForsaleVm {
 
   // 上拉加载 更多
   Future loadMore() async {
-    Log.d("----for_sale_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();
+    bool isShowing = await ref.read(communityVmProvider.notifier).isCurrentPageViewShowing(CommunityPageViewIdxData.forSale);
+    if(isShowing){
+      Log.d("----for_sale_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();
+    }else {
+      refreshController.finishRefresh();
+    }
   }
 
 
   // 下拉刷新
   Future onRefresh() async {
-    Log.d("----forsale_vm-----onRefresh ");
-
-    // await Future.delayed(const Duration(seconds: 2));
-    state = state.copyWith(curPage: 1);
-    getListData();
+    bool isShowing = await ref.read(communityVmProvider.notifier).isCurrentPageViewShowing(CommunityPageViewIdxData.forSale);
+    if(isShowing){
+      // 当前pageView 页面正处于显示状态
+      Log.d("----forsale_vm-----onRefresh ");
+      // await Future.delayed(const Duration(seconds: 2));
+      state = state.copyWith(curPage: 1);
+      getListData();
+    }else {
+      refreshController.finishRefresh();
+      // //更新展示的状态
+      changeLoadingState(LoadState.State_Success, null);
+    }
   }
 
   // 重试请求
   Future retryRequest() async {
-    state = state.copyWith(curPage: 1);
-    _needShowPlaceholder = true;
-    getListData();
+    bool isShowing = await ref.read(communityVmProvider.notifier).isCurrentPageViewShowing(CommunityPageViewIdxData.forSale);
+    if(isShowing){
+      state = state.copyWith(curPage: 1);
+      _needShowPlaceholder = true;
+      getListData();
+    }
   }
 
 
@@ -97,7 +116,7 @@ class ForsaleVm extends _$ForsaleVm {
       changeLoadingState(LoadState.State_Loading, null);
     }
 
-    Log.d("for_sale加载listData数据---------------start--${state.curPage}---");
+    Log.d("for_sale_vm加载listData数据---------------start--${state.curPage}---");
     //   try {
     //     //请求网络
     //     Map<String, dynamic>  params = {
@@ -235,6 +254,6 @@ class ForsaleVm extends _$ForsaleVm {
   // 去详情页面
   void handlerGotoDetail(id){
     Log.d("去详情页面");
-    appRouter.push(GaragesaleDetailPageRoute(id: id, type: 'forsale'));
+    appRouter.push(GaragesaleDetailPageRoute(id: id, type: 'forSale'));
   }
 }

+ 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'9a70198331dbbe38ddaef55b495dd4e2defbc885';
+String _$forsaleVmHash() => r'8c0f414fe06c15283d9147864e04d1532064fe2b';
 
 /// See also [ForsaleVm].
 @ProviderFor(ForsaleVm)

+ 0 - 273
packages/cpt_community/lib/modules/garage/garage_page.dart

@@ -1,273 +0,0 @@
-
-import 'package:cpt_community/components/newsfeed_card_content.dart';
-import 'package:cpt_community/components/newsfeed_card_footer.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/rendering.dart';
-import 'package:hooks_riverpod/hooks_riverpod.dart';
-import 'package:router/ext/auto_router_extensions.dart';
-import 'package:shared/utils/color_utils.dart';
-import 'package:shared/utils/log_utils.dart';
-import 'package:widgets/ext/ex_widget.dart';
-import 'package:widgets/my_appbar.dart';
-import 'package:widgets/my_load_image.dart';
-import 'package:widgets/my_text_view.dart';
-import 'package:widgets/widget_export.dart';
-
-import '../../components/newfeed_card_header.dart';
-import '../../router/page/community_page_router.dart';
-import '../garage/garage_vm.dart';
-
-import 'garage_tabs.dart';
-
-import 'garage_vm.dart';
-
-
-@RoutePage()
-class GaragePage extends HookConsumerWidget {
-  const GaragePage({Key? key}) : super(key: key);
-
-  //启动当前页面
-  static void startInstance({BuildContext? context}) {
-    if (context != null) {
-      context.router.push(const GaragePageRoute());
-    } else {
-      appRouter.push(const GaragePageRoute());
-    }
-  }
-
-  Widget _buildTabsSection(BuildContext context, WidgetRef ref, tabsRouter){
-    final vm = ref.read(garageVmProvider.notifier);
-    return Container(
-      width: double.infinity,
-      padding: const EdgeInsets.only(left: 15, right: 15,top: 14,bottom: 14),
-      child: GarageTabs(
-        key: UniqueKey(),
-        tabsList: vm.state.tabsList,
-        tabsRouter: tabsRouter,
-        onClickAction:(activeTabIdx){
-          vm.handlerChangeTab(activeTabIdx, tabsRouter);
-        }
-      ),
-    );
-  }
-
-  Widget _buildPostSection(BuildContext context, WidgetRef ref, vm){
-    return Container(
-      height: 65.5,
-      width: double.infinity,
-      padding: const EdgeInsets.only(left: 20, right: 20),
-      color: Colors.white,
-      child: Row(
-        children: [
-          const MyAssetImage(Assets.communityNesFeed, width: 45,height: 45,),
-          Expanded(
-            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);
-      }),
-    );
-  }
-
-  Widget _buildNewsItem(BuildContext context, WidgetRef ref, item, vm){
-    return Container(
-        width: double.infinity,
-        // padding: const EdgeInsets.only(left: 15, right: 15,top: 14,bottom: 14),
-        color: Colors.yellow,
-        child: Container(
-          margin: const EdgeInsets.only(left: 15, right: 15,top: 14,bottom: 14),
-          color: Colors.white,
-          padding: const EdgeInsets.only(left: 15, right: 15,top: 17,bottom: 17),
-          height: 280,
-          child: Column(
-              mainAxisAlignment: MainAxisAlignment.center,
-              crossAxisAlignment: CrossAxisAlignment.start,
-              children: [
-                // 卡片头部(头像 标题 时间)
-                NewsFeedCardHeader(
-                  key: UniqueKey(),
-                  title: item['title'],
-                  avator: item['avator'],
-                  time: item['time'],
-                ),
-                const SizedBox(height: 15),
-                // 卡片中间 (文字和图片)
-                Expanded(
-                  child: NewsFeedCardContent(
-                    key: UniqueKey(),
-                    content: item['content'],
-                    imageUrls: item['imageUrls'],
-                  ),
-                ),
-                const SizedBox(height: 26),
-                // // 卡片底部 (点赞 评论 分享)
-                NewsFeedCardFooter(
-                  key: UniqueKey(),
-                  isLike: item['isLike'],
-                ),
-              ]
-          ),
-        )
-    );
-  }
-  
-
-  @override
-  Widget build(BuildContext context, WidgetRef ref) {
-    final vm = ref.read(garageVmProvider.notifier);
-
-    return Scaffold(
-      appBar: MyAppBar.searchAppBar(
-        context,
-        backgroundColor: context.appColors.backgroundWhite,
-        actions: [
-          IconButton(
-            icon: const Icon(Icons.search),
-            onPressed: () {
-              // do something
-              vm.handlerChooseCategory(context);
-            },
-          ),
-        ],
-      ),
-      backgroundColor: ColorUtils.string2Color("#F2F3F6"),
-      body: NestedScrollView(
-        headerSliverBuilder: (context, innerBoxIsScrolled) {
-          return [
-            SliverToBoxAdapter(
-              child: Consumer(
-                builder: (context, ref, _) {
-                  return _buildTopSection(context, ref, vm);
-                },
-              ),
-            ),
-          ];
-        },
-        body: NotificationListener<ScrollNotification>(
-          onNotification: (ScrollNotification notification) {
-            // 是否拦截滚动  false 表示不拦截通知
-            // return _isPreventScroll(notification, ref);
-            return false;
-          },
-          child: AutoTabsRouter.pageView(
-            key: UniqueKey(),
-            routes: const [
-              ForsalePageRoute(),
-              ForrentPageRoute(),
-            ],
-            builder: (context, child, animation) {
-              final tabsRouter = AutoTabsRouter.of(context);
-              return Column(
-                mainAxisSize: MainAxisSize.max,
-                children: [
-                  //  garagesale tab 分类 (For sale  For Rent)
-                  _buildTabsSection(context, ref, tabsRouter),
-                  // 发布 garage sale 组件
-                  _buildPostSection(context, ref, vm),
-                  Expanded(
-                    child: child,
-                  )
-                ],
-              );
-            },
-          ),
-        ),
-      ),
-      // body: AutoTabsRouter.pageView(
-      //     key: UniqueKey(),
-      //     routes: const [
-      //       ForsalePageRoute(),
-      //       ForrentPageRoute(),
-      //     ],
-      //     builder: (context, child, animation) {
-      //       final tabsRouter = AutoTabsRouter.of(context);
-      //       return Column(
-      //         mainAxisSize: MainAxisSize.max,
-      //         children: [
-      //           //  garagesale tab 分类 (For sale  For Rent)
-      //           _buildTabsSection(context, ref, tabsRouter),
-      //           // 发布 garage sale 组件
-      //           _buildPostSection(context, ref, vm),
-      //           Expanded(
-      //             child: child,
-      //           )
-      //         ],
-      //       );
-      //     },
-      // )
-    );
-  }
-  Widget _buildTopSection(BuildContext context, WidgetRef ref, vm) {
-    final topSectionsData = vm.topSectionsData;
-    int curTagIdx = 1;
-    return Container(
-      color: context.appColors.whiteBG,
-      padding: const EdgeInsets.only(top: 23, bottom: 30),
-      child: Center(
-        child: Row(
-          mainAxisSize: MainAxisSize.max,
-          mainAxisAlignment: MainAxisAlignment.center,
-          crossAxisAlignment: CrossAxisAlignment.center,
-          children: List.generate(topSectionsData.length, (index) {
-            final item = topSectionsData[index];
-            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,
-                  ).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);
-          }),
-        ),
-      ),
-    );
-  }
-}

+ 0 - 71
packages/cpt_community/lib/modules/garage/garage_repository.dart

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

+ 0 - 72
packages/cpt_community/lib/modules/garage/garage_state.dart

@@ -1,72 +0,0 @@
-import 'package:cs_resources/generated/assets.dart';
-import 'package:flutter/material.dart';
-import 'package:shared/utils/color_utils.dart';
-
-class GarageState {
-  List<Map<String, dynamic>>? topSectionsData;
-  int? curPage;
-  int? pageSize;
-  int? filterCount;
-  int? activeIndex = 0;
-  List tabsList = [];
-  List<Map<String,dynamic>> categoryList = [];
-  List? list = [];
-
-  GarageState({
-    this.topSectionsData,
-    this.curPage,
-    this.pageSize,
-    this.filterCount,
-    this.activeIndex,
-    List<Map<String, dynamic>>? categoryList,
-    required this.tabsList,
-    this.list,
-  }): categoryList = categoryList ?? [];
-
-  GarageState copyWith({
-    List<Map<String, dynamic>>? topSectionsData,
-    List<Map<String, dynamic>>? categoryList,
-    int? curPage,
-    int? pageSize,
-    int? filterCount,
-    int? activeIndex,
-    List? tabsList,
-    List? list,
-  }) {
-    return GarageState(
-      topSectionsData: topSectionsData ?? this.topSectionsData,
-      curPage: curPage ?? this.curPage,
-      pageSize: pageSize ?? this.pageSize,
-      filterCount: filterCount ?? this.filterCount,
-      activeIndex: activeIndex ?? this.activeIndex,
-      categoryList: categoryList ?? this.categoryList,
-      tabsList: tabsList ?? this.tabsList,
-      list: list ?? this.list,
-    );
-  }
-
-  Map<String, dynamic> toMap() {
-    return {
-      'topSectionsData': this.topSectionsData,
-      'curPage': this.curPage,
-      'pageSize': this.pageSize,
-      'filterCount': this.filterCount,
-      'activeIndex': this.activeIndex,
-      'tabsList': this.tabsList,
-      'list': this.list,
-      'categoryList': this.categoryList,
-    };
-  }
-
-  factory GarageState.fromMap(Map<String, dynamic> map) {
-    return GarageState(
-      topSectionsData: map['topSectionsData'] as List<Map<String, dynamic>>,
-      curPage: map['curPage'] as int,
-      pageSize: map['pageSize'] as int,
-      filterCount: map['filterCount'] as int,
-      activeIndex: map['activeIndex'] as int,
-      tabsList: map['tabsList'] as List,
-      list: map['list'] as List,
-    );
-  }
-}

+ 0 - 242
packages/cpt_community/lib/modules/garage/garage_vm.dart

@@ -1,242 +0,0 @@
-
-import 'package:cpt_community/modules/community/community_page.dart';
-import 'package:cs_resources/generated/assets.dart';
-import 'package:flutter/material.dart';
-import 'package:plugin_platform/engine/dialog/dialog_engine.dart';
-import 'package:plugin_platform/engine/toast/toast_engine.dart';
-import 'package:riverpod_annotation/riverpod_annotation.dart';
-import 'package:router/path/router_path.dart';
-import 'package:shared/utils/color_utils.dart';
-import 'package:shared/utils/log_utils.dart';
-import 'package:auto_route/auto_route.dart';
-import 'package:widgets/dialog/app_default_dialog.dart';
-import 'package:widgets/dialog/app_custom_dialog.dart';
-import 'package:widgets/app_check_box.dart';
-import 'package:widgets/my_checkbox_group.dart';
-
-import 'garage_page.dart';
-import 'garage_state.dart';
-import 'garage_repository.dart';
-
-part 'garage_vm.g.dart';
-
-@riverpod
-class GarageVm extends _$GarageVm {
-  late GarageRepository garageRepository;
-  get topSectionsData => state.topSectionsData;
-  GarageState initState() {
-    return GarageState(
-        activeIndex: 0,
-        topSectionsData: [
-          {
-            "title": "News Feed",
-            "icon": Assets.communityNesFeed,
-            "pageStartInstanceFn": CommunityPage.startInstance,
-            "page": const CommunityPage(),
-          },
-          {
-            "title": "Garage Sale",
-            "icon": Assets.communityGarageSale,
-            "pageStartInstanceFn": GaragePage.startInstance,
-            "page": const GaragePage(),
-          },
-        ],
-        tabsList: [
-          {
-            'title': 'For Sale',
-            'icon': null,
-            'active': true,
-            'activeTitleColor': Colors.white,
-            'activeTitleFontSize': 16,
-            'activeTitleBackgroundColor': ColorUtils.string2Color("#4161D0"),
-          },
-          {
-            'title': 'For Rent',
-            'icon': null,
-            'active': false,
-            'activeTitleColor': Colors.white,
-            'activeTitleFontSize': 16,
-            'activeTitleBackgroundColor': ColorUtils.string2Color("#4161D0"),
-          },
-        ],
-        categoryList: [
-          {
-            'id': '1',
-            'label': 'Kids',
-          },
-          {
-            'id': '2',
-            'label': 'Homeware',
-          },
-          {
-            'id': '3',
-            'label': 'Fashion',
-          },
-          {
-            'id': '4',
-            'label': 'Electronics',
-          },
-          {
-            'id': '5',
-            'label': 'Sports',
-          },
-          {
-            'id': '6',
-            'label': 'Furniture',
-          },
-          {
-            'id': '7',
-            'label': 'Others',
-          },
-        ],
-        list: [
-          {
-            'id':1,
-            'avator': Assets.communityCamera,
-            'title': '发动机上课士大夫',
-            'isFollow': false,
-            'content': '经典福克斯附件是的开飞机迪斯科封禁端口是否建立四道口附近 ……[More]',
-            'imageUrls': [],
-            'time': 'June 17,2016 at 7:23 p.m.',
-            'isLike': true,
-            'likeno': 12
-          },
-          {
-            'id':2,
-            'avator': Assets.communityCamera,
-            'title': '分等级付给的积分多少',
-            'isFollow': true,
-            'content': 'She said YES and our lives changed.Thank you all for coming to my propose today.We hope everyone can ……[More]',
-            'imageUrls': ['https://img2.baidu.com/it/u=3489233687,2364672159&fm=253&fmt=auto&app=120&f=JPEG?w=507&h=500','https://img2.baidu.com/it/u=3489233687,2364672159&fm=253&fmt=auto&app=120&f=JPEG?w=507&h=500','https://img2.baidu.com/it/u=3489233687,2364672159&fm=253&fmt=auto&app=120&f=JPEG?w=507&h=500'],
-            'time': 'June 17,2016 at 7:23 p.m.',
-            'isLike': true,
-            'likeno': 12
-          },
-        ]
-    );
-  }
-  @override
-  GarageState build(){
-    // 引入数据仓库
-    garageRepository = ref.read(garageRepositoryProvider);
-    // 初始化状态
-    GarageState state = initState();
-    return state;
-  }
-
-  // 上拉加载
-  Future onLoadData() async {
-    Log.d("----garage_vm-----initListData");
-    // await Future.delayed(const Duration(seconds: 2));
-    // if(state.list.length >= state.filterCount){
-    //   return;
-    // }else {
-    //   int curPage = state.curPage + 1;
-    //   state = state.copyWith(curPage: curPage,);
-    //   getListData();
-    // }
-    // getListData();
-  }
-
-  // 获取list 列表数据
-  void getListData<T>() async {
-    Log.d("加载listData数据---------------start-----");
-    try {
-      //请求网络
-      Map<String, dynamic>  params = {
-        "curPage": state.curPage,
-        "pageSize": state.pageSize,
-      };
-      Log.d("请求参数------$params");
-      final result = await garageRepository.fetchGarageList(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("----garage_vm-----refreshListData ");
-
-    // await Future.delayed(const Duration(seconds: 2));
-
-    state = state.copyWith(curPage: 1, pageSize: 10);
-    // ref.invalidateSelf();
-    // ref.invalidate(garageVmProvider);
-    getListData();
-
-  }
-
-  // 选择 category
-  handlerChooseCategory(BuildContext context) async {
-    await DialogEngine.show(
-      tag: "choosegaragesalecategory",
-      position: DialogPosition.center,
-      widget: AppCustomDialog(
-        message: '',
-        confirmTxt: "Ok",
-        messageBuilder: (BuildContext context){
-          return Container(
-            // width: 500,
-            height: 400,
-            color: Colors.white,
-            child: Column(
-              mainAxisAlignment: MainAxisAlignment.start,
-              crossAxisAlignment: CrossAxisAlignment.start,
-              children: [
-                MyCheckboxGroup(
-                  isSingleSelect: false,
-                    labelStyle: const TextStyle(
-                    fontSize: 16,
-                    fontWeight: FontWeight.w500,
-                  ),
-                  items: state.categoryList,
-                  onChanged: (List<Map<String, dynamic>> selectedItems){
-                    Log.d("----MyCheckboxGroup onChanged  $selectedItems");
-                  }
-                )
-              ],
-            ),
-          );
-        },
-        isShowCancelBtn:false,
-        confirmAction: (){
-
-        },
-      )
-    );
-  }
-
-  // 切换tab
-  handlerChangeTab(int index, tabsRouter) {
-    tabsRouter.setActiveIndex(index);
-    // state = state.copyWith(tabsRouter: tabsRouter ,activeTabIdx: index);
-    Log.d("garage_vm handlerChangeTab--index:    $index");
-  }
-
-
-  // 点击发布的按钮 跳转到发布的页面
-  void handlerGotoPost(context){
-    // ComponentServiceManager().communityService.startCommunityPage();
-    AutoRouter.of(context).pushNamed(RouterPath.garageSalePost);
-  }
-
-
-  handlerChangeCommunityType(context, int index){
-    if(index == 0){
-      // 返回到 newsfeed 页面
-      Navigator.pop(context);
-    }
-  }
-
-}

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

@@ -16,11 +16,11 @@ import 'package:widgets/my_text_view.dart';
 @RoutePage()
 class GaragesaleDetailPage extends HookConsumerWidget {
   final int? id;
-  final String? type;  // forsale  forrent
+  final String? type;  // forSale  forRent
 
   const GaragesaleDetailPage({Key? key, required this.id, required this.type}) : super(key: key);
   // 启动当前页面
-  static void startInstance({BuildContext? context, int? id, String? type = 'forsale'}) {
+  static void startInstance({BuildContext? context, int? id, String? type = 'forSale'}) {
     if (context != null) {
       context.router.push(GaragesaleDetailPageRoute(id: id, type: type));
     } else {

+ 30 - 2
packages/cpt_community/lib/modules/garage/garagesale_post/garagesale_post_page.dart

@@ -86,12 +86,40 @@ class GaragesalePostPage extends HookConsumerWidget {
                                   errorText: state.titleErrorText,
                                   onSubmit: (formKey, value) {
                                     state!.formData[formKey]!['focusNode'].unfocus();
-                                    FocusScope.of(context).requestFocus(state.formData['description']!['focusNode']);
+                                    FocusScope.of(context).requestFocus(state.formData['price']!['focusNode']);
                                   },
                                 ),
                               ]
                             )
                           ),
+                          // price
+                          Container(
+                              margin: const EdgeInsets.only(left:15, right:15, top: 15),
+                              child: Column(
+                                  crossAxisAlignment: CrossAxisAlignment.start,
+                                  children: [
+                                    FormRequireText(
+                                      text: "Price(\$)",
+                                      textColor: context.appColors.textBlack,
+                                      fontSize: 17,
+                                    ).marginOnly(bottom: 14.5),
+                                    _buildInputLayout(
+                                      context,
+                                      ref,
+                                      state,
+                                      'price',
+                                      marginTop: 16,
+                                      textInputType: TextInputType.text,
+                                      textInputAction: TextInputAction.next,
+                                      errorText: state.priceErrorText,
+                                      onSubmit: (formKey, value) {
+                                        state!.formData[formKey]!['focusNode'].unfocus();
+                                        FocusScope.of(context).requestFocus(state.formData['description']!['focusNode']);
+                                      },
+                                    ),
+                                  ]
+                              )
+                          ),
                           // description
                           Container(
                             margin: const EdgeInsets.only(left:15, right:15,top: 15),
@@ -284,8 +312,8 @@ class GaragesalePostPage extends HookConsumerWidget {
     return IgnoreKeyboardDismiss(
       child: MyTextField(
         key,
-        fillBackgroundColor: context.appColors.authFiledBG,
         state.formData[key]!['value'],
+        fillBackgroundColor: context.appColors.authFiledBG,
         hintText: state.formData[key]!['hintText'],
         hintStyle: TextStyle(
           color: context.appColors.authFiledHint,

+ 14 - 1
packages/cpt_community/lib/modules/garage/garagesale_post/garagesale_post_state.dart

@@ -4,7 +4,10 @@ class GaragesalePostPageState {
   //title 字段的错误信息展示
   String? titleErrorText;
 
-  //title 字段的错误信息展示
+  //price 字段的错误信息展示
+  String? priceErrorText;
+
+  //description 字段的错误信息展示
   String? descriptionErrorText;
 
   //表单的校验与数据
@@ -30,6 +33,7 @@ class GaragesalePostPageState {
     formData,
     required this.imgList,
     this.titleErrorText,
+    this.priceErrorText,
     this.descriptionErrorText,
     this.title,
     this.description,
@@ -57,6 +61,13 @@ class GaragesalePostPageState {
       'focusNode': FocusNode(),
       'obsecure': false,
     },
+    'price': {
+      'value': '',
+      'controller': TextEditingController(),
+      'hintText': '',
+      'focusNode': FocusNode(),
+      'obsecure': false,
+    },
     'description': {
       'value': '',
       'controller': TextEditingController(),
@@ -70,6 +81,7 @@ class GaragesalePostPageState {
     Map<String, Map<String, dynamic>>? formData,
     List<String>? imgList,
     String? titleErrorText,
+    String? priceErrorText,
     String? descriptionErrorText,
     String? saleSelectedOption,
     String? categorySelectedOption,
@@ -84,6 +96,7 @@ class GaragesalePostPageState {
       saleSelectedOption: saleSelectedOption ?? this.saleSelectedOption,
       categorySelectedOption: categorySelectedOption ?? this.categorySelectedOption,
       titleErrorText: titleErrorText ,
+      priceErrorText: priceErrorText ,
       descriptionErrorText: descriptionErrorText,
     );
   }

+ 29 - 2
packages/cpt_community/lib/modules/garage/garagesale_post/garagesale_post_vm.dart

@@ -22,6 +22,7 @@ class GaragesalePostVm extends _$GaragesalePostVm {
   GaragesalePostPageState initState() {
     return GaragesalePostPageState(
       titleErrorText: null,
+      priceErrorText: null,
       descriptionErrorText: '',
       formData: {
         'sale': {
@@ -45,6 +46,13 @@ class GaragesalePostVm extends _$GaragesalePostVm {
           'focusNode': FocusNode(),
           'obsecure': false,
         },
+        'price': {
+          'value': '',
+          'controller': TextEditingController(),
+          'hintText': '',
+          'focusNode': FocusNode(),
+          'obsecure': false,
+        },
         'description': {
           'value': '',
           'controller': TextEditingController(),
@@ -91,6 +99,7 @@ class GaragesalePostVm extends _$GaragesalePostVm {
   //sale 选择选项
   void pickSaleCallback() {
     _dismissKeyboard(keyStr: 'title');
+    _dismissKeyboard(keyStr: 'price');
     _dismissKeyboard(keyStr: 'description');
 
     OptionPickerUtil.showCupertinoOptionPicker(
@@ -156,9 +165,10 @@ class GaragesalePostVm extends _$GaragesalePostVm {
     String  categoryValue= state.categorySelectedOption ?? "";
 
     String  titleValue= _getFormFieldValue(keyStr: 'title');
+    String  priceValue= _getFormFieldValue(keyStr: 'price');
     String  descriptionValue= _getFormFieldValue(keyStr: 'description');
 
-    Log.d('当前待提交的 sale:$saleValue category:$categoryValue title:$titleValue description:$descriptionValue  imgList:${state.imgList}');
+    Log.d('当前待提交的 sale:$saleValue category:$categoryValue title:$titleValue price:$priceValue  description:$descriptionValue  imgList:${state.imgList}');
 
 
     if (Utils.isEmpty(saleValue)) {
@@ -174,6 +184,14 @@ class GaragesalePostVm extends _$GaragesalePostVm {
       state = state.copyWith(titleErrorText: null);
     }
 
+    if (Utils.isEmpty(priceValue)) {
+      state = state.copyWith(priceErrorText: 'Price is empty',);
+      return;
+    }else {
+      // state.priceErrorText = null;
+      state = state.copyWith(priceErrorText: null);
+    }
+
     if (Utils.isEmpty(descriptionValue)) {
       state = state.copyWith(descriptionErrorText: 'Description is empty');
       return;
@@ -197,11 +215,18 @@ class GaragesalePostVm extends _$GaragesalePostVm {
 
     // 获取表单的焦点节点
     final FocusNode focusNode = getFocusNode(state.formData, 'title');
+    final FocusNode focusNodePrice = getFocusNode(state.formData, 'price');
 
     focusNode.addListener(() {
       // 获取焦点的时候清空错误文本
       if (focusNode.hasFocus) {
-        state = state.copyWith(titleErrorText: null, descriptionErrorText: null);
+        state = state.copyWith(titleErrorText: null, priceErrorText:null, descriptionErrorText: null);
+      }
+    });
+    focusNodePrice.addListener(() {
+      // 获取焦点的时候清空错误文本
+      if(focusNodePrice.hasFocus){
+        state = state.copyWith(titleErrorText: null,priceErrorText: null, descriptionErrorText: null);
       }
     });
   }
@@ -210,7 +235,9 @@ class GaragesalePostVm extends _$GaragesalePostVm {
   void onDispose(GaragesalePostPageState initState) {
     // 获取表单的焦点节点
     final FocusNode focusNode = getFocusNode(state.formData, 'title');
+    final FocusNode focusNodePrice = getFocusNode(state.formData, 'price');
     focusNode.dispose();
+    focusNodePrice.dispose();
 
     Log.d("GaragesalePostPageState 销毁 onDispose");
   }

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

@@ -6,7 +6,7 @@ part of 'garagesale_post_vm.dart';
 // RiverpodGenerator
 // **************************************************************************
 
-String _$garagesalePostVmHash() => r'263c880d5ef88c9a3808b91d6448cbee51b8ff8e';
+String _$garagesalePostVmHash() => r'fb025048ae4a1e025cf3fb3e788ec4ac63811009';
 
 /// See also [GaragesalePostVm].
 @ProviderFor(GaragesalePostVm)

+ 92 - 0
packages/cpt_community/lib/modules/my_following/components/item_following.dart

@@ -0,0 +1,92 @@
+import 'package:cpt_community/components/comments_dialog.dart';
+import 'package:cs_resources/theme/app_colors_theme.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_hooks/flutter_hooks.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:hooks_riverpod/hooks_riverpod.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_button.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/my_text_view.dart';
+
+enum MyFollowingType {
+  isFollowType,
+  isFollowerType,
+}
+
+class MyFollowingListItem extends StatelessWidget {
+  final MyFollowingType? itemType;
+  bool? hasBottomDriver = true;
+  Map<String, dynamic> itemObj;
+  void Function(dynamic)? onClickAction;
+  MyFollowingListItem({
+    super.key,
+    required this.itemObj,
+    this.itemType = MyFollowingType.isFollowType,
+    this.hasBottomDriver=true,
+    this.onClickAction
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return Column(
+      children: [
+        Container(
+          margin: const EdgeInsets.only(left: 15,right: 15,top: 15,bottom: 15),
+          child: Row(
+            mainAxisSize: MainAxisSize.max,
+            children: [
+              Expanded(
+                child: Row(
+                  mainAxisAlignment: MainAxisAlignment.start,
+                  children: [
+                    MyLoadImage(
+                      'https://img1.baidu.com/it/u=2743394743,692629981&fm=253&fmt=auto&app=120&f=JPEG?w=800&h=800',
+                      width: 65,
+                      height: 65,
+                      isCircle: true,
+                    ),
+                    MyTextView(
+                      'Chin Lan',
+                      fontSize: 17,
+                      isFontMedium: true,
+                      marginLeft: 17,
+                    )
+                  ],
+                ).onTap((){
+                  // onClickAction?.call(itemObj);
+                }),
+              ),
+              // _buildIsFollowButton(context),
+              HookConsumer(
+                builder: (context, ref, child) {
+                  final isFollow = useState(itemObj['isFollow']);
+                  return (!isFollow.value)? MyButton(
+                    text:'+Follow',
+                    onPressed: (){
+                      // todo 调用接口 然后更新状态
+                      isFollow.value = !isFollow.value;
+                    },
+                    textColor: context.appColors.textWhite,
+                    backgroundColor: context.appColors.textPrimary,
+                    fontSize: 14,
+                    fontWeight: FontWeight.w400,
+                    minWidth: 67.5,
+                    minHeight: 30.5,
+                  ): const SizedBox.shrink();
+                },
+              )
+
+            ],
+          ),
+        ),
+        if(hasBottomDriver!)
+          Container(
+            height: 1,
+            color: context.appColors.dividerDefault,
+          )
+      ],
+    );
+  }
+}

+ 64 - 0
packages/cpt_community/lib/modules/my_following/components/search_cmp.dart

@@ -0,0 +1,64 @@
+import 'package:flutter/material.dart';
+import 'package:widgets/search_app_bar.dart';
+
+class SearchCmp extends StatelessWidget {
+  String? value;
+  String? hintText;
+  Color backgroundColor = Colors.transparent;
+  ValueChanged<String>? onSearch;
+  ValueChanged<String>? onChanged;
+  TextEditingController? controller;
+  List<Widget>? actions;
+  void Function()? backCallback;
+
+  SearchCmp({
+    Key? key,
+    this.backCallback,
+    this.value,
+    this.hintText,
+    this.backgroundColor = Colors.transparent,
+    this.onSearch,
+    this.onChanged,
+    this.controller,
+    this.actions,
+  }) : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    // 检查当前主题是亮色还是暗色
+    final bool isDarkMode = Theme.of(context).brightness == Brightness.dark;
+
+
+    return Column(
+      children: [
+        Container(
+          height: kToolbarHeight,
+          color: backgroundColor,
+          child: Row(
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              // 搜索栏
+              Expanded(
+                child: SearchAppBar(
+                  onSearch: onSearch,
+                  onChanged: onChanged,
+                  value: value,
+                  hintText: hintText,
+                  controller: controller,
+                ),
+              ),
+              // 右侧操作按钮
+              Container(
+                alignment: Alignment.centerRight,
+                child: Row(
+                  mainAxisSize: MainAxisSize.min,
+                  children: actions ?? [],
+                ),
+              ),
+            ],
+          ),
+        ),
+      ],
+    );
+  }
+}

+ 105 - 0
packages/cpt_community/lib/modules/my_following/my_follow/my_follow_page.dart

@@ -0,0 +1,105 @@
+import 'package:flutter/material.dart';
+import 'package:auto_route/auto_route.dart';
+import 'package:flutter/rendering.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: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';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/my_appbar.dart';
+import 'package:cs_resources/theme/app_colors_theme.dart';
+import 'package:widgets/search_app_bar.dart';
+import 'package:widgets/widget_export.dart';
+
+import '../../../router/page/community_page_router.dart';
+import '../components/item_following.dart';
+import 'my_follow_vm.dart';
+
+@RoutePage()
+class MyFollowPage extends HookConsumerWidget {
+  const MyFollowPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance({BuildContext? context}) {
+    if (context != null) {
+      context.router.push(const MyFollowPageRoute());
+    } else {
+      appRouter.push(const MyFollowPageRoute());
+    }
+  }
+
+  @override
+  Widget build(BuildContext context, WidgetRef ref) {
+    final vm = ref.read(myFollowVmProvider.notifier);
+    final state = ref.watch(myFollowVmProvider);
+
+    useEffect(() {
+      // 组件挂载时执行 - 执行接口请求
+      Future.microtask(() => vm.initPageData());
+      return () {
+        // 组件卸载时执行
+      };
+    }, []);
+
+    return  Scaffold(
+        // appBar: MyAppBar.appBar(
+        //   context,
+        //   "following",
+        //   backgroundColor: context.appColors.whiteBG,
+        // ),
+        backgroundColor: ColorUtils.string2Color("#F2F3F6"),
+        body: Container(
+          height: double.infinity,
+          width: double.infinity,
+          color: context.appColors.whiteBG,
+          child: EasyRefresh(
+            controller: vm.refreshController,
+            // 上拉加载
+            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 _buildFollowItem(context, ref, state.list![index], vm, index, state.list.length);
+                        },
+                        childCount: state.list!.length
+                    )
+                )
+              ],
+            ),
+          ).marginOnly(left: 15,right: 15,top: 15,bottom: 15),
+        )
+    );
+  }
+
+  Widget _buildFollowItem(BuildContext context,WidgetRef ref, item, vm, index, totalIndex) {
+    bool isLast = index == totalIndex - 1;
+    return MyFollowingListItem(
+        itemObj: item,
+        itemType: MyFollowingType.isFollowType,
+        hasBottomDriver: isLast? false : true,
+        onClickAction:(itemObj){
+          print("点击了  ${itemObj['name']}");
+        }
+    );
+  }
+}

+ 39 - 0
packages/cpt_community/lib/modules/my_following/my_follow/my_follow_state.dart

@@ -0,0 +1,39 @@
+import 'package:widgets/load_state_layout.dart';
+
+class MyFollowState {
+  //页面 LoadView 状态的展示
+  LoadState loadingState;
+  String? errorMessage;
+
+  int? curPage;
+  int? pageSize = 10;
+  int? filterCount = 0;
+  List<Map<String, dynamic>> list;
+
+  MyFollowState({
+    this.loadingState = LoadState.State_Loading,
+    String? errorMessage,
+    this.curPage = 1,
+    this.pageSize = 10,
+    this.filterCount = 0,
+    required this.list,
+  });
+
+  MyFollowState copyWith({
+    LoadState? loadingState,
+    String? errorMessage,
+    int? curPage,
+    int? pageSize,
+    int? filterCount,
+    List<Map<String, dynamic>>? list,
+  }) {
+    return MyFollowState(
+      loadingState: loadingState ?? this.loadingState,
+      errorMessage: errorMessage ?? this.errorMessage,
+      curPage: curPage ?? this.curPage,
+      pageSize: pageSize ?? this.pageSize,
+      filterCount: filterCount ?? this.filterCount,
+      list: list ?? this.list,
+    );
+  }
+}

+ 153 - 0
packages/cpt_community/lib/modules/my_following/my_follow/my_follow_vm.dart

@@ -0,0 +1,153 @@
+import 'package:cs_resources/generated/assets.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:riverpod_annotation/riverpod_annotation.dart';
+import 'package:shared/utils/log_utils.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/widget_export.dart';
+
+import 'my_follow_state.dart';
+
+part 'my_follow_vm.g.dart';
+
+@riverpod
+class MyFollowVm extends _$MyFollowVm {
+
+  bool _needShowPlaceholder = true; //是否展示LoadingView
+
+  // Refresh 控制器
+  final EasyRefreshController refreshController = EasyRefreshController(
+    controlFinishRefresh: true,  //允许刷新
+    controlFinishLoad: true,   //允许加载
+  );
+
+  MyFollowState initState() {
+    return MyFollowState(
+        list: []
+    );
+  }
+
+  @override
+  MyFollowState build(){
+    final state = initState();
+    Log.d("--------------------------build---------------------");
+
+    return state;
+  }
+
+  //刷新页面状态
+  void changeLoadingState(LoadState loadState, String? errorMsg) {
+    state = state.copyWith(
+        loadingState: loadState,
+        errorMessage: errorMsg
+    );
+  }
+
+  // 初始化页面数据
+  initPageData() {
+    Log.d("----for_sale_vm-----initPageData   ${state.loadingState}");
+    onRefresh();
+  }
+
+  // 上拉加载 更多
+  Future loadMore() async {
+    Log.d("----for_sale_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() async {
+    Log.d("----forsale_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>() 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,
+        'avator': 'https://img2.baidu.com/it/u=3489233687,2364672159&fm=253&fmt=auto&app=120&f=JPEG?w=507&h=500',
+        'title': 'William Jefferson',
+        'isFollow': false,
+      },
+      {
+        'id':2,
+        'avator': 'https://img2.baidu.com/it/u=3489233687,2364672159&fm=253&fmt=auto&app=120&f=JPEG?w=507&h=500',
+        'title': 'William Jefferson',
+        'isFollow': true,
+      },
+    ];
+
+    if (state.curPage == 1) {
+      //刷新的方式
+      state = state.copyWith(list: listData);
+      refreshController.finishRefresh();
+      // //更新展示的状态
+      changeLoadingState(LoadState.State_Success, null);
+    } else {
+      //加载更多
+      final allList = state.list;
+      allList.addAll(listData);
+      state = state.copyWith(list: allList);
+      refreshController.finishLoad();
+
+    }
+
+    // 最后赋值
+    _needShowPlaceholder = false;
+  }
+
+}

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

@@ -1,25 +1,25 @@
 // GENERATED CODE - DO NOT MODIFY BY HAND
 
-part of 'garage_vm.dart';
+part of 'my_follow_vm.dart';
 
 // **************************************************************************
 // RiverpodGenerator
 // **************************************************************************
 
-String _$garageVmHash() => r'7856fbf737fe062c1e4487f9fffdff90f8641794';
+String _$myFollowVmHash() => r'c3a6e5047a72ec1315e4cf10a24c0925ef9b9223';
 
-/// See also [GarageVm].
-@ProviderFor(GarageVm)
-final garageVmProvider =
-    AutoDisposeNotifierProvider<GarageVm, GarageState>.internal(
-  GarageVm.new,
-  name: r'garageVmProvider',
+/// See also [MyFollowVm].
+@ProviderFor(MyFollowVm)
+final myFollowVmProvider =
+    AutoDisposeNotifierProvider<MyFollowVm, MyFollowState>.internal(
+  MyFollowVm.new,
+  name: r'myFollowVmProvider',
   debugGetCreateSourceHash:
-      const bool.fromEnvironment('dart.vm.product') ? null : _$garageVmHash,
+      const bool.fromEnvironment('dart.vm.product') ? null : _$myFollowVmHash,
   dependencies: null,
   allTransitiveDependencies: null,
 );
 
-typedef _$GarageVm = AutoDisposeNotifier<GarageState>;
+typedef _$MyFollowVm = AutoDisposeNotifier<MyFollowState>;
 // 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

+ 105 - 0
packages/cpt_community/lib/modules/my_following/my_follower/my_follower_page.dart

@@ -0,0 +1,105 @@
+import 'package:flutter/material.dart';
+import 'package:auto_route/auto_route.dart';
+import 'package:flutter/rendering.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: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';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/my_appbar.dart';
+import 'package:cs_resources/theme/app_colors_theme.dart';
+import 'package:widgets/search_app_bar.dart';
+import 'package:widgets/widget_export.dart';
+
+import '../../../router/page/community_page_router.dart';
+import '../components/item_following.dart';
+import 'my_follower_vm.dart';
+
+@RoutePage()
+class MyFollowerPage extends HookConsumerWidget {
+  const MyFollowerPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance({BuildContext? context}) {
+    if (context != null) {
+      context.router.push(const MyFollowerPageRoute());
+    } else {
+      appRouter.push(const MyFollowerPageRoute());
+    }
+  }
+
+  @override
+  Widget build(BuildContext context, WidgetRef ref) {
+    final vm = ref.read(myFollowerVmProvider.notifier);
+    final state = ref.watch(myFollowerVmProvider);
+
+    useEffect(() {
+      // 组件挂载时执行 - 执行接口请求
+      Future.microtask(() => vm.initPageData());
+      return () {
+        // 组件卸载时执行
+      };
+    }, []);
+
+    return  Scaffold(
+      // appBar: MyAppBar.appBar(
+      //   context,
+      //   "following",
+      //   backgroundColor: context.appColors.whiteBG,
+      // ),
+        backgroundColor: ColorUtils.string2Color("#F2F3F6"),
+        body: Container(
+          height: double.infinity,
+          width: double.infinity,
+          color: context.appColors.whiteBG,
+          child: EasyRefresh(
+            controller: vm.refreshController,
+            // 上拉加载
+            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 _buildFollowItem(context, ref, state.list![index], vm, index, state.list.length);
+                        },
+                        childCount: state.list!.length
+                    )
+                )
+              ],
+            ),
+          ).marginOnly(left: 15,right: 15,top: 15,bottom: 15),
+        )
+    );
+  }
+
+  Widget _buildFollowItem(BuildContext context,WidgetRef ref, item, vm, index, totalIndex) {
+    bool isLast = index == totalIndex - 1;
+    return MyFollowingListItem(
+        itemObj: item,
+        itemType: MyFollowingType.isFollowerType,
+        hasBottomDriver: isLast? false : true,
+        onClickAction:(itemObj){
+          print("点击了  ${itemObj['name']}");
+        }
+    );
+  }
+}

+ 39 - 0
packages/cpt_community/lib/modules/my_following/my_follower/my_follower_state.dart

@@ -0,0 +1,39 @@
+import 'package:widgets/load_state_layout.dart';
+
+class MyFollowerState {
+  //页面 LoadView 状态的展示
+  LoadState loadingState;
+  String? errorMessage;
+
+  int? curPage;
+  int? pageSize = 10;
+  int? filterCount = 0;
+  List<Map<String, dynamic>> list;
+
+  MyFollowerState({
+    this.loadingState = LoadState.State_Loading,
+    String? errorMessage,
+    this.curPage = 1,
+    this.pageSize = 10,
+    this.filterCount = 0,
+    required this.list,
+  });
+
+  MyFollowerState copyWith({
+    LoadState? loadingState,
+    String? errorMessage,
+    int? curPage,
+    int? pageSize,
+    int? filterCount,
+    List<Map<String, dynamic>>? list,
+  }) {
+    return MyFollowerState(
+      loadingState: loadingState ?? this.loadingState,
+      errorMessage: errorMessage ?? this.errorMessage,
+      curPage: curPage ?? this.curPage,
+      pageSize: pageSize ?? this.pageSize,
+      filterCount: filterCount ?? this.filterCount,
+      list: list ?? this.list,
+    );
+  }
+}

+ 153 - 0
packages/cpt_community/lib/modules/my_following/my_follower/my_follower_vm.dart

@@ -0,0 +1,153 @@
+import 'package:cs_resources/generated/assets.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:riverpod_annotation/riverpod_annotation.dart';
+import 'package:shared/utils/log_utils.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/widget_export.dart';
+
+import 'my_follower_state.dart';
+
+part 'my_follower_vm.g.dart';
+
+@riverpod
+class MyFollowerVm extends _$MyFollowerVm {
+
+  bool _needShowPlaceholder = true; //是否展示LoadingView
+
+  // Refresh 控制器
+  final EasyRefreshController refreshController = EasyRefreshController(
+    controlFinishRefresh: true,  //允许刷新
+    controlFinishLoad: true,   //允许加载
+  );
+
+  MyFollowerState initState() {
+    return MyFollowerState(
+        list: []
+    );
+  }
+
+  @override
+  MyFollowerState build(){
+    final state = initState();
+    Log.d("--------------------------build---------------------");
+
+    return state;
+  }
+
+  //刷新页面状态
+  void changeLoadingState(LoadState loadState, String? errorMsg) {
+    state = state.copyWith(
+        loadingState: loadState,
+        errorMessage: errorMsg
+    );
+  }
+
+  // 初始化页面数据
+  initPageData() {
+    Log.d("----for_sale_vm-----initPageData   ${state.loadingState}");
+    onRefresh();
+  }
+
+  // 上拉加载 更多
+  Future loadMore() async {
+    Log.d("----for_sale_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() async {
+    Log.d("----forsale_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>() 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,
+        'avator': 'https://iknow-pic.cdn.bcebos.com/4afbfbedab64034f6c21389bbdc379310b551dba',
+        'title': 'Steve Jobs',
+        'isFollow': false,
+      },
+      {
+        'id':2,
+        'avator': 'https://img2.baidu.com/it/u=3489233687,2364672159&fm=253&fmt=auto&app=120&f=JPEG?w=507&h=500',
+        'title': 'William Jefferson',
+        'isFollow': true,
+      },
+    ];
+
+    if (state.curPage == 1) {
+      //刷新的方式
+      state = state.copyWith(list: listData);
+      refreshController.finishRefresh();
+      // //更新展示的状态
+      changeLoadingState(LoadState.State_Success, null);
+    } else {
+      //加载更多
+      final allList = state.list;
+      allList.addAll(listData);
+      state = state.copyWith(list: allList);
+      refreshController.finishLoad();
+
+    }
+
+    // 最后赋值
+    _needShowPlaceholder = false;
+  }
+
+}

+ 25 - 0
packages/cpt_community/lib/modules/my_following/my_follower/my_follower_vm.g.dart

@@ -0,0 +1,25 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'my_follower_vm.dart';
+
+// **************************************************************************
+// RiverpodGenerator
+// **************************************************************************
+
+String _$myFollowerVmHash() => r'68d8164b29974ce64dd0be2f989f83b9445b74e9';
+
+/// See also [MyFollowerVm].
+@ProviderFor(MyFollowerVm)
+final myFollowerVmProvider =
+    AutoDisposeNotifierProvider<MyFollowerVm, MyFollowerState>.internal(
+  MyFollowerVm.new,
+  name: r'myFollowerVmProvider',
+  debugGetCreateSourceHash:
+      const bool.fromEnvironment('dart.vm.product') ? null : _$myFollowerVmHash,
+  dependencies: null,
+  allTransitiveDependencies: null,
+);
+
+typedef _$MyFollowerVm = AutoDisposeNotifier<MyFollowerState>;
+// 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

+ 96 - 0
packages/cpt_community/lib/modules/my_following/my_following_page.dart

@@ -0,0 +1,96 @@
+
+import 'package:cpt_community/components/newsfeed_card_content.dart';
+import 'package:cpt_community/components/newsfeed_card_footer.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/rendering.dart';
+import 'package:hooks_riverpod/hooks_riverpod.dart';
+import 'package:router/ext/auto_router_extensions.dart';
+import 'package:shared/utils/color_utils.dart';
+import 'package:shared/utils/log_utils.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_appbar.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/search_app_bar.dart';
+import 'package:widgets/widget_export.dart';
+
+import '../../components/newfeed_card_header.dart';
+import '../../router/page/community_page_router.dart';
+import 'my_following_vm.dart';
+
+import 'my_following_tabs.dart';
+
+import 'my_following_vm.dart';
+
+
+@RoutePage()
+class MyFollowingPage extends HookConsumerWidget {
+  const MyFollowingPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance({BuildContext? context}) {
+    if (context != null) {
+      context.router.push(const MyFollowingPageRoute());
+    } else {
+      appRouter.push(const MyFollowingPageRoute());
+    }
+  }
+
+  Widget _buildTabsSection(BuildContext context, WidgetRef ref, tabsRouter, state){
+    final vm = ref.read(myFollowingVmProvider.notifier);
+    return Container(
+      width: double.infinity,
+      padding: const EdgeInsets.only(left: 15, right: 15,top: 14,bottom: 14),
+      child: MyFollowingTabs(
+          key: UniqueKey(),
+          tabsList: state.tabsList,
+          tabsRouter: tabsRouter,
+          onClickAction:(activeTabIdx){
+            vm.handlerChangeTab.call(activeTabIdx, tabsRouter);
+          }
+      ),
+    );
+  }
+
+  @override
+  Widget build(BuildContext context, WidgetRef ref) {
+    final vm = ref.read(myFollowingVmProvider.notifier);
+    final state = ref.watch(myFollowingVmProvider);
+    return Scaffold(
+      appBar: MyAppBar.appBar(
+        context,
+        "My Following",
+        backgroundColor: context.appColors.whiteBG,
+      ),
+      backgroundColor: ColorUtils.string2Color("#F2F3F6"),
+      body: Column(
+        children:[
+          Expanded(
+            child: AutoTabsRouter.pageView(
+              key: UniqueKey(),
+              routes: const [
+                MyFollowPageRoute(),
+                MyFollowerPageRoute(),
+              ],
+              builder: (context, child, animation) {
+                final tabsRouter = AutoTabsRouter.of(context);
+                return Column(
+                  mainAxisSize: MainAxisSize.max,
+                  children: [
+                    _buildTabsSection(context, ref, tabsRouter, state),
+                    Expanded(
+                      child: child,
+                    )
+                  ],
+                );
+              },
+            ),
+          ),
+        ],
+      ),
+    );
+  }
+}

+ 30 - 0
packages/cpt_community/lib/modules/my_following/my_following_state.dart

@@ -0,0 +1,30 @@
+class MyFollowingState {
+  final List<String>? tabsList;
+  int? activeTabIdx;
+  int? followerCount;
+  int? followCount;
+
+  MyFollowingState({
+    tabsList,
+    activeTabIdx = 0,
+    this.followerCount = 0,
+    this.followCount = 0,
+  }) : tabsList = tabsList ?? [
+    'Follow',
+    'Follower',
+  ];
+
+  MyFollowingState copyWith({
+    List<String>? tabsList,
+    int? activeTabIdx,
+    int? followerCount,
+    int? followCount,
+  }) {
+    return MyFollowingState(
+      tabsList: tabsList ?? this.tabsList,
+      activeTabIdx: activeTabIdx ?? this.activeTabIdx,
+      followerCount: followerCount ?? this.followerCount,
+      followCount: followCount ?? this.followCount,
+    );
+  }
+}

+ 126 - 110
packages/cpt_community/lib/modules/garage/garage_tabs.dart

@@ -1,110 +1,126 @@
-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:shared/utils/log_utils.dart';
-import 'package:widgets/my_load_image.dart';
-import 'package:widgets/ext/ex_widget.dart';
-import 'package:widgets/my_text_view.dart';
-import 'package:widgets/my_appbar.dart';
-
-import '../community/community_vm.dart';
-import '../garage/garage_vm.dart';
-
-class GarageTabs extends HookConsumerWidget {
-  List tabsList;
-  Widget? Function(BuildContext)? tabItemBuilder;
-  dynamic? tabsRouter;
-  void Function(int)? onClickAction;
-  GarageTabs({
-    Key? key,
-    required this.tabsList,
-    this.tabsRouter,
-    this.onClickAction,
-    this.tabItemBuilder
-  }) : super(key: key);
-
-  Widget _buildTabItem(BuildContext context, WidgetRef ref, vm, item, index) {
-    // 监听 activeIndex 的变化
-    final activeTabIdx = tabsRouter!.activeIndex;
-
-    return Container(
-      width: MediaQuery.of(context).size.width / vm.state.tabsList.length - 30,
-      height: 43,
-      padding: const EdgeInsets.only(top: 10, bottom: 10, left: 10, right: 10),
-      decoration: index==activeTabIdx? BoxDecoration(
-        color: index==activeTabIdx? context.appColors.btnBgDefault: ColorUtils.string2Color("#F2F3F6"),
-        borderRadius: BorderRadius.circular(20),
-        boxShadow: [
-          BoxShadow(
-            color: Colors.grey.withOpacity(0.5),
-            spreadRadius: 1,
-            blurRadius: 5,
-            offset: const Offset(0, 2), // changes position of shadow
-          ),
-        ],
-      ): null,
-      child: Row(
-        children: [
-          Expanded(
-            child: Container(
-              alignment: Alignment.center,
-              child: MyTextView(
-                item['title'],
-                fontSize: 16,
-                textAlign: TextAlign.center,
-                isFontMedium: true,
-                textColor: index == activeTabIdx ? Colors.white :ColorUtils.string2Color("#000000"),
-              ),
-            ).onTap((){
-              print("garage_tabs 中点击的tab index:  $index");
-              onClickAction?.call(index);
-            }),
-          ),
-        ],
-      ),
-    );
-  }
-
-  List<Widget> _buildTabs(BuildContext context, WidgetRef ref, vm){
-
-
-    List tabsList = ref.read(garageVmProvider).tabsList;
-
-    int tabsLength = tabsList.length;
-
-    return List.generate(tabsLength, (index) {
-      return _buildTabItem(context, ref, vm, tabsList[index], index);
-    });
-  }
-
-  @override
-  Widget build(BuildContext context, WidgetRef ref) {
-    final vm = ref.read(garageVmProvider.notifier);
-    // 使用useEffect钩子
-    useEffect(() {
-      print('副作用函数执行');
-      // 这里是副作用逻辑
-      // 返回清理函数
-      return () {
-        print('清理函数执行');
-      };
-    }, []); // 空依赖列表意味着这个副作用只在组件挂载时执行一次
-
-    return SingleChildScrollView(
-      scrollDirection: Axis.horizontal,
-      physics: const BouncingScrollPhysics(),
-      clipBehavior: Clip.none,
-      child: Row(
-        mainAxisSize: MainAxisSize.max,
-        mainAxisAlignment: MainAxisAlignment.center,
-        children: _buildTabs(context, ref, vm),
-      ).constrained(
-          maxWidth:  MediaQuery.of(context).size.width
-      ),
-    );
-  }
-}
+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:shared/utils/log_utils.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/my_appbar.dart';
+
+import '../community/community_vm.dart';
+import 'my_following_vm.dart';
+
+class MyFollowingTabs extends HookConsumerWidget {
+  List tabsList;
+  Widget? Function(BuildContext)? tabItemBuilder;
+  dynamic? tabsRouter;
+  void Function(int)? onClickAction;
+  MyFollowingTabs({
+    Key? key,
+    required this.tabsList,
+    this.tabsRouter,
+    this.onClickAction,
+    this.tabItemBuilder
+  }) : super(key: key);
+
+  Widget _buildTabItem(BuildContext context, WidgetRef ref, vm, item, index) {
+    // 监听 activeIndex 的变化
+    final activeTabIdx = tabsRouter!.activeIndex;
+
+    final activeTabCounter = ref.watch(myFollowingVmProvider.select((state) =>
+      state.tabsList![index] == 'follow'? state.followerCount: state.followerCount
+    ));
+
+    return Container(
+      width: MediaQuery.of(context).size.width / vm.state.tabsList.length - 30,
+      height: 43,
+      padding: const EdgeInsets.only(top: 10, bottom: 10, left: 10, right: 10),
+      decoration: index==activeTabIdx? BoxDecoration(
+        color: index==activeTabIdx? context.appColors.btnBgDefault: ColorUtils.string2Color("#F2F3F6"),
+        borderRadius: BorderRadius.circular(20),
+        boxShadow: [
+          BoxShadow(
+            color: Colors.grey.withOpacity(0.5),
+            spreadRadius: 1,
+            blurRadius: 5,
+            offset: const Offset(0, 2), // changes position of shadow
+          ),
+        ],
+      ): null,
+      child: Row(
+        mainAxisAlignment: MainAxisAlignment.center,
+        children: [
+          Expanded(
+            child: Container(
+              alignment: Alignment.center,
+              child: Row(
+                mainAxisAlignment: MainAxisAlignment.center,
+                children: [
+                  MyTextView(
+                    item,
+                    fontSize: 16,
+                    textAlign: TextAlign.center,
+                    isFontMedium: true,
+                    textColor: index == activeTabIdx ? Colors.white :ColorUtils.string2Color("#000000"),
+                  ),
+                  MyTextView(
+                    '(${activeTabCounter.toString()})',
+                    fontSize: 16,
+                    textAlign: TextAlign.center,
+                    isFontMedium: true,
+                    textColor: index == activeTabIdx ? Colors.white :ColorUtils.string2Color("#000000"),
+                  ),
+                ],
+              ),
+            ).onTap((){
+              onClickAction?.call(index);
+            }),
+          ),
+        ],
+      ),
+    );
+  }
+
+  List<Widget> _buildTabs(BuildContext context, WidgetRef ref, vm, state){
+
+    List tabsList = state.tabsList;
+
+    int tabsLength = tabsList.length;
+
+    return List.generate(tabsLength, (index) {
+      return _buildTabItem(context, ref, vm, tabsList[index], index);
+    });
+  }
+
+  @override
+  Widget build(BuildContext context, WidgetRef ref) {
+    final vm = ref.read(myFollowingVmProvider.notifier);
+    final state = ref.watch(myFollowingVmProvider);
+    // 使用useEffect钩子
+    useEffect(() {
+      print('副作用函数执行');
+      // 这里是副作用逻辑
+      // 返回清理函数
+      return () {
+        print('清理函数执行');
+      };
+    }, []); // 空依赖列表意味着这个副作用只在组件挂载时执行一次
+
+    return SingleChildScrollView(
+      scrollDirection: Axis.horizontal,
+      physics: const BouncingScrollPhysics(),
+      clipBehavior: Clip.none,
+      child: Row(
+        mainAxisSize: MainAxisSize.max,
+        mainAxisAlignment: MainAxisAlignment.center,
+        children: _buildTabs(context, ref, vm, state),
+      ).constrained(
+          maxWidth:  MediaQuery.of(context).size.width
+      ),
+    );
+  }
+}

+ 33 - 0
packages/cpt_community/lib/modules/my_following/my_following_vm.dart

@@ -0,0 +1,33 @@
+import 'package:cs_resources/generated/assets.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:riverpod_annotation/riverpod_annotation.dart';
+import 'package:shared/utils/log_utils.dart';
+import 'package:auto_route/auto_route.dart';
+
+import 'my_following_state.dart';
+
+part 'my_following_vm.g.dart';
+
+@riverpod
+class MyFollowingVm extends _$MyFollowingVm {
+
+  MyFollowingState initState() {
+    return MyFollowingState();
+  }
+
+  @override
+  MyFollowingState build(){
+    final state = initState();
+    Log.d("--------------------------build---------------------");
+
+    return state;
+  }
+
+  handlerChangeTab(int activeTabIdx, TabsRouter tabsRouter){
+    Log.d("handlerChangeTab: $activeTabIdx");
+    state.activeTabIdx = activeTabIdx;
+    tabsRouter.setActiveIndex(activeTabIdx);
+  }
+
+}

+ 10 - 11
packages/cpt_community/lib/modules/garage/garage_repository.g.dart

@@ -1,27 +1,26 @@
 // GENERATED CODE - DO NOT MODIFY BY HAND
 
-part of 'garage_repository.dart';
+part of 'my_following_vm.dart';
 
 // **************************************************************************
 // RiverpodGenerator
 // **************************************************************************
 
-String _$garageRepositoryHash() => r'93e545c5f107ba1eb1f1e188d7a4744046d0da64';
+String _$myFollowingVmHash() => r'25a5afa320dc906371f23c97e9b23131fa686a70';
 
-/// See also [garageRepository].
-@ProviderFor(garageRepository)
-final garageRepositoryProvider = Provider<GarageRepository>.internal(
-  garageRepository,
-  name: r'garageRepositoryProvider',
+/// See also [MyFollowingVm].
+@ProviderFor(MyFollowingVm)
+final myFollowingVmProvider =
+    AutoDisposeNotifierProvider<MyFollowingVm, MyFollowingState>.internal(
+  MyFollowingVm.new,
+  name: r'myFollowingVmProvider',
   debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
       ? null
-      : _$garageRepositoryHash,
+      : _$myFollowingVmHash,
   dependencies: null,
   allTransitiveDependencies: null,
 );
 
-@Deprecated('Will be removed in 3.0. Use Ref instead')
-// ignore: unused_element
-typedef GarageRepositoryRef = ProviderRef<GarageRepository>;
+typedef _$MyFollowingVm = AutoDisposeNotifier<MyFollowingState>;
 // 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

+ 109 - 8
packages/cpt_community/lib/modules/my_posts/my_posts_forrent/my_posts_forrent_page.dart

@@ -1,10 +1,25 @@
-import 'package:cpt_community/router/page/community_page_router.dart';
-import 'package:cs_resources/theme/app_colors_theme.dart';
+import 'package:cs_resources/generated/assets.dart';
 import 'package:flutter/material.dart';
 import 'package:auto_route/auto_route.dart';
+import 'package:flutter/rendering.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: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';
+import 'package:widgets/my_text_view.dart';
 import 'package:widgets/my_appbar.dart';
+import 'package:cs_resources/theme/app_colors_theme.dart';
+import 'package:widgets/widget_export.dart';
+
+import '../../../components/garage_card.dart';
+import '../../../components/newfeed_card_header.dart';
+import '../../../router/page/community_page_router.dart';
+import 'my_posts_forrent_vm.dart';
 
 @RoutePage()
 class MyPostsForRentPage extends HookConsumerWidget {
@@ -21,18 +36,104 @@ class MyPostsForRentPage extends HookConsumerWidget {
 
   @override
   Widget build(BuildContext context, WidgetRef ref) {
-    // final viewModel = ref.watch(newsfeedPostVmProvider.notifier);
+    final vm = ref.read(myPostsForRentVmProvider.notifier);
+    final state = ref.watch(myPostsForRentVmProvider);
+    useEffect(() {
+      // 组件挂载时执行 - 执行接口请求
+      Future.microtask(() => vm.initPageData());
+      return () {
+        // 组件卸载时执行
+        Log.d("garage_forrent_page 组件卸载时执行");
+      };
+    }, []);
 
     return Scaffold(
       // appBar: MyAppBar.appBar(
       //   context,
-      //   "My Posts",
+      //   "MyPostsForRent",
       //   backgroundColor: context.appColors.whiteBG,
       // ),
-      backgroundColor: context.appColors.backgroundDefault,
-      body: Center(
-        child: Text("myposts-forrent"),
+      backgroundColor: ColorUtils.string2Color("#F2F3F6"),
+      body: SizedBox(
+          width: double.infinity,
+          height: double.infinity,
+          child: EasyRefresh(
+            controller: vm.refreshController,
+            // 上拉加载
+            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.85, // 宽高比
+                  ),
+                  delegate: SliverChildBuilderDelegate(
+                        (context, index) {
+                      return  _buildMyPostsForRentItem(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 _buildMyPostsForRentItem(BuildContext context, WidgetRef ref, item, vm){
+    return SizedBox(
+      width: double.infinity,
+      child: Container(
+        decoration: BoxDecoration(
+          color: context.appColors.whiteBG,
+          borderRadius: BorderRadius.circular(8),
+          boxShadow: [
+            BoxShadow(
+              color: ColorUtils.string2Color('#E5E5E5'),
+              offset: const Offset(0, 2),
+              blurRadius: 8,
+            ),
+          ],
+        ),
+        child: Column(
+            mainAxisAlignment: MainAxisAlignment.start,
+            crossAxisAlignment: CrossAxisAlignment.start,
+            mainAxisSize: MainAxisSize.max,
+            children: [
+              // 卡片头部(头像 标题 时间)
+              Expanded(
+                child: GarageCard(
+                    key: UniqueKey(),
+                    useType: GarageCardUseType.myPostsForRent,
+                    itemObj: item,
+                    onClickColleciotn: (dynamic collectionValue){
+                      Log.d("点击了收藏按钮  --${item['id']}-$collectionValue");
+                      return true;
+                    }
+                ),
+              ),
+            ]
+        ),
       ),
     );
   }
-}
+}

+ 0 - 0
packages/cpt_community/lib/modules/my_posts/my_posts_forrent/my_posts_forrent_respository.dart


+ 74 - 0
packages/cpt_community/lib/modules/my_posts/my_posts_forrent/my_posts_forrent_state.dart

@@ -0,0 +1,74 @@
+import 'package:widgets/load_state_layout.dart';
+
+class MyPostsForRentState {
+  int? activeTabIndex =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'];
+
+  MyPostsForRentState({
+    this.activeTabIndex,
+    this.loadingState = LoadState.State_Loading,
+    String? errorMessage,
+    this.curPage = 1,
+    this.pageSize = 10,
+    this.filterCount = 0,
+    required this.list,
+    this.tabsList,
+  });
+
+  MyPostsForRentState copyWith({
+    int? activeTabIndex,
+    LoadState? loadingState,
+    String? errorMessage,
+    int? curPage,
+    int? pageSize,
+    int? filterCount,
+    List<Map<String, dynamic>>? list,
+    List<String>? tabsList,
+  }) {
+    return MyPostsForRentState(
+      activeTabIndex: activeTabIndex ?? this.activeTabIndex,
+      loadingState: loadingState ?? this.loadingState,
+      errorMessage: errorMessage ?? this.errorMessage,
+      curPage: curPage ?? this.curPage,
+      pageSize: pageSize ?? this.pageSize,
+      filterCount: filterCount ?? this.filterCount,
+      tabsList: tabsList ?? this.tabsList,
+      list: list ?? this.list,
+    );
+  }
+
+  Map<String, dynamic> toMap() {
+    return {
+      'activeTabIndex': this.activeTabIndex,
+      'loadingState': this.loadingState,
+      'errorMessage': this.errorMessage,
+      'curPage': this.curPage,
+      'pageSize': this.pageSize,
+      'filterCount': this.filterCount,
+      'list': this.list,
+      'tabsList': this.tabsList,
+    };
+  }
+
+  factory MyPostsForRentState.fromMap(Map<String, dynamic> map) {
+    return MyPostsForRentState(
+      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,
+      list: map['list'] as List<Map<String, dynamic>>,
+      tabsList: map['tabsList'] as List<String>,
+    );
+  }
+}

+ 209 - 0
packages/cpt_community/lib/modules/my_posts/my_posts_forrent/my_posts_forrent_vm.dart

@@ -0,0 +1,209 @@
+import 'package:cpt_community/modules/my_posts/my_posts_vm.dart';
+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 'my_posts_forrent_respository.dart';
+import 'my_posts_forrent_state.dart';
+
+part 'my_posts_forrent_vm.g.dart';
+
+@riverpod
+class MyPostsForRentVm extends _$MyPostsForRentVm {
+  // late MyPostsForRentRepository MyPostsForRentRepositoryInstance;
+  bool _needShowPlaceholder = true; //是否展示LoadingView
+
+  // Refresh 控制器
+  final EasyRefreshController refreshController = EasyRefreshController(
+    controlFinishRefresh: true,  //允许刷新
+    controlFinishLoad: true,   //允许加载
+  );
+
+  MyPostsForRentState initState() {
+    return MyPostsForRentState(
+        list: []
+    );
+  }
+
+  @override
+  MyPostsForRentState build(){
+    // 引入数据仓库
+    // MyPostsForRentRepositoryInstance = ref.read(newsRepositoryProvider);
+    final state = initState();
+    Log.d("--------------------------build---------------------");
+
+    return state;
+  }
+
+
+  //刷新页面状态
+  void changeLoadingState(LoadState loadState, String? errorMsg) {
+    state = state.copyWith(
+        loadingState: loadState,
+        errorMessage: errorMsg
+    );
+  }
+
+  // 初始化页面数据
+  initPageData() {
+    Log.d("----for_sale_vm-----initPageData   ${state.loadingState}");
+    onRefresh();
+  }
+
+  // 上拉加载 更多
+  Future loadMore() async {
+    Log.d("----for_sale_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() async {
+    Log.d("----forrent_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>() 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://img2.baidu.com/it/u=3489233687,2364672159&fm=253&fmt=auto&app=120&f=JPEG?w=507&h=500',
+        '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': 'https://img1.baidu.com/it/u=3890726495,1572750319&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500'
+      },
+      {
+        'id':2,
+        'goods_img':  'https://img2.baidu.com/it/u=3489233687,2364672159&fm=253&fmt=auto&app=120&f=JPEG?w=507&h=500',
+        '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': 'https://img1.baidu.com/it/u=3890726495,1572750319&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500'
+      },
+      {
+        'id':3,
+        'goods_img':  'https://img2.baidu.com/it/u=3489233687,2364672159&fm=253&fmt=auto&app=120&f=JPEG?w=507&h=500',
+        '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': 'https://img1.baidu.com/it/u=3890726495,1572750319&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500'
+      },
+    ];
+
+    if (state.curPage == 1) {
+      //刷新的方式
+      state = state.copyWith(list: listData);
+      refreshController.finishRefresh();
+      // //更新展示的状态
+      changeLoadingState(LoadState.State_Success, null);
+    } else {
+      //加载更多
+      final allList = state.list;
+      allList.addAll(listData);
+      state = state.copyWith(list: allList,);
+      refreshController.finishLoad();
+    }
+
+    // 需要更新 my_posts_tabs 里面的数字
+    // ref.read(myPostsVmProvider.notifier).updateMyPostsTabsNum( 'forSale', state.list.length, 1);
+
+    // 最后赋值
+    _needShowPlaceholder = false;
+  }
+
+
+  // 点击 like comments  share
+  void handlerClickActionBtn(String? actionStr, item){
+    final id = item['id'];
+    switch (actionStr) {
+      case 'like':
+        Log.d("点击了 点赞");
+        handlerGotoDetail(id);
+        break;
+      case 'comments':
+        Log.d("点击了 评论");
+        handlerGotoDetail(id);
+        break;
+      case 'share':
+        Log.d("点击了 分享");
+        handlerGotoDetail(id);
+        break;
+      default:
+        break;
+    }
+  }
+  // 去详情页面
+  void handlerGotoDetail(id){
+    Log.d("去详情页面");
+    appRouter.push(GaragesaleDetailPageRoute(id: id, type: 'forrent'));
+  }
+}

+ 26 - 0
packages/cpt_community/lib/modules/my_posts/my_posts_forrent/my_posts_forrent_vm.g.dart

@@ -0,0 +1,26 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'my_posts_forrent_vm.dart';
+
+// **************************************************************************
+// RiverpodGenerator
+// **************************************************************************
+
+String _$myPostsForRentVmHash() => r'1c21b636795250178ca2877dd0dd495474061ef2';
+
+/// See also [MyPostsForRentVm].
+@ProviderFor(MyPostsForRentVm)
+final myPostsForRentVmProvider =
+    AutoDisposeNotifierProvider<MyPostsForRentVm, MyPostsForRentState>.internal(
+  MyPostsForRentVm.new,
+  name: r'myPostsForRentVmProvider',
+  debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
+      ? null
+      : _$myPostsForRentVmHash,
+  dependencies: null,
+  allTransitiveDependencies: null,
+);
+
+typedef _$MyPostsForRentVm = AutoDisposeNotifier<MyPostsForRentState>;
+// 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

+ 110 - 8
packages/cpt_community/lib/modules/my_posts/my_posts_forsale/my_posts_forsale_page.dart

@@ -1,10 +1,25 @@
-import 'package:cpt_community/router/page/community_page_router.dart';
-import 'package:cs_resources/theme/app_colors_theme.dart';
+import 'package:cs_resources/generated/assets.dart';
 import 'package:flutter/material.dart';
 import 'package:auto_route/auto_route.dart';
+import 'package:flutter/rendering.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: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';
+import 'package:widgets/my_text_view.dart';
 import 'package:widgets/my_appbar.dart';
+import 'package:cs_resources/theme/app_colors_theme.dart';
+import 'package:widgets/widget_export.dart';
+
+import '../../../components/garage_card.dart';
+import '../../../components/newfeed_card_header.dart';
+import '../../../router/page/community_page_router.dart';
+import 'my_posts_forsale_vm.dart';
 
 @RoutePage()
 class MyPostsForSalePage extends HookConsumerWidget {
@@ -21,18 +36,105 @@ class MyPostsForSalePage extends HookConsumerWidget {
 
   @override
   Widget build(BuildContext context, WidgetRef ref) {
-    // final viewModel = ref.watch(newsfeedPostVmProvider.notifier);
+    final vm = ref.read(myPostsForSaleVmProvider.notifier);
+    final state = ref.watch(myPostsForSaleVmProvider);
+    useEffect(() {
+      vm.setCurrentPageContext(context);
+      // 组件挂载时执行 - 执行接口请求
+      Future.microtask(() => vm.initPageData());
+      return () {
+        // 组件卸载时执行
+        Log.d("garage_forsale_page 组件卸载时执行");
+      };
+    }, []);
 
     return Scaffold(
       // appBar: MyAppBar.appBar(
       //   context,
-      //   "My Posts",
+      //   "MyPostsForSale",
       //   backgroundColor: context.appColors.whiteBG,
       // ),
-      backgroundColor: context.appColors.backgroundDefault,
-      body: Center(
-        child: Text("myposts-forsale"),
+      backgroundColor: ColorUtils.string2Color("#F2F3F6"),
+      body: SizedBox(
+          width: double.infinity,
+          height: double.infinity,
+          child: EasyRefresh(
+            controller: vm.refreshController,
+            // 上拉加载
+            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.85, // 宽高比
+                  ),
+                  delegate: SliverChildBuilderDelegate(
+                        (context, index) {
+                      return  _buildMyPostsForSaleItem(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 _buildMyPostsForSaleItem(BuildContext context, WidgetRef ref, item, vm){
+    return SizedBox(
+      width: double.infinity,
+      child: Container(
+        decoration: BoxDecoration(
+          color: context.appColors.whiteBG,
+          borderRadius: BorderRadius.circular(8),
+          boxShadow: [
+            BoxShadow(
+              color: ColorUtils.string2Color('#E5E5E5'),
+              offset: const Offset(0, 2),
+              blurRadius: 8,
+            ),
+          ],
+        ),
+        child: Column(
+            mainAxisAlignment: MainAxisAlignment.start,
+            crossAxisAlignment: CrossAxisAlignment.start,
+            mainAxisSize: MainAxisSize.max,
+            children: [
+              // 卡片头部(头像 标题 时间)
+              Expanded(
+                child: GarageCard(
+                    key: UniqueKey(),
+                    useType: GarageCardUseType.myPostsForSale,
+                    itemObj: item,
+                    onClickColleciotn: (dynamic collectionValue){
+                      Log.d("点击了收藏按钮  --${item['id']}-$collectionValue");
+                      return true;
+                    }
+                ),
+              ),
+            ]
+        ),
       ),
     );
   }
-}
+}

+ 0 - 0
packages/cpt_community/lib/modules/my_posts/my_posts_forsale/my_posts_forsale_respository.dart


+ 74 - 0
packages/cpt_community/lib/modules/my_posts/my_posts_forsale/my_posts_forsale_state.dart

@@ -0,0 +1,74 @@
+import 'package:widgets/load_state_layout.dart';
+
+class MyPostsForSaleState {
+  int? activeTabIndex =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'];
+
+  MyPostsForSaleState({
+    this.activeTabIndex,
+    this.loadingState = LoadState.State_Loading,
+    String? errorMessage,
+    this.curPage = 1,
+    this.pageSize = 10,
+    this.filterCount = 0,
+    required this.list,
+    this.tabsList,
+  });
+
+  MyPostsForSaleState copyWith({
+    int? activeTabIndex,
+    LoadState? loadingState,
+    String? errorMessage,
+    int? curPage,
+    int? pageSize,
+    int? filterCount,
+    List<Map<String, dynamic>>? list,
+    List<String>? tabsList,
+  }) {
+    return MyPostsForSaleState(
+      activeTabIndex: activeTabIndex ?? this.activeTabIndex,
+      loadingState: loadingState ?? this.loadingState,
+      errorMessage: errorMessage ?? this.errorMessage,
+      curPage: curPage ?? this.curPage,
+      pageSize: pageSize ?? this.pageSize,
+      filterCount: filterCount ?? this.filterCount,
+      tabsList: tabsList ?? this.tabsList,
+      list: list ?? this.list,
+    );
+  }
+
+  Map<String, dynamic> toMap() {
+    return {
+      'activeTabIndex': this.activeTabIndex,
+      'loadingState': this.loadingState,
+      'errorMessage': this.errorMessage,
+      'curPage': this.curPage,
+      'pageSize': this.pageSize,
+      'filterCount': this.filterCount,
+      'list': this.list,
+      'tabsList': this.tabsList,
+    };
+  }
+
+  factory MyPostsForSaleState.fromMap(Map<String, dynamic> map) {
+    return MyPostsForSaleState(
+      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,
+      list: map['list'] as List<Map<String, dynamic>>,
+      tabsList: map['tabsList'] as List<String>,
+    );
+  }
+}

+ 257 - 0
packages/cpt_community/lib/modules/my_posts/my_posts_forsale/my_posts_forsale_vm.dart

@@ -0,0 +1,257 @@
+import 'package:cpt_community/modules/my_posts/my_posts_vm.dart';
+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 'package:auto_route/auto_route.dart';
+
+import '../../../router/page/community_page_router.dart';
+import 'my_posts_forsale_respository.dart';
+import 'my_posts_forsale_state.dart';
+
+part 'my_posts_forsale_vm.g.dart';
+
+@riverpod
+class MyPostsForSaleVm extends _$MyPostsForSaleVm {
+  // late MyPostsForSaleRepository MyPostsForSaleRepositoryInstance;
+  late BuildContext _currentPageContext;
+
+  bool _needShowPlaceholder = true; //是否展示LoadingView
+
+  // Refresh 控制器
+  final EasyRefreshController refreshController = EasyRefreshController(
+    controlFinishRefresh: true,  //允许刷新
+    controlFinishLoad: true,   //允许加载
+  );
+
+  MyPostsForSaleState initState() {
+    return MyPostsForSaleState(
+        list: []
+    );
+  }
+
+  @override
+  MyPostsForSaleState build(){
+    // 引入数据仓库
+    // MyPostsForSaleRepositoryInstance = ref.read(newsRepositoryProvider);
+    final state = initState();
+    Log.d("--------------------------build---------------------");
+
+    return state;
+  }
+
+
+  //刷新页面状态
+  void changeLoadingState(LoadState loadState, String? errorMsg) {
+    state = state.copyWith(
+        loadingState: loadState,
+        errorMessage: errorMsg
+    );
+  }
+
+  setCurrentPageContext(BuildContext context){
+    _currentPageContext = context;
+  }
+  // 初始化页面数据
+  initPageData() {
+    Log.d("----for_sale_vm-----initPageData   ${state.loadingState}");
+    onRefresh();
+  }
+
+  // 上拉加载 更多
+  Future loadMore() async {
+    Log.d("----for_sale_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() async {
+    Log.d("----forsale_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>() 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://img2.baidu.com/it/u=3489233687,2364672159&fm=253&fmt=auto&app=120&f=JPEG?w=507&h=500',
+        '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': 'https://img1.baidu.com/it/u=3890726495,1572750319&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500'
+      },
+      {
+        'id':2,
+        'goods_img':  'https://img2.baidu.com/it/u=3489233687,2364672159&fm=253&fmt=auto&app=120&f=JPEG?w=507&h=500',
+        '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': 'https://img1.baidu.com/it/u=3890726495,1572750319&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500'
+      },
+      {
+        'id':3,
+        'goods_img':  'https://img2.baidu.com/it/u=3489233687,2364672159&fm=253&fmt=auto&app=120&f=JPEG?w=507&h=500',
+        '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': 'https://img1.baidu.com/it/u=3890726495,1572750319&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500'
+      },
+      {
+        'id':4,
+        'goods_img':  'https://img2.baidu.com/it/u=3489233687,2364672159&fm=253&fmt=auto&app=120&f=JPEG?w=507&h=500',
+        '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': 'https://img1.baidu.com/it/u=3890726495,1572750319&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500'
+      },
+      {
+        'id':5,
+        'goods_img':  'https://img2.baidu.com/it/u=3489233687,2364672159&fm=253&fmt=auto&app=120&f=JPEG?w=507&h=500',
+        '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': 'https://img1.baidu.com/it/u=3890726495,1572750319&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500'
+      },
+      {
+        'id':6,
+        'goods_img':  'https://img2.baidu.com/it/u=3489233687,2364672159&fm=253&fmt=auto&app=120&f=JPEG?w=507&h=500',
+        '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': 'https://img1.baidu.com/it/u=3890726495,1572750319&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500'
+      },
+    ];
+
+    if (state.curPage == 1) {
+      //刷新的方式
+      state = state.copyWith(list: listData);
+      refreshController.finishRefresh();
+      // //更新展示的状态
+      changeLoadingState(LoadState.State_Success, null);
+    } else {
+      //加载更多
+      final allList = state.list;
+      allList.addAll(listData);
+      state = state.copyWith(list: allList,);
+      refreshController.finishLoad();
+    }
+
+
+    // if(_currentPageContext != null){
+    //   Log.d("994444  $_currentPageContext");
+    //   WidgetsBinding.instance.addPostFrameCallback((_) {
+    //     if (_currentPageContext != null) {
+    //       // 需要更新 my_posts_tabs 里面的数字
+    //       // ref.read(myPostsVmProvider.notifier).updateMyPostsTabsNum( 'forSale', state.list.length, 1);
+    //       // AutoTabsRouter.of(_currentPageContext!).setActiveIndex(1);
+    //     }
+    //   });
+    // }
+
+    // 最后赋值
+    _needShowPlaceholder = false;
+  }
+
+
+  // 点击 like comments  share
+  void handlerClickActionBtn(String? actionStr, item){
+    final id = item['id'];
+    switch (actionStr) {
+      case 'like':
+        Log.d("点击了 点赞");
+        handlerGotoDetail(id);
+        break;
+      case 'comments':
+        Log.d("点击了 评论");
+        handlerGotoDetail(id);
+        break;
+      case 'share':
+        Log.d("点击了 分享");
+        handlerGotoDetail(id);
+        break;
+      default:
+        break;
+    }
+  }
+  // 去详情页面
+  void handlerGotoDetail(id){
+    Log.d("去详情页面");
+    appRouter.push(GaragesaleDetailPageRoute(id: id, type: 'forsale'));
+  }
+}

+ 26 - 0
packages/cpt_community/lib/modules/my_posts/my_posts_forsale/my_posts_forsale_vm.g.dart

@@ -0,0 +1,26 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'my_posts_forsale_vm.dart';
+
+// **************************************************************************
+// RiverpodGenerator
+// **************************************************************************
+
+String _$myPostsForSaleVmHash() => r'6894e45314a1131fd4ff967a031aebd29614ec40';
+
+/// See also [MyPostsForSaleVm].
+@ProviderFor(MyPostsForSaleVm)
+final myPostsForSaleVmProvider =
+    AutoDisposeNotifierProvider<MyPostsForSaleVm, MyPostsForSaleState>.internal(
+  MyPostsForSaleVm.new,
+  name: r'myPostsForSaleVmProvider',
+  debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
+      ? null
+      : _$myPostsForSaleVmHash,
+  dependencies: null,
+  allTransitiveDependencies: null,
+);
+
+typedef _$MyPostsForSaleVm = AutoDisposeNotifier<MyPostsForSaleState>;
+// 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

+ 13 - 2
packages/cpt_community/lib/modules/my_posts/my_posts_page.dart

@@ -31,6 +31,7 @@ class MyPostsPage extends HookConsumerWidget {
     BuildContext pageContext = context;
     final vm = ref.watch(myPostsVmProvider.notifier);
     final state = ref.watch(myPostsVmProvider);
+    var _pageController = null;
     // // 创建 GlobalKey
     // final GlobalKey<AutoTabsRouterState> _tabsRouterKey = GlobalKey<AutoTabsRouterState>();
     return Scaffold(
@@ -50,10 +51,20 @@ class MyPostsPage extends HookConsumerWidget {
                 MyPostsForSalePageRoute(),
                 MyPostsForRentPageRoute()
               ],
-              builder: (context, child, animation) {
+              builder: (context, child, pageController) {
                 final tabsRouter = AutoTabsRouter.of(context);
+                tabsRouter.addListener((){
+                  int currentIndex = tabsRouter.activeIndex;
+                  Log.d("MyPostsPage onPageChanged: $currentIndex");
+                  // vm.handlerChangeTab(context, currentIndex);
+                  // vm.setCurrentTabIndex(currentIndex);
+                });
+                // 恢复页面索引
+                // vm.restorePageViewIndex(pageController);
+
                 return Column(
                   children: [
+                    // tab 标签
                     _buildHeaderTabs(context, ref, state),
                     Expanded(
                       child: child,
@@ -72,7 +83,7 @@ class MyPostsPage extends HookConsumerWidget {
   Widget _buildHeaderTabs(BuildContext context, WidgetRef ref, state) {
     final vm = ref.read(myPostsVmProvider.notifier);
     return Container(
-      color: Colors.blue,
+      color: context.appColors.textWhite,
       child: MyPostsTab(
         key: UniqueKey(),
         tabsList: state.tabsList,

+ 55 - 37
packages/cpt_community/lib/modules/my_posts/my_posts_tabs.dart

@@ -29,48 +29,66 @@ class MyPostsTab extends HookConsumerWidget {
 
   Widget _buildTabItem(BuildContext context, WidgetRef ref, vm, item, index) {
     Log.d("MyPostsTab _buildTabItem index: ${vm.state.tabsList}");
-    // Log.d("MyPostsTab _buildTabItem index: ${vm.state.activeTabIdx}");
-    // 监听 activeTabIdx 的变化
-    // final activeTabIdx = ref.watch(communityVmProvider.select((state) => state.activeTabIdx));
 
     final activeTabIdx = AutoTabsRouter.of(context).activeIndex;
+    final isLast = index == tabsList.length - 1;
 
-    // Log.d("MyPostsTab _buildTabItem activeTabIdx: $activeTabIdx");
-    return Container(
-      width: MediaQuery.of(context).size.width / vm.state.tabsList.length - 30,
-      height: 43,
-      padding: const EdgeInsets.only(top: 10, bottom: 10, left: 10, right: 10),
-      decoration: index==activeTabIdx? BoxDecoration(
-        color: index==activeTabIdx? context.appColors.btnBgDefault: ColorUtils.string2Color("#F2F3F6"),
-        borderRadius: BorderRadius.circular(20),
-        boxShadow: [
-          BoxShadow(
-            color: Colors.grey.withOpacity(0.5),
-            spreadRadius: 1,
-            blurRadius: 5,
-            offset: const Offset(0, 2), // changes position of shadow
-          ),
-        ],
-      ): null,
-      child: Row(
-        children: [
-          Expanded(
-            child: Container(
-              alignment: Alignment.center,
-              child: MyTextView(
-                item!['title'],
-                fontSize: 16,
-                textAlign: TextAlign.center,
-                isFontMedium: true,
-                textColor: index == activeTabIdx ? Colors.white :ColorUtils.string2Color("#000000"),
+    return Row(
+      children: [
+        Container(
+          width: MediaQuery.of(context).size.width / vm.state.tabsList.length - 5,
+          padding: const EdgeInsets.only(top: 10, bottom: 10, left: 10, right: 10),
+          decoration: index==activeTabIdx? BoxDecoration(
+            color: context.appColors.textWhite,
+            // borderRadius: BorderRadius.circular(20),
+            border: Border(
+              bottom: BorderSide(
+                color: context.appColors.textPrimary,
+                width: 2,
               ),
-            ).onTap((){
-              print("newsfeed_tabs 中点击的tab index:  $index");
-              onClickAction?.call(index);
-            }),
+            ),
+          ): null,
+          child: Row(
+            children: [
+              Expanded(
+                child: Column(
+                  children: [
+                    Container(
+                      alignment: Alignment.center,
+                      child: MyTextView(
+                        item!['publish_num'].toString(),
+                        fontSize: 15,
+                        textAlign: TextAlign.center,
+                        isFontMedium: true,
+                        textColor: index == activeTabIdx ? context.appColors.textPrimary : context.appColors.textBlack,
+                      ),
+                    ),
+                    const SizedBox(height: 5,),
+                    Container(
+                      alignment: Alignment.center,
+                      child: MyTextView(
+                        item!['title'],
+                        fontSize: 15,
+                        textAlign: TextAlign.center,
+                        isFontMedium: true,
+                        textColor: index == activeTabIdx ? context.appColors.textPrimary : context.appColors.textBlack,
+                      ),
+                    ),
+                  ],
+                ).onTap((){
+                  Log.d("newsfeed_tabs 中点击的tab index:  $index");
+                  onClickAction?.call(index);
+                }),
+              ),
+            ],
           ),
-        ],
-      ),
+        ),
+        isLast? const SizedBox.shrink(): Container(
+          width: 1,
+          height: 60,
+          color: context.appColors.grayBgE9,
+        )
+      ],
     );
   }
 

+ 24 - 3
packages/cpt_community/lib/modules/my_posts/my_posts_vm.dart

@@ -18,6 +18,8 @@ part 'my_posts_vm.g.dart';
 class MyPostsVm extends _$MyPostsVm {
   // late MyPostsRepository MyPostsRepositoryInstance;
 
+  int _currentPageIndex = 0;
+
   bool _needShowPlaceholder = true; //是否展示LoadingView
   // Refresh 控制器
   final EasyRefreshController refreshController = EasyRefreshController(
@@ -48,19 +50,38 @@ class MyPostsVm extends _$MyPostsVm {
   }
 
   @override
-   build(){
+  MyPostsState build(){
     // 引入数据仓库
     // MyPostsRepositoryInstance = ref.read(newsRepositoryProvider);
-    final state = initState();
+    MyPostsState state = initState();
     Log.d("--------------------------build---------------------");
-
     return state;
   }
 
+
   // 设置当前的 tabsRouter 和 pageController
   handlerChangeTab(BuildContext context, int activeTabIdx) {
     Log.d("handlerChangeTab: $activeTabIdx");
     final tabsRouter = AutoTabsRouter.of(context);
     tabsRouter.setActiveIndex(activeTabIdx);
   }
+
+  setCurrentTabIndex(int activeTabIdx){
+    state = state.copyWith(
+      activeTabIdx: activeTabIdx,
+    );
+  }
+
+  updateMyPostsTabsNum(String code, int num, int activeTabIdx){
+    state = state.copyWith(
+      tabsList: state.tabsList?.map((e) {
+        if(e['code'] == code){
+          e['publish_num'] = num;
+        }
+        return e;
+      }).toList(),
+      activeTabIdx: 1,
+    );
+  }
+
 }

+ 3 - 3
packages/cpt_community/lib/modules/my_posts/my_posts_vm.g.dart

@@ -6,12 +6,12 @@ part of 'my_posts_vm.dart';
 // RiverpodGenerator
 // **************************************************************************
 
-String _$myPostsVmHash() => r'c34f116d3e53ad01725f996da557a0132d687980';
+String _$myPostsVmHash() => r'3bc495c4d4180bbc0081b607a2ffa3c2e172ba91';
 
 /// See also [MyPostsVm].
 @ProviderFor(MyPostsVm)
 final myPostsVmProvider =
-    AutoDisposeNotifierProvider<MyPostsVm, Object?>.internal(
+    AutoDisposeNotifierProvider<MyPostsVm, MyPostsState>.internal(
   MyPostsVm.new,
   name: r'myPostsVmProvider',
   debugGetCreateSourceHash:
@@ -20,6 +20,6 @@ final myPostsVmProvider =
   allTransitiveDependencies: null,
 );
 
-typedef _$MyPostsVm = AutoDisposeNotifier<Object?>;
+typedef _$MyPostsVm = AutoDisposeNotifier<MyPostsState>;
 // 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

+ 16 - 0
packages/cpt_community/lib/router/component/community_component_service.dart

@@ -1,6 +1,7 @@
 /*
  * Community 组件的组件路由
  */
+import 'package:cpt_community/router/page/community_page_router.dart';
 import 'package:flutter/cupertino.dart';
 import 'package:router/componentRouter/community_service.dart';
 import 'package:flutter/material.dart';
@@ -8,6 +9,9 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
 import 'package:riverpod_annotation/riverpod_annotation.dart';
 
 import '../../modules/community/community_page.dart';
+import '../../modules/my_following/my_follow/my_follow_page.dart';
+import '../../modules/my_following/my_follower/my_follower_page.dart';
+import '../../modules/my_posts/my_posts_page.dart';
 
 part 'community_component_service.g.dart';
 
@@ -22,4 +26,16 @@ class CommunityComponentService extends CommunityService {
     CommunityPage.startInstance();
   }
 
+  void startMyPostsPage() {
+    MyPostsPage.startInstance();
+  }
+
+  void startMyFollowPage() {
+    MyFollowPage.startInstance();
+  }
+
+  void startMyFollowerPage() {
+    MyFollowerPage.startInstance();
+  }
+
 }

+ 32 - 20
packages/cpt_community/lib/router/page/community_page_router.dart

@@ -11,7 +11,6 @@ import '../../modules/community/newsfeed_detail/newsfeed_detail_page.dart';
 import '../../modules/community/newsfeed_post/newsfeed_post_page.dart';
 // import '../../modules/community/newsfeed_myposts/newsfeed_myposts_page.dart';
 
-import '../../modules/garage/garage_page.dart';
 import '../../modules/garage/for_sale/for_sale_page.dart';
 import '../../modules/garage/for_rent/for_rent_page.dart';
 import '../../modules/garage/garagesale_detail/garagesale_detail_page.dart';
@@ -23,6 +22,10 @@ import '../../modules/my_posts/my_posts_newsfeed/my_posts_newsfeed_page.dart';
 import '../../modules/my_posts/my_posts_forrent/my_posts_forrent_page.dart';
 import '../../modules/my_posts/my_posts_forsale/my_posts_forsale_page.dart';
 
+import '../../modules/my_following/my_following_page.dart';
+import '../../modules/my_following/my_follow/my_follow_page.dart';
+import '../../modules/my_following/my_follower/my_follower_page.dart';
+
 
 
 
@@ -59,6 +62,17 @@ class CommunityPageRouter extends _$CommunityPageRouter {
                 path: RouterPath.newsfeedForYou,
                 transitionsBuilder: applySlideTransition,
             ),
+            CustomRoute(
+              page: ForsalePageRoute.page,
+              path: RouterPath.garageForSale,
+              transitionsBuilder: applySlideTransition,
+            ),
+            // garageSale-forRent page
+            CustomRoute(
+              page: ForrentPageRoute.page,
+              path: RouterPath.garageForRent,
+              transitionsBuilder: applySlideTransition,
+            )
         ],
     ),
     CustomRoute(
@@ -73,25 +87,6 @@ class CommunityPageRouter extends _$CommunityPageRouter {
     ),
     // Garage
     CustomRoute(
-      page: GaragePageRoute.page,
-      path: RouterPath.garage,
-      transitionsBuilder: applySlideTransition,
-      children: [
-        // garageSale-forSale page
-        CustomRoute(
-          page: ForsalePageRoute.page,
-          path: RouterPath.garageForSale,
-          transitionsBuilder: applySlideTransition,
-        ),
-        // garageSale-forRent page
-        CustomRoute(
-          page: ForrentPageRoute.page,
-          path: RouterPath.garageForRent,
-          transitionsBuilder: applySlideTransition,
-        )
-      ]
-    ),
-    CustomRoute(
       page: GaragesalePostPageRoute.page,
       path: RouterPath.garageSalePost,
       transitionsBuilder: applySlideTransition,
@@ -126,5 +121,22 @@ class CommunityPageRouter extends _$CommunityPageRouter {
         )
       ]
     ),
+    CustomRoute(
+        page: MyFollowingPageRoute.page,
+        path: RouterPath.myFollowing,
+        transitionsBuilder: applySlideTransition,
+        children: [
+          CustomRoute(
+            page: MyFollowPageRoute.page,
+            path: RouterPath.myFollowingFollow,
+            transitionsBuilder: applySlideTransition,
+          ),
+          CustomRoute(
+            page: MyFollowerPageRoute.page,
+            path: RouterPath.myFollowingFollower,
+            transitionsBuilder: applySlideTransition,
+          ),
+        ]
+    ),
   ];
 }

+ 60 - 20
packages/cpt_community/lib/router/page/community_page_router.gr.dart

@@ -45,12 +45,6 @@ abstract class _$CommunityPageRouter extends RootStackRouter {
         child: const ForyouPage(),
       );
     },
-    GaragePageRoute.name: (routeData) {
-      return AutoRoutePage<dynamic>(
-        routeData: routeData,
-        child: const GaragePage(),
-      );
-    },
     GaragesaleDetailPageRoute.name: (routeData) {
       final args = routeData.argsAs<GaragesaleDetailPageRouteArgs>();
       return AutoRoutePage<dynamic>(
@@ -68,6 +62,24 @@ abstract class _$CommunityPageRouter extends RootStackRouter {
         child: const GaragesalePostPage(),
       );
     },
+    MyFollowPageRoute.name: (routeData) {
+      return AutoRoutePage<dynamic>(
+        routeData: routeData,
+        child: const MyFollowPage(),
+      );
+    },
+    MyFollowerPageRoute.name: (routeData) {
+      return AutoRoutePage<dynamic>(
+        routeData: routeData,
+        child: const MyFollowerPage(),
+      );
+    },
+    MyFollowingPageRoute.name: (routeData) {
+      return AutoRoutePage<dynamic>(
+        routeData: routeData,
+        child: const MyFollowingPage(),
+      );
+    },
     MyPostsForRentPageRoute.name: (routeData) {
       return AutoRoutePage<dynamic>(
         routeData: routeData,
@@ -189,20 +201,6 @@ class ForyouPageRoute extends PageRouteInfo<void> {
 }
 
 /// generated route for
-/// [GaragePage]
-class GaragePageRoute extends PageRouteInfo<void> {
-  const GaragePageRoute({List<PageRouteInfo>? children})
-      : super(
-          GaragePageRoute.name,
-          initialChildren: children,
-        );
-
-  static const String name = 'GaragePageRoute';
-
-  static const PageInfo<void> page = PageInfo<void>(name);
-}
-
-/// generated route for
 /// [GaragesaleDetailPage]
 class GaragesaleDetailPageRoute
     extends PageRouteInfo<GaragesaleDetailPageRouteArgs> {
@@ -261,6 +259,48 @@ class GaragesalePostPageRoute extends PageRouteInfo<void> {
 }
 
 /// generated route for
+/// [MyFollowPage]
+class MyFollowPageRoute extends PageRouteInfo<void> {
+  const MyFollowPageRoute({List<PageRouteInfo>? children})
+      : super(
+          MyFollowPageRoute.name,
+          initialChildren: children,
+        );
+
+  static const String name = 'MyFollowPageRoute';
+
+  static const PageInfo<void> page = PageInfo<void>(name);
+}
+
+/// generated route for
+/// [MyFollowerPage]
+class MyFollowerPageRoute extends PageRouteInfo<void> {
+  const MyFollowerPageRoute({List<PageRouteInfo>? children})
+      : super(
+          MyFollowerPageRoute.name,
+          initialChildren: children,
+        );
+
+  static const String name = 'MyFollowerPageRoute';
+
+  static const PageInfo<void> page = PageInfo<void>(name);
+}
+
+/// generated route for
+/// [MyFollowingPage]
+class MyFollowingPageRoute extends PageRouteInfo<void> {
+  const MyFollowingPageRoute({List<PageRouteInfo>? children})
+      : super(
+          MyFollowingPageRoute.name,
+          initialChildren: children,
+        );
+
+  static const String name = 'MyFollowingPageRoute';
+
+  static const PageInfo<void> page = PageInfo<void>(name);
+}
+
+/// generated route for
 /// [MyPostsForRentPage]
 class MyPostsForRentPageRoute extends PageRouteInfo<void> {
   const MyPostsForRentPageRoute({List<PageRouteInfo>? children})

+ 6 - 3
packages/cpt_main/lib/modules/me/me_view_model.dart

@@ -21,7 +21,8 @@ class MeViewModel extends _$MeViewModel {
 
   //去我的发布页面
   void gotoMyPostPage() {
-    ToastEngine.show("去我的发布页面");
+    // ToastEngine.show("去我的发布页面");
+    ComponentServiceManager().communityService.startMyPostsPage();
   }
 
   //去设置页面
@@ -31,12 +32,14 @@ class MeViewModel extends _$MeViewModel {
 
   //我的关注Tab
   void gotoFollowingPage() {
-    ToastEngine.show("我的关注Tab");
+    // ToastEngine.show("我的关注Tab");
+    ComponentServiceManager().communityService.startMyFollowPage();
   }
 
   //我的粉丝Tab
   void gotoFollowerPage() {
-    ToastEngine.show("我的粉丝Tab");
+    // ToastEngine.show("我的粉丝Tab");
+    ComponentServiceManager().communityService.startMyFollowerPage();
   }
 
   //编辑附加信息

+ 15 - 15
packages/cpt_property/lib/modules/ioan/property_ioan_page.dart

@@ -35,14 +35,14 @@ class PropertyIoanPage extends HookConsumerWidget {
       children: [
         MyTextView(
           "YY Home",
-          textColor: ColorUtils.string2Color('#000000'),
+          textColor: context.appColors.textBlack,
           fontSize: 27,
           isFontMedium: true,
           textAlign: TextAlign.center,
         ),
         MyTextView(
           "Find the best home loan for you",
-          textColor: ColorUtils.string2Color('#000000'),
+          textColor: context.appColors.textBlack,
           fontSize: 16,
           isFontRegular: true,
           marginBottom: 14,
@@ -163,13 +163,13 @@ class PropertyIoanPage extends HookConsumerWidget {
                       children: [
                         MyTextView(
                           "Floating",
-                          textColor: ColorUtils.string2Color('#000000'),
+                          textColor: context.appColors.textBlack,
                           fontSize: 14,
                           textAlign: TextAlign.center,
                         ),
                         MyTextView(
                           "Fixed",
-                          textColor: ColorUtils.string2Color('#000000'),
+                          textColor: context.appColors.textBlack,
                           fontSize: 14,
                           textAlign: TextAlign.center,
                           marginLeft: 50.5,
@@ -186,7 +186,7 @@ class PropertyIoanPage extends HookConsumerWidget {
                           children: [
                             MyTextView(
                               "3.08%",
-                              textColor: ColorUtils.string2Color('#000000'),
+                              textColor: context.appColors.textBlack,
                               fontSize: 16,
                               textAlign: TextAlign.center,
                               isFontMedium: true,
@@ -194,7 +194,7 @@ class PropertyIoanPage extends HookConsumerWidget {
                             ),
                             MyTextView(
                               "2.50%",
-                              textColor: ColorUtils.string2Color('#000000'),
+                              textColor: context.appColors.textBlack,
                               fontSize: 16,
                               textAlign: TextAlign.center,
                               isFontMedium: true,
@@ -207,7 +207,7 @@ class PropertyIoanPage extends HookConsumerWidget {
                           children: [
                             MyTextView(
                               "3.08%",
-                              textColor: ColorUtils.string2Color('#000000'),
+                              textColor: context.appColors.textBlack,
                               fontSize: 16,
                               textAlign: TextAlign.center,
                               isFontMedium: true,
@@ -215,7 +215,7 @@ class PropertyIoanPage extends HookConsumerWidget {
                             ),
                             MyTextView(
                               "2.50%",
-                              textColor: ColorUtils.string2Color('#000000'),
+                              textColor: context.appColors.textBlack,
                               fontSize: 16,
                               textAlign: TextAlign.center,
                               isFontMedium: true,
@@ -228,7 +228,7 @@ class PropertyIoanPage extends HookConsumerWidget {
                           children: [
                             MyTextView(
                               "3.08%",
-                              textColor: ColorUtils.string2Color('#000000'),
+                              textColor: context.appColors.textBlack,
                               fontSize: 16,
                               textAlign: TextAlign.center,
                               isFontMedium: true,
@@ -236,7 +236,7 @@ class PropertyIoanPage extends HookConsumerWidget {
                             ),
                             MyTextView(
                               "2.50%",
-                              textColor: ColorUtils.string2Color('#000000'),
+                              textColor: context.appColors.textBlack,
                               fontSize: 16,
                               textAlign: TextAlign.center,
                               isFontMedium: true,
@@ -263,7 +263,7 @@ class PropertyIoanPage extends HookConsumerWidget {
         children: [
           MyTextView(
             "The right advice to help you choose the best package in the market!",
-            textColor: ColorUtils.string2Color('#000000'),
+            textColor: context.appColors.textBlack,
             fontSize: 18,
             isFontMedium: true,
             marginTop: 20,
@@ -272,7 +272,7 @@ class PropertyIoanPage extends HookConsumerWidget {
           ),
           MyTextView(
             "-No Hidden Fees, We Are Out ToHelp You!-Interest Savings With Lowest RatesGuarantee-One-Stop Access to All The BanksPackages",
-            textColor: ColorUtils.string2Color('#000000'),
+            textColor: context.appColors.textBlack,
             fontSize: 15,
             textAlign: TextAlign.center,
             marginBottom: 20,
@@ -289,7 +289,7 @@ class PropertyIoanPage extends HookConsumerWidget {
         children: [
           MyTextView(
            "What do we offer?",
-            textColor: ColorUtils.string2Color('#000000'),
+            textColor: context.appColors.textBlack,
             fontSize: 18,
             isFontMedium: true,
             marginTop: 16.5,
@@ -316,7 +316,7 @@ class PropertyIoanPage extends HookConsumerWidget {
                     MyTextView(
                       offerTextInfoList[index]["title"],
                       fontSize: 15,
-                      textColor: ColorUtils.string2Color('#000000'),
+                      textColor: context.appColors.textBlack,
                       textAlign: TextAlign.center,
                     ),
                   ]
@@ -336,7 +336,7 @@ class PropertyIoanPage extends HookConsumerWidget {
       children: [
         MyTextView(
           "Our Partners",
-          textColor: ColorUtils.string2Color('#000000'),
+          textColor: context.appColors.textBlack,
           fontSize: 18,
           isFontMedium: true,
           marginBottom: 16.5,

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

@@ -1,5 +1,6 @@
 
 import 'package:cs_resources/generated/assets.dart';
+import 'package:cs_resources/theme/app_colors_theme.dart';
 import 'package:flutter/cupertino.dart';
 import 'package:plugin_platform/engine/dialog/dialog_engine.dart';
 import 'package:plugin_platform/engine/toast/toast_engine.dart';
@@ -147,7 +148,7 @@ class PropertyIoanVm extends _$PropertyIoanVm {
               children: [
                 MyTextView(
                   "Submit Request?",
-                  textColor: ColorUtils.string2Color('#000000'),
+                  textColor: context.appColors.textBlack,
                   textAlign: TextAlign.left,
                   fontWeight: FontWeight.w500,
                   fontSize: 21,

+ 6 - 0
packages/cs_router/lib/componentRouter/community_service.dart

@@ -5,4 +5,10 @@ abstract class CommunityService {
 
   void startCommunityPage();
 
+  void startMyPostsPage();
+
+  void startMyFollowPage();
+
+  void startMyFollowerPage();
+
 }

+ 11 - 2
packages/cs_router/lib/path/router_path.dart

@@ -43,17 +43,26 @@ class RouterPath {
   static const newsfeedNews = 'community/newsfeed_news';
   static const newsfeedFollowing = 'community/newsfeed_following';
   static const newsfeedForYou = 'community/newsfeed_for_you';
+  static const garageForSale = 'community/garage_for_sale';
+  static const garageForRent = 'community/garage_for_rent';
   static const newsFeedPost = '/newsfeed_post';
   static const newsFeedDetail = '/newsfeed_detail';
+
+
   static const garage = '/garage';
-  static const garageForSale = 'garage/garage_for_sale';
-  static const garageForRent = 'garage/garage_for_rent';
+
+
+  // static const garageForSale = 'garage/garage_for_sale';
+  // static const garageForRent = 'garage/garage_for_rent';
   static const garageSalePost = '/garage_sale_post';
   static const garageSaleDetail = '/garage_sale_detail';
   static const myPosts = '/my_posts';
   static const myPostsNewsfeed = 'my_posts/my_posts_newsfeed';
   static const myPostsForSale = 'my_posts/my_posts_for_sale';
   static const myPostsForRent = 'my_posts/my_posts_for_rent';
+  static const myFollowing = '/my_following';
+  static const myFollowingFollow = 'my_following/follow';
+  static const myFollowingFollower = 'my_following/follower';
 
 
   //设施

+ 105 - 95
packages/cs_widgets/lib/dialog/app_custom_dialog.dart

@@ -19,6 +19,9 @@ import '../no_shadow_scroll_behavior.dart';
 class AppCustomDialog extends StatelessWidget {
   String? title;
   String message;
+  double? dialogWidth;
+  double? contentBoxMaxHeight;
+  double? contentBoxMinHeight;
   Widget Function(BuildContext context)? messageBuilder;
   VoidCallback confirmAction;
   VoidCallback? cancelAction;
@@ -31,6 +34,9 @@ class AppCustomDialog extends StatelessWidget {
     required this.confirmAction,
     this.messageBuilder,
     this.title,
+    this.dialogWidth,
+    this.contentBoxMaxHeight = 500,
+    this.contentBoxMinHeight = 300,
     this.cancelAction,
     this.isShowCancelBtn = true,
     this.confirmTxt,
@@ -41,121 +47,125 @@ class AppCustomDialog extends StatelessWidget {
 
   Widget build(BuildContext context) {
     //使用一个 Column 为最外层容器,可以方便的视线 wrap_content 的效果
-    return Column(
-      crossAxisAlignment: CrossAxisAlignment.center,
-      mainAxisAlignment: MainAxisAlignment.center,
-      mainAxisSize: MainAxisSize.max,
-      children: [
-        //Title (如果使用 Container 为最外层容器则默认为 match_parent 的效果,除非我们限制宽度和最大高度最小高度)
-        Container(
-          width: double.infinity,
-          height: 55,
-          decoration: BoxDecoration(
-            color: context.appColors.btnBgDefault,
-            borderRadius: const BorderRadius.only(
-              topRight: Radius.circular(15),
-              topLeft: Radius.circular(15),
+    return SizedBox(
+      width: dialogWidth?? MediaQuery.of(context).size.width * 0.65,
+      child: Column(
+        crossAxisAlignment: CrossAxisAlignment.center,
+        mainAxisAlignment: MainAxisAlignment.center,
+        mainAxisSize: MainAxisSize.max,
+        children: [
+          //Title (如果使用 Container 为最外层容器则默认为 match_parent 的效果,除非我们限制宽度和最大高度最小高度)
+          Container(
+            width: double.infinity,
+            height: 55,
+            decoration: BoxDecoration(
+              color: context.appColors.btnBgDefault,
+              borderRadius: const BorderRadius.only(
+                topRight: Radius.circular(15),
+                topLeft: Radius.circular(15),
+              ),
             ),
-          ),
-          child: Row(
-            children: [
-              const SizedBox(width: 45),
-              MyTextView(
-                title ?? S.current.alert,
-                fontSize: 18,
-                textAlign: TextAlign.center,
-                isFontMedium: true,
-                textColor: Colors.white,
-              ).expanded(),
-              const MyAssetImage(Assets.baseServiceDialogDeleteIcon,width: 25,height: 25.5,).onTap((){
-                onCancel();
-              },padding: 10)
-            ],
+            child: Row(
+              children: [
+                const SizedBox(width: 45),
+                MyTextView(
+                  title ?? S.current.alert,
+                  fontSize: 18,
+                  textAlign: TextAlign.center,
+                  isFontMedium: true,
+                  textColor: Colors.white,
+                ).expanded(),
+                const MyAssetImage(Assets.baseServiceDialogDeleteIcon,width: 25,height: 25.5,).onTap((){
+                  onCancel();
+                },padding: 10)
+              ],
 
+            ),
           ),
-        ),
 
-        Container(
-          width: double.infinity,
-          padding: const EdgeInsets.only(top: 30),
-          decoration: BoxDecoration(
-            color: context.appColors.whiteSecondBG,
-            borderRadius: const BorderRadius.only(
-              bottomLeft: Radius.circular(15),
-              bottomRight: Radius.circular(15),
+          Container(
+            width: double.infinity,
+            // height: 500,
+            padding: const EdgeInsets.only(top: 30),
+            decoration: BoxDecoration(
+              color: context.appColors.whiteSecondBG,
+              borderRadius: const BorderRadius.only(
+                bottomLeft: Radius.circular(15),
+                bottomRight: Radius.circular(15),
+              ),
             ),
-          ),
-          child: Column(
-            children: [
-              Scrollbar(
-                child: ScrollConfiguration(
-                  behavior: NoShadowScrollBehavior(),
-                  child: SingleChildScrollView(
-                    child: message.isNotEmpty?MyTextView(
-                      message,
-                      fontSize: 18,
-                      textColor: context.appColors.textBlack,
-                      isFontRegular: true,
-                      textAlign: TextAlign.center,
-                      paddingLeft: 30,
-                      paddingRight: 30,
-                    ):  (messageBuilder != null ? messageBuilder!(context) : Container()),
+            child: Column(
+              children: [
+                Scrollbar(
+                  child: ScrollConfiguration(
+                    behavior: NoShadowScrollBehavior(),
+                    child: SingleChildScrollView(
+                      child: message.isNotEmpty?MyTextView(
+                        message,
+                        fontSize: 18,
+                        textColor: context.appColors.textBlack,
+                        isFontRegular: true,
+                        textAlign: TextAlign.center,
+                        paddingLeft: 30,
+                        paddingRight: 30,
+                      ):  (messageBuilder != null ? messageBuilder!(context) : Container()),
+                    ),
                   ),
-                ),
-              ).constrained(maxHeight: 210),
-              Row(
-                children: [
-                  const SizedBox(width: 18),
-                  Visibility(
-                    visible: isShowCancelBtn,
-                    child: Expanded(
+                ).constrained(maxHeight: contentBoxMaxHeight?? 300),
+                Row(
+                  children: [
+                    const SizedBox(width: 18),
+                    Visibility(
+                      visible: isShowCancelBtn,
+                      child: Expanded(
+                          flex: 1,
+                          child: InkWell(
+                            onTap: () {
+                              onCancel();
+                              cancelAction?.call();
+                            },
+                            child: MyTextView(
+                              cancelTxt ?? S.current.no,
+                              fontSize: 16,
+                              isFontMedium: true,
+                              paddingTop: 13,
+                              marginRight: 15,
+                              paddingBottom: 13,
+                              textAlign: TextAlign.center,
+                              textColor: Colors.white,
+                              backgroundColor: context.appColors.orangeBG,
+                              cornerRadius: 7,
+                            ),
+                          )),
+                    ),
+                    Expanded(
                         flex: 1,
                         child: InkWell(
-                          onTap: () {
+                          onTap: () async {
                             onCancel();
-                            cancelAction?.call();
+                            confirmAction();
                           },
                           child: MyTextView(
-                            cancelTxt ?? S.current.no,
+                            confirmTxt ?? S.current.yes,
                             fontSize: 16,
-                            isFontMedium: true,
                             paddingTop: 13,
-                            marginRight: 15,
                             paddingBottom: 13,
+                            isFontMedium: true,
                             textAlign: TextAlign.center,
                             textColor: Colors.white,
-                            backgroundColor: context.appColors.orangeBG,
+                            backgroundColor: context.appColors.btnBgDefault,
                             cornerRadius: 7,
                           ),
                         )),
-                  ),
-                  Expanded(
-                      flex: 1,
-                      child: InkWell(
-                        onTap: () async {
-                          onCancel();
-                          confirmAction();
-                        },
-                        child: MyTextView(
-                          confirmTxt ?? S.current.yes,
-                          fontSize: 16,
-                          paddingTop: 13,
-                          paddingBottom: 13,
-                          isFontMedium: true,
-                          textAlign: TextAlign.center,
-                          textColor: Colors.white,
-                          backgroundColor: context.appColors.btnBgDefault,
-                          cornerRadius: 7,
-                        ),
-                      )),
-                  const SizedBox(width: 18),
-                ],
-              ).marginOnly(bottom: 30, top: 28),
-            ],
+                    const SizedBox(width: 18),
+                  ],
+                ).marginOnly(bottom: 30, top: 28),
+              ],
+            ),
           ),
-        ),
-      ],
-    ).constrained(width: 300);
+        ],
+      ).constrained(width: 300),
+    );
   }
 
   //取消弹框