mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-07 08:46:40 +08:00
优化媒体卡片和海报卡片的点击事件处理,改进路由滚动行为,注册中止控制器以管理异步请求
This commit is contained in:
@@ -59,11 +59,7 @@ const seasonInfos = ref<TmdbSeason[]>([])
|
|||||||
|
|
||||||
// 选中的订阅季
|
// 选中的订阅季
|
||||||
const seasonsSelected = ref<TmdbSeason[]>([])
|
const seasonsSelected = ref<TmdbSeason[]>([])
|
||||||
let abortController: AbortController | null = null
|
|
||||||
|
|
||||||
abortController = new AbortController()
|
|
||||||
registerAbortController(abortController)
|
|
||||||
const { signal } = abortController
|
|
||||||
// 来源角标字典
|
// 来源角标字典
|
||||||
const sourceIconDict: { [key: string]: any } = {
|
const sourceIconDict: { [key: string]: any } = {
|
||||||
themoviedb: tmdbImage,
|
themoviedb: tmdbImage,
|
||||||
@@ -100,7 +96,6 @@ function getChipColor(type: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 添加订阅处理
|
// 添加订阅处理
|
||||||
|
|
||||||
async function handleAddSubscribe() {
|
async function handleAddSubscribe() {
|
||||||
if (props.media?.type === '电视剧' && props.media?.tmdb_id) {
|
if (props.media?.type === '电视剧' && props.media?.tmdb_id) {
|
||||||
// TMDB电视剧
|
// TMDB电视剧
|
||||||
@@ -229,6 +224,9 @@ async function handleCheckSubscribe() {
|
|||||||
// 查询当前媒体是否已入库
|
// 查询当前媒体是否已入库
|
||||||
async function handleCheckExists() {
|
async function handleCheckExists() {
|
||||||
try {
|
try {
|
||||||
|
const abortController = new AbortController()
|
||||||
|
registerAbortController(abortController)
|
||||||
|
const { signal } = abortController
|
||||||
const result: { [key: string]: any } = await api.get('mediaserver/exists', {
|
const result: { [key: string]: any } = await api.get('mediaserver/exists', {
|
||||||
params: {
|
params: {
|
||||||
tmdbid: props.media?.tmdb_id,
|
tmdbid: props.media?.tmdb_id,
|
||||||
@@ -249,8 +247,10 @@ async function handleCheckExists() {
|
|||||||
// 调用API检查是否已订阅,电视剧需要指定季
|
// 调用API检查是否已订阅,电视剧需要指定季
|
||||||
async function checkSubscribe(season = 0) {
|
async function checkSubscribe(season = 0) {
|
||||||
try {
|
try {
|
||||||
|
const abortController = new AbortController()
|
||||||
|
registerAbortController(abortController)
|
||||||
|
const { signal } = abortController
|
||||||
const mediaid = getMediaId()
|
const mediaid = getMediaId()
|
||||||
|
|
||||||
const result: Subscribe = await api.get(`subscribe/media/${mediaid}`, {
|
const result: Subscribe = await api.get(`subscribe/media/${mediaid}`, {
|
||||||
params: {
|
params: {
|
||||||
season,
|
season,
|
||||||
@@ -279,7 +279,6 @@ async function checkSeasonsNotExists() {
|
|||||||
let state = 0
|
let state = 0
|
||||||
if (item.episodes.length === 0) state = 2
|
if (item.episodes.length === 0) state = 2
|
||||||
else if (item.episodes.length < item.total_episode) state = 1
|
else if (item.episodes.length < item.total_episode) state = 1
|
||||||
|
|
||||||
seasonsNotExisted.value[item.season] = state
|
seasonsNotExisted.value[item.season] = state
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -502,7 +501,7 @@ function onRemoveSubscribe() {
|
|||||||
<p class="leading-4 line-clamp-4 overflow-hidden text-ellipsis ...">
|
<p class="leading-4 line-clamp-4 overflow-hidden text-ellipsis ...">
|
||||||
{{ props.media?.overview }}
|
{{ props.media?.overview }}
|
||||||
</p>
|
</p>
|
||||||
<div v-if="props.media?.collection_id" class="mb-3"></div>
|
<div v-if="props.media?.collection_id" class="mb-3" @click.stop=""></div>
|
||||||
<div v-else class="flex align-center justify-between">
|
<div v-else class="flex align-center justify-between">
|
||||||
<IconBtn icon="mdi-magnify" color="white" @click.stop="handleSearch" />
|
<IconBtn icon="mdi-magnify" color="white" @click.stop="handleSearch" />
|
||||||
<IconBtn icon="mdi-heart" :color="isSubscribed ? 'error' : 'white'" @click.stop="handleSubscribe" />
|
<IconBtn icon="mdi-heart" :color="isSubscribed ? 'error' : 'white'" @click.stop="handleSubscribe" />
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ function goPlay(isHovering = false) {
|
|||||||
<VCardText
|
<VCardText
|
||||||
v-show="hover.isHovering || imageLoadError"
|
v-show="hover.isHovering || imageLoadError"
|
||||||
class="w-full flex flex-col flex-wrap justify-end align-left text-white absolute bottom-0 cursor-pointer pa-2"
|
class="w-full flex flex-col flex-wrap justify-end align-left text-white absolute bottom-0 cursor-pointer pa-2"
|
||||||
|
@click.stop=""
|
||||||
>
|
>
|
||||||
<span class="font-bold">{{ props.media?.subtitle }}</span>
|
<span class="font-bold">{{ props.media?.subtitle }}</span>
|
||||||
<h1 class="mb-1 text-white font-extrabold text-xl line-clamp-2 overflow-hidden text-ellipsis ...">
|
<h1 class="mb-1 text-white font-extrabold text-xl line-clamp-2 overflow-hidden text-ellipsis ...">
|
||||||
|
|||||||
+11
-6
@@ -8,7 +8,7 @@ configureNProgress()
|
|||||||
// Router
|
// Router
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHashHistory(import.meta.env.BASE_URL),
|
history: createWebHashHistory(import.meta.env.BASE_URL),
|
||||||
scrollBehavior(to, from, savedPosition) {
|
scrollBehavior(to: any, from: any, savedPosition: any) {
|
||||||
// 如果页面有缓存那么恢复其位置, 否则始终滚动到顶部
|
// 如果页面有缓存那么恢复其位置, 否则始终滚动到顶部
|
||||||
if (to.meta.keepAlive && savedPosition) return savedPosition
|
if (to.meta.keepAlive && savedPosition) return savedPosition
|
||||||
return { top: 0 }
|
return { top: 0 }
|
||||||
@@ -189,31 +189,36 @@ const router = createRouter({
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
const abortControllers = new Set<AbortController>()
|
const abortControllers = new Set<AbortController>()
|
||||||
|
|
||||||
|
// 注册中止控制器
|
||||||
function registerAbortController(controller: AbortController) {
|
function registerAbortController(controller: AbortController) {
|
||||||
abortControllers.add(controller)
|
abortControllers.add(controller)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 中止所有组件的任务
|
||||||
function abortAllControllers() {
|
function abortAllControllers() {
|
||||||
for (const controller of abortControllers) {
|
for (const controller of abortControllers) {
|
||||||
controller.abort()
|
controller.abort()
|
||||||
}
|
}
|
||||||
abortControllers.clear()
|
abortControllers.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 路由导航守卫
|
// 路由导航守卫
|
||||||
router.beforeEach((to, from, next) => {
|
router.beforeEach((to: any, from: any, next: any) => {
|
||||||
// 总是记录非login路由
|
// 总是记录非login路由
|
||||||
if (to.fullPath != '/login') store.state.auth.originalPath = to.fullPath
|
if (to.fullPath != '/login') store.state.auth.originalPath = to.fullPath
|
||||||
const isAuthenticated = store.state.auth.token !== null
|
const isAuthenticated = store.state.auth.token !== null
|
||||||
if (to.meta.requiresAuth && !isAuthenticated) {
|
if (to.meta.requiresAuth && !isAuthenticated) {
|
||||||
next('/login')
|
next('/login')
|
||||||
} else {
|
} else {
|
||||||
abortAllControllers() // 中止所有组件的任务
|
abortAllControllers()
|
||||||
|
|
||||||
next()
|
next()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
export default router // 导出默认对象
|
// 导出默认对象
|
||||||
export { registerAbortController } // 另行导出其他功能
|
export default router
|
||||||
|
// 另行导出其他功能
|
||||||
|
export { registerAbortController }
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import api from '@/api'
|
|||||||
import type { MediaInfo } from '@/api/types'
|
import type { MediaInfo } from '@/api/types'
|
||||||
import MediaCard from '@/components/cards/MediaCard.vue'
|
import MediaCard from '@/components/cards/MediaCard.vue'
|
||||||
import SlideView from '@/components/slide/SlideView.vue'
|
import SlideView from '@/components/slide/SlideView.vue'
|
||||||
import { registerAbortController } from "@/router";
|
import { registerAbortController } from '@/router'
|
||||||
|
|
||||||
// 输入参数
|
// 输入参数
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -11,8 +11,8 @@ const props = defineProps({
|
|||||||
linkurl: String,
|
linkurl: String,
|
||||||
title: String,
|
title: String,
|
||||||
})
|
})
|
||||||
let abortController: AbortController | null = null;
|
|
||||||
|
|
||||||
|
// 提供给子组件的属性
|
||||||
provide('rankingPropsKey', reactive({ ...props }))
|
provide('rankingPropsKey', reactive({ ...props }))
|
||||||
|
|
||||||
// 组件加载完成
|
// 组件加载完成
|
||||||
@@ -24,30 +24,26 @@ const dataList = ref<MediaInfo[]>([])
|
|||||||
// 获取订阅列表数据
|
// 获取订阅列表数据
|
||||||
async function fetchData() {
|
async function fetchData() {
|
||||||
try {
|
try {
|
||||||
if (!props.apipath)
|
if (!props.apipath) return
|
||||||
return
|
const abortController = new AbortController()
|
||||||
abortController = new AbortController();
|
registerAbortController(abortController)
|
||||||
registerAbortController(abortController);
|
const { signal } = abortController
|
||||||
const { signal } = abortController;
|
|
||||||
dataList.value = await api.get(props.apipath, { signal })
|
dataList.value = await api.get(props.apipath, { signal })
|
||||||
if (dataList.value.length > 0)
|
if (dataList.value.length > 0) componentLoaded.value = true
|
||||||
componentLoaded.value = true
|
} catch (error) {
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
console.error(error)
|
console.error(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 加载时获取数据
|
// 加载时获取数据
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
fetchData();
|
fetchData()
|
||||||
});
|
})
|
||||||
onActivated(() => {
|
onActivated(() => {
|
||||||
if (dataList.value.length == 0) {
|
if (dataList.value.length == 0) {
|
||||||
fetchData();
|
fetchData()
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
Reference in New Issue
Block a user