diff --git a/lib/features/customer/presentation/customer_tab.dart b/lib/features/customer/presentation/customer_tab.dart index 84f3851..39a910f 100644 --- a/lib/features/customer/presentation/customer_tab.dart +++ b/lib/features/customer/presentation/customer_tab.dart @@ -136,6 +136,7 @@ class _CustomerTabState extends ConsumerState { trailingColor: AppColors.primary, ), child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, children: [ _buildPageHead(), _buildSearchBar(), @@ -297,113 +298,111 @@ class _CustomerTabState extends ConsumerState { padding: EdgeInsets.zero, margin: const EdgeInsets.only(bottom: 12), onTap: () => _goDetail(c), - child: Stack( - children: [ - // 左侧状态色条 / 右侧编号面板均贴边,圆角按卡片圆角裁出 - Positioned( - left: 0, - top: 0, - bottom: 0, - width: 4, - child: DecoratedBox( - decoration: BoxDecoration( - color: customerStatusBarColor(c.status), - borderRadius: const BorderRadius.horizontal( - left: Radius.circular(AppRadius.lg), + // 对应源项目 `.customer-card { display:flex }`:主内容与右侧编号面板是并排的 + // 两个子项,卡片高度取两者较大值。IntrinsicHeight 让两侧等高,避免右侧 + // 内容(编号换行 + 操作按钮)撑出卡片导致 RenderFlex 溢出。 + child: IntrinsicHeight( + child: Row( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + // 左侧状态色条,圆角按卡片圆角裁出 + SizedBox( + width: 4, + child: DecoratedBox( + decoration: BoxDecoration( + color: customerStatusBarColor(c.status), + borderRadius: const BorderRadius.horizontal( + left: Radius.circular(AppRadius.lg), + ), ), ), ), - ), - const Positioned( - right: 0, - top: 0, - bottom: 0, - width: 86, - child: DecoratedBox( - decoration: BoxDecoration( + Expanded( + child: Padding( + padding: const EdgeInsets.all(14), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Wrap( + spacing: 6, + runSpacing: 6, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + Text( + c.customerName, + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.w700, + color: AppColors.onSurface, + ), + ), + XChip( + customerStatusText(c.status), + tone: customerStatusTone(c.status), + ), + if (c.customerLevel.isNotEmpty) + XChip(c.customerLevel, tone: ChipTone.muted), + ], + ), + ), + const SizedBox(width: 6), + const XIcon( + 'more', + size: 20, + color: AppColors.textMuted, + ), + ], + ), + const SizedBox(height: 10), + Row( + children: [ + const XIcon( + 'location', + size: 16, + color: AppColors.textMuted, + ), + const SizedBox(width: 4), + Text( + c.locationText, + style: const TextStyle( + fontSize: 14, + color: AppColors.textMuted, + ), + ), + const SizedBox(width: 16), + const XIcon( + 'person', + size: 16, + color: AppColors.textMuted, + ), + const SizedBox(width: 4), + Text( + c.contactPerson.isEmpty ? '-' : c.contactPerson, + style: const TextStyle( + fontSize: 14, + color: AppColors.textMuted, + ), + ), + ], + ), + ], + ), + ), + ), + // 右侧编号面板,圆角按卡片圆角裁出 + Container( + width: 86, + padding: const EdgeInsets.all(12), + decoration: const BoxDecoration( color: AppColors.surfaceBright, borderRadius: BorderRadius.horizontal( right: Radius.circular(AppRadius.lg), ), ), - ), - ), - Padding( - padding: const EdgeInsets.only(left: 4, right: 86), - child: Padding( - padding: const EdgeInsets.all(14), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: Wrap( - spacing: 6, - runSpacing: 6, - crossAxisAlignment: WrapCrossAlignment.center, - children: [ - Text( - c.customerName, - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w700, - color: AppColors.onSurface, - ), - ), - XChip( - customerStatusText(c.status), - tone: customerStatusTone(c.status), - ), - if (c.customerLevel.isNotEmpty) - XChip(c.customerLevel, tone: ChipTone.muted), - ], - ), - ), - const SizedBox(width: 6), - const XIcon('more', size: 20, color: AppColors.textMuted), - ], - ), - const SizedBox(height: 10), - Row( - children: [ - const XIcon( - 'location', - size: 16, - color: AppColors.textMuted, - ), - const SizedBox(width: 4), - Text( - c.locationText, - style: const TextStyle( - fontSize: 14, - color: AppColors.textMuted, - ), - ), - const SizedBox(width: 16), - const XIcon('person', size: 16, color: AppColors.textMuted), - const SizedBox(width: 4), - Text( - c.contactPerson.isEmpty ? '-' : c.contactPerson, - style: const TextStyle( - fontSize: 14, - color: AppColors.textMuted, - ), - ), - ], - ), - ], - ), - ), - ), - Positioned( - right: 0, - top: 0, - bottom: 0, - width: 86, - child: Padding( - padding: const EdgeInsets.all(12), child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.start, @@ -432,24 +431,32 @@ class _CustomerTabState extends ConsumerState { ), decoration: BoxDecoration( color: const Color(0x1A712AE2), - borderRadius: BorderRadius.circular(AppRadius.regular), + borderRadius: BorderRadius.circular( + AppRadius.regular, + ), ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - const XIcon( - 'calendar', - size: 14, - color: AppColors.secondary, - ), - const SizedBox(width: 2), - Text( - action, - style: AppTypography.captionSm.copyWith( + // '跟进展' 等较长文案在 62px 内容宽内会横向溢出, + // 等比缩放兜底,避免 RenderFlex 溢出条纹。 + child: FittedBox( + fit: BoxFit.scaleDown, + alignment: Alignment.centerLeft, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const XIcon( + 'calendar', + size: 14, color: AppColors.secondary, ), - ), - ], + const SizedBox(width: 2), + Text( + action, + style: AppTypography.captionSm.copyWith( + color: AppColors.secondary, + ), + ), + ], + ), ), ), ), @@ -457,9 +464,9 @@ class _CustomerTabState extends ConsumerState { ], ), ), - ), - ], + ], + ), ), ); } -} \ No newline at end of file +} diff --git a/lib/features/project/presentation/project_tab.dart b/lib/features/project/presentation/project_tab.dart index 8e582b6..77e109b 100644 --- a/lib/features/project/presentation/project_tab.dart +++ b/lib/features/project/presentation/project_tab.dart @@ -131,11 +131,9 @@ class _ProjectTabState extends ConsumerState { }); return XPageShell( - topBar: XTopBar.brand( - title: '鑫潼智电', - trailingColor: AppColors.primary, - ), + topBar: XTopBar.brand(title: '鑫潼智电', trailingColor: AppColors.primary), child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, children: [ _buildPageHead(), _buildSearchBar(), @@ -297,7 +295,11 @@ class _ProjectTabState extends ConsumerState { ), ), const SizedBox(width: 12), - const XIcon('clock', size: 15, color: AppColors.textMuted), + const XIcon( + 'clock', + size: 15, + color: AppColors.textMuted, + ), const SizedBox(width: 4), Text( formatDate(p.registerTime), @@ -327,4 +329,4 @@ class _ProjectTabState extends ConsumerState { ), ); } -} \ No newline at end of file +} diff --git a/lib/features/survey/presentation/survey_list_page.dart b/lib/features/survey/presentation/survey_list_page.dart index c318bc8..d72ec4b 100644 --- a/lib/features/survey/presentation/survey_list_page.dart +++ b/lib/features/survey/presentation/survey_list_page.dart @@ -50,7 +50,7 @@ class _SurveyListPageState extends ConsumerState { @override Widget build(BuildContext context) { return XPageShell( - topBar: XTopBar.brand(title: '勘测任务'), + topBar: XTopBar.nav(title: '勘测任务', onBack: () => context.pop()), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ @@ -156,10 +156,13 @@ class _SurveyListPageState extends ConsumerState { Expanded( child: Text( text, - style: const TextStyle(fontSize: 14, color: AppColors.onSurfaceVariant), + style: const TextStyle( + fontSize: 14, + color: AppColors.onSurfaceVariant, + ), ), ), ], ); } -} \ No newline at end of file +} diff --git a/lib/shared/widgets/x_bottom_nav.dart b/lib/shared/widgets/x_bottom_nav.dart index 0148fdb..3d9f2ab 100644 --- a/lib/shared/widgets/x_bottom_nav.dart +++ b/lib/shared/widgets/x_bottom_nav.dart @@ -7,14 +7,10 @@ import 'x_icon.dart'; /// 底部悬浮胶囊导航,对应 `components/XBottomNav.vue`。 /// -/// 距屏幕底部 12px(再叠加安全区),高 56,四周内边距 5, +/// 距屏幕底部 4px(再叠加安全区),高 56,四周内边距 5, /// 四个 tab 等宽均分;激活项铺满所在分格。 class XBottomNav extends StatelessWidget { - const XBottomNav({ - super.key, - required this.current, - required this.onChanged, - }); + const XBottomNav({super.key, required this.current, required this.onChanged}); final String current; final ValueChanged onChanged; @@ -31,11 +27,7 @@ class XBottomNav extends StatelessWidget { final bottomInset = MediaQuery.paddingOf(context).bottom; return Padding( - padding: EdgeInsets.only( - left: 16, - right: 16, - bottom: 12 + bottomInset, - ), + padding: EdgeInsets.only(left: 16, right: 16, bottom: 4 + bottomInset), child: Container( height: 56, padding: const EdgeInsets.all(5), @@ -92,4 +84,4 @@ class XBottomNav extends StatelessWidget { ), ); } -} \ No newline at end of file +}