admin lists: server-side pagination + filters for accounts/users/cdks/showcase/banned-words (limit/offset/total; stats over full set; /showcase/admin flat paginated view; dead=1 accounts filter for bulk dead-delete)

This commit is contained in:
Linda
2026-07-16 10:48:35 +08:00
committed by chiyi
parent 86559eb7fc
commit a65f52b7f4
12 changed files with 398 additions and 149 deletions
+15 -9
View File
@@ -1,5 +1,5 @@
<script setup>
import { ref, computed, onMounted } from 'vue'
import { ref, computed, onMounted, watch } from 'vue'
import { api, jsonBody } from '../api'
import Icon from '../components/Icon.vue'
@@ -12,9 +12,16 @@ function flash(msg) { toast.value = msg; clearTimeout(toastTimer); toastTimer =
async function load() {
loading.value = true
const r = await api('/banned-words')
const qs = new URLSearchParams({
limit: String(pageSize),
offset: String((page.value - 1) * pageSize),
})
const r = await api('/banned-words?' + qs.toString())
items.value = r.data?.data || []
total.value = Number(r.data?.total ?? items.value.length)
loading.value = false
// Deleting the last row of the last page can leave the cursor past the end.
if (page.value > totalPages.value) page.value = totalPages.value
}
async function add() {
@@ -79,14 +86,13 @@ async function delSelected() {
load()
}
// pagination (client-side; the full list arrives in one payload)
// Server-side pagination: items IS the current page.
const page = ref(1)
const pageSize = 20
const totalPages = computed(() => Math.max(1, Math.ceil(items.value.length / pageSize)))
const pagedItems = computed(() => {
const start = (Math.min(page.value, totalPages.value) - 1) * pageSize
return items.value.slice(start, start + pageSize)
})
const total = ref(0)
const totalPages = computed(() => Math.max(1, Math.ceil(total.value / pageSize)))
const pagedItems = computed(() => items.value)
watch(page, () => { load() })
function goPage(n) {
const t = Math.max(1, Math.min(totalPages.value, n))
if (t !== page.value) page.value = t
@@ -156,7 +162,7 @@ onMounted(load)
</tbody>
</table>
<div v-if="totalPages > 1" class="flex items-center justify-between px-5 py-3 border-t border-white/[0.06] text-xs text-white/45">
<div><span class="tabular-nums text-white/75">{{ items.length ? (Math.min(page, totalPages) - 1) * pageSize + 1 : 0 }}{{ Math.min(items.length, Math.min(page, totalPages) * pageSize) }}</span><span class="ml-1">/ {{ items.length }} </span></div>
<div><span class="tabular-nums text-white/75">{{ total ? (Math.min(page, totalPages) - 1) * pageSize + 1 : 0 }}{{ Math.min(total, Math.min(page, totalPages) * pageSize) }}</span><span class="ml-1">/ {{ total }} </span></div>
<div class="flex items-center gap-1">
<template v-for="(n, i) in pageNumbers" :key="i">
<span v-if="n === null" class="px-1 text-white/30"></span>