170 lines
4.4 KiB
Vue
170 lines
4.4 KiB
Vue
<!-- Author: fruit.com.cn -->
|
|
<!-- 剧集转码状态、进度、错误与重新转码操作 -->
|
|
|
|
<script setup lang="ts">
|
|
import type { EpisodeTranscodeItem } from '@/api/admin/types'
|
|
import { AppIcon } from '@/components/AppIcon'
|
|
import { AppIcons } from '@/constants/icons'
|
|
import { useI18n } from '@/hooks/web/useI18n'
|
|
import { formatDateTime } from '@/utils/format'
|
|
import type { TranscodeProgressStatus, TranscodeTagType } from './episodeTranscodeUi'
|
|
|
|
interface StatusView {
|
|
loading: boolean
|
|
errorMessage: string
|
|
hasMedia: boolean
|
|
retriggering: boolean
|
|
isProcessing: boolean
|
|
statusLabel: string
|
|
statusType: TranscodeTagType
|
|
progressStatus: TranscodeProgressStatus
|
|
progress: number
|
|
}
|
|
|
|
defineProps<{
|
|
detail: EpisodeTranscodeItem | null
|
|
view: StatusView
|
|
}>()
|
|
|
|
const emit = defineEmits<{
|
|
retry: []
|
|
retrigger: []
|
|
}>()
|
|
|
|
const { t } = useI18n()
|
|
</script>
|
|
|
|
<template>
|
|
<p class="episode-transcode-status__description">
|
|
{{ t('episodeTranscode.description') }}
|
|
</p>
|
|
<el-skeleton v-if="view.loading && !detail" :rows="4" animated />
|
|
<div v-else-if="view.errorMessage" class="episode-transcode-status__error">
|
|
<el-alert type="error" :title="view.errorMessage" :closable="false" show-icon />
|
|
<el-button size="small" @click="emit('retry')">
|
|
<AppIcon :icon="AppIcons.refresh" :size="16" />
|
|
{{ t('episodeTranscode.retryLoad') }}
|
|
</el-button>
|
|
</div>
|
|
<el-empty
|
|
v-else-if="detail && !view.hasMedia"
|
|
:description="detail.errorMsg || t('episodeTranscode.noMedia')"
|
|
:image-size="72"
|
|
/>
|
|
<template v-else-if="detail">
|
|
<div class="episode-transcode-status__summary">
|
|
<div class="episode-transcode-status__metric">
|
|
<span>{{ t('episodeTranscode.statusLabel') }}</span>
|
|
<el-tag :type="view.statusType" effect="light">{{ view.statusLabel }}</el-tag>
|
|
</div>
|
|
<div class="episode-transcode-status__metric">
|
|
<span>{{ t('episodeTranscode.progress') }}</span>
|
|
<b>{{ view.progress }}%</b>
|
|
</div>
|
|
<div class="episode-transcode-status__metric">
|
|
<span>{{ t('episodeTranscode.retryCount') }}</span>
|
|
<b>{{ detail.retryCount || 0 }}</b>
|
|
</div>
|
|
<div class="episode-transcode-status__metric">
|
|
<span>{{ t('episodeTranscode.updatedAt') }}</span>
|
|
<b>{{ formatDateTime(detail.updatedAt) }}</b>
|
|
</div>
|
|
<el-button
|
|
class="episode-transcode-status__retry"
|
|
type="primary"
|
|
plain
|
|
:loading="view.retriggering"
|
|
:disabled="!view.hasMedia || view.isProcessing || view.retriggering"
|
|
@click="emit('retrigger')"
|
|
>
|
|
<AppIcon :icon="AppIcons.restart" :size="16" />
|
|
{{
|
|
view.retriggering ? t('episodeTranscode.reprocessing') : t('episodeTranscode.reprocess')
|
|
}}
|
|
</el-button>
|
|
</div>
|
|
<el-progress
|
|
class="episode-transcode-status__progress"
|
|
:percentage="view.progress"
|
|
:status="view.progressStatus"
|
|
:stroke-width="8"
|
|
/>
|
|
<p v-if="view.isProcessing && view.progress === 0" class="episode-transcode-status__waiting">
|
|
{{ t('episodeTranscode.waitingProgress') }}
|
|
</p>
|
|
<el-alert
|
|
v-if="detail.errorMsg"
|
|
class="episode-transcode-status__error-alert"
|
|
type="error"
|
|
:title="detail.errorMsg"
|
|
:closable="false"
|
|
show-icon
|
|
/>
|
|
</template>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.episode-transcode-status__description {
|
|
margin: 0 0 14px;
|
|
font-size: 12px;
|
|
color: var(--el-text-color-secondary);
|
|
}
|
|
|
|
.episode-transcode-status__error {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
gap: 10px;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.episode-transcode-status__summary {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 18px;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.episode-transcode-status__metric {
|
|
display: flex;
|
|
font-size: 12px;
|
|
color: var(--el-text-color-secondary);
|
|
align-items: center;
|
|
gap: 8px;
|
|
}
|
|
|
|
.episode-transcode-status__metric b {
|
|
font-size: 14px;
|
|
color: var(--el-text-color-primary);
|
|
font-variant-numeric: tabular-nums;
|
|
}
|
|
|
|
.episode-transcode-status__retry {
|
|
margin-left: auto;
|
|
}
|
|
|
|
.episode-transcode-status__progress {
|
|
margin-top: 12px;
|
|
}
|
|
|
|
.episode-transcode-status__waiting {
|
|
margin: 8px 0 0;
|
|
font-size: 12px;
|
|
color: var(--el-color-warning);
|
|
}
|
|
|
|
.episode-transcode-status__error-alert {
|
|
margin-top: 12px;
|
|
}
|
|
|
|
@media (width <= 600px) {
|
|
.episode-transcode-status__summary {
|
|
align-items: flex-start;
|
|
}
|
|
|
|
.episode-transcode-status__retry {
|
|
width: 100%;
|
|
margin-left: 0;
|
|
}
|
|
}
|
|
</style>
|