feat(creator-center): 分集支持视频预览与表格横向滚动

This commit is contained in:
Zhou Weidong committed 2026-11-09 10:27:41 +08:00
1 parent 3c730c7d33
commit 71ee469563
2 files changed
+163 -136

No files matched your search

+162 -135
View File
@@ -1,7 +1,7 @@
<!-- Author: fruit.com.cn --> <!-- Author: fruit.com.cn -->
<script setup> <script setup>
import { computed } from 'vue' import { computed, ref } from 'vue'
import { AppIcons } from '@/constants/icons' import { AppIcons } from '@/constants/icons'
import { AppImage } from '@/components/AppImage' import { AppImage } from '@/components/AppImage'
import PageHeading from '@/views/components/PageHeading.vue' import PageHeading from '@/views/components/PageHeading.vue'
@@ -45,7 +45,6 @@ const {
moveEpisode, moveEpisode,
uploadVideo, uploadVideo,
uploadCover, uploadCover,
hasResumeSession,
submit, submit,
withdraw withdraw
} = useDramaEdit() } = useDramaEdit()
@@ -62,6 +61,16 @@ function back() {
window.history.back() window.history.back()
} }
/* ---------- 分集视频预览 ---------- */
const videoPreviewVisible = ref(false)
const videoPreviewUrl = ref('')
function playEpisode(row) {
if (!row.videoUrl) return
videoPreviewUrl.value = row.videoUrl
videoPreviewVisible.value = true
}
/** el-upload 的 http-request 回调:拿到原始 File 后交给统一的(可续传)上传逻辑 */ /** el-upload 的 http-request 回调:拿到原始 File 后交给统一的(可续传)上传逻辑 */
function requestVideo(row, options) { function requestVideo(row, options) {
return uploadVideo(row, options.file) return uploadVideo(row, options.file)
@@ -123,15 +132,9 @@ function requestDramaCover(options) {
<el-form-item label="作品名称" required> <el-form-item label="作品名称" required>
<el-input v-model="infoForm.title" maxlength="64" /> <el-input v-model="infoForm.title" maxlength="64" />
</el-form-item> </el-form-item>
<el-form-item label="副标题">
<el-input v-model="infoForm.subtitle" maxlength="64" />
</el-form-item>
<el-form-item label="题材"> <el-form-item label="题材">
<el-input v-model="infoForm.genre" maxlength="32" placeholder="例如:都市情感" /> <el-input v-model="infoForm.genre" maxlength="32" placeholder="例如:都市情感" />
</el-form-item> </el-form-item>
<el-form-item label="语言">
<el-input v-model="infoForm.language" maxlength="16" placeholder="zh-CN / id-ID" />
</el-form-item>
</div> </div>
<el-form-item label="简介"> <el-form-item label="简介">
<el-input <el-input
@@ -163,13 +166,6 @@ function requestDramaCover(options) {
</div> </div>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item label="预告片地址">
<el-input
v-model="infoForm.trailerUrl"
maxlength="512"
placeholder="整剧一支预告片,可留空"
/>
</el-form-item>
</div> </div>
<el-button <el-button
v-if="canEdit" v-if="canEdit"
@@ -202,80 +198,92 @@ function requestDramaCover(options) {
show-icon show-icon
:title="resumeHint" :title="resumeHint"
/> />
<el-table :data="episodes" row-key="id" border class="drama-el-table" empty-text="还没有分集"> <div class="creator-table-scroll creator-table-scroll--episodes">
<el-table-column prop="number" label="集号" width="70" /> <el-table
<el-table-column label="封面" width="88"> :data="episodes"
<template #default="{ row }"> row-key="id"
<div class="creator-episode-cover"> border
<AppImage class="drama-el-table"
v-if="row.cover" style="min-width: 1150px"
:src="row.cover" empty-text="还没有分集"
:preview-list="episodeCoverPreviewList" >
:initial-index="episodeCoverPreviewIndex(row)" <el-table-column prop="number" label="集号" width="70" />
fit="cover" <el-table-column label="封面" width="88">
class="creator-episode-image" <template #default="{ row }">
:alt="row.title" <div class="creator-episode-cover">
/> <AppImage
<span v-else>无</span> v-if="row.cover"
</div> :src="row.cover"
</template> :preview-list="episodeCoverPreviewList"
</el-table-column> :initial-index="episodeCoverPreviewIndex(row)"
<el-table-column prop="title" label="标题" min-width="150" show-overflow-tooltip /> fit="cover"
<el-table-column prop="duration" label="时长" width="90" /> class="creator-episode-image"
<el-table-column label="片源" min-width="120"> :alt="row.title"
<template #default="{ row }"> />
<span class="console-muted">{{ row.videoUrl ? '已上传' : '未上传' }}</span> <span v-else>无</span>
</template> </div>
</el-table-column> </template>
<el-table-column label="状态" width="90"> </el-table-column>
<template #default="{ row }"> <el-table-column prop="title" label="标题" min-width="150" show-overflow-tooltip />
<el-tag <el-table-column prop="duration" label="时长" width="90" />
size="small" <el-table-column label="片源" min-width="120">
effect="light" <template #default="{ row }">
:type="row.status === 'published' ? 'success' : 'info'" <el-button v-if="row.videoUrl" link type="primary" @click="playEpisode(row)"
> >播放</el-button
{{ row.statusText }} >
</el-tag> <span v-else class="console-muted">未上传</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" width="300" fixed="right"> <el-table-column label="状态" width="90">
<template #default="{ row, $index }"> <template #default="{ row }">
<div class="table-actions"> <el-tag
<el-button
size="small" size="small"
:disabled="!editable || $index === 0" effect="light"
@click="moveEpisode(row, -1)" :type="row.status === 'published' ? 'success' : 'info'"
>上移</el-button
> >
<el-button {{ row.statusText }}
size="small" </el-tag>
:disabled="!editable || $index === episodes.length - 1" </template>
@click="moveEpisode(row, 1)" </el-table-column>
>下移</el-button <el-table-column label="操作" width="340">
> <template #default="{ row, $index }">
<el-button size="small" :disabled="!editable" @click="openEpisode(row)" <div class="table-actions">
>编辑</el-button <el-button
> size="small"
<el-upload :disabled="!editable || $index === 0"
v-if="canUpload" @click="moveEpisode(row, -1)"
:show-file-list="false" >上移</el-button
accept="video/*" >
:http-request="(options) => requestVideo(row, options)" <el-button
:disabled="!editable || uploadingId !== null" size="small"
> :disabled="!editable || $index === episodes.length - 1"
<el-button size="small">{{ hasResumeSession ? '继续上传' : '上传视频' }}</el-button> @click="moveEpisode(row, 1)"
</el-upload> >下移</el-button
<el-button >
type="danger" <el-button size="small" :disabled="!editable" @click="openEpisode(row)"
size="small" >编辑</el-button
:disabled="!editable" >
@click="removeEpisode(row)" <el-upload
>删除</el-button v-if="canUpload"
> :show-file-list="false"
</div> accept="video/*"
</template> :http-request="(options) => requestVideo(row, options)"
</el-table-column> :disabled="!editable || uploadingId !== null"
</el-table> >
<el-button size="small">上传视频</el-button>
</el-upload>
<el-button
type="danger"
size="small"
:disabled="!editable"
@click="removeEpisode(row)"
>删除</el-button
>
</div>
</template>
</el-table-column>
</el-table>
</div>
<p v-if="uploadingId !== null" class="creator-upload-hint" <p v-if="uploadingId !== null" class="creator-upload-hint"
>上传中 {{ uploadPercent }}%(分片上传,可断点续传)</p >上传中 {{ uploadPercent }}%(分片上传,可断点续传)</p
> >
@@ -283,56 +291,75 @@ function requestDramaCover(options) {
<section class="panel"> <section class="panel">
<h3 class="creator-section-title">提交记录</h3> <h3 class="creator-section-title">提交记录</h3>
<el-table <div class="creator-table-scroll creator-table-scroll--submissions">
:data="submissions" <el-table
row-key="id" :data="submissions"
border row-key="id"
class="drama-el-table" border
empty-text="还没有提交记录" class="drama-el-table"
> style="min-width: 1000px"
<el-table-column prop="version" label="版本" width="70" /> empty-text="还没有提交记录"
<el-table-column label="类型" width="100"> >
<template #default="{ row }">{{ submissionTypeText(row.type) }}</template> <el-table-column prop="version" label="版本" width="70" />
</el-table-column> <el-table-column label="类型" width="100">
<el-table-column label="状态" width="100"> <template #default="{ row }">{{ submissionTypeText(row.type) }}</template>
<template #default="{ row }"> </el-table-column>
<el-tag size="small" :type="submissionStatusMeta(row.status).tag" effect="light"> <el-table-column label="状态" width="100">
{{ submissionStatusMeta(row.status).label }} <template #default="{ row }">
</el-tag> <el-tag size="small" :type="submissionStatusMeta(row.status).tag" effect="light">
</template> {{ submissionStatusMeta(row.status).label }}
</el-table-column> </el-tag>
<el-table-column </template>
prop="submitAt" </el-table-column>
label="提交时间" <el-table-column
min-width="165" prop="submitAt"
:formatter="dateCell" label="提交时间"
show-overflow-tooltip min-width="165"
/> :formatter="dateCell"
<el-table-column show-overflow-tooltip
prop="reviewAt" />
label="审核时间" <el-table-column
min-width="165" prop="reviewAt"
:formatter="dateCell" label="审核时间"
show-overflow-tooltip min-width="165"
/> :formatter="dateCell"
<el-table-column prop="reviewNote" label="审核意见" min-width="200" show-overflow-tooltip /> show-overflow-tooltip
<el-table-column label="操作" width="110" fixed="right"> />
<template #default="{ row }"> <el-table-column
<div class="table-actions"> prop="reviewNote"
<el-button label="审核意见"
v-if="canEdit && ['SUBMITTED', 'REVIEWING'].includes(row.status)" min-width="200"
type="danger" show-overflow-tooltip
size="small" />
@click="withdraw(row.id)" <el-table-column label="操作" width="110">
>撤回</el-button <template #default="{ row }">
> <div class="table-actions">
<span v-else class="console-muted">—</span> <el-button
</div> v-if="canEdit && ['SUBMITTED', 'REVIEWING'].includes(row.status)"
</template> type="danger"
</el-table-column> size="small"
</el-table> @click="withdraw(row.id)"
>撤回</el-button
>
<span v-else class="console-muted">—</span>
</div>
</template>
</el-table-column>
</el-table>
</div>
</section> </section>
<el-dialog v-model="videoPreviewVisible" title="视频预览" width="720px" append-to-body>
<video
v-if="videoPreviewUrl"
:src="videoPreviewUrl"
controls
autoplay
playsinline
class="creator-video-preview"
></video>
</el-dialog>
<el-dialog <el-dialog
v-model="episodeVisible" v-model="episodeVisible"
:title="episodeEditingId ? '编辑分集' : '新增分集'" :title="episodeEditingId ? '编辑分集' : '新增分集'"
@@ -259,7 +259,7 @@ export function useDramaEdit() {
ElMessage.success('视频已上传并挂到该分集') ElMessage.success('视频已上传并挂到该分集')
await loadEpisodes() await loadEpisodes()
} catch { } catch {
resumeHint.value = `「${file.name}」上传中断,进度已记住,可点「继续上传」接着传` resumeHint.value = `「${file.name}」上传中断,进度已记住;重新选择同一个文件即可续传`
} finally { } finally {
uploadingId.value = null uploadingId.value = null
uploadPercent.value = 0 uploadPercent.value = 0