182 lines
5.4 KiB
Dart
182 lines
5.4 KiB
Dart
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,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
}
|