mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-05 23:56:42 +08:00
refactor: 优化站点卡片组件
This commit is contained in:
@@ -6,15 +6,15 @@ import SiteUserDataDialog from '../dialog/SiteUserDataDialog.vue'
|
|||||||
import SiteResourceDialog from '../dialog/SiteResourceDialog.vue'
|
import SiteResourceDialog from '../dialog/SiteResourceDialog.vue'
|
||||||
import SiteCookieUpdateDialog from '../dialog/SiteCookieUpdateDialog.vue'
|
import SiteCookieUpdateDialog from '../dialog/SiteCookieUpdateDialog.vue'
|
||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
import type { Site, SiteStatistic } from '@/api/types'
|
import type { Site, SiteStatistic, SiteUserData } from '@/api/types'
|
||||||
import { isNullOrEmptyObject } from '@/@core/utils'
|
import { isNullOrEmptyObject } from '@/@core/utils'
|
||||||
import { VCardActions, VExpandTransition, VSpacer } from 'vuetify/lib/components/index.mjs'
|
import { VCardActions, VExpandTransition, VProgressLinear, VSpacer } from 'vuetify/lib/components/index.mjs'
|
||||||
|
import { formatFileSize } from '@/@core/utils/formatters'
|
||||||
|
|
||||||
// 输入参数
|
// 输入参数
|
||||||
const cardProps = defineProps({
|
const cardProps = defineProps({
|
||||||
site: Object as PropType<Site>,
|
site: Object as PropType<Site>,
|
||||||
width: String,
|
data: Object as PropType<SiteUserData>,
|
||||||
height: String,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// 定义触发的自定义事件
|
// 定义触发的自定义事件
|
||||||
@@ -121,6 +121,12 @@ const statColor = computed(() => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 计算上传量和下载量的百分比
|
||||||
|
const getPercentage = computed(() => {
|
||||||
|
if (cardProps.data?.upload === 0) return 100
|
||||||
|
return ((cardProps.data?.download ?? 0) / ((cardProps.data?.download ?? 0) + (cardProps.data?.upload ?? 0))) * 100
|
||||||
|
})
|
||||||
|
|
||||||
// 保存站点
|
// 保存站点
|
||||||
function saveSite() {
|
function saveSite() {
|
||||||
siteEditDialog.value = false
|
siteEditDialog.value = false
|
||||||
@@ -149,8 +155,6 @@ onMounted(() => {
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<VCard
|
<VCard
|
||||||
:height="cardProps.height"
|
|
||||||
:width="cardProps.width"
|
|
||||||
:variant="cardProps.site?.is_active ? 'elevated' : 'outlined'"
|
:variant="cardProps.site?.is_active ? 'elevated' : 'outlined'"
|
||||||
class="overflow-hidden"
|
class="overflow-hidden"
|
||||||
@click="siteEditDialog = true"
|
@click="siteEditDialog = true"
|
||||||
@@ -195,6 +199,9 @@ onMounted(() => {
|
|||||||
:icon="siteActionShow ? 'mdi-chevron-up' : 'mdi-chevron-down'"
|
:icon="siteActionShow ? 'mdi-chevron-up' : 'mdi-chevron-down'"
|
||||||
@click.stop="siteActionShow = !siteActionShow"
|
@click.stop="siteActionShow = !siteActionShow"
|
||||||
/>
|
/>
|
||||||
|
<span class="text-sm">
|
||||||
|
↑ {{ formatFileSize(cardProps.data?.upload || 0) }} / ↓ {{ formatFileSize(cardProps.data?.download || 0) }}
|
||||||
|
</span>
|
||||||
<VSpacer />
|
<VSpacer />
|
||||||
</VCardActions>
|
</VCardActions>
|
||||||
<VDivider class="mb-1" v-if="siteActionShow" />
|
<VDivider class="mb-1" v-if="siteActionShow" />
|
||||||
@@ -230,6 +237,9 @@ onMounted(() => {
|
|||||||
<span class="absolute top-1 right-8">
|
<span class="absolute top-1 right-8">
|
||||||
<VIcon class="cursor-move">mdi-drag</VIcon>
|
<VIcon class="cursor-move">mdi-drag</VIcon>
|
||||||
</span>
|
</span>
|
||||||
|
<div class="w-full absolute bottom-0" v-if="(cardProps.data?.upload || cardProps.data?.download || 0) > 0">
|
||||||
|
<VProgressLinear :model-value="getPercentage" bg-color="success" color="warning" bg-opacity="0.5" height="3" />
|
||||||
|
</div>
|
||||||
</VCard>
|
</VCard>
|
||||||
<!-- 更新站点Cookie & UA弹窗 -->
|
<!-- 更新站点Cookie & UA弹窗 -->
|
||||||
<SiteCookieUpdateDialog
|
<SiteCookieUpdateDialog
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import draggable from 'vuedraggable'
|
import draggable from 'vuedraggable'
|
||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
import type { Site } from '@/api/types'
|
import type { Site, SiteUserData } from '@/api/types'
|
||||||
import SiteCard from '@/components/cards/SiteCard.vue'
|
import SiteCard from '@/components/cards/SiteCard.vue'
|
||||||
import NoDataFound from '@/components/NoDataFound.vue'
|
import NoDataFound from '@/components/NoDataFound.vue'
|
||||||
import SiteAddEditDialog from '@/components/dialog/SiteAddEditDialog.vue'
|
import SiteAddEditDialog from '@/components/dialog/SiteAddEditDialog.vue'
|
||||||
@@ -15,8 +15,11 @@ const appMode = computed(() => {
|
|||||||
return localStorage.getItem('MP_APPMODE') != '0' && display.mdAndDown.value
|
return localStorage.getItem('MP_APPMODE') != '0' && display.mdAndDown.value
|
||||||
})
|
})
|
||||||
|
|
||||||
// 数据列表
|
// 站点列表
|
||||||
const dataList = ref<Site[]>([])
|
const siteList = ref<Site[]>([])
|
||||||
|
|
||||||
|
// 站点数据列表
|
||||||
|
const userDataList = ref<SiteUserData[]>([])
|
||||||
|
|
||||||
// 是否刷新过
|
// 是否刷新过
|
||||||
const isRefreshed = ref(false)
|
const isRefreshed = ref(false)
|
||||||
@@ -31,7 +34,7 @@ const siteAddDialog = ref(false)
|
|||||||
async function fetchData() {
|
async function fetchData() {
|
||||||
try {
|
try {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
dataList.value = await api.get('site/')
|
siteList.value = await api.get('site/')
|
||||||
loading.value = false
|
loading.value = false
|
||||||
isRefreshed.value = true
|
isRefreshed.value = true
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -39,10 +42,19 @@ async function fetchData() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取站点最新数据
|
||||||
|
async function fetchUserData() {
|
||||||
|
try {
|
||||||
|
userDataList.value = await api.get('site/userdata/latest')
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 保存站点排序
|
// 保存站点排序
|
||||||
async function savaSitesPriority() {
|
async function savaSitesPriority() {
|
||||||
// 重新排序
|
// 重新排序
|
||||||
const priorities = dataList.value.map((site, index) => ({ id: site.id, pri: index + 1 }))
|
const priorities = siteList.value.map((site, index) => ({ id: site.id, pri: index + 1 }))
|
||||||
try {
|
try {
|
||||||
const result: { [key: string]: any } = await api.post('site/priorities', priorities)
|
const result: { [key: string]: any } = await api.post('site/priorities', priorities)
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
@@ -53,6 +65,11 @@ async function savaSitesPriority() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 根据站点ID获取站点数据
|
||||||
|
function getUserData(domain: string) {
|
||||||
|
return userDataList.value.find(userData => userData.domain === domain)
|
||||||
|
}
|
||||||
|
|
||||||
// 更新站点事件时
|
// 更新站点事件时
|
||||||
function onSiteSave() {
|
function onSiteSave() {
|
||||||
siteAddDialog.value = false
|
siteAddDialog.value = false
|
||||||
@@ -60,11 +77,15 @@ function onSiteSave() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 加载时获取数据
|
// 加载时获取数据
|
||||||
onBeforeMount(fetchData)
|
onBeforeMount(() => {
|
||||||
|
fetchData()
|
||||||
|
fetchUserData()
|
||||||
|
})
|
||||||
|
|
||||||
onActivated(() => {
|
onActivated(() => {
|
||||||
if (!loading.value) {
|
if (!loading.value) {
|
||||||
fetchData()
|
fetchData()
|
||||||
|
fetchUserData()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
@@ -73,8 +94,8 @@ onActivated(() => {
|
|||||||
<LoadingBanner v-if="!isRefreshed" class="mt-12" />
|
<LoadingBanner v-if="!isRefreshed" class="mt-12" />
|
||||||
<div>
|
<div>
|
||||||
<draggable
|
<draggable
|
||||||
v-if="dataList.length > 0"
|
v-if="siteList.length > 0"
|
||||||
v-model="dataList"
|
v-model="siteList"
|
||||||
@end="savaSitesPriority"
|
@end="savaSitesPriority"
|
||||||
handle=".cursor-move"
|
handle=".cursor-move"
|
||||||
item-key="id"
|
item-key="id"
|
||||||
@@ -82,12 +103,12 @@ onActivated(() => {
|
|||||||
:component-data="{ 'class': 'grid gap-3 grid-site-card' }"
|
:component-data="{ 'class': 'grid gap-3 grid-site-card' }"
|
||||||
>
|
>
|
||||||
<template #item="{ element }">
|
<template #item="{ element }">
|
||||||
<SiteCard :site="element" @remove="fetchData" @update="fetchData" />
|
<SiteCard :site="element" :data="getUserData(element.domain)" @remove="fetchData" @update="fetchData" />
|
||||||
</template>
|
</template>
|
||||||
</draggable>
|
</draggable>
|
||||||
</div>
|
</div>
|
||||||
<NoDataFound
|
<NoDataFound
|
||||||
v-if="dataList.length === 0 && isRefreshed"
|
v-if="siteList.length === 0 && isRefreshed"
|
||||||
error-code="404"
|
error-code="404"
|
||||||
error-title="没有站点"
|
error-title="没有站点"
|
||||||
error-description="已添加并支持的站点将会在这里显示。"
|
error-description="已添加并支持的站点将会在这里显示。"
|
||||||
|
|||||||
Reference in New Issue
Block a user