抽取分装组件
This commit is contained in:
145
components/CommonPagination/CommonPagination.uvue
Normal file
145
components/CommonPagination/CommonPagination.uvue
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
<template>
|
||||||
|
<view class="pagination-footer">
|
||||||
|
<text class="total-txt">共 {{ total }} 条</text>
|
||||||
|
|
||||||
|
<picker class="page-select" :range="pageSizeOptionLabels" :value="pageSizeIndex" @change="onPageSizeChange">
|
||||||
|
<view class="page-select-inner">
|
||||||
|
<text class="page-val">{{ pageSize }} 条/页</text>
|
||||||
|
<text class="arrow-down">▼</text>
|
||||||
|
</view>
|
||||||
|
</picker>
|
||||||
|
|
||||||
|
<view class="page-btns">
|
||||||
|
<view class="p-btn" :class="{ disabled: currentPage <= 1 }" @click="onPageBtnClick(currentPage - 1)">
|
||||||
|
<text><</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view
|
||||||
|
v-for="(p, index) in visiblePages"
|
||||||
|
:key="index"
|
||||||
|
class="p-btn"
|
||||||
|
:class="{ active: p === currentPage, 'ellipsis-btn': p === -1 }"
|
||||||
|
@click="onPageBtnClick(p)">
|
||||||
|
<text>{{ p === -1 ? '...' : p }}</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="p-btn" :class="{ disabled: currentPage >= totalPage }" @click="onPageBtnClick(currentPage + 1)">
|
||||||
|
<text>></text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="page-jump">
|
||||||
|
<text class="jump-txt">前往</text>
|
||||||
|
<input
|
||||||
|
class="jump-input"
|
||||||
|
type="number"
|
||||||
|
:value="jumpPageInput"
|
||||||
|
@input="onJumpInputChange"
|
||||||
|
@confirm="onJumpPage"
|
||||||
|
@blur="onJumpPage"
|
||||||
|
placeholder="页码"
|
||||||
|
/>
|
||||||
|
<text class="jump-txt">页</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="uts">
|
||||||
|
const props = defineProps({
|
||||||
|
total: { type: Number, default: 0 },
|
||||||
|
loading: { type: Boolean, default: false },
|
||||||
|
currentPage: { type: Number, default: 1 },
|
||||||
|
pageSize: { type: Number, default: 10 },
|
||||||
|
pageSizeOptionLabels: { type: Array, default: (): string[] => [] },
|
||||||
|
pageSizeIndex: { type: Number, default: 0 },
|
||||||
|
visiblePages: { type: Array, default: (): number[] => [] },
|
||||||
|
totalPage: { type: Number, default: 1 },
|
||||||
|
jumpPageInput: { type: String, default: '' }
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['page-size-change', 'page-change', 'update:jumpPageInput', 'jump-page'])
|
||||||
|
|
||||||
|
const onPageSizeChange = (e : any) => {
|
||||||
|
emit('page-size-change', e)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onPageBtnClick = (p : number) => {
|
||||||
|
if (p !== -1) {
|
||||||
|
emit('page-change', p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onJumpInputChange = (e : any) => {
|
||||||
|
emit('update:jumpPageInput', e.detail.value as string)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onJumpPage = () => {
|
||||||
|
emit('jump-page')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
/* 分页 */
|
||||||
|
.pagination-footer {
|
||||||
|
padding: 16px 24px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 16px;
|
||||||
|
border-top: 1px solid #e8eaec;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
.total-txt { font-size: 14px; color: #515a6e; }
|
||||||
|
|
||||||
|
.page-select {
|
||||||
|
border: 1px solid #dcdee2;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #fff;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: border 0.2s;
|
||||||
|
}
|
||||||
|
.page-select:hover { border-color: #2d8cf0; }
|
||||||
|
.page-select-inner {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 12px;
|
||||||
|
height: 32px;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
.page-val { font-size: 14px; color: #515a6e; }
|
||||||
|
.arrow-down { font-size: 10px; color: #c0c4cc; }
|
||||||
|
|
||||||
|
.page-btns { display: flex; flex-direction: row; gap: 4px; }
|
||||||
|
.p-btn {
|
||||||
|
min-width: 32px; height: 32px; padding: 0 4px; border: 1px solid #dcdee2; border-radius: 4px;
|
||||||
|
display: flex; align-items: center; justify-content: center; font-size: 14px; color: #515a6e;
|
||||||
|
background-color: #fff; cursor: pointer; transition: all 0.2s;
|
||||||
|
}
|
||||||
|
.p-btn:hover:not(.disabled):not(.active):not(.ellipsis-btn) {
|
||||||
|
border-color: #2d8cf0; color: #2d8cf0;
|
||||||
|
}
|
||||||
|
.p-btn.active { background-color: #2d8cf0; border-color: #2d8cf0; color: #fff; }
|
||||||
|
.p-btn.disabled { color: #c5c8ce; background-color: #f7f7f7; cursor: not-allowed; border-color: #dcdee2; }
|
||||||
|
.p-btn.ellipsis-btn { border: none; cursor: default; }
|
||||||
|
|
||||||
|
.page-jump {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
.jump-txt { font-size: 14px; color: #515a6e; }
|
||||||
|
.jump-input {
|
||||||
|
width: 50px;
|
||||||
|
height: 32px;
|
||||||
|
border: 1px solid #dcdee2;
|
||||||
|
border-radius: 4px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #515a6e;
|
||||||
|
transition: border 0.2s;
|
||||||
|
}
|
||||||
|
.jump-input:focus { border-color: #2d8cf0; outline: none; }
|
||||||
|
</style>
|
||||||
@@ -123,41 +123,22 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 分页 -->
|
<!-- 分页 -->
|
||||||
<view class="pagination-footer" v-if="dataList.length > 0 || pageState.loading">
|
<CommonPagination
|
||||||
<text class="total-txt">共 {{ pageState.total }} 条</text>
|
v-if="dataList.length > 0 || pageState.loading"
|
||||||
|
:total="pageState.total"
|
||||||
<picker class="page-select" :range="pageSizeOptionLabels" :value="pageSizeIndex" @change="handlePageSizeChange">
|
:loading="pageState.loading"
|
||||||
<view class="page-select-inner">
|
:currentPage="pageState.currentPage"
|
||||||
<text class="page-val">{{ pageState.pageSize }} 条/页</text>
|
:pageSize="pageState.pageSize"
|
||||||
<text class="arrow-down">▼</text>
|
:pageSizeOptionLabels="pageSizeOptionLabels"
|
||||||
</view>
|
:pageSizeIndex="pageSizeIndex"
|
||||||
</picker>
|
:visiblePages="visiblePages"
|
||||||
|
:totalPage="totalPage"
|
||||||
<view class="page-btns">
|
:jumpPageInput="pageState.jumpPageInput"
|
||||||
<view class="p-btn" :class="{ disabled: pageState.currentPage <= 1 }" @click="handlePageChange(pageState.currentPage - 1)">
|
@page-size-change="handlePageSizeChange"
|
||||||
<text><</text>
|
@page-change="handlePageChange"
|
||||||
</view>
|
@update:jumpPageInput="(val : string) => { pageState.jumpPageInput = val }"
|
||||||
|
@jump-page="handleJumpPage"
|
||||||
<view
|
/>
|
||||||
v-for="(p, index) in visiblePages"
|
|
||||||
:key="index"
|
|
||||||
class="p-btn"
|
|
||||||
:class="{ active: p === pageState.currentPage, 'ellipsis-btn': p === -1 }"
|
|
||||||
@click="p !== -1 && handlePageChange(p)">
|
|
||||||
<text>{{ p === -1 ? '...' : p }}</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="p-btn" :class="{ disabled: pageState.currentPage >= totalPage }" @click="handlePageChange(pageState.currentPage + 1)">
|
|
||||||
<text>></text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="page-jump">
|
|
||||||
<text class="jump-txt">前往</text>
|
|
||||||
<input class="jump-input" type="number" v-model="pageState.jumpPageInput" @confirm="handleJumpPage" @blur="handleJumpPage" placeholder="页码" />
|
|
||||||
<text class="jump-txt">页</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 空数据状态 -->
|
<!-- 空数据状态 -->
|
||||||
<view class="table-empty" v-if="dataList.length === 0 && !pageState.loading">
|
<view class="table-empty" v-if="dataList.length === 0 && !pageState.loading">
|
||||||
@@ -201,6 +182,7 @@
|
|||||||
<script setup lang="uts">
|
<script setup lang="uts">
|
||||||
import { ref, reactive, onMounted, computed } from 'vue'
|
import { ref, reactive, onMounted, computed } from 'vue'
|
||||||
import StatusSwitch from '@/components/StatusSwitch.uvue'
|
import StatusSwitch from '@/components/StatusSwitch.uvue'
|
||||||
|
import CommonPagination from '@/components/CommonPagination/CommonPagination.uvue'
|
||||||
import supa from '@/components/supadb/aksupainstance.uts'
|
import supa from '@/components/supadb/aksupainstance.uts'
|
||||||
|
|
||||||
interface CouponItem {
|
interface CouponItem {
|
||||||
@@ -733,69 +715,6 @@ onMounted(() => {
|
|||||||
.op-links { flex-direction: column; align-items: center; }
|
.op-links { flex-direction: column; align-items: center; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 分页 */
|
|
||||||
.pagination-footer {
|
|
||||||
padding: 16px 24px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-end;
|
|
||||||
gap: 16px;
|
|
||||||
border-top: 1px solid #e8eaec;
|
|
||||||
background-color: #fff;
|
|
||||||
}
|
|
||||||
.total-txt { font-size: 14px; color: #515a6e; }
|
|
||||||
|
|
||||||
.page-select {
|
|
||||||
border: 1px solid #dcdee2;
|
|
||||||
border-radius: 4px;
|
|
||||||
background-color: #fff;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: border 0.2s;
|
|
||||||
}
|
|
||||||
.page-select:hover { border-color: #2d8cf0; }
|
|
||||||
.page-select-inner {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
padding: 0 12px;
|
|
||||||
height: 32px;
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
.page-val { font-size: 14px; color: #515a6e; }
|
|
||||||
|
|
||||||
.page-btns { display: flex; flex-direction: row; gap: 4px; }
|
|
||||||
.p-btn {
|
|
||||||
min-width: 32px; height: 32px; padding: 0 4px; border: 1px solid #dcdee2; border-radius: 4px;
|
|
||||||
display: flex; align-items: center; justify-content: center; font-size: 14px; color: #515a6e;
|
|
||||||
background-color: #fff; cursor: pointer; transition: all 0.2s;
|
|
||||||
}
|
|
||||||
.p-btn:hover:not(.disabled):not(.active):not(.ellipsis-btn) {
|
|
||||||
border-color: #2d8cf0; color: #2d8cf0;
|
|
||||||
}
|
|
||||||
.p-btn.active { background-color: #2d8cf0; border-color: #2d8cf0; color: #fff; }
|
|
||||||
.p-btn.disabled { color: #c5c8ce; background-color: #f7f7f7; cursor: not-allowed; border-color: #dcdee2; }
|
|
||||||
.p-btn.ellipsis-btn { border: none; cursor: default; }
|
|
||||||
|
|
||||||
.page-jump {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
.jump-txt { font-size: 14px; color: #515a6e; }
|
|
||||||
.jump-input {
|
|
||||||
width: 50px;
|
|
||||||
height: 32px;
|
|
||||||
border: 1px solid #dcdee2;
|
|
||||||
border-radius: 4px;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 14px;
|
|
||||||
color: #515a6e;
|
|
||||||
transition: border 0.2s;
|
|
||||||
}
|
|
||||||
.jump-input:focus { border-color: #2d8cf0; outline: none; }
|
|
||||||
|
|
||||||
/* 空数据状态 */
|
/* 空数据状态 */
|
||||||
.table-empty {
|
.table-empty {
|
||||||
padding: 60px 0;
|
padding: 60px 0;
|
||||||
|
|||||||
@@ -749,6 +749,7 @@ onMounted(() => {
|
|||||||
.no-wrap {
|
.no-wrap {
|
||||||
flex-direction: row !important;
|
flex-direction: row !important;
|
||||||
flex-wrap: nowrap;
|
flex-wrap: nowrap;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.overflow-visible {
|
.overflow-visible {
|
||||||
|
|||||||
Reference in New Issue
Block a user