feat: UI全面改造 + 后端多项修复
【后端修复】 - 删除diet/consultation agent假工具声明 - 修复DayOfWeek实体注释 - 修复Vision API content序列化 - cleanup_service级联删除修复 - 用药提醒时区偏差修复 - 统一DateTime处理(UtcNow+8) - 新增UTC DateTime JSON转换器 【前端UI重构】 - 配色体系全面更新(#8B5CF6淡紫+#F0ECFF背景) - 登录页重设计 - 首页重设计(透明顶栏、渐变背景、胶囊输入区) - 聊天卡片加白蓝边框、渐变标题 - 侧边栏重构(渐变背景、合并顶部、删除底部设置) - 确认卡片可编辑字段恢复 - 所有子页面加返回按钮 - catch异常加日志 - 删除后refresh provider缓存
This commit is contained in:
@@ -23,7 +23,7 @@ class GradientBorderButton extends StatelessWidget {
|
||||
return Container(
|
||||
height: height,
|
||||
decoration: BoxDecoration(
|
||||
gradient: isSuccess ? AppColors.successButtonGradient : AppColors.buttonGradient,
|
||||
gradient: isSuccess ? AppColors.primaryGradient : AppColors.primaryGradient,
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
boxShadow: AppColors.buttonShadow,
|
||||
),
|
||||
@@ -78,14 +78,14 @@ class CardActionButton extends StatelessWidget {
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.backgroundSecondary,
|
||||
color: AppColors.cardInner,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(color: AppColors.borderLight),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(icon, size: 18, color: iconColor ?? AppColors.iconColor),
|
||||
Icon(icon, size: 18, color: iconColor ?? AppColors.primary),
|
||||
const SizedBox(width: 6),
|
||||
Text(
|
||||
label,
|
||||
@@ -102,6 +102,63 @@ class CardActionButton extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
/// 滑动删除组件:左滑露出红色删除背景,达30%阈值锁定,点击确认删除
|
||||
/// [margin] 控制卡片之间的间距,red背景与child完全对齐
|
||||
class SwipeDeleteTile extends StatefulWidget {
|
||||
final Widget child;
|
||||
final VoidCallback onDelete;
|
||||
final VoidCallback? onTap;
|
||||
final EdgeInsetsGeometry margin;
|
||||
const SwipeDeleteTile({super.key, required this.child, required this.onDelete, this.onTap, this.margin = const EdgeInsets.symmetric(horizontal: 16, vertical: 4)});
|
||||
@override State<SwipeDeleteTile> createState() => _SwipeDeleteTileState();
|
||||
}
|
||||
|
||||
class _SwipeDeleteTileState extends State<SwipeDeleteTile> with SingleTickerProviderStateMixin {
|
||||
double _dx = 0;
|
||||
static const _maxSlide = 80.0;
|
||||
static const _threshold = 24.0; // 30% of 80
|
||||
|
||||
void _onDragUpdate(DragUpdateDetails d) {
|
||||
setState(() => _dx = (_dx + d.delta.dx).clamp(-_maxSlide, 0.0));
|
||||
}
|
||||
|
||||
void _onDragEnd(DragEndDetails d) {
|
||||
if (_dx < -_threshold) {
|
||||
setState(() => _dx = -_maxSlide);
|
||||
} else {
|
||||
setState(() => _dx = 0);
|
||||
}
|
||||
}
|
||||
|
||||
@override Widget build(BuildContext context) {
|
||||
final isSwiped = _dx < 0;
|
||||
return Padding(
|
||||
padding: widget.margin,
|
||||
child: Stack(children: [
|
||||
Positioned.fill(child: Container(
|
||||
decoration: BoxDecoration(color: AppColors.error, borderRadius: BorderRadius.circular(16)),
|
||||
child: const Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: Padding(padding: EdgeInsets.only(right: 20), child: Icon(Icons.delete_outline, color: AppColors.textOnGradient, size: 28)),
|
||||
),
|
||||
)),
|
||||
GestureDetector(
|
||||
behavior: isSwiped ? HitTestBehavior.opaque : HitTestBehavior.deferToChild,
|
||||
onTap: isSwiped ? () { widget.onDelete(); setState(() => _dx = 0); } : widget.onTap,
|
||||
onHorizontalDragUpdate: _onDragUpdate,
|
||||
onHorizontalDragEnd: _onDragEnd,
|
||||
child: Transform.translate(
|
||||
offset: Offset(_dx, 0),
|
||||
child: isSwiped
|
||||
? AbsorbPointer(absorbing: true, child: widget.child)
|
||||
: widget.child,
|
||||
),
|
||||
),
|
||||
]),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 功能区小图标容器
|
||||
class IconBox extends StatelessWidget {
|
||||
final IconData icon;
|
||||
@@ -123,13 +180,13 @@ class IconBox extends StatelessWidget {
|
||||
width: size,
|
||||
height: size,
|
||||
decoration: BoxDecoration(
|
||||
color: backgroundColor ?? AppColors.iconBackground,
|
||||
color: backgroundColor ?? AppColors.iconBg,
|
||||
borderRadius: BorderRadius.circular(size / 3),
|
||||
),
|
||||
child: Icon(
|
||||
icon,
|
||||
size: size * 0.55,
|
||||
color: iconColor ?? AppColors.iconColor,
|
||||
color: iconColor ?? AppColors.primary,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user