feat: 医生端完整实现 + 双角色登录 + 健康日历 + 饮食记录重做 + 配色系统重构
后端: - User表加Role字段 + DoctorProfile表 + 废弃旧Doctor数据 - JWT加Role claim + 注册/登录拆分(/api/auth/register + /api/auth/login) - 医生端点全量加JWT鉴权+Role校验(15个端点) - 日历端点改造(用药/运动/随访按日期+星期匹配) - 饮食记录PUT端点 + 健康记录DELETE端点 - 用户Profile端点返回Role 前端: - 登录页重做(角色选择卡片 用户紫/医生蓝 + 审核码6666 + 注册返登录) - App路由分流(userRole→患者端/医生端) - 医生端: 工作台Dashboard + 患者管理(搜索分页) + 问诊/报告/随访CRUD - 报告审核: AI预分析+指标表格+严重程度4级+模板多选+评语 - 随访编辑: 患者选择器+日期时间+打通患者端 - 健康日历: 可点击日历+当日安排列表+用药/运动/随访颜色标记 - 饮食记录: 热量趋势7/30天+日历(一周)+当日胶囊详情+侧滑编辑删除 - 健康档案: 日期选择器+手术可添加多条+白底渐变保存按钮 - 配色系统: 清理25个未使用色+新增doctorBlue/drawerGradient/pageGrey - 患者端侧边栏: 新渐变+白底按钮+紫色汉堡图标 - AI对话: 用户气泡白底黑字+药管家改蓝色 - App启动闪屏: 防登录页闪烁 文档: color_design_system.md(20页面完整配色设计+图标底色对照表)
This commit is contained in:
@@ -1,70 +1,55 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// 健康管家 — 蚂蚁阿福风格 v2.0
|
||||
/// 柔和淡紫 + 大量留白 + 紫色仅作点缀
|
||||
/// 健康管家 — 色彩体系 v3.0
|
||||
class AppColors {
|
||||
AppColors._();
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// 主色 — 柔和淡紫(非浓烈深紫)
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// ── 主色 ──
|
||||
static const Color primary = Color(0xFF8B5CF6);
|
||||
static const Color primaryLight = Color(0xFFA78BFA);
|
||||
static const Color primaryDark = Color(0xFF7C3AED);
|
||||
|
||||
static const Color primary = Color(0xFF8B5CF6); // 主紫(柔和不刺眼)
|
||||
static const Color primaryLight = Color(0xFFA78BFA); // 浅紫(装饰/渐变)
|
||||
static const Color primaryDark = Color(0xFF7C3AED); // 深紫(按压态)
|
||||
static const Color primaryMid = Color(0xFFA78BFA); // 兼容旧名
|
||||
|
||||
// 渐变 — 柔和淡紫,仅垂直
|
||||
static const LinearGradient primaryGradient = LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
begin: Alignment.topCenter, end: Alignment.bottomCenter,
|
||||
colors: [Color(0xFF8B5CF6), Color(0xFFA78BFA)],
|
||||
);
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// 背景色
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// ── 医生端主色 ──
|
||||
static const Color doctorBlue = Color(0xFF6366F1);
|
||||
static const LinearGradient doctorGradient = LinearGradient(begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [
|
||||
Color(0xFF38BDF8), Color(0xFF6366F1), Color(0xFF60A5FA), Color(0xFF818CF8)
|
||||
]);
|
||||
|
||||
static const Color background = Color(0xFFF0ECFF); // 页面全局背景(淡紫)
|
||||
static const Color backgroundSoft = Color(0xFFF0ECFF); // 输入框底色(淡紫,同页面背景)
|
||||
static const Color cardBackground = Color(0xFFFFFFFF); // 卡片白色
|
||||
static const Color cardInner = Color(0xFFF5F2FF); // 卡片内区域底色
|
||||
// ── 背景 ──
|
||||
static const Color background = Color(0xFFF0ECFF);
|
||||
static const Color cardBackground = Color(0xFFFFFFFF);
|
||||
static const Color cardInner = Color(0xFFF5F2FF);
|
||||
static const Color pageGrey = Color(0xFFF5F5F5); // 医生端/设置页灰底
|
||||
static const Color iconBg = Color(0xFFE8E0FA);
|
||||
|
||||
// 主背景渐变(紫→蓝,4:6比例)
|
||||
static const LinearGradient bgGradient = LinearGradient(
|
||||
begin: Alignment.centerLeft,
|
||||
end: Alignment.centerRight,
|
||||
begin: Alignment.centerLeft, end: Alignment.centerRight,
|
||||
colors: [Color(0xFFF0ECFF), Color(0xFFEBF4FF)],
|
||||
stops: [0.0, 0.4],
|
||||
);
|
||||
|
||||
// 导航栏背景(极淡蓝紫)
|
||||
static const LinearGradient navGradient = LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [Color(0xFFE0E7FF), Color(0xFFC7D2FE)],
|
||||
// 抽屉专用渐变(原色降低饱和度)
|
||||
static const LinearGradient drawerGradient = LinearGradient(
|
||||
begin: Alignment.topLeft, end: Alignment.bottomRight,
|
||||
colors: [Color(0xFFD4B5F0), Color(0xFFF3E8FF), Color(0xFFA8A0E8)],
|
||||
stops: [0.0, 0.5, 1.0],
|
||||
);
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// 文字颜色
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
// ── 文字 ──
|
||||
static const Color textPrimary = Color(0xFF1F2937);
|
||||
static const Color textSecondary = Color(0xFF6B7280);
|
||||
static const Color textHint = Color(0xFF9CA3AF);
|
||||
static const Color textOnGradient = Color(0xFFFFFFFF);
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// 边框/分割线
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
// ── 边框 ──
|
||||
static const Color border = Color(0xFFE5E7EB);
|
||||
static const Color borderLight = Color(0xFFF3F4F6);
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// 功能色
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
// ── 功能色 ──
|
||||
static const Color success = Color(0xFF10B981);
|
||||
static const Color successLight = Color(0xFFD1FAE5);
|
||||
static const Color error = Color(0xFFEF4444);
|
||||
@@ -72,51 +57,9 @@ class AppColors {
|
||||
static const Color warning = Color(0xFFF59E0B);
|
||||
static const Color warningLight = Color(0xFFFEF3C7);
|
||||
static const Color blueMeasure = Color(0xFF3B82F6);
|
||||
static const Color avatarBg = Color(0xFFF0F0FF); // 头像底
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// 图标 / 小区域底色(极淡紫蓝)
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
static const Color iconBg = Color(0xFFE8E0FA); // 卡片内底色,比页面背景稍深
|
||||
|
||||
// 兼容旧名字
|
||||
static const Color iconBlueStart = Color(0xFF8B5CF6);
|
||||
static const Color iconBlueEnd = Color(0xFFA78BFA);
|
||||
static const Color iconCyanStart = Color(0xFF10B981);
|
||||
static const Color iconCyanEnd = Color(0xFF34D399);
|
||||
static const Color iconPurpleStart = Color(0xFF8B5CF6);
|
||||
static const Color iconPurpleEnd = Color(0xFFA78BFA);
|
||||
static const Color accentCyan = Color(0xFF10B981);
|
||||
static const Color accentCyanDark = Color(0xFF059669);
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// 渐变 — 所有旧名字统一为柔和淡紫
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
static LinearGradient get borderGradient => primaryGradient;
|
||||
static LinearGradient get cyanGradient => primaryGradient;
|
||||
static LinearGradient get purpleGradient => primaryGradient;
|
||||
static LinearGradient get pageBgGradient => bgGradient;
|
||||
static LinearGradient get cardLightGradient => bgGradient;
|
||||
static LinearGradient get gWelcomeHeader => primaryGradient;
|
||||
|
||||
// 各种旧花渐变全改为极淡色或纯色
|
||||
static LinearGradient get gPurplePink => primaryGradient;
|
||||
static LinearGradient get gBluePurple => primaryGradient;
|
||||
static LinearGradient get gPinkPurple => primaryGradient;
|
||||
static LinearGradient get gBlueRed => primaryGradient;
|
||||
static LinearGradient get gBlueGreen => primaryGradient;
|
||||
static LinearGradient get gPurpleCyan => primaryGradient;
|
||||
static LinearGradient get gRedPurple => primaryGradient;
|
||||
static LinearGradient get gCyanBlue => primaryGradient;
|
||||
static LinearGradient get gPinkCyan => primaryGradient;
|
||||
static LinearGradient get gLightPurple => bgGradient;
|
||||
static LinearGradient get gLightBlue => bgGradient;
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// 阴影 — 轻柔
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
// ── 阴影 ──
|
||||
static List<BoxShadow> get cardShadow => [
|
||||
BoxShadow(color: Colors.black.withOpacity(0.06), blurRadius: 8, offset: const Offset(0, 2)),
|
||||
];
|
||||
@@ -130,18 +73,14 @@ class AppColors {
|
||||
BoxShadow(color: Color(0xFF8B5CF6).withOpacity(0.30), blurRadius: 16, offset: const Offset(0, 6)),
|
||||
];
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// 旧代码兼容别名(chat_messages_view 原始代码引用)
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
static const Color purpleGradientStart = Color(0xFF8B5CF6);
|
||||
static const Color blueGradientEnd = Color(0xFF3B82F6);
|
||||
// ── 兼容别名 ──
|
||||
static Color get iconColor => Color(0xFF9B8AF7);
|
||||
static LinearGradient get purpleBlueGradient => primaryGradient;
|
||||
static const Color backgroundSoft = background;
|
||||
static const Color textOnGradient = Color(0xFFFFFFFF);
|
||||
static Color get primaryPurple => primary;
|
||||
static Color get iconColor => Color(0xFF9B8AF7); // 淡紫图标色
|
||||
static Color get iconBackground => iconBg;
|
||||
static Color get primaryBlue => blueMeasure;
|
||||
static LinearGradient get lightGradient => gLightPurple;
|
||||
static Color get backgroundSecondary => background;
|
||||
static LinearGradient get successButtonGradient => primaryGradient;
|
||||
static LinearGradient get lightGradient => bgGradient;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'navigation_provider.dart';
|
||||
import '../pages/auth/login_page.dart';
|
||||
import '../pages/home/home_page.dart';
|
||||
@@ -17,60 +18,55 @@ import '../pages/diet/diet_capture_page.dart';
|
||||
import '../pages/device/device_scan_page.dart';
|
||||
import '../pages/device/device_management_page.dart';
|
||||
import '../pages/remaining_pages.dart';
|
||||
import '../pages/doctor/doctor_home_page.dart';
|
||||
import '../pages/doctor/doctor_patient_detail_page.dart';
|
||||
import '../pages/doctor/doctor_report_detail_page.dart';
|
||||
import '../pages/doctor/doctor_followup_edit_page.dart';
|
||||
import '../pages/doctor/doctor_settings_page.dart';
|
||||
import '../pages/doctor/doctor_profile_page.dart';
|
||||
import '../providers/auth_provider.dart' show userRoleProvider;
|
||||
|
||||
/// 根据路由信息返回对应页面
|
||||
Widget buildPage(RouteInfo route) {
|
||||
Widget buildPage(RouteInfo route, WidgetRef ref) {
|
||||
final params = route.params;
|
||||
switch (route.name) {
|
||||
case 'login':
|
||||
return const LoginPage();
|
||||
case 'login': return const LoginPage();
|
||||
case 'home':
|
||||
return const HomePage();
|
||||
case 'trend':
|
||||
return TrendPage(metricType: params['type']?.isNotEmpty == true ? params['type'] : null);
|
||||
case 'calendar':
|
||||
return const HealthCalendarPage();
|
||||
case 'medications':
|
||||
return const MedicationListPage();
|
||||
case 'medCheckIn':
|
||||
return MedicationCheckInPage(medId: params['id']);
|
||||
case 'medicationEdit':
|
||||
return const MedicationEditPage();
|
||||
case 'reports':
|
||||
return const ReportListPage();
|
||||
case 'aiAnalysis':
|
||||
return AiAnalysisPage(id: params['id']!);
|
||||
case 'consultation':
|
||||
return DoctorChatPage(id: params['id']!);
|
||||
case 'exercisePlan':
|
||||
return const ExercisePlanPage();
|
||||
case 'exerciseCreate':
|
||||
return const ExercisePlanCreatePage();
|
||||
case 'dietRecords':
|
||||
return const DietRecordListPage();
|
||||
case 'dietCapture':
|
||||
return const DietCapturePage();
|
||||
case 'profile':
|
||||
return const ProfilePage();
|
||||
case 'devices':
|
||||
return const DeviceManagementPage();
|
||||
case 'deviceScan':
|
||||
return const DeviceScanPage();
|
||||
case 'healthArchive':
|
||||
return const HealthArchivePage();
|
||||
case 'followups':
|
||||
return const FollowUpListPage();
|
||||
case 'settings':
|
||||
return const SettingsPage();
|
||||
case 'notificationPrefs':
|
||||
return const NotificationPrefsPage();
|
||||
case 'staticText':
|
||||
return StaticTextPage(type: params['type']!);
|
||||
case 'servicePackageDetail':
|
||||
return ServicePackageDetailPage(packageId: params['id']!);
|
||||
case 'dietDetail':
|
||||
return DietRecordDetailPage(id: params['id']!);
|
||||
default:
|
||||
return const LoginPage();
|
||||
final role = ref.watch(userRoleProvider);
|
||||
return role == 'Doctor' ? const DoctorHomePage() : const HomePage();
|
||||
case 'doctorHome': return const DoctorHomePage();
|
||||
case 'trend': return TrendPage(metricType: params['type']?.isNotEmpty == true ? params['type'] : null);
|
||||
case 'calendar': return const HealthCalendarPage();
|
||||
case 'medications': return const MedicationListPage();
|
||||
case 'medCheckIn': return MedicationCheckInPage(medId: params['id']);
|
||||
case 'medicationEdit': return const MedicationEditPage();
|
||||
case 'reports': return const ReportListPage();
|
||||
case 'aiAnalysis': return AiAnalysisPage(id: params['id']!);
|
||||
case 'consultation': return DoctorChatPage(id: params['id']!);
|
||||
case 'exercisePlan': return const ExercisePlanPage();
|
||||
case 'exerciseCreate': return const ExercisePlanCreatePage();
|
||||
case 'dietRecords': return const DietRecordListPage();
|
||||
case 'dietCapture': return const DietCapturePage();
|
||||
case 'profile': return const ProfilePage();
|
||||
case 'doctorProfile': return const DoctorProfileEditPage();
|
||||
case 'doctorSettings': return const DoctorSettingsPage();
|
||||
case 'doctorPatientDetail': return DoctorPatientDetailPage(id: params['id']!);
|
||||
case 'doctorChat': return DoctorChatPage(id: params['id']!);
|
||||
case 'doctorReportDetail': return DoctorReportDetailPage(id: params['id']!);
|
||||
case 'doctorFollowUpEdit': return DoctorFollowUpEditPage(id: params['id']!);
|
||||
case 'devices': return const DeviceManagementPage();
|
||||
case 'deviceScan': return const DeviceScanPage();
|
||||
case 'healthArchive': return const HealthArchivePage();
|
||||
case 'followups': return const FollowUpListPage();
|
||||
case 'settings': return const SettingsPage();
|
||||
case 'notificationPrefs': return const NotificationPrefsPage();
|
||||
case 'staticText': return StaticTextPage(type: params['type']!);
|
||||
case 'servicePackageDetail': return ServicePackageDetailPage(packageId: params['id']!);
|
||||
case 'dietDetail': return DietRecordDetailPage(id: params['id']!);
|
||||
default: return const LoginPage();
|
||||
}
|
||||
}
|
||||
|
||||
// ── 医生端次级页面 Stubs(逐步实现)──
|
||||
|
||||
|
||||
|
||||
@@ -34,13 +34,13 @@ class AppTheme {
|
||||
static const Color primary = AppColors.primary;
|
||||
static const Color primaryLight = AppColors.primaryLight;
|
||||
static const Color primaryDark = AppColors.primaryDark;
|
||||
static const Color primaryMid = AppColors.primaryMid;
|
||||
static const Color primaryMid = AppColors.primaryLight;
|
||||
static const Color accent = AppColors.success;
|
||||
static const Color info = AppColors.blueMeasure;
|
||||
|
||||
// ── 中性色 ──
|
||||
static const Color bg = AppColors.background;
|
||||
static const Color bgSoft = AppColors.backgroundSoft;
|
||||
static const Color bgSoft = AppColors.background;
|
||||
static const Color surface = AppColors.cardBackground;
|
||||
static const Color surfaceInner = AppColors.cardInner;
|
||||
static const Color text = AppColors.textPrimary;
|
||||
|
||||
Reference in New Issue
Block a user