From 3e0eb2f35c7a474b1175a6fcdc6486f84a52bd6d Mon Sep 17 00:00:00 2001 From: lxm <1274844347@qq.com> Date: Mon, 26 May 2025 17:23:15 +0800 Subject: [PATCH 1/7] =?UTF-8?q?feat(=E7=99=BB=E5=BD=95):=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E9=9A=90=E7=A7=81=E6=94=BF=E7=AD=96=E5=BC=B9=E7=AA=97?= =?UTF-8?q?=E5=B9=B6=E6=9B=B4=E6=96=B0=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在登录控制器中添加隐私政策弹窗功能,强制用户同意后才能继续使用 - 修改intl依赖版本从^0.20.2降级到^0.19.0 - 完善配对控制器初始化流程的注释说明 隐私弹窗包含以下特性: 1. 禁止通过返回键或点击外部关闭 2. 提供隐私政策和用户协议链接 3. 不同意则退出应用 4. 同意后设置标志位并继续 --- .../login/controllers/login_controller.dart | 145 +++++++++++++++++- .../controllers/pairing_controller.dart | 2 +- pubspec.yaml | 2 +- 3 files changed, 140 insertions(+), 9 deletions(-) diff --git a/lib/modules/login/controllers/login_controller.dart b/lib/modules/login/controllers/login_controller.dart index 951885884..c5561a250 100644 --- a/lib/modules/login/controllers/login_controller.dart +++ b/lib/modules/login/controllers/login_controller.dart @@ -10,9 +10,11 @@ import 'googleLogin.dart'; import 'weixinLogin.dart'; import '../../../data/services/network/api.dart'; import '../../../../data/models/user_Info.dart'; +import '../../common/webview_page.dart'; //import 'package:shared_preferences/shared_preferences.dart'; import 'package:get_storage/get_storage.dart'; import 'package:device_info_plus/device_info_plus.dart'; +import 'dart:io'; enum LoginViewState { welcome, // 欢迎页面 @@ -175,6 +177,12 @@ class LoginController extends GetxController { void onInit() { super.onInit(); _viewState.value = LoginViewState.welcome; + + // 使用addPostFrameCallback确保在构建完成后显示对话框 + // WidgetsBinding.instance.addPostFrameCallback((_) { + // _showPrivacyDialog(); + // }); + _initDeviceInfo(); } @@ -185,6 +193,128 @@ class LoginController extends GetxController { super.onClose(); } + // 显示隐私政策弹窗 + void _showPrivacyDialog() { + Get.dialog( + WillPopScope( + onWillPop: () async => false, // 禁止通过返回键关闭弹窗 + child: Dialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + child: Container( + padding: const EdgeInsets.all(20), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Text( + 'DeapSound 声明', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 16), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: Text.rich( + TextSpan( + children: [ + const TextSpan( + text: '欢迎使用DeapSound,请先阅读', + style: TextStyle(fontSize: 14), + ), + WidgetSpan( + child: GestureDetector( + onTap: () { + String url = 'https://www.deepsoud.com/ysxy.html'; + if (Get.locale?.toString() != 'zh_CN') { + url = 'https://www.deepsoud.com/ysxy_en.html'; + } + Get.to(() => WebViewPage( + url: url, + title: 'privacyPolicy'.tr, + )); + }, + child: Text( + '《隐私政策》', + style: TextStyle( + fontSize: 14, + color: const Color(0xFF3B82F6), + ), + ), + ), + ), + const TextSpan( + text: '和', + style: TextStyle(fontSize: 14), + ), + WidgetSpan( + child: GestureDetector( + onTap: () { + String url = 'https://www.deepsoud.com/yhxy.html'; + if (Get.locale?.toString() != 'zh_CN') { + url = 'https://www.deepsoud.com/yhxy_en.html'; + } + Get.to(() => WebViewPage( + url: url, + title: 'userAgreement'.tr, + )); + }, + child: Text( + '《用户协议》', + style: TextStyle( + fontSize: 14, + color: const Color(0xFF3B82F6), + ), + ), + ), + ), + ], + ), + textAlign: TextAlign.center, + ), + ), + const SizedBox(height: 20), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + TextButton( + onPressed: () { + // 用户不同意,退出应用 + exit(0); + }, + style: TextButton.styleFrom( + foregroundColor: Colors.black54, + ), + child: const Text('取消'), + ), + ElevatedButton( + onPressed: () { + // 用户同意,关闭弹窗并继续 + _hasAcceptedPrivacy.value = true; + Get.back(); + }, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF0066CC), + foregroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + child: const Text('同意并进入'), + ), + ], + ), + ], + ), + ), + ), + ), + barrierDismissible: false, // 禁止点击外部关闭弹窗 + ); + } + // 初始化设备信息 Future _initDeviceInfo() async { try { @@ -462,13 +592,14 @@ class LoginController extends GetxController { //验证隐私协议勾选状态 if (!_hasAcceptedPrivacy.value) { - Get.snackbar( - 'tip'.tr, - 'pleaseAcceptPrivacyPolicy'.tr, - snackPosition: SnackPosition.TOP, - backgroundColor: Colors.red.withOpacity(0.1), - colorText: Colors.red, - ); + // Get.snackbar( + // 'tip'.tr, + // 'pleaseAcceptPrivacyPolicy'.tr, + // snackPosition: SnackPosition.TOP, + // backgroundColor: Colors.red.withOpacity(0.1), + // colorText: Colors.red, + // ); + _showPrivacyDialog(); return; } _isLoading.value = true; diff --git a/lib/modules/pairing/controllers/pairing_controller.dart b/lib/modules/pairing/controllers/pairing_controller.dart index 686db7ba8..585cc30d3 100644 --- a/lib/modules/pairing/controllers/pairing_controller.dart +++ b/lib/modules/pairing/controllers/pairing_controller.dart @@ -79,7 +79,7 @@ class PairingController extends GetxController { super.onClose(); } - /// 初始化流程 + /// 初始化流程:检查权限-如果通过,设置监听-检查蓝牙是否开启-如果开启,刷新设备连接-检查配对状态 Future _initialize() async { try { isLoading.value = true; diff --git a/pubspec.yaml b/pubspec.yaml index f32b631d5..fd7ad853a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -25,7 +25,7 @@ dependencies: web_socket_channel: ^3.0.2 flutter_dotenv: ^5.1.0 synchronized: ^3.1.0 - intl: ^0.20.2 + intl: ^0.19.0 crypto: ^3.0.3 flutter_tts: ^4.2.2 logger: ^2.0.2+1 From 306cd2243e6729bcf24e8148e3077c8af91724c8 Mon Sep 17 00:00:00 2001 From: lxm <1274844347@qq.com> Date: Thu, 29 May 2025 17:37:36 +0800 Subject: [PATCH 2/7] =?UTF-8?q?fix(login):=20=E4=BF=AE=E5=A4=8D=E9=9A=90?= =?UTF-8?q?=E7=A7=81=E6=94=BF=E7=AD=96=E5=BC=B9=E7=AA=97=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../login/controllers/login_controller.dart | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/modules/login/controllers/login_controller.dart b/lib/modules/login/controllers/login_controller.dart index c5561a250..1ac7e8af7 100644 --- a/lib/modules/login/controllers/login_controller.dart +++ b/lib/modules/login/controllers/login_controller.dart @@ -178,10 +178,16 @@ class LoginController extends GetxController { super.onInit(); _viewState.value = LoginViewState.welcome; - // 使用addPostFrameCallback确保在构建完成后显示对话框 - // WidgetsBinding.instance.addPostFrameCallback((_) { - // _showPrivacyDialog(); - // }); + _hasAcceptedPrivacy.value = + _storage.read('hasAcceptedPrivacy') ?? false; // 从本地存储中读取是否已接受隐私政策 + + //使用addPostFrameCallback确保在构建完成后显示对话框 + WidgetsBinding.instance.addPostFrameCallback((_) { + //如果用户未接受隐私政策,显示弹窗 + if (!_hasAcceptedPrivacy.value) { + _showPrivacyDialog(); + } + }); _initDeviceInfo(); } @@ -221,7 +227,7 @@ class LoginController extends GetxController { TextSpan( children: [ const TextSpan( - text: '欢迎使用DeapSound,请先阅读', + text: '欢迎使用DeapSound,请充分阅读', style: TextStyle(fontSize: 14), ), WidgetSpan( From 44b1eac2a10bdc3a4ce423a304247664f3fc9696 Mon Sep 17 00:00:00 2001 From: lxm <1274844347@qq.com> Date: Wed, 4 Jun 2025 11:55:15 +0800 Subject: [PATCH 3/7] =?UTF-8?q?feat(=E6=B6=88=E6=81=AF=E6=B0=94=E6=B3=A1):?= =?UTF-8?q?=20=E6=B7=BB=E5=8A=A0=E9=95=BF=E6=8C=89=E5=A4=8D=E5=88=B6?= =?UTF-8?q?=E5=92=8C=E4=B8=BE=E6=8A=A5=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在非用户消息上添加长按手势,显示包含复制和举报选项的菜单 - 实现复制功能,将消息内容复制到剪贴板 - 添加举报功能,支持多种举报类型和自定义描述 - 禁用消息气泡的选择功能以优化交互体验 - 引入触觉反馈增强用户操作感知 --- lib/modules/agent/views/agent_view.dart | 260 +++++++++++++++++++- lib/modules/agent/views/message_bubble.dart | 2 +- 2 files changed, 252 insertions(+), 10 deletions(-) diff --git a/lib/modules/agent/views/agent_view.dart b/lib/modules/agent/views/agent_view.dart index 54cb541d3..f91b246ac 100644 --- a/lib/modules/agent/views/agent_view.dart +++ b/lib/modules/agent/views/agent_view.dart @@ -3,6 +3,10 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import '../controllers/agent_controller.dart'; import 'message_bubble.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import '../../../core/theme/app_colors.dart'; +import 'package:haptic_feedback/haptic_feedback.dart'; class AgentView extends StatelessWidget { const AgentView({Key? key}) : super(key: key); @@ -163,15 +167,32 @@ class AgentView extends StatelessWidget { .messages[controller.messages.length - 1 - index]; return Padding( padding: const EdgeInsets.only(bottom: 8), - child: MessageBubble( - isUser: message.isUser, - message: message.text, - timestamp: message.timestamp, - isRecognizing: message.isRecognizing, - hasImage: message.hasImage, - imagePath: message.imagePath, - meta: message.meta, - ), + child: !message.isUser + ? GestureDetector( + onLongPressStart: + (LongPressStartDetails details) { + _onLongPressMessageContent( + context, isDarkMode, details, message); + }, + child: MessageBubble( + isUser: message.isUser, + message: message.text, + timestamp: message.timestamp, + isRecognizing: message.isRecognizing, + hasImage: message.hasImage, + imagePath: message.imagePath, + meta: message.meta, + ), + ) + : MessageBubble( + isUser: message.isUser, + message: message.text, + timestamp: message.timestamp, + isRecognizing: message.isRecognizing, + hasImage: message.hasImage, + imagePath: message.imagePath, + meta: message.meta, + ), ); }, ), @@ -522,6 +543,227 @@ class AgentView extends StatelessWidget { ); } + void _onLongPressMessageContent(BuildContext context, bool isDarkMode, + LongPressStartDetails details, Message message) { + Haptics.vibrate(HapticsType.success); + RenderBox? renderBox = + Overlay.of(context).context.findRenderObject() as RenderBox; + final RelativeRect position = RelativeRect.fromRect( + Rect.fromLTRB( + details.globalPosition.dx, + details.globalPosition.dy, + details.globalPosition.dx + 110, // 菜单显示位置X轴坐标 + details.globalPosition.dy - 40, // 菜单显示位置Y轴坐标 + ), + Offset.zero & renderBox.size, + ); + + showMenu( + context: context, + position: position, + color: isDarkMode ? AppColors.cardBackground : Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12.r), + ), + items: [ + _popupMenuEntry( + Icon( + Icons.copy, + size: 20.w, + color: isDarkMode ? Colors.white : Colors.black87, + ), + '复制', + isDarkMode ? Colors.white : Colors.black87, + () { + Clipboard.setData( + ClipboardData( + text: message.text, + ), + ).then((value) => Get.snackbar( + 'success'.tr, // 成功 + '复制成功', + backgroundColor: Colors.blue.withOpacity(0.8), + colorText: Colors.white, + )); + }, + ), + // 自定义分隔线样式 + PopupMenuItem( + height: 1, // 控制间距 + enabled: false, + child: Divider( + height: 1, + thickness: 0.8, + indent: 12, + endIndent: 12, + color: isDarkMode ? Colors.grey[700] : Colors.grey[300], + ), + ), + _popupMenuEntry( + Icon( + Icons.report, + size: 20.w, + color: isDarkMode ? Colors.red[700] : Colors.red, + ), + '举报'.tr, // 举报 + isDarkMode ? Colors.red[700]! : Colors.red, + () { + // 实现举报功能 + showModalBottomSheet( + context: context, + backgroundColor: + isDarkMode ? AppColors.cardBackground : Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.vertical(top: Radius.circular(16.r)), + ), + builder: (BuildContext context) { + return Container( + padding: EdgeInsets.all(16.w), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + '举报', + style: TextStyle( + fontSize: 18.sp, + fontWeight: FontWeight.bold, + color: isDarkMode ? Colors.white : Colors.black, + ), + ), + IconButton( + icon: Icon( + Icons.close, + color: + isDarkMode ? Colors.white70 : Colors.black54, + ), + onPressed: () => Navigator.pop(context), + ), + ], + ), + SizedBox(height: 16.h), + Wrap( + spacing: 8.w, + runSpacing: 8.h, + children: [ + _buildReportChip('有害/不安全', isDarkMode), + _buildReportChip('色情低俗', isDarkMode), + _buildReportChip('误导攻击', isDarkMode), + _buildReportChip('违法犯罪', isDarkMode), + _buildReportChip('隐私相关', isDarkMode), + _buildReportChip('侵犯我的著作权、名誉权等', isDarkMode), + _buildReportChip('其他', isDarkMode), + ], + ), + SizedBox(height: 16.h), + Container( + padding: EdgeInsets.all(12.w), + decoration: BoxDecoration( + color: + isDarkMode ? Colors.grey[800] : Colors.grey[200], + borderRadius: BorderRadius.circular(8.r), + ), + child: TextField( + maxLines: 3, + style: TextStyle( + color: isDarkMode ? Colors.white : Colors.black, + ), + decoration: InputDecoration( + hintText: '我们想知道你举报的原因,你可以描述你遇到的问题。', + hintStyle: TextStyle( + color: + isDarkMode ? Colors.white70 : Colors.black54, + fontSize: 14.sp, + ), + border: InputBorder.none, + ), + ), + ), + SizedBox(height: 14.h), + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Colors.blue, + foregroundColor: Colors.white, + padding: EdgeInsets.symmetric(vertical: 12.h), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8.r), + ), + ), + child: Text('提交'), + onPressed: () { + // 处理举报提交逻辑 + Navigator.pop(context); + Get.snackbar( + '提示', + '举报已提交,我们会尽快处理', + backgroundColor: Colors.green.withOpacity(0.8), + colorText: Colors.white, + ); + }, + ), + SizedBox(height: 8.h), + ], + ), + ); + }, + ); + }, + ), + ], + ); + } + + // 添加这个辅助方法来创建举报选项 + Widget _buildReportChip(String label, bool isDarkMode) { + return ChoiceChip( + label: Text( + label, + style: TextStyle( + color: isDarkMode ? Colors.white : Colors.black87, + fontSize: 14.sp, + ), + ), + selected: false, + backgroundColor: isDarkMode ? Colors.grey[800] : Colors.grey[200], + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16.r), + ), + onSelected: (bool selected) { + // 可以在这里处理选择逻辑 + }, + ); + } + + PopupMenuEntry _popupMenuEntry( + Icon icon, + String title, + Color color, + Function() onTap, + ) { + return PopupMenuItem( + onTap: onTap, + child: SizedBox( + width: 140.w, + child: Row( + children: [ + icon, + 8.horizontalSpace, + Text( + title, + style: TextStyle( + color: color, + fontSize: 14.sp, + ), + ), + ], + ), + ), + ); + } + // 构建提示选项芯片 Widget _buildPromptChip({ required BuildContext context, diff --git a/lib/modules/agent/views/message_bubble.dart b/lib/modules/agent/views/message_bubble.dart index 94bbb5415..b4a7a0ed4 100644 --- a/lib/modules/agent/views/message_bubble.dart +++ b/lib/modules/agent/views/message_bubble.dart @@ -406,7 +406,7 @@ class MessageBubble extends GetView { fontSize: 14, ), ), - selectable: true, + //selectable: true, ); } // 用户消息仍然使用普通文本 From 55c9077c3036461a8ab6f3646a45ffb4e3ac2339 Mon Sep 17 00:00:00 2001 From: lxm <1274844347@qq.com> Date: Wed, 4 Jun 2025 15:55:21 +0800 Subject: [PATCH 4/7] =?UTF-8?q?fix(=E4=B8=BE=E6=8A=A5=E5=BC=B9=E7=AA=97):?= =?UTF-8?q?=20=E4=BF=AE=E5=A4=8D=E9=94=AE=E7=9B=98=E5=BC=B9=E5=87=BA?= =?UTF-8?q?=E6=97=B6=E5=B8=83=E5=B1=80=E9=81=AE=E6=8C=A1=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加isScrollControlled属性使弹窗随键盘移动 - 增加底部内边距避免键盘遮挡内容 - 使用SingleChildScrollView确保内容可滚动 - 优化关闭按钮位置和样式 --- lib/modules/agent/views/agent_view.dart | 193 ++++++++++++++---------- 1 file changed, 111 insertions(+), 82 deletions(-) diff --git a/lib/modules/agent/views/agent_view.dart b/lib/modules/agent/views/agent_view.dart index f91b246ac..b71c2e2f1 100644 --- a/lib/modules/agent/views/agent_view.dart +++ b/lib/modules/agent/views/agent_view.dart @@ -594,8 +594,8 @@ class AgentView extends StatelessWidget { child: Divider( height: 1, thickness: 0.8, - indent: 12, - endIndent: 12, + indent: 0, + endIndent: 0, color: isDarkMode ? Colors.grey[700] : Colors.grey[300], ), ), @@ -611,101 +611,130 @@ class AgentView extends StatelessWidget { // 实现举报功能 showModalBottomSheet( context: context, + isScrollControlled: true, // 关键:允许弹窗随键盘移动 backgroundColor: isDarkMode ? AppColors.cardBackground : Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(16.r)), ), builder: (BuildContext context) { - return Container( - padding: EdgeInsets.all(16.w), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + return Padding( + // 添加底部内边距以容纳键盘 + padding: EdgeInsets.only( + bottom: MediaQuery.of(context).viewInsets.bottom, + ), + child: Container( + padding: EdgeInsets.all(16.w), + child: SingleChildScrollView( + // 添加滚动视图 + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - Text( - '举报', - style: TextStyle( - fontSize: 18.sp, - fontWeight: FontWeight.bold, - color: isDarkMode ? Colors.white : Colors.black, - ), + Stack( + alignment: Alignment.center, + children: [ + Center( + child: Text( + '举报', + style: TextStyle( + fontSize: 18.sp, + fontWeight: FontWeight.bold, + color: isDarkMode + ? Colors.white + : Colors.black, + ), + ), + ), + SizedBox( + height: 20.w, + ), + Positioned( + right: 0, + child: IconButton( + icon: Icon( + Icons.close, + color: isDarkMode + ? Colors.grey[400] + : Colors.black54, + ), + onPressed: () => Navigator.pop(context), + ), + ), + ], ), - IconButton( - icon: Icon( - Icons.close, - color: - isDarkMode ? Colors.white70 : Colors.black54, + Container( + padding: EdgeInsets.symmetric(horizontal: 12.w), + margin: EdgeInsets.only(bottom: 10.w), + child: Divider( + height: 1, + color: Colors.grey[300], ), - onPressed: () => Navigator.pop(context), ), - ], - ), - SizedBox(height: 16.h), - Wrap( - spacing: 8.w, - runSpacing: 8.h, - children: [ - _buildReportChip('有害/不安全', isDarkMode), - _buildReportChip('色情低俗', isDarkMode), - _buildReportChip('误导攻击', isDarkMode), - _buildReportChip('违法犯罪', isDarkMode), - _buildReportChip('隐私相关', isDarkMode), - _buildReportChip('侵犯我的著作权、名誉权等', isDarkMode), - _buildReportChip('其他', isDarkMode), - ], - ), - SizedBox(height: 16.h), - Container( - padding: EdgeInsets.all(12.w), - decoration: BoxDecoration( - color: - isDarkMode ? Colors.grey[800] : Colors.grey[200], - borderRadius: BorderRadius.circular(8.r), - ), - child: TextField( - maxLines: 3, - style: TextStyle( - color: isDarkMode ? Colors.white : Colors.black, + Wrap( + spacing: 8.w, + runSpacing: 8.h, + children: [ + _buildReportChip('有害/不安全', isDarkMode), + _buildReportChip('色情低俗', isDarkMode), + _buildReportChip('误导攻击', isDarkMode), + _buildReportChip('违法犯罪', isDarkMode), + _buildReportChip('隐私相关', isDarkMode), + _buildReportChip('侵犯我的著作权、名誉权等', isDarkMode), + _buildReportChip('其他', isDarkMode), + ], ), - decoration: InputDecoration( - hintText: '我们想知道你举报的原因,你可以描述你遇到的问题。', - hintStyle: TextStyle( - color: - isDarkMode ? Colors.white70 : Colors.black54, - fontSize: 14.sp, + SizedBox(height: 16.h), + Container( + padding: EdgeInsets.all(12.w), + decoration: BoxDecoration( + color: isDarkMode + ? Colors.grey[800] + : Colors.grey[200], + borderRadius: BorderRadius.circular(8.r), + ), + child: TextField( + maxLines: 3, + style: TextStyle( + color: isDarkMode ? Colors.white : Colors.black, + ), + decoration: InputDecoration( + hintText: '我们想知道你举报的原因,你可以描述你遇到的问题。', + hintStyle: TextStyle( + color: isDarkMode + ? Colors.white70 + : Colors.black54, + fontSize: 14.sp, + ), + border: InputBorder.none, + ), ), - border: InputBorder.none, ), - ), - ), - SizedBox(height: 14.h), - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Colors.blue, - foregroundColor: Colors.white, - padding: EdgeInsets.symmetric(vertical: 12.h), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8.r), + SizedBox(height: 14.h), + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Colors.blue, + foregroundColor: Colors.white, + padding: EdgeInsets.symmetric(vertical: 12.h), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8.r), + ), + ), + child: Text('提交'), + onPressed: () { + Navigator.pop(context); + Get.snackbar( + '提示', + '举报已提交,我们会尽快处理', + backgroundColor: Colors.green.withOpacity(0.8), + colorText: Colors.white, + ); + }, ), - ), - child: Text('提交'), - onPressed: () { - // 处理举报提交逻辑 - Navigator.pop(context); - Get.snackbar( - '提示', - '举报已提交,我们会尽快处理', - backgroundColor: Colors.green.withOpacity(0.8), - colorText: Colors.white, - ); - }, + SizedBox(height: 8.h), + ], ), - SizedBox(height: 8.h), - ], + ), ), ); }, From ee6babf4aa3d7fc0c3405ee2a0aa3ea863fd64f4 Mon Sep 17 00:00:00 2001 From: lxm <1274844347@qq.com> Date: Thu, 5 Jun 2025 08:05:55 +0800 Subject: [PATCH 5/7] =?UTF-8?q?feat(=E4=B8=BE=E6=8A=A5):=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0AI=E5=86=85=E5=AE=B9=E4=B8=BE=E6=8A=A5=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在API服务中添加举报接口 - 创建ReportController处理举报逻辑 - 重构举报表单为独立组件 - 实现举报原因选择和提交功能 --- lib/data/services/network/api.dart | 9 + lib/modules/agent/bindings/agent_binding.dart | 4 +- .../agent/controllers/report_controller.dart | 74 +++ lib/modules/agent/views/agent_view.dart | 460 ++++++++++++------ 4 files changed, 401 insertions(+), 146 deletions(-) create mode 100644 lib/modules/agent/controllers/report_controller.dart diff --git a/lib/data/services/network/api.dart b/lib/data/services/network/api.dart index 1bb13c1c8..7d8f95b50 100644 --- a/lib/data/services/network/api.dart +++ b/lib/data/services/network/api.dart @@ -89,4 +89,13 @@ class Api { params: params, ); } + + //举报AI内容 + static reportAiContext([params]) { + return DioManager().request( + NWMethod.post, + '/api/home/user_reportaicontext', + params: params, + ); + } } diff --git a/lib/modules/agent/bindings/agent_binding.dart b/lib/modules/agent/bindings/agent_binding.dart index 812e44d8b..ebb69cab2 100644 --- a/lib/modules/agent/bindings/agent_binding.dart +++ b/lib/modules/agent/bindings/agent_binding.dart @@ -1,9 +1,11 @@ import 'package:get/get.dart'; import '../controllers/agent_controller.dart'; +import '../controllers/report_controller.dart'; class AgentBinding extends Bindings { @override void dependencies() { Get.lazyPut(() => AgentController()); + Get.lazyPut(() => ReportController()); } -} \ No newline at end of file +} diff --git a/lib/modules/agent/controllers/report_controller.dart b/lib/modules/agent/controllers/report_controller.dart new file mode 100644 index 000000000..bd6371283 --- /dev/null +++ b/lib/modules/agent/controllers/report_controller.dart @@ -0,0 +1,74 @@ +import 'package:get/get.dart'; +import 'agent_controller.dart'; // 确保导入Message模型 +import 'package:flutter/material.dart'; +import '../../../data/services/network/api.dart'; + +class ReportController extends GetxController { + // 当前举报的消息 + final reportingMessage = Rxn(); + + // 选择的举报原因 + List selectedReasons = []; + + // 举报描述 + final reportDescription = ''.obs; + + // 初始化举报状态 + void initReport(Message message) { + reportingMessage.value = message; + selectedReasons.clear(); + reportDescription.value = ''; + } + + // 切换举报原因选择状态 + void toggleReason(String reason) { + if (selectedReasons.contains(reason)) { + selectedReasons.remove(reason); + } else { + selectedReasons.add(reason); + } + update(); + } + + // 更新举报描述 + void updateDescription(String text) { + reportDescription.value = text; + } + + // 提交举报 + Future submitReport() async { + if (reportingMessage.value == null) return; + + // 构建举报数据 + final reportData = { + 'describe': reportDescription.value, + 'message': reportingMessage.value, + 'reportContext': reportingMessage.value, + 'reporttype': selectedReasons.toList(), + }; + + print('提交举报数据: ${reportData}'); + + //调用API提交举报: + final Response = Api.reportAiContext(reportData); + + print('提交举报响应: $Response'); + + // 提交成功后重置状态 + selectedReasons.clear(); + reportDescription.value = ''; + reportingMessage.value = null; + + // 关闭举报表单 + Navigator.of(Get.context!).pop(); + + // 显示成功通知 + Get.snackbar( + '提交成功', + '举报已提交,我们会尽快处理', + backgroundColor: Colors.green.withOpacity(0.8), + colorText: Colors.white, + duration: const Duration(seconds: 2), + ); + } +} diff --git a/lib/modules/agent/views/agent_view.dart b/lib/modules/agent/views/agent_view.dart index b71c2e2f1..15044c63c 100644 --- a/lib/modules/agent/views/agent_view.dart +++ b/lib/modules/agent/views/agent_view.dart @@ -2,6 +2,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import '../controllers/agent_controller.dart'; +import '../controllers/report_controller.dart'; import 'message_bubble.dart'; import 'package:flutter/services.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; @@ -609,163 +610,187 @@ class AgentView extends StatelessWidget { isDarkMode ? Colors.red[700]! : Colors.red, () { // 实现举报功能 - showModalBottomSheet( - context: context, - isScrollControlled: true, // 关键:允许弹窗随键盘移动 - backgroundColor: - isDarkMode ? AppColors.cardBackground : Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.vertical(top: Radius.circular(16.r)), - ), - builder: (BuildContext context) { - return Padding( - // 添加底部内边距以容纳键盘 - padding: EdgeInsets.only( - bottom: MediaQuery.of(context).viewInsets.bottom, - ), - child: Container( - padding: EdgeInsets.all(16.w), - child: SingleChildScrollView( - // 添加滚动视图 - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Stack( - alignment: Alignment.center, - children: [ - Center( - child: Text( - '举报', - style: TextStyle( - fontSize: 18.sp, - fontWeight: FontWeight.bold, - color: isDarkMode - ? Colors.white - : Colors.black, - ), - ), - ), - SizedBox( - height: 20.w, - ), - Positioned( - right: 0, - child: IconButton( - icon: Icon( - Icons.close, - color: isDarkMode - ? Colors.grey[400] - : Colors.black54, - ), - onPressed: () => Navigator.pop(context), - ), - ), - ], - ), - Container( - padding: EdgeInsets.symmetric(horizontal: 12.w), - margin: EdgeInsets.only(bottom: 10.w), - child: Divider( - height: 1, - color: Colors.grey[300], - ), - ), - Wrap( - spacing: 8.w, - runSpacing: 8.h, - children: [ - _buildReportChip('有害/不安全', isDarkMode), - _buildReportChip('色情低俗', isDarkMode), - _buildReportChip('误导攻击', isDarkMode), - _buildReportChip('违法犯罪', isDarkMode), - _buildReportChip('隐私相关', isDarkMode), - _buildReportChip('侵犯我的著作权、名誉权等', isDarkMode), - _buildReportChip('其他', isDarkMode), - ], - ), - SizedBox(height: 16.h), - Container( - padding: EdgeInsets.all(12.w), - decoration: BoxDecoration( - color: isDarkMode - ? Colors.grey[800] - : Colors.grey[200], - borderRadius: BorderRadius.circular(8.r), - ), - child: TextField( - maxLines: 3, - style: TextStyle( - color: isDarkMode ? Colors.white : Colors.black, - ), - decoration: InputDecoration( - hintText: '我们想知道你举报的原因,你可以描述你遇到的问题。', - hintStyle: TextStyle( - color: isDarkMode - ? Colors.white70 - : Colors.black54, - fontSize: 14.sp, - ), - border: InputBorder.none, - ), - ), - ), - SizedBox(height: 14.h), - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Colors.blue, - foregroundColor: Colors.white, - padding: EdgeInsets.symmetric(vertical: 12.h), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8.r), - ), - ), - child: Text('提交'), - onPressed: () { - Navigator.pop(context); - Get.snackbar( - '提示', - '举报已提交,我们会尽快处理', - backgroundColor: Colors.green.withOpacity(0.8), - colorText: Colors.white, - ); - }, - ), - SizedBox(height: 8.h), - ], - ), - ), - ), - ); - }, - ); + final reportController = Get.find(); + reportController.initReport(message); + + _showReportForm(context, isDarkMode); + // showModalBottomSheet( + // context: context, + // isScrollControlled: true, // 关键:允许弹窗随键盘移动 + // backgroundColor: + // isDarkMode ? AppColors.cardBackground : Colors.white, + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.vertical(top: Radius.circular(16.r)), + // ), + // builder: (BuildContext context) { + // return Padding( + // // 添加底部内边距以容纳键盘 + // padding: EdgeInsets.only( + // bottom: MediaQuery.of(context).viewInsets.bottom, + // ), + // child: Container( + // padding: EdgeInsets.all(16.w), + // child: SingleChildScrollView( + // // 添加滚动视图 + // child: Column( + // mainAxisSize: MainAxisSize.min, + // crossAxisAlignment: CrossAxisAlignment.stretch, + // children: [ + // Stack( + // alignment: Alignment.center, + // children: [ + // Center( + // child: Text( + // '举报', + // style: TextStyle( + // fontSize: 18.sp, + // fontWeight: FontWeight.bold, + // color: isDarkMode + // ? Colors.white + // : Colors.black, + // ), + // ), + // ), + // SizedBox( + // height: 20.w, + // ), + // Positioned( + // right: 0, + // child: IconButton( + // icon: Icon( + // Icons.close, + // color: isDarkMode + // ? Colors.grey[400] + // : Colors.black54, + // ), + // onPressed: () => Navigator.pop(context), + // ), + // ), + // ], + // ), + // Container( + // padding: EdgeInsets.symmetric(horizontal: 12.w), + // margin: EdgeInsets.only(bottom: 10.w), + // child: Divider( + // height: 1, + // color: Colors.grey[300], + // ), + // ), + // Wrap( + // spacing: 8.w, + // runSpacing: 8.h, + // children: [ + // _buildReportChip('有害/不安全', isDarkMode), + // _buildReportChip('色情低俗', isDarkMode), + // _buildReportChip('误导攻击', isDarkMode), + // _buildReportChip('违法犯罪', isDarkMode), + // _buildReportChip('隐私相关', isDarkMode), + // _buildReportChip('侵犯我的著作权、名誉权等', isDarkMode), + // _buildReportChip('其他', isDarkMode), + // ], + // ), + // SizedBox(height: 16.h), + // Container( + // padding: EdgeInsets.all(12.w), + // decoration: BoxDecoration( + // color: isDarkMode + // ? Colors.grey[800] + // : Colors.grey[200], + // borderRadius: BorderRadius.circular(8.r), + // ), + // child: TextField( + // maxLines: 3, + // style: TextStyle( + // color: isDarkMode ? Colors.white : Colors.black, + // ), + // decoration: InputDecoration( + // hintText: '我们想知道你举报的原因,你可以描述你遇到的问题。', + // hintStyle: TextStyle( + // color: isDarkMode + // ? Colors.white70 + // : Colors.black54, + // fontSize: 14.sp, + // ), + // border: InputBorder.none, + // ), + // ), + // ), + // SizedBox(height: 14.h), + // ElevatedButton( + // style: ElevatedButton.styleFrom( + // backgroundColor: Colors.blue, + // foregroundColor: Colors.white, + // padding: EdgeInsets.symmetric(vertical: 12.h), + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(8.r), + // ), + // ), + // child: Text('提交'), + // onPressed: () { + // Navigator.pop(context); + // Get.snackbar( + // '提示', + // '举报已提交,我们会尽快处理', + // backgroundColor: Colors.green.withOpacity(0.8), + // colorText: Colors.white, + // ); + // }, + // ), + // SizedBox(height: 8.h), + // ], + // ), + // ), + // ), + // ); + // }, + // ); }, ), ], ); } - // 添加这个辅助方法来创建举报选项 - Widget _buildReportChip(String label, bool isDarkMode) { - return ChoiceChip( - label: Text( - label, - style: TextStyle( - color: isDarkMode ? Colors.white : Colors.black87, - fontSize: 14.sp, - ), - ), - selected: false, - backgroundColor: isDarkMode ? Colors.grey[800] : Colors.grey[200], + // 更新_showReportForm方法 + void _showReportForm(BuildContext context, bool isDarkMode) { + showModalBottomSheet( + context: context, + isScrollControlled: true, + backgroundColor: isDarkMode ? AppColors.cardBackground : Colors.white, shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16.r), + borderRadius: BorderRadius.vertical(top: Radius.circular(16.r)), ), - onSelected: (bool selected) { - // 可以在这里处理选择逻辑 + builder: (BuildContext context) { + return Padding( + padding: EdgeInsets.only( + bottom: MediaQuery.of(context).viewInsets.bottom, + ), + child: _ReportForm(isDarkMode: isDarkMode), + ); }, ); } + // // 添加这个辅助方法来创建举报选项 + // Widget _buildReportChip(String label, bool isDarkMode) { + // return ChoiceChip( + // label: Text( + // label, + // style: TextStyle( + // color: isDarkMode ? Colors.white : Colors.black87, + // fontSize: 14.sp, + // ), + // ), + // selected: false, + // backgroundColor: isDarkMode ? Colors.grey[800] : Colors.grey[200], + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(16.r), + // ), + // onSelected: (bool selected) { + // // 可以在这里处理选择逻辑 + // }, + // ); + // } + PopupMenuEntry _popupMenuEntry( Icon icon, String title, @@ -838,6 +863,151 @@ class AgentView extends StatelessWidget { } } +class _ReportForm extends StatelessWidget { + final bool isDarkMode; + final ReportController reportController = Get.find(); + + _ReportForm({required this.isDarkMode}); + + @override + Widget build(BuildContext context) { + return Container( + padding: EdgeInsets.all(16.w), + child: SingleChildScrollView( + child: GetBuilder( + builder: (_) => Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + alignment: Alignment.center, + children: [ + Center( + child: Text( + '举报', + style: TextStyle( + fontSize: 18.sp, + fontWeight: FontWeight.bold, + color: isDarkMode ? Colors.white : Colors.black, + ), + ), + ), + Positioned( + right: 0, + child: IconButton( + icon: Icon( + Icons.close, + color: isDarkMode ? Colors.grey[400] : Colors.black54, + ), + onPressed: () => Navigator.pop(context), + ), + ), + ], + ), + Container( + padding: EdgeInsets.symmetric(horizontal: 12.w), + margin: EdgeInsets.only(bottom: 10.w), + child: Divider( + height: 1, + color: Colors.grey[300], + ), + ), + GetBuilder( + builder: (controller) { + return Wrap( + spacing: 8.w, + runSpacing: 8.h, + children: [ + _buildReportChip('有害/不安全', isDarkMode, controller), + _buildReportChip('色情低俗', isDarkMode, controller), + _buildReportChip('误导攻击', isDarkMode, controller), + _buildReportChip('违法犯罪', isDarkMode, controller), + _buildReportChip('隐私相关', isDarkMode, controller), + _buildReportChip('侵犯我的著作权、名誉权等', isDarkMode, controller), + _buildReportChip('其他', isDarkMode, controller), + ], + ); + }, + ), + SizedBox(height: 16.h), + Container( + padding: EdgeInsets.all(12.w), + decoration: BoxDecoration( + color: isDarkMode ? Colors.grey[800] : Colors.grey[200], + borderRadius: BorderRadius.circular(8.r), + ), + child: TextField( + maxLines: 3, + onChanged: reportController.updateDescription, + style: TextStyle( + color: isDarkMode ? Colors.white : Colors.black, + ), + decoration: InputDecoration( + hintText: '我们想知道你举报的原因,你可以描述你遇到的问题。', + hintStyle: TextStyle( + color: isDarkMode ? Colors.white70 : Colors.black54, + fontSize: 14.sp, + ), + border: InputBorder.none, + ), + ), + ), + SizedBox(height: 14.h), + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Colors.blue, + foregroundColor: Colors.white, + padding: EdgeInsets.symmetric(vertical: 12.h), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8.r), + ), + ), + child: Text('提交'), + onPressed: () => reportController.submitReport(), + ), + SizedBox(height: 8.h), + ], + ), + ), + ), + ); + } + + Widget _buildReportChip( + String label, bool isDarkMode, ReportController controller) { + final isSelected = reportController.selectedReasons.contains(label); + + return GestureDetector( + onTap: () => reportController.toggleReason(label), + child: Container( + padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 8.h), + decoration: BoxDecoration( + color: isSelected + ? Colors.red + : (isDarkMode ? Colors.grey[800] : Colors.grey[200]), + borderRadius: BorderRadius.circular(16.r), + border: Border.all( + color: isSelected + ? Colors.red[700]! + : (isDarkMode ? Colors.grey[700]! : Colors.grey[300]!), + width: isSelected ? 1.0 : 0.5, + ), + ), + child: Text( + label, + style: TextStyle( + color: isSelected + ? Colors.white + : (isDarkMode ? Colors.white : Colors.black87), + fontSize: 14.sp, + fontWeight: isSelected ? FontWeight.bold : FontWeight.normal, + ), + ), + ), + ); + } +} + // 声音柱动画组件 class _SoundBar extends StatefulWidget { final double delay; From 48726debb56d666eb511b04f6d4864b902a6e6cf Mon Sep 17 00:00:00 2001 From: lxm <1274844347@qq.com> Date: Thu, 5 Jun 2025 18:55:06 +0800 Subject: [PATCH 6/7] =?UTF-8?q?fix(agent):=20=E4=BF=AE=E5=A4=8D=E4=B8=BE?= =?UTF-8?q?=E6=8A=A5=E5=8A=9F=E8=83=BD=E5=B9=B6=E6=9B=B4=E6=96=B0API?= =?UTF-8?q?=E7=AB=AF=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 更新`intl`依赖版本至^0.20.2 - 重命名API方法`reportAiContext`为`reportAiContent`并更新端点URL - 重构举报数据格式,确保可序列化 - 添加异步处理举报响应 --- lib/data/services/network/api.dart | 4 ++-- .../agent/controllers/report_controller.dart | 15 ++++++++++----- pubspec.yaml | 2 +- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/lib/data/services/network/api.dart b/lib/data/services/network/api.dart index 7d8f95b50..ff8adaa70 100644 --- a/lib/data/services/network/api.dart +++ b/lib/data/services/network/api.dart @@ -91,10 +91,10 @@ class Api { } //举报AI内容 - static reportAiContext([params]) { + static reportAiContent([params]) { return DioManager().request( NWMethod.post, - '/api/home/user_reportaicontext', + '/api/home/user_reportaicontent', params: params, ); } diff --git a/lib/modules/agent/controllers/report_controller.dart b/lib/modules/agent/controllers/report_controller.dart index bd6371283..0bae0106a 100644 --- a/lib/modules/agent/controllers/report_controller.dart +++ b/lib/modules/agent/controllers/report_controller.dart @@ -42,17 +42,22 @@ class ReportController extends GetxController { // 构建举报数据 final reportData = { 'describe': reportDescription.value, - 'message': reportingMessage.value, - 'reportContext': reportingMessage.value, - 'reporttype': selectedReasons.toList(), + // 将Message对象转换为可序列化的Map + 'message': [], + // 同样处理reportContext + 'reportContext': reportingMessage.value!.text, + + 'reporttype': selectedReasons.toString(), }; print('提交举报数据: ${reportData}'); //调用API提交举报: - final Response = Api.reportAiContext(reportData); + var response = await Api.reportAiContent(reportData); - print('提交举报响应: $Response'); + if (response != null) { + print('提交举报响应: $response'); + } // 提交成功后重置状态 selectedReasons.clear(); diff --git a/pubspec.yaml b/pubspec.yaml index 55f6887b5..6a32e6dd1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -25,7 +25,7 @@ dependencies: web_socket_channel: ^3.0.2 flutter_dotenv: ^5.1.0 synchronized: ^3.1.0 - intl: ^0.19.0 + intl: ^0.20.2 crypto: ^3.0.3 flutter_tts: ^4.2.2 logger: ^2.0.2+1 From fb95895d1cab81250a2e6d545cb9d3422a57e52b Mon Sep 17 00:00:00 2001 From: lxm <1274844347@qq.com> Date: Thu, 5 Jun 2025 19:36:23 +0800 Subject: [PATCH 7/7] =?UTF-8?q?refactor(data/models):=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E6=A8=A1=E5=9E=8B=E4=BB=A5=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E6=9B=B4=E5=A4=9A=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将`role`字段改为更明确的`isUser`布尔值 - 重命名`content`为`text`以提高可读性 - 添加`hasImage`和`imagePath`支持图片消息 - 新增`meta`字段用于存储卡片数据 - 将`isLoading`改为`isRecognizing`以更准确描述语音识别状态 --- lib/data/models/message_model.dart | 67 +++++++++++++++++++----------- 1 file changed, 43 insertions(+), 24 deletions(-) diff --git a/lib/data/models/message_model.dart b/lib/data/models/message_model.dart index 94aebc3ac..aef99cbc9 100644 --- a/lib/data/models/message_model.dart +++ b/lib/data/models/message_model.dart @@ -1,58 +1,77 @@ class Message { - final String role; // 'user' or 'assistant' - final String content; - final DateTime timestamp; - final bool isLoading; + final bool isUser; //标识信息是否来自用户还是AI + final String text; //信息文本内容 + final DateTime timestamp; // 消息时间戳 + final bool isRecognizing; // 是否为语音识别中的临时消息 + final bool hasImage; // 是否包含图片 + final String? imagePath; // 图片路径 + final Map? meta; //卡片数据 Message({ - required this.role, - required this.content, - required this.timestamp, - this.isLoading = false, - }); + // 构造函数 + required this.isUser, + required this.text, + DateTime? timestamp, + this.isRecognizing = false, + this.hasImage = false, + this.imagePath, + this.meta, + }) : this.timestamp = timestamp ?? DateTime.now(); // 从JSON构造函数 factory Message.fromJson(Map json) { return Message( - role: json['role'] as String, - content: json['content'] as String, + isUser: json['isUser'] as bool, + text: json['text'] as String, timestamp: DateTime.parse(json['timestamp'] as String), - isLoading: json['isLoading'] as bool? ?? false, + isRecognizing: json['isRecognizing'] as bool? ?? false, + hasImage: json['hasImage'] as bool? ?? false, + imagePath: json['imagePath'] as String?, + meta: json['meta'] as Map?, ); } // 转换为JSON Map toJson() { return { - 'role': role, - 'content': content, + 'isUser': isUser, + 'text': text, 'timestamp': timestamp.toIso8601String(), - 'isLoading': isLoading, + 'isRecognizing': isRecognizing, + 'hasImage': hasImage, + 'imagePath': imagePath, + 'meta': meta, }; } // 创建一个加载中的消息 factory Message.loading() { return Message( - role: 'assistant', - content: '', + isUser: false, + text: '', timestamp: DateTime.now(), - isLoading: true, + isRecognizing: true, ); } // 复制并修改 Message copyWith({ - String? role, - String? content, + bool? isUser, + String? text, DateTime? timestamp, - bool? isLoading, + bool? isRecognizing, + bool? hasImage, + String? imagePath, + Map? meta, }) { return Message( - role: role ?? this.role, - content: content ?? this.content, + isUser: isUser ?? this.isUser, + text: text ?? this.text, timestamp: timestamp ?? this.timestamp, - isLoading: isLoading ?? this.isLoading, + isRecognizing: isRecognizing ?? this.isRecognizing, + hasImage: hasImage ?? this.hasImage, + imagePath: imagePath ?? this.imagePath, + meta: meta ?? this.meta, ); } }