mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-08-28 11:37:29 +08:00
优化 SiteCard 组件,调整样式和结构,提升可读性和用户体验
This commit is contained in:
@@ -122,10 +122,10 @@ const getMaxDataValue = computed(() => {
|
|||||||
// 获取站点数据中的最大值作为基准
|
// 获取站点数据中的最大值作为基准
|
||||||
const upload = cardProps.data?.upload || 0
|
const upload = cardProps.data?.upload || 0
|
||||||
const download = cardProps.data?.download || 0
|
const download = cardProps.data?.download || 0
|
||||||
|
|
||||||
// 避免两者都为0的情况
|
// 避免两者都为0的情况
|
||||||
if (upload === 0 && download === 0) return 1
|
if (upload === 0 && download === 0) return 1
|
||||||
|
|
||||||
return Math.max(upload, download)
|
return Math.max(upload, download)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -164,112 +164,78 @@ onMounted(() => {
|
|||||||
getSiteIcon()
|
getSiteIcon()
|
||||||
getSiteStats()
|
getSiteStats()
|
||||||
})
|
})
|
||||||
|
|
||||||
// 在 script 部分添加计算速度等级的函数
|
|
||||||
function calcSpeedClass(speed: number) {
|
|
||||||
if (speed === undefined || speed <= 0) return 'speed-idle';
|
|
||||||
if (speed < 50 * 1024) return 'speed-low';
|
|
||||||
if (speed < 500 * 1024) return 'speed-medium';
|
|
||||||
return 'speed-high';
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div
|
<VCard
|
||||||
class="site-card relative h-full flex flex-col overflow-hidden group"
|
class="site-card relative h-full flex flex-col overflow-hidden group"
|
||||||
:class="[
|
:class="[
|
||||||
cardProps.site?.is_active ? '' : 'inactive',
|
cardProps.site?.is_active ? '' : 'inactive',
|
||||||
{
|
{
|
||||||
'status-error': statColor === 'error',
|
'status-error': statColor === 'error',
|
||||||
'status-warning': statColor === 'warning',
|
'status-warning': statColor === 'warning',
|
||||||
'status-success': statColor === 'success'
|
'status-success': statColor === 'success',
|
||||||
}
|
},
|
||||||
]"
|
]"
|
||||||
|
:ripple="false"
|
||||||
@click="handleResourceBrowse"
|
@click="handleResourceBrowse"
|
||||||
>
|
>
|
||||||
<!-- 装饰性状态指示器 -->
|
<!-- 装饰性状态指示器 -->
|
||||||
<div
|
<div v-if="cardProps.site?.is_active" class="site-status-indicator" :class="statColor"></div>
|
||||||
v-if="cardProps.site?.is_active"
|
|
||||||
class="site-status-indicator"
|
|
||||||
:class="statColor"
|
|
||||||
></div>
|
|
||||||
|
|
||||||
<!-- 主体部分 -->
|
<!-- 主体部分 -->
|
||||||
<div class="site-card-content relative flex-1 flex flex-col">
|
<div class="site-card-content relative flex-1 flex flex-col">
|
||||||
<!-- 顶部:图标和站点名称 -->
|
<!-- 顶部:图标和站点名称 -->
|
||||||
<div class="flex items-center mb-1">
|
<div class="flex items-center mb-1">
|
||||||
<!-- 站点图标 -->
|
<!-- 站点图标 -->
|
||||||
<div
|
<div class="site-icon-container mr-2.5" @click.stop="siteEditDialog = true">
|
||||||
class="site-icon-container mr-2.5"
|
<img :src="siteIcon" class="site-icon" :alt="cardProps.site?.name" />
|
||||||
@click.stop="siteEditDialog = true"
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
:src="siteIcon"
|
|
||||||
class="site-icon"
|
|
||||||
:alt="cardProps.site?.name"
|
|
||||||
/>
|
|
||||||
<div class="site-icon-edit-overlay">
|
<div class="site-icon-edit-overlay">
|
||||||
<VIcon icon="mdi-pencil" color="white" size="16" />
|
<VIcon icon="mdi-pencil" color="white" size="16" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 拖动图标 -->
|
<!-- 拖动图标 -->
|
||||||
<VIcon icon="mdi-drag" size="16" class="drag-handle cursor-move opacity-40 mr-1.5 z-10" />
|
<VIcon icon="mdi-drag" size="20" class="drag-handle cursor-move opacity-40 mr-1.5 z-10" />
|
||||||
|
|
||||||
<!-- 站点名称和特性图标 -->
|
<!-- 站点名称和特性图标 -->
|
||||||
<div class="flex-1 min-w-0 flex items-center">
|
<div class="flex-1 min-w-0 flex items-center">
|
||||||
<h3 class="site-title truncate">{{ cardProps.site?.name }}</h3>
|
<h3 class="site-title truncate">{{ cardProps.site?.name }}</h3>
|
||||||
|
|
||||||
<!-- 站点特性图标 -->
|
<!-- 站点特性图标 -->
|
||||||
<div class="site-features flex items-center gap-1 ml-auto">
|
<div class="site-features flex items-center gap-1 ml-auto">
|
||||||
<VTooltip>
|
<VTooltip>
|
||||||
<template #activator="{ props }">
|
<template #activator="{ props }">
|
||||||
<div v-if="cardProps.site?.limit_interval" v-bind="props" class="feature-icon-wrapper">
|
<div v-if="cardProps.site?.limit_interval" v-bind="props" class="feature-icon-wrapper">
|
||||||
<VIcon
|
<VIcon icon="mdi-speedometer" size="16" class="site-feature-icon" />
|
||||||
icon="mdi-speedometer"
|
|
||||||
size="16"
|
|
||||||
class="site-feature-icon"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<span>流控</span>
|
<span>流控</span>
|
||||||
</VTooltip>
|
</VTooltip>
|
||||||
|
|
||||||
<VTooltip>
|
<VTooltip>
|
||||||
<template #activator="{ props }">
|
<template #activator="{ props }">
|
||||||
<div v-if="cardProps.site?.proxy === 1" v-bind="props" class="feature-icon-wrapper">
|
<div v-if="cardProps.site?.proxy === 1" v-bind="props" class="feature-icon-wrapper">
|
||||||
<VIcon
|
<VIcon icon="mdi-network-outline" size="16" class="site-feature-icon" />
|
||||||
icon="mdi-network-outline"
|
|
||||||
size="16"
|
|
||||||
class="site-feature-icon"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<span>代理</span>
|
<span>代理</span>
|
||||||
</VTooltip>
|
</VTooltip>
|
||||||
|
|
||||||
<VTooltip>
|
<VTooltip>
|
||||||
<template #activator="{ props }">
|
<template #activator="{ props }">
|
||||||
<div v-if="cardProps.site?.render === 1" v-bind="props" class="feature-icon-wrapper">
|
<div v-if="cardProps.site?.render === 1" v-bind="props" class="feature-icon-wrapper">
|
||||||
<VIcon
|
<VIcon icon="mdi-apple-safari" size="16" class="site-feature-icon" />
|
||||||
icon="mdi-apple-safari"
|
|
||||||
size="16"
|
|
||||||
class="site-feature-icon"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<span>仿真</span>
|
<span>仿真</span>
|
||||||
</VTooltip>
|
</VTooltip>
|
||||||
|
|
||||||
<VTooltip>
|
<VTooltip>
|
||||||
<template #activator="{ props }">
|
<template #activator="{ props }">
|
||||||
<div v-if="cardProps.site?.filter" v-bind="props" class="feature-icon-wrapper">
|
<div v-if="cardProps.site?.filter" v-bind="props" class="feature-icon-wrapper">
|
||||||
<VIcon
|
<VIcon icon="mdi-filter-cog-outline" size="16" class="site-feature-icon" />
|
||||||
icon="mdi-filter-cog-outline"
|
|
||||||
size="16"
|
|
||||||
class="site-feature-icon"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<span>过滤</span>
|
<span>过滤</span>
|
||||||
@@ -277,14 +243,14 @@ function calcSpeedClass(speed: number) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 中间部分:网址 -->
|
<!-- 中间部分:网址 -->
|
||||||
<div class="site-meta mb-1.5">
|
<div class="site-meta mb-1.5">
|
||||||
<div class="site-url truncate" @click.stop="openSitePage">
|
<div class="site-url truncate" @click.stop="openSitePage">
|
||||||
{{ cardProps.site?.url }}
|
{{ cardProps.site?.url }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 底部:数据统计 -->
|
<!-- 底部:数据统计 -->
|
||||||
<div class="site-stats flex-1 flex flex-col justify-end">
|
<div class="site-stats flex-1 flex flex-col justify-end">
|
||||||
<!-- 更直观的上传下载数据条 -->
|
<!-- 更直观的上传下载数据条 -->
|
||||||
@@ -296,15 +262,12 @@ function calcSpeedClass(speed: number) {
|
|||||||
<span>{{ formatFileSize(cardProps.data?.upload || 0) }}</span>
|
<span>{{ formatFileSize(cardProps.data?.upload || 0) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="data-progress-bar">
|
<div class="data-progress-bar">
|
||||||
<div
|
<div class="progress-filled upload-filled" :style="`width: ${getUploadPercent}%`">
|
||||||
class="progress-filled upload-filled"
|
|
||||||
:style="`width: ${getUploadPercent}%`"
|
|
||||||
>
|
|
||||||
<div class="progress-glow"></div>
|
<div class="progress-glow"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 下载数据 -->
|
<!-- 下载数据 -->
|
||||||
<div class="data-row download-row">
|
<div class="data-row download-row">
|
||||||
<div class="data-label">
|
<div class="data-label">
|
||||||
@@ -312,10 +275,7 @@ function calcSpeedClass(speed: number) {
|
|||||||
<span>{{ formatFileSize(cardProps.data?.download || 0) }}</span>
|
<span>{{ formatFileSize(cardProps.data?.download || 0) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="data-progress-bar">
|
<div class="data-progress-bar">
|
||||||
<div
|
<div class="progress-filled download-filled" :style="`width: ${getDownloadPercent}%`">
|
||||||
class="progress-filled download-filled"
|
|
||||||
:style="`width: ${getDownloadPercent}%`"
|
|
||||||
>
|
|
||||||
<div class="progress-glow"></div>
|
<div class="progress-glow"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -323,16 +283,16 @@ function calcSpeedClass(speed: number) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 右侧操作按钮区 -->
|
<!-- 右侧操作按钮区 -->
|
||||||
<div class="site-card-actions">
|
<div class="site-card-actions">
|
||||||
<VTooltip>
|
<VTooltip>
|
||||||
<template #activator="{ props }">
|
<template #activator="{ props }">
|
||||||
<button
|
<button
|
||||||
v-bind="props"
|
v-bind="props"
|
||||||
class="site-action-btn test-btn"
|
class="site-action-btn test-btn"
|
||||||
@click.stop="testSite"
|
@click.stop="testSite"
|
||||||
:class="{'testing': testButtonDisable}"
|
:class="{ 'testing': testButtonDisable }"
|
||||||
>
|
>
|
||||||
<div class="test-btn-content">
|
<div class="test-btn-content">
|
||||||
<div class="pulse-dot" :class="statColor"></div>
|
<div class="pulse-dot" :class="statColor"></div>
|
||||||
@@ -348,39 +308,28 @@ function calcSpeedClass(speed: number) {
|
|||||||
</template>
|
</template>
|
||||||
<span>测试站点连通性</span>
|
<span>测试站点连通性</span>
|
||||||
</VTooltip>
|
</VTooltip>
|
||||||
|
|
||||||
<VTooltip>
|
<VTooltip>
|
||||||
<template #activator="{ props }">
|
<template #activator="{ props }">
|
||||||
<button
|
<button v-bind="props" class="site-action-btn" @click.stop="handleSiteUserData">
|
||||||
v-bind="props"
|
|
||||||
class="site-action-btn"
|
|
||||||
@click.stop="handleSiteUserData"
|
|
||||||
>
|
|
||||||
<VIcon icon="mdi-chart-bell-curve" size="18" />
|
<VIcon icon="mdi-chart-bell-curve" size="18" />
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
<span>查看站点数据</span>
|
<span>查看站点数据</span>
|
||||||
</VTooltip>
|
</VTooltip>
|
||||||
|
|
||||||
<VTooltip v-if="!cardProps.site?.public">
|
<VTooltip v-if="!cardProps.site?.public">
|
||||||
<template #activator="{ props }">
|
<template #activator="{ props }">
|
||||||
<button
|
<button v-bind="props" class="site-action-btn" @click.stop="handleSiteUpdate">
|
||||||
v-bind="props"
|
|
||||||
class="site-action-btn"
|
|
||||||
@click.stop="handleSiteUpdate"
|
|
||||||
>
|
|
||||||
<VIcon icon="mdi-refresh" size="18" />
|
<VIcon icon="mdi-refresh" size="18" />
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
<span>更新Cookie/UA</span>
|
<span>更新Cookie/UA</span>
|
||||||
</VTooltip>
|
</VTooltip>
|
||||||
|
|
||||||
<VTooltip>
|
<VTooltip>
|
||||||
<template #activator="{ props }">
|
<template #activator="{ props }">
|
||||||
<button
|
<button v-bind="props" class="site-action-btn more-btn">
|
||||||
v-bind="props"
|
|
||||||
class="site-action-btn more-btn"
|
|
||||||
>
|
|
||||||
<VIcon icon="mdi-dots-vertical" size="18" />
|
<VIcon icon="mdi-dots-vertical" size="18" />
|
||||||
<VMenu activator="parent" close-on-content-click location="left">
|
<VMenu activator="parent" close-on-content-click location="left">
|
||||||
<VList density="compact" nav class="dropdown-menu">
|
<VList density="compact" nav class="dropdown-menu">
|
||||||
@@ -403,8 +352,8 @@ function calcSpeedClass(speed: number) {
|
|||||||
<span>更多操作</span>
|
<span>更多操作</span>
|
||||||
</VTooltip>
|
</VTooltip>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</VCard>
|
||||||
|
|
||||||
<!-- 对话框组件 -->
|
<!-- 对话框组件 -->
|
||||||
<SiteCookieUpdateDialog
|
<SiteCookieUpdateDialog
|
||||||
v-if="siteCookieDialog"
|
v-if="siteCookieDialog"
|
||||||
@@ -528,7 +477,7 @@ function calcSpeedClass(speed: number) {
|
|||||||
.data-label {
|
.data-label {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
font-size: 12px;
|
font-size: 0.8rem;
|
||||||
color: rgba(var(--v-theme-on-surface), 0.8);
|
color: rgba(var(--v-theme-on-surface), 0.8);
|
||||||
min-width: 70px;
|
min-width: 70px;
|
||||||
}
|
}
|
||||||
@@ -577,7 +526,8 @@ function calcSpeedClass(speed: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@keyframes pulse-width {
|
@keyframes pulse-width {
|
||||||
0%, 100% {
|
0%,
|
||||||
|
100% {
|
||||||
opacity: 0.85;
|
opacity: 0.85;
|
||||||
}
|
}
|
||||||
50% {
|
50% {
|
||||||
@@ -617,7 +567,8 @@ function calcSpeedClass(speed: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@keyframes pulse-width {
|
@keyframes pulse-width {
|
||||||
0%, 100% {
|
0%,
|
||||||
|
100% {
|
||||||
transform: scaleX(0.95);
|
transform: scaleX(0.95);
|
||||||
}
|
}
|
||||||
50% {
|
50% {
|
||||||
@@ -673,14 +624,14 @@ function calcSpeedClass(speed: number) {
|
|||||||
|
|
||||||
/* 站点标题 */
|
/* 站点标题 */
|
||||||
.site-title {
|
.site-title {
|
||||||
font-size: 15px;
|
font-size: 1.1rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 站点网址 */
|
/* 站点网址 */
|
||||||
.site-url {
|
.site-url {
|
||||||
font-size: 11px;
|
font-size: 0.9rem;
|
||||||
color: rgba(var(--v-theme-on-surface), 0.6);
|
color: rgba(var(--v-theme-on-surface), 0.6);
|
||||||
transition: color 0.2s ease;
|
transition: color 0.2s ease;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -840,8 +791,12 @@ function calcSpeedClass(speed: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@keyframes spin {
|
@keyframes spin {
|
||||||
0% { transform: rotate(0deg); }
|
0% {
|
||||||
100% { transform: rotate(360deg); }
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.loading-text {
|
.loading-text {
|
||||||
@@ -855,8 +810,12 @@ function calcSpeedClass(speed: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@keyframes fade-in {
|
@keyframes fade-in {
|
||||||
from { opacity: 0; }
|
from {
|
||||||
to { opacity: 1; }
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.pulse-dot {
|
.pulse-dot {
|
||||||
|
|||||||
Reference in New Issue
Block a user