1
This commit is contained in:
@@ -4,16 +4,39 @@
|
||||
<template #header>
|
||||
<div class="header">
|
||||
<span>系列管理</span>
|
||||
<div>
|
||||
<div class="header-right">
|
||||
<el-input v-model="keyword" placeholder="搜索系列标题" clearable
|
||||
style="width: 200px; margin-right: 8px" @keyup.enter="load" />
|
||||
<el-button :loading="syncAllLoading" @click="syncAll">同步新剧</el-button>
|
||||
<el-button type="primary" @click="showCreate">+ 新建系列</el-button>
|
||||
|
||||
<el-dropdown trigger="click" @command="handleBatchCmd">
|
||||
<el-button :loading="batchLoading">批量更新 <el-icon class="el-icon--right"><arrow-down /></el-icon></el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item command="rebuild" :disabled="batchLoading">
|
||||
<el-icon><refresh-left /></el-icon> 重算集数(total_episodes)
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item command="syncDrama" :disabled="batchLoading">
|
||||
<el-icon><download /></el-icon> 同步短剧采集(新集数)
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item command="syncSources" :disabled="batchLoading">
|
||||
<el-icon><collection-tag /></el-icon> 同步视频采集源
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
|
||||
<el-button v-if="selectedIds.length" type="warning" plain
|
||||
style="margin-left: 8px"
|
||||
@click="showBatchEdit">批量编辑(已选 {{ selectedIds.length }})</el-button>
|
||||
|
||||
<el-button type="primary" style="margin-left: 8px" @click="showCreate">+ 新建系列</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-table :data="list" v-loading="loading" stripe>
|
||||
<el-table :data="list" v-loading="loading" stripe
|
||||
@selection-change="onSelectionChange">
|
||||
<el-table-column type="selection" width="42" />
|
||||
<el-table-column prop="id" label="ID" width="70" />
|
||||
<el-table-column prop="title" label="系列标题" min-width="160">
|
||||
<template #default="{ row }">
|
||||
@@ -106,12 +129,41 @@
|
||||
<el-button type="primary" :loading="submitting" @click="save">保存</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 批量编辑弹窗 -->
|
||||
<el-dialog v-model="batchDialogVisible" title="批量编辑系列" width="400px">
|
||||
<div style="margin-bottom: 12px; color: #606266; font-size: 13px">
|
||||
共选中 <b>{{ selectedIds.length }}</b> 个系列,只修改下面勾选的字段:
|
||||
</div>
|
||||
<el-form :model="batchForm" label-width="80px">
|
||||
<el-form-item label="状态">
|
||||
<el-switch v-model="batchForm.touchStatus" active-text="修改" inactive-text="不改" />
|
||||
<el-select v-if="batchForm.touchStatus" v-model="batchForm.status"
|
||||
style="width: 120px; margin-left: 12px">
|
||||
<el-option label="正常" :value="1" />
|
||||
<el-option label="隐藏" :value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="分类">
|
||||
<el-switch v-model="batchForm.touchCategory" active-text="修改" inactive-text="不改" />
|
||||
<el-select v-if="batchForm.touchCategory" v-model="batchForm.category_id"
|
||||
placeholder="请选择" style="width: 180px; margin-left: 12px">
|
||||
<el-option v-for="c in categories" :key="c.id" :label="c.name" :value="c.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="batchDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="batchSubmitting" @click="batchSave">保存</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, ref, onMounted } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { ArrowDown, RefreshLeft, Download, CollectionTag } from '@element-plus/icons-vue'
|
||||
import request from '@/api/request'
|
||||
|
||||
const list = ref([])
|
||||
@@ -125,13 +177,25 @@ const dialogVisible = ref(false)
|
||||
const editing = ref(null)
|
||||
const submitting = ref(false)
|
||||
const coverUploading = ref(false)
|
||||
const syncAllLoading = ref(false)
|
||||
const syncingId = ref(0)
|
||||
const selectedIds = ref([])
|
||||
const batchLoading = ref(false)
|
||||
const batchDialogVisible = ref(false)
|
||||
const batchSubmitting = ref(false)
|
||||
|
||||
const form = reactive({
|
||||
title: '', cover_url: '', description: '', category_id: 0,
|
||||
})
|
||||
|
||||
const batchForm = reactive({
|
||||
touchStatus: false, status: 1,
|
||||
touchCategory: false, category_id: 0,
|
||||
})
|
||||
|
||||
function onSelectionChange(rows) {
|
||||
selectedIds.value = rows.map(r => r.id)
|
||||
}
|
||||
|
||||
async function uploadCover(file) {
|
||||
if (!file || !file.raw) return
|
||||
const allowed = ['image/jpeg', 'image/png', 'image/webp', 'image/gif']
|
||||
@@ -247,20 +311,66 @@ async function syncOne(row) {
|
||||
}
|
||||
}
|
||||
|
||||
async function syncAll() {
|
||||
syncAllLoading.value = true
|
||||
// ---------- 批量操作 ----------
|
||||
|
||||
async function handleBatchCmd(cmd) {
|
||||
batchLoading.value = true
|
||||
try {
|
||||
await request({ url: '/admin/collection/sync-all', method: 'post', data: { pages: 2 } })
|
||||
ElMessage.success('已触发后台同步,稍后刷新查看')
|
||||
setTimeout(load, 15000)
|
||||
if (cmd === 'rebuild') {
|
||||
await ElMessageBox.confirm(
|
||||
'将遍历全部系列,按已发布视频真实数量重算 total_episodes。确定执行?',
|
||||
'确认', { type: 'warning' }
|
||||
)
|
||||
const r = await request({ url: '/admin/series/rebuild-counts', method: 'post' })
|
||||
ElMessage.success(`共 ${r.total} 个系列,修复了 ${r.fixed} 个`)
|
||||
load()
|
||||
} else if (cmd === 'syncDrama') {
|
||||
const r = await request({
|
||||
url: '/admin/collection/sync-all', method: 'post', data: { pages: 2 },
|
||||
})
|
||||
ElMessage.success(`已触发后台增量同步(pages=2),稍后刷新查看`)
|
||||
setTimeout(load, 15000)
|
||||
} else if (cmd === 'syncSources') {
|
||||
await ElMessageBox.confirm(
|
||||
'将同时触发所有 23 个视频采集源的全量同步(异步后台执行)。确定?',
|
||||
'确认', { type: 'warning' }
|
||||
)
|
||||
const r = await request({ url: '/admin/collection/sources/sync-all', method: 'post' })
|
||||
ElMessage.success(`已触发 ${r.started?.length || 0} 个采集源同步`)
|
||||
}
|
||||
} catch (e) {} finally {
|
||||
syncAllLoading.value = false
|
||||
batchLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function showBatchEdit() {
|
||||
Object.assign(batchForm, { touchStatus: false, status: 1, touchCategory: false, category_id: 0 })
|
||||
batchDialogVisible.value = true
|
||||
}
|
||||
|
||||
async function batchSave() {
|
||||
if (!batchForm.touchStatus && !batchForm.touchCategory) {
|
||||
ElMessage.warning('至少勾选一个要修改的字段')
|
||||
return
|
||||
}
|
||||
batchSubmitting.value = true
|
||||
try {
|
||||
const data = { series_ids: selectedIds.value }
|
||||
if (batchForm.touchStatus) data.status = batchForm.status
|
||||
if (batchForm.touchCategory) data.category_id = batchForm.category_id
|
||||
const r = await request({ url: '/admin/series/batch', method: 'put', data })
|
||||
ElMessage.success(`已更新 ${r.affected} 个系列`)
|
||||
batchDialogVisible.value = false
|
||||
load()
|
||||
} catch (e) {} finally {
|
||||
batchSubmitting.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.header { display: flex; justify-content: space-between; align-items: center; }
|
||||
.header-right { display: flex; align-items: center; }
|
||||
.title-col { display: flex; align-items: center; gap: 8px; }
|
||||
.cover { width: 40px; height: 40px; border-radius: 4px; object-fit: cover; }
|
||||
.cover-upload { display: flex; align-items: center; }
|
||||
|
||||
Reference in New Issue
Block a user