feat: UI 系统中心化 + 趋势图重构 + 法律文档 H5 上线
- UI 系统: 新增 design_tokens / module_visuals / app_buttons / app_status_badge / app_toast / ai_content 六个共享模块; 28 个页面接入, SnackBar 全部替换为 AppToast - 趋势图: 直线折线 + 渐变填充 + 阴影; 去网格线; X 轴日+月份分隔; Y 轴整数刻度最多 4 个; 点击数据点/录入记录显示上方浮层, 选中点变实心 - 法律文档 H5: 后端 wwwroot 托管隐私政策/服务协议/关于/个人信息收集清单/第三方 SDK 清单 + 索引页; Program.cs 启用 UseDefaultFiles + UseStaticFiles - 其他: auth_provider 登录流程调整; api_client IP 适配; 主页智能体栏间距优化
This commit is contained in:
@@ -6,6 +6,7 @@ import 'package:image_picker/image_picker.dart';
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||
import '../../core/app_colors.dart';
|
||||
import '../../core/app_module_visuals.dart';
|
||||
import '../../core/app_theme.dart';
|
||||
import '../../core/navigation_provider.dart';
|
||||
import '../../providers/auth_provider.dart';
|
||||
@@ -26,6 +27,8 @@ class _HomePageState extends ConsumerState<HomePage>
|
||||
final _textCtrl = TextEditingController();
|
||||
final _scrollCtrl = ScrollController();
|
||||
final _focusNode = FocusNode();
|
||||
final _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
double? _drawerDragStartX;
|
||||
String? _pickedImagePath;
|
||||
int _lastMsgCount = 0;
|
||||
Timer? _notificationTimer;
|
||||
@@ -38,11 +41,18 @@ class _HomePageState extends ConsumerState<HomePage>
|
||||
(_) => ref.invalidate(notificationUnreadCountProvider),
|
||||
);
|
||||
_notificationTimer = Timer.periodic(
|
||||
const Duration(seconds: 30),
|
||||
const Duration(minutes: 2),
|
||||
(_) => ref.invalidate(notificationUnreadCountProvider),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||
if (state == AppLifecycleState.resumed) {
|
||||
ref.invalidate(notificationUnreadCountProvider);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeMetrics() {
|
||||
// 键盘动画期间每帧都会回调,让列表底部始终贴住输入区上沿
|
||||
@@ -113,20 +123,46 @@ class _HomePageState extends ConsumerState<HomePage>
|
||||
_lastMsgCount = currentCount;
|
||||
|
||||
return Scaffold(
|
||||
key: _scaffoldKey,
|
||||
backgroundColor: const Color(0xFFFFFCFF),
|
||||
drawer: const HealthDrawer(),
|
||||
drawerEdgeDragWidth: MediaQuery.sizeOf(context).width * 0.65,
|
||||
drawerEnableOpenDragGesture: false,
|
||||
body: AppBackground(
|
||||
safeArea: true,
|
||||
child: Column(
|
||||
children: [
|
||||
_buildHeader(user),
|
||||
Expanded(
|
||||
child: RepaintBoundary(
|
||||
child: ChatMessagesView(
|
||||
scrollCtrl: _scrollCtrl,
|
||||
messages: chatState.messages,
|
||||
),
|
||||
child: Stack(
|
||||
children: [
|
||||
RepaintBoundary(
|
||||
child: ChatMessagesView(
|
||||
scrollCtrl: _scrollCtrl,
|
||||
messages: chatState.messages,
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
left: 0,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
width: 44,
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onHorizontalDragStart: (details) {
|
||||
_drawerDragStartX = details.globalPosition.dx;
|
||||
},
|
||||
onHorizontalDragUpdate: (details) {
|
||||
final startX = _drawerDragStartX;
|
||||
if (startX == null) return;
|
||||
if (details.globalPosition.dx - startX < 28) return;
|
||||
_drawerDragStartX = null;
|
||||
_scaffoldKey.currentState?.openDrawer();
|
||||
},
|
||||
onHorizontalDragEnd: (_) => _drawerDragStartX = null,
|
||||
onHorizontalDragCancel: () => _drawerDragStartX = null,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
_buildBottomBar(context),
|
||||
@@ -210,12 +246,12 @@ class _HomePageState extends ConsumerState<HomePage>
|
||||
}
|
||||
|
||||
static final _agentDefs = [
|
||||
(ActiveAgent.consultation, 'AI问诊', LucideIcons.messageCircle),
|
||||
(ActiveAgent.health, '记数据', LucideIcons.heartPulse),
|
||||
(ActiveAgent.diet, '拍饮食', LucideIcons.utensils),
|
||||
(ActiveAgent.medication, '药管家', LucideIcons.pill),
|
||||
(ActiveAgent.report, '报告分析', LucideIcons.fileText),
|
||||
(ActiveAgent.exercise, '运动', LucideIcons.activity),
|
||||
ActiveAgent.consultation,
|
||||
ActiveAgent.health,
|
||||
ActiveAgent.diet,
|
||||
ActiveAgent.medication,
|
||||
ActiveAgent.report,
|
||||
ActiveAgent.exercise,
|
||||
];
|
||||
|
||||
Widget _buildAgentBar() {
|
||||
@@ -227,24 +263,18 @@ class _HomePageState extends ConsumerState<HomePage>
|
||||
itemCount: _agentDefs.length,
|
||||
separatorBuilder: (_, _) => const SizedBox(width: 8),
|
||||
itemBuilder: (_, i) {
|
||||
final (agent, label, icon) = _agentDefs[i];
|
||||
final gradient = _agentGradient(agent);
|
||||
final agent = _agentDefs[i];
|
||||
final visual = _agentVisual(agent);
|
||||
return GestureDetector(
|
||||
onTap: () =>
|
||||
ref.read(chatProvider.notifier).triggerAgent(agent, label),
|
||||
onTap: () => ref
|
||||
.read(chatProvider.notifier)
|
||||
.triggerAgent(agent, visual.label),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 13, vertical: 9),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withValues(alpha: 0.86),
|
||||
borderRadius: BorderRadius.circular(999),
|
||||
border: Border.all(color: Colors.white, width: 1.2),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: const Color(0xFF6366F1).withValues(alpha: 0.10),
|
||||
blurRadius: 14,
|
||||
offset: const Offset(0, 7),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
@@ -253,14 +283,14 @@ class _HomePageState extends ConsumerState<HomePage>
|
||||
width: 16,
|
||||
height: 16,
|
||||
decoration: BoxDecoration(
|
||||
gradient: gradient,
|
||||
gradient: visual.gradient,
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
child: Icon(icon, size: 11, color: Colors.white),
|
||||
child: Icon(visual.icon, size: 11, color: Colors.white),
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
Text(
|
||||
label,
|
||||
visual.label,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w700,
|
||||
@@ -276,39 +306,41 @@ class _HomePageState extends ConsumerState<HomePage>
|
||||
);
|
||||
}
|
||||
|
||||
LinearGradient _agentGradient(ActiveAgent agent) {
|
||||
({String label, IconData icon, LinearGradient gradient}) _agentVisual(
|
||||
ActiveAgent agent,
|
||||
) {
|
||||
({String label, AppModuleVisual visual}) fromModule(
|
||||
String label,
|
||||
AppModuleVisual visual,
|
||||
) => (label: label, visual: visual);
|
||||
|
||||
final module = switch (agent) {
|
||||
ActiveAgent.health => fromModule('记数据', AppModuleVisuals.health),
|
||||
ActiveAgent.diet => fromModule('拍饮食', AppModuleVisuals.diet),
|
||||
ActiveAgent.medication => fromModule('药管家', AppModuleVisuals.medication),
|
||||
ActiveAgent.report => fromModule('报告分析', AppModuleVisuals.report),
|
||||
ActiveAgent.exercise => fromModule('运动', AppModuleVisuals.exercise),
|
||||
_ => null,
|
||||
};
|
||||
if (module != null) {
|
||||
return (
|
||||
label: module.label,
|
||||
icon: module.visual.icon,
|
||||
gradient: module.visual.gradient,
|
||||
);
|
||||
}
|
||||
|
||||
return switch (agent) {
|
||||
ActiveAgent.consultation => const LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [Color(0xFFFFCAD4), Color(0xFFFF9AAE)],
|
||||
ActiveAgent.consultation => (
|
||||
label: 'AI问诊',
|
||||
icon: LucideIcons.messageCircle,
|
||||
gradient: AppColors.doctorGradient,
|
||||
),
|
||||
ActiveAgent.health => const LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [Color(0xFFA1FFCE), Color(0xFF69DB8F)],
|
||||
_ => (
|
||||
label: 'AI问诊',
|
||||
icon: LucideIcons.messageCircle,
|
||||
gradient: AppColors.primaryGradient,
|
||||
),
|
||||
ActiveAgent.diet => const LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [Color(0xFFF6D365), Color(0xFFFDA085)],
|
||||
),
|
||||
ActiveAgent.medication => const LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [Color(0xFF89F7FE), Color(0xFF66A6FF)],
|
||||
),
|
||||
ActiveAgent.report => const LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [Color(0xFFE0C3FC), Color(0xFF8EC5FC)],
|
||||
),
|
||||
ActiveAgent.exercise => const LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [Color(0xFFB6F2FF), Color(0xFF7DD3FC)],
|
||||
),
|
||||
_ => AppColors.primaryGradient,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -319,20 +351,13 @@ class _HomePageState extends ConsumerState<HomePage>
|
||||
border: Border(
|
||||
top: BorderSide(color: Colors.white.withValues(alpha: 0.62)),
|
||||
),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: const Color(0xFF101828).withValues(alpha: 0.045),
|
||||
blurRadius: 20,
|
||||
offset: const Offset(0, -8),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const SizedBox(height: 6),
|
||||
const SizedBox(height: 8),
|
||||
_buildAgentBar(),
|
||||
const SizedBox(height: 6),
|
||||
const SizedBox(height: 12),
|
||||
if (_pickedImagePath != null) _buildImagePreview(),
|
||||
_buildInputBar(),
|
||||
],
|
||||
@@ -503,11 +528,9 @@ class _HomePageState extends ConsumerState<HomePage>
|
||||
final path = pdfFile.path;
|
||||
if (path == null || path.isEmpty) return;
|
||||
// 上传 + 让 AI 看 PDF 内容
|
||||
await ref.read(chatProvider.notifier).sendPdf(
|
||||
path,
|
||||
pdfFile.name,
|
||||
_textCtrl.text.trim(),
|
||||
);
|
||||
await ref
|
||||
.read(chatProvider.notifier)
|
||||
.sendPdf(path, pdfFile.name, _textCtrl.text.trim());
|
||||
_textCtrl.clear();
|
||||
if (mounted) setState(() {});
|
||||
},
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
import 'dart:io';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_markdown/flutter_markdown.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||
import '../../../core/app_colors.dart';
|
||||
import '../../../core/app_design_tokens.dart';
|
||||
import '../../../core/app_module_visuals.dart';
|
||||
import '../../../core/app_theme.dart';
|
||||
import '../../../core/api_client.dart' show baseUrl;
|
||||
import '../../../core/navigation_provider.dart';
|
||||
import '../../../providers/chat_provider.dart';
|
||||
import '../../../providers/data_providers.dart';
|
||||
import '../../../widgets/ai_content.dart';
|
||||
import '../../../widgets/app_toast.dart';
|
||||
|
||||
/// 卡片入场动画包装(从下往上滑入 + 淡入)
|
||||
class _AnimatedCardEntry extends StatefulWidget {
|
||||
@@ -260,20 +263,15 @@ class ChatMessagesView extends ConsumerWidget {
|
||||
const SizedBox(height: 9),
|
||||
Text(
|
||||
info.$2,
|
||||
style: const TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.w800,
|
||||
color: AppColors.textPrimary,
|
||||
),
|
||||
style: AppTextStyles.chatTitle.copyWith(
|
||||
fontSize: 22,
|
||||
fontWeight: FontWeight.w900,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
info.$3,
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
color: AppColors.textSecondary,
|
||||
height: 1.4,
|
||||
),
|
||||
style: AppTextStyles.summarySubtitle,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -514,7 +512,7 @@ class ChatMessagesView extends ConsumerWidget {
|
||||
} else if (isExercise) {
|
||||
// 运动计划 — 主展示区大号显示运动名,字段列时长/频率/天数
|
||||
title = '运动计划确认';
|
||||
titleIcon = Icons.directions_run_outlined;
|
||||
titleIcon = LucideIcons.footprints;
|
||||
final exName =
|
||||
(meta['value'] ??
|
||||
meta['name'] ??
|
||||
@@ -706,7 +704,7 @@ class ChatMessagesView extends ConsumerWidget {
|
||||
: Icon(
|
||||
isMedication
|
||||
? Icons.medication_liquid_outlined
|
||||
: Icons.directions_run_outlined,
|
||||
: LucideIcons.footprints,
|
||||
size: 36,
|
||||
color: AppColors.iconColor,
|
||||
),
|
||||
@@ -895,9 +893,11 @@ class ChatMessagesView extends ConsumerWidget {
|
||||
.read(chatProvider.notifier)
|
||||
.confirmMessage(msg.id);
|
||||
if (error != null && context.mounted) {
|
||||
ScaffoldMessenger.of(
|
||||
AppToast.show(
|
||||
context,
|
||||
).showSnackBar(SnackBar(content: Text(error)));
|
||||
error,
|
||||
type: AppToastType.error,
|
||||
);
|
||||
}
|
||||
},
|
||||
borderRadius: BorderRadius.circular(18),
|
||||
@@ -1098,63 +1098,13 @@ class ChatMessagesView extends ConsumerWidget {
|
||||
if (isUser)
|
||||
SelectableText(
|
||||
msg.content,
|
||||
style: const TextStyle(
|
||||
fontSize: 19,
|
||||
color: Colors.white,
|
||||
height: 1.5,
|
||||
),
|
||||
style: AppTextStyles.chatBody.copyWith(color: Colors.white),
|
||||
)
|
||||
else
|
||||
MarkdownBody(
|
||||
data: _cleanAiText(msg.content),
|
||||
selectable: true,
|
||||
AiMarkdownView(
|
||||
data: msg.content,
|
||||
onTapLink: (text, href, title) =>
|
||||
_handleMarkdownLink(context, ref, href),
|
||||
styleSheet: MarkdownStyleSheet(
|
||||
p: const TextStyle(
|
||||
fontSize: 19,
|
||||
color: AppColors.textPrimary,
|
||||
height: 1.5,
|
||||
),
|
||||
a: const TextStyle(
|
||||
fontSize: 19,
|
||||
color: AppColors.primary,
|
||||
fontWeight: FontWeight.w700,
|
||||
decoration: TextDecoration.underline,
|
||||
decorationColor: AppColors.primary,
|
||||
),
|
||||
strong: const TextStyle(
|
||||
fontSize: 19,
|
||||
color: AppColors.textPrimary,
|
||||
height: 1.5,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
h1: const TextStyle(
|
||||
fontSize: 22,
|
||||
color: AppColors.textPrimary,
|
||||
height: 1.35,
|
||||
fontWeight: FontWeight.w800,
|
||||
),
|
||||
h2: const TextStyle(
|
||||
fontSize: 21,
|
||||
color: AppColors.textPrimary,
|
||||
height: 1.4,
|
||||
fontWeight: FontWeight.w800,
|
||||
),
|
||||
h3: const TextStyle(
|
||||
fontSize: 20,
|
||||
color: AppColors.textPrimary,
|
||||
height: 1.4,
|
||||
fontWeight: FontWeight.w800,
|
||||
),
|
||||
listBullet: const TextStyle(
|
||||
fontSize: 24,
|
||||
color: AppColors.textPrimary,
|
||||
height: 1.2,
|
||||
fontWeight: FontWeight.w900,
|
||||
),
|
||||
listBulletPadding: const EdgeInsets.only(right: 8),
|
||||
),
|
||||
),
|
||||
|
||||
// 图片缩略图(在文字下方)
|
||||
@@ -1321,6 +1271,7 @@ class ChatMessagesView extends ConsumerWidget {
|
||||
}
|
||||
|
||||
/// 清理 AI 返回文本中的异常占位符(Markdown 格式交给 MarkdownBody 渲染)
|
||||
// ignore: unused_element
|
||||
static String _cleanAiText(String text) {
|
||||
var t = text;
|
||||
// 移除 $1、$2 等占位符
|
||||
@@ -1449,7 +1400,21 @@ class ChatMessagesView extends ConsumerWidget {
|
||||
}
|
||||
|
||||
static _AgentColors _agentColors(ActiveAgent agent) {
|
||||
_AgentColors fromModule(AppModuleVisual visual) => _AgentColors(
|
||||
gradient: [visual.gradient.colors.first, visual.gradient.colors.last],
|
||||
bg: visual.lightColor,
|
||||
border: visual.borderColor,
|
||||
iconBg: visual.lightColor,
|
||||
accent: visual.color,
|
||||
verticalGradient: true,
|
||||
);
|
||||
|
||||
return switch (agent) {
|
||||
ActiveAgent.health => fromModule(AppModuleVisuals.health),
|
||||
ActiveAgent.diet => fromModule(AppModuleVisuals.diet),
|
||||
ActiveAgent.medication => fromModule(AppModuleVisuals.medication),
|
||||
ActiveAgent.report => fromModule(AppModuleVisuals.report),
|
||||
ActiveAgent.exercise => fromModule(AppModuleVisuals.exercise),
|
||||
ActiveAgent.consultation => _AgentColors(
|
||||
gradient: [Color(0xFFFFCAD4), Color(0xFFFF9AAE)],
|
||||
bg: const Color(0xFFFFF4F6),
|
||||
@@ -1458,46 +1423,6 @@ class ChatMessagesView extends ConsumerWidget {
|
||||
accent: const Color(0xFFFF7F98),
|
||||
verticalGradient: true,
|
||||
),
|
||||
ActiveAgent.health => _AgentColors(
|
||||
gradient: [Color(0xFFA1FFCE), Color(0xFF69DB8F)],
|
||||
bg: const Color(0xFFF4FEF2),
|
||||
border: const Color(0xFFD4F0C8),
|
||||
iconBg: const Color(0xFFF0FCEF),
|
||||
accent: const Color(0xFF52B87A),
|
||||
verticalGradient: true,
|
||||
),
|
||||
ActiveAgent.diet => _AgentColors(
|
||||
gradient: [Color(0xFFF6D365), Color(0xFFFDA085)],
|
||||
bg: const Color(0xFFFFF7F0),
|
||||
border: const Color(0xFFFFE8D4),
|
||||
iconBg: const Color(0xFFFFF0E4),
|
||||
accent: const Color(0xFFF89C5B),
|
||||
verticalGradient: true,
|
||||
),
|
||||
ActiveAgent.medication => _AgentColors(
|
||||
gradient: [Color(0xFF89F7FE), Color(0xFF66A6FF)],
|
||||
bg: const Color(0xFFF4F6FF),
|
||||
border: const Color(0xFFDDE6FF),
|
||||
iconBg: const Color(0xFFEFF3FF),
|
||||
accent: const Color(0xFF4F8FF7),
|
||||
verticalGradient: true,
|
||||
),
|
||||
ActiveAgent.report => _AgentColors(
|
||||
gradient: [Color(0xFFE0C3FC), Color(0xFF8EC5FC)],
|
||||
bg: const Color(0xFFF8F5FF),
|
||||
border: const Color(0xFFE9E0FF),
|
||||
iconBg: const Color(0xFFF2EDFF),
|
||||
accent: const Color(0xFF9D8AF8),
|
||||
verticalGradient: true,
|
||||
),
|
||||
ActiveAgent.exercise => _AgentColors(
|
||||
gradient: [Color(0xFFB6F2FF), Color(0xFF7DD3FC)],
|
||||
bg: const Color(0xFFF0FCFF),
|
||||
border: const Color(0xFFD8F5FC),
|
||||
iconBg: const Color(0xFFEAFBFF),
|
||||
accent: const Color(0xFF38BDE8),
|
||||
verticalGradient: true,
|
||||
),
|
||||
_ => _AgentColors(
|
||||
gradient: [AppColors.primary, AppColors.blueMeasure],
|
||||
bg: const Color(0xFFF6F3FF),
|
||||
@@ -1519,7 +1444,7 @@ class ChatMessagesView extends ConsumerWidget {
|
||||
'AI智能问诊,描述症状获取建议',
|
||||
),
|
||||
ActiveAgent.report => (LucideIcons.fileText, '报告分析', '上传体检报告,AI 辅助解读'),
|
||||
ActiveAgent.exercise => (LucideIcons.activity, '运动', '制定运动计划,打卡记录进度'),
|
||||
ActiveAgent.exercise => (LucideIcons.footprints, '运动', '制定运动计划,打卡记录进度'),
|
||||
_ => (Icons.forum_outlined, 'AI 助手', '血管病患者的 AI 健康管理助手'),
|
||||
};
|
||||
}
|
||||
@@ -1621,8 +1546,8 @@ class ChatMessagesView extends ConsumerWidget {
|
||||
|
||||
// ── 1. 健康指标 ──
|
||||
// 没记录则整行不显示(避免每天唠叨提醒)
|
||||
const healthIconColor = Color(0xFF3B82F6);
|
||||
const healthIconBg = Color(0xFFDBEAFE);
|
||||
final healthIconColor = AppModuleVisuals.health.color;
|
||||
final healthIconBg = AppModuleVisuals.health.lightColor;
|
||||
if (allNull) {
|
||||
// 不显示
|
||||
} else if (hasAbnormal) {
|
||||
@@ -1632,7 +1557,7 @@ class ChatMessagesView extends ConsumerWidget {
|
||||
tasks.add(
|
||||
_taskRow(
|
||||
context,
|
||||
Icons.warning_amber_rounded,
|
||||
LucideIcons.triangleAlert,
|
||||
'健康指标',
|
||||
trailing: trailing,
|
||||
status: 'warning',
|
||||
@@ -1646,7 +1571,7 @@ class ChatMessagesView extends ConsumerWidget {
|
||||
tasks.add(
|
||||
_taskRow(
|
||||
context,
|
||||
Icons.check_circle,
|
||||
LucideIcons.circleCheck,
|
||||
'健康指标',
|
||||
trailing: '指标正常',
|
||||
status: 'done',
|
||||
@@ -1658,8 +1583,8 @@ class ChatMessagesView extends ConsumerWidget {
|
||||
}
|
||||
|
||||
// ── 2. 运动 ──
|
||||
const exIconColor = Color(0xFFF59E0B);
|
||||
const exIconBg = Color(0xFFFEF3C7);
|
||||
final exIconColor = AppModuleVisuals.exercise.color;
|
||||
final exIconBg = AppModuleVisuals.exercise.lightColor;
|
||||
final exercisePlan = ref.watch(currentExercisePlanProvider);
|
||||
var hasExercise = false;
|
||||
exercisePlan.when(
|
||||
@@ -1685,7 +1610,7 @@ class ChatMessagesView extends ConsumerWidget {
|
||||
tasks.add(
|
||||
_taskRow(
|
||||
context,
|
||||
Icons.directions_run,
|
||||
LucideIcons.footprints,
|
||||
'$name $dur分钟',
|
||||
status: done
|
||||
? 'done'
|
||||
@@ -1703,7 +1628,7 @@ class ChatMessagesView extends ConsumerWidget {
|
||||
tasks.add(
|
||||
_taskRow(
|
||||
context,
|
||||
Icons.directions_run,
|
||||
LucideIcons.footprints,
|
||||
'运动',
|
||||
trailing: '正在加载运动计划',
|
||||
status: 'pending',
|
||||
@@ -1718,7 +1643,7 @@ class ChatMessagesView extends ConsumerWidget {
|
||||
tasks.add(
|
||||
_taskRow(
|
||||
context,
|
||||
Icons.directions_run,
|
||||
LucideIcons.footprints,
|
||||
'运动',
|
||||
trailing: '运动计划加载失败',
|
||||
status: 'overdue',
|
||||
@@ -1733,7 +1658,7 @@ class ChatMessagesView extends ConsumerWidget {
|
||||
tasks.add(
|
||||
_taskRow(
|
||||
context,
|
||||
Icons.directions_run,
|
||||
LucideIcons.footprints,
|
||||
'运动',
|
||||
trailing: '暂无今日运动计划',
|
||||
status: 'pending',
|
||||
@@ -1746,8 +1671,8 @@ class ChatMessagesView extends ConsumerWidget {
|
||||
|
||||
// ── 3. 用药打卡 ──
|
||||
// 漏服时突出提醒;未到服药时间时也保留一行轻提示,避免今日健康缺少用药状态。
|
||||
const medIconColor = Color(0xFFEC4899);
|
||||
const medIconBg = Color(0xFFFCE7F3);
|
||||
final medIconColor = AppModuleVisuals.medication.color;
|
||||
final medIconBg = AppModuleVisuals.medication.lightColor;
|
||||
reminders.whenOrNull(
|
||||
data: (meds) {
|
||||
final overdueMeds = meds
|
||||
@@ -1757,7 +1682,7 @@ class ChatMessagesView extends ConsumerWidget {
|
||||
tasks.add(
|
||||
_taskRow(
|
||||
context,
|
||||
Icons.medication_rounded,
|
||||
LucideIcons.pill,
|
||||
'用药',
|
||||
trailing: meds.isEmpty ? '暂无用药安排' : '暂时不用吃药',
|
||||
status: 'done',
|
||||
@@ -1815,7 +1740,7 @@ class ChatMessagesView extends ConsumerWidget {
|
||||
tasks.add(
|
||||
_taskRow(
|
||||
context,
|
||||
Icons.medication_rounded,
|
||||
LucideIcons.pill,
|
||||
title,
|
||||
trailing: trailing,
|
||||
status: status,
|
||||
|
||||
Reference in New Issue
Block a user