feat: 问诊对话+建档引导+报告+日历+趋势页重写+视觉统一
- 问诊对话页: 新建consultation_provider, 完整AI分身聊天UI - 首次建档引导: OnboardingPrompt+ManageArchiveTool+前端卡片 - 报告模块: POST端点 + report_agent_handler接VLM - 健康日历: GET /api/calendar端点 + 前端接API - 趋势页重写: 删除Mock数据 + 真实API + 手动录入 - 饮食保存: submit按钮接后端API - 侧边栏: 健康概览横排 + 统一紫色配色 - 运动计划: 修复JSON反序列化(record→手动解析) - VLM: prompt优化 + 模型切qwen3-vl-plus + 1280px压缩 - UI颜色: 加深主色 8B9CF7→6C5CE7 - 个人信息页精简 + 健康档案可编辑重设计 - 保洁: 删除无用agent_bar + 删除意见反馈/关于我们 - 新增AI提示词文档
This commit is contained in:
@@ -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, taskCard }
|
||||
enum MessageType { text, dataConfirm, medicationConfirm, dietAnalysis, reportAnalysis, quickOptions, agentWelcome, taskCard, onboarding }
|
||||
|
||||
class ChatMessage {
|
||||
final String id;
|
||||
@@ -25,7 +25,7 @@ class ChatMessage {
|
||||
bool get isUser => role == 'user';
|
||||
}
|
||||
|
||||
enum ActiveAgent { default_, consultation, health, diet, medication, report, exercise }
|
||||
enum ActiveAgent { default_, consultation, health, diet, medication, report, exercise, onboarding }
|
||||
|
||||
class ChatState {
|
||||
final ActiveAgent activeAgent;
|
||||
@@ -116,11 +116,51 @@ class ChatNotifier extends Notifier<ChatState> {
|
||||
|
||||
@override
|
||||
ChatState build() {
|
||||
// 首次加载时插入今日任务卡片作为第一条消息
|
||||
Future.microtask(() => insertTaskCard());
|
||||
Future.microtask(() {
|
||||
insertTaskCard();
|
||||
_checkOnboarding();
|
||||
});
|
||||
return const ChatState();
|
||||
}
|
||||
|
||||
void _checkOnboarding() async {
|
||||
try {
|
||||
final api = ref.read(apiClientProvider);
|
||||
final res = await api.get('/api/user/health-archive');
|
||||
final archive = res.data['data'];
|
||||
// 档案全空 → 触发建档引导
|
||||
final isEmpty = archive == null ||
|
||||
(archive['diagnosis'] == null && archive['surgeryType'] == null &&
|
||||
(archive['allergies'] == null || (archive['allergies'] as List).isEmpty) &&
|
||||
(archive['chronicDiseases'] == null || (archive['chronicDiseases'] as List).isEmpty) &&
|
||||
(archive['dietRestrictions'] == null || (archive['dietRestrictions'] as List).isEmpty));
|
||||
if (isEmpty && !state.messages.any((m) => m.type == MessageType.onboarding)) {
|
||||
final db = ref.read(localDbProvider);
|
||||
final skipped = await db.read('onboarding_skipped');
|
||||
if (skipped == null) {
|
||||
state = state.copyWith(messages: [
|
||||
...state.messages,
|
||||
ChatMessage(id: 'onboarding_card', role: 'assistant', content: '', createdAt: DateTime.now(), type: MessageType.onboarding),
|
||||
]);
|
||||
}
|
||||
}
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
void startOnboarding() {
|
||||
setAgent(ActiveAgent.onboarding);
|
||||
// Remove onboarding card
|
||||
state = state.copyWith(messages: state.messages.where((m) => m.type != MessageType.onboarding).toList());
|
||||
// Send trigger message
|
||||
Future.microtask(() => _sendToAI('开始建档'));
|
||||
}
|
||||
|
||||
void dismissOnboarding() async {
|
||||
final db = ref.read(localDbProvider);
|
||||
await db.write('onboarding_skipped', DateTime.now().toIso8601String());
|
||||
state = state.copyWith(messages: state.messages.where((m) => m.type != MessageType.onboarding).toList());
|
||||
}
|
||||
|
||||
void insertTaskCard() {
|
||||
if (state.messages.any((m) => m.type == MessageType.taskCard)) return;
|
||||
state = state.copyWith(messages: [ChatMessage(
|
||||
|
||||
Reference in New Issue
Block a user