- 新增管理员角色(手机号12345678910),管理员可增删医生、查看患者 - 注册页重构:去掉角色选择+审核码,改为选医生+填姓名 - 医生端点按DoctorId过滤患者,Patient↔Doctor关系建立 - Doctor/DoctorProfile/User实体新增关联字段 - JSON循环引用修复(IgnoreCycles) - /api/doctors改为公开接口 - 登录闪屏修复+原生Android启动页 - 输入框全局白底+灰框 - 蓝牙重连同步修复 - Web端(doctor_web+health_app/web)全部删除 - 全局UI改版:白底企业风,新配色和组件系统 - 新品牌图标和启动图
257 lines
7.8 KiB
Dart
257 lines
7.8 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:shadcn_ui/shadcn_ui.dart';
|
|
import 'app_colors.dart';
|
|
|
|
class GradientScaffold extends StatelessWidget {
|
|
final PreferredSizeWidget? appBar;
|
|
final Widget? body;
|
|
final Widget? floatingActionButton;
|
|
final Widget? drawer;
|
|
final Widget? bottomNavigationBar;
|
|
final bool extendBody;
|
|
|
|
const GradientScaffold({
|
|
super.key,
|
|
this.appBar,
|
|
this.body,
|
|
this.floatingActionButton,
|
|
this.drawer,
|
|
this.bottomNavigationBar,
|
|
this.extendBody = false,
|
|
});
|
|
|
|
@override
|
|
Widget build(BuildContext context) => Container(
|
|
decoration: const BoxDecoration(gradient: AppColors.bgGradient),
|
|
child: Scaffold(
|
|
backgroundColor: Colors.transparent,
|
|
appBar: appBar,
|
|
body: body,
|
|
floatingActionButton: floatingActionButton,
|
|
drawer: drawer,
|
|
bottomNavigationBar: bottomNavigationBar,
|
|
extendBody: extendBody,
|
|
),
|
|
);
|
|
}
|
|
|
|
class AppTheme {
|
|
AppTheme._();
|
|
|
|
static const Color primary = AppColors.primary;
|
|
static const Color primaryLight = AppColors.primaryLight;
|
|
static const Color primaryDark = AppColors.primaryDark;
|
|
static const Color primaryMid = AppColors.blueMeasure;
|
|
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 surface = AppColors.cardBackground;
|
|
static const Color surfaceInner = AppColors.cardInner;
|
|
static const Color text = AppColors.textPrimary;
|
|
static const Color textSub = AppColors.textSecondary;
|
|
static const Color textHint = AppColors.textHint;
|
|
static const Color border = AppColors.border;
|
|
static const Color divider = AppColors.divider;
|
|
|
|
static const Color success = AppColors.success;
|
|
static const Color successLight = AppColors.successLight;
|
|
static const Color error = AppColors.error;
|
|
static const Color errorLight = AppColors.errorLight;
|
|
static const Color warning = AppColors.warning;
|
|
static const Color warningLight = AppColors.warningLight;
|
|
|
|
static const double rXs = 4;
|
|
static const double rSm = 8;
|
|
static const double rMd = 12;
|
|
static const double rLg = 16;
|
|
static const double rXl = 20;
|
|
static const double rPill = 999;
|
|
|
|
static const double sXs = 4;
|
|
static const double sSm = 8;
|
|
static const double sMd = 12;
|
|
static const double sLg = 16;
|
|
static const double sXl = 20;
|
|
static const double sXxl = 24;
|
|
|
|
static BoxShadow get shadowCard => BoxShadow(
|
|
color: const Color(0xFF101828).withValues(alpha: 0.07),
|
|
blurRadius: 22,
|
|
offset: const Offset(0, 10),
|
|
);
|
|
|
|
static BoxShadow get shadowLight => BoxShadow(
|
|
color: const Color(0xFF101828).withValues(alpha: 0.045),
|
|
blurRadius: 14,
|
|
offset: const Offset(0, 6),
|
|
);
|
|
|
|
static BoxShadow get shadowElevated => BoxShadow(
|
|
color: primary.withValues(alpha: 0.12),
|
|
blurRadius: 18,
|
|
offset: const Offset(0, 8),
|
|
);
|
|
|
|
static BoxShadow get shadowButton => BoxShadow(
|
|
color: primary.withValues(alpha: 0.22),
|
|
blurRadius: 16,
|
|
offset: const Offset(0, 8),
|
|
);
|
|
|
|
static const Map<String, Color> agentColors = {
|
|
'default': Color(0xFFF3F0FF),
|
|
'consultation': Color(0xFFEFF5FF),
|
|
'health': Color(0xFFF3F0FF),
|
|
'diet': Color(0xFFFFF7E6),
|
|
'medication': Color(0xFFEFF5FF),
|
|
'report': Color(0xFFF6F3FF),
|
|
'exercise': Color(0xFFEFF8FF),
|
|
};
|
|
|
|
static Color agentLight(String? name) => agentColors[name] ?? primaryLight;
|
|
|
|
static ThemeData get lightTheme => ThemeData(
|
|
useMaterial3: true,
|
|
colorScheme: ColorScheme.fromSeed(
|
|
seedColor: primary,
|
|
primary: primary,
|
|
primaryContainer: primaryLight,
|
|
onPrimary: Colors.white,
|
|
secondary: AppColors.blueMeasure,
|
|
surface: surface,
|
|
brightness: Brightness.light,
|
|
),
|
|
scaffoldBackgroundColor: bg,
|
|
splashColor: primary.withValues(alpha: 0.06),
|
|
highlightColor: Colors.transparent,
|
|
hoverColor: primaryLight.withValues(alpha: 0.55),
|
|
fontFamily: null,
|
|
|
|
appBarTheme: const AppBarTheme(
|
|
backgroundColor: surface,
|
|
foregroundColor: text,
|
|
elevation: 0,
|
|
centerTitle: true,
|
|
scrolledUnderElevation: 0,
|
|
surfaceTintColor: Colors.transparent,
|
|
titleTextStyle: TextStyle(
|
|
fontSize: 17,
|
|
fontWeight: FontWeight.w700,
|
|
color: text,
|
|
),
|
|
toolbarHeight: 48,
|
|
),
|
|
|
|
cardTheme: CardThemeData(
|
|
color: surface,
|
|
elevation: 0,
|
|
surfaceTintColor: Colors.transparent,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(rLg),
|
|
side: const BorderSide(color: border),
|
|
),
|
|
margin: EdgeInsets.zero,
|
|
),
|
|
|
|
inputDecorationTheme: InputDecorationTheme(
|
|
filled: true,
|
|
fillColor: Colors.white,
|
|
contentPadding: const EdgeInsets.symmetric(horizontal: sLg, vertical: 13),
|
|
border: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(rMd),
|
|
borderSide: const BorderSide(color: border),
|
|
),
|
|
enabledBorder: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(rMd),
|
|
borderSide: const BorderSide(color: border),
|
|
),
|
|
focusedBorder: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(rMd),
|
|
borderSide: const BorderSide(color: primary, width: 1.2),
|
|
),
|
|
errorBorder: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(rMd),
|
|
borderSide: const BorderSide(color: error),
|
|
),
|
|
hintStyle: const TextStyle(color: textHint, fontSize: 15),
|
|
),
|
|
|
|
elevatedButtonTheme: ElevatedButtonThemeData(
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: primary,
|
|
foregroundColor: Colors.white,
|
|
minimumSize: const Size(double.infinity, 50),
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(rMd)),
|
|
textStyle: const TextStyle(fontSize: 16, fontWeight: FontWeight.w700),
|
|
elevation: 0,
|
|
),
|
|
),
|
|
|
|
outlinedButtonTheme: OutlinedButtonThemeData(
|
|
style: OutlinedButton.styleFrom(
|
|
foregroundColor: text,
|
|
side: const BorderSide(color: border),
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(rMd)),
|
|
textStyle: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600),
|
|
),
|
|
),
|
|
|
|
dialogTheme: DialogThemeData(
|
|
backgroundColor: surface,
|
|
surfaceTintColor: Colors.transparent,
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(rLg)),
|
|
),
|
|
|
|
textTheme: const TextTheme(
|
|
headlineLarge: TextStyle(
|
|
fontSize: 24,
|
|
fontWeight: FontWeight.w800,
|
|
color: text,
|
|
),
|
|
titleLarge: TextStyle(
|
|
fontSize: 18,
|
|
fontWeight: FontWeight.w700,
|
|
color: text,
|
|
),
|
|
titleMedium: TextStyle(
|
|
fontSize: 16,
|
|
fontWeight: FontWeight.w600,
|
|
color: text,
|
|
),
|
|
bodyLarge: TextStyle(fontSize: 15, color: text, height: 1.5),
|
|
bodyMedium: TextStyle(fontSize: 13, color: textSub, height: 1.4),
|
|
labelMedium: TextStyle(fontSize: 13, color: textSub),
|
|
labelSmall: TextStyle(fontSize: 12, color: textHint),
|
|
),
|
|
);
|
|
|
|
static ShadThemeData get shadTheme => ShadThemeData(
|
|
brightness: Brightness.light,
|
|
colorScheme: ShadVioletColorScheme.light(
|
|
background: bg,
|
|
foreground: text,
|
|
card: surface,
|
|
cardForeground: text,
|
|
popover: surface,
|
|
popoverForeground: text,
|
|
primary: primary,
|
|
primaryForeground: Colors.white,
|
|
secondary: primaryLight,
|
|
secondaryForeground: primaryDark,
|
|
muted: bgSoft,
|
|
mutedForeground: textSub,
|
|
accent: AppColors.blueMeasure,
|
|
accentForeground: Colors.white,
|
|
destructive: error,
|
|
destructiveForeground: Colors.white,
|
|
border: border,
|
|
input: border,
|
|
ring: primary,
|
|
selection: primaryLight,
|
|
),
|
|
radius: BorderRadius.circular(rMd),
|
|
);
|
|
}
|