|
|
|
|
@ -1,6 +1,6 @@
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
import { computed, onMounted, reactive, ref, watch } from 'vue'
|
|
|
|
|
import { useRoute } from 'vue-router'
|
|
|
|
|
import { computed, reactive, ref, watch } from 'vue'
|
|
|
|
|
import { useRoute, useRouter } from 'vue-router'
|
|
|
|
|
import {
|
|
|
|
|
getApiBase,
|
|
|
|
|
readReviewerSession,
|
|
|
|
|
@ -25,6 +25,7 @@ export interface ReviewApplicationRow {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const route = useRoute()
|
|
|
|
|
const router = useRouter()
|
|
|
|
|
const slug = computed(() => String(route.params.slug ?? '').trim())
|
|
|
|
|
|
|
|
|
|
const rows = ref<ReviewApplicationRow[]>([])
|
|
|
|
|
@ -47,6 +48,31 @@ const meta = ref({
|
|
|
|
|
const page = ref(1)
|
|
|
|
|
const perPage = ref(15)
|
|
|
|
|
|
|
|
|
|
function parsePositiveInt(v: unknown, fallback: number): number {
|
|
|
|
|
const n = typeof v === 'string' ? Number(v) : typeof v === 'number' ? v : NaN
|
|
|
|
|
return Number.isInteger(n) && n > 0 ? n : fallback
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function listReturnQuery(): Record<string, string> {
|
|
|
|
|
const q: Record<string, string> = {}
|
|
|
|
|
if (page.value > 1) q.page = String(page.value)
|
|
|
|
|
if (perPage.value !== 15) q.per_page = String(perPage.value)
|
|
|
|
|
return q
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function applyListQueryFromRoute(): void {
|
|
|
|
|
page.value = parsePositiveInt(route.query.page, 1)
|
|
|
|
|
perPage.value = parsePositiveInt(route.query.per_page, 15)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function syncListQueryToRoute(): void {
|
|
|
|
|
const next = listReturnQuery()
|
|
|
|
|
const curPage = typeof route.query.page === 'string' ? route.query.page : undefined
|
|
|
|
|
const curPer = typeof route.query.per_page === 'string' ? route.query.per_page : undefined
|
|
|
|
|
if (curPage === next.page && curPer === next.per_page) return
|
|
|
|
|
void router.replace({ query: next })
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function buildListParams(): URLSearchParams {
|
|
|
|
|
const qs = new URLSearchParams()
|
|
|
|
|
qs.set('competition_slug', slug.value)
|
|
|
|
|
@ -125,7 +151,6 @@ function updateResultHint() {
|
|
|
|
|
|
|
|
|
|
function refresh(p = page.value) {
|
|
|
|
|
page.value = p
|
|
|
|
|
void fetchList()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function resetFilters() {
|
|
|
|
|
@ -134,9 +159,12 @@ function resetFilters() {
|
|
|
|
|
refresh(1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
watch([slug, page, perPage], () => void fetchList())
|
|
|
|
|
applyListQueryFromRoute()
|
|
|
|
|
|
|
|
|
|
onMounted(() => void fetchList())
|
|
|
|
|
watch([slug, page, perPage], () => {
|
|
|
|
|
syncListQueryToRoute()
|
|
|
|
|
void fetchList()
|
|
|
|
|
}, { immediate: true })
|
|
|
|
|
|
|
|
|
|
const pageHint = computed(() => {
|
|
|
|
|
if (loading.value) return '加载中…'
|
|
|
|
|
@ -150,7 +178,6 @@ function onPageChange(p: number) {
|
|
|
|
|
function onPerPageChange(size: number) {
|
|
|
|
|
perPage.value = size
|
|
|
|
|
page.value = 1
|
|
|
|
|
void fetchList()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function rowIndex(i: number): number {
|
|
|
|
|
@ -234,7 +261,11 @@ function actionLabel(row: ReviewApplicationRow): string {
|
|
|
|
|
<td class="admin-actions-cell portal-sticky-right-1">
|
|
|
|
|
<router-link
|
|
|
|
|
class="btn btn-sm btn-outline-primary"
|
|
|
|
|
:to="{ name: 'reviewer-application-detail', params: { slug, id: String(row.id) } }"
|
|
|
|
|
:to="{
|
|
|
|
|
name: 'reviewer-application-detail',
|
|
|
|
|
params: { slug, id: String(row.id) },
|
|
|
|
|
query: listReturnQuery(),
|
|
|
|
|
}"
|
|
|
|
|
>
|
|
|
|
|
{{ actionLabel(row) }}
|
|
|
|
|
</router-link>
|
|
|
|
|
|