优化 SiteCard 组件,调整样式和结构,提升可读性和用户体验

This commit is contained in:
jxxghp
2025-04-01 00:06:31 +08:00
parent ed53fbae93
commit 410ff78ef5
+38 -79
View File
@@ -164,58 +164,40 @@ 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">
@@ -226,11 +208,7 @@ function calcSpeedClass(speed: number) {
<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>
@@ -239,11 +217,7 @@ function calcSpeedClass(speed: number) {
<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>
@@ -252,11 +226,7 @@ function calcSpeedClass(speed: number) {
<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>
@@ -265,11 +235,7 @@ function calcSpeedClass(speed: number) {
<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>
@@ -296,10 +262,7 @@ 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>
@@ -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>
@@ -332,7 +292,7 @@ function calcSpeedClass(speed: number) {
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>
@@ -351,11 +311,7 @@ function calcSpeedClass(speed: number) {
<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>
@@ -364,11 +320,7 @@ function calcSpeedClass(speed: number) {
<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>
@@ -377,10 +329,7 @@ function calcSpeedClass(speed: number) {
<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,7 +352,7 @@ function calcSpeedClass(speed: number) {
<span>更多操作</span> <span>更多操作</span>
</VTooltip> </VTooltip>
</div> </div>
</div> </VCard>
<!-- 对话框组件 --> <!-- 对话框组件 -->
<SiteCookieUpdateDialog <SiteCookieUpdateDialog
@@ -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 {