feat: 三端抽屉重构 + 配色系统更新 + 后台管理页精调 + 键盘抬起组件

## 抽屉重构
- admin_drawer / doctor_drawer / health_drawer 三端抽屉全部重做
- drawer_shell 增强

## 配色系统
- app_colors / app_module_visuals / app_theme 更新
- app.dart 启动流程调整

## 后台管理页
- admin_doctors_page 大幅重构(+251)
- admin_home / doctor_dashboard / doctor_reports / doctor_home / doctor_followups / doctor_settings 精调

## 患者端
- home_page / chat_messages_view / medication_list / notification_center / remaining_pages / exercise_plan / device / diet / consultation 微调

## 新增
- keyboard_lift.dart: 键盘抬起处理组件
- AGENTS.md: agent 指引文档

## 其他
- api_client IP 适配
- app_future_view 增强
- data_providers 调整
- secondary_page_visuals_test 更新
This commit is contained in:
MingNian
2026-07-19 19:11:30 +08:00
parent ae94ced2d5
commit 0d4fd88ce7
35 changed files with 1022 additions and 644 deletions

View File

@@ -213,11 +213,7 @@ class _HealthDashboard extends StatelessWidget {
onTap: () => pushRoute(ref, 'trend'),
),
titleColor: Colors.white,
backgroundGradient: const LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [Color(0xFF89F7FE), Color(0xFF66A6FF)],
),
backgroundPainter: const _HealthDashboardBackgroundPainter(),
child: latestHealth.when(
data: (data) => _DashboardMetrics(data: data, ref: ref),
loading: () => const SizedBox(
@@ -392,7 +388,7 @@ class _NavigationSection extends StatelessWidget {
colors: AppColors.medicationGradient.colors,
),
_NavItem(
icon: LucideIcons.utensils,
icon: AppModuleVisuals.diet.icon,
title: '饮食',
route: 'dietRecords',
colors: AppColors.dietGradient.colors,
@@ -476,6 +472,7 @@ class _NavTile extends StatelessWidget {
@override
Widget build(BuildContext context) {
final isDevice = item.route == 'devices';
return InkWell(
onTap: onTap,
borderRadius: AppRadius.mdBorder,
@@ -488,12 +485,16 @@ class _NavTile extends StatelessWidget {
width: 48,
height: 48,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: _colors,
),
color: isDevice ? AppColors.device : null,
gradient: isDevice
? null
: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: _colors,
),
borderRadius: AppRadius.mdBorder,
border: null,
boxShadow: [
BoxShadow(
color: _colors.last.withValues(alpha: 0.10),
@@ -567,60 +568,96 @@ class _Panel extends StatelessWidget {
final String title;
final Widget child;
final Widget? trailing;
final LinearGradient? backgroundGradient;
final CustomPainter? backgroundPainter;
final Color titleColor;
const _Panel({
required this.title,
required this.child,
this.trailing,
this.backgroundGradient,
this.backgroundPainter,
this.titleColor = AppColors.textPrimary,
});
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(14),
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
gradient:
backgroundGradient ??
LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Colors.white.withValues(alpha: 0.92),
const Color(0xFFF8F4FF).withValues(alpha: 0.84),
],
),
color: backgroundPainter == null ? null : const Color(0xFFBAE6FD),
gradient: backgroundPainter != null
? null
: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Colors.white.withValues(alpha: 0.92),
const Color(0xFFF8F4FF).withValues(alpha: 0.84),
],
),
borderRadius: AppRadius.xlBorder,
boxShadow: AppShadows.soft,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
child: CustomPaint(
painter: backgroundPainter,
child: Padding(
padding: const EdgeInsets.all(14),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Text(
title,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
color: titleColor,
Row(
children: [
Expanded(
child: Text(
title,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
color: titleColor,
),
),
),
),
?trailing,
],
),
?trailing,
const SizedBox(height: 12),
child,
],
),
const SizedBox(height: 12),
child,
],
),
),
);
}
}
class _HealthDashboardBackgroundPainter extends CustomPainter {
const _HealthDashboardBackgroundPainter();
@override
void paint(Canvas canvas, Size size) {
final rect = Offset.zero & size;
canvas.drawRect(rect, Paint()..color = const Color(0xFFBAE6FD));
void drawGlow(Alignment center, Color color) {
final paint = Paint()
..shader = RadialGradient(
center: center,
radius: 1,
colors: [color, color.withValues(alpha: 0)],
stops: const [0, 0.8],
).createShader(rect);
canvas.drawRect(rect, paint);
}
drawGlow(Alignment.bottomRight, const Color(0xFF818CF8));
drawGlow(const Alignment(0, 0.6), const Color(0xFF60A5FA));
drawGlow(const Alignment(0.6, -0.6), const Color(0xFF6366F1));
drawGlow(const Alignment(-0.6, -0.6), const Color(0xFF38BDF8));
}
@override
bool shouldRepaint(_HealthDashboardBackgroundPainter oldDelegate) => false;
}
class _TextAction extends StatelessWidget {
final String label;
final VoidCallback onTap;