From c5c303282a70379ff87a7898dd0ea8445cb4c2dd Mon Sep 17 00:00:00 2001 From: YakumoChen Date: Thu, 2 Apr 2026 00:30:33 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/controller/home/report_controller.dart | 16 +- .../home/user_information_controller.dart | 23 + .../message/chat_settings_controller.dart | 2 +- .../mine/real_feedback_controller.dart | 247 ++++++++++ .../setting/blacklist_controller.dart | 85 ++++ lib/model/mine/blacklist_data.dart | 72 +++ lib/network/api_urls.dart | 17 + lib/network/home_api.dart | 5 + lib/network/home_api.g.dart | 34 ++ lib/network/user_api.dart | 22 + lib/network/user_api.g.dart | 139 ++++++ lib/pages/home/report_page.dart | 6 +- lib/pages/home/timeline_info.dart | 2 +- lib/pages/home/timeline_item.dart | 2 +- lib/pages/home/user_information_page.dart | 3 +- lib/pages/mine/feedback_page.dart | 339 +++---------- lib/pages/mine/mine_page.dart | 4 +- lib/pages/mine/real_feedback_page.dart | 460 ++++++++++++++++++ lib/pages/setting/blacklist_page.dart | 221 +++++++-- 19 files changed, 1362 insertions(+), 337 deletions(-) create mode 100644 lib/controller/mine/real_feedback_controller.dart create mode 100644 lib/controller/setting/blacklist_controller.dart create mode 100644 lib/model/mine/blacklist_data.dart create mode 100644 lib/pages/mine/real_feedback_page.dart diff --git a/lib/controller/home/report_controller.dart b/lib/controller/home/report_controller.dart index 4fa33d9..d595d9f 100644 --- a/lib/controller/home/report_controller.dart +++ b/lib/controller/home/report_controller.dart @@ -12,7 +12,9 @@ import 'package:permission_handler/permission_handler.dart'; class ReportController extends GetxController { final String id; - ReportController({required this.id}); + final String userId; + final int type; + ReportController({required this.id, required this.userId, required this.type}); final checked = 1.obs; @@ -198,11 +200,15 @@ class ReportController extends GetxController { try { if(isClick.value) return; isClick.value = true; - final response = await _homeApi.userReportPost({ + final response = await _homeApi.userCommitUserReport({ "id": id, - "reportPicUrls": imgList.isNotEmpty ? imgList.join(",") : "", - "reportContent": message.value, - "reportReason": checked.value + "images": imgList.isNotEmpty ? imgList.join(",") : "", + "content": message.value, + "addUserBlacklist": blockUser.value, + "reportType": checked.value, + "targetId": id, + "targetType": type, + "targetUserId": userId, }); if (response.data.isSuccess) { diff --git a/lib/controller/home/user_information_controller.dart b/lib/controller/home/user_information_controller.dart index 5ac9a78..6a29bf8 100644 --- a/lib/controller/home/user_information_controller.dart +++ b/lib/controller/home/user_information_controller.dart @@ -68,6 +68,29 @@ class UserInformationController extends GetxController { } } + createUserBlack() async { + try { + final response = await _userApi.userCreateUserBlacklist({ + "blackUserId": userData.value.miUserId, + }); + if (response.data.isSuccess) { + + SmartDialog.showToast('已拉黑成功'); + } else { + + // 响应失败,抛出异常 + throw Exception(response.data.message ?? '获取数据失败'); + } + } catch(e){ + print('拉黑失败: $e'); + SmartDialog.showToast('拉黑失败'); + rethrow; + + } finally { + + } + } + int calculateAge(String birthdayStr) { final birthday = DateTime.parse(birthdayStr); // 自动识别 1996-1-20 final today = DateTime.now(); diff --git a/lib/controller/message/chat_settings_controller.dart b/lib/controller/message/chat_settings_controller.dart index 2eed191..3fdc16e 100644 --- a/lib/controller/message/chat_settings_controller.dart +++ b/lib/controller/message/chat_settings_controller.dart @@ -494,7 +494,7 @@ class ChatSettingsController extends GetxController { /// 举报用户 void reportUser() { // 跳转到举报页面 - Get.to(() => ReportPage(id: "",)); + Get.to(() => ReportPage(id: userId, userId: userId, type: 1,)); } /// 跳转到用户主页 diff --git a/lib/controller/mine/real_feedback_controller.dart b/lib/controller/mine/real_feedback_controller.dart new file mode 100644 index 0000000..4db1fc6 --- /dev/null +++ b/lib/controller/mine/real_feedback_controller.dart @@ -0,0 +1,247 @@ +import 'dart:io'; + +import 'package:dating_touchme_app/network/user_api.dart'; +import 'package:dating_touchme_app/oss/oss_manager.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; +import 'package:get/get.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:permission_handler/permission_handler.dart'; + +class RealFeedbackController extends GetxController { + final int type; + RealFeedbackController({required this.type}); + + + late UserApi _userApi; + final message = ''.obs; + final messageController = TextEditingController().obs; + + final tagList = [].obs; + + final active = 0.obs; + + final imgList = [].obs; + + changeActive(int i){ + active.value = i; + } + + @override + void onInit() { + super.onInit(); + _userApi = Get.find(); + if(type == 1){ + tagList.value = [ + {"label": "账号异常", "value": 101}, + {"label": "违规与封禁", "value": 102}, + {"label": "头像/签名/实名认证", "value": 103}, + ]; + } else if(type == 2){ + tagList.value = [ + {"label": "私信相关", "value": 201}, + {"label": "资料相关", "value": 202}, + {"label": "动态相关", "value": 203}, + {"label": "直播间相关", "value": 204}, + ]; + } else if(type == 3){ + tagList.value = [ + {"label": "举报有人诈骗", "value": 301}, + {"label": "举报有人涉嫌诱导", "value": 302}, + {"label": "其他不良行为举报", "value": 303}, + {"label": "虚假宣传广告投诉", "value": 304}, + {"label": "未成年问题", "value": 305}, + {"label": "智能推荐相关", "value": 306}, + ]; + } + } + + + + // 选择头像 - 业务逻辑处理 + Future handleCameraCapture() async { + try { + // 请求相机权限 + final ok = await _ensurePermission( + Permission.camera, + denyToast: '相机权限被拒绝,请在设置中允许访问相机', + ); + if (!ok) return; + + // 请求麦克风权限(部分设备拍照/录像会一并请求建议预授权) + await _ensurePermission(Permission.microphone, denyToast: '麦克风权限被拒绝'); + + // 权限通过后拍照 + final ImagePicker picker = ImagePicker(); + final XFile? photo = await picker.pickImage(source: ImageSource.camera); + + if (photo != null) { + await processSelectedImage(File(photo.path)); + } + } catch (e) { + print('拍照失败: $e'); + // 更友好的错误提示 + if (e.toString().contains('permission') || e.toString().contains('权限')) { + SmartDialog.showToast('相机权限被拒绝,请在设置中允许访问相机'); + } else if (e.toString().contains('camera') || + e.toString().contains('相机')) { + SmartDialog.showToast('设备没有可用的相机'); + } else { + SmartDialog.showToast('拍照失败,请重试'); + } + } + } + + Future handleGallerySelection() async { + try { + // 请求相册/照片权限 + // final ok = await _ensurePermission( + // Permission.photos, + // // Android 上 photos 等价于 storage/mediaLibrary,permission_handler 会映射 + // denyToast: '相册权限被拒绝,请在设置中允许访问相册', + + // ); + // if (!ok) return; + + // 从相册选择图片 + final ImagePicker picker = ImagePicker(); + final XFile? image = await picker.pickImage(source: ImageSource.gallery); + + if (image != null) { + await processSelectedImage(File(image.path)); + } + } catch (e) { + print('选择图片失败: $e'); + // 更友好的错误提示 + if (e.toString().contains('permission') || e.toString().contains('权限')) { + SmartDialog.showToast('相册权限被拒绝,请在设置中允许访问相册'); + } else { + SmartDialog.showToast('选择图片失败,请重试'); + } + } + } + + Future handleMultiGallerySelection() async { + try { + // 请求相册/照片权限 + // final ok = await _ensurePermission( + // Permission.photos, + // // Android 上 photos 等价于 storage/mediaLibrary,permission_handler 会映射 + // denyToast: '相册权限被拒绝,请在设置中允许访问相册', + + // ); + // if (!ok) return; + + // 从相册选择图片 + final ImagePicker picker = ImagePicker(); + final List? image = await picker.pickMultiImage(limit: 9 - imgList.length); + + if (image != null) { + final futures = image.map((e){ + return processSelectedMoreImage(File(e.path)); + }); + final list = await Future.wait(futures); + imgList.addAll(list); + print(imgList); + SmartDialog.dismiss(); + SmartDialog.showToast('上传相册成功'); + + + } + } catch (e) { + print('选择图片失败: $e'); + // 更友好的错误提示 + if (e.toString().contains('permission') || e.toString().contains('权限')) { + SmartDialog.showToast('相册权限被拒绝,请在设置中允许访问相册'); + } else { + SmartDialog.showToast('选择图片失败,请重试'); + } + } + } + + // 通用权限申请 + Future _ensurePermission(Permission permission, {String? denyToast}) async { + var status = await permission.status; + if (status.isGranted) return true; + + if (status.isDenied || status.isRestricted || status.isLimited) { + status = await permission.request(); + if (status.isGranted) return true; + if (denyToast != null) SmartDialog.showToast(denyToast); + return false; + } + + if (status.isPermanentlyDenied) { + if (denyToast != null) SmartDialog.showToast('$denyToast,前往系统设置开启'); + // 延迟弹设置,避免与弹窗冲突 + Future.delayed(const Duration(milliseconds: 300), openAppSettings); + return false; + } + return false; + } + + + // 处理选中的图片 + Future processSelectedImage(File imageFile) async { + try { + // 显示加载提示 + SmartDialog.showLoading(msg: '上传相册中...'); + String objectName = '${DateUtil.getNowDateMs()}.${imageFile.path.split('.').last}'; + String imageUrl = await OSSManager.instance.uploadFile(imageFile.readAsBytesSync(), objectName); + print('上传成功,图片URL: $imageUrl'); + imgList.add(imageUrl); + SmartDialog.dismiss(); + SmartDialog.showToast('相册上传成功'); + + + } catch (e) { + SmartDialog.dismiss(); + print('处理图片失败: $e'); + SmartDialog.showToast('上传相册失败,请重试'); + } + } + // 处理选中的图片 + Future processSelectedMoreImage(File imageFile) async { + try { + // 显示加载提示 + SmartDialog.showLoading(msg: '上传相册中...'); + String objectName = '${DateUtil.getNowDateMs()}.${imageFile.path.split('.').last}'; + String imageUrl = await OSSManager.instance.uploadFile(imageFile.readAsBytesSync(), objectName); + print('上传成功,图片URL: $imageUrl'); + return imageUrl; + } catch (e) { + SmartDialog.dismiss(); + print('处理图片失败: $e'); + SmartDialog.showToast('上传相册失败,请重试'); + return ""; + } + } + + + sendFeedback() async { + try { + final response = await _userApi.userCreateUserFeedback({ + "images": imgList.isNotEmpty ? imgList.join(",") : "", + "content": message.value, + "feedbackType": active.value, + }); + if (response.data.isSuccess) { + + SmartDialog.showToast('反馈已提交成功'); + Get.until((route) => route.isFirst); + } else { + + // 响应失败,抛出异常 + throw Exception(response.data.message ?? '获取数据失败'); + } + } catch(e){ + print('反馈提交失败: $e'); + SmartDialog.showToast('反馈提交失败'); + rethrow; + + } finally { + + } + } +} \ No newline at end of file diff --git a/lib/controller/setting/blacklist_controller.dart b/lib/controller/setting/blacklist_controller.dart new file mode 100644 index 0000000..8c65062 --- /dev/null +++ b/lib/controller/setting/blacklist_controller.dart @@ -0,0 +1,85 @@ +import 'package:dating_touchme_app/network/user_api.dart'; +import 'package:easy_refresh/easy_refresh.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; +import 'package:get/get.dart'; +import 'package:dating_touchme_app/model/mine/blacklist_data.dart'; + +class BlacklistController extends GetxController { + + late UserApi _userApi; + + final page = 1.obs; + final size = 10.obs; + + late final EasyRefreshController listRefreshController; + + final blackList = [].obs; + + + @override + void onInit() { + super.onInit(); + + listRefreshController = EasyRefreshController( + controlFinishRefresh: true, + controlFinishLoad: true, + ); + _userApi = Get.find(); + getBlackList(); + } + + + + getBlackList() async { + try{ + final response = await _userApi.userPageUserBlacklist( + pageNum: page.value, + pageSize: size.value, + ); + if (response.data.isSuccess && response.data.data != null) { + final data = response.data.data?.records ?? []; + + blackList.addAll(data.toList()); + if((data.length ?? 0) == size.value){ + + listRefreshController.finishLoad(IndicatorResult.success); + } else { + listRefreshController.finishLoad(IndicatorResult.noMore); + } + } else { + + // 响应失败,抛出异常 + throw Exception(response.data.message ?? '获取数据失败'); + } + } catch(e) { + print('玫瑰记录获取失败: $e'); + SmartDialog.showToast('玫瑰记录获取失败'); + rethrow; + } + } + + unBlack(String blackUserId) async { + try { + final response = await _userApi.userDeleteUserBlacklist({ + "blackUserId": blackUserId, + }); + if (response.data.isSuccess) { + + SmartDialog.showToast('已解除拉黑'); + blackList.value = blackList.where((e) => e.blackUserId != blackUserId).toList(); + } else { + + // 响应失败,抛出异常 + throw Exception(response.data.message ?? '获取数据失败'); + } + } catch(e){ + print('解除拉黑失败: $e'); + SmartDialog.showToast('解除拉黑失败'); + rethrow; + + } finally { + + } + } + +} \ No newline at end of file diff --git a/lib/model/mine/blacklist_data.dart b/lib/model/mine/blacklist_data.dart new file mode 100644 index 0000000..ce8bbb5 --- /dev/null +++ b/lib/model/mine/blacklist_data.dart @@ -0,0 +1,72 @@ +class BlacklistData { + List? records; + int? total; + int? size; + int? current; + int? pages; + + BlacklistData( + {this.records, this.total, this.size, this.current, this.pages}); + + BlacklistData.fromJson(Map json) { + if (json['records'] != null) { + records = []; + json['records'].forEach((v) { + records!.add(new Records.fromJson(v)); + }); + } + total = json['total']; + size = json['size']; + current = json['current']; + pages = json['pages']; + } + + Map toJson() { + final Map data = new Map(); + if (this.records != null) { + data['records'] = this.records!.map((v) => v.toJson()).toList(); + } + data['total'] = this.total; + data['size'] = this.size; + data['current'] = this.current; + data['pages'] = this.pages; + return data; + } +} + +class Records { + String? id; + String? blackUserId; + String? miId; + String? nickName; + String? profilePhoto; + String? createTime; + + Records( + {this.id, + this.blackUserId, + this.miId, + this.nickName, + this.profilePhoto, + this.createTime}); + + Records.fromJson(Map json) { + id = json['id']; + blackUserId = json['blackUserId']; + miId = json['miId']; + nickName = json['nickName']; + profilePhoto = json['profilePhoto']; + createTime = json['createTime']; + } + + Map toJson() { + final Map data = new Map(); + data['id'] = this.id; + data['blackUserId'] = this.blackUserId; + data['miId'] = this.miId; + data['nickName'] = this.nickName; + data['profilePhoto'] = this.profilePhoto; + data['createTime'] = this.createTime; + return data; + } +} diff --git a/lib/network/api_urls.dart b/lib/network/api_urls.dart index 58931f7..626f086 100644 --- a/lib/network/api_urls.dart +++ b/lib/network/api_urls.dart @@ -236,4 +236,21 @@ class ApiUrls { static const String userPageLiveMatchmaker = 'dating-agency-chat-audio/user/page/live-matchmaker'; + static const String userCommitUserReport = + 'dating-agency-chat-audio/user/commit/user-report'; + + static const String userCreateUserBlacklist = + 'dating-agency-chat-audio/user/create/user-blacklist'; + + + static const String userDeleteUserBlacklist = + 'dating-agency-chat-audio/user/delete/user-blacklist'; + + + static const String userPageUserBlacklist = + 'dating-agency-chat-audio/user/page/user-blacklist'; + + static const String userCreateUserFeedback = + 'dating-agency-service/user/create/user-feedback'; + } diff --git a/lib/network/home_api.dart b/lib/network/home_api.dart index 18ee3b0..11cbbb2 100644 --- a/lib/network/home_api.dart +++ b/lib/network/home_api.dart @@ -99,4 +99,9 @@ abstract class HomeApi { @Query('pageSize') required int pageSize, }); + @POST(ApiUrls.userCommitUserReport) + Future>> userCommitUserReport( + @Body() Map data, + ); + } \ No newline at end of file diff --git a/lib/network/home_api.g.dart b/lib/network/home_api.g.dart index f7250ae..4de6132 100644 --- a/lib/network/home_api.g.dart +++ b/lib/network/home_api.g.dart @@ -531,6 +531,40 @@ class _HomeApi implements HomeApi { return httpResponse; } + @override + Future>> userCommitUserReport( + Map data, + ) async { + final _extra = {}; + final queryParameters = {}; + final _headers = {}; + final _data = {}; + _data.addAll(data); + final _options = _setStreamType>>( + Options(method: 'POST', headers: _headers, extra: _extra) + .compose( + _dio.options, + 'dating-agency-chat-audio/user/commit/user-report', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); + final _result = await _dio.fetch>(_options); + late BaseResponse _value; + try { + _value = BaseResponse.fromJson( + _result.data!, + (json) => json as dynamic, + ); + } on Object catch (e, s) { + errorLogger?.logError(e, s, _options); + rethrow; + } + final httpResponse = HttpResponse(_value, _result); + return httpResponse; + } + RequestOptions _setStreamType(RequestOptions requestOptions) { if (T != dynamic && !(requestOptions.responseType == ResponseType.bytes || diff --git a/lib/network/user_api.dart b/lib/network/user_api.dart index 33cae6f..5e00445 100644 --- a/lib/network/user_api.dart +++ b/lib/network/user_api.dart @@ -4,6 +4,7 @@ import 'package:dating_touchme_app/model/home/post_data.dart'; import 'package:dating_touchme_app/model/home/user_info_data.dart'; import 'package:dating_touchme_app/model/mine/bank_card_data.dart'; import 'package:dating_touchme_app/model/mine/bank_card_ocr_data.dart'; +import 'package:dating_touchme_app/model/mine/blacklist_data.dart'; import 'package:dating_touchme_app/model/mine/connect_history_data.dart'; import 'package:dating_touchme_app/model/mine/education_data.dart'; import 'package:dating_touchme_app/model/mine/friend_apply_data.dart'; @@ -313,4 +314,25 @@ abstract class UserApi { @Query('pageSize') required int pageSize, @Query('authorUserId') required String authorUserId, }); + + @POST(ApiUrls.userCreateUserBlacklist) + Future>> userCreateUserBlacklist( + @Body() Map data, + ); + + @GET(ApiUrls.userPageUserBlacklist) + Future>> userPageUserBlacklist({ + @Query('pageNum') required int pageNum, + @Query('pageSize') required int pageSize, + }); + + @POST(ApiUrls.userDeleteUserBlacklist) + Future>> userDeleteUserBlacklist( + @Body() Map data, + ); + + @POST(ApiUrls.userCreateUserFeedback) + Future>> userCreateUserFeedback( + @Body() Map data, + ); } diff --git a/lib/network/user_api.g.dart b/lib/network/user_api.g.dart index 7979581..323ce70 100644 --- a/lib/network/user_api.g.dart +++ b/lib/network/user_api.g.dart @@ -1896,6 +1896,145 @@ class _UserApi implements UserApi { return httpResponse; } + @override + Future>> userCreateUserBlacklist( + Map data, + ) async { + final _extra = {}; + final queryParameters = {}; + final _headers = {}; + final _data = {}; + _data.addAll(data); + final _options = _setStreamType>>( + Options(method: 'POST', headers: _headers, extra: _extra) + .compose( + _dio.options, + 'dating-agency-chat-audio/user/create/user-blacklist', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); + final _result = await _dio.fetch>(_options); + late BaseResponse _value; + try { + _value = BaseResponse.fromJson( + _result.data!, + (json) => json as dynamic, + ); + } on Object catch (e, s) { + errorLogger?.logError(e, s, _options); + rethrow; + } + final httpResponse = HttpResponse(_value, _result); + return httpResponse; + } + + @override + Future>> userPageUserBlacklist({ + required int pageNum, + required int pageSize, + }) async { + final _extra = {}; + final queryParameters = { + r'pageNum': pageNum, + r'pageSize': pageSize, + }; + final _headers = {}; + const Map? _data = null; + final _options = _setStreamType>>( + Options(method: 'GET', headers: _headers, extra: _extra) + .compose( + _dio.options, + 'dating-agency-chat-audio/user/page/user-blacklist', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); + final _result = await _dio.fetch>(_options); + late BaseResponse _value; + try { + _value = BaseResponse.fromJson( + _result.data!, + (json) => BlacklistData.fromJson(json as Map), + ); + } on Object catch (e, s) { + errorLogger?.logError(e, s, _options); + rethrow; + } + final httpResponse = HttpResponse(_value, _result); + return httpResponse; + } + + @override + Future>> userDeleteUserBlacklist( + Map data, + ) async { + final _extra = {}; + final queryParameters = {}; + final _headers = {}; + final _data = {}; + _data.addAll(data); + final _options = _setStreamType>>( + Options(method: 'POST', headers: _headers, extra: _extra) + .compose( + _dio.options, + 'dating-agency-chat-audio/user/delete/user-blacklist', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); + final _result = await _dio.fetch>(_options); + late BaseResponse _value; + try { + _value = BaseResponse.fromJson( + _result.data!, + (json) => json as dynamic, + ); + } on Object catch (e, s) { + errorLogger?.logError(e, s, _options); + rethrow; + } + final httpResponse = HttpResponse(_value, _result); + return httpResponse; + } + + @override + Future>> userCreateUserFeedback( + Map data, + ) async { + final _extra = {}; + final queryParameters = {}; + final _headers = {}; + final _data = {}; + _data.addAll(data); + final _options = _setStreamType>>( + Options(method: 'POST', headers: _headers, extra: _extra) + .compose( + _dio.options, + 'dating-agency-service/user/create/user-feedback', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); + final _result = await _dio.fetch>(_options); + late BaseResponse _value; + try { + _value = BaseResponse.fromJson( + _result.data!, + (json) => json as dynamic, + ); + } on Object catch (e, s) { + errorLogger?.logError(e, s, _options); + rethrow; + } + final httpResponse = HttpResponse(_value, _result); + return httpResponse; + } + RequestOptions _setStreamType(RequestOptions requestOptions) { if (T != dynamic && !(requestOptions.responseType == ResponseType.bytes || diff --git a/lib/pages/home/report_page.dart b/lib/pages/home/report_page.dart index f174a30..279ce6e 100644 --- a/lib/pages/home/report_page.dart +++ b/lib/pages/home/report_page.dart @@ -10,7 +10,9 @@ import 'package:tdesign_flutter/tdesign_flutter.dart'; class ReportPage extends StatelessWidget { final String id; - const ReportPage({super.key, required this.id}); + final String userId; + final int type; + const ReportPage({super.key, required this.id, required this.userId, required this.type}); @@ -109,7 +111,7 @@ class ReportPage extends StatelessWidget { @override Widget build(BuildContext context) { return GetX( - init: ReportController(id: id), + init: ReportController(id: id, userId: userId, type: type), builder: (controller){ return Scaffold( appBar: PageAppbar(title: "举报中心"), diff --git a/lib/pages/home/timeline_info.dart b/lib/pages/home/timeline_info.dart index 3c5b25a..53d5aa4 100644 --- a/lib/pages/home/timeline_info.dart +++ b/lib/pages/home/timeline_info.dart @@ -62,7 +62,7 @@ class TimelineInfo extends StatelessWidget { onSelected: (v) { if (v == 'report') { print("举报"); - Get.to(() => ReportPage(id: id,)); + Get.to(() => ReportPage(id: id, userId: controller.item.value.userId ?? "", type: 2,)); } }, child: Icon( diff --git a/lib/pages/home/timeline_item.dart b/lib/pages/home/timeline_item.dart index 9c52e3b..a289d67 100644 --- a/lib/pages/home/timeline_item.dart +++ b/lib/pages/home/timeline_item.dart @@ -216,7 +216,7 @@ class _TimelineItemState extends State { onSelected: (v) { if (v == 'report') { print("举报"); - Get.to(() => ReportPage(id: widget.item.id ?? "",)); + Get.to(() => ReportPage(id: widget.item.id ?? "", userId: widget.item.userId ?? "", type: 2,)); } }, child: Icon( diff --git a/lib/pages/home/user_information_page.dart b/lib/pages/home/user_information_page.dart index ec0b3a0..70135fa 100644 --- a/lib/pages/home/user_information_page.dart +++ b/lib/pages/home/user_information_page.dart @@ -479,9 +479,10 @@ class UserInformationPage extends StatelessWidget { onSelected: (v) { if (v == 'report') { print("举报"); - Get.to(() => ReportPage(id: "",)); + Get.to(() => ReportPage(id: controller.userData.value.miUserId ?? "", userId: controller.userData.value.miUserId ?? "", type: 1,)); } else if (v == 'block') { print("拉黑"); + controller.createUserBlack(); } }, child: Container( diff --git a/lib/pages/mine/feedback_page.dart b/lib/pages/mine/feedback_page.dart index 5a1e2ba..af0baf7 100644 --- a/lib/pages/mine/feedback_page.dart +++ b/lib/pages/mine/feedback_page.dart @@ -1,9 +1,17 @@ import 'package:dating_touchme_app/components/page_appbar.dart'; import 'package:dating_touchme_app/extension/ex_widget.dart'; import 'package:dating_touchme_app/generated/assets.dart'; +import 'package:dating_touchme_app/pages/mine/real_feedback_page.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:dating_touchme_app/components/page_appbar.dart'; +import 'package:dating_touchme_app/extension/ex_widget.dart'; +import 'package:dating_touchme_app/generated/assets.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; + class FeedbackPage extends StatefulWidget { const FeedbackPage({super.key}); @@ -93,234 +101,75 @@ class _FeedbackPageState extends State { child: Container( width: 375.w, padding: EdgeInsets.symmetric( - vertical: 11.w, - horizontal: 14.w + vertical: 15.w, + horizontal: 10.w ), decoration: BoxDecoration( borderRadius: BorderRadius.vertical(top: Radius.circular(9.w)), color: Colors.white ), - child: SingleChildScrollView( + child: Container( + width: 355.w, + height: 150.w, + padding: EdgeInsets.only( + left: 17.w, + right: 10.w + ), + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(9.w)), + color: const Color.fromRGBO(250, 250, 250, 1) + ), child: Column( - crossAxisAlignment: CrossAxisAlignment.start, children: [ - RichText( - text: TextSpan( - style: TextStyle( - fontSize: 16.w, - fontWeight: FontWeight.w500 - ), - children: [ - TextSpan( - text: "选择问题的类型", - style: TextStyle( - color: const Color.fromRGBO(51, 51, 51, 1) - ) - ), - TextSpan( - text: "*", - style: TextStyle( - color: const Color.fromRGBO(248, 85, 66, 1) - ) - ) - ] - ), - ), - SizedBox(height: 11.w,), - Wrap( - alignment: WrapAlignment.spaceBetween, - spacing: 10.w, - runSpacing: 10.w, - children: [ - ...tagList.asMap().entries.map((entry){ - return TagItem(title: entry.value, index: entry.key, active: active, changeActive: changeActive,); - }), - ], - ), SizedBox(height: 20.w,), - RichText( - text: TextSpan( - style: TextStyle( - fontSize: 16.w, - fontWeight: FontWeight.w500 - ), - children: [ - TextSpan( - text: "问题描述", - style: TextStyle( - color: const Color.fromRGBO(51, 51, 51, 1) - ) - ), - TextSpan( - text: "*", - style: TextStyle( - color: const Color.fromRGBO(248, 85, 66, 1) - ) - ) - ] - ), - ), - SizedBox(height: 11.w,), - Container( - padding: EdgeInsets.all(14.w), - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(8.w)), - color: const Color.fromRGBO(245, 245, 245, 1) - ), - child: TextField( - controller: _messageController, - maxLength: 500, // 上限 - minLines: 5, // 多行 - maxLines: 5, // 自适应高度 - style: TextStyle( - fontSize: ScreenUtil().setWidth(13), - height: 1 - ), - decoration: InputDecoration( - contentPadding: EdgeInsets.symmetric( - vertical: 0, - horizontal: 0 - ), - hintText: "请输入交友心声", - - border: const OutlineInputBorder( - borderSide: BorderSide.none, // 这将移除边框 // 可选:设置圆角 - ), - // 如果你希望聚焦时和未聚焦时都没有边框,也可以设置 focusedBorder 和 enabledBorder - focusedBorder: const OutlineInputBorder( - borderSide: BorderSide.none, - borderRadius: BorderRadius.all(Radius.circular(8.0)), - ), - enabledBorder: const OutlineInputBorder( - borderSide: BorderSide.none, - borderRadius: BorderRadius.all(Radius.circular(8.0)), - ), - ), - onChanged: (value){ - message = value; - }, - ), - ), - SizedBox(height: 10.w,), - Wrap( - alignment: WrapAlignment.spaceBetween, - spacing: 10.w, - runSpacing: 10.w, + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Container( - width: 70.w, - height: 70.w, - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(9.w)), - border: Border.all(width: 1, color: const Color.fromRGBO(224, 224, 224, 1)) - ), - child: Center( - child: Icon( - Icons.add, - size: 18.w, - color: const Color.fromRGBO(224, 224, 224, 1) - ), - ), + Text( + "账号与个人信息", ), + Icon( + Icons.arrow_right, + size: 20.w, + color: const Color.fromRGBO(204, 204, 2074, 1), + ) ], - ), - SizedBox(height: 10.w,), - Text( - "上传问题截图可以让问题快速解决!", - style: TextStyle( - fontSize: 11.w, - color: const Color.fromRGBO(189, 189, 189, 1) - ), - ), - SizedBox(height: 20.w,), - RichText( - text: TextSpan( - style: TextStyle( - fontSize: 16.w, - fontWeight: FontWeight.w500 - ), - children: [ - TextSpan( - text: "联系方式", - style: TextStyle( - color: const Color.fromRGBO(51, 51, 51, 1) - ) - ), - ] - ), - ), - Container( - padding: EdgeInsets.symmetric(horizontal: 13.w), - margin: EdgeInsets.only(top: 7.w), - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(8.w)), - color: const Color.fromRGBO(245, 245, 245, 1) - ), - child: TextField( - controller: _phoneController, - keyboardType: TextInputType.number, - style: TextStyle( - fontSize: ScreenUtil().setWidth(14), - height: 1 - ), - decoration: InputDecoration( - hintText: "留下手机号、QQ、邮箱,以便我们回复您", - contentPadding: EdgeInsets.symmetric( - vertical: 0, - horizontal: 0 - ), - - border: const OutlineInputBorder( - borderSide: BorderSide.none, // 这将移除边框 // 可选:设置圆角 - ), - // 如果你希望聚焦时和未聚焦时都没有边框,也可以设置 focusedBorder 和 enabledBorder - focusedBorder: const OutlineInputBorder( - borderSide: BorderSide.none, - borderRadius: BorderRadius.all(Radius.circular(8.0)), - ), - enabledBorder: const OutlineInputBorder( - borderSide: BorderSide.none, - borderRadius: BorderRadius.all(Radius.circular(8.0)), - ), - ), - onChanged: (value){ - phone = value; - setState(() { - - }); - }, - ), - ), - Container( - margin: EdgeInsets.symmetric(vertical: 30.w), - child: Container( - width: 350.w, - height: 45.w, - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(45.w)), - gradient: LinearGradient( - begin: Alignment.centerLeft, // 90deg: 从左到右 - end: Alignment.centerRight, - colors: [ - Color.fromRGBO(131, 89, 255, 1), // 起点颜色 - Color.fromRGBO(77, 127, 231, 1), // 中间颜色 - Color.fromRGBO(61, 138, 224, 1), // 终点颜色 - ], - stops: [0.0, 0.7753, 1.0], // 对应 0%、77.53%、100% - ), + ).onTap((){ + Get.to(() => RealFeedbackPage(type: 1,)); + }), + SizedBox(height: 25.w,), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "现有功能建议", ), - child: Center( - child: Text( - "确认", - style: TextStyle( - fontSize: 18.w, - color: Colors.white, - fontWeight: FontWeight.w500 - ), - ), + Icon( + Icons.arrow_right, + size: 20.w, + color: const Color.fromRGBO(204, 204, 2074, 1), + ) + ], + ).onTap((){ + Get.to(() => RealFeedbackPage(type: 2,)); + }), + SizedBox(height: 25.w,), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "举报投诉", ), - ), - ) + Icon( + Icons.arrow_right, + size: 20.w, + color: const Color.fromRGBO(204, 204, 2074, 1), + ) + ], + ).onTap((){ + Get.to(() => RealFeedbackPage(type: 3,)); + }), + SizedBox(height: 25.w,), ], ), ), @@ -336,64 +185,4 @@ class _FeedbackPageState extends State { -class TagItem extends StatefulWidget { - final String title; - final int index; - final int active; - final void Function(int) changeActive; - const TagItem({super.key, required this.title, required this.index, required this.active, required this.changeActive}); - - @override - State createState() => _TagItemState(); -} - -class _TagItemState extends State { - @override - Widget build(BuildContext context) { - return Stack( - children: [ - Container( - padding: EdgeInsets.symmetric( - vertical: 9.w, - horizontal: 14.w - ), - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(8.w)), - border: Border.all(width: 1, color: widget.index == widget.active ? const Color.fromRGBO(117, 98, 249, 1) : const Color.fromRGBO(207, 207, 207, 1)), - color: widget.index == widget.active ? const Color.fromRGBO(194, 195, 255, 0.2) : Colors.transparent - ), - child: Text( - widget.title, - style: TextStyle( - fontSize: 13.w - ), - ), - ).onTap((){ - widget.changeActive(widget.index); - }), - if(widget.active == widget.index)Positioned( - bottom: 0, - right: 0, - child: Container( - width: 17.w, - height: 13.w, - decoration: BoxDecoration( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(8.w), - bottomRight: Radius.circular(8.w) - ), - color: const Color.fromRGBO(117, 98, 249, 1) - ), - child: Center( - child: Image.asset( - Assets.imagesCheck, - width: 6.w, - ), - ), - ), - ) - ], - ); - } -} diff --git a/lib/pages/mine/mine_page.dart b/lib/pages/mine/mine_page.dart index 4a79128..29c8998 100644 --- a/lib/pages/mine/mine_page.dart +++ b/lib/pages/mine/mine_page.dart @@ -7,8 +7,10 @@ import 'package:dating_touchme_app/model/mine/user_count_data.dart'; import 'package:dating_touchme_app/network/user_api.dart'; import 'package:dating_touchme_app/pages/mine/auth_center_page.dart'; import 'package:dating_touchme_app/pages/mine/edit_info_page.dart'; +import 'package:dating_touchme_app/pages/mine/feedback_page.dart'; import 'package:dating_touchme_app/pages/mine/my_friend_page.dart'; import 'package:dating_touchme_app/pages/mine/my_wallet_page.dart'; +import 'package:dating_touchme_app/pages/mine/real_feedback_page.dart'; import 'package:dating_touchme_app/pages/mine/rose_page.dart'; import 'package:dating_touchme_app/pages/mine/user_help_center_page.dart'; import 'package:dating_touchme_app/pages/mine/vip_page.dart'; @@ -401,7 +403,7 @@ class MinePageState extends State with AutomaticKeepAliveClientMixin{ fontSize: 14.w ), ), onClick: (cell) { - SmartDialog.showToast('功能暂未开放'); + Get.to(() => FeedbackPage()); } ), TDCell(arrow: true, diff --git a/lib/pages/mine/real_feedback_page.dart b/lib/pages/mine/real_feedback_page.dart new file mode 100644 index 0000000..68978ba --- /dev/null +++ b/lib/pages/mine/real_feedback_page.dart @@ -0,0 +1,460 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:dating_touchme_app/components/page_appbar.dart'; +import 'package:dating_touchme_app/controller/mine/real_feedback_controller.dart'; +import 'package:dating_touchme_app/extension/ex_widget.dart'; +import 'package:dating_touchme_app/generated/assets.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; +import 'package:get/get.dart'; +import 'package:tdesign_flutter/tdesign_flutter.dart'; + + +class RealFeedbackPage extends StatelessWidget { + final int type; + const RealFeedbackPage({super.key, required this.type}); + + + + + void _showAvatarPopup(RealFeedbackController controller){ + Navigator.of(Get.context!).push( + TDSlidePopupRoute( + slideTransitionFrom: SlideTransitionFrom.bottom, + builder: (context) { + return Container( + height: 176, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + topLeft: Radius.circular(12.0), + topRight: Radius.circular(12.0), + ), + ), + child: Column( + children: [ + ClipRRect( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(12.0), + topRight: Radius.circular(12.0), + ), + child: TDCell( + arrow: false, + titleWidget: Center( + child: Text('拍照', style: TextStyle(fontSize: 16.w, color: const Color.fromRGBO(51, 51, 51, 1))), + ), + style: TDCellStyle( + padding: EdgeInsets.all(TDTheme.of(context).spacer16), + clickBackgroundColor: TDTheme.of(context).bgColorContainerHover, + cardBorderRadius: BorderRadius.only( + topLeft: Radius.circular(12.0), + topRight: Radius.circular(12.0), + ) + ), + onClick: (cell) async{ + Navigator.pop(context); + + if(9 - controller.imgList.length == 1){ + + await controller.handleCameraCapture(); + } else { + if(controller.imgList.length >= 9){ + + SmartDialog.showToast('超出数量限制,请先删除再尝试上传'); + return; + } + await controller.handleCameraCapture(); + } + }, + ), + ), + const TDDivider(), + TDCell( + arrow: false, + titleWidget: Center( + child: Text('从相册选择'), + ), + onClick: (cell) async{ + Navigator.pop(context); + if(9 - controller.imgList.length == 1){ + await controller.handleGallerySelection(); + } else { + if(controller.imgList.length >= 9){ + + SmartDialog.showToast('超出数量限制,请先删除再尝试上传'); + return; + } + await controller.handleMultiGallerySelection(); + } + }, + ), + Expanded( + child: Container( + color: Color(0xFFF3F3F3), + ), + ), + TDCell( + arrow: false, + titleWidget: Center( + child: Text('取消'), + ), + onClick: (cell){ + Navigator.pop(context); + }, + ), + ], + ), + ); + }), + ); + } + + @override + Widget build(BuildContext context) { + return GetX( + init: RealFeedbackController(type: type), + builder: (controller){ + return Stack( + children: [ + Container( + width: 375.w, + height: 812.h, + color: Colors.white, + ), + Positioned( + top: -320.w, + left: -270.w, + child: Image.asset( + Assets.imagesFeedbackBg, + width: 971.75.w, + height: 781.25.w, + fit: BoxFit.cover, + ), + ), + Positioned( + top: 53.w, + left: 207.w, + child: Image.asset( + Assets.imagesFeedbackIcon, + width: 140.w, + height: 140.w, + ), + ), + Scaffold( + appBar: PageAppbar(title: "", backgroundColor: Colors.transparent,), + backgroundColor: Colors.transparent, + body: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + padding: EdgeInsets.symmetric( + vertical: 22.w, + horizontal: 14.w + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "意见反馈", + style: TextStyle( + fontSize: 21.w, + fontWeight: FontWeight.w500 + ), + ), + SizedBox(height: 5.w,), + Text( + "Hi,给出你的小建议吧~", + style: TextStyle( + fontSize: 13.w, + fontWeight: FontWeight.w500 + ), + ), + ], + ), + ), + Expanded( + child: Container( + width: 375.w, + padding: EdgeInsets.symmetric( + vertical: 11.w, + horizontal: 14.w + ), + decoration: BoxDecoration( + borderRadius: BorderRadius.vertical(top: Radius.circular(9.w)), + color: Colors.white + ), + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + RichText( + text: TextSpan( + style: TextStyle( + fontSize: 16.w, + fontWeight: FontWeight.w500 + ), + children: [ + TextSpan( + text: "选择问题的类型", + style: TextStyle( + color: const Color.fromRGBO(51, 51, 51, 1) + ) + ), + TextSpan( + text: "*", + style: TextStyle( + color: const Color.fromRGBO(248, 85, 66, 1) + ) + ) + ] + ), + ), + SizedBox(height: 11.w,), + Wrap( + alignment: WrapAlignment.spaceBetween, + spacing: 10.w, + runSpacing: 10.w, + children: [ + ...controller.tagList.asMap().entries.map((entry){ + return TagItem(item: entry.value, index: entry.key, active: controller.active.value, changeActive: controller.changeActive,); + }), + ], + ), + SizedBox(height: 20.w,), + RichText( + text: TextSpan( + style: TextStyle( + fontSize: 16.w, + fontWeight: FontWeight.w500 + ), + children: [ + TextSpan( + text: "问题描述", + style: TextStyle( + color: const Color.fromRGBO(51, 51, 51, 1) + ) + ), + TextSpan( + text: "*", + style: TextStyle( + color: const Color.fromRGBO(248, 85, 66, 1) + ) + ) + ] + ), + ), + SizedBox(height: 11.w,), + Container( + padding: EdgeInsets.all(14.w), + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(8.w)), + color: const Color.fromRGBO(245, 245, 245, 1) + ), + child: TextField( + controller: controller.messageController.value, + maxLength: 500, // 上限 + minLines: 5, // 多行 + maxLines: 5, // 自适应高度 + style: TextStyle( + fontSize: ScreenUtil().setWidth(13), + height: 1 + ), + decoration: InputDecoration( + contentPadding: EdgeInsets.symmetric( + vertical: 0, + horizontal: 0 + ), + hintText: "请输入交友心声", + + border: const OutlineInputBorder( + borderSide: BorderSide.none, // 这将移除边框 // 可选:设置圆角 + ), + // 如果你希望聚焦时和未聚焦时都没有边框,也可以设置 focusedBorder 和 enabledBorder + focusedBorder: const OutlineInputBorder( + borderSide: BorderSide.none, + borderRadius: BorderRadius.all(Radius.circular(8.0)), + ), + enabledBorder: const OutlineInputBorder( + borderSide: BorderSide.none, + borderRadius: BorderRadius.all(Radius.circular(8.0)), + ), + ), + onChanged: (value){ + controller.message.value = value; + }, + ), + ), + SizedBox(height: 10.w,), + Wrap( + spacing: 10.w, + runSpacing: 10.w, + children: [ + ...controller.imgList.map((e){ + return Stack( + children: [ + CachedNetworkImage( + imageUrl: e, + width: 70.w, + height: 70.w, + fit: BoxFit.cover, + ), + Positioned( + left: 5.w, + top: 5.w, + child: Container( + width: 20.w, + height: 20.w, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(20.w)), + color: const Color.fromRGBO(0, 0, 0, .3) + ), + child: Icon( + Icons.close, + size: 20.w, + ), + ).onTap((){ + controller.imgList.remove(e); + + }), + ) + ], + ); + }), + Container( + width: 70.w, + height: 70.w, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(8.w)), + border: Border.all(width: 1, color: const Color.fromRGBO(224, 224, 224, 1)) + ), + child: Center( + child: Icon( + Icons.add, + size: 18.w, + color: const Color.fromRGBO(144, 144, 144, 1), + ), + ), + ).onTap((){ + _showAvatarPopup(controller); + }) + ], + ), + SizedBox(height: 10.w,), + Text( + "上传问题截图可以让问题快速解决!", + style: TextStyle( + fontSize: 11.w, + color: const Color.fromRGBO(189, 189, 189, 1) + ), + ), + Container( + margin: EdgeInsets.symmetric(vertical: 30.w), + child: Container( + width: 350.w, + height: 45.w, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(45.w)), + gradient: LinearGradient( + begin: Alignment.centerLeft, // 90deg: 从左到右 + end: Alignment.centerRight, + colors: [ + Color.fromRGBO(131, 89, 255, 1), // 起点颜色 + Color.fromRGBO(77, 127, 231, 1), // 中间颜色 + Color.fromRGBO(61, 138, 224, 1), // 终点颜色 + ], + stops: [0.0, 0.7753, 1.0], // 对应 0%、77.53%、100% + ), + ), + child: Center( + child: Text( + "确认", + style: TextStyle( + fontSize: 18.w, + color: Colors.white, + fontWeight: FontWeight.w500 + ), + ), + ), + ), + ).onTap((){ + controller.sendFeedback(); + }) + ], + ), + ), + ), + ) + ], + ), + ) + ], + ); + }, + ); + } +} + + + + +class TagItem extends StatefulWidget { + final Map item; + final int index; + final int active; + final void Function(int) changeActive; + const TagItem({super.key, required this.item, required this.index, required this.active, required this.changeActive}); + + @override + State createState() => _TagItemState(); +} + +class _TagItemState extends State { + @override + Widget build(BuildContext context) { + return Stack( + children: [ + Container( + padding: EdgeInsets.symmetric( + vertical: 9.w, + horizontal: 14.w + ), + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(8.w)), + border: Border.all(width: 1, color: widget.item["value"] == widget.active ? const Color.fromRGBO(117, 98, 249, 1) : const Color.fromRGBO(207, 207, 207, 1)), + color: widget.item["value"] == widget.active ? const Color.fromRGBO(194, 195, 255, 0.2) : Colors.transparent + ), + child: Text( + widget.item["label"], + style: TextStyle( + fontSize: 13.w + ), + ), + ).onTap((){ + widget.changeActive(widget.item["value"]); + }), + if(widget.active == widget.item["value"])Positioned( + bottom: 0, + right: 0, + child: Container( + width: 17.w, + height: 13.w, + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(8.w), + bottomRight: Radius.circular(8.w) + ), + color: const Color.fromRGBO(117, 98, 249, 1) + ), + child: Center( + child: Image.asset( + Assets.imagesCheck, + width: 6.w, + ), + ), + ), + ) + ], + ); + } +} + diff --git a/lib/pages/setting/blacklist_page.dart b/lib/pages/setting/blacklist_page.dart index 849a8e8..656e895 100644 --- a/lib/pages/setting/blacklist_page.dart +++ b/lib/pages/setting/blacklist_page.dart @@ -1,44 +1,92 @@ +import 'package:cached_network_image/cached_network_image.dart'; import 'package:dating_touchme_app/components/page_appbar.dart'; +import 'package:dating_touchme_app/controller/setting/blacklist_controller.dart'; +import 'package:dating_touchme_app/extension/ex_widget.dart'; import 'package:dating_touchme_app/generated/assets.dart'; +import 'package:dating_touchme_app/model/mine/blacklist_data.dart'; +import 'package:dating_touchme_app/pages/home/report_page.dart'; +import 'package:dating_touchme_app/pages/home/user_information_page.dart'; +import 'package:easy_refresh/easy_refresh.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:tdesign_flutter/tdesign_flutter.dart'; -class BlacklistPage extends StatefulWidget { +class BlacklistPage extends StatelessWidget { const BlacklistPage({super.key}); - @override - State createState() => _BlacklistPageState(); -} -class _BlacklistPageState extends State { @override Widget build(BuildContext context) { - return Scaffold( - appBar: PageAppbar(title: "黑名单"), - body: SingleChildScrollView( - child: Container( - padding: EdgeInsets.symmetric( - vertical: 20.w, - horizontal: 15.w - ), - child: Column( - children: [ - BlackItem(), - BlackItem(), - BlackItem(), - BlackItem(), - BlackItem(), - BlackItem(), - ], + return GetX( + init: BlacklistController(), + builder: (controller) { + return Scaffold( + appBar: PageAppbar(title: "黑名单"), + body: EasyRefresh( + controller: controller.listRefreshController, + header: const ClassicHeader( + dragText: '下拉刷新', + armedText: '释放刷新', + readyText: '刷新中...', + processingText: '刷新中...', + processedText: '刷新完成', + failedText: '刷新失败', + noMoreText: '没有更多数据', + showMessage: false + ), + footer: ClassicFooter( + dragText: '上拉加载', + armedText: '释放加载', + readyText: '加载中...', + processingText: '加载中...', + processedText: '加载完成', + failedText: '加载失败', + noMoreText: '没有更多数据', + showMessage: false + ), + // 下拉刷新 + onRefresh: () async { + print('推荐列表下拉刷新被触发'); + controller.page.value = 1; + controller.blackList.clear(); + await controller.getBlackList(); + controller.listRefreshController.finishRefresh(IndicatorResult.success); + controller.listRefreshController.finishLoad(IndicatorResult.none); + }, + // 上拉加载更多 + onLoad: () async { + print('推荐列表上拉加载被触发, hasMore: '); + controller.page.value += 1; + controller.getBlackList(); + }, + child: SingleChildScrollView( + child: Container( + padding: EdgeInsets.symmetric( + vertical: 20.w, + horizontal: 15.w + ), + child: Column( + children: [ + ...controller.blackList.map((e){ + return BlackItem(item: e, controller: controller,); + }) + ], + ), + ), + ), ), - ), - ), + ); + }, ); } } + class BlackItem extends StatefulWidget { - const BlackItem({super.key}); + final Records item; + final BlacklistController controller; + const BlackItem({super.key, required this.item, required this.controller}); @override State createState() => _BlackItemState(); @@ -57,26 +105,39 @@ class _BlackItemState extends State { Row( children: [ ClipRRect( - borderRadius: BorderRadius.all(Radius.circular(40.w)), - child: Image.asset( - Assets.imagesUserAvatar, - width: 40.w, - height: 40.w, - ), + borderRadius: BorderRadius.all(Radius.circular(40.w)), + child: (widget.item.profilePhoto != null && widget.item.profilePhoto != "") ? CachedNetworkImage( + imageUrl: "${widget.item.profilePhoto ?? ""}?x-oss-process=image/format,webp/resize,w_120", + width: 40.w, + height: 40.w, + imageBuilder: (context, imageProvider) => Container( + decoration: BoxDecoration( + image: DecorationImage( + image: imageProvider, + fit: BoxFit.cover, + ), + ), + ), + ) : Image.asset( + gaplessPlayback: true, + Assets.imagesUserAvatar, + width: 40.w, + height: 40.w, + ) ), SizedBox(width: 12.w,), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - "法大师傅", + "${widget.item.nickName ?? ""}", style: TextStyle( fontSize: 13.w, fontWeight: FontWeight.w500 ), ), Text( - "拉黑时间:11月7日", + "30岁·广州", style: TextStyle( fontSize: 11.w, color: const Color.fromRGBO(144, 144, 144, 1) @@ -86,26 +147,86 @@ class _BlackItemState extends State { ) ], ), - Container( - width: 70.w, - height: 25.w, - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(25.w)), - border: Border.all(width: 1, color: const Color.fromRGBO(51, 51, 51, 1)) - ), - child: Center( - child: Text( - "拆除", - style: TextStyle( - fontSize: 13.w, - fontWeight: FontWeight.w500 - ), - ), - ), + Icon( + Icons.more_horiz, + size: 20.w, ) ], ), - ); + ).onTap(() { + Navigator.of(context).push( + TDSlidePopupRoute( + slideTransitionFrom: SlideTransitionFrom.bottom, + builder: (context) { + return Material( + borderRadius: BorderRadius.vertical(top: Radius.circular(9.w)), + child: ClipRRect( + borderRadius: BorderRadius.vertical(top: Radius.circular(9.w)), + child: Container( + color: TDTheme.of(context).bgColorContainer, + height: 212.w, + padding: EdgeInsets.symmetric(horizontal: 28.w), + child: Column( + children: [ + Container( + height: 65.w, + decoration: BoxDecoration( + border: Border(bottom: BorderSide(width: 1, color: const Color.from(alpha: 245, red: 245, green: 245, blue: 1))) + ), + child: Center( + child: Text( + "查看详情", + style: TextStyle( + fontSize: 18.w + ), + ), + ), + ).onTap((){ + + Get.to(() => UserInformationPage(miId: widget.item.miId ?? "")); + }), + Container( + height: 65.w, + decoration: BoxDecoration( + border: Border(bottom: BorderSide(width: 1, color: const Color.from(alpha: 245, red: 245, green: 245, blue: 1))) + ), + child: Center( + child: Text( + "解除拉黑", + style: TextStyle( + fontSize: 18.w + ), + ), + ), + ).onTap((){ + widget.controller.unBlack(widget.item.blackUserId ?? ""); + }), + Container( + height: 65.w, + decoration: BoxDecoration( + border: Border(bottom: BorderSide(width: 1, color: const Color.fromRGBO(245, 245, 245, 1))) + ), + child: Center( + child: Text( + "举报", + style: TextStyle( + fontSize: 18.w, + color: const Color.fromRGBO(245, 83, 83, 1) + ), + ), + ), + ).onTap((){ + + Get.to(() => ReportPage(id: widget.item.blackUserId ?? "", userId: widget.item.blackUserId ?? "", type: 1,)); + }), + ], + ), + ), + ), + ); + }), + ); + }); } }