feat(subscribe-card): render progress with backend completed_episode (#475)

This commit is contained in:
InfinityPacer
2026-05-22 19:39:07 +08:00
committed by GitHub
parent cc8d5cf931
commit dcf0924c73
6 changed files with 88 additions and 11 deletions

View File

@@ -46,6 +46,8 @@ export interface Subscribe {
start_episode?: number
// 缺失集数
lack_episode?: number
// 已完成集数(普通订阅 = 已入库集数,洗版订阅 = 起始集前 + [start, total] 范围内 priority==100 命中数)
completed_episode?: number
// 附加信息
note?: string
// 状态N-新建 R-订阅中 P-待定 S-暂停
@@ -64,6 +66,8 @@ export interface Subscribe {
search_imdbid?: any
// 当前优先级
current_priority: number
// 洗版时已下载剧集的优先级状态
episode_priority?: Record<string, number>
// 保存目录
save_path?: string
// 时间

View File

@@ -79,18 +79,67 @@ const bestVersionModeLabel = computed(() => {
: t('subscribe.bestVersionEpisodeShort')
})
// 已下载集数total_episode - lack_episode
const downloadedEpisode = computed(() => {
const total = props.media?.total_episode || 0
if (!total) return 0
return Math.min(Math.max(total - (props.media?.lack_episode || 0), 0), total)
})
// 是否为洗版订阅(影响进度条与 tooltip 的展示分支)
const isBestVersion = computed(() => isEnabledFlag(props.media?.best_version) && isTvSubscribe(props.media))
// 已洗版集数:取后端派生字段 completed_episode。普通订阅下其值等于已下载集数洗版订阅下为
// (start-1) + [start, total] 范围内 priority==100 命中数。
const completedEpisode = computed(() => {
const total = props.media?.total_episode || 0
return Math.min(Math.max(props.media?.completed_episode ?? 0, 0), total)
})
// 卡片主文案:已下载集数 / 总集数
const subscribeProgressText = computed(() => {
const total = props.media?.total_episode || 0
if (!total) return ''
return `${downloadedEpisode.value} / ${total}`
})
// 订阅卡片 hover 文案:
// - 普通订阅:「已下载 X · 共 Y 集」
// - 洗版订阅:「已下载 X · 已洗版 N · 共 Y 集」
const subscribeProgressTooltip = computed(() => {
const total = props.media?.total_episode || 0
if (!total) return ''
if (isBestVersion.value) {
return t('subscribe.bestVersionEpisodeProgressTooltip', {
completed: completedEpisode.value,
downloaded: downloadedEpisode.value,
total,
})
}
return t('subscribe.subscribeProgressTooltip', { downloaded: downloadedEpisode.value, total })
})
// 图片加载完成响应
function imageLoadHandler() {
imageLoaded.value = true
}
// 计算百分
// 进度条 model 段百分比:洗版订阅表示"已洗版"占比(亮段),普通订阅表示"已下载"占
function getPercentage() {
if (props.media?.total_episode === 0) return 0
const total = props.media?.total_episode || 0
if (!total) return 0
const value = isBestVersion.value ? completedEpisode.value : downloadedEpisode.value
return Math.round((value / total) * 100)
}
return Math.round(
(((props.media?.total_episode ?? 0) - (props.media?.lack_episode ?? 0)) / (props.media?.total_episode ?? 1)) * 100,
)
// 洗版进度条的 buffer 段百分比:表示"已下载"的占比,叠在底色之上、高亮段之外。
// 普通订阅 buffer 与 model 等值(视觉上呈单段),此函数仅在洗版场景被模板调用。
function getBufferPercentage() {
const total = props.media?.total_episode || 0
if (!isBestVersion.value || !total) return 0
return Math.round((downloadedEpisode.value / total) * 100)
}
// 删除订阅
@@ -444,9 +493,12 @@ function handleCardClick() {
icon="mdi-progress-download"
color="white"
/>
<div v-if="props.media?.season" class="flex-shrink-0 text-subtitle-2 me-2 text-white">
{{ (props.media?.total_episode || 0) - (props.media?.lack_episode || 0) }} /
{{ props.media?.total_episode }}
<!-- 守卫改用 total_episode电视剧订阅可能不带 season 字段旧数据或自定义来源仍应展示集数进度 -->
<div v-if="props.media?.total_episode" class="flex-shrink-0 text-subtitle-2 me-2 text-white">
{{ subscribeProgressText }}
<VTooltip v-if="subscribeProgressTooltip" activator="parent" location="top">
{{ subscribeProgressTooltip }}
</VTooltip>
</div>
<VChip
v-if="bestVersionModeLabel"
@@ -473,8 +525,22 @@ function handleCardClick() {
{{ lastUpdateText }}
</VCardText>
<div class="w-full absolute bottom-0">
<!--
分集洗版模式底色保持深绿buffer 段显示"已下载未洗版"为浅绿model 段显示"已洗版完成"为亮绿
形成两段语义其余订阅维持原有单段进度条
-->
<VProgressLinear
v-if="getPercentage() > 0"
v-if="isBestVersion && getBufferPercentage() > 0"
:model-value="getPercentage()"
:buffer-value="getBufferPercentage()"
bg-color="success"
bg-opacity="0.25"
color="success"
buffer-color="success"
buffer-opacity="0.55"
/>
<VProgressLinear
v-else-if="getPercentage() > 0"
:model-value="getPercentage()"
bg-color="success"
color="success"

View File

@@ -986,6 +986,8 @@ export default {
bestVersion: 'Version Upgrading',
bestVersionEpisodeShort: 'Episode',
bestVersionWholeShort: 'Full',
bestVersionEpisodeProgressTooltip: 'Upgraded {completed} · Downloaded {downloaded} · Total {total}',
subscribeProgressTooltip: 'Downloaded {downloaded} · Total {total}',
completed: 'Completed',
subscribing: 'Subscribing',
notStarted: 'Not Started',

View File

@@ -981,6 +981,8 @@ export default {
bestVersion: '洗版中',
bestVersionEpisodeShort: '分集',
bestVersionWholeShort: '全集',
bestVersionEpisodeProgressTooltip: '已洗版 {completed} · 已下载 {downloaded} · 共 {total} 集',
subscribeProgressTooltip: '已下载 {downloaded} · 共 {total} 集',
completed: '订阅完成',
subscribing: '订阅中',
notStarted: '未开始',

View File

@@ -981,6 +981,8 @@ export default {
bestVersion: '洗版中',
bestVersionEpisodeShort: '分集',
bestVersionWholeShort: '全集',
bestVersionEpisodeProgressTooltip: '已洗版 {completed} · 已下載 {downloaded} · 共 {total} 集',
subscribeProgressTooltip: '已下載 {downloaded} · 共 {total} 集',
completed: '訂閱完成',
subscribing: '訂閱中',
notStarted: '未開始',

View File

@@ -109,10 +109,11 @@ function getSubscribeStatus(subscribe: Subscribe) {
return 'all'
}
// 电视剧根据集数情况判断
// 电视剧根据集数情况判断completed_episode 由后端按订阅类型派生
// (普通=已入库集数,洗版=起始集前 + [start, total] 范围内 priority==100 命中)
if (subscribe.total_episode && subscribe.total_episode > 0) {
const lackEpisode = subscribe.lack_episode || 0
const completedEpisode = subscribe.total_episode - lackEpisode
const completedEpisode = subscribe.completed_episode ?? 0
if (lackEpisode === 0) {
return 'completed' // 订阅完成