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份实施文档(情况/问诊/报告/建档/日历/视觉统一)
This commit is contained in:
MingNian
2026-06-03 23:17:37 +08:00
parent 5bd0155e17
commit c2399b952f
33 changed files with 3311 additions and 660 deletions

View File

@@ -0,0 +1,292 @@
# 视觉统一 — 实施文档
> 对照《页面设计文档》规范,逐项统一圆角、阴影、留白、颜色。
## 一、设计 Token 集中化
`AppTheme` 中新增静态 Token所有组件从 Token 取值,不再硬编码:
```dart
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 统一调整
```dart
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
```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
```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 相关页面
```dart
// medication_list_page.dart / medication_edit_page.dart
// 列表项卡片: was 12-16 → AppTheme.radiusMd (16)
// 按钮: was 14 → AppTheme.radiusLg (20)
```
### 3.4 remaining_pages.dart
```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
```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 等页面
```dart
// 搜索替换BorderRadius.circular(12) → AppTheme.radiusSm
// 搜索替换BorderRadius.circular(16) → AppTheme.radiusMd
// 卡片外框:→ AppTheme.radiusXl
// 按钮:→ AppTheme.radiusLg
```
## 四、阴影统一
全局替换:
```dart
// 旧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 组件