feat: AI 对话附件上下文解析 + 历史会话归档 + 多页面 UI 重构

- 后端: 新增 AttachmentContextBuilder 解析图片/PDF 摘要并拼入 LLM 上下文; ai_chat_endpoints 扩展附件接口; 新增 ReportAnalysisService
- 前端: 新增历史会话页与 conversation_history_provider; chat 链路支持附件展示与回放
- UI: 重构 medication_checkin / notification_center / profile / health_drawer 等多页面
- 配置: api_client baseUrl 适配当前 WiFi IP
This commit is contained in:
MingNian
2026-07-06 12:44:59 +08:00
parent 4507083f3f
commit 7a93237069
38 changed files with 4165 additions and 1157 deletions

View File

@@ -359,6 +359,7 @@ class _DeviceManagementPageState extends ConsumerState<DeviceManagementPage>
final ok = await showDialog<bool>(
context: context,
builder: (ctx) => AlertDialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
title: const Text('解绑设备'),
content: Text('确定解绑这台${device.type.label}吗?'),
actions: [
@@ -388,29 +389,33 @@ class _DevicesHeader extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.fromLTRB(16, 14, 16, 14),
padding: const EdgeInsets.fromLTRB(18, 18, 18, 18),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: AppColors.border),
boxShadow: AppColors.cardShadowLight,
borderRadius: BorderRadius.circular(20),
border: Border.all(color: AppColors.borderLight, width: 1.1),
boxShadow: [AppTheme.shadowLight],
),
child: Row(
children: [
Container(
width: 42,
height: 42,
width: 50,
height: 50,
decoration: BoxDecoration(
color: const Color(0xFFEFF6FF),
borderRadius: BorderRadius.circular(8),
gradient: const LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [Color(0xFF60A5FA), Color(0xFF8B5CF6)],
),
borderRadius: BorderRadius.circular(16),
),
child: const Icon(
Icons.bluetooth_audio_rounded,
color: Color(0xFF2563EB),
size: 23,
color: Colors.white,
size: 27,
),
),
const SizedBox(width: 12),
const SizedBox(width: 14),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -418,17 +423,17 @@ class _DevicesHeader extends StatelessWidget {
const Text(
'已绑定设备',
style: TextStyle(
fontSize: 16,
fontSize: 19,
fontWeight: FontWeight.w900,
color: AppColors.textPrimary,
),
),
const SizedBox(height: 3),
const SizedBox(height: 4),
Text(
'$deviceCount 台设备',
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.w700,
fontSize: 13,
fontWeight: FontWeight.w800,
color: AppColors.textSecondary,
),
),
@@ -466,24 +471,24 @@ class _DeviceSection extends StatelessWidget {
child: Row(
children: [
Container(
width: 30,
height: 30,
width: 34,
height: 34,
decoration: BoxDecoration(
color: const Color(0xFFF8FAFC),
borderRadius: BorderRadius.circular(8),
color: const Color(0xFFEFF6FF),
borderRadius: BorderRadius.circular(11),
border: Border.all(color: AppColors.borderLight),
),
child: Icon(
type.icon,
size: 17,
size: 19,
color: const Color(0xFF2563EB),
),
),
const SizedBox(width: 9),
const SizedBox(width: 10),
Text(
type.label,
style: const TextStyle(
fontSize: 15,
fontSize: 16,
fontWeight: FontWeight.w900,
color: AppColors.textPrimary,
),
@@ -530,10 +535,10 @@ class _BoundDeviceTile extends StatelessWidget {
final accent = connected ? AppColors.success : AppColors.textHint;
return AnimatedContainer(
duration: const Duration(milliseconds: 180),
padding: const EdgeInsets.fromLTRB(14, 12, 8, 12),
padding: const EdgeInsets.fromLTRB(16, 15, 10, 15),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
borderRadius: BorderRadius.circular(18),
border: Border.all(
color: connected ? AppColors.success : AppColors.border,
width: connected ? 1.4 : 1.1,
@@ -552,17 +557,18 @@ class _BoundDeviceTile extends StatelessWidget {
children: [
AnimatedContainer(
duration: const Duration(milliseconds: 180),
width: 42,
height: 42,
width: 50,
height: 50,
decoration: BoxDecoration(
color: connected
? AppColors.successLight
: const Color(0xFFF8FAFC),
borderRadius: BorderRadius.circular(8),
borderRadius: BorderRadius.circular(16),
border: Border.all(color: AppColors.borderLight),
),
child: Icon(device.type.icon, color: accent, size: 22),
child: Icon(device.type.icon, color: accent, size: 25),
),
const SizedBox(width: 13),
const SizedBox(width: 14),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -572,16 +578,16 @@ class _BoundDeviceTile extends StatelessWidget {
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
fontSize: 15,
fontSize: 18,
fontWeight: FontWeight.w800,
color: AppColors.textPrimary,
),
),
const SizedBox(height: 3),
const SizedBox(height: 4),
Text(
'最近同步:${_formatLastSync(device.lastSyncAt)}',
style: const TextStyle(
fontSize: 12,
fontSize: 13,
fontWeight: FontWeight.w700,
color: AppColors.textHint,
),
@@ -592,7 +598,7 @@ class _BoundDeviceTile extends StatelessWidget {
if (connected)
Container(
margin: const EdgeInsets.only(right: 4),
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 5),
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
decoration: BoxDecoration(
color: AppColors.successLight,
borderRadius: BorderRadius.circular(999),
@@ -600,7 +606,8 @@ class _BoundDeviceTile extends StatelessWidget {
child: const Text(
'已连接',
style: TextStyle(
fontSize: 11,
fontSize: 12,
height: 1,
fontWeight: FontWeight.w900,
color: AppColors.success,
),
@@ -638,32 +645,33 @@ class _EmptyDevices extends StatelessWidget {
Widget build(BuildContext context) {
return Container(
width: double.infinity,
padding: const EdgeInsets.fromLTRB(24, 42, 24, 42),
padding: const EdgeInsets.fromLTRB(24, 46, 24, 46),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: AppColors.borderLight),
borderRadius: BorderRadius.circular(22),
border: Border.all(color: AppColors.borderLight, width: 1.1),
boxShadow: [AppTheme.shadowLight],
),
child: Column(
children: [
Container(
width: 62,
height: 62,
width: 72,
height: 72,
decoration: BoxDecoration(
color: const Color(0xFFEFF6FF),
borderRadius: BorderRadius.circular(8),
borderRadius: BorderRadius.circular(22),
),
child: const Icon(
Icons.bluetooth_disabled_rounded,
color: Color(0xFF2563EB),
size: 31,
size: 36,
),
),
const SizedBox(height: 16),
const SizedBox(height: 18),
const Text(
'还没有绑定设备',
style: TextStyle(
fontSize: 18,
fontSize: 19,
fontWeight: FontWeight.w900,
color: AppColors.textPrimary,
),
@@ -673,7 +681,7 @@ class _EmptyDevices extends StatelessWidget {
'右上角添加设备',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 13,
fontSize: 14,
fontWeight: FontWeight.w700,
color: AppColors.textSecondary,
),