游标分页优化
This commit is contained in:
1 parent
f5db2f6e77
commit
0a0713e65b
17 files changed
+448
-156
No files matched your search
@@ -28,15 +28,17 @@ interface AppUpdateRelease {
|
||||
|
||||
interface PageResult<T> {
|
||||
items: T[]
|
||||
total: number
|
||||
page: number
|
||||
nextCursor?: string
|
||||
hasMore: boolean
|
||||
pageSize: number
|
||||
}
|
||||
|
||||
const loading = ref(false)
|
||||
const uploadBusy = ref(false)
|
||||
const rows = ref<AppUpdateRelease[]>([])
|
||||
const total = ref(0)
|
||||
const cursors = ref<string[]>([])
|
||||
const nextCursor = ref<string>()
|
||||
const hasMore = ref(false)
|
||||
const uploadVisible = ref(false)
|
||||
const selectedBundle = ref<File>()
|
||||
const uploadFiles = ref<UploadFiles>([])
|
||||
@@ -92,8 +94,8 @@ function statusType(value: UpdateStatus) {
|
||||
async function loadReleases() {
|
||||
loading.value = true
|
||||
try {
|
||||
const params: Record<string, string | number> = {
|
||||
page: filter.page,
|
||||
const params: Record<string, string | number | undefined> = {
|
||||
cursor: cursors.value.at(-1),
|
||||
pageSize: filter.pageSize,
|
||||
}
|
||||
if (filter.platform) params.platform = filter.platform
|
||||
@@ -103,7 +105,8 @@ async function loadReleases() {
|
||||
{ params },
|
||||
)
|
||||
rows.value = data.items
|
||||
total.value = data.total
|
||||
hasMore.value = data.hasMore
|
||||
nextCursor.value = data.nextCursor
|
||||
} catch (error) {
|
||||
ElMessage.error(apiErrorMessage(error))
|
||||
} finally {
|
||||
@@ -113,9 +116,25 @@ async function loadReleases() {
|
||||
|
||||
function search() {
|
||||
filter.page = 1
|
||||
cursors.value = []
|
||||
nextCursor.value = undefined
|
||||
loadReleases()
|
||||
}
|
||||
|
||||
async function nextPage() {
|
||||
if (!nextCursor.value || loading.value) return
|
||||
cursors.value.push(nextCursor.value)
|
||||
filter.page++
|
||||
await loadReleases()
|
||||
}
|
||||
|
||||
async function previousPage() {
|
||||
if (!cursors.value.length || loading.value) return
|
||||
cursors.value.pop()
|
||||
filter.page--
|
||||
await loadReleases()
|
||||
}
|
||||
|
||||
function openUpload() {
|
||||
Object.assign(form, {
|
||||
platform: 'Android',
|
||||
@@ -316,14 +335,11 @@ onMounted(loadReleases)
|
||||
</template>
|
||||
</el-table>
|
||||
|
||||
<el-pagination
|
||||
v-model:current-page="filter.page"
|
||||
v-model:page-size="filter.pageSize"
|
||||
background
|
||||
layout="total, prev, pager, next"
|
||||
:total="total"
|
||||
@current-change="loadReleases"
|
||||
/>
|
||||
<div v-if="cursors.length || hasMore" class="cursor-pager">
|
||||
<el-button :disabled="!cursors.length || loading" @click="previousPage">上一批</el-button>
|
||||
<span>第 {{ filter.page }} 批</span>
|
||||
<el-button type="primary" :disabled="!hasMore || loading" @click="nextPage">下一批</el-button>
|
||||
</div>
|
||||
|
||||
<el-dialog
|
||||
v-model="uploadVisible"
|
||||
@@ -444,7 +460,8 @@ onMounted(loadReleases)
|
||||
small { color: #74818a; display: block; font-size: 10px; margin-top: 4px; }
|
||||
.active-label { color: #1f7468; font-size: 11px; font-weight: 700; }
|
||||
.el-table { margin-top: 12px; }
|
||||
.el-pagination { justify-content: flex-end; padding: 16px 18px; }
|
||||
.cursor-pager { align-items:center; display:flex; gap:10px; justify-content:flex-end; padding:16px 18px; }
|
||||
.cursor-pager span { color:#74818a; font-size:11px; }
|
||||
.form-grid { display: grid; gap: 0 14px; grid-template-columns: 1fr 1fr; }
|
||||
.form-grid .el-select { width: 100%; }
|
||||
|
||||
|
||||
@@ -31,9 +31,13 @@ const sessionLoading = ref(false)
|
||||
const termId = ref<string>()
|
||||
const tab = ref(isManager.value ? 'reviews' : 'mine')
|
||||
const minePage = ref(1)
|
||||
const mineTotal = ref(0)
|
||||
const mineCursors = ref<string[]>([])
|
||||
const nextMineCursor = ref<string>()
|
||||
const mineHasMore = ref(false)
|
||||
const reviewPage = ref(1)
|
||||
const reviewTotal = ref(0)
|
||||
const reviewCursors = ref<string[]>([])
|
||||
const nextReviewCursor = ref<string>()
|
||||
const reviewHasMore = ref(false)
|
||||
const pageSize = 20
|
||||
const targetAdjustmentId = computed(() => {
|
||||
const value = route.query.adjustmentId
|
||||
@@ -95,33 +99,67 @@ async function load(resetPages = false) {
|
||||
if (resetPages) {
|
||||
minePage.value = 1
|
||||
reviewPage.value = 1
|
||||
mineCursors.value = []
|
||||
reviewCursors.value = []
|
||||
nextMineCursor.value = undefined
|
||||
nextReviewCursor.value = undefined
|
||||
}
|
||||
loading.value = true
|
||||
reviewLoading.value = isManager.value
|
||||
try {
|
||||
if (isTeacher.value || (!isManager.value)) {
|
||||
const response = await http.get('/course-adjustments/mine', {
|
||||
params: { academicTermId: termId.value, page: minePage.value, pageSize },
|
||||
params: { academicTermId: termId.value, cursor: mineCursors.value.at(-1), pageSize },
|
||||
})
|
||||
adjustments.value = response.data.items
|
||||
mineTotal.value = response.data.total
|
||||
mineHasMore.value = response.data.hasMore
|
||||
nextMineCursor.value = response.data.nextCursor
|
||||
}
|
||||
if (isManager.value) {
|
||||
const response = await http.get('/course-adjustments/pending-reviews', {
|
||||
params: {
|
||||
academicTermId: targetAdjustmentId.value ? undefined : termId.value,
|
||||
adjustmentId: targetAdjustmentId.value,
|
||||
page: reviewPage.value,
|
||||
cursor: reviewCursors.value.at(-1),
|
||||
pageSize,
|
||||
},
|
||||
})
|
||||
pendingReviews.value = response.data.items
|
||||
reviewTotal.value = response.data.total
|
||||
reviewHasMore.value = response.data.hasMore
|
||||
nextReviewCursor.value = response.data.nextCursor
|
||||
}
|
||||
} catch (e) { ElMessage.error(apiErrorMessage(e)) }
|
||||
finally { loading.value = false; reviewLoading.value = false }
|
||||
}
|
||||
|
||||
async function nextMinePage() {
|
||||
if (!nextMineCursor.value || loading.value) return
|
||||
mineCursors.value.push(nextMineCursor.value)
|
||||
minePage.value++
|
||||
await load()
|
||||
}
|
||||
|
||||
async function previousMinePage() {
|
||||
if (!mineCursors.value.length || loading.value) return
|
||||
mineCursors.value.pop()
|
||||
minePage.value--
|
||||
await load()
|
||||
}
|
||||
|
||||
async function nextReviewPage() {
|
||||
if (!nextReviewCursor.value || reviewLoading.value) return
|
||||
reviewCursors.value.push(nextReviewCursor.value)
|
||||
reviewPage.value++
|
||||
await load()
|
||||
}
|
||||
|
||||
async function previousReviewPage() {
|
||||
if (!reviewCursors.value.length || reviewLoading.value) return
|
||||
reviewCursors.value.pop()
|
||||
reviewPage.value--
|
||||
await load()
|
||||
}
|
||||
|
||||
function openCreate() {
|
||||
Object.assign(form, {
|
||||
teachingTaskId: undefined,
|
||||
@@ -346,15 +384,11 @@ function showSub(type: string) { return type === 'Substitute' }
|
||||
</footer>
|
||||
</article>
|
||||
<el-empty v-if="!adjustments.length" description="暂无调停课申请" />
|
||||
<el-pagination
|
||||
v-if="mineTotal > pageSize"
|
||||
v-model:current-page="minePage"
|
||||
:page-size="pageSize"
|
||||
:total="mineTotal"
|
||||
layout="total, prev, pager, next"
|
||||
class="table-pagination"
|
||||
@current-change="() => load()"
|
||||
/>
|
||||
<div v-if="mineCursors.length || mineHasMore" class="table-pagination cursor-pager">
|
||||
<el-button :disabled="!mineCursors.length || loading" @click="previousMinePage">上一批</el-button>
|
||||
<span>第 {{ minePage }} 批</span>
|
||||
<el-button type="primary" :disabled="!mineHasMore || loading" @click="nextMinePage">下一批</el-button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Pending reviews -->
|
||||
@@ -393,15 +427,11 @@ function showSub(type: string) { return type === 'Substitute' }
|
||||
</footer>
|
||||
</article>
|
||||
<el-empty v-if="!pendingReviews.length" description="暂无待审核申请" />
|
||||
<el-pagination
|
||||
v-if="reviewTotal > pageSize"
|
||||
v-model:current-page="reviewPage"
|
||||
:page-size="pageSize"
|
||||
:total="reviewTotal"
|
||||
layout="total, prev, pager, next"
|
||||
class="table-pagination"
|
||||
@current-change="() => load()"
|
||||
/>
|
||||
<div v-if="reviewCursors.length || reviewHasMore" class="table-pagination cursor-pager">
|
||||
<el-button :disabled="!reviewCursors.length || reviewLoading" @click="previousReviewPage">上一批</el-button>
|
||||
<span>第 {{ reviewPage }} 批</span>
|
||||
<el-button type="primary" :disabled="!reviewHasMore || reviewLoading" @click="nextReviewPage">下一批</el-button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Create dialog -->
|
||||
|
||||
@@ -9,6 +9,9 @@ const auth = useAuthStore()
|
||||
const loading = ref(false)
|
||||
const rows = ref<any[]>([])
|
||||
const total = ref(0)
|
||||
const cursors = ref<string[]>([])
|
||||
const nextCursor = ref<string>()
|
||||
const hasMore = ref(false)
|
||||
const colleges = ref<any[]>([])
|
||||
const categories = ref<any[]>([])
|
||||
const courseOptions = ref<any[]>([])
|
||||
@@ -100,9 +103,9 @@ function resetForm(row?: any) {
|
||||
async function load() {
|
||||
loading.value = true
|
||||
try {
|
||||
const { data } = await http.get('/courses', {
|
||||
const response = await http.get('/courses', {
|
||||
params: {
|
||||
page: query.page,
|
||||
cursor: cursors.value.at(-1),
|
||||
pageSize: query.pageSize,
|
||||
keyword: query.keyword || undefined,
|
||||
collegeId: query.collegeId,
|
||||
@@ -111,8 +114,11 @@ async function load() {
|
||||
isEnabled: query.isEnabled,
|
||||
},
|
||||
})
|
||||
const { data } = response
|
||||
rows.value = data.items
|
||||
total.value = data.total
|
||||
total.value = Number(data.total ?? 0)
|
||||
hasMore.value = data.hasMore
|
||||
nextCursor.value = data.nextCursor
|
||||
} catch (error) {
|
||||
ElMessage.error(apiErrorMessage(error))
|
||||
} finally {
|
||||
@@ -120,6 +126,26 @@ async function load() {
|
||||
}
|
||||
}
|
||||
|
||||
async function nextPage() {
|
||||
if (!nextCursor.value || loading.value) return
|
||||
cursors.value.push(nextCursor.value)
|
||||
query.page++
|
||||
await load()
|
||||
}
|
||||
|
||||
async function previousPage() {
|
||||
if (!cursors.value.length || loading.value) return
|
||||
cursors.value.pop()
|
||||
query.page--
|
||||
await load()
|
||||
}
|
||||
|
||||
function resetCursor() {
|
||||
query.page = 1
|
||||
cursors.value = []
|
||||
nextCursor.value = undefined
|
||||
}
|
||||
|
||||
async function resetFilters() {
|
||||
Object.assign(query, {
|
||||
page: 1,
|
||||
@@ -129,6 +155,7 @@ async function resetFilters() {
|
||||
nature: undefined,
|
||||
isEnabled: undefined,
|
||||
})
|
||||
resetCursor()
|
||||
await load()
|
||||
}
|
||||
|
||||
@@ -177,7 +204,7 @@ async function handleImport(event: Event) {
|
||||
ElMessage.success(
|
||||
`导入完成:新增 ${data.created} 门,更新 ${data.updated} 门,共处理 ${data.total} 门。`,
|
||||
)
|
||||
query.page = 1
|
||||
resetCursor()
|
||||
await load()
|
||||
courseOptions.value = (await http.get('/courses/options')).data
|
||||
} catch (error) {
|
||||
@@ -284,7 +311,7 @@ onMounted(async () => {
|
||||
:prefix-icon="Search"
|
||||
clearable
|
||||
placeholder="搜索课程编码、中英文名称"
|
||||
@keyup.enter="query.page = 1; load()"
|
||||
@keyup.enter="resetCursor(); load()"
|
||||
/>
|
||||
<el-select
|
||||
v-model="query.collegeId"
|
||||
@@ -304,7 +331,7 @@ onMounted(async () => {
|
||||
<el-option label="启用" :value="true" />
|
||||
<el-option label="停用" :value="false" />
|
||||
</el-select>
|
||||
<el-button type="primary" @click="query.page = 1; load()">查询</el-button>
|
||||
<el-button type="primary" @click="resetCursor(); load()">查询</el-button>
|
||||
<el-button :icon="Refresh" @click="resetFilters">重置</el-button>
|
||||
</div>
|
||||
<div class="table-toolbar">
|
||||
@@ -378,13 +405,11 @@ onMounted(async () => {
|
||||
</el-table>
|
||||
<div class="pagination-bar">
|
||||
<span>共 {{ total }} 门</span>
|
||||
<el-pagination
|
||||
v-model:current-page="query.page"
|
||||
:page-size="query.pageSize"
|
||||
:total="total"
|
||||
layout="prev, pager, next"
|
||||
@current-change="load"
|
||||
/>
|
||||
<div v-if="cursors.length || hasMore" class="cursor-pager">
|
||||
<el-button :disabled="!cursors.length || loading" @click="previousPage">上一批</el-button>
|
||||
<span>第 {{ query.page }} 批</span>
|
||||
<el-button type="primary" :disabled="!hasMore || loading" @click="nextPage">下一批</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
Loaded 3 of 17 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user