mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-04 23:18:44 +08:00
feat 站点资源
This commit is contained in:
@@ -1,9 +1,10 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { PropType } from 'vue'
|
import type { PropType } from 'vue'
|
||||||
import { useToast } from 'vue-toast-notification'
|
import { useToast } from 'vue-toast-notification'
|
||||||
|
import { formatFileSize } from '@core/utils/formatters'
|
||||||
import { numberValidator, requiredValidator } from '@/@validators'
|
import { numberValidator, requiredValidator } from '@/@validators'
|
||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
import type { Site } from '@/api/types'
|
import type { Site, TorrentInfo } from '@/api/types'
|
||||||
import ExistIcon from '@core/components/ExistIcon.vue'
|
import ExistIcon from '@core/components/ExistIcon.vue'
|
||||||
|
|
||||||
// 输入参数
|
// 输入参数
|
||||||
@@ -40,85 +41,48 @@ const siteCookieDialog = ref(false)
|
|||||||
// 站点编辑弹窗
|
// 站点编辑弹窗
|
||||||
const siteInfoDialog = ref(false)
|
const siteInfoDialog = ref(false)
|
||||||
|
|
||||||
|
// 资源浏览弹窗
|
||||||
|
const resourceDialog = ref(false)
|
||||||
|
|
||||||
|
// 资源浏览表头
|
||||||
|
const resourceHeaders = [
|
||||||
|
{ title: '标题', key: 'title', sortable: false },
|
||||||
|
{ title: '时间', key: 'pubdate', sortable: false },
|
||||||
|
{ title: '大小', key: 'size', sortable: false },
|
||||||
|
{ title: '做种', key: 'seeders', sortable: false },
|
||||||
|
{ title: '下载', key: 'peers', sortable: false },
|
||||||
|
{ title: '', key: 'actions', sortable: false },
|
||||||
|
]
|
||||||
|
|
||||||
|
// 数据列表
|
||||||
|
const resourceDataList = ref<TorrentInfo[]>([])
|
||||||
|
|
||||||
|
// 搜索
|
||||||
|
const resourceSearch = ref('')
|
||||||
|
|
||||||
|
// 加载状态
|
||||||
|
const resourceLoading = ref(false)
|
||||||
|
|
||||||
|
// 总条数
|
||||||
|
const resourceTotalItems = ref(1000)
|
||||||
|
|
||||||
|
// 每页条数
|
||||||
|
const resourceItemsPerPage = ref(100)
|
||||||
|
|
||||||
|
// 当前页码
|
||||||
|
const resourceCurrentPage = ref(1)
|
||||||
|
|
||||||
// 用户名密码表单
|
// 用户名密码表单
|
||||||
const userPwForm = ref({
|
const userPwForm = ref({
|
||||||
username: '',
|
username: '',
|
||||||
password: '',
|
password: '',
|
||||||
})
|
})
|
||||||
|
|
||||||
// 查询站点图标
|
// 状态下拉项
|
||||||
async function getSiteIcon() {
|
const statusItems = [
|
||||||
try {
|
{ title: '启用', value: true },
|
||||||
siteIcon.value = (await api.get(`site/icon/${cardProps.site?.id}`)).data.icon
|
{ title: '停用', value: false },
|
||||||
}
|
]
|
||||||
catch (error) {
|
|
||||||
console.error(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 测试站点连通性
|
|
||||||
async function testSite() {
|
|
||||||
try {
|
|
||||||
testButtonText.value = '测试中 ...'
|
|
||||||
testButtonDisable.value = true
|
|
||||||
|
|
||||||
const result: { [key: string]: any } = await api.get(`site/test/${cardProps.site?.id}`)
|
|
||||||
if (result.success)
|
|
||||||
$toast.success(`${cardProps.site?.name} 连通性测试成功,可正常使用!`)
|
|
||||||
else
|
|
||||||
$toast.error(`${cardProps.site?.name} 连通性测试失败:${result.message}`)
|
|
||||||
|
|
||||||
testButtonText.value = '测试'
|
|
||||||
testButtonDisable.value = false
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
console.error(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 打开更新站点Cookie UA弹窗
|
|
||||||
async function handleSiteUpdate() {
|
|
||||||
siteCookieDialog.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// 打开站点编辑弹窗
|
|
||||||
async function handleSiteInfo() {
|
|
||||||
siteInfoDialog.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// 调用API,更新站点Cookie UA
|
|
||||||
async function updateSiteCookie() {
|
|
||||||
try {
|
|
||||||
if (!userPwForm.value.username || !userPwForm.value.password)
|
|
||||||
return
|
|
||||||
|
|
||||||
// 更新按钮状态
|
|
||||||
siteCookieDialog.value = false
|
|
||||||
updateButtonText.value = '更新中 ...'
|
|
||||||
updateButtonDisable.value = true
|
|
||||||
|
|
||||||
const result: { [key: string]: any } = await api.get(
|
|
||||||
`site/cookie/${cardProps.site?.id}`,
|
|
||||||
{
|
|
||||||
params: {
|
|
||||||
username: userPwForm.value.username,
|
|
||||||
password: userPwForm.value.password,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
if (result.success)
|
|
||||||
$toast.success(`${cardProps.site?.name} 更新Cookie & UA 成功!`)
|
|
||||||
else
|
|
||||||
$toast.error(`${cardProps.site?.name} 更新失败:${result.message}`)
|
|
||||||
|
|
||||||
updateButtonText.value = '更新'
|
|
||||||
updateButtonDisable.value = false
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
console.error(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 站点编辑表单数据
|
// 站点编辑表单数据
|
||||||
const siteForm = reactive({
|
const siteForm = reactive({
|
||||||
@@ -174,6 +138,96 @@ const siteForm = reactive({
|
|||||||
is_active: cardProps.site?.is_active,
|
is_active: cardProps.site?.is_active,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 打开种子详情页面
|
||||||
|
function openTorrentDetail(page_url: string) {
|
||||||
|
window.open(page_url, '_blank')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 下载种子文件
|
||||||
|
async function downloadTorrentFile(enclosure: string) {
|
||||||
|
window.open(enclosure, '_blank')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询站点图标
|
||||||
|
async function getSiteIcon() {
|
||||||
|
try {
|
||||||
|
siteIcon.value = (await api.get(`site/icon/${cardProps.site?.id}`)).data.icon
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试站点连通性
|
||||||
|
async function testSite() {
|
||||||
|
try {
|
||||||
|
testButtonText.value = '测试中 ...'
|
||||||
|
testButtonDisable.value = true
|
||||||
|
|
||||||
|
const result: { [key: string]: any } = await api.get(`site/test/${cardProps.site?.id}`)
|
||||||
|
if (result.success)
|
||||||
|
$toast.success(`${cardProps.site?.name} 连通性测试成功,可正常使用!`)
|
||||||
|
else
|
||||||
|
$toast.error(`${cardProps.site?.name} 连通性测试失败:${result.message}`)
|
||||||
|
|
||||||
|
testButtonText.value = '测试'
|
||||||
|
testButtonDisable.value = false
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打开更新站点Cookie UA弹窗
|
||||||
|
async function handleSiteUpdate() {
|
||||||
|
siteCookieDialog.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打开站点编辑弹窗
|
||||||
|
async function handleSiteInfo() {
|
||||||
|
siteInfoDialog.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打开资源浏览弹窗
|
||||||
|
async function handleResourceBrowse() {
|
||||||
|
resourceDialog.value = true
|
||||||
|
getResourceList()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用API,更新站点Cookie UA
|
||||||
|
async function updateSiteCookie() {
|
||||||
|
try {
|
||||||
|
if (!userPwForm.value.username || !userPwForm.value.password)
|
||||||
|
return
|
||||||
|
|
||||||
|
// 更新按钮状态
|
||||||
|
siteCookieDialog.value = false
|
||||||
|
updateButtonText.value = '更新中 ...'
|
||||||
|
updateButtonDisable.value = true
|
||||||
|
|
||||||
|
const result: { [key: string]: any } = await api.get(
|
||||||
|
`site/cookie/${cardProps.site?.id}`,
|
||||||
|
{
|
||||||
|
params: {
|
||||||
|
username: userPwForm.value.username,
|
||||||
|
password: userPwForm.value.password,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
if (result.success)
|
||||||
|
$toast.success(`${cardProps.site?.name} 更新Cookie & UA 成功!`)
|
||||||
|
else
|
||||||
|
$toast.error(`${cardProps.site?.name} 更新失败:${result.message}`)
|
||||||
|
|
||||||
|
updateButtonText.value = '更新'
|
||||||
|
updateButtonDisable.value = false
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 调用API更新站点信息
|
// 调用API更新站点信息
|
||||||
async function updateSiteInfo() {
|
async function updateSiteInfo() {
|
||||||
try {
|
try {
|
||||||
@@ -192,11 +246,23 @@ async function updateSiteInfo() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 状态下拉项
|
// 调用API,查询站点资源
|
||||||
const statusItems = [
|
async function getResourceList() {
|
||||||
{ title: '启用', value: true },
|
resourceLoading.value = true
|
||||||
{ title: '停用', value: false },
|
try {
|
||||||
]
|
resourceDataList.value = await api.get('search/title', {
|
||||||
|
params: {
|
||||||
|
keyword: resourceSearch.value,
|
||||||
|
page: resourceCurrentPage.value,
|
||||||
|
site: cardProps.site?.id,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
resourceLoading.value = false
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 装载时查询站点图标
|
// 装载时查询站点图标
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
@@ -210,7 +276,7 @@ onMounted(() => {
|
|||||||
:width="cardProps.width"
|
:width="cardProps.width"
|
||||||
:flat="!siteForm.is_active"
|
:flat="!siteForm.is_active"
|
||||||
class="overflow-hidden"
|
class="overflow-hidden"
|
||||||
@click="siteInfoDialog = true"
|
@click="handleSiteInfo"
|
||||||
>
|
>
|
||||||
<template #image>
|
<template #image>
|
||||||
<VAvatar
|
<VAvatar
|
||||||
@@ -299,12 +365,6 @@ onMounted(() => {
|
|||||||
</template>
|
</template>
|
||||||
{{ updateButtonText }}
|
{{ updateButtonText }}
|
||||||
</VBtn>
|
</VBtn>
|
||||||
<VBtn @click.stop="handleSiteInfo">
|
|
||||||
<template #prepend>
|
|
||||||
<VIcon icon="mdi-square-edit-outline" />
|
|
||||||
</template>
|
|
||||||
编辑
|
|
||||||
</VBtn>
|
|
||||||
<VBtn
|
<VBtn
|
||||||
:disabled="testButtonDisable"
|
:disabled="testButtonDisable"
|
||||||
@click.stop="testSite"
|
@click.stop="testSite"
|
||||||
@@ -314,6 +374,12 @@ onMounted(() => {
|
|||||||
</template>
|
</template>
|
||||||
{{ testButtonText }}
|
{{ testButtonText }}
|
||||||
</VBtn>
|
</VBtn>
|
||||||
|
<VBtn @click.stop="handleResourceBrowse">
|
||||||
|
<template #prepend>
|
||||||
|
<VIcon icon="mdi-web" />
|
||||||
|
</template>
|
||||||
|
浏览
|
||||||
|
</VBtn>
|
||||||
</VCardActions>
|
</VCardActions>
|
||||||
</VCard>
|
</VCard>
|
||||||
<!-- 更新站点Cookie & UA弹窗 -->
|
<!-- 更新站点Cookie & UA弹窗 -->
|
||||||
@@ -488,4 +554,96 @@ onMounted(() => {
|
|||||||
</VCardActions>
|
</VCardActions>
|
||||||
</VCard>
|
</VCard>
|
||||||
</VDialog>
|
</VDialog>
|
||||||
|
<!-- 站点资源弹窗 -->
|
||||||
|
<VDialog
|
||||||
|
v-model="resourceDialog"
|
||||||
|
max-width="1600"
|
||||||
|
scrollable
|
||||||
|
>
|
||||||
|
<!-- Dialog Content -->
|
||||||
|
<VCard :title="`浏览站点 - ${cardProps.site?.name}`">
|
||||||
|
<DialogCloseBtn @click="resourceDialog = false" />
|
||||||
|
<VCardText class="pt-2">
|
||||||
|
<VDataTable
|
||||||
|
v-model:items-per-page="resourceItemsPerPage"
|
||||||
|
:headers="resourceHeaders"
|
||||||
|
:items="resourceDataList"
|
||||||
|
:items-length="resourceTotalItems"
|
||||||
|
:search="resourceSearch"
|
||||||
|
:loading="resourceLoading"
|
||||||
|
density="compact"
|
||||||
|
item-value="id"
|
||||||
|
return-object
|
||||||
|
fixed-header
|
||||||
|
items-per-page-text="每页条数"
|
||||||
|
page-text="{0}-{1} 共 {2} 条"
|
||||||
|
>
|
||||||
|
<template #item.title="{ item }">
|
||||||
|
<div>{{ item.raw.title }}</div>
|
||||||
|
<small>{{ item.raw.description }}</small>
|
||||||
|
<VChip
|
||||||
|
v-for="(label, index) in item.raw?.labels"
|
||||||
|
:key="index"
|
||||||
|
variant="elevated"
|
||||||
|
size="small"
|
||||||
|
color="primary"
|
||||||
|
class="me-1 mb-1"
|
||||||
|
>
|
||||||
|
{{ label }}
|
||||||
|
</VChip>
|
||||||
|
</template>
|
||||||
|
<template #item.pubdate="{ item }">
|
||||||
|
<div>{{ item.raw.date_elapsed }}</div>
|
||||||
|
<small>{{ item.raw.pubdate }}</small>
|
||||||
|
</template>
|
||||||
|
<template #item.size="{ item }">
|
||||||
|
<div>{{ formatFileSize(item.raw.size) }}</div>
|
||||||
|
</template>
|
||||||
|
<template #item.seeders="{ item }">
|
||||||
|
<div>{{ item.raw.seeders }}</div>
|
||||||
|
</template>
|
||||||
|
<template #item.peers="{ item }">
|
||||||
|
<div>{{ item.raw.peers }}</div>
|
||||||
|
</template>
|
||||||
|
<template #item.actions="{ item }">
|
||||||
|
<div class="me-n3">
|
||||||
|
<IconBtn>
|
||||||
|
<VIcon
|
||||||
|
icon="mdi-dots-vertical"
|
||||||
|
/>
|
||||||
|
<VMenu
|
||||||
|
activator="parent"
|
||||||
|
close-on-content-click
|
||||||
|
>
|
||||||
|
<VList>
|
||||||
|
<VListItem
|
||||||
|
variant="plain"
|
||||||
|
@click="openTorrentDetail(item.raw.page_url)"
|
||||||
|
>
|
||||||
|
<template #prepend>
|
||||||
|
<VIcon icon="mdi-information" />
|
||||||
|
</template>
|
||||||
|
<VListItemTitle>查看详情</VListItemTitle>
|
||||||
|
</VListItem>
|
||||||
|
<VListItem
|
||||||
|
variant="plain"
|
||||||
|
@click="downloadTorrentFile(item.raw.enclosure)"
|
||||||
|
>
|
||||||
|
<template #prepend>
|
||||||
|
<VIcon icon="mdi-download" />
|
||||||
|
</template>
|
||||||
|
<VListItemTitle>下载种子</VListItemTitle>
|
||||||
|
</VListItem>
|
||||||
|
</VList>
|
||||||
|
</VMenu>
|
||||||
|
</IconBtn>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #no-data>
|
||||||
|
没有数据
|
||||||
|
</template>
|
||||||
|
</VDataTable>
|
||||||
|
</VCardText>
|
||||||
|
</VCard>
|
||||||
|
</VDialog>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -168,7 +168,7 @@ function getW500Image(url = '') {
|
|||||||
variant="elevated"
|
variant="elevated"
|
||||||
color="success"
|
color="success"
|
||||||
class="me-1 mb-1"
|
class="me-1 mb-1"
|
||||||
@click="openTmdbPage(nameTestResult?.media_info?.type, nameTestResult?.media_info?.tmdb_id)"
|
@click="openTmdbPage(nameTestResult?.media_info?.type || '', nameTestResult?.media_info?.tmdb_id)"
|
||||||
>
|
>
|
||||||
{{ nameTestResult?.media_info?.tmdb_id }}
|
{{ nameTestResult?.media_info?.tmdb_id }}
|
||||||
</VChip>
|
</VChip>
|
||||||
|
|||||||
Reference in New Issue
Block a user