mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-05-16 23:57:34 +08:00
refactor: Remove unused import in SiteTorrentTable.vue
Remove the unused import of MediaInfo in SiteTorrentTable.vue to improve code cleanliness and reduce potential confusion.
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
import { useToast } from 'vue-toast-notification'
|
||||
import { useConfirm } from 'vuetify-use-dialog'
|
||||
import SubscribeEditDialog from '../dialog/SubscribeEditDialog.vue'
|
||||
import SubscribeFilesDialog from '../dialog/SubscribeFilesDialog.vue'
|
||||
import { formatDateDifference } from '@/@core/utils/formatters'
|
||||
import { formatSeason } from '@/@core/utils/formatters'
|
||||
import api from '@/api'
|
||||
@@ -31,6 +32,9 @@ const imageLoaded = ref(false)
|
||||
// 订阅弹窗
|
||||
const subscribeEditDialog = ref(false)
|
||||
|
||||
// 订阅文件信息弹窗
|
||||
const subscribeFilesDialog = ref(false)
|
||||
|
||||
// 上一次更新时间
|
||||
const lastUpdateText = ref(props.media && props.media.last_update ? formatDateDifference(props.media.last_update) : '')
|
||||
|
||||
@@ -39,13 +43,6 @@ function imageLoadHandler() {
|
||||
imageLoaded.value = true
|
||||
}
|
||||
|
||||
// 根据 type 返回不同的图标
|
||||
function getIcon() {
|
||||
if (props.media?.type === '电影') return 'mdi-movie-open'
|
||||
else if (props.media?.type === '电视剧') return 'mdi-television-play'
|
||||
else return 'mdi-help-circle'
|
||||
}
|
||||
|
||||
// 计算百分比
|
||||
function getPercentage() {
|
||||
if (props.media?.total_episode === 0) return 0
|
||||
@@ -107,7 +104,7 @@ async function editSubscribeDialog() {
|
||||
subscribeEditDialog.value = true
|
||||
}
|
||||
|
||||
// 查看详情
|
||||
// 查看媒体详情
|
||||
async function viewMediaDetail() {
|
||||
router.push({
|
||||
path: '/media',
|
||||
@@ -118,6 +115,11 @@ async function viewMediaDetail() {
|
||||
})
|
||||
}
|
||||
|
||||
// 查看文件详情
|
||||
async function viewSubscribeFiles() {
|
||||
subscribeFilesDialog.value = true
|
||||
}
|
||||
|
||||
// 弹出菜单
|
||||
const dropdownItems = ref([
|
||||
{
|
||||
@@ -137,16 +139,24 @@ const dropdownItems = ref([
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '查看详情',
|
||||
title: '媒体详情',
|
||||
value: 3,
|
||||
props: {
|
||||
prependIcon: 'mdi-open-in-new',
|
||||
prependIcon: 'mdi-information-outline',
|
||||
click: viewMediaDetail,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '重置',
|
||||
title: '文件信息',
|
||||
value: 4,
|
||||
props: {
|
||||
prependIcon: 'mdi-file-document-outline',
|
||||
click: viewSubscribeFiles,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '重置',
|
||||
value: 5,
|
||||
props: {
|
||||
prependIcon: 'mdi-restore-alert',
|
||||
click: resetSubscribe,
|
||||
@@ -156,7 +166,7 @@ const dropdownItems = ref([
|
||||
},
|
||||
{
|
||||
title: '取消订阅',
|
||||
value: 5,
|
||||
value: 6,
|
||||
props: {
|
||||
prependIcon: 'mdi-trash-can-outline',
|
||||
color: 'error',
|
||||
@@ -190,6 +200,18 @@ const posterUrl = computed(() => {
|
||||
return `${import.meta.env.VITE_API_BASE_URL}system/cache/image?url=${encodeURIComponent(url)}`
|
||||
return url
|
||||
})
|
||||
|
||||
// 订阅编辑保存
|
||||
function onSubscribeEditSave() {
|
||||
subscribeEditDialog.value = false
|
||||
emit('save')
|
||||
}
|
||||
|
||||
// 订阅编辑取消
|
||||
function onSubscribeEditRemove() {
|
||||
subscribeEditDialog.value = false
|
||||
emit('remove')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -297,20 +319,18 @@ const posterUrl = computed(() => {
|
||||
v-if="subscribeEditDialog"
|
||||
v-model="subscribeEditDialog"
|
||||
:subid="props.media?.id"
|
||||
@remove="
|
||||
() => {
|
||||
emit('remove')
|
||||
subscribeEditDialog = false
|
||||
}
|
||||
"
|
||||
@save="
|
||||
() => {
|
||||
emit('save')
|
||||
subscribeEditDialog = false
|
||||
}
|
||||
"
|
||||
@remove="onSubscribeEditRemove"
|
||||
@save="onSubscribeEditSave"
|
||||
@close="subscribeEditDialog = false"
|
||||
/>
|
||||
|
||||
<!-- 订阅文件信息弹窗 -->
|
||||
<SubscribeFilesDialog
|
||||
v-if="subscribeFilesDialog"
|
||||
v-model="subscribeFilesDialog"
|
||||
:subid="props.media?.id"
|
||||
@close="subscribeFilesDialog = false"
|
||||
/>
|
||||
</template>
|
||||
<style lang="scss">
|
||||
.subscribe-card-background {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { useToast } from 'vue-toast-notification'
|
||||
import { numberValidator } from '@/@validators'
|
||||
import api from '@/api'
|
||||
import type { MediaDirectory, Site, Subscribe } from '@/api/types'
|
||||
import type { Site, Subscribe, TransferDirectoryConf } from '@/api/types'
|
||||
import { useDisplay } from 'vuetify'
|
||||
import { useConfirm } from 'vuetify-use-dialog'
|
||||
|
||||
@@ -26,7 +26,7 @@ const emit = defineEmits(['remove', 'save', 'close'])
|
||||
const siteList = ref<Site[]>([])
|
||||
|
||||
// 下载目录列表
|
||||
const downloadDirectories = ref<MediaDirectory[]>([])
|
||||
const downloadDirectories = ref<TransferDirectoryConf[]>([])
|
||||
|
||||
// 站点选择下载框
|
||||
const selectSitesOptions = ref<{ [key: number]: string }[]>([])
|
||||
@@ -185,7 +185,7 @@ async function loadDownloadDirectories() {
|
||||
// 保存目录下拉框
|
||||
const targetDirectories = computed(() => {
|
||||
// 去重后的下载目录
|
||||
const directories = downloadDirectories.value.map(item => item.path)
|
||||
const directories = downloadDirectories.value.map(item => item.download_path)
|
||||
return [...new Set(directories)]
|
||||
})
|
||||
|
||||
|
||||
301
src/components/dialog/SubscribeFilesDialog.vue
Normal file
301
src/components/dialog/SubscribeFilesDialog.vue
Normal file
@@ -0,0 +1,301 @@
|
||||
<script setup lang="ts">
|
||||
import api from '@/api'
|
||||
import { SubscrbieInfo } from '@/api/types'
|
||||
import { useDisplay } from 'vuetify'
|
||||
|
||||
// 显示器宽度
|
||||
const display = useDisplay()
|
||||
|
||||
//定义输入参数
|
||||
const props = defineProps({
|
||||
subid: Number,
|
||||
})
|
||||
|
||||
const activeTab = ref('download')
|
||||
|
||||
// 定义触发的自定义事件
|
||||
const emit = defineEmits(['close'])
|
||||
|
||||
// 订阅文件信息
|
||||
const subScribeInfo = ref<SubscrbieInfo>()
|
||||
|
||||
// 下载文件表头
|
||||
const downloadHeaders = [
|
||||
{ title: '集', key: 'episode_number', sortable: true },
|
||||
{ title: '种子', key: 'torrent_title', sortable: true },
|
||||
{ title: '文件', key: 'file_path', sortable: true },
|
||||
]
|
||||
|
||||
// 媒体库文件表头
|
||||
const libraryHeaders = [
|
||||
{ title: '集', key: 'episode_number', sortable: true },
|
||||
{ title: '文件', key: 'file_path', sortable: true },
|
||||
]
|
||||
|
||||
// 调用API查询订阅文件信息
|
||||
async function loadSubscribeFilesInfo() {
|
||||
try {
|
||||
subScribeInfo.value = await api.get(`subscribe/files/${props.subid}`)
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
}
|
||||
|
||||
// 计算下载文件列表
|
||||
const downloadInfos = computed(() => {
|
||||
return Object.keys(subScribeInfo.value?.episodes ?? {}).map((key: number) => {
|
||||
const item = subScribeInfo.value?.episodes[key]
|
||||
return {
|
||||
episode_number: key,
|
||||
title: item?.title,
|
||||
download: item?.download ?? [],
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// 总集数
|
||||
const totalCount = computed(() => {
|
||||
return Object.keys(subScribeInfo.value?.episodes ?? {}).length
|
||||
})
|
||||
|
||||
// 计算媒体库文件列表
|
||||
const libraryInfos = computed(() => {
|
||||
return Object.keys(subScribeInfo.value?.episodes ?? {}).map((key: number) => {
|
||||
const item = subScribeInfo.value?.episodes[key]
|
||||
return {
|
||||
episode_number: key,
|
||||
title: item?.title,
|
||||
library: item?.library ?? [],
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
onBeforeMount(() => {
|
||||
loadSubscribeFilesInfo()
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<VDialog scrollable max-width="80rem" :fullscreen="!display.mdAndUp.value">
|
||||
<VCard class="rounded-t">
|
||||
<VCardItem>
|
||||
<DialogCloseBtn @click="emit('close')" />
|
||||
</VCardItem>
|
||||
<VCardText>
|
||||
<div class="media-page">
|
||||
<div class="media-header">
|
||||
<div class="media-poster">
|
||||
<VImg
|
||||
:src="subScribeInfo?.subscribe?.poster"
|
||||
cover
|
||||
class="object-cover aspect-w-2 aspect-h-3 ring-1 ring-gray-500"
|
||||
>
|
||||
<template #placeholder>
|
||||
<div class="w-full h-full">
|
||||
<VSkeletonLoader class="object-cover aspect-w-2 aspect-h-3" />
|
||||
</div>
|
||||
</template>
|
||||
</VImg>
|
||||
</div>
|
||||
<div class="media-title">
|
||||
<h1 class="d-flex flex-column flex-lg-row align-baseline justify-center justify-lg-start">
|
||||
<div class="align-self-center align-self-lg-end">
|
||||
{{ subScribeInfo?.subscribe?.name }}
|
||||
</div>
|
||||
<div v-if="subScribeInfo?.subscribe?.season" class="text-lg align-self-center align-self-lg-end ms-3">
|
||||
第 {{ subScribeInfo?.subscribe?.season }} 季
|
||||
</div>
|
||||
</h1>
|
||||
<div>{{ subScribeInfo?.subscribe?.year }}</div>
|
||||
<div class="media-overview">
|
||||
<div class="media-overview-left">
|
||||
<p>{{ subScribeInfo?.subscribe?.description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-7">
|
||||
<VTabs v-model="activeTab" show-arrows class="v-tabs-pill">
|
||||
<VTab value="download" selected-class="v-slide-group-item--active v-tab--selected">
|
||||
<div>
|
||||
<VIcon size="20" start icon="mdi-download" />
|
||||
下载文件
|
||||
</div>
|
||||
</VTab>
|
||||
<VTab value="library" selected-class="v-slide-group-item--active v-tab--selected">
|
||||
<div>
|
||||
<VIcon size="20" start icon="mdi-filmstrip-box-multiple" />
|
||||
媒体库文件
|
||||
</div>
|
||||
</VTab>
|
||||
</VTabs>
|
||||
<VWindow v-model="activeTab" class="mt-5 disable-tab-transition" :touch="false">
|
||||
<VWindowItem value="download">
|
||||
<transition name="fade-slide" appear>
|
||||
<VDataTable
|
||||
items-per-page="50"
|
||||
:headers="downloadHeaders"
|
||||
:items="downloadInfos"
|
||||
:items-length="totalCount"
|
||||
density="compact"
|
||||
item-value="title"
|
||||
return-object
|
||||
fixed-header
|
||||
hover
|
||||
items-per-page-text="每页条数"
|
||||
page-text="{0}-{1} 共 {2} 条"
|
||||
loading-text="加载中..."
|
||||
>
|
||||
<template #item.episode_number="{ item }">
|
||||
<div class="text-high-emphasis pt-1">{{ item.episode_number }}. {{ item.title }}</div>
|
||||
</template>
|
||||
<template #item.torrent_title="{ item }">
|
||||
<div class="text-sm" v-for="file in item.download">
|
||||
【{{ file.site_name }}】{{ file.torrent_name }}
|
||||
</div>
|
||||
</template>
|
||||
<template #item.file_path="{ item }">
|
||||
<div class="text-sm" v-for="file in item.download">{{ file.file_path }}</div>
|
||||
</template>
|
||||
<template #no-data> 没有数据 </template>
|
||||
</VDataTable>
|
||||
</transition>
|
||||
</VWindowItem>
|
||||
<VWindowItem value="library">
|
||||
<transition name="fade-slide" appear>
|
||||
<VDataTable
|
||||
items-per-page="50"
|
||||
:headers="libraryHeaders"
|
||||
:items="libraryInfos"
|
||||
:items-length="totalCount"
|
||||
density="compact"
|
||||
item-value="title"
|
||||
return-object
|
||||
fixed-header
|
||||
hover
|
||||
items-per-page-text="每页条数"
|
||||
page-text="{0}-{1} 共 {2} 条"
|
||||
loading-text="加载中..."
|
||||
>
|
||||
<template #item.episode_number="{ item }">
|
||||
<div class="text-high-emphasis pt-1">{{ item.episode_number }}. {{ item.title }}</div>
|
||||
</template>
|
||||
<template #item.file_path="{ item }">
|
||||
<div class="text-sm" v-for="file in item.library">【{{ file.storage }}】{{ file.file_path }}</div>
|
||||
</template>
|
||||
<template #no-data> 没有数据 </template>
|
||||
</VDataTable>
|
||||
</transition>
|
||||
</VWindowItem>
|
||||
</VWindow>
|
||||
</div>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
</VDialog>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.vue-media-back {
|
||||
background-image: linear-gradient(
|
||||
180deg,
|
||||
rgba(var(--v-theme-background), 0) 50%,
|
||||
rgba(var(--v-theme-background), 1) 100%
|
||||
),
|
||||
linear-gradient(90deg, rgba(var(--v-theme-background), 0) 50%, rgba(var(--v-theme-background), 1) 100%),
|
||||
linear-gradient(270deg, rgba(var(--v-theme-background), 0) 50%, rgba(var(--v-theme-background), 1) 100%);
|
||||
box-shadow: 0 0 0 2px rgb(var(--v-theme-background));
|
||||
margin-block-start: calc(-70px - env(safe-area-inset-top));
|
||||
}
|
||||
|
||||
.media-page {
|
||||
position: relative;
|
||||
background-position: 50%;
|
||||
background-size: cover;
|
||||
margin-block-start: calc(-4rem - env(safe-area-inset-top));
|
||||
padding-block-start: calc(4rem + env(safe-area-inset-top));
|
||||
padding-inline: 1rem;
|
||||
}
|
||||
|
||||
.media-header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding-block-start: 1rem;
|
||||
}
|
||||
|
||||
@media (width >= 1280px) {
|
||||
.media-header {
|
||||
flex-direction: row;
|
||||
align-items: flex-end;
|
||||
}
|
||||
}
|
||||
|
||||
.media-overview {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-block: 1rem 1rem;
|
||||
}
|
||||
|
||||
@media (width >= 1024px) {
|
||||
.media-overview {
|
||||
flex-direction: row;
|
||||
}
|
||||
}
|
||||
|
||||
.media-poster {
|
||||
overflow: hidden;
|
||||
border-radius: 0.25rem;
|
||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||
inline-size: 8rem;
|
||||
|
||||
--tw-shadow: 0 1px 3px 0 rgba(0, 0, 0, 10%), 0 1px 2px -1px rgba(0, 0, 0, 10%);
|
||||
--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);
|
||||
}
|
||||
|
||||
@media (width >= 1280px) {
|
||||
.media-poster {
|
||||
inline-size: 13rem;
|
||||
margin-inline-end: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (width >= 768px) {
|
||||
.media-poster {
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||
inline-size: 11rem;
|
||||
|
||||
--tw-shadow: 0 25px 50px -12px rgba(0, 0, 0, 25%);
|
||||
--tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);
|
||||
}
|
||||
}
|
||||
|
||||
.media-title {
|
||||
display: flex;
|
||||
flex: 1 1 0%;
|
||||
flex-direction: column;
|
||||
margin-block-start: 1rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media (width >= 1280px) {
|
||||
.media-title {
|
||||
margin-block-start: 0;
|
||||
margin-inline-end: 1rem;
|
||||
text-align: start;
|
||||
}
|
||||
}
|
||||
|
||||
.media-title > h1 {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
line-height: 2rem;
|
||||
}
|
||||
|
||||
@media (width >= 1280px) {
|
||||
.media-title > h1 {
|
||||
font-size: 2.25rem;
|
||||
line-height: 2.5rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts" setup>
|
||||
import api from '@/api'
|
||||
import type { MediaInfo, TorrentInfo } from '@/api/types'
|
||||
import type { TorrentInfo } from '@/api/types'
|
||||
import { formatFileSize } from '@core/utils/formatters'
|
||||
import AddDownloadDialog from '../dialog/AddDownloadDialog.vue'
|
||||
|
||||
|
||||
Reference in New Issue
Block a user