Browse Source

反馈的分类,创建,状态列表,详情接口调试

liukai 4 months ago
parent
commit
619a504588
32 changed files with 804 additions and 266 deletions
  1. 6 9
      packages/cpt_main/lib/modules/feedback/create/feedback_create_page.dart
  2. 7 9
      packages/cpt_main/lib/modules/feedback/create/feedback_create_state.dart
  3. 51 36
      packages/cpt_main/lib/modules/feedback/create/feedback_create_view_model.dart
  4. 1 1
      packages/cpt_main/lib/modules/feedback/create/feedback_create_view_model.g.dart
  5. 27 21
      packages/cpt_main/lib/modules/feedback/detail/feedback_detail_page.dart
  6. 10 7
      packages/cpt_main/lib/modules/feedback/detail/feedback_detail_state.dart
  7. 22 4
      packages/cpt_main/lib/modules/feedback/detail/feedback_detail_view_model.dart
  8. 1 1
      packages/cpt_main/lib/modules/feedback/detail/feedback_detail_view_model.g.dart
  9. 8 9
      packages/cpt_main/lib/modules/feedback/history/feedback_history.dart
  10. 3 2
      packages/cpt_main/lib/modules/feedback/history/feedback_history_state.dart
  11. 48 69
      packages/cpt_main/lib/modules/feedback/history/feedback_history_view_model.dart
  12. 1 1
      packages/cpt_main/lib/modules/feedback/history/feedback_history_view_model.g.dart
  13. 7 6
      packages/cpt_main/lib/modules/feedback/item_feedback.dart
  14. 7 8
      packages/cpt_main/lib/modules/feedback/progress/feedback_progress.dart
  15. 3 2
      packages/cpt_main/lib/modules/feedback/progress/feedback_progress_state.dart
  16. 51 70
      packages/cpt_main/lib/modules/feedback/progress/feedback_progress_view_model.dart
  17. 1 1
      packages/cpt_main/lib/modules/feedback/progress/feedback_progress_view_model.g.dart
  18. 1 1
      packages/cpt_main/lib/modules/main/main_view_model.g.dart
  19. 1 1
      packages/cpt_main/lib/modules/me/me_view_model.g.dart
  20. 34 5
      packages/cpt_main/lib/router/page/main_page_router.gr.dart
  21. 12 0
      packages/cs_domain/lib/constants/api_constants.dart
  22. 51 0
      packages/cs_domain/lib/entity/feedback_detail_entity.dart
  23. 48 0
      packages/cs_domain/lib/entity/feedback_list_entity.dart
  24. 18 0
      packages/cs_domain/lib/generated/json/base/json_convert_content.dart
  25. 132 0
      packages/cs_domain/lib/generated/json/feedback_detail_entity.g.dart
  26. 116 0
      packages/cs_domain/lib/generated/json/feedback_list_entity.g.dart
  27. 123 3
      packages/cs_domain/lib/repository/main_repository.dart
  28. 1 0
      packages/cs_resources/lib/generated/intl/messages_en.dart
  29. 10 0
      packages/cs_resources/lib/generated/l10n.dart
  30. 1 0
      packages/cs_resources/lib/l10n/intl_en.arb
  31. 1 0
      packages/cs_resources/lib/l10n/intl_zh_CN.arb
  32. 1 0
      packages/cs_resources/lib/l10n/intl_zh_HK.arb

+ 6 - 9
packages/cpt_main/lib/modules/feedback/create/feedback_create_page.dart

@@ -52,14 +52,14 @@ class FeedbackCreatePage extends HookConsumerWidget {
             children: [
               //选择类型
               FormRequireText(
-                text: S.current.full_name,
+                text: S.current.choose_category,
                 textColor: context.appColors.textBlack,
                 fontSize: 17,
               ).marginOnly(top: 14.5),
               // 选择器
               PickerContainer(
-                content: state.selectedOption ?? "",
-                hint: S.current.choose_category,
+                content: state.selectedOption?.name ?? "",
+                hint: S.current.choose_an_option,
                 margin: const EdgeInsets.only(top: 16),
                 onClick: viewModel.pickCategory,
               ),
@@ -78,7 +78,6 @@ class FeedbackCreatePage extends HookConsumerWidget {
                 marginTop: 16,
                 textInputType: TextInputType.text,
                 textInputAction: TextInputAction.next,
-                errorText: state.titleErrorText,
                 onSubmit: (formKey, value) {
                   state.formData[formKey]!['focusNode'].unfocus();
                   FocusScope.of(context).requestFocus(state.formData['desc']!['focusNode']);
@@ -86,13 +85,11 @@ class FeedbackCreatePage extends HookConsumerWidget {
               ),
 
               // DESC
-              MyTextView(
-                S.current.describe_your_feedback,
+              FormRequireText(
+                text: S.current.describe_your_feedback,
                 textColor: context.appColors.textBlack,
                 fontSize: 17,
-                marginTop: 14.5,
-                isFontMedium: true,
-              ),
+              ).marginOnly(top: 14.5),
               //大文本框
               IgnoreKeyboardDismiss(
                 child: Container(

+ 7 - 9
packages/cpt_main/lib/modules/feedback/create/feedback_create_state.dart

@@ -1,16 +1,14 @@
 import 'package:cs_resources/generated/l10n.dart';
+import 'package:domain/entity/id_name_entity.dart';
 import 'package:flutter/material.dart';
 
 class FeedbackCreateState {
 //表单的校验与数据
   final Map<String, Map<String, dynamic>> formData;
 
-  //表单的错误信息展示
-  String? titleErrorText;
-
   //类型选项
-  final List<String> optionList = ["条件1", "条件2", "条件3", "条件4"];
-  String? selectedOption;
+  List<IdNameEntity>? optionList;
+  IdNameEntity? selectedOption;
 
   //选择的图片
   List<String> imgList;
@@ -19,8 +17,8 @@ class FeedbackCreateState {
 
   FeedbackCreateState({
     Map<String, Map<String, dynamic>>? formData,
-    this.titleErrorText,
     required this.imgList,
+    this.optionList,
     this.selectedOption,
   }) : formData = formData ??
             {
@@ -40,14 +38,14 @@ class FeedbackCreateState {
             };
 
   FeedbackCreateState copyWith({
-    String? titleErrorText,
-    String? selectedOption,
+    List<IdNameEntity>? optionList,
+    IdNameEntity? selectedOption,
     List<String>? imgList,
   }) {
     return FeedbackCreateState(
       formData: this.formData,
-      titleErrorText: titleErrorText,
       imgList: imgList ?? this.imgList,
+      optionList: optionList ?? this.optionList,
       selectedOption: selectedOption ?? this.selectedOption,
     );
   }

+ 51 - 36
packages/cpt_main/lib/modules/feedback/create/feedback_create_view_model.dart

@@ -1,6 +1,8 @@
 import 'package:cs_resources/generated/l10n.dart';
+import 'package:domain/repository/main_repository.dart';
 import 'package:flutter/material.dart';
 import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
 import 'package:riverpod_annotation/riverpod_annotation.dart';
 import 'package:shared/utils/log_utils.dart';
 import 'package:shared/utils/util.dart';
@@ -13,27 +15,47 @@ import 'feedback_create_state.dart';
 part 'feedback_create_view_model.g.dart';
 
 @riverpod
-class FeedbackCreateViewModel extends _$FeedbackCreateViewModel {
+class FeedbackCreateViewModel extends _$FeedbackCreateViewModel with DioCancelableMixin {
+  late final MainRepository _mainRepository;
+
   @override
   FeedbackCreateState build() {
+    _mainRepository = ref.read(mainRepositoryProvider);
     final state = FeedbackCreateState(imgList: []);
-    initListener(state);
-    ref.onDispose(() {
-      onDispose(state);
-    });
+
+    registerCancellation();
 
     return state;
   }
 
   //选择选项
-  void pickCategory() {
+  void pickCategory() async {
     _dismissKeyboard();
+    Log.d("当前的optionList:${state.optionList}");
+    if (state.optionList == null || state.optionList!.isEmpty) {
+      //请求接口
+      final result = await _mainRepository.fetchFeedbackCategory(cancelToken: cancelToken);
+
+      if (result.isSuccess) {
+        state.optionList = result.list;
+        showCategoryPicker();
+      } else {
+        ToastEngine.show(result.errorMsg ?? "UnKnow Error");
+      }
+    } else {
+      showCategoryPicker();
+    }
+  }
+
+  //展示分类的PickerView
+  void showCategoryPicker() {
+    if (state.optionList == null) return;
 
     OptionPickerUtil.showCupertinoOptionPicker(
-      items: state.optionList,
+      items: state.optionList!.map((e) => e.name).whereType<String>().toList(),
       initialSelectIndex: 0,
       onPickerChanged: (_, index) {
-        state = state.copyWith(selectedOption: state.optionList[index]);
+        state = state.copyWith(selectedOption: state.optionList![index]);
       },
     );
   }
@@ -46,9 +68,7 @@ class FeedbackCreateViewModel extends _$FeedbackCreateViewModel {
   }
 
   ///提交反馈
-  void submitFeedback() {
-    state = state.copyWith(titleErrorText: null);
-
+  void submitFeedback() async {
     _dismissKeyboard();
 
     final TextEditingController titleController = state.formData['title']!['controller'];
@@ -59,45 +79,40 @@ class FeedbackCreateViewModel extends _$FeedbackCreateViewModel {
 
     Log.d('当前待提交的 option:${state.selectedOption} title:$title desc:$desc imgList:${state.imgList}');
 
-    if (Utils.isEmpty(state.selectedOption)) {
+    if (state.selectedOption == null) {
       ToastEngine.show(S.current.choose_category);
       return;
     }
 
     if (Utils.isEmpty(title)) {
-      state = state.copyWith(titleErrorText: "Title cannot be empty!");
+      ToastEngine.show("Title cannot be empty!");
       return;
     }
 
+    if (Utils.isEmpty(desc)) {
+      ToastEngine.show("Enter Your FeedBack Description");
+      return;
+    }
     //执行密码登录
-    ToastEngine.show('准备执行请求 option:${state.selectedOption} title:$title desc:$desc imgList:${state.imgList}');
+    final result = await _mainRepository.postFeedback(
+      categoryId: state.selectedOption?.id,
+      title: title,
+      content: desc,
+      paths: state.imgList,
+      cancelToken: cancelToken,
+    );
 
-    //去成功页面
-    FeedbackCreateSuccessPage.startInstance();
+    if (result.isSuccess) {
+      //去成功页面
+      FeedbackCreateSuccessPage.startInstance();
+    } else {
+      ToastEngine.show(result.errorMsg ?? "UnKnow Error");
+    }
   }
 
   //选中图片
   void setImgList(List<String> list) {
+    _dismissKeyboard();
     state = state.copyWith(imgList: list);
   }
-
-  //初始化监听
-  void initListener(FeedbackCreateState initState) {
-    final FocusNode titleFocusNode = initState.formData['title']!['focusNode'];
-
-    titleFocusNode.addListener(() {
-      // 获取焦点的时候清空错误文本
-      if (titleFocusNode.hasFocus) {
-        state = state.copyWith(titleErrorText: null);
-      }
-    });
-  }
-
-  //销毁资源
-  void onDispose(FeedbackCreateState initState) {
-    final FocusNode titleFocusNode = initState.formData['title']!['focusNode'];
-    titleFocusNode.dispose();
-
-    Log.d("FeedbackCreateViewModel 销毁 onDispose");
-  }
 }

+ 1 - 1
packages/cpt_main/lib/modules/feedback/create/feedback_create_view_model.g.dart

@@ -7,7 +7,7 @@ part of 'feedback_create_view_model.dart';
 // **************************************************************************
 
 String _$feedbackCreateViewModelHash() =>
-    r'ee07ee653b4c52ef48983fa988a0043ea3b4f057';
+    r'ee4b40e8287e9137352fc27343230886bba87325';
 
 /// See also [FeedbackCreateViewModel].
 @ProviderFor(FeedbackCreateViewModel)

+ 27 - 21
packages/cpt_main/lib/modules/feedback/detail/feedback_detail_page.dart

@@ -3,6 +3,7 @@ import 'package:cs_resources/generated/l10n.dart';
 import 'package:cs_resources/theme/app_colors_theme.dart';
 import 'package:flutter/material.dart';
 import 'package:auto_route/auto_route.dart';
+import 'package:flutter_hooks/flutter_hooks.dart';
 import 'package:hooks_riverpod/hooks_riverpod.dart';
 import 'package:plugin_platform/engine/image/image_nine_grid.dart';
 import 'package:router/ext/auto_router_extensions.dart';
@@ -16,14 +17,17 @@ import 'feedback_detail_view_model.dart';
 
 @RoutePage()
 class FeedbackDetailPage extends HookConsumerWidget {
-  const FeedbackDetailPage({Key? key}) : super(key: key);
+  //Feedback的Id
+  final String? id;
+
+  const FeedbackDetailPage({Key? key, required this.id}) : super(key: key);
 
   //启动当前页面
-  static void startInstance({BuildContext? context}) {
+  static void startInstance({BuildContext? context, required String? id}) {
     if (context != null) {
-      context.router.push(const FeedbackDetailPageRoute());
+      context.router.push(FeedbackDetailPageRoute(id: id));
     } else {
-      appRouter.push(const FeedbackDetailPageRoute());
+      appRouter.push(FeedbackDetailPageRoute(id: id));
     }
   }
 
@@ -32,6 +36,14 @@ class FeedbackDetailPage extends HookConsumerWidget {
     final viewModel = ref.watch(feedbackDetailViewModelProvider.notifier);
     final state = ref.watch(feedbackDetailViewModelProvider);
 
+    useEffect(() {
+      // 组件挂载时执行 - 执行接口请求
+      Future.microtask(() => viewModel.fetchFeedbackDetail(id));
+      return () {
+        // 组件卸载时执行
+      };
+    }, []);
+
     return Scaffold(
       appBar: MyAppBar.appBar(context, S.current.feedback_details, showBottomDivider: true),
       backgroundColor: context.appColors.backgroundDark,
@@ -53,13 +65,13 @@ class FeedbackDetailPage extends HookConsumerWidget {
                   crossAxisAlignment: CrossAxisAlignment.start,
                   children: [
                     MyTextView(
-                      "Exchange old houses for new ones",
+                      state.detail?.title ?? "-",
                       fontSize: 21,
                       isFontMedium: true,
                       textColor: context.appColors.textBlack,
                     ),
                     MyTextView(
-                      "18 Sep 2024 18:00  |  Security  |  In Progress",
+                      "${state.detail?.createdAt ?? ""}  |  ${state.detail?.category?.name ?? ""}  |  ${state.detail?.status == 1 ? S.current.in_progress : S.current.replied}",
                       fontSize: 12,
                       marginTop: 8,
                       isFontRegular: true,
@@ -87,9 +99,10 @@ class FeedbackDetailPage extends HookConsumerWidget {
                   ],
                 ),
                 child: Column(
+                  crossAxisAlignment: CrossAxisAlignment.start,
                   children: [
                     MyTextView(
-                      "Why are there no implementation rules andapplication methods for exchanging old houses for new ones in Jiang han District?",
+                      state.detail?.content ?? "",
                       fontSize: 15,
                       marginBottom: 15,
                       isFontRegular: true,
@@ -102,12 +115,7 @@ class FeedbackDetailPage extends HookConsumerWidget {
                       maxImages: 10,
                       spacing: 10,
                       aspectRatio: 108 / 80,
-                      initialImages: const [
-                        "https://img1.baidu.com/it/u=2931243091,718249849&fm=253&fmt=auto&app=120&f=JPEG?w=569&h=427",
-                        "https://inews.gtimg.com/om_bt/OE8piEBa-tbqn-wNvWZl8coi4AlzoUD43upEkoAnIkYL8AA/641",
-                        "https://inews.gtimg.com/om_bt/OVx3YS2XJc1zbndGTkjPKW9J0W7kN8M0SIidT-3K4mb2YAA/641",
-                        "https://inews.gtimg.com/om_bt/OAVMydtx9BsJxf5i_thi4Oll9sR1px-Esmtv6UHSxoisEAA/641"
-                      ],
+                      initialImages: state.detail?.resources ?? [],
                       onImagesChanged: (list) {},
                     ),
                   ],
@@ -122,6 +130,7 @@ class FeedbackDetailPage extends HookConsumerWidget {
   }
 
   Widget _buildReplyWidget(BuildContext context, WidgetRef ref) {
+    final state = ref.watch(feedbackDetailViewModelProvider);
     return Column(
       crossAxisAlignment: CrossAxisAlignment.start,
       children: [
@@ -137,13 +146,13 @@ class FeedbackDetailPage extends HookConsumerWidget {
               textColor: context.appColors.textBlack,
             ).expanded(),
             MyTextView(
-              "20 sep 2024 18:00",
+              state.detail?.replies?[0].createdAt ?? "-",
               fontSize: 12,
               isFontRegular: true,
               textColor: context.appColors.textDarkGray,
             )
           ],
-        ).marginOnly(left: 12.5, right: 12.5,bottom: 14,top: 2.5),
+        ).marginOnly(left: 12.5, right: 12.5, bottom: 14, top: 2.5),
 
         //回复的内容
         Container(
@@ -163,9 +172,10 @@ class FeedbackDetailPage extends HookConsumerWidget {
             ],
           ),
           child: Column(
+            crossAxisAlignment: CrossAxisAlignment.start,
             children: [
               MyTextView(
-                "Although the policy of exchanging old houses for new houses in Jianghan District has been released, the specific implementation details and application methods are not yet clear. According to relevant reports, Jianghan District has issued multiple measures for the development of the real estate market, including promoting the trade in policy, but the specific implementation details and application methods have not vet been announced",
+                state.detail?.replies?[0].content ?? "",
                 fontSize: 15,
                 marginBottom: 15,
                 isFontRegular: true,
@@ -178,11 +188,7 @@ class FeedbackDetailPage extends HookConsumerWidget {
                 maxImages: 10,
                 spacing: 10,
                 aspectRatio: 108 / 80,
-                initialImages: const [
-                  "https://img1.baidu.com/it/u=2931243091,718249849&fm=253&fmt=auto&app=120&f=JPEG?w=569&h=427",
-                  "https://inews.gtimg.com/om_bt/OVx3YS2XJc1zbndGTkjPKW9J0W7kN8M0SIidT-3K4mb2YAA/641",
-                  "https://inews.gtimg.com/om_bt/OAVMydtx9BsJxf5i_thi4Oll9sR1px-Esmtv6UHSxoisEAA/641"
-                ],
+                initialImages: state.detail?.replies?[0].resources ?? [],
                 onImagesChanged: (list) {},
               ),
             ],

+ 10 - 7
packages/cpt_main/lib/modules/feedback/detail/feedback_detail_state.dart

@@ -1,18 +1,21 @@
-class FeedbackDetailState{
+import 'package:domain/entity/feedback_detail_entity.dart';
 
+class FeedbackDetailState {
   //是等待状态还是已完成状态(是否已经回复)
   bool isReplyState;
 
+  //详情数据
+  FeedbackDetailEntity? detail;
+
   FeedbackDetailState({
-     this.isReplyState = false,
+    this.isReplyState = false,
+    this.detail,
   });
 
-  FeedbackDetailState copyWith({
-    bool? isReplyState,
-  }) {
+  FeedbackDetailState copyWith({bool? isReplyState, FeedbackDetailEntity? detail}) {
     return FeedbackDetailState(
       isReplyState: isReplyState ?? this.isReplyState,
+      detail: detail ?? this.detail,
     );
   }
-
-}
+}

+ 22 - 4
packages/cpt_main/lib/modules/feedback/detail/feedback_detail_view_model.dart

@@ -1,15 +1,33 @@
-
+import 'package:domain/repository/main_repository.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
 import 'package:riverpod_annotation/riverpod_annotation.dart';
+import 'package:shared/utils/log_utils.dart';
 
 import 'feedback_detail_state.dart';
+
 part 'feedback_detail_view_model.g.dart';
 
 @riverpod
-class FeedbackDetailViewModel extends _$FeedbackDetailViewModel {
+class FeedbackDetailViewModel extends _$FeedbackDetailViewModel with DioCancelableMixin {
+  late final MainRepository _mainRepository;
 
   @override
-  FeedbackDetailState build(){
-    return FeedbackDetailState();
+  FeedbackDetailState build() {
+    _mainRepository = ref.read(mainRepositoryProvider);
+    final state = FeedbackDetailState();
+    registerCancellation();
+    return state;
   }
 
+  /// 获取详情数据
+  void fetchFeedbackDetail(String? id) async {
+    final result = await _mainRepository.fetchFeedbackDetail(id: id, cancelToken: cancelToken);
+
+    if (result.isSuccess) {
+      state = state.copyWith(detail: result.data, isReplyState: result.data?.replies?.isNotEmpty);
+    } else {
+      ToastEngine.show(result.errorMsg ?? "UnKnow Error");
+    }
+  }
 }

+ 1 - 1
packages/cpt_main/lib/modules/feedback/detail/feedback_detail_view_model.g.dart

@@ -7,7 +7,7 @@ part of 'feedback_detail_view_model.dart';
 // **************************************************************************
 
 String _$feedbackDetailViewModelHash() =>
-    r'c319af8c4d4805a867eb1f6481c9e6267e45cc5a';
+    r'a41644cc5725d2230d11c7a6f904b5eaa49665b6';
 
 /// See also [FeedbackDetailViewModel].
 @ProviderFor(FeedbackDetailViewModel)

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

@@ -11,7 +11,6 @@ import '../detail/feedback_detail_page.dart';
 import '../item_feedback.dart';
 import 'feedback_history_view_model.dart';
 
-
 @RoutePage()
 class FeedbackHistoryScreen extends HookConsumerWidget {
   @override
@@ -44,14 +43,14 @@ class FeedbackHistoryScreen extends HookConsumerWidget {
           successSliverWidget: [
             SliverList(
                 delegate: SliverChildBuilderDelegate(
-                      (context, index) {
-                    return FeedbackItem(index: index, item: state.datas[index]).onTap((){
-                      FeedbackDetailPage.startInstance(context: context);
-                    });
-                  },
-                  childCount: state.datas.length,
-                ))
-            ],
+              (context, index) {
+                return FeedbackItem(index: index, item: state.datas[index]).onTap(() {
+                  FeedbackDetailPage.startInstance(context: context, id: state.datas[index].id);
+                });
+              },
+              childCount: state.datas.length,
+            ))
+          ],
         ),
       ).marginOnly(top: 5, bottom: 5),
     );

+ 3 - 2
packages/cpt_main/lib/modules/feedback/history/feedback_history_state.dart

@@ -1,3 +1,4 @@
+import 'package:domain/entity/feedback_list_entity.dart';
 import 'package:widgets/load_state_layout.dart';
 
 class FeedbackHistoryState {
@@ -6,7 +7,7 @@ class FeedbackHistoryState {
   LoadState loadingState;
   String? errorMessage;
 
-  List<String> datas; //页面列表数据
+  List<FeedbackItemEntity> datas; //页面列表数据
 
   // ===================================  Begin  ↓  ===================================
 
@@ -20,7 +21,7 @@ class FeedbackHistoryState {
     LoadState? loadingState,
     String? errorMessage,
     bool? needShowPlaceholder,
-    List<String>? datas,
+    List<FeedbackItemEntity>? datas,
   }) {
     return FeedbackHistoryState(
       errorMessage: errorMessage ?? this.errorMessage,

+ 48 - 69
packages/cpt_main/lib/modules/feedback/history/feedback_history_view_model.dart

@@ -1,3 +1,6 @@
+import 'package:domain/entity/feedback_list_entity.dart';
+import 'package:domain/repository/main_repository.dart';
+import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
 import 'package:riverpod_annotation/riverpod_annotation.dart';
 import 'package:shared/utils/log_utils.dart';
 import 'package:widgets/load_state_layout.dart';
@@ -8,19 +11,23 @@ import 'feedback_history_state.dart';
 part 'feedback_history_view_model.g.dart';
 
 @riverpod
-class FeedbackHistoryViewModel extends _$FeedbackHistoryViewModel {
+class FeedbackHistoryViewModel extends _$FeedbackHistoryViewModel with DioCancelableMixin {
+  late final MainRepository _mainRepository;
+
   var _curPage = 1; //请求参数当前的页面
   var _needShowPlaceholder = true; //是否展示LoadingView
 
   // Refresh 控制器
   final EasyRefreshController refreshController = EasyRefreshController(
-    controlFinishRefresh: true,  //允许刷新
-    controlFinishLoad: true,   //允许加载
+    controlFinishRefresh: true, //允许刷新
+    controlFinishLoad: true, //允许加载
   );
 
   @override
   FeedbackHistoryState build() {
+    _mainRepository = ref.read(mainRepositoryProvider);
     final state = FeedbackHistoryState(datas: []);
+    registerCancellation();
     return state;
   }
 
@@ -54,44 +61,18 @@ class FeedbackHistoryViewModel extends _$FeedbackHistoryViewModel {
       changeLoadingState(LoadState.State_Loading, null);
     }
 
-    // 获取 Applied 列表
-    // var listResult = await _jobRepository.fetchJobAppliedList(
-    //   state.jobId,
-    //   state.selectedStatusId,
-    //   state.keyword,
-    //   curPage: _curPage,
-    //   cancelToken: cancelToken,
-    // );
-    //
-    // // 处理数据
-    // if (listResult.isSuccess) {
-    //   handleList(listResult.data?.rows);
-    // } else {
-    //   errorMessage = listResult.errorMsg;
-    //   changeLoadingState(LoadState.State_Error);
-    // }
-
-
-    await Future.delayed(const Duration(milliseconds: 1500));
-
-    final List<String> list = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"];
-
-    if (_curPage == 1) {
-      //刷新的方式
-      state = state.copyWith(datas: list);
-      refreshController.finishRefresh();
-
-      //更新展示的状态
-      changeLoadingState(LoadState.State_Success, null);
-    } else {
-      //加载更多
-      final allList = state.datas;
-      allList.addAll(list);
-      state.datas.addAll(list);
-
-      refreshController.finishLoad();
+    // 获取列表
+    var listResult = await _mainRepository.fetchFeedbackList(
+      status: "2",
+      curPage: _curPage,
+      cancelToken: cancelToken,
+    );
 
-      state = state.copyWith(datas: allList);
+    // 处理数据
+    if (listResult.isSuccess) {
+      handleList(listResult.data?.list);
+    } else {
+      changeLoadingState(LoadState.State_Error, listResult.errorMsg);
     }
 
     // 最后赋值
@@ -99,33 +80,31 @@ class FeedbackHistoryViewModel extends _$FeedbackHistoryViewModel {
   }
 
 // 处理数据与展示的逻辑
-// void handleList(List<JobAppliedListSGRows>? list) {
-//   if (list != null && list.isNotEmpty) {
-//     //有数据,判断是刷新还是加载更多的数据
-//     if (_curPage == 1) {
-//       //刷新的方式
-//       state.datas.clear();
-//       state.datas.addAll(list);
-//       refreshController.finishRefresh();
-//
-//       //更新展示的状态
-//       changeLoadingState(LoadState.State_Success);
-//     } else {
-//       //加载更多
-//       state.datas.addAll(list);
-//       refreshController.finishLoad();
-//       update();
-//     }
-//   } else {
-//     if (_curPage == 1) {
-//       //展示无数据的布局
-//       state.datas.clear();
-//       changeLoadingState(LoadState.State_Empty);
-//       refreshController.finishRefresh();
-//     } else {
-//       //展示加载完成,没有更多数据了
-//       refreshController.finishLoad(IndicatorResult.noMore);
-//     }
-//   }
-// }
+  void handleList(List<FeedbackItemEntity>? list) {
+    if (list != null && list.isNotEmpty) {
+      //有数据,判断是刷新还是加载更多的数据
+      if (_curPage == 1) {
+        //刷新的方式
+        state = state.copyWith(datas: list);
+        refreshController.finishRefresh();
+
+        //更新展示的状态
+        changeLoadingState(LoadState.State_Success, null);
+      } else {
+        //加载更多
+        state.datas.addAll(List<FeedbackItemEntity>.from(state.datas)..addAll(list));
+        refreshController.finishLoad();
+      }
+    } else {
+      if (_curPage == 1) {
+        //展示无数据的布局
+        state = state.copyWith(datas: []);
+        changeLoadingState(LoadState.State_Empty, null);
+        refreshController.finishRefresh();
+      } else {
+        //展示加载完成,没有更多数据了
+        refreshController.finishLoad(IndicatorResult.noMore);
+      }
+    }
+  }
 }

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

@@ -7,7 +7,7 @@ part of 'feedback_history_view_model.dart';
 // **************************************************************************
 
 String _$feedbackHistoryViewModelHash() =>
-    r'1be8a480c3593a25a17cd22deeefe9d707f6151a';
+    r'4ab33c4926c1af3ab217b6cc3829f3c118811476';
 
 /// See also [FeedbackHistoryViewModel].
 @ProviderFor(FeedbackHistoryViewModel)

+ 7 - 6
packages/cpt_main/lib/modules/feedback/item_feedback.dart

@@ -1,5 +1,7 @@
 import 'package:cs_resources/generated/assets.dart';
+import 'package:cs_resources/generated/l10n.dart';
 import 'package:cs_resources/theme/app_colors_theme.dart';
+import 'package:domain/entity/feedback_list_entity.dart';
 import 'package:flutter/material.dart';
 import 'package:widgets/ext/ex_widget.dart';
 import 'package:widgets/my_load_image.dart';
@@ -7,7 +9,7 @@ import 'package:widgets/my_text_view.dart';
 
 class FeedbackItem extends StatelessWidget {
   final int index;
-  final String item;
+  final FeedbackItemEntity item;
 
   const FeedbackItem({
     required this.index,
@@ -40,17 +42,16 @@ class FeedbackItem extends StatelessWidget {
               Column(
                 crossAxisAlignment: CrossAxisAlignment.start,
                 children: [
-
                   MyTextView(
-                    "Exchange old houses for new ones",
+                    item.title ?? "",
                     fontSize: 16,
                     textColor: context.appColors.textBlack,
                     isFontMedium: true,
                   ),
-
                   MyTextView(
-                    "Why are there no implementation rules and application methods for something",
+                    item.content ?? "",
                     fontSize: 14,
+                    maxLines: 2,
                     marginTop: 5,
                     textColor: context.appColors.textBlack,
                     isFontRegular: true,
@@ -62,7 +63,7 @@ class FeedbackItem extends StatelessWidget {
 
           //备注
           MyTextView(
-            "18 Sep 2024 18:00  |  Security  |  In Progress",
+            "${item.createdAt}  |  ${item.category?.name ?? ""}  |  ${item.status == 1 ? S.current.in_progress : S.current.replied}",
             fontSize: 12,
             marginTop: 10,
             textColor: context.appColors.textDarkGray,

+ 7 - 8
packages/cpt_main/lib/modules/feedback/progress/feedback_progress.dart

@@ -11,7 +11,6 @@ import '../detail/feedback_detail_page.dart';
 import '../item_feedback.dart';
 import 'feedback_progress_view_model.dart';
 
-
 @RoutePage()
 class FeedbackProgressScreen extends HookConsumerWidget {
   @override
@@ -44,13 +43,13 @@ class FeedbackProgressScreen extends HookConsumerWidget {
           successSliverWidget: [
             SliverList(
                 delegate: SliverChildBuilderDelegate(
-                      (context, index) {
-                    return FeedbackItem(index: index, item: state.datas[index]).onTap((){
-                      FeedbackDetailPage.startInstance(context: context);
-                    });
-                  },
-                  childCount: state.datas.length,
-                ))
+              (context, index) {
+                return FeedbackItem(index: index, item: state.datas[index]).onTap(() {
+                  FeedbackDetailPage.startInstance(context: context, id: state.datas[index].id);
+                });
+              },
+              childCount: state.datas.length,
+            ))
           ],
         ),
       ).marginOnly(top: 5, bottom: 5),

+ 3 - 2
packages/cpt_main/lib/modules/feedback/progress/feedback_progress_state.dart

@@ -1,3 +1,4 @@
+import 'package:domain/entity/feedback_list_entity.dart';
 import 'package:widgets/load_state_layout.dart';
 
 class FeedbackProgressState {
@@ -6,7 +7,7 @@ class FeedbackProgressState {
   LoadState loadingState;
   String? errorMessage;
 
-  List<String> datas; //页面列表数据
+  List<FeedbackItemEntity> datas; //页面列表数据
 
   // ===================================  Begin  ↓  ===================================
 
@@ -20,7 +21,7 @@ class FeedbackProgressState {
     LoadState? loadingState,
     String? errorMessage,
     bool? needShowPlaceholder,
-    List<String>? datas,
+    List<FeedbackItemEntity>? datas,
   }) {
     return FeedbackProgressState(
       errorMessage: errorMessage ?? this.errorMessage,

+ 51 - 70
packages/cpt_main/lib/modules/feedback/progress/feedback_progress_view_model.dart

@@ -1,3 +1,6 @@
+import 'package:domain/entity/feedback_list_entity.dart';
+import 'package:domain/repository/main_repository.dart';
+import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
 import 'package:riverpod_annotation/riverpod_annotation.dart';
 import 'package:shared/utils/log_utils.dart';
 import 'package:widgets/load_state_layout.dart';
@@ -8,19 +11,24 @@ import 'feedback_progress_state.dart';
 part 'feedback_progress_view_model.g.dart';
 
 @riverpod
-class FeedbackProgressViewModel extends _$FeedbackProgressViewModel {
+class FeedbackProgressViewModel extends _$FeedbackProgressViewModel with DioCancelableMixin {
+  late final MainRepository _mainRepository;
+
   var _curPage = 1; //请求参数当前的页面
   var _needShowPlaceholder = true; //是否展示LoadingView
 
   // Refresh 控制器
   final EasyRefreshController refreshController = EasyRefreshController(
-    controlFinishRefresh: true,  //允许刷新
-    controlFinishLoad: true,   //允许加载
+    controlFinishRefresh: true, //允许刷新
+    controlFinishLoad: true, //允许加载
   );
 
   @override
   FeedbackProgressState build() {
-    return FeedbackProgressState(datas: []);
+    _mainRepository = ref.read(mainRepositoryProvider);
+    final state = FeedbackProgressState(datas: []);
+    registerCancellation();
+    return state;
   }
 
   //刷新页面状态
@@ -53,44 +61,18 @@ class FeedbackProgressViewModel extends _$FeedbackProgressViewModel {
       changeLoadingState(LoadState.State_Loading, null);
     }
 
-    // 获取 Applied 列表
-    // var listResult = await _jobRepository.fetchJobAppliedList(
-    //   state.jobId,
-    //   state.selectedStatusId,
-    //   state.keyword,
-    //   curPage: _curPage,
-    //   cancelToken: cancelToken,
-    // );
-    //
-    // // 处理数据
-    // if (listResult.isSuccess) {
-    //   handleList(listResult.data?.rows);
-    // } else {
-    //   errorMessage = listResult.errorMsg;
-    //   changeLoadingState(LoadState.State_Error);
-    // }
-
-
-    await Future.delayed(const Duration(milliseconds: 1500));
-
-    final List<String> list = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"];
-
-    if (_curPage == 1) {
-      //刷新的方式
-      state = state.copyWith(datas: list);
-      refreshController.finishRefresh();
-
-      //更新展示的状态
-      changeLoadingState(LoadState.State_Success, null);
-    } else {
-      //加载更多
-      final allList = state.datas;
-      allList.addAll(list);
-      state.datas.addAll(list);
-
-      refreshController.finishLoad();
+    // 获取列表
+    var listResult = await _mainRepository.fetchFeedbackList(
+      status: "1",
+      curPage: _curPage,
+      cancelToken: cancelToken,
+    );
 
-      state = state.copyWith(datas: allList);
+    // 处理数据
+    if (listResult.isSuccess) {
+      handleList(listResult.data?.list);
+    } else {
+      changeLoadingState(LoadState.State_Error, listResult.errorMsg);
     }
 
     // 最后赋值
@@ -98,33 +80,32 @@ class FeedbackProgressViewModel extends _$FeedbackProgressViewModel {
   }
 
 // 处理数据与展示的逻辑
-// void handleList(List<JobAppliedListSGRows>? list) {
-//   if (list != null && list.isNotEmpty) {
-//     //有数据,判断是刷新还是加载更多的数据
-//     if (_curPage == 1) {
-//       //刷新的方式
-//       state.datas.clear();
-//       state.datas.addAll(list);
-//       refreshController.finishRefresh();
-//
-//       //更新展示的状态
-//       changeLoadingState(LoadState.State_Success);
-//     } else {
-//       //加载更多
-//       state.datas.addAll(list);
-//       refreshController.finishLoad();
-//       update();
-//     }
-//   } else {
-//     if (_curPage == 1) {
-//       //展示无数据的布局
-//       state.datas.clear();
-//       changeLoadingState(LoadState.State_Empty);
-//       refreshController.finishRefresh();
-//     } else {
-//       //展示加载完成,没有更多数据了
-//       refreshController.finishLoad(IndicatorResult.noMore);
-//     }
-//   }
-// }
+  void handleList(List<FeedbackItemEntity>? list) {
+    if (list != null && list.isNotEmpty) {
+      //有数据,判断是刷新还是加载更多的数据
+      if (_curPage == 1) {
+        //刷新的方式
+        state = state.copyWith(datas: list);
+        refreshController.finishRefresh();
+
+        //更新展示的状态
+        changeLoadingState(LoadState.State_Success, null);
+      } else {
+        //加载更多
+        state.datas.addAll(List<FeedbackItemEntity>.from(state.datas)
+          ..addAll(list));
+        refreshController.finishLoad();
+      }
+    } else {
+      if (_curPage == 1) {
+        //展示无数据的布局
+        state = state.copyWith(datas: []);
+        changeLoadingState(LoadState.State_Empty, null);
+        refreshController.finishRefresh();
+      } else {
+        //展示加载完成,没有更多数据了
+        refreshController.finishLoad(IndicatorResult.noMore);
+      }
+    }
+  }
 }

+ 1 - 1
packages/cpt_main/lib/modules/feedback/progress/feedback_progress_view_model.g.dart

@@ -7,7 +7,7 @@ part of 'feedback_progress_view_model.dart';
 // **************************************************************************
 
 String _$feedbackProgressViewModelHash() =>
-    r'0753e433b0a575a262661e6b99030d250b69d0d0';
+    r'c3efb93d755db84c7aa75667ce2e504628759842';
 
 /// See also [FeedbackProgressViewModel].
 @ProviderFor(FeedbackProgressViewModel)

+ 1 - 1
packages/cpt_main/lib/modules/main/main_view_model.g.dart

@@ -6,7 +6,7 @@ part of 'main_view_model.dart';
 // RiverpodGenerator
 // **************************************************************************
 
-String _$mainViewModelHash() => r'755642bf17f8e933622907db69f84db9cb02f40e';
+String _$mainViewModelHash() => r'e3930e02c521760d4d40336f6dd1439b36d8a000';
 
 /// See also [MainViewModel].
 @ProviderFor(MainViewModel)

+ 1 - 1
packages/cpt_main/lib/modules/me/me_view_model.g.dart

@@ -6,7 +6,7 @@ part of 'me_view_model.dart';
 // RiverpodGenerator
 // **************************************************************************
 
-String _$meViewModelHash() => r'e7ffdeb5e84ad07ec6167a6249276bc25ca834fb';
+String _$meViewModelHash() => r'8244a47fa4533ff1373c03518aa3332e8c23e66b';
 
 /// See also [MeViewModel].
 @ProviderFor(MeViewModel)

+ 34 - 5
packages/cpt_main/lib/router/page/main_page_router.gr.dart

@@ -28,9 +28,13 @@ abstract class _$MainPageRouter extends RootStackRouter {
       );
     },
     FeedbackDetailPageRoute.name: (routeData) {
+      final args = routeData.argsAs<FeedbackDetailPageRouteArgs>();
       return AutoRoutePage<dynamic>(
         routeData: routeData,
-        child: const FeedbackDetailPage(),
+        child: FeedbackDetailPage(
+          key: args.key,
+          id: args.id,
+        ),
       );
     },
     FeedbackHistoryPageRoute.name: (routeData) {
@@ -186,16 +190,41 @@ class FeedbackCreateSuccessPageRoute extends PageRouteInfo<void> {
 
 /// generated route for
 /// [FeedbackDetailPage]
-class FeedbackDetailPageRoute extends PageRouteInfo<void> {
-  const FeedbackDetailPageRoute({List<PageRouteInfo>? children})
-      : super(
+class FeedbackDetailPageRoute
+    extends PageRouteInfo<FeedbackDetailPageRouteArgs> {
+  FeedbackDetailPageRoute({
+    Key? key,
+    required String? id,
+    List<PageRouteInfo>? children,
+  }) : super(
           FeedbackDetailPageRoute.name,
+          args: FeedbackDetailPageRouteArgs(
+            key: key,
+            id: id,
+          ),
           initialChildren: children,
         );
 
   static const String name = 'FeedbackDetailPageRoute';
 
-  static const PageInfo<void> page = PageInfo<void>(name);
+  static const PageInfo<FeedbackDetailPageRouteArgs> page =
+      PageInfo<FeedbackDetailPageRouteArgs>(name);
+}
+
+class FeedbackDetailPageRouteArgs {
+  const FeedbackDetailPageRouteArgs({
+    this.key,
+    required this.id,
+  });
+
+  final Key? key;
+
+  final String? id;
+
+  @override
+  String toString() {
+    return 'FeedbackDetailPageRouteArgs{key: $key, id: $id}';
+  }
 }
 
 /// generated route for

+ 12 - 0
packages/cs_domain/lib/constants/api_constants.dart

@@ -35,6 +35,18 @@ class ApiConstants {
 
   // =========================== 首页 ↓=========================================
 
+  //反馈的分类列表
+  static const apiFeedbackCategory = "/api/v1/user/feedback/category/index";
+
+  //反馈的发布
+  static const apiFeedbackPost = "/api/v1/user/feedback/index/publish";
+
+  //已发布的反馈列表
+  static const apiFeedbackList = "/api/v1/user/feedback/index";
+
+  //反馈详情
+  static const apiFeedbackDetail = "/api/v1/user/feedback/index/detail";
+
   // =========================== Profile ↓=========================================
 
   //用户Me页面详情

+ 51 - 0
packages/cs_domain/lib/entity/feedback_detail_entity.dart

@@ -0,0 +1,51 @@
+import 'package:domain/entity/id_name_entity.dart';
+import 'package:domain/generated/json/base/json_field.dart';
+import 'package:domain/generated/json/feedback_detail_entity.g.dart';
+import 'dart:convert';
+export 'package:domain/generated/json/feedback_detail_entity.g.dart';
+
+@JsonSerializable()
+class FeedbackDetailEntity {
+	String? id;
+	String? title;
+	String? content;
+	List<String>? resources = [];
+	int status = 0;
+	@JSONField(name: "created_at")
+	String? createdAt;
+	IdNameEntity? category;
+	List<FeedbackDetailReplies>? replies = [];
+
+	FeedbackDetailEntity();
+
+	factory FeedbackDetailEntity.fromJson(Map<String, dynamic> json) => $FeedbackDetailEntityFromJson(json);
+
+	Map<String, dynamic> toJson() => $FeedbackDetailEntityToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
+}
+
+
+@JsonSerializable()
+class FeedbackDetailReplies {
+	String? id;
+	String? content;
+	List<String>? resources = [];
+	@JSONField(name: "created_at")
+	String? createdAt;
+	IdNameEntity? accountable;
+
+	FeedbackDetailReplies();
+
+	factory FeedbackDetailReplies.fromJson(Map<String, dynamic> json) => $FeedbackDetailRepliesFromJson(json);
+
+	Map<String, dynamic> toJson() => $FeedbackDetailRepliesToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
+}

+ 48 - 0
packages/cs_domain/lib/entity/feedback_list_entity.dart

@@ -0,0 +1,48 @@
+import 'package:domain/entity/id_name_entity.dart';
+import 'package:domain/generated/json/base/json_field.dart';
+import 'package:domain/generated/json/feedback_list_entity.g.dart';
+import 'dart:convert';
+export 'package:domain/generated/json/feedback_list_entity.g.dart';
+
+@JsonSerializable()
+class FeedbackListEntity {
+	int count = 0;
+	int page = 0;
+	@JSONField(name: "count_page")
+	int countPage = 1;
+	int limit = 0;
+	List<FeedbackItemEntity>? list = [];
+
+	FeedbackListEntity();
+
+	factory FeedbackListEntity.fromJson(Map<String, dynamic> json) => $FeedbackListEntityFromJson(json);
+
+	Map<String, dynamic> toJson() => $FeedbackListEntityToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
+}
+
+@JsonSerializable()
+class FeedbackItemEntity {
+	String? id;
+	String? title;
+	String? content;
+	int status = 0;
+	@JSONField(name: "created_at")
+	String? createdAt;
+	IdNameEntity? category;
+
+	FeedbackItemEntity();
+
+	factory FeedbackItemEntity.fromJson(Map<String, dynamic> json) => $FeedbackItemEntityFromJson(json);
+
+	Map<String, dynamic> toJson() => $FeedbackItemEntityToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
+}

+ 18 - 0
packages/cs_domain/lib/generated/json/base/json_convert_content.dart

@@ -6,6 +6,8 @@
 import 'package:flutter/material.dart' show debugPrint;
 import 'package:domain/entity/auth_login_entity.dart';
 import 'package:domain/entity/captcha_img_entity.dart';
+import 'package:domain/entity/feedback_detail_entity.dart';
+import 'package:domain/entity/feedback_list_entity.dart';
 import 'package:domain/entity/id_name_entity.dart';
 import 'package:domain/entity/property_news_entity.dart';
 import 'package:domain/entity/property_sale_entity.dart';
@@ -149,6 +151,18 @@ class JsonConvert {
     if (<CaptchaImgEntity>[] is M) {
       return data.map<CaptchaImgEntity>((Map<String, dynamic> e) => CaptchaImgEntity.fromJson(e)).toList() as M;
     }
+    if (<FeedbackDetailEntity>[] is M) {
+      return data.map<FeedbackDetailEntity>((Map<String, dynamic> e) => FeedbackDetailEntity.fromJson(e)).toList() as M;
+    }
+    if (<FeedbackDetailReplies>[] is M) {
+      return data.map<FeedbackDetailReplies>((Map<String, dynamic> e) => FeedbackDetailReplies.fromJson(e)).toList() as M;
+    }
+    if (<FeedbackListEntity>[] is M) {
+      return data.map<FeedbackListEntity>((Map<String, dynamic> e) => FeedbackListEntity.fromJson(e)).toList() as M;
+    }
+    if (<FeedbackItemEntity>[] is M) {
+      return data.map<FeedbackItemEntity>((Map<String, dynamic> e) => FeedbackItemEntity.fromJson(e)).toList() as M;
+    }
     if (<IdNameEntity>[] is M) {
       return data.map<IdNameEntity>((Map<String, dynamic> e) => IdNameEntity.fromJson(e)).toList() as M;
     }
@@ -204,6 +218,10 @@ class JsonConvertClassCollection {
   Map<String, JsonConvertFunction> convertFuncMap = {
     (AuthLoginEntity).toString(): AuthLoginEntity.fromJson,
     (CaptchaImgEntity).toString(): CaptchaImgEntity.fromJson,
+    (FeedbackDetailEntity).toString(): FeedbackDetailEntity.fromJson,
+    (FeedbackDetailReplies).toString(): FeedbackDetailReplies.fromJson,
+    (FeedbackListEntity).toString(): FeedbackListEntity.fromJson,
+    (FeedbackItemEntity).toString(): FeedbackItemEntity.fromJson,
     (IdNameEntity).toString(): IdNameEntity.fromJson,
     (PropertyNewsEntity).toString(): PropertyNewsEntity.fromJson,
     (PropertySaleEntity).toString(): PropertySaleEntity.fromJson,

+ 132 - 0
packages/cs_domain/lib/generated/json/feedback_detail_entity.g.dart

@@ -0,0 +1,132 @@
+import 'package:domain/generated/json/base/json_convert_content.dart';
+import 'package:domain/entity/feedback_detail_entity.dart';
+import 'package:domain/entity/id_name_entity.dart';
+
+
+FeedbackDetailEntity $FeedbackDetailEntityFromJson(Map<String, dynamic> json) {
+  final FeedbackDetailEntity feedbackDetailEntity = FeedbackDetailEntity();
+  final String? id = jsonConvert.convert<String>(json['id']);
+  if (id != null) {
+    feedbackDetailEntity.id = id;
+  }
+  final String? title = jsonConvert.convert<String>(json['title']);
+  if (title != null) {
+    feedbackDetailEntity.title = title;
+  }
+  final String? content = jsonConvert.convert<String>(json['content']);
+  if (content != null) {
+    feedbackDetailEntity.content = content;
+  }
+  final List<String>? resources = (json['resources'] as List<dynamic>?)?.map(
+          (e) => jsonConvert.convert<String>(e) as String).toList();
+  if (resources != null) {
+    feedbackDetailEntity.resources = resources;
+  }
+  final int? status = jsonConvert.convert<int>(json['status']);
+  if (status != null) {
+    feedbackDetailEntity.status = status;
+  }
+  final String? createdAt = jsonConvert.convert<String>(json['created_at']);
+  if (createdAt != null) {
+    feedbackDetailEntity.createdAt = createdAt;
+  }
+  final IdNameEntity? category = jsonConvert.convert<IdNameEntity>(json['category']);
+  if (category != null) {
+    feedbackDetailEntity.category = category;
+  }
+  final List<FeedbackDetailReplies>? replies = (json['replies'] as List<dynamic>?)?.map(
+          (e) => jsonConvert.convert<FeedbackDetailReplies>(e) as FeedbackDetailReplies).toList();
+  if (replies != null) {
+    feedbackDetailEntity.replies = replies;
+  }
+  return feedbackDetailEntity;
+}
+
+Map<String, dynamic> $FeedbackDetailEntityToJson(FeedbackDetailEntity entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['id'] = entity.id;
+  data['title'] = entity.title;
+  data['content'] = entity.content;
+  data['resources'] = entity.resources;
+  data['status'] = entity.status;
+  data['created_at'] = entity.createdAt;
+  data['category'] = entity.category?.toJson();
+  data['replies'] = entity.replies?.map((v) => v.toJson()).toList();
+  return data;
+}
+
+extension FeedbackDetailEntityExtension on FeedbackDetailEntity {
+  FeedbackDetailEntity copyWith({
+    String? id,
+    String? title,
+    String? content,
+    List<String>? resources,
+    int? status,
+    String? createdAt,
+    IdNameEntity? category,
+    List<FeedbackDetailReplies>? replies,
+  }) {
+    return FeedbackDetailEntity()
+      ..id = id ?? this.id
+      ..title = title ?? this.title
+      ..content = content ?? this.content
+      ..resources = resources ?? this.resources
+      ..status = status ?? this.status
+      ..createdAt = createdAt ?? this.createdAt
+      ..category = category ?? this.category
+      ..replies = replies ?? this.replies;
+  }
+}
+
+FeedbackDetailReplies $FeedbackDetailRepliesFromJson(Map<String, dynamic> json) {
+  final FeedbackDetailReplies feedbackDetailReplies = FeedbackDetailReplies();
+  final String? id = jsonConvert.convert<String>(json['id']);
+  if (id != null) {
+    feedbackDetailReplies.id = id;
+  }
+  final String? content = jsonConvert.convert<String>(json['content']);
+  if (content != null) {
+    feedbackDetailReplies.content = content;
+  }
+  final List<String>? resources = (json['resources'] as List<dynamic>?)?.map(
+          (e) => jsonConvert.convert<String>(e) as String).toList();
+  if (resources != null) {
+    feedbackDetailReplies.resources = resources;
+  }
+  final String? createdAt = jsonConvert.convert<String>(json['created_at']);
+  if (createdAt != null) {
+    feedbackDetailReplies.createdAt = createdAt;
+  }
+  final IdNameEntity? accountable = jsonConvert.convert<IdNameEntity>(json['accountable']);
+  if (accountable != null) {
+    feedbackDetailReplies.accountable = accountable;
+  }
+  return feedbackDetailReplies;
+}
+
+Map<String, dynamic> $FeedbackDetailRepliesToJson(FeedbackDetailReplies entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['id'] = entity.id;
+  data['content'] = entity.content;
+  data['resources'] = entity.resources;
+  data['created_at'] = entity.createdAt;
+  data['accountable'] = entity.accountable?.toJson();
+  return data;
+}
+
+extension FeedbackDetailRepliesExtension on FeedbackDetailReplies {
+  FeedbackDetailReplies copyWith({
+    String? id,
+    String? content,
+    List<String>? resources,
+    String? createdAt,
+    IdNameEntity? accountable,
+  }) {
+    return FeedbackDetailReplies()
+      ..id = id ?? this.id
+      ..content = content ?? this.content
+      ..resources = resources ?? this.resources
+      ..createdAt = createdAt ?? this.createdAt
+      ..accountable = accountable ?? this.accountable;
+  }
+}

+ 116 - 0
packages/cs_domain/lib/generated/json/feedback_list_entity.g.dart

@@ -0,0 +1,116 @@
+import 'package:domain/generated/json/base/json_convert_content.dart';
+import 'package:domain/entity/feedback_list_entity.dart';
+import 'package:domain/entity/id_name_entity.dart';
+
+
+FeedbackListEntity $FeedbackListEntityFromJson(Map<String, dynamic> json) {
+  final FeedbackListEntity feedbackListEntity = FeedbackListEntity();
+  final int? count = jsonConvert.convert<int>(json['count']);
+  if (count != null) {
+    feedbackListEntity.count = count;
+  }
+  final int? page = jsonConvert.convert<int>(json['page']);
+  if (page != null) {
+    feedbackListEntity.page = page;
+  }
+  final int? countPage = jsonConvert.convert<int>(json['count_page']);
+  if (countPage != null) {
+    feedbackListEntity.countPage = countPage;
+  }
+  final int? limit = jsonConvert.convert<int>(json['limit']);
+  if (limit != null) {
+    feedbackListEntity.limit = limit;
+  }
+  final List<FeedbackItemEntity>? list = (json['list'] as List<dynamic>?)?.map(
+          (e) => jsonConvert.convert<FeedbackItemEntity>(e) as FeedbackItemEntity).toList();
+  if (list != null) {
+    feedbackListEntity.list = list;
+  }
+  return feedbackListEntity;
+}
+
+Map<String, dynamic> $FeedbackListEntityToJson(FeedbackListEntity entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['count'] = entity.count;
+  data['page'] = entity.page;
+  data['count_page'] = entity.countPage;
+  data['limit'] = entity.limit;
+  data['list'] = entity.list?.map((v) => v.toJson()).toList();
+  return data;
+}
+
+extension FeedbackListEntityExtension on FeedbackListEntity {
+  FeedbackListEntity copyWith({
+    int? count,
+    int? page,
+    int? countPage,
+    int? limit,
+    List<FeedbackItemEntity>? list,
+  }) {
+    return FeedbackListEntity()
+      ..count = count ?? this.count
+      ..page = page ?? this.page
+      ..countPage = countPage ?? this.countPage
+      ..limit = limit ?? this.limit
+      ..list = list ?? this.list;
+  }
+}
+
+FeedbackItemEntity $FeedbackItemEntityFromJson(Map<String, dynamic> json) {
+  final FeedbackItemEntity feedbackItemEntity = FeedbackItemEntity();
+  final String? id = jsonConvert.convert<String>(json['id']);
+  if (id != null) {
+    feedbackItemEntity.id = id;
+  }
+  final String? title = jsonConvert.convert<String>(json['title']);
+  if (title != null) {
+    feedbackItemEntity.title = title;
+  }
+  final String? content = jsonConvert.convert<String>(json['content']);
+  if (content != null) {
+    feedbackItemEntity.content = content;
+  }
+  final int? status = jsonConvert.convert<int>(json['status']);
+  if (status != null) {
+    feedbackItemEntity.status = status;
+  }
+  final String? createdAt = jsonConvert.convert<String>(json['created_at']);
+  if (createdAt != null) {
+    feedbackItemEntity.createdAt = createdAt;
+  }
+  final IdNameEntity? category = jsonConvert.convert<IdNameEntity>(json['category']);
+  if (category != null) {
+    feedbackItemEntity.category = category;
+  }
+  return feedbackItemEntity;
+}
+
+Map<String, dynamic> $FeedbackItemEntityToJson(FeedbackItemEntity entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['id'] = entity.id;
+  data['title'] = entity.title;
+  data['content'] = entity.content;
+  data['status'] = entity.status;
+  data['created_at'] = entity.createdAt;
+  data['category'] = entity.category?.toJson();
+  return data;
+}
+
+extension FeedbackItemEntityExtension on FeedbackItemEntity {
+  FeedbackItemEntity copyWith({
+    String? id,
+    String? title,
+    String? content,
+    int? status,
+    String? createdAt,
+    IdNameEntity? category,
+  }) {
+    return FeedbackItemEntity()
+      ..id = id ?? this.id
+      ..title = title ?? this.title
+      ..content = content ?? this.content
+      ..status = status ?? this.status
+      ..createdAt = createdAt ?? this.createdAt
+      ..category = category ?? this.category;
+  }
+}

+ 123 - 3
packages/cs_domain/lib/repository/main_repository.dart

@@ -1,15 +1,17 @@
-import 'package:domain/entity/auth_login_entity.dart';
-import 'package:domain/entity/server_time.dart';
+import 'package:domain/entity/feedback_detail_entity.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:shared/utils/log_utils.dart';
 
 import '../constants/api_constants.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:plugin_basic/provider/http_provider/http_provider.dart';
 
+import '../entity/feedback_list_entity.dart';
+import '../entity/id_name_entity.dart';
+
 part 'main_repository.g.dart';
 
 @Riverpod(keepAlive: true)
@@ -26,5 +28,123 @@ class MainRepository {
 
   MainRepository({required this.dioEngine});
 
+  /// 获取反馈的分类
+  Future<HttpResult<IdNameEntity>> fetchFeedbackCategory({
+    CancelToken? cancelToken,
+  }) async {
+    final result = await dioEngine.requestNetResult(
+      ApiConstants.apiFeedbackCategory,
+      method: HttpMethod.GET,
+      isShowLoadingDialog: true,
+      networkDebounce: true,
+      cancelToken: cancelToken,
+    );
+
+    if (result.isSuccess) {
+      final jsonList = result.getListJson();
+
+      //获取List数据 需要转换一次
+      var list = jsonList
+          ?.map((value) {
+            if (value is Map<String, dynamic>) {
+              return IdNameEntity.fromJson(value);
+            } else {
+              return null;
+            }
+          })
+          .where((item) => item != null)
+          .cast<IdNameEntity>()
+          .toList();
+
+      return result.convert<IdNameEntity>(list: list);
+    }
+    return result.convert<IdNameEntity>();
+  }
+
+  /// 发布反馈
+  Future<HttpResult> postFeedback({
+    required String? categoryId,
+    required String? title,
+    required String? content,
+    List<String>? paths,
+    CancelToken? cancelToken,
+  }) async {
+    Map<String, String> params = {};
+    params['category_id'] = categoryId!;
+    params['title'] = title!;
+    params['content'] = content!;
+
+    Map<String, String> files = {};
+    if (paths != null && paths.isNotEmpty) {
+      paths.asMap().forEach((index, path) {
+        files["resources[$index]"] = path;
+      });
+    }
+
+    final result = await dioEngine.requestNetResult(
+      ApiConstants.apiFeedbackPost,
+      params: params,
+      paths: files,
+      method: HttpMethod.POST,
+      isShowLoadingDialog: true,
+      networkDebounce: true,
+      cancelToken: cancelToken,
+    );
+
+    if (result.isSuccess) {
+      return result.convert();
+    }
+    return result.convert();
+  }
+
+  /// 已发布的反馈列表
+  Future<HttpResult<FeedbackListEntity>> fetchFeedbackList({
+    required String status,
+    required int curPage,
+    CancelToken? cancelToken,
+  }) async {
+    Map<String, String> params = {};
+    params['status'] = status;
+    params['page'] = curPage.toString();
+    params['limit'] = "10";
+
+    final result = await dioEngine.requestNetResult(
+      ApiConstants.apiFeedbackList,
+      params: params,
+      method: HttpMethod.GET,
+      cancelToken: cancelToken,
+    );
+
+    if (result.isSuccess) {
+      final json = result.getDataJson();
+      var data = FeedbackListEntity.fromJson(json!);
+      return result.convert<FeedbackListEntity>(data: data);
+    }
+    return result.convert();
+  }
+
+  /// 获取反馈详情
+  Future<HttpResult<FeedbackDetailEntity>> fetchFeedbackDetail({
+    required String? id,
+    CancelToken? cancelToken,
+  }) async {
+    Map<String, String> params = {};
+    params['id'] = id??"";
+
+    final result = await dioEngine.requestNetResult(
+      ApiConstants.apiFeedbackDetail,
+      method: HttpMethod.GET,
+      params: params,
+      isShowLoadingDialog: true,
+      networkDebounce: true,
+      cancelToken: cancelToken,
+    );
 
+    if (result.isSuccess) {
+      final json = result.getDataJson();
+      var data = FeedbackDetailEntity.fromJson(json!);
+      return result.convert<FeedbackDetailEntity>(data: data);
+    }
+    return result.convert();
+  }
 }

+ 1 - 0
packages/cs_resources/lib/generated/intl/messages_en.dart

@@ -345,6 +345,7 @@ class MessageLookup extends MessageLookupByLibrary {
             "Kindly list all other sub-contractors who are involved in your renovation.\n\nIf you would like to leave the Management a note to accompany this application or have any special requests, please leave them here."),
         "renovation_start_date":
             MessageLookupByLibrary.simpleMessage("RENOVATION START DATE"),
+        "replied": MessageLookupByLibrary.simpleMessage("Replied"),
         "resend_code": MessageLookupByLibrary.simpleMessage("Resend Code"),
         "reset_password":
             MessageLookupByLibrary.simpleMessage("Reset Password"),

+ 10 - 0
packages/cs_resources/lib/generated/l10n.dart

@@ -2750,6 +2750,16 @@ class S {
     );
   }
 
+  /// `Replied`
+  String get replied {
+    return Intl.message(
+      'Replied',
+      name: 'replied',
+      desc: '',
+      args: [],
+    );
+  }
+
   /// `Other`
   String get other {
     return Intl.message(

+ 1 - 0
packages/cs_resources/lib/l10n/intl_en.arb

@@ -269,5 +269,6 @@
   "estate_upload_success_desc": "You have successfully submitted your application\n\nThe Management may take a few days to process your application\n\nOnce your application is approved you Will be notified via a push notification to the YY Home app\n\nKindly contact the Management if you would like to amend or check the status of your application",
   "send_email": "Email",
   "call_phone": "Call",
+  "replied": "Replied",
   "other": "Other"
 }

+ 1 - 0
packages/cs_resources/lib/l10n/intl_zh_CN.arb

@@ -269,5 +269,6 @@
   "estate_upload_success_desc": "您已成功提交申请\n\n管理员可能需要几天时间来处理您的申请\n\n一旦您的申请获得批准,您将通过推送通知YY Home应用程序收到通知\n\n如果您想修改或检查您的申请状态,请联系管理层",
   "send_email": "发送邮件",
   "call_phone": "拨打电话",
+  "replied": "已回复",
   "other": "其他"
 }

+ 1 - 0
packages/cs_resources/lib/l10n/intl_zh_HK.arb

@@ -255,5 +255,6 @@
   "estate_upload_success_desc": "您已成功提交申请\n\n管理员可能需要几天时间来处理您的申请\n\n一旦您的申请获得批准,您将通过推送通知YY Home应用程序收到通知\n\n如果您想修改或检查您的申请状态,请联系管理层",
   "send_email": "发送邮件",
   "call_phone": "拨打电话",
+  "replied": "已回复",
   "other": "其他"
 }