feat: UI 系统中心化 + 趋势图重构 + 法律文档 H5 上线

- UI 系统: 新增 design_tokens / module_visuals / app_buttons / app_status_badge / app_toast / ai_content 六个共享模块; 28 个页面接入, SnackBar 全部替换为 AppToast
- 趋势图: 直线折线 + 渐变填充 + 阴影; 去网格线; X 轴日+月份分隔; Y 轴整数刻度最多 4 个; 点击数据点/录入记录显示上方浮层, 选中点变实心
- 法律文档 H5: 后端 wwwroot 托管隐私政策/服务协议/关于/个人信息收集清单/第三方 SDK 清单 + 索引页; Program.cs 启用 UseDefaultFiles + UseStaticFiles
- 其他: auth_provider 登录流程调整; api_client IP 适配; 主页智能体栏间距优化
This commit is contained in:
MingNian
2026-07-08 21:25:07 +08:00
parent 7a93237069
commit 1c020b8ae5
45 changed files with 3480 additions and 1000 deletions

View File

@@ -5,9 +5,11 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../core/navigation_provider.dart';
import '../../core/app_colors.dart';
import '../../core/app_module_visuals.dart';
import '../../core/app_theme.dart';
import '../../providers/auth_provider.dart';
import '../../utils/sse_handler.dart';
import '../../widgets/app_toast.dart';
final dietProvider = NotifierProvider<DietNotifier, DietState>(
DietNotifier.new,
@@ -303,14 +305,11 @@ class DietNotifier extends Notifier<DietState> {
}
// ─────────── 饮食主题色(暖橙系,不再用紫色)───────────
const _dietAccent = Color(0xFFF97316);
const _dietAccentLight = Color(0xFFFFF3E0);
const _dietVisual = AppModuleVisuals.diet;
const _dietAccent = AppColors.diet;
const _dietAccentLight = AppColors.dietLight;
const _dietKcalText = Color(0xFF9A3412);
const _dietGradient = LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [Color(0xFFF6D365), Color(0xFFFDA085)],
);
const _dietGradient = AppColors.dietGradient;
class DietCapturePage extends ConsumerStatefulWidget {
const DietCapturePage({super.key});
@@ -362,47 +361,47 @@ class _DietCapturePageState extends ConsumerState<DietCapturePage> {
return SingleChildScrollView(
padding: const EdgeInsets.fromLTRB(16, 12, 16, 24),
child: Column(
children: [
// 图片自适应显示
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(24),
border: Border.all(color: AppColors.borderLight),
boxShadow: AppColors.cardShadowLight,
),
child: ClipRRect(
borderRadius: BorderRadius.circular(18),
child: Image.file(
File(state.imagePath!),
width: screenW - 48,
height: 220,
fit: BoxFit.cover,
),
child: Column(
children: [
// 图片自适应显示
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(24),
border: Border.all(color: AppColors.borderLight),
boxShadow: AppColors.cardShadowLight,
),
child: ClipRRect(
borderRadius: BorderRadius.circular(18),
child: Image.file(
File(state.imagePath!),
width: screenW - 48,
height: 220,
fit: BoxFit.cover,
),
),
),
const SizedBox(height: 16),
_buildMealSelector(ref),
const SizedBox(height: 16),
if (state.isAnalyzing)
_buildAnalyzing(state)
else if (state.foods.isEmpty)
_buildNoFoodHint()
else ...[
_buildFoodList(ref),
const SizedBox(height: 16),
_buildMealSelector(ref),
const SizedBox(height: 16),
if (state.isAnalyzing)
_buildAnalyzing(state)
else if (state.foods.isEmpty)
_buildNoFoodHint()
else ...[
_buildFoodList(ref),
_buildNutritionCard(ref),
if (state.commentary != null && state.commentary!.isNotEmpty) ...[
const SizedBox(height: 16),
_buildNutritionCard(ref),
if (state.commentary != null && state.commentary!.isNotEmpty) ...[
const SizedBox(height: 16),
_buildAiCommentary(state.commentary!),
],
const SizedBox(height: 20),
_buildSaveButton(),
_buildAiCommentary(state.commentary!),
],
const SizedBox(height: 20),
_buildSaveButton(),
],
),
],
),
);
}
@@ -931,11 +930,7 @@ class _DietCapturePageState extends ConsumerState<DietCapturePage> {
color: _dietAccentLight,
borderRadius: BorderRadius.circular(10),
),
child: const Icon(
Icons.auto_awesome,
size: 20,
color: _dietAccent,
),
child: Icon(_dietVisual.icon, size: 20, color: _dietAccent),
),
const SizedBox(width: 12),
Expanded(
@@ -981,6 +976,13 @@ class _DietCapturePageState extends ConsumerState<DietCapturePage> {
if (mounted) popRoute(ref);
} catch (e) {
debugPrint('[Diet] 保存记录失败: $e');
if (mounted) {
AppToast.show(
context,
'保存失败,请检查网络后重试',
type: AppToastType.error,
);
}
}
},
child: const Row(