diff --git a/health_app/lib/pages/home/home_page.dart b/health_app/lib/pages/home/home_page.dart index 1fa456c..127356b 100644 --- a/health_app/lib/pages/home/home_page.dart +++ b/health_app/lib/pages/home/home_page.dart @@ -92,10 +92,7 @@ class _HomePageState extends ConsumerState { // ── 顶部栏 ── _buildHeader(user), - // ── 今日任务(可折叠) ── - _buildTaskCardsArea(), - - // ── 聊天区域(弹性填充剩余空间) ── + // ── 聊天区域(今日任务已移入对话流第一条消息) ── Expanded(child: ChatMessagesView(scrollCtrl: _scrollCtrl, messages: chatState.messages)), // ── 底部合并区:智能体栏 + 操作面板 + 输入框(固定高度) ── diff --git a/health_app/lib/pages/home/widgets/chat_messages_view.dart b/health_app/lib/pages/home/widgets/chat_messages_view.dart index fc1bd80..2e41bb0 100644 --- a/health_app/lib/pages/home/widgets/chat_messages_view.dart +++ b/health_app/lib/pages/home/widgets/chat_messages_view.dart @@ -63,7 +63,10 @@ class ChatMessagesView extends ConsumerWidget { switch (msg.type) { case MessageType.agentWelcome: - return _buildAgentWelcomeCard(context, ref, msg, chatState.activeAgent); + final storedAgent = _parseAgentFromName(msg.metadata?['agent'] as String?); + return _buildAgentWelcomeCard(context, ref, msg, storedAgent); + case MessageType.taskCard: + return _buildTaskCardInChat(context, ref); case MessageType.dataConfirm: return _buildDataConfirmCard(context, msg); case MessageType.medicationConfirm: @@ -1254,4 +1257,69 @@ class _ExpandableAdviceState extends State<_ExpandableAdvice> { ), ); } + + static ActiveAgent _parseAgentFromName(String? name) { + switch (name) { + case 'consultation': return ActiveAgent.consultation; + case 'health': return ActiveAgent.health; + case 'diet': return ActiveAgent.diet; + case 'medication': return ActiveAgent.medication; + case 'report': return ActiveAgent.report; + case 'exercise': return ActiveAgent.exercise; + default: return ActiveAgent.default_; + } + } + + Widget _buildTaskCardInChat(BuildContext context, WidgetRef ref) { + final health = ref.watch(latestHealthProvider); + return health.when( + data: (data) => _taskCardBubble(context, ref, data), + loading: () => _taskCardBubble(context, ref, {}), + error: (_, __) => _taskCardBubble(context, ref, {}), + ); + } + + Widget _taskCardBubble(BuildContext context, WidgetRef ref, Map data) { + final bp = data['BloodPressure']; + final bpText = bp is Map ? '${bp['systolic'] ?? '--'}/${bp['diastolic'] ?? '--'}' : '--'; + final hr = data['HeartRate']; + final hrText = hr is Map && hr['value'] != null ? '${hr['value']}' : '--'; + final gl = data['Glucose']; + final glText = gl is Map && gl['value'] != null ? '${gl['value']}' : '--'; + final sp = data['SpO2']; + final spText = sp is Map && sp['value'] != null ? '${sp['value']}' : '--'; + + return Container( + margin: const EdgeInsets.only(bottom: 12), + padding: const EdgeInsets.all(14), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + boxShadow: [BoxShadow(color: const Color(0xFF635BFF).withAlpha(10), blurRadius: 8, offset: const Offset(0, 2))], + ), + child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ + Row(children: [ + Icon(Icons.today, size: 18, color: const Color(0xFF635BFF)), + const SizedBox(width: 8), + const Text('今日任务', style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600, color: Color(0xFF1A1A1A))), + ]), + const SizedBox(height: 10), + Row(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ + _miniMetric('血压', bpText, Icons.favorite, ref), + _miniMetric('心率', hrText, Icons.monitor_heart, ref), + _miniMetric('血糖', glText, Icons.bloodtype, ref), + _miniMetric('血氧', spText, Icons.air, ref), + ]), + ]), + ); + } + + Widget _miniMetric(String label, String value, IconData icon, WidgetRef ref) { + return Column(children: [ + Icon(icon, size: 20, color: const Color(0xFF635BFF)), + const SizedBox(height: 4), + Text(value, style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold, color: Color(0xFF1A1A1A))), + Text(label, style: const TextStyle(fontSize: 10, color: Color(0xFF999999))), + ]); + } } diff --git a/health_app/lib/providers/chat_provider.dart b/health_app/lib/providers/chat_provider.dart index e8fe403..64d8b32 100644 --- a/health_app/lib/providers/chat_provider.dart +++ b/health_app/lib/providers/chat_provider.dart @@ -5,7 +5,7 @@ import 'auth_provider.dart'; import 'data_providers.dart'; import '../utils/sse_handler.dart'; -enum MessageType { text, dataConfirm, medicationConfirm, dietAnalysis, reportAnalysis, quickOptions, agentWelcome } +enum MessageType { text, dataConfirm, medicationConfirm, dietAnalysis, reportAnalysis, quickOptions, agentWelcome, taskCard } class ChatMessage { final String id; @@ -115,7 +115,22 @@ class ChatNotifier extends Notifier { StreamSubscription>? _subscription; @override - ChatState build() => const ChatState(); + ChatState build() { + // 首次加载时插入今日任务卡片作为第一条消息 + Future.microtask(() => insertTaskCard()); + return const ChatState(); + } + + void insertTaskCard() { + if (state.messages.any((m) => m.type == MessageType.taskCard)) return; + state = state.copyWith(messages: [ChatMessage( + id: 'task_card', + role: 'assistant', + content: '', + createdAt: DateTime.now(), + type: MessageType.taskCard, + ), ...state.messages]); + } void setAgent(ActiveAgent a) { _subscription?.cancel();