refactor: 死代码清理 + 趋势图重构 + 侧边栏交互优化 + 智能体卡片去延迟

- 死代码清理: 删除 AppCard/AppMenuItem/AppTabChip/AppButtons 等 4 个未使用 Widget 文件; 清理 common_widgets/enterprise_widgets/app_status_badge 中未使用 class; 移除 HealthService 等未使用方法; 后端移除 ExerciseService.CreateFromItemsAsync/HealthArchiveService.GetOrCreateAsync/MedicationAgentHandler 死分支/ChatRequest DTO
- 趋势图: 直线折线 + 渐变填充 + 阴影; 去网格; X 轴日+月份; Y 轴整数刻度最多 4 个; 点击数据点/录入记录显示上方浮层; 选中点变实心
- 侧边栏: 对话记录改单选删除(灰底高亮); 操作栏浮层修复触摸问题; 常用功能/健康仪表盘间距收紧; _Panel 去外框
- 智能体: 欢迎卡片去掉 400ms 延迟; 胶囊去阴影
- 其他: api_client IP 适配; 多页面 UI 微调; 新增 chat_provider/prelaunch_guardrails 测试
This commit is contained in:
MingNian
2026-07-09 15:04:02 +08:00
parent 1c020b8ae5
commit d82e006cf4
37 changed files with 1842 additions and 2096 deletions

View File

@@ -1,117 +1,13 @@
import 'package:flutter/material.dart';
import '../core/app_colors.dart';
/// 渐变边框按钮(白色底+彩色渐变边框)
class GradientBorderButton extends StatelessWidget {
final String text;
final IconData? icon;
final VoidCallback? onTap;
final double height;
final bool isSuccess;
const GradientBorderButton({
super.key,
required this.text,
this.icon,
this.onTap,
this.height = 52,
this.isSuccess = false,
});
@override
Widget build(BuildContext context) {
return Container(
height: height,
decoration: BoxDecoration(
gradient: isSuccess
? AppColors.calmHealthGradient
: AppColors.primaryGradient,
borderRadius: BorderRadius.circular(14),
boxShadow: AppColors.buttonShadow,
),
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(14),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (icon != null) ...[
Icon(icon, size: 22, color: AppColors.textOnGradient),
const SizedBox(width: 8),
],
Text(
text,
style: const TextStyle(
fontSize: 17,
fontWeight: FontWeight.w600,
color: AppColors.textOnGradient,
),
),
],
),
),
),
);
}
}
/// 卡片内的小操作按钮
class CardActionButton extends StatelessWidget {
final String label;
final IconData icon;
final VoidCallback? onTap;
final Color? iconColor;
const CardActionButton({
super.key,
required this.label,
required this.icon,
this.onTap,
this.iconColor,
});
@override
Widget build(BuildContext context) {
return InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(12),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10),
decoration: BoxDecoration(
gradient: AppColors.surfaceGradient,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: AppColors.borderLight),
boxShadow: AppColors.cardShadowLight,
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(icon, size: 18, color: iconColor ?? AppColors.primary),
const SizedBox(width: 6),
Text(
label,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: AppColors.textPrimary,
),
),
],
),
),
);
}
}
/// 滑动删除组件左滑露出红色删除背景达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,
@@ -119,6 +15,7 @@ class SwipeDeleteTile extends StatefulWidget {
this.onTap,
this.margin = const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
});
@override
State<SwipeDeleteTile> createState() => _SwipeDeleteTileState();
}
@@ -127,18 +24,14 @@ class _SwipeDeleteTileState extends State<SwipeDeleteTile>
with SingleTickerProviderStateMixin {
double _dx = 0;
static const _maxSlide = 80.0;
static const _threshold = 24.0; // 30% of 80
static const _threshold = 24.0;
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);
}
setState(() => _dx = _dx < -_threshold ? -_maxSlide : 0);
}
@override
@@ -191,34 +84,3 @@ class _SwipeDeleteTileState extends State<SwipeDeleteTile>
);
}
}
/// 功能区小图标容器
class IconBox extends StatelessWidget {
final IconData icon;
final double size;
final Color? backgroundColor;
final Color? iconColor;
const IconBox({
super.key,
required this.icon,
this.size = 44,
this.backgroundColor,
this.iconColor,
});
@override
Widget build(BuildContext context) {
return Container(
width: size,
height: size,
decoration: BoxDecoration(
gradient: backgroundColor == null ? AppColors.calmHealthGradient : null,
color: backgroundColor,
borderRadius: BorderRadius.circular(size / 3),
boxShadow: AppColors.cardShadowLight,
),
child: Icon(icon, size: size * 0.55, color: iconColor ?? Colors.white),
);
}
}