import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:hgdj/hj_model/comment/comment_model.dart'; import 'package:hgdj/hj_model/comment/reply_model.dart'; import 'package:hgdj/hj_page/comment/comment_input_view.dart'; import 'package:hgdj/hj_utils/api_service/comment_service.dart'; import 'package:hgdj/hj_utils/api_service/common_service.dart'; import 'package:hgdj/hj_utils/date_time_util.dart'; import 'package:hgdj/tools_base/debug_log.dart'; import 'package:hgdj/tools_base/toast.dart'; import 'package:pull_to_refresh/pull_to_refresh.dart'; import '../../hj_model/banner/comment_top_banner_model.dart'; import '../../hj_model/comment/comment_list_res.dart'; import '../../tools_base/file_upload/file_upload_tool.dart'; import '../../tools_base/file_upload/upload_result_model.dart'; mixin CommentMixin on GetxController { final comments = []; final commentController = TextEditingController(); Function(int)? totalCallback; CommentModel? replyComment; ReplyModel? replyCommentModel; int page = 1; String? hintText; Rx selectedImagePath = Rx(null); RefreshController? refreshCtr; final quickSearchList = []; final commentTopBanners = []; String? id; String? objType; RxBool isSendingMsg = false.obs; @override void onClose() { commentController.dispose(); super.onClose(); } Future sendComment() async { String content = commentController.text; if (content.isEmpty) { showToast('请输入评论内容哦~'); return; } isSendingMsg.value = true; String? sendImagePath; if (selectedImagePath.value?.isNotEmpty == true) { try { ImageUploadResultModel? imgResult = await FileUploadTool().uploadImage(selectedImagePath.value!); sendImagePath = imgResult?.coverImg ?? ""; if (sendImagePath.isEmpty) { isSendingMsg.value = false; showToast("图片上传失败!"); return; } } catch (e) { debugLog(e); isSendingMsg.value = false; showToast("图片上传失败!"); return; } } try { if (replyComment != null) { // 回复评论 final res = await CommentService.sendReply( id, 2, content, rid: replyCommentModel?.id, cid: replyComment?.id, toUserID: replyCommentModel?.toUserID, objType: objType, image: sendImagePath, ); if (res != null) { replyComment?.replies ??= []; replyComment?.replies?.insert(0, res); replyComment?.commCount = replyComment?.replies?.length ?? 0; replyComment = null; replyCommentModel = null; hintText = null; showToast('已提交,审核通过后将展示'); } update(); } else { // 评论 final res = await CommentService.sendComment( id, 1, content, objType ?? '', image: sendImagePath, ); if (res == null) { hintText = null; } else { showToast('已提交,审核通过后将展示'); hintText = null; //插在第一条普通评论前面,置顶那几条不动 final insertIndex = comments.indexWhere((e) => !e.isHideLikeOrComment); comments.insert( insertIndex == -1 ? comments.length : insertIndex, res); } update(); } } catch (e) { debugLog(e); } selectedImagePath.value = null; commentController.text = ""; isSendingMsg.value = false; } // isSend: true 点击了发送按钮, 如果没有发送内容弹键盘, 有内容直接发送 readyReplyComment(CommentModel? comment, {ReplyModel? replyModel, bool? isSend}) async { replyComment = comment; replyCommentModel = replyModel; if (replyModel != null) { hintText = '回复:${replyModel.userName ?? ''}'; } if (comment != null && hintText == null) { hintText = '回复:${comment.userName ?? ''}'; } if (isSend == true && commentController.text.isNotEmpty) { update(); sendComment(); } else { final result = await Get.bottomSheet( CommentInputView( hint: hintText, textCtr: commentController, imgPath: selectedImagePath.value, onImgChange: (value) => selectedImagePath.value = value, ), backgroundColor: Colors.transparent, barrierColor: Colors.transparent, enableDrag: false, settings: RouteSettings(name: CommentInputView.routeName), useRootNavigator: true, ); if (result == true) { update(); sendComment(); } } } // 获取评论 Future fetchComments(String id, {bool isRefresh = false}) async { try { if (isRefresh) { page = 1; } final currentT = DateTimeUtil.format2utc(DateTime.now()) ?? ""; final result = await CommentService.getCommentList(id, currentT, page, 20); totalCallback?.call(result?.total ?? 0); refreshCtr?.refreshCompleted(); refreshCtr?.loadComplete(); if (!(result?.hasNext ?? false)) { refreshCtr?.loadNoData(); } if (page == 1) { comments.clear(); quickSearchList.clear(); // 首屏并行拉置顶 Banner;失败不影响评论列表 _fetchCommentTopBanners(); } comments.addAll(result?.list ?? []); if (page == 1) { quickSearchList.addAll(result?.quickSearchList ?? []); } page += 1; for (final e in comments) { e.hasMoreReply = (e.commCount ?? 0) > (e.replies?.length ?? 0); } } catch (e) { refreshCtr?.refreshCompleted(); refreshCtr?.loadComplete(); debugLog(e); } update(); } /// 评论区置顶 Banner(scene=COMMENT_TOP) Future _fetchCommentTopBanners() async { try { final list = await CommonService.fetchBannerList(scene: 'COMMENT_TOP'); commentTopBanners ..clear() ..addAll(list); update(); } catch (e) { debugLog(e); } } /// 首条置顶评论下标:官方评论或带内外链的置顶样式评论 int get topPinnedCommentIndex { for (int i = 0; i < comments.length; i++) { final c = comments[i]; if (c.isOfficial || c.isHideLikeOrComment) return i; } return -1; } }