This commit is contained in:
jxxghp
2023-07-29 15:07:33 +08:00
parent ccedd79344
commit d81503ddbc
6 changed files with 338 additions and 15 deletions

View File

@@ -182,7 +182,7 @@ export interface MediaInfo {
poster_path?: string
// 评分
vote_average: number
vote_average?: number
// 描述
overview?: string

View File

@@ -271,21 +271,10 @@ async function checkSeasonsNotExists() {
doneNProgress()
}
// 检查电影是否存在
async function checkMovieExists() {
try {
const result: NotExistMediaInfo[] = await api.post('download/notexists', props.media)
return !result || result.length === 0
}
catch (error) {
console.error(error)
}
}
// 查询TMDB的所有季信息
async function getMediaSeasons() {
try {
seasonInfos.value = await api.get(`tmdb/${props.media?.tmdb_id}/seasons`)
seasonInfos.value = await api.get(`tmdb/seasons/${props.media?.tmdb_id}`)
}
catch (error) {
console.error(error)
@@ -343,7 +332,17 @@ function getExistText(season: number) {
// 打开详情页
function openDetailWindow() {
window.open(getDetailLink(), '_blank')
router.push({
path: '/media',
query: {
mediaid: `${
props.media?.tmdb_id
? `tmdb:${props.media?.tmdb_id}`
: `douban:${props.media?.douban_id}`
}`,
type: props.media?.type,
},
})
}
// 开始搜索

View File

@@ -222,7 +222,7 @@ const dropdownItems = ref([
<VCard
v-if="cardState"
:key="props.media?.id"
:class="`${subscribeForm.best_version ? 'outline-dotted' : ''}`"
:class="`${subscribeForm.best_version ? 'outline-dashed outline-1' : ''}`"
@click="editSubscribeDialog"
>
<template #image>

21
src/pages/media.vue Normal file
View File

@@ -0,0 +1,21 @@
<script setup lang="ts">
import MediaDetailView from '@/views/discover/MediaDetailView.vue'
// 路由参数
const route = useRoute()
// TMDBID
const mediaid = route.query?.mediaid?.toString()
// 类型
const type = route.query?.type?.toString()
</script>
<template>
<div>
<MediaDetailView
:mediaid="mediaid"
:type="type"
/>
</div>
</template>

View File

@@ -98,6 +98,13 @@ const router = createRouter({
requiresAuth: true,
},
},
{
path: '/media',
component: () => import('../pages/media.vue'),
meta: {
requiresAuth: true,
},
},
],
},
{

View File

@@ -0,0 +1,296 @@
<script setup lang="ts">
import MediaCardSlideView from './MediaCardSlideView.vue'
import api from '@/api'
import type { MediaInfo } from '@/api/types'
// 输入参数
const mediaProps = defineProps({
mediaid: String,
type: String,
})
// 媒体详情
const mediaDetail = ref<MediaInfo>({} as MediaInfo)
// 调用API查询详情
async function getMediaDetail() {
if (mediaProps.mediaid && mediaProps.type) {
const result: MediaInfo = await api.get(`tmdb/${mediaProps.mediaid}`, {
params: {
type_name: mediaProps.type,
},
})
mediaDetail.value = result
}
}
onMounted(() => {
getMediaDetail()
})
</script>
<template>
<div class="max-w-8xl mx-auto px-4">
<div class="media-page">
<div class="media-page-bg-image">
<VImg cover :src="mediaDetail.backdrop_path" class="absolute inset-0 w-full h-full object-cover object-center" />
<div
class="absolute inset-0"
style="background-image: linear-gradient(180deg, rgba(17, 24, 39, 47%) 0%, rgba(17, 24, 39, 100%) 100%);"
/>
</div>
</div>
<div class="media-header">
<div class="media-poster">
<VImg :src="mediaDetail.poster_path" cover />
</div>
<div class="media-title">
<div class="media-status" />
<h1 class="media-title">
{{ mediaDetail.title }}
<span class="media-year">
({{ mediaDetail.year }})
</span>
</h1>
<span class="media-attributes">
<span>分级</span>
<span>时长</span>
<span>风格</span>
</span>
</div>
<div class="media-actions" />
</div>
<div class="media-overview">
<div class="media-overview-left">
<div class="tagline">
标签
</div>
<h2>简介</h2>
<p>{{ mediaDetail.overview }}</p>
</div>
<div class="media-overview-right" />
</div>
<div v-if="mediaDetail.tmdb_id">
<MediaCardSlideView :apipath="`tmdb/credits/${mediaDetail.tmdb_id}/${mediaProps.type}`">
<template #title="{ loaded }">
<div v-if="loaded" class="slider-header mt-3 ms-1">
<RouterLink to="" class="slider-title">
<span>演员阵容</span>
<VIcon icon="mdi-arrow-right-circle-outline" class="ms-1" />
</RouterLink>
</div>
</template>
</MediaCardSlideView>
</div>
<div v-if="mediaDetail.tmdb_id">
<MediaCardSlideView :apipath="`tmdb/recommend/${mediaDetail.tmdb_id}/${mediaProps.type}`">
<template #title="{ loaded }">
<div v-if="loaded" class="slider-header mt-3 ms-1">
<RouterLink to="" class="slider-title">
<span>推荐</span>
<VIcon icon="mdi-arrow-right-circle-outline" class="ms-1" />
</RouterLink>
</div>
</template>
</MediaCardSlideView>
</div>
<div v-if="mediaDetail.tmdb_id">
<MediaCardSlideView :apipath="`tmdb/similar/${mediaDetail.tmdb_id}/${mediaProps.type}`">
<template #title="{ loaded }">
<div v-if="loaded" class="slider-header mt-3 ms-1">
<RouterLink to="" class="slider-title">
<span>类似</span>
<VIcon icon="mdi-arrow-right-circle-outline" class="ms-1" />
</RouterLink>
</div>
</template>
</MediaCardSlideView>
</div>
</div>
</template>
<style lang="scss">
.media-page {
position: relative;
background-position: 50%;
background-size: cover;
margin-block-start: calc(-4rem - env(safe-area-inset-top));
margin-inline: -1rem;
padding-block-start: calc(4rem + env(safe-area-inset-top));
padding-inline: 1rem;
}
.media-page-bg-image {
position: absolute;
z-index: -10;
block-size: 100%;
inline-size: 100%;
inset: 0;
}
@media (min-width: 1280px) {
.media-header {
flex-direction: row;
align-items: flex-end;
}
}
.media-header {
display: flex;
flex-direction: column;
align-items: center;
padding-block-start: 1rem;
}
@media (min-width: 1024px) {
.media-overview {
flex-direction: row;
}
}
@media (min-width: 1280px) {
.media-poster {
margin-right: 1rem;
width: 13rem;
}
}
@media (min-width: 768px) {
.media-poster {
width: 11rem;
border-radius: .5rem;
--tw-shadow: 0 25px 50px -12px rgba(0, 0, 0, .25);
--tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}
}
.media-poster {
width: 8rem;
overflow: hidden;
border-radius: .25rem;
--tw-shadow: 0 1px 3px 0 rgba(0, 0, 0, .1), 0 1px 2px -1px rgba(0, 0, 0, .1);
--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}
@media (min-width: 1280px) {
.media-title {
margin-right: 1rem;
margin-top: 0;
text-align: left;
}
}
.media-title {
margin-top: 1rem;
display: flex;
flex: 1 1 0%;
flex-direction: column;
text-align: center;
--tw-text-opacity: 1;
color: rgb(255 255 255/var(--tw-text-opacity));
}
@media (min-width: 640px) {
ul.media-crew {
grid-template-columns: repeat(3,minmax(0,1fr));
}
}
ul.media-crew {
margin-top: 1.5rem;
display: grid;
grid-template-columns: repeat(2,minmax(0,1fr));
gap: 1.5rem;
}
.media-status {
margin-bottom: .5rem;
}
@media (min-width: 1280px) {
.media-attributes {
margin-top: 0;
justify-content: flex-start;
font-size: 1rem;
line-height: 1.5rem;
}
}
@media (min-width: 640px) {
.media-attributes {
font-size: .875rem;
line-height: 1.25rem;
}
}
.media-attributes {
font-size: .75rem;
line-height: 1rem;
--tw-text-opacity: 1;
color: rgb(209 213 219/var(--tw-text-opacity));
}
.media-attributes {
margin-top: .25rem;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
}
@media (min-width: 1280px) {
.media-actions {
margin-top: 0;
}
}
@media (min-width: 640px) {
.media-actions {
flex-wrap: nowrap;
justify-content: flex-end;
}
}
.media-actions {
position: relative;
margin-top: 1rem;
display: flex;
flex-shrink: 0;
flex-wrap: wrap;
align-items: center;
justify-content: center;
}
.media-overview {
display: flex;
flex-direction: column;
padding-top: 2rem;
padding-bottom: 1rem;
--tw-text-opacity: 1;
color: rgb(255 255 255/var(--tw-text-opacity));
}
@media (min-width: 1024px) {
.media-overview-left {
margin-right: 2rem;
}
}
.media-overview-left {
flex: 1 1 0%;
}
@media (min-width: 1024px) {
.media-overview-right {
margin-top: 0;
width: 20rem;
}
}
.media-overview-right {
margin-top: 2rem;
width: 100%;
}
</style>