mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-05 07:28:37 +08:00
添加 SubscribeSeasonDialog 组件,实现媒体季订阅功能,包含季信息获取和缺失状态检查
This commit is contained in:
@@ -1,18 +1,18 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { PropType, Ref } from 'vue'
|
|
||||||
import { useToast } from 'vue-toast-notification'
|
|
||||||
import SubscribeEditDialog from '../dialog/SubscribeEditDialog.vue'
|
|
||||||
import { formatSeason, formatRating } from '@/@core/utils/formatters'
|
|
||||||
import api from '@/api'
|
|
||||||
import { doneNProgress, startNProgress } from '@/api/nprogress'
|
|
||||||
import type { MediaInfo, NotExistMediaInfo, Subscribe, MediaSeason, Site } from '@/api/types'
|
|
||||||
import router, { registerAbortController } from '@/router'
|
|
||||||
import noImage from '@images/no-image.jpeg'
|
import noImage from '@images/no-image.jpeg'
|
||||||
import tmdbImage from '@images/logos/tmdb.png'
|
import tmdbImage from '@images/logos/tmdb.png'
|
||||||
import doubanImage from '@images/logos/douban-black.png'
|
import doubanImage from '@images/logos/douban-black.png'
|
||||||
import bangumiImage from '@images/logos/bangumi.png'
|
import bangumiImage from '@images/logos/bangumi.png'
|
||||||
|
import api from '@/api'
|
||||||
|
import { useToast } from 'vue-toast-notification'
|
||||||
|
import { formatSeason, formatRating } from '@/@core/utils/formatters'
|
||||||
|
import { doneNProgress, startNProgress } from '@/api/nprogress'
|
||||||
|
import type { MediaInfo, Subscribe, MediaSeason, Site } from '@/api/types'
|
||||||
|
import router, { registerAbortController } from '@/router'
|
||||||
import { useUserStore } from '@/stores'
|
import { useUserStore } from '@/stores'
|
||||||
|
import SubscribeEditDialog from '../dialog/SubscribeEditDialog.vue'
|
||||||
import SearchSiteDialog from '@/components/dialog/SearchSiteDialog.vue'
|
import SearchSiteDialog from '@/components/dialog/SearchSiteDialog.vue'
|
||||||
|
import SubscribeSeasonDialog from '../dialog/SubscribeSeasonDialog.vue'
|
||||||
|
|
||||||
// 输入参数
|
// 输入参数
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -36,18 +36,12 @@ const isImageLoaded = ref(false)
|
|||||||
// 图片加载失败
|
// 图片加载失败
|
||||||
const imageLoadError = ref(false)
|
const imageLoadError = ref(false)
|
||||||
|
|
||||||
// TMDB识别标志
|
|
||||||
const tmdbFlag = ref(true)
|
|
||||||
|
|
||||||
// 当前订阅状态
|
// 当前订阅状态
|
||||||
const isSubscribed = ref(false)
|
const isSubscribed = ref(false)
|
||||||
|
|
||||||
// 本地存在状态
|
// 本地存在状态
|
||||||
const isExists = ref(false)
|
const isExists = ref(false)
|
||||||
|
|
||||||
// 各季缺失状态:0-已入库 1-部分缺失 2-全部缺失,没有数据也是已入库
|
|
||||||
const seasonsNotExisted = ref<{ [key: number]: number }>({})
|
|
||||||
|
|
||||||
// 订阅季弹窗
|
// 订阅季弹窗
|
||||||
const subscribeSeasonDialog = ref(false)
|
const subscribeSeasonDialog = ref(false)
|
||||||
|
|
||||||
@@ -57,9 +51,6 @@ const subscribeEditDialog = ref(false)
|
|||||||
// 订阅ID
|
// 订阅ID
|
||||||
const subscribeId = ref<number>()
|
const subscribeId = ref<number>()
|
||||||
|
|
||||||
// 季详情
|
|
||||||
const seasonInfos = ref<MediaSeason[]>([])
|
|
||||||
|
|
||||||
// 选中的订阅季
|
// 选中的订阅季
|
||||||
const seasonsSelected = ref<MediaSeason[]>([])
|
const seasonsSelected = ref<MediaSeason[]>([])
|
||||||
|
|
||||||
@@ -118,14 +109,6 @@ function getMediaId() {
|
|||||||
else return `${props.media?.mediaid_prefix}:${props.media?.media_id}`
|
else return `${props.media?.mediaid_prefix}:${props.media?.media_id}`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 订阅弹窗选择的多季
|
|
||||||
function subscribeSeasons() {
|
|
||||||
subscribeSeasonDialog.value = false
|
|
||||||
seasonsSelected.value.forEach(season => {
|
|
||||||
addSubscribe(season.season_number)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 角标颜色
|
// 角标颜色
|
||||||
function getChipColor(type: string) {
|
function getChipColor(type: string) {
|
||||||
if (type === '电影') return 'border-blue-500 bg-blue-600'
|
if (type === '电影') return 'border-blue-500 bg-blue-600'
|
||||||
@@ -136,24 +119,9 @@ function getChipColor(type: string) {
|
|||||||
// 添加订阅处理
|
// 添加订阅处理
|
||||||
async function handleAddSubscribe() {
|
async function handleAddSubscribe() {
|
||||||
if (props.media?.type === '电视剧') {
|
if (props.media?.type === '电视剧') {
|
||||||
// 查询所有季信息
|
// 弹出季选择列表,支持多选
|
||||||
await getMediaSeasons()
|
seasonsSelected.value = []
|
||||||
if (!seasonInfos.value || seasonInfos.value.length === 0) {
|
subscribeSeasonDialog.value = true
|
||||||
$toast.error(`${props.media?.title} 查询剧集信息失败!`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// 检查各季的缺失状态
|
|
||||||
await checkSeasonsNotExists()
|
|
||||||
if (!tmdbFlag.value) return
|
|
||||||
|
|
||||||
if (seasonInfos.value.length === 1) {
|
|
||||||
// 添加订阅
|
|
||||||
addSubscribe(1)
|
|
||||||
} else {
|
|
||||||
// 弹出季选择列表,支持多选
|
|
||||||
seasonsSelected.value = []
|
|
||||||
subscribeSeasonDialog.value = true
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// 电影
|
// 电影
|
||||||
addSubscribe()
|
addSubscribe()
|
||||||
@@ -161,15 +129,12 @@ async function handleAddSubscribe() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 调用API添加订阅,电视剧的话需要指定季
|
// 调用API添加订阅,电视剧的话需要指定季
|
||||||
async function addSubscribe(season = 0) {
|
async function addSubscribe(season: number = 0, best_version: number = 0) {
|
||||||
// 开始处理
|
// 开始处理
|
||||||
startNProgress()
|
startNProgress()
|
||||||
try {
|
try {
|
||||||
// 是否洗版
|
// 是否洗版
|
||||||
let best_version = isExists.value ? 1 : 0
|
if (!best_version && props.media?.type == '电影') best_version = isExists.value ? 1 : 0
|
||||||
if (season && props.media?.tmdb_id)
|
|
||||||
// 全部存在时洗版
|
|
||||||
best_version = !seasonsNotExisted.value[season] ? 1 : 0
|
|
||||||
// 请求API
|
// 请求API
|
||||||
const result: { [key: string]: any } = await api.post('subscribe/', {
|
const result: { [key: string]: any } = await api.post('subscribe/', {
|
||||||
name: props.media?.title,
|
name: props.media?.title,
|
||||||
@@ -300,48 +265,6 @@ async function checkSubscribe(season = 0) {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查所有季的缺失状态(数据库)
|
|
||||||
async function checkSeasonsNotExists() {
|
|
||||||
// 开始处理
|
|
||||||
startNProgress()
|
|
||||||
try {
|
|
||||||
const result: NotExistMediaInfo[] = await api.post('mediaserver/notexists', props.media)
|
|
||||||
if (result) {
|
|
||||||
result.forEach(item => {
|
|
||||||
// 0-已入库 1-部分缺失 2-全部缺失
|
|
||||||
let state = 0
|
|
||||||
if (item.episodes.length === 0) state = 2
|
|
||||||
else if (item.episodes.length < item.total_episode) state = 1
|
|
||||||
seasonsNotExisted.value[item.season] = state
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
$toast.error(`${props.media?.title}无法识别TMDB媒体信息!`)
|
|
||||||
tmdbFlag.value = false
|
|
||||||
} finally {
|
|
||||||
// 处理完成
|
|
||||||
doneNProgress()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 查询TMDB的所有季信息
|
|
||||||
async function getMediaSeasons() {
|
|
||||||
startNProgress()
|
|
||||||
try {
|
|
||||||
seasonInfos.value = await api.get('media/seasons', {
|
|
||||||
params: {
|
|
||||||
mediaid: getMediaId(),
|
|
||||||
title: props.media?.title,
|
|
||||||
year: props.media?.year,
|
|
||||||
season: props.media?.season,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error)
|
|
||||||
}
|
|
||||||
doneNProgress()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 查询订阅弹窗规则
|
// 查询订阅弹窗规则
|
||||||
async function queryDefaultSubscribeConfig() {
|
async function queryDefaultSubscribeConfig() {
|
||||||
// 非管理员不显示
|
// 非管理员不显示
|
||||||
@@ -350,9 +273,7 @@ async function queryDefaultSubscribeConfig() {
|
|||||||
let subscribe_config_url = ''
|
let subscribe_config_url = ''
|
||||||
if (props.media?.type === '电影') subscribe_config_url = 'system/setting/DefaultMovieSubscribeConfig'
|
if (props.media?.type === '电影') subscribe_config_url = 'system/setting/DefaultMovieSubscribeConfig'
|
||||||
else subscribe_config_url = 'system/setting/DefaultTvSubscribeConfig'
|
else subscribe_config_url = 'system/setting/DefaultTvSubscribeConfig'
|
||||||
|
|
||||||
const result: { [key: string]: any } = await api.get(subscribe_config_url)
|
const result: { [key: string]: any } = await api.get(subscribe_config_url)
|
||||||
|
|
||||||
if (result.data?.value) return result.data.value.show_edit_dialog
|
if (result.data?.value) return result.data.value.show_edit_dialog
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
@@ -366,24 +287,17 @@ function handleSubscribe() {
|
|||||||
else handleAddSubscribe()
|
else handleAddSubscribe()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 计算存在状态的颜色
|
// 订阅多季
|
||||||
function getExistColor(season: number) {
|
function subscribeSeasons(seasons: MediaSeason[], seasonNoExists: { [key: number]: number }) {
|
||||||
const state = seasonsNotExisted.value[season]
|
subscribeSeasonDialog.value = false
|
||||||
if (!state) return 'success'
|
seasonsSelected.value = seasons || []
|
||||||
|
seasonsSelected.value.forEach(season => {
|
||||||
if (state === 1) return 'warning'
|
let best_version = 0
|
||||||
else if (state === 2) return 'error'
|
if (season && props.media?.tmdb_id)
|
||||||
else return 'success'
|
// 全部存在时洗版
|
||||||
}
|
best_version = !seasonNoExists[season.season_number || 0] ? 1 : 0
|
||||||
|
addSubscribe(season.season_number, best_version)
|
||||||
// 计算存在状态的文本
|
})
|
||||||
function getExistText(season: number) {
|
|
||||||
const state = seasonsNotExisted.value[season]
|
|
||||||
if (!state) return '已入库'
|
|
||||||
|
|
||||||
if (state === 1) return '部分缺失'
|
|
||||||
else if (state === 2) return '缺失'
|
|
||||||
else return '已入库'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 打开详情页
|
// 打开详情页
|
||||||
@@ -496,26 +410,6 @@ const getImgUrl: Ref<string> = computed(() => {
|
|||||||
return url
|
return url
|
||||||
})
|
})
|
||||||
|
|
||||||
// 拼装季图片地址
|
|
||||||
function getSeasonPoster(posterPath: string) {
|
|
||||||
if (!posterPath) return ''
|
|
||||||
return `https://${globalSettings.TMDB_IMAGE_DOMAIN}/t/p/w500${posterPath}`
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将yyyy-mm-dd转换为yyyy年mm月dd日
|
|
||||||
function formatAirDate(airDate: string) {
|
|
||||||
if (!airDate) return ''
|
|
||||||
const date = new Date(airDate.replaceAll(/-/g, '/'))
|
|
||||||
return `${date.getFullYear()}年${date.getMonth() + 1}月${date.getDate()}日`
|
|
||||||
}
|
|
||||||
|
|
||||||
// 从yyyy-mm-dd中提取年份
|
|
||||||
function getYear(airDate: string) {
|
|
||||||
if (!airDate) return ''
|
|
||||||
const date = new Date(airDate.replaceAll(/-/g, '/'))
|
|
||||||
return date.getFullYear()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 移除订阅
|
// 移除订阅
|
||||||
function onRemoveSubscribe() {
|
function onRemoveSubscribe() {
|
||||||
subscribeEditDialog.value = false
|
subscribeEditDialog.value = false
|
||||||
@@ -607,62 +501,13 @@ function onRemoveSubscribe() {
|
|||||||
</template>
|
</template>
|
||||||
</VHover>
|
</VHover>
|
||||||
<!-- 订阅季弹窗 -->
|
<!-- 订阅季弹窗 -->
|
||||||
<VBottomSheet v-if="subscribeSeasonDialog" v-model="subscribeSeasonDialog" inset scrollable>
|
<subscribeSeasonDialog
|
||||||
<VCard class="rounded-t">
|
v-if="subscribeSeasonDialog"
|
||||||
<DialogCloseBtn @click="subscribeSeasonDialog = false" />
|
v-model="subscribeSeasonDialog"
|
||||||
<VCardItem>
|
:media="media"
|
||||||
<VCardTitle class="pe-10"> 订阅 - {{ props.media?.title }} </VCardTitle>
|
@subscribe="subscribeSeasons"
|
||||||
</VCardItem>
|
@close="subscribeEditDialog = false"
|
||||||
<VDivider />
|
/>
|
||||||
<VCardText>
|
|
||||||
<VList v-model:selected="seasonsSelected" lines="three" select-strategy="classic">
|
|
||||||
<VListItem v-for="(item, i) in seasonInfos" :key="i" :value="item">
|
|
||||||
<template #prepend>
|
|
||||||
<VImg
|
|
||||||
height="90"
|
|
||||||
width="60"
|
|
||||||
:src="getSeasonPoster(item.poster_path || '')"
|
|
||||||
aspect-ratio="2/3"
|
|
||||||
class="object-cover rounded shadow ring-gray-500 me-3"
|
|
||||||
cover
|
|
||||||
>
|
|
||||||
<template #placeholder>
|
|
||||||
<div class="w-full h-full">
|
|
||||||
<VSkeletonLoader class="object-cover aspect-w-2 aspect-h-3" />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</VImg>
|
|
||||||
</template>
|
|
||||||
<VListItemTitle> 第 {{ item.season_number }} 季 </VListItemTitle>
|
|
||||||
<VListItemSubtitle class="mt-1 me-2">
|
|
||||||
<VChip v-if="item.vote_average" color="primary" size="small" class="mb-1">
|
|
||||||
<VIcon icon="mdi-star" /> {{ item.vote_average }}
|
|
||||||
</VChip>
|
|
||||||
{{ getYear(item.air_date || '') }} • {{ item.episode_count }} 集
|
|
||||||
</VListItemSubtitle>
|
|
||||||
<VListItemSubtitle>
|
|
||||||
《{{ media?.title }}》第 {{ item.season_number }} 季于 {{ formatAirDate(item.air_date || '') }} 首播。
|
|
||||||
</VListItemSubtitle>
|
|
||||||
<VListItemSubtitle>
|
|
||||||
<VChip v-if="seasonsNotExisted" class="mt-2" size="small" :color="getExistColor(item.season_number || 0)">
|
|
||||||
{{ getExistText(item.season_number || 0) }}
|
|
||||||
</VChip>
|
|
||||||
</VListItemSubtitle>
|
|
||||||
<template #append="{ isSelected }">
|
|
||||||
<VListItemAction start>
|
|
||||||
<VSwitch :model-value="isSelected" />
|
|
||||||
</VListItemAction>
|
|
||||||
</template>
|
|
||||||
</VListItem>
|
|
||||||
</VList>
|
|
||||||
</VCardText>
|
|
||||||
<div class="my-2 text-center">
|
|
||||||
<VBtn size="large" :disabled="seasonsSelected.length === 0" width="30%" @click="subscribeSeasons">
|
|
||||||
{{ seasonsSelected.length === 0 ? '请选择订阅季' : '提交订阅' }}
|
|
||||||
</VBtn>
|
|
||||||
</div>
|
|
||||||
</VCard>
|
|
||||||
</VBottomSheet>
|
|
||||||
<!-- 订阅编辑弹窗 -->
|
<!-- 订阅编辑弹窗 -->
|
||||||
<SubscribeEditDialog
|
<SubscribeEditDialog
|
||||||
v-if="subscribeEditDialog"
|
v-if="subscribeEditDialog"
|
||||||
|
|||||||
@@ -0,0 +1,198 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import api from '@/api'
|
||||||
|
import { doneNProgress, startNProgress } from '@/api/nprogress'
|
||||||
|
import { MediaInfo, MediaSeason, NotExistMediaInfo } from '@/api/types'
|
||||||
|
import { PropType } from 'vue'
|
||||||
|
|
||||||
|
// 定义事件
|
||||||
|
const emit = defineEmits(['subscribe', 'close'])
|
||||||
|
|
||||||
|
// 定义输入
|
||||||
|
const props = defineProps({
|
||||||
|
media: Object as PropType<MediaInfo>,
|
||||||
|
noexists: {
|
||||||
|
type: Object as PropType<{ [key: number]: number }>,
|
||||||
|
default: {},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// 从 provide 中获取全局设置
|
||||||
|
const globalSettings: any = inject('globalSettings')
|
||||||
|
|
||||||
|
// 季详情
|
||||||
|
const seasonInfos = ref<MediaSeason[]>([])
|
||||||
|
|
||||||
|
// 选中的订阅季
|
||||||
|
const seasonsSelected = ref<MediaSeason[]>([])
|
||||||
|
|
||||||
|
// 各季缺失状态:0-已入库 1-部分缺失 2-全部缺失,没有数据也是已入库
|
||||||
|
const seasonsNotExisted = ref<{ [key: number]: number }>({})
|
||||||
|
|
||||||
|
// 是否刷新过
|
||||||
|
const isRefreshed = ref(false)
|
||||||
|
|
||||||
|
// 获得mediaid
|
||||||
|
function getMediaId() {
|
||||||
|
if (props.media?.tmdb_id) return `tmdb:${props.media?.tmdb_id}`
|
||||||
|
else if (props.media?.douban_id) return `douban:${props.media?.douban_id}`
|
||||||
|
else if (props.media?.bangumi_id) return `bangumi:${props.media?.bangumi_id}`
|
||||||
|
else return `${props.media?.mediaid_prefix}:${props.media?.media_id}`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询TMDB的所有季信息
|
||||||
|
async function getMediaSeasons() {
|
||||||
|
startNProgress()
|
||||||
|
try {
|
||||||
|
seasonInfos.value = await api.get('media/seasons', {
|
||||||
|
params: {
|
||||||
|
mediaid: getMediaId(),
|
||||||
|
title: props.media?.title,
|
||||||
|
year: props.media?.year,
|
||||||
|
season: props.media?.season,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
isRefreshed.value = true
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
doneNProgress()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查所有季的缺失状态(数据库)
|
||||||
|
async function checkSeasonsNotExists() {
|
||||||
|
// 开始处理
|
||||||
|
startNProgress()
|
||||||
|
try {
|
||||||
|
const result: NotExistMediaInfo[] = await api.post('mediaserver/notexists', props.media)
|
||||||
|
if (result) {
|
||||||
|
result.forEach(item => {
|
||||||
|
// 0-已入库 1-部分缺失 2-全部缺失
|
||||||
|
let state = 0
|
||||||
|
if (item.episodes.length === 0) state = 2
|
||||||
|
else if (item.episodes.length < item.total_episode) state = 1
|
||||||
|
seasonsNotExisted.value[item.season] = state
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
} finally {
|
||||||
|
// 处理完成
|
||||||
|
doneNProgress()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算存在状态的颜色
|
||||||
|
function getExistColor(season: number) {
|
||||||
|
const state = props.noexists[season]
|
||||||
|
if (!state) return 'success'
|
||||||
|
|
||||||
|
if (state === 1) return 'warning'
|
||||||
|
else if (state === 2) return 'error'
|
||||||
|
else return 'success'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算存在状态的文本
|
||||||
|
function getExistText(season: number) {
|
||||||
|
const state = props.noexists[season]
|
||||||
|
if (!state) return '已入库'
|
||||||
|
|
||||||
|
if (state === 1) return '部分缺失'
|
||||||
|
else if (state === 2) return '缺失'
|
||||||
|
else return '已入库'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 拼装季图片地址
|
||||||
|
function getSeasonPoster(posterPath: string) {
|
||||||
|
if (!posterPath) return ''
|
||||||
|
return `https://${globalSettings.TMDB_IMAGE_DOMAIN}/t/p/w500${posterPath}`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将yyyy-mm-dd转换为yyyy年mm月dd日
|
||||||
|
function formatAirDate(airDate: string) {
|
||||||
|
if (!airDate) return ''
|
||||||
|
const date = new Date(airDate.replaceAll(/-/g, '/'))
|
||||||
|
return `${date.getFullYear()}年${date.getMonth() + 1}月${date.getDate()}日`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从yyyy-mm-dd中提取年份
|
||||||
|
function getYear(airDate: string) {
|
||||||
|
if (!airDate) return ''
|
||||||
|
const date = new Date(airDate.replaceAll(/-/g, '/'))
|
||||||
|
return date.getFullYear()
|
||||||
|
}
|
||||||
|
|
||||||
|
function subscribeSeasons() {
|
||||||
|
emit('subscribe', seasonsSelected.value, seasonsNotExisted.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
getMediaSeasons()
|
||||||
|
checkSeasonsNotExists()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<VBottomSheet inset scrollable>
|
||||||
|
<VCard class="rounded-t">
|
||||||
|
<DialogCloseBtn @click="emit('close')" />
|
||||||
|
<VCardItem>
|
||||||
|
<VCardTitle class="pe-10"> 订阅 - {{ props.media?.title }} </VCardTitle>
|
||||||
|
</VCardItem>
|
||||||
|
<VDivider />
|
||||||
|
<VCardText>
|
||||||
|
<LoadingBanner v-if="!isRefreshed" class="mt-5" />
|
||||||
|
<VList
|
||||||
|
v-if="isRefreshed && seasonInfos.length > 0"
|
||||||
|
v-model:selected="seasonsSelected"
|
||||||
|
lines="three"
|
||||||
|
select-strategy="classic"
|
||||||
|
>
|
||||||
|
<VListItem v-for="(item, i) in seasonInfos" :key="i" :value="item">
|
||||||
|
<template #prepend>
|
||||||
|
<VImg
|
||||||
|
height="90"
|
||||||
|
width="60"
|
||||||
|
:src="getSeasonPoster(item.poster_path || '')"
|
||||||
|
aspect-ratio="2/3"
|
||||||
|
class="object-cover rounded shadow ring-gray-500 me-3"
|
||||||
|
cover
|
||||||
|
>
|
||||||
|
<template #placeholder>
|
||||||
|
<div class="w-full h-full">
|
||||||
|
<VSkeletonLoader class="object-cover aspect-w-2 aspect-h-3" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</VImg>
|
||||||
|
</template>
|
||||||
|
<VListItemTitle> 第 {{ item.season_number }} 季 </VListItemTitle>
|
||||||
|
<VListItemSubtitle class="mt-1 me-2">
|
||||||
|
<VChip v-if="item.vote_average" color="primary" size="small" class="mb-1">
|
||||||
|
<VIcon icon="mdi-star" /> {{ item.vote_average }}
|
||||||
|
</VChip>
|
||||||
|
{{ getYear(item.air_date || '') }} • {{ item.episode_count }} 集
|
||||||
|
</VListItemSubtitle>
|
||||||
|
<VListItemSubtitle>
|
||||||
|
《{{ media?.title }}》第 {{ item.season_number }} 季于 {{ formatAirDate(item.air_date || '') }} 首播。
|
||||||
|
</VListItemSubtitle>
|
||||||
|
<VListItemSubtitle>
|
||||||
|
<VChip v-if="noexists" class="mt-2" size="small" :color="getExistColor(item.season_number || 0)">
|
||||||
|
{{ getExistText(item.season_number || 0) }}
|
||||||
|
</VChip>
|
||||||
|
</VListItemSubtitle>
|
||||||
|
<template #append="{ isSelected }">
|
||||||
|
<VListItemAction start>
|
||||||
|
<VSwitch :model-value="isSelected" />
|
||||||
|
</VListItemAction>
|
||||||
|
</template>
|
||||||
|
</VListItem>
|
||||||
|
</VList>
|
||||||
|
<NoDataFound v-else errorTitle="出错啦!" :errorDescription="`${props.media?.title} 无法识别TMDB媒体信息!`" />
|
||||||
|
</VCardText>
|
||||||
|
<div class="my-2 text-center">
|
||||||
|
<VBtn :disabled="seasonsSelected.length === 0" width="30%" @click="subscribeSeasons">
|
||||||
|
{{ seasonsSelected.length === 0 ? '请选择订阅季' : '提交订阅' }}
|
||||||
|
</VBtn>
|
||||||
|
</div>
|
||||||
|
</VCard>
|
||||||
|
</VBottomSheet>
|
||||||
|
</template>
|
||||||
Reference in New Issue
Block a user