From a28eaa45140fb56a73b50ba1f1e8e7a12af66933 Mon Sep 17 00:00:00 2001 From: Zhou Weidong <502333560@qq.com> Date: Wed, 21 Oct 2026 23:00:08 +0800 Subject: [PATCH] =?UTF-8?q?feat(admin):=20=E5=89=A7=E9=9B=86=E5=88=97?= =?UTF-8?q?=E8=A1=A8=E5=88=86=E9=A1=B5=E9=BB=98=E8=AE=A4=E6=AF=8F=E9=A1=B5?= =?UTF-8?q?100=E6=9D=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../EpisodeManagementView.vue | 73 ++++++++++++++++--- 1 file changed, 63 insertions(+), 10 deletions(-) diff --git a/src/views/contentManagement/EpisodeManagementView.vue b/src/views/contentManagement/EpisodeManagementView.vue index 3686df7..b2cad80 100644 --- a/src/views/contentManagement/EpisodeManagementView.vue +++ b/src/views/contentManagement/EpisodeManagementView.vue @@ -15,6 +15,9 @@ import BatchUploadDialog from './upload/BatchUploadDialog.vue' import EpisodeFormDialog from './upload/EpisodeFormDialog.vue' import { listPendingSessions } from './upload/uploadSessions' +const DEFAULT_PAGE_SIZE = 100 +const PAGE_SIZE_OPTIONS = [50, 100, 200] + const route = useRoute() const { can } = useRbac() const { t } = useI18n() @@ -23,6 +26,8 @@ const loading = ref(false) const dramas = ref([]) const episodes = ref([]) const selectedDramaId = ref(undefined) +const pageIndex = ref(1) +const pageSize = ref(DEFAULT_PAGE_SIZE) const batchUploadVisible = ref(false) const previewVisible = ref(false) const previewEpisode = ref(null) @@ -34,6 +39,17 @@ const existingEpisodeNumbers = computed(() => episodes.value.map((item) => Number(item.number)).filter((n) => Number.isFinite(n)) ) +const pagedEpisodes = computed(() => { + const start = (pageIndex.value - 1) * pageSize.value + return episodes.value.slice(start, start + pageSize.value) +}) + +const showPagination = computed(() => { + const total = episodes.value.length + if (total <= 0) return false + return Math.ceil(total / pageSize.value) > 1 +}) + async function loadDramas() { const res = await pageDramasApi({ pageIndex: 1, pageSize: 200 }) dramas.value = res.data?.list || [] @@ -55,11 +71,19 @@ async function loadEpisodes() { try { const res = await listEpisodesApi(selectedDramaId.value) episodes.value = res.data || [] + clampPageIndex() } finally { loading.value = false } } +/** 刷新后若当前页越界(如删除末页最后一条),夹到最后一页。 */ +function clampPageIndex() { + const total = episodes.value.length + const maxPage = Math.max(1, Math.ceil(total / pageSize.value) || 1) + if (pageIndex.value > maxPage) pageIndex.value = maxPage +} + function nextNumber() { return episodes.value.reduce((max, item) => Math.max(max, item.number || 0), 0) + 1 } @@ -122,10 +146,24 @@ function stopThumb(event) { } } +function episodeIndexInFullList(row) { + return episodes.value.findIndex((item) => item.id === row.id) +} + +function canMoveUp(row) { + return episodeIndexInFullList(row) > 0 +} + +function canMoveDown(row) { + const index = episodeIndexInFullList(row) + return index >= 0 && index < episodes.value.length - 1 +} + /** 上移/下移后把新顺序整表提交,由后端重排 sort。 */ -async function move(index, offset) { +async function move(row, offset) { + const index = episodeIndexInFullList(row) const target = index + offset - if (target < 0 || target >= episodes.value.length) return + if (index < 0 || target < 0 || target >= episodes.value.length) return const next = [...episodes.value] const [moved] = next.splice(index, 1) next.splice(target, 0, moved) @@ -135,10 +173,15 @@ async function move(index, offset) { } async function onDramaChange() { + pageIndex.value = 1 await loadEpisodes() openBatchIfPendingSessions() } +function handleSizeChange() { + pageIndex.value = 1 +} + /** 进入页面或切换短剧时,若有 24h 内未完成上传则打开批量上传弹窗以提示续传。 */ function openBatchIfPendingSessions() { if (!selectedDramaId.value || !can('episode:upload')) return @@ -202,11 +245,10 @@ onMounted(async () => {

剧集列表({{ episodes.length }})

按列表顺序播放

+ > { >