mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-07-07 07:21:29 +08:00
新增订阅分享统计功能
This commit is contained in:
@@ -1391,3 +1391,13 @@ export interface TorrentCacheData {
|
|||||||
// 缓存数据
|
// 缓存数据
|
||||||
data: TorrentCacheItem[]
|
data: TorrentCacheItem[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 订阅分享统计
|
||||||
|
export interface SubscribeShareStatistics {
|
||||||
|
// 分享人
|
||||||
|
share_user?: string
|
||||||
|
// 分享数量
|
||||||
|
share_count?: number
|
||||||
|
// 总复用人次
|
||||||
|
total_reuse_count?: number
|
||||||
|
}
|
||||||
|
|||||||
306
src/components/dialog/SubscribeShareStatisticsDialog.vue
Normal file
306
src/components/dialog/SubscribeShareStatisticsDialog.vue
Normal file
@@ -0,0 +1,306 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, computed, onMounted } from 'vue'
|
||||||
|
import api from '@/api'
|
||||||
|
import type { SubscribeShareStatistics } from '@/api/types'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import { useDisplay, useTheme } from 'vuetify'
|
||||||
|
|
||||||
|
// 国际化
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
|
// 显示器宽度
|
||||||
|
const display = useDisplay()
|
||||||
|
|
||||||
|
// 主题
|
||||||
|
const theme = useTheme()
|
||||||
|
|
||||||
|
// 定义事件
|
||||||
|
const emit = defineEmits(['close'])
|
||||||
|
|
||||||
|
// 统计数据
|
||||||
|
const statistics = ref<SubscribeShareStatistics[]>([])
|
||||||
|
|
||||||
|
// 是否加载中
|
||||||
|
const loading = ref(false)
|
||||||
|
|
||||||
|
// 获取统计数据
|
||||||
|
async function fetchStatistics() {
|
||||||
|
try {
|
||||||
|
loading.value = true
|
||||||
|
const data: SubscribeShareStatistics[] = await api.get('subscribe/share/statistics')
|
||||||
|
statistics.value = data
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取分享统计数据失败:', error)
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算排名
|
||||||
|
const rankedStatistics = computed(() => {
|
||||||
|
return statistics.value
|
||||||
|
.sort((a, b) => (b.total_reuse_count || 0) - (a.total_reuse_count || 0))
|
||||||
|
.map((item, index) => ({
|
||||||
|
...item,
|
||||||
|
rank: index + 1,
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
|
||||||
|
// 获取排名样式
|
||||||
|
function getRankStyle(rank: number) {
|
||||||
|
if (rank === 1) {
|
||||||
|
return {
|
||||||
|
background: 'linear-gradient(135deg, #FFD700 0%, #FFA500 100%)',
|
||||||
|
color: '#fff',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
}
|
||||||
|
} else if (rank === 2) {
|
||||||
|
return {
|
||||||
|
background: 'linear-gradient(135deg, #CD7F32 0%, #B8860B 100%)',
|
||||||
|
color: '#fff',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
}
|
||||||
|
} else if (rank === 3) {
|
||||||
|
return {
|
||||||
|
background: 'linear-gradient(135deg, #C0C0C0 0%, #A0A0A0 100%)',
|
||||||
|
color: '#fff',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取前三名文字颜色
|
||||||
|
function getPodiumTextColor() {
|
||||||
|
return theme.global.current.value.dark ? '#fff' : '#000'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取前三名统计背景样式
|
||||||
|
function getPodiumStatStyle() {
|
||||||
|
const isDark = theme.global.current.value.dark
|
||||||
|
return {
|
||||||
|
border: `1px solid ${isDark ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)'}`,
|
||||||
|
background: isDark ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取排名图标
|
||||||
|
function getRankIcon(rank: number) {
|
||||||
|
if (rank === 1) return 'mdi-trophy'
|
||||||
|
if (rank === 2) return 'mdi-medal-outline'
|
||||||
|
if (rank === 3) return 'mdi-medal'
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// 组件挂载时获取数据
|
||||||
|
onMounted(() => {
|
||||||
|
fetchStatistics()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<DialogWrapper scrollable max-width="40rem" :fullscreen="!display.mdAndUp.value">
|
||||||
|
<VCard>
|
||||||
|
<VCardItem>
|
||||||
|
<template #prepend>
|
||||||
|
<VIcon icon="mdi-chart-line" class="me-2" />
|
||||||
|
</template>
|
||||||
|
<VCardTitle>{{ t('subscribe.shareStatistics') }}</VCardTitle>
|
||||||
|
</VCardItem>
|
||||||
|
<VDialogCloseBtn @click="emit('close')" />
|
||||||
|
<VDivider />
|
||||||
|
<VCardText>
|
||||||
|
<LoadingBanner v-if="loading" class="mt-4" />
|
||||||
|
<div v-else-if="rankedStatistics.length === 0" class="text-center py-8">
|
||||||
|
<VIcon icon="mdi-chart-line" size="64" color="grey" class="mb-4" />
|
||||||
|
<div class="text-h6 text-grey">{{ t('subscribe.noStatisticsData') }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else class="mt-4">
|
||||||
|
<!-- 前三名特殊展示 -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<div class="text-h6 mb-4 text-center">{{ t('subscribe.ranking') }}</div>
|
||||||
|
<div class="d-flex justify-center align-center gap-4 flex-wrap">
|
||||||
|
<!-- 第二名 -->
|
||||||
|
<div v-if="rankedStatistics[1]" class="text-center">
|
||||||
|
<div class="rank-circle mb-2" :style="getRankStyle(2)">
|
||||||
|
<VIcon :icon="getRankIcon(2)" size="24" />
|
||||||
|
</div>
|
||||||
|
<div class="text-h6 font-weight-bold" :style="{ color: getPodiumTextColor() }">
|
||||||
|
{{ rankedStatistics[1].share_user || '未知' }}
|
||||||
|
</div>
|
||||||
|
<div class="d-flex align-center justify-center gap-2 mt-1">
|
||||||
|
<div class="d-flex align-center podium-stat" :style="getPodiumStatStyle()">
|
||||||
|
<VIcon icon="mdi-share-outline" size="14" :color="getPodiumTextColor()" class="mr-1" />
|
||||||
|
<span class="font-weight-bold" :style="{ color: getPodiumTextColor() }">{{
|
||||||
|
rankedStatistics[1].share_count || 0
|
||||||
|
}}</span>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex align-center podium-stat" :style="getPodiumStatStyle()">
|
||||||
|
<VIcon icon="mdi-fire" size="14" :color="getPodiumTextColor()" class="mr-1" />
|
||||||
|
<span class="font-weight-bold" :style="{ color: getPodiumTextColor() }">{{
|
||||||
|
rankedStatistics[1].total_reuse_count || 0
|
||||||
|
}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 第一名 -->
|
||||||
|
<div v-if="rankedStatistics[0]" class="text-center">
|
||||||
|
<div class="rank-circle mb-2 first-place" :style="getRankStyle(1)">
|
||||||
|
<VIcon :icon="getRankIcon(1)" size="32" />
|
||||||
|
</div>
|
||||||
|
<div class="text-h5 font-weight-bold" :style="{ color: getPodiumTextColor() }">
|
||||||
|
{{ rankedStatistics[0].share_user || '未知' }}
|
||||||
|
</div>
|
||||||
|
<div class="d-flex align-center justify-center gap-3 mt-1">
|
||||||
|
<div class="d-flex align-center podium-stat" :style="getPodiumStatStyle()">
|
||||||
|
<VIcon icon="mdi-share-outline" size="14" :color="getPodiumTextColor()" class="mr-1" />
|
||||||
|
<span class="font-weight-bold" :style="{ color: getPodiumTextColor() }">{{
|
||||||
|
rankedStatistics[0].share_count || 0
|
||||||
|
}}</span>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex align-center podium-stat" :style="getPodiumStatStyle()">
|
||||||
|
<VIcon icon="mdi-fire" size="14" :color="getPodiumTextColor()" class="mr-1" />
|
||||||
|
<span class="font-weight-bold" :style="{ color: getPodiumTextColor() }">{{
|
||||||
|
rankedStatistics[0].total_reuse_count || 0
|
||||||
|
}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 第三名 -->
|
||||||
|
<div v-if="rankedStatistics[2]" class="text-center">
|
||||||
|
<div class="rank-circle mb-2" :style="getRankStyle(3)">
|
||||||
|
<VIcon :icon="getRankIcon(3)" size="24" />
|
||||||
|
</div>
|
||||||
|
<div class="text-h6 font-weight-bold" :style="{ color: getPodiumTextColor() }">
|
||||||
|
{{ rankedStatistics[2].share_user || '未知' }}
|
||||||
|
</div>
|
||||||
|
<div class="d-flex align-center justify-center gap-2 mt-1">
|
||||||
|
<div class="d-flex align-center podium-stat" :style="getPodiumStatStyle()">
|
||||||
|
<VIcon icon="mdi-share-outline" size="14" :color="getPodiumTextColor()" class="mr-1" />
|
||||||
|
<span class="font-weight-bold" :style="{ color: getPodiumTextColor() }">{{
|
||||||
|
rankedStatistics[2].share_count || 0
|
||||||
|
}}</span>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex align-center podium-stat" :style="getPodiumStatStyle()">
|
||||||
|
<VIcon icon="mdi-fire" size="14" :color="getPodiumTextColor()" class="mr-1" />
|
||||||
|
<span class="font-weight-bold" :style="{ color: getPodiumTextColor() }">{{
|
||||||
|
rankedStatistics[2].total_reuse_count || 0
|
||||||
|
}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 完整排行榜 -->
|
||||||
|
<VDivider class="mb-4" />
|
||||||
|
<div class="text-h6 mb-4">{{ t('subscribe.ranking') }}</div>
|
||||||
|
<VList class="bg-transparent">
|
||||||
|
<VListItem
|
||||||
|
v-for="item in rankedStatistics"
|
||||||
|
:key="item.share_user"
|
||||||
|
class="mb-2 rounded-lg"
|
||||||
|
:class="item.rank <= 3 ? 'elevation-1 pb-3' : ''"
|
||||||
|
>
|
||||||
|
<template #prepend>
|
||||||
|
<div class="rank-badge mr-3" :style="getRankStyle(item.rank)">
|
||||||
|
<VIcon :icon="getRankIcon(item.rank)" size="16" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<VListItemTitle class="font-weight-bold text-h6 mb-1">
|
||||||
|
{{ item.share_user || '未知' }}
|
||||||
|
</VListItemTitle>
|
||||||
|
|
||||||
|
<VListItemSubtitle class="d-flex align-center gap-3 mt-1">
|
||||||
|
<div class="stat-badge share-badge">
|
||||||
|
<VIcon icon="mdi-share-outline" size="14" color="primary" class="mr-1" />
|
||||||
|
<span class="text-primary font-weight-bold">{{ item.share_count || 0 }}</span>
|
||||||
|
<span class="text-grey text-caption ml-1">{{ t('subscribe.shareCount') }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-badge reuse-badge">
|
||||||
|
<VIcon icon="mdi-fire" size="14" color="warning" class="mr-1" />
|
||||||
|
<span class="text-warning font-weight-bold">{{ item.total_reuse_count || 0 }}</span>
|
||||||
|
<span class="text-grey text-caption ml-1">{{ t('subscribe.totalReuseCount') }}</span>
|
||||||
|
</div>
|
||||||
|
</VListItemSubtitle>
|
||||||
|
|
||||||
|
<template #append>
|
||||||
|
<div class="text-right">
|
||||||
|
<div
|
||||||
|
class="text-h6 font-weight-bold"
|
||||||
|
:style="{ color: item.rank <= 3 ? 'var(--v-primary-base)' : 'inherit' }"
|
||||||
|
>
|
||||||
|
#{{ item.rank }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</VListItem>
|
||||||
|
</VList>
|
||||||
|
</div>
|
||||||
|
</VCardText>
|
||||||
|
</VCard>
|
||||||
|
</DialogWrapper>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.rank-circle {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border-radius: 50%;
|
||||||
|
block-size: 60px;
|
||||||
|
inline-size: 60px;
|
||||||
|
margin-block: 0;
|
||||||
|
margin-inline: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.first-place {
|
||||||
|
block-size: 80px;
|
||||||
|
box-shadow: 0 4px 12px rgba(255, 215, 0, 30%);
|
||||||
|
inline-size: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rank-badge {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border-radius: 50%;
|
||||||
|
block-size: 32px;
|
||||||
|
inline-size: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-badge {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
border: 1px solid rgba(var(--v-theme-outline), 0.2);
|
||||||
|
border-radius: 6px;
|
||||||
|
background: rgba(var(--v-theme-surface), 0.8);
|
||||||
|
padding-block: 4px;
|
||||||
|
padding-inline: 8px;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.share-badge {
|
||||||
|
border-inline-start: 3px solid rgb(var(--v-theme-primary));
|
||||||
|
}
|
||||||
|
|
||||||
|
.reuse-badge {
|
||||||
|
border-inline-start: 3px solid rgb(var(--v-theme-warning));
|
||||||
|
}
|
||||||
|
|
||||||
|
.podium-stat {
|
||||||
|
border-radius: 6px;
|
||||||
|
backdrop-filter: blur(4px);
|
||||||
|
padding-block: 4px;
|
||||||
|
padding-inline: 8px;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.podium-stat:hover {
|
||||||
|
transform: scale(1.05);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -807,6 +807,11 @@ export default {
|
|||||||
'After reset, {name} will be restored to its initial state, downloaded records will be cleared, and unimported content will be downloaded again. Are you sure?',
|
'After reset, {name} will be restored to its initial state, downloaded records will be cleared, and unimported content will be downloaded again. Are you sure?',
|
||||||
resetSuccess: '{name} has been reset successfully!',
|
resetSuccess: '{name} has been reset successfully!',
|
||||||
resetFailed: '{name} reset failed: {message}',
|
resetFailed: '{name} reset failed: {message}',
|
||||||
|
shareStatistics: 'Share Statistics',
|
||||||
|
shareCount: 'Shares',
|
||||||
|
totalReuseCount: 'Total Reuse Count',
|
||||||
|
ranking: 'Ranking',
|
||||||
|
noStatisticsData: 'No share statistics data available',
|
||||||
},
|
},
|
||||||
recommend: {
|
recommend: {
|
||||||
all: 'All',
|
all: 'All',
|
||||||
@@ -1781,7 +1786,8 @@ export default {
|
|||||||
shareSuccess: '{name} shared successfully!',
|
shareSuccess: '{name} shared successfully!',
|
||||||
shareFailed: '{name} share failed: {message}!',
|
shareFailed: '{name} share failed: {message}!',
|
||||||
securityWarning: 'Security Warning',
|
securityWarning: 'Security Warning',
|
||||||
securityWarningMessage: 'Before sharing, please ensure the workflow does not contain sensitive information such as PassKey in RSS links to avoid information leakage.',
|
securityWarningMessage:
|
||||||
|
'Before sharing, please ensure the workflow does not contain sensitive information such as PassKey in RSS links to avoid information leakage.',
|
||||||
},
|
},
|
||||||
u115Auth: {
|
u115Auth: {
|
||||||
loginTitle: '115 Cloud Login',
|
loginTitle: '115 Cloud Login',
|
||||||
|
|||||||
@@ -803,6 +803,11 @@ export default {
|
|||||||
resetConfirm: '重置后 {name} 将恢复初始状态,已下载记录将被清除,未入库的内容将会重新下载,是否确认?',
|
resetConfirm: '重置后 {name} 将恢复初始状态,已下载记录将被清除,未入库的内容将会重新下载,是否确认?',
|
||||||
resetSuccess: '{name} 重置成功!',
|
resetSuccess: '{name} 重置成功!',
|
||||||
resetFailed: '{name} 重置失败:{message}',
|
resetFailed: '{name} 重置失败:{message}',
|
||||||
|
shareStatistics: '分享统计',
|
||||||
|
shareCount: '个分享',
|
||||||
|
totalReuseCount: '次复用',
|
||||||
|
ranking: '排名',
|
||||||
|
noStatisticsData: '暂无分享统计数据',
|
||||||
},
|
},
|
||||||
recommend: {
|
recommend: {
|
||||||
all: '全部',
|
all: '全部',
|
||||||
|
|||||||
@@ -801,6 +801,11 @@ export default {
|
|||||||
resetConfirm: '重置後 {name} 將恢復初始狀態,已下載記錄將被清除,未入庫的內容將會重新下載,是否確認?',
|
resetConfirm: '重置後 {name} 將恢復初始狀態,已下載記錄將被清除,未入庫的內容將會重新下載,是否確認?',
|
||||||
resetSuccess: '{name} 重置成功!',
|
resetSuccess: '{name} 重置成功!',
|
||||||
resetFailed: '{name} 重置失敗:{message}',
|
resetFailed: '{name} 重置失敗:{message}',
|
||||||
|
shareStatistics: '分享統計',
|
||||||
|
shareCount: '個分享',
|
||||||
|
totalReuseCount: '次複用',
|
||||||
|
ranking: '排名',
|
||||||
|
noStatisticsData: '暫無分享統計數據',
|
||||||
},
|
},
|
||||||
recommend: {
|
recommend: {
|
||||||
all: '全部',
|
all: '全部',
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import SubscribeListView from '@/views/subscribe/SubscribeListView.vue'
|
|||||||
import SubscribePopularView from '@/views/subscribe/SubscribePopularView.vue'
|
import SubscribePopularView from '@/views/subscribe/SubscribePopularView.vue'
|
||||||
import SubscribeShareView from '@/views/subscribe/SubscribeShareView.vue'
|
import SubscribeShareView from '@/views/subscribe/SubscribeShareView.vue'
|
||||||
import SubscribeEditDialog from '@/components/dialog/SubscribeEditDialog.vue'
|
import SubscribeEditDialog from '@/components/dialog/SubscribeEditDialog.vue'
|
||||||
|
import SubscribeShareStatisticsDialog from '@/components/dialog/SubscribeShareStatisticsDialog.vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import { useDynamicHeaderTab } from '@/composables/useDynamicHeaderTab'
|
import { useDynamicHeaderTab } from '@/composables/useDynamicHeaderTab'
|
||||||
|
|
||||||
@@ -36,6 +37,9 @@ const filterSubscribeDialog = ref(false)
|
|||||||
// 搜索订阅分享弹窗
|
// 搜索订阅分享弹窗
|
||||||
const searchShareDialog = ref(false)
|
const searchShareDialog = ref(false)
|
||||||
|
|
||||||
|
// 订阅分享统计弹窗
|
||||||
|
const shareStatisticsDialog = ref(false)
|
||||||
|
|
||||||
// 订阅过滤词
|
// 订阅过滤词
|
||||||
const subscribeFilter = ref('')
|
const subscribeFilter = ref('')
|
||||||
|
|
||||||
@@ -51,6 +55,7 @@ const searchShares = () => {
|
|||||||
// VMenu activator选择器
|
// VMenu activator选择器
|
||||||
const filterActivator = computed(() => '[data-menu-activator="filter-btn"]')
|
const filterActivator = computed(() => '[data-menu-activator="filter-btn"]')
|
||||||
const searchActivator = computed(() => '[data-menu-activator="search-btn"]')
|
const searchActivator = computed(() => '[data-menu-activator="search-btn"]')
|
||||||
|
const statisticsActivator = computed(() => '[data-menu-activator="statistics-btn"]')
|
||||||
|
|
||||||
// 使用动态标签页
|
// 使用动态标签页
|
||||||
const { registerHeaderTab } = useDynamicHeaderTab()
|
const { registerHeaderTab } = useDynamicHeaderTab()
|
||||||
@@ -71,6 +76,17 @@ registerHeaderTab({
|
|||||||
},
|
},
|
||||||
show: computed(() => activeTab.value === 'mysub'),
|
show: computed(() => activeTab.value === 'mysub'),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
icon: 'mdi-chart-line',
|
||||||
|
variant: 'text',
|
||||||
|
color: 'gray',
|
||||||
|
class: 'settings-icon-button',
|
||||||
|
dataAttr: 'statistics-btn',
|
||||||
|
action: () => {
|
||||||
|
shareStatisticsDialog.value = true
|
||||||
|
},
|
||||||
|
show: computed(() => activeTab.value === 'share'),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
icon: 'mdi-movie-search-outline',
|
icon: 'mdi-movie-search-outline',
|
||||||
variant: 'text',
|
variant: 'text',
|
||||||
@@ -191,6 +207,13 @@ onMounted(() => {
|
|||||||
@save="subscribeEditDialog = false"
|
@save="subscribeEditDialog = false"
|
||||||
@close="subscribeEditDialog = false"
|
@close="subscribeEditDialog = false"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<!-- 订阅分享统计弹窗 -->
|
||||||
|
<SubscribeShareStatisticsDialog
|
||||||
|
v-if="shareStatisticsDialog"
|
||||||
|
v-model="shareStatisticsDialog"
|
||||||
|
@close="shareStatisticsDialog = false"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user