qa1145's picture
Upload 1245 files
8ede856 verified
<template>
<v-card elevation="1" class="platform-stat-card">
<v-card-text>
<div class="platform-header">
<div>
<div class="platform-title">{{ t('charts.platformStat.title') }}</div>
<div class="platform-subtitle">{{ t('charts.platformStat.subtitle') }}</div>
</div>
</div>
<v-divider class="my-3"></v-divider>
<div v-if="platforms.length > 0" class="platform-list-container">
<v-list class="platform-list" density="compact">
<v-list-item
v-for="(platform, i) in sortedPlatforms"
:key="i"
:value="platform"
class="platform-item"
>
<template v-slot:prepend>
<div class="platform-rank" :class="{'top-rank': i < 3}">{{ i + 1 }}</div>
</template>
<v-list-item-title class="platform-name">{{ platform.name }}</v-list-item-title>
<template v-slot:append>
<div class="platform-count">
<span class="count-value">{{ platform.count }}</span>
<span class="count-label">{{ t('charts.platformStat.messageUnit') }}</span>
</div>
</template>
</v-list-item>
</v-list>
<div class="platform-stats-summary">
<div class="platform-stat-item">
<div class="stat-label">{{ t('charts.platformStat.platformCount') }}</div>
<div class="stat-value">{{ platforms.length }}</div>
</div>
<v-divider vertical></v-divider>
<div class="platform-stat-item">
<div class="stat-label">{{ t('charts.platformStat.mostActive') }}</div>
<div class="stat-value">{{ mostActivePlatform }}</div>
</div>
<v-divider vertical></v-divider>
<div class="platform-stat-item">
<div class="stat-label">{{ t('charts.platformStat.totalPercentage') }}</div>
<div class="stat-value">{{ topPlatformPercentage }}%</div>
</div>
</div>
<div class="platform-chart">
<v-progress-linear
v-for="(platform, i) in sortedPlatforms.slice(0, 5)"
:key="i"
:model-value="getPercentage(platform.count)"
height="8"
rounded
class="platform-progress"
:color="i === 0 ? 'primary' : i === 1 ? 'info' : i === 2 ? 'success' : 'grey-lighten-1'"
></v-progress-linear>
</div>
</div>
<div v-else class="no-data">
<v-icon icon="mdi-information-outline" size="40" color="grey-lighten-1"></v-icon>
<div class="no-data-text">{{ t('charts.platformStat.noData') }}</div>
</div>
</v-card-text>
</v-card>
</template>
<script>
import { useModuleI18n } from '@/i18n/composables';
export default {
name: 'PlatformStat',
props: ['stat'],
setup() {
const { tm: t } = useModuleI18n('features/dashboard');
return { t };
},
data() {
return {
platforms: []
};
},
computed: {
sortedPlatforms() {
return [...this.platforms].sort((a, b) => b.count - a.count);
},
totalCount() {
return this.platforms.reduce((sum, platform) => sum + platform.count, 0);
},
mostActivePlatform() {
return this.sortedPlatforms.length > 0 ? this.sortedPlatforms[0].name : '-';
},
topPlatformPercentage() {
if (this.totalCount === 0 || this.sortedPlatforms.length === 0) return 0;
return Math.round((this.sortedPlatforms[0].count / this.totalCount) * 100);
}
},
watch: {
stat: {
handler: function (val) {
if (val && val.platform) {
this.platforms = val.platform;
}
},
deep: true,
}
},
methods: {
getPercentage(count) {
return this.totalCount ? (count / this.totalCount) * 100 : 0;
}
}
};
</script>
<style scoped>
.platform-stat-card {
height: 100%;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05) !important;
transition: transform 0.2s;
}
.platform-stat-card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08) !important;
}
.platform-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
}
.platform-title {
font-size: 18px;
font-weight: 600;
color: var(--v-theme-primaryText);
}
.platform-subtitle {
font-size: 12px;
color: var(--v-theme-secondaryText);
margin-top: 4px;
}
.platform-list-container {
display: flex;
flex-direction: column;
}
.platform-list {
max-height: 180px;
overflow-y: auto;
padding: 0;
margin-bottom: 16px;
}
.platform-item {
padding: 8px 16px;
margin-bottom: 4px;
border-radius: 8px;
transition: background-color 0.2s;
}
.platform-item:hover {
background-color: #f5f5f5;
}
.platform-rank {
display: flex;
align-items: center;
justify-content: center;
width: 24px;
height: 24px;
border-radius: 50%;
background-color: var(--v-theme-surface);
color: var(--v-theme-primaryText);
font-weight: 600;
font-size: 14px;
margin-right: 12px;
}
.top-rank {
background-color: var(--v-theme-secondary);
color: var(--v-theme-surface);
}
.platform-name {
font-weight: 500;
}
.platform-count {
display: flex;
align-items: center;
}
.count-value {
font-weight: 600;
font-size: 14px;
color: var(--v-theme-secondary);
margin-right: 4px;
}
.count-label {
font-size: 12px;
color: var(--v-theme-secondaryText);
}
.platform-stats-summary {
display: flex;
justify-content: space-between;
background-color: var(--v-theme-containerBg);
border-radius: 8px;
padding: 12px;
margin-bottom: 16px;
}
.platform-stat-item {
flex: 1;
text-align: center;
}
.stat-label {
font-size: 12px;
color: var(--v-theme-secondaryText);
margin-bottom: 4px;
}
.stat-value {
font-weight: 600;
color: var(--v-theme-primaryText);
}
.platform-chart {
margin-top: 8px;
}
.platform-progress {
margin-bottom: 12px;
}
.no-data {
height: 250px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.no-data-text {
color: var(--v-theme-secondaryText);
margin-top: 16px;
font-size: 14px;
}
</style>