Files
biz_xfj_cloud/lib/common/widgets/app/app_page.dart
T

182 lines
5.4 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'package:ducafe_ui_core/ducafe_ui_core.dart';
import 'package:flutter/material.dart';
import 'package:forui/forui.dart';
import 'package:pj_supermarket_cloud/common/index.dart';
Widget appPage(
BuildContext context, {
required int pageNo,
required int pageSize,
required int total,
required Function(int) onPageChanged,
String itemLabel = '条数据',
}) {
return TerminalPagination(
currentPage: pageNo,
pageSize: pageSize,
total: total,
itemLabel: itemLabel,
onPageChanged: onPageChanged,
);
}
/// 对齐主界面原型的圆角分页条,不依赖第三方分页组件的固定视觉实现。
class TerminalPagination extends StatelessWidget {
const TerminalPagination({
super.key,
required this.currentPage,
required this.pageSize,
required this.total,
required this.onPageChanged,
this.itemLabel = '条数据',
});
final int currentPage;
final int pageSize;
final int total;
final String itemLabel;
final ValueChanged<int> onPageChanged;
@override
Widget build(BuildContext context) {
final theme = FTheme.of(context);
final totalPages = total == 0 ? 1 : (total / pageSize).ceil();
return LayoutBuilder(
builder: (context, constraints) {
final buttonWidth = 48.w;
final available =
(constraints.maxWidth - 260.w).clamp(0, double.infinity);
final pageCount =
((available / buttonWidth).floor() - 2).clamp(5, 6).toInt();
return Container(
height: 76.h,
padding: EdgeInsets.symmetric(horizontal: 20.w),
decoration: BoxDecoration(
color: XfjDesignTokens.surface,
border: Border.all(color: XfjDesignTokens.line),
borderRadius: BorderRadius.circular(XfjDesignTokens.cardRadius),
boxShadow: XfjDesignTokens.surfaceShadow,
),
child: Row(
children: [
Text(
'共 $total $itemLabel',
style: theme.typography.lg.copyWith(
color: XfjDesignTokens.muted,
fontWeight: FontWeight.w500,
),
),
const Spacer(),
if (total > 0)
Row(
children: [
_PageButton(
label: '‹',
enabled: currentPage > 1,
onTap: () => onPageChanged(currentPage - 1),
),
..._visibleItems(currentPage, totalPages, pageCount).map(
(page) => page == 0
? const _PageEllipsis()
: _PageButton(
label: '$page',
selected: page == currentPage,
onTap: () => onPageChanged(page),
),
),
_PageButton(
label: '›',
enabled: currentPage < totalPages,
onTap: () => onPageChanged(currentPage + 1),
),
],
),
],
),
);
},
);
}
List<int> _visibleItems(int current, int totalPages, int count) {
if (totalPages <= count) {
return List.generate(totalPages, (index) => index + 1);
}
if (current <= count - 2) {
return [...List.generate(count - 1, (index) => index + 1), 0, totalPages];
}
if (current >= totalPages - count + 3) {
return [
1,
0,
...List.generate(count - 1, (index) => totalPages - count + 2 + index),
];
}
return [1, 0, current - 1, current, current + 1, 0, totalPages];
}
}
class _PageButton extends StatelessWidget {
const _PageButton({
required this.label,
required this.onTap,
this.selected = false,
this.enabled = true,
});
final String label;
final VoidCallback onTap;
final bool selected;
final bool enabled;
@override
Widget build(BuildContext context) {
final theme = FTheme.of(context);
final buttonSize = 52.h;
return Opacity(
opacity: enabled ? 1 : 0.35,
child: InkWell(
onTap: enabled ? onTap : null,
borderRadius: BorderRadius.circular(XfjDesignTokens.controlRadius),
child: Container(
constraints: BoxConstraints(minWidth: buttonSize),
height: buttonSize,
margin: EdgeInsets.symmetric(horizontal: 3.w),
alignment: Alignment.center,
decoration: BoxDecoration(
color: selected ? XfjDesignTokens.primary : Colors.transparent,
borderRadius: BorderRadius.circular(XfjDesignTokens.controlRadius),
),
child: Text(
label,
style: theme.typography.sm.copyWith(
color: selected ? Colors.white : XfjDesignTokens.muted,
fontWeight: selected ? FontWeight.w700 : FontWeight.w600,
),
),
),
),
);
}
}
class _PageEllipsis extends StatelessWidget {
const _PageEllipsis();
@override
Widget build(BuildContext context) => SizedBox(
width: 48.w,
height: 52.h,
child: Center(
child: Text(
'…',
style: FTheme.of(context).typography.base.copyWith(
color: XfjDesignTokens.muted,
fontWeight: FontWeight.w600,
),
),
),
);
}