Files
AI-Health/健康管家-视觉统一实施文档.md
MingNian c2399b952f refactor: 4层架构重构 + 饮食VLM接入 + 多项修复
- 后端: remaining_endpoints拆分为6个独立文件
- 后端: AI Agent Handler从ai_chat_endpoints抽取为7个独立处理器
- 后端: 食物识别prompt改为输出结构化JSON
- 前端: 饮食识别从Mock替换为真实VLM API调用
- 前端: 首页图片上传URL修复(/api/upload→/api/files/upload)
- 前端: 拍饮食按钮导航到独立DietCapturePage
- 前端: 删除无用agent_bar.dart
- 前端: 修复widget_test.dart过期属性名
- 前端: 恢复ServicePackageCard和详情页
- 新增6份实施文档(情况/问诊/报告/建档/日历/视觉统一)
2026-06-03 23:17:37 +08:00

9.4 KiB
Raw Blame History

视觉统一 — 实施文档

对照《页面设计文档》规范,逐项统一圆角、阴影、留白、颜色。

一、设计 Token 集中化

AppTheme 中新增静态 Token所有组件从 Token 取值,不再硬编码:

class AppTheme {
  // ── 已有(不动)──
  static const Color primary = Color(0xFF8B9CF7);
  static const Color primaryLight = Color(0xFFF0F2FF);
  static const Color bg = Color(0xFFF8F9FC);
  static const Color surface = Color(0xFFFFFFFF);
  static const Color text = Color(0xFF2D2B32);
  static const Color textSub = Color(0xFF8A8892);
  static const Color textHint = Color(0xFFBFBCC4);
  static const Color success = Color(0xFF6ECF8A);
  static const Color error = Color(0xFFF56C6C);
  static const Color warning = Color(0xFFF5A623);

  // ── 新增:圆角 Token ──
  static const double radiusXs = 8;      // 标签、小徽章
  static const double radiusSm = 12;     // 输入框、小按钮
  static const double radiusMd = 16;     // 列表项、菜单、弹窗内卡片
  static const double radiusLg = 20;     // 按钮
  static const double radiusXl = 24;     // 主卡片
  static const double radiusPill = 999;  // 胶囊

  // ── 新增:间距 Token ──
  static const double spaceXs = 4;
  static const double spaceSm = 8;
  static const double spaceMd = 12;
  static const double spaceLg = 16;
  static const double spaceXl = 20;
  static const double space2xl = 24;

  // ── 新增:阴影 Token ──
  static BoxShadow shadowCard = BoxShadow(
    color: primary.withAlpha(15),
    blurRadius: 12,
    offset: const Offset(0, 4),
  );
  static BoxShadow shadowBubble = BoxShadow(
    color: primary.withAlpha(12),
    blurRadius: 10,
    offset: const Offset(0, 3),
  );
  static BoxShadow shadowNone = const BoxShadow(
    color: Colors.transparent,
    blurRadius: 0,
    offset: Offset.zero,
  );
}

二、ThemeData 统一调整

static ThemeData get lightTheme => ThemeData(
    useMaterial3: true,
    colorScheme: ColorScheme.fromSeed(
        seedColor: primary, primary: primary, surface: bg,
        brightness: Brightness.light),
    scaffoldBackgroundColor: bg,

    // ── AppBar ── 不变
    appBarTheme: const AppBarTheme(
        backgroundColor: surface, foregroundColor: text,
        elevation: 0, centerTitle: true, scrolledUnderElevation: 0,
        titleTextStyle: TextStyle(
            fontSize: 17, fontWeight: FontWeight.w600, color: text),
    ),

    // ── Card: radius 16 → 24 ──
    cardTheme: CardThemeData(
        color: surface, elevation: 0,
        shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(radiusXl)),  // 24
        margin: EdgeInsets.zero,
    ),

    // ── Input: radius 12 → 16, 内边距增加 ──
    inputDecorationTheme: InputDecorationTheme(
        filled: true, fillColor: const Color(0xFFF4F5FA),
        contentPadding: const EdgeInsets.symmetric(
            horizontal: 16, vertical: 14),  // 更宽松
        border: OutlineInputBorder(
            borderRadius: BorderRadius.circular(radiusMd),  // 16
            borderSide: BorderSide.none),
        enabledBorder: OutlineInputBorder(
            borderRadius: BorderRadius.circular(radiusMd),
            borderSide: BorderSide.none),
        focusedBorder: OutlineInputBorder(
            borderRadius: BorderRadius.circular(radiusMd),
            borderSide: const BorderSide(color: primary, width: 1.5)),
        hintStyle: const TextStyle(color: textHint, fontSize: 15),
    ),

    // ── Button: radius 14 → 20, 高度 48 → 52 ──
    elevatedButtonTheme: ElevatedButtonThemeData(
        style: ElevatedButton.styleFrom(
            backgroundColor: primary, foregroundColor: Colors.white,
            minimumSize: const Size(double.infinity, 52),   // 更高
            shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.circular(radiusLg)),  // 20
            textStyle: const TextStyle(
                fontSize: 16, fontWeight: FontWeight.w600),
            elevation: 0,
        ),
    ),

    // ── Dialog: radius 保持 22略增 ──
    dialogTheme: DialogThemeData(
        shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(radiusXl)),  // 24
    ),

    // BottomSheet 主题
    bottomSheetTheme: const BottomSheetThemeData(
        shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.vertical(
                top: Radius.circular(radiusXl))),  // 24
    ),

    // 文字主题(不动)
    textTheme: const TextTheme(...),
);

三、逐文件硬编码替换

3.1 health_drawer.dart

// 找BorderRadius.circular(16)
// 替换BorderRadius.circular(AppTheme.radiusXl)  → 24

// _SectionCard
decoration: BoxDecoration(
  borderRadius: BorderRadius.circular(AppTheme.radiusXl),   // was 16
  boxShadow: [AppTheme.shadowCard],                         // 统一
)

// _MetricTile
decoration: BoxDecoration(
  borderRadius: BorderRadius.circular(AppTheme.radiusMd),   // was 10
)

// _FeatureChip
decoration: BoxDecoration(
  borderRadius: BorderRadius.circular(AppTheme.radiusMd),   // was 12
)

// _ConversationItem
decoration: BoxDecoration(
  borderRadius: BorderRadius.circular(AppTheme.radiusSm),   // was 10
)

3.2 chat_messages_view.dart

// AI 气泡 — 不动radius 20 符合规范)
// 用户气泡 — 不动
// 按钮卡片 — 统一

// _cardFilledBtn
shape: RoundedRectangleBorder(
  borderRadius: BorderRadius.circular(AppTheme.radiusLg)),  // was 12

// _cardOutlineBtn
shape: RoundedRectangleBorder(
  borderRadius: BorderRadius.circular(AppTheme.radiusLg)),  // was 12

// DataConfirmCard 外层
borderRadius: BorderRadius.circular(AppTheme.radiusXl),     // was 20

// 内部小卡片
borderRadius: BorderRadius.circular(AppTheme.radiusMd),     // was 10-14

// 快捷选项按钮
borderRadius: BorderRadius.circular(AppTheme.radiusPill),   // was 20

3.3 medication 相关页面

// medication_list_page.dart / medication_edit_page.dart
// 列表项卡片: was 12-16 → AppTheme.radiusMd (16)
// 按钮: was 14 → AppTheme.radiusLg (20)

3.4 remaining_pages.dart

// HealthCalendarPage 日期格子
borderRadius: BorderRadius.circular(AppTheme.radiusXs),     // was 20错误值

// ExercisePlanPage 进度卡片
borderRadius: BorderRadius.circular(AppTheme.radiusXl),     // was 20

// ExercisePlanItem 日条目
borderRadius: BorderRadius.circular(AppTheme.radiusMd),     // was 16

// FollowUpItem 随访卡片
borderRadius: BorderRadius.circular(AppTheme.radiusXl),     // was 16

3.5 diet_capture_page.dart

// 拍照大圆
borderRadius: BorderRadius.circular(90),                    // 不动

// 食物列表容器
borderRadius: BorderRadius.circular(AppTheme.radiusXl),     // was 20

// 食物条目
borderRadius: BorderRadius.circular(AppTheme.radiusMd),     // was 16

// 按钮
borderRadius: BorderRadius.circular(AppTheme.radiusPill),   // was 24

3.6 report/consultation 等页面

// 搜索替换BorderRadius.circular(12) → AppTheme.radiusSm
// 搜索替换BorderRadius.circular(16) → AppTheme.radiusMd
// 卡片外框:→ AppTheme.radiusXl
// 按钮:→ AppTheme.radiusLg

四、阴影统一

全局替换:

// 旧boxShadow: [BoxShadow(color: Color(0xFF8B9CF7).withAlpha(15), blurRadius: 14, offset: Offset(0, 4))]
// 新boxShadow: [AppTheme.shadowCard]

// 旧boxShadow: [BoxShadow(color: Color(0xFF8B9CF7).withAlpha(12), blurRadius: 10, offset: Offset(0, 3))]
// 新boxShadow: [AppTheme.shadowBubble]

五、替换策略

原值 Token 用于
8 radiusXs 标签、小圆点、Chip
10-12 radiusSm 输入框、列表项、小图标容器
14-16 radiusMd 弹窗内部卡片、指标方块、食物条目
18-20 radiusLg 按钮
24+ radiusXl 主卡片、抽屉分区、对话框
999 radiusPill 胶囊按钮、快捷选项

六、验证方式

改完后跑 flutter analyze 确认无错误,然后运行 App 目测以下页面:

  1. 侧滑抽屉 — 卡片圆角、阴影
  2. 首页对话 — 气泡、按钮、任务卡片
  3. 拍饮食 — 识别结果卡片、按钮
  4. 登录页 — 输入框、按钮
  5. 运动计划 — 日条目、进度卡片

七、文件改动清单

修改:
  lib/core/app_theme.dart                       (+ 圆角/间距/阴影 Token, ThemeData 调整, ~50行)
  lib/widgets/health_drawer.dart                 (~15处硬编码替换)
  lib/pages/home/widgets/chat_messages_view.dart (~20处硬编码替换)
  lib/pages/diet/diet_capture_page.dart          (~8处硬编码替换)
  lib/pages/auth/login_page.dart                 (~5处硬编码替换)
  lib/pages/remaining_pages.dart                 (~10处硬编码替换)
  lib/pages/medication/medication_list_page.dart (~5处硬编码替换)
  lib/pages/medication/medication_edit_page.dart  (~3处硬编码替换)
  lib/pages/report/report_pages.dart             (~5处硬编码替换)
  lib/pages/report/ai_analysis_page.dart         (~3处硬编码替换)
  lib/pages/settings/*.dart                      (~3处硬编码替换)
  lib/pages/profile/*.dart                       (~5处硬编码替换)

改动虽然文件多,但每个文件都是纯替换——把数字换成 AppTheme Token不涉及逻辑变更

八、不做的事情

  • 不改变颜色体系(淡薰紫主题保持)
  • 不改变字体/字号
  • 不改变布局结构
  • 不引入新的 UI 组件