add Paginator

git 2025-12-13 14:38:11 +08:00
parent 25c582735f
commit afa04cb1f6
Signed by: git
GPG Key ID: 3F65EFFA44207ADD
2 changed files with 151 additions and 87 deletions

View File

@ -1,116 +1,166 @@
package paginator
// Paginator
type Paginator struct {
page int
limit int
import (
"fmt"
"strings"
)
type Paginator[T any] struct {
rawTtems []T // 当前页的数据
curPage int // 当前页
limit int // 每页数量
pageCount int // 最多显示的总页数
}
// New
func New(page, limit int) *Paginator {
return &Paginator{page: page, limit: limit}
}
// Cut 按分页切割数据
// @param items 原始数据
// @param page 当前页
// @param limit 每页数量, 0 表示不分页
// @param pageCount 最多显示的总页数, 0 表示不限制
func Cut[T any](items []T, page int, limit int, pageCount int) *Paginator[T] {
// 参数校验
page = max(page, 1)
limit = max(limit, 0)
pageCount = max(pageCount, 0)
// Offset
func (p *Paginator) Offset() int {
if p.page < 1 {
p.page = 1
return &Paginator[T]{
rawTtems: items,
curPage: page,
limit: limit,
pageCount: pageCount,
}
offset := p.limit * (p.page - 1)
return int(offset)
}
// Limit
func (p *Paginator) Limit() int {
return p.limit
func (p *Paginator[T]) Items() []T {
// 计算起始索引和结束索引
startIdx := (p.curPage - 1) * p.limit
endIdx := startIdx + p.limit
endIdx = min(endIdx, len(p.rawTtems))
items := p.rawTtems[startIdx:endIdx]
return items
}
// Pagination
func (p *Paginator) Pagination(totalCount int) *Pagination {
pg := Pagination{}
total := (totalCount / p.limit)
// Calculator Total Page
remainder := totalCount % p.limit
if remainder == 0 {
pg.totalPage = total
} else {
pg.totalPage = total + 1
// TotalPage 总页数
func (p *Paginator[T]) TotalPage() int {
if p.limit == 0 {
return 1
}
// Set current/record per page meta data
pg.currentPage = p.page
pg.recordPerPage = p.limit
// Calculator the Next/Previous Page
if p.page <= 0 {
pg.next = p.page + 1
} else if p.page < pg.totalPage {
pg.previous = p.page - 1
pg.next = p.page + 1
} else if p.page == pg.totalPage {
pg.previous = p.page - 1
pg.next = 0
// 计算总页数
total := (len(p.rawTtems) / p.limit)
if len(p.rawTtems)%p.limit != 0 {
total++
}
return &pg
return total
}
// Pagination Object
type Pagination struct {
next int
previous int
recordPerPage int
currentPage int
totalPage int
func (p *Paginator[T]) pageRangeIdx() (int, int) {
if p.limit == 0 {
return 1, 1
}
total := p.TotalPage()
if p.pageCount == 0 || total <= p.pageCount {
return 1, total
}
if p.curPage > total {
p.curPage = total
}
// 计算起始页和结束页
offset := p.pageCount / 2
startPage := p.curPage - offset
endPage := p.curPage + offset
if startPage < 1 {
endPage = endPage - startPage + 1
startPage = 1
}
if endPage > total {
startPage = startPage - (endPage - total)
endPage = total
}
return startPage, endPage
}
// FirstPage 第一页, 如果limit为0, 表示不显示
func (p *Paginator[T]) FirstPage() int {
if p.limit == 0 {
return 0
}
start, _ := p.pageRangeIdx()
if start > 1 {
return 1
}
return 0
}
// FirstPage 第一页, 如果limit为0, 表示不显示
func (p *Paginator[T]) LastPage() int {
if p.limit == 0 {
return 0
}
_, end := p.pageRangeIdx()
if end == p.TotalPage() {
return 0
}
return p.TotalPage()
}
// PreviewPage 上一页, 如果为0, 表示不显示
func (p *Paginator[T]) PreviewPage() int {
preview := p.curPage - 1
if preview <= 1 {
preview = 0
}
return preview
}
// PreviewPage 下一页, 如果为0, 表示不显示
func (p *Paginator[T]) NextPage() int {
next := p.curPage + 1
if next >= p.TotalPage() {
next = 0
}
return next
}
// PageRange 迭代页码
func (p *Pagination) PageRange() []int {
func (p *Paginator[T]) PageRange() []int {
pages := []int{}
for i := 1; i <= p.totalPage; i++ {
start, end := p.pageRangeIdx()
for i := start; i <= end; i++ {
pages = append(pages, i)
}
return pages
}
// NumPages 页码数量
func (p *Pagination) NumPages() int {
return p.totalPage
}
func (p *Paginator[T]) String() string {
pages := p.PageRange()
// HasPrevious 是否有上一页
func (p *Pagination) HasPrevious() bool {
return p.previous > 0
}
buf := make([]string, len(pages))
for i, k := range pages {
if k == p.curPage {
buf[i] = fmt.Sprintf("[%d]", k)
} else {
buf[i] = fmt.Sprintf("%d", k)
}
// PreviousPageNumber 上一页的页码
func (p *Pagination) PreviousPageNumber() int {
return p.previous
}
}
pageStr := strings.Join(buf, " ")
// HasNext 是否有下一页
func (p *Pagination) HasNext() bool {
return p.next > 0
}
// NextPageNumber 下一页的页码
func (p *Pagination) NextPageNumber() int {
return p.next
}
// Number 当前页码
func (p *Pagination) Number() int {
return p.currentPage
}
// Number 当前页码
func (p *Pagination) IsFirstPage() bool {
return true
}
// Number 当前页码
func (p *Pagination) IsLastPage() bool {
return false
return fmt.Sprintf("items=%v\nfirst=%d, preview=%d pages=%s, next=%d, last=%d", p.Items(), p.FirstPage(), p.PreviewPage(), pageStr, p.NextPage(), p.LastPage())
}

View File

@ -0,0 +1,14 @@
package paginator
import (
"testing"
)
func TestCut(t *testing.T) {
items := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
page := 3
limit := 3
pageCount := 3
pag := Cut(items, page, limit, pageCount)
t.Logf("pag: %s", pag)
}