mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-05 23:56:42 +08:00
fix 详情页面订阅
This commit is contained in:
@@ -33,7 +33,7 @@ const isSubscribed = ref(false)
|
|||||||
// 本地存在状态
|
// 本地存在状态
|
||||||
const isExists = ref(false)
|
const isExists = ref(false)
|
||||||
|
|
||||||
// 各季缺失状态:0-已存在 1-部分缺失 2-全部缺失
|
// 各季缺失状态:0-已存在 1-部分缺失 2-全部缺失,没有数据也是已存在
|
||||||
const seasonsNotExisted = ref<{ [key: number]: number }>({})
|
const seasonsNotExisted = ref<{ [key: number]: number }>({})
|
||||||
|
|
||||||
// 订阅季弹窗
|
// 订阅季弹窗
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { useToast } from 'vue-toast-notification'
|
||||||
import PersonCardSlideView from './PersonCardSlideView.vue'
|
import PersonCardSlideView from './PersonCardSlideView.vue'
|
||||||
import MediaCardSlideView from './MediaCardSlideView.vue'
|
import MediaCardSlideView from './MediaCardSlideView.vue'
|
||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
import type { MediaInfo, Subscribe, TmdbEpisode } from '@/api/types'
|
import type { MediaInfo, NotExistMediaInfo, Subscribe, TmdbEpisode } from '@/api/types'
|
||||||
import NoDataFound from '@/components/NoDataFound.vue'
|
import NoDataFound from '@/components/NoDataFound.vue'
|
||||||
|
import { doneNProgress, startNProgress } from '@/api/nprogress'
|
||||||
|
import { formatSeason } from '@/@core/utils/formatters'
|
||||||
|
|
||||||
// 输入参数
|
// 输入参数
|
||||||
const mediaProps = defineProps({
|
const mediaProps = defineProps({
|
||||||
@@ -11,6 +14,9 @@ const mediaProps = defineProps({
|
|||||||
type: String,
|
type: String,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 提示框
|
||||||
|
const $toast = useToast()
|
||||||
|
|
||||||
// 媒体详情
|
// 媒体详情
|
||||||
const mediaDetail = ref<MediaInfo>({} as MediaInfo)
|
const mediaDetail = ref<MediaInfo>({} as MediaInfo)
|
||||||
|
|
||||||
@@ -26,6 +32,12 @@ const isRefreshed = ref(false)
|
|||||||
// 存储每一季的集信息
|
// 存储每一季的集信息
|
||||||
const seasonEpisodesInfo = ref({} as { [key: number]: TmdbEpisode[] })
|
const seasonEpisodesInfo = ref({} as { [key: number]: TmdbEpisode[] })
|
||||||
|
|
||||||
|
// 各季缺失状态:0-已存在 1-部分缺失 2-全部缺失,没有数据也是已存在
|
||||||
|
const seasonsNotExisted = ref<{ [key: number]: number }>({})
|
||||||
|
|
||||||
|
// 各季的订阅状态
|
||||||
|
const seasonsSubscribed = ref<{ [key: number]: boolean }>({})
|
||||||
|
|
||||||
// 调用API查询详情
|
// 调用API查询详情
|
||||||
async function getMediaDetail() {
|
async function getMediaDetail() {
|
||||||
if (mediaProps.mediaid && mediaProps.type) {
|
if (mediaProps.mediaid && mediaProps.type) {
|
||||||
@@ -35,10 +47,18 @@ async function getMediaDetail() {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
isRefreshed.value = true
|
isRefreshed.value = true
|
||||||
|
if (!mediaDetail.value.tmdb_id)
|
||||||
|
return
|
||||||
// 检查存在状态
|
// 检查存在状态
|
||||||
checkExists()
|
if (mediaDetail.value.type === '电影')
|
||||||
|
checkMovieExists()
|
||||||
|
else
|
||||||
|
checkSeasonsNotExists()
|
||||||
// 检查订阅状态
|
// 检查订阅状态
|
||||||
checkSubscribe()
|
if (mediaDetail.value.type === '电影')
|
||||||
|
checkMovieSubscribed()
|
||||||
|
else
|
||||||
|
checkSeasonsSubscribed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,7 +77,7 @@ async function loadSeasonEpisodes(season: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 查询当前媒体是否已存在
|
// 查询当前媒体是否已存在
|
||||||
async function checkExists() {
|
async function checkMovieExists() {
|
||||||
try {
|
try {
|
||||||
const result: { [key: string]: any } = await api.get('media/exists', {
|
const result: { [key: string]: any } = await api.get('media/exists', {
|
||||||
params: {
|
params: {
|
||||||
@@ -89,13 +109,168 @@ async function checkSubscribe(season = 0) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if (result.id)
|
if (result.id)
|
||||||
isSubscribed.value = true
|
return true
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查所有季的缺失状态
|
||||||
|
async function checkSeasonsNotExists() {
|
||||||
|
if (mediaDetail.value.type !== '电视剧')
|
||||||
|
return
|
||||||
|
try {
|
||||||
|
const result: NotExistMediaInfo[] = await api.post('download/notexists', mediaDetail.value)
|
||||||
|
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_episodes)
|
||||||
|
state = 1
|
||||||
|
|
||||||
|
seasonsNotExisted.value[item.season] = state
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查电影订阅状态
|
||||||
|
async function checkMovieSubscribed() {
|
||||||
|
if (mediaDetail.value.type !== '电影')
|
||||||
|
return
|
||||||
|
isSubscribed.value = await checkSubscribe()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 过滤掉第0季
|
||||||
|
const getMediaSeasons = computed(() => {
|
||||||
|
return mediaDetail.value?.season_info?.filter(season => season.season_number !== 0)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 检查所有季的订阅状态
|
||||||
|
async function checkSeasonsSubscribed() {
|
||||||
|
if (mediaDetail.value.type !== '电视剧')
|
||||||
|
return
|
||||||
|
try {
|
||||||
|
mediaDetail.value?.season_info?.forEach(async (item) => {
|
||||||
|
seasonsSubscribed.value[item.season_number || 0] = await checkSubscribe(item.season_number)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用API添加订阅,电视剧的话需要指定季
|
||||||
|
async function addSubscribe(season = 0) {
|
||||||
|
// 开始处理
|
||||||
|
startNProgress()
|
||||||
|
try {
|
||||||
|
// 是否洗版
|
||||||
|
let best_version = isExists.value ? 1 : 0
|
||||||
|
if (mediaDetail.value?.type === '电视剧' && mediaDetail.value?.tmdb_id)
|
||||||
|
// 全部存在时洗版
|
||||||
|
best_version = (!seasonsNotExisted.value[season] || seasonsNotExisted.value[season] === 0) ? 1 : 0
|
||||||
|
// 请求API
|
||||||
|
const result: { [key: string]: any } = await api.post('subscribe', {
|
||||||
|
name: mediaDetail.value?.title,
|
||||||
|
type: mediaDetail.value?.type,
|
||||||
|
year: mediaDetail.value?.year,
|
||||||
|
tmdbid: mediaDetail.value?.tmdb_id,
|
||||||
|
doubanid: mediaDetail.value?.douban_id,
|
||||||
|
season,
|
||||||
|
best_version,
|
||||||
|
})
|
||||||
|
|
||||||
|
// 订阅状态
|
||||||
|
if (result.success) {
|
||||||
|
// 订阅成功
|
||||||
|
isSubscribed.value = true
|
||||||
|
if (season)
|
||||||
|
seasonsSubscribed.value[season] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提示
|
||||||
|
showSubscribeAddToast(
|
||||||
|
result.success,
|
||||||
|
mediaDetail.value?.title ?? '',
|
||||||
|
season,
|
||||||
|
result.message,
|
||||||
|
best_version,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
doneNProgress()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 弹出添加订阅提示
|
||||||
|
function showSubscribeAddToast(result: boolean,
|
||||||
|
title: string,
|
||||||
|
season: number,
|
||||||
|
message: string,
|
||||||
|
best_version: number) {
|
||||||
|
if (season)
|
||||||
|
title = `${title} ${formatSeason(season.toString())}`
|
||||||
|
|
||||||
|
let subname = '订阅'
|
||||||
|
if (best_version > 0)
|
||||||
|
subname = '洗版订阅'
|
||||||
|
|
||||||
|
if (result)
|
||||||
|
$toast.success(`${title} 添加${subname}成功!`)
|
||||||
|
else
|
||||||
|
$toast.error(`${title} 添加${subname}失败:${message}!`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用API取消订阅
|
||||||
|
async function removeSubscribe(season: number) {
|
||||||
|
// 开始处理
|
||||||
|
startNProgress()
|
||||||
|
try {
|
||||||
|
const mediaid = mediaDetail.value?.tmdb_id
|
||||||
|
? `tmdb:${mediaDetail.value?.tmdb_id}`
|
||||||
|
: `douban:${mediaDetail.value?.douban_id}`
|
||||||
|
|
||||||
|
const result: { [key: string]: any } = await api.delete(
|
||||||
|
`subscribe/media/${mediaid}`,
|
||||||
|
{
|
||||||
|
params: {
|
||||||
|
season,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
if (result.success) {
|
||||||
|
isSubscribed.value = false
|
||||||
|
if (season)
|
||||||
|
seasonsSubscribed.value[season] = false
|
||||||
|
$toast.success(`${mediaDetail.value?.title} 已取消订阅!`)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$toast.error(`${mediaDetail.value?.title} 取消订阅失败:${result.message}!`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
doneNProgress()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 订阅按钮响应
|
||||||
|
function handleSubscribe(season = 0) {
|
||||||
|
if (isSubscribed.value)
|
||||||
|
removeSubscribe(season)
|
||||||
|
else
|
||||||
|
addSubscribe(season)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 从genres中获取name,使用、分隔
|
// 从genres中获取name,使用、分隔
|
||||||
@@ -141,6 +316,50 @@ const getProductionCompanies = computed(() => {
|
|||||||
return mediaDetail.value.production_companies?.map(company => company.name)
|
return mediaDetail.value.production_companies?.map(company => company.name)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 计算存在状态的颜色
|
||||||
|
function getExistColor(season: number) {
|
||||||
|
const state = seasonsNotExisted.value[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 = seasonsNotExisted.value[season]
|
||||||
|
if (!state)
|
||||||
|
return '已存在'
|
||||||
|
|
||||||
|
if (state === 1)
|
||||||
|
return '部分缺失'
|
||||||
|
else if (state === 2)
|
||||||
|
return '缺失'
|
||||||
|
else
|
||||||
|
return '已存在'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算订阅图标
|
||||||
|
const getSubscribeIcon = computed(() => {
|
||||||
|
if (isSubscribed.value)
|
||||||
|
return 'mdi-heart'
|
||||||
|
else
|
||||||
|
return 'mdi-heart-outline'
|
||||||
|
})
|
||||||
|
|
||||||
|
// 计算订阅按钮颜色
|
||||||
|
const getSubscribeColor = computed(() => {
|
||||||
|
if (isSubscribed.value)
|
||||||
|
return 'error'
|
||||||
|
else
|
||||||
|
return 'warning'
|
||||||
|
})
|
||||||
|
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
getMediaDetail()
|
getMediaDetail()
|
||||||
})
|
})
|
||||||
@@ -183,8 +402,11 @@ onBeforeMount(() => {
|
|||||||
<VBtn v-if="isExists" class="ms-2" color="success" variant="tonal">
|
<VBtn v-if="isExists" class="ms-2" color="success" variant="tonal">
|
||||||
<VIcon icon="mdi-play" />播放
|
<VIcon icon="mdi-play" />播放
|
||||||
</VBtn>
|
</VBtn>
|
||||||
<VBtn class="ms-2" color="warning" variant="tonal">
|
<VBtn v-if="mediaDetail.type === '电影'" class="ms-2" :color="getSubscribeColor" variant="tonal" @click="handleSubscribe(0)">
|
||||||
<VIcon icon="mdi-plus" />订阅
|
<template #prepend>
|
||||||
|
<VIcon :icon="getSubscribeIcon" />
|
||||||
|
</template>
|
||||||
|
{{ isSubscribed ? '已订阅' : '订阅' }}
|
||||||
</VBtn>
|
</VBtn>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -235,7 +457,7 @@ onBeforeMount(() => {
|
|||||||
<div v-if="mediaDetail.type === '电视剧'" class="flex w-full flex-col space-y-2">
|
<div v-if="mediaDetail.type === '电视剧'" class="flex w-full flex-col space-y-2">
|
||||||
<VExpansionPanels>
|
<VExpansionPanels>
|
||||||
<VExpansionPanel
|
<VExpansionPanel
|
||||||
v-for="season in mediaDetail.season_info"
|
v-for="season in getMediaSeasons"
|
||||||
:key="season.season_number"
|
:key="season.season_number"
|
||||||
@group:selected="loadSeasonEpisodes(season.season_number || 0)"
|
@group:selected="loadSeasonEpisodes(season.season_number || 0)"
|
||||||
>
|
>
|
||||||
@@ -243,9 +465,24 @@ onBeforeMount(() => {
|
|||||||
<template #default>
|
<template #default>
|
||||||
<div class="flex flex-row items-center justify-between">
|
<div class="flex flex-row items-center justify-between">
|
||||||
<span>第 {{ season.season_number }} 季</span>
|
<span>第 {{ season.season_number }} 季</span>
|
||||||
<VChip size="small" class="ms-2">
|
<VChip size="small">
|
||||||
{{ season.episode_count }}集
|
{{ season.episode_count }}集
|
||||||
</VChip>
|
</VChip>
|
||||||
|
<div class="absolute right-12">
|
||||||
|
<VChip
|
||||||
|
v-if="seasonsNotExisted"
|
||||||
|
:color="getExistColor(season.season_number || 0)"
|
||||||
|
flat
|
||||||
|
>
|
||||||
|
{{ getExistText(season.season_number || 0) }}
|
||||||
|
</VChip>
|
||||||
|
<IconBtn
|
||||||
|
class="ms-1" :color="seasonsSubscribed[season.season_number || 0] ? 'error' : 'warning'" variant="text"
|
||||||
|
@click.stop="handleSubscribe(season.season_number)"
|
||||||
|
>
|
||||||
|
<VIcon :icon="seasonsSubscribed[season.season_number || 0] ? 'mdi-heart' : 'mdi-heart-outline'" />
|
||||||
|
</IconBtn>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</VExpansionPanelTitle>
|
</VExpansionPanelTitle>
|
||||||
@@ -326,7 +563,7 @@ onBeforeMount(() => {
|
|||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="mediaDetail.production_companies?.length" class="media-fact">
|
<div v-if="mediaDetail.production_companies?.length" class="media-fact border-b-0">
|
||||||
<span>制作公司</span>
|
<span>制作公司</span>
|
||||||
<span class="media-fact-value text-end">
|
<span class="media-fact-value text-end">
|
||||||
<span v-for="company in getProductionCompanies" :key="company" class="block">{{ company }}</span>
|
<span v-for="company in getProductionCompanies" :key="company" class="block">{{ company }}</span>
|
||||||
@@ -377,7 +614,7 @@ onBeforeMount(() => {
|
|||||||
v-if="!mediaDetail.tmdb_id && isRefreshed"
|
v-if="!mediaDetail.tmdb_id && isRefreshed"
|
||||||
error-code="500"
|
error-code="500"
|
||||||
error-title="出错啦!"
|
error-title="出错啦!"
|
||||||
error-description="无法获取到媒体信息,请检查网络连接。"
|
error-description="未识别到TMDB媒体信息。"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user