## 后端安全加固 - 新增 UserUploadPathResolver: 用户上传文件路径安全解析, 防目录穿越 - LocalReportFileStorage: 文件存储路径安全加固 - local_account_file_cleanup: 账号删除时文件清理逻辑增强 - AuthService: 认证逻辑增强 - file_endpoints / report_endpoints: 文件访问接口安全加固 - ai_chat_endpoints / doctor_endpoints: 接口安全调整 - Program.cs: 服务注册调整 ## 前端认证与媒体 - 新增 authenticated_network_image.dart: 带认证的图片加载组件 - auth_provider: 认证状态管理大幅增强(+173) - api_client: 网络客户端增强(+124) - chat_provider: 聊天 provider 重构(+76) - omron_device_provider: 蓝牙设备 provider 增强(+53) - sse_handler: SSE 处理增强(+35) - consultation_provider / data_providers / conversation_history_provider: 调整 ## 页面调整 - remaining_pages: 健康档案/饮食记录等页面增强(+115) - home_page / chat_messages_view: 主页微调 - doctor 端多页微调(consultations/dashboard/followups/patient_detail/profile/report_detail/reports) - report_pages / settings_pages / notification_prefs_page: 微调 - device_scan_page / diet_capture_page / admin_home_page: 微调 ## 测试 - 新增 file_path_security_tests: 文件路径安全测试 - 新增 protected_media_url_test: 媒体URL保护测试 - 新增 user_session_identity_test: 用户会话身份测试 - account_deletion_tests / application_service_tests / auth_tests: 更新
161 lines
4.8 KiB
Dart
161 lines
4.8 KiB
Dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'auth_provider.dart';
|
|
import '../services/health_service.dart';
|
|
import '../services/admin_service.dart';
|
|
import '../services/in_app_notification_service.dart';
|
|
|
|
final exerciseServiceProvider = Provider<ExerciseService>((ref) {
|
|
return ExerciseService(ref.watch(apiClientProvider));
|
|
});
|
|
|
|
/// 健康数据服务
|
|
final healthServiceProvider = Provider<HealthService>((ref) {
|
|
return HealthService(ref.watch(apiClientProvider));
|
|
});
|
|
|
|
final userServiceProvider = Provider<UserService>((ref) {
|
|
return UserService(ref.watch(apiClientProvider));
|
|
});
|
|
|
|
final medicationServiceProvider = Provider<MedicationService>((ref) {
|
|
return MedicationService(ref.watch(apiClientProvider));
|
|
});
|
|
|
|
final dietServiceProvider = Provider<DietService>((ref) {
|
|
return DietService(ref.watch(apiClientProvider));
|
|
});
|
|
|
|
final followUpServiceProvider = Provider<FollowUpService>((ref) {
|
|
return FollowUpService(ref.watch(apiClientProvider));
|
|
});
|
|
|
|
final consultationServiceProvider = Provider<ConsultationService>((ref) {
|
|
return ConsultationService(ref.watch(apiClientProvider));
|
|
});
|
|
|
|
final adminServiceProvider = Provider<AdminService>((ref) {
|
|
return AdminService(ref.watch(apiClientProvider));
|
|
});
|
|
|
|
final inAppNotificationServiceProvider = Provider<InAppNotificationService>((
|
|
ref,
|
|
) {
|
|
return InAppNotificationService(ref.watch(apiClientProvider));
|
|
});
|
|
|
|
final notificationUnreadCountProvider = FutureProvider<int>((ref) async {
|
|
ref.watch(userSessionIdentityProvider);
|
|
final history = await ref
|
|
.watch(inAppNotificationServiceProvider)
|
|
.getHistory();
|
|
return history.unreadCount;
|
|
});
|
|
|
|
/// 最新健康数据 Provider
|
|
final latestHealthProvider = FutureProvider<Map<String, dynamic>>((ref) async {
|
|
ref.watch(userSessionIdentityProvider);
|
|
final service = ref.watch(healthServiceProvider);
|
|
return service.getLatest();
|
|
});
|
|
|
|
/// 用药列表 Provider
|
|
final medicationListProvider = FutureProvider<List<Map<String, dynamic>>>((
|
|
ref,
|
|
) async {
|
|
ref.watch(userSessionIdentityProvider);
|
|
final service = ref.watch(medicationServiceProvider);
|
|
return service.getList();
|
|
});
|
|
|
|
final exercisePlansProvider = FutureProvider<List<Map<String, dynamic>>>((
|
|
ref,
|
|
) async {
|
|
ref.watch(userSessionIdentityProvider);
|
|
return ref.watch(exerciseServiceProvider).getPlans();
|
|
});
|
|
|
|
final followUpListProvider = FutureProvider<List<Map<String, dynamic>>>((
|
|
ref,
|
|
) async {
|
|
ref.watch(userSessionIdentityProvider);
|
|
return ref.watch(followUpServiceProvider).getList();
|
|
});
|
|
|
|
final dietRecordsProvider = FutureProvider<List<Map<String, dynamic>>>((
|
|
ref,
|
|
) async {
|
|
ref.watch(userSessionIdentityProvider);
|
|
return ref.watch(dietServiceProvider).getRecords();
|
|
});
|
|
|
|
final medicationReminderProvider = FutureProvider<List<Map<String, dynamic>>>((
|
|
ref,
|
|
) async {
|
|
ref.watch(userSessionIdentityProvider);
|
|
final service = ref.watch(medicationServiceProvider);
|
|
return service.getReminders();
|
|
});
|
|
|
|
/// 医生列表 Provider
|
|
final doctorListProvider =
|
|
FutureProvider.autoDispose<List<Map<String, dynamic>>>((ref) async {
|
|
ref.watch(userSessionIdentityProvider);
|
|
final service = ref.watch(consultationServiceProvider);
|
|
return service.getDoctors().timeout(const Duration(seconds: 8));
|
|
});
|
|
|
|
/// 当前运动计划 Provider
|
|
final currentExercisePlanProvider = FutureProvider<Map<String, dynamic>?>((
|
|
ref,
|
|
) async {
|
|
ref.watch(userSessionIdentityProvider);
|
|
final service = ref.watch(exerciseServiceProvider);
|
|
return service.getCurrentPlan().timeout(const Duration(seconds: 8));
|
|
});
|
|
|
|
typedef TodayHealthSnapshot = ({
|
|
Map<String, dynamic> health,
|
|
List<Map<String, dynamic>> reminders,
|
|
Map<String, dynamic>? exercisePlan,
|
|
});
|
|
|
|
/// 首页今日健康一次性快照。依赖项即使先后返回,也只在全部完成后整体更新。
|
|
final todayHealthSnapshotProvider = FutureProvider<TodayHealthSnapshot>((
|
|
ref,
|
|
) async {
|
|
final values = await Future.wait<dynamic>([
|
|
ref.watch(latestHealthProvider.future),
|
|
ref.watch(medicationReminderProvider.future),
|
|
ref.watch(currentExercisePlanProvider.future),
|
|
]);
|
|
return (
|
|
health: values[0] as Map<String, dynamic>,
|
|
reminders: values[1] as List<Map<String, dynamic>>,
|
|
exercisePlan: values[2] as Map<String, dynamic>?,
|
|
);
|
|
});
|
|
|
|
/// 拍照/相册直接触发(无需跳转页面)
|
|
final cameraActionProvider = NotifierProvider<CameraActionNotifier, String?>(
|
|
CameraActionNotifier.new,
|
|
);
|
|
|
|
class CameraActionNotifier extends Notifier<String?> {
|
|
@override
|
|
String? build() => null;
|
|
void trigger(String action) => state = action;
|
|
void clear() => state = null;
|
|
}
|
|
|
|
/// 拍饮食动作触发(不用跳多余页面)
|
|
final dietActionProvider = NotifierProvider<DietActionNotifier, String?>(
|
|
DietActionNotifier.new,
|
|
);
|
|
|
|
class DietActionNotifier extends Notifier<String?> {
|
|
@override
|
|
String? build() => null;
|
|
void trigger(String action) => state = action;
|
|
void clear() => state = null;
|
|
}
|