Removes unnecessary manual watcher cleanup via stopWatchQueryChange across multiple Vue components. Vue 3's watch() automatically handles cleanup when components are unmounted, making explicit stopWatchQueryChange calls and onBeforeUnmount handlers redundant. This change: - Improves code maintainability - Reduces boilerplate code - Follows Vue 3 best practices for reactive system cleanup
111 lines
2.5 KiB
Vue
111 lines
2.5 KiB
Vue
<script setup>
|
|
import { Maximize } from 'lucide-vue-next'
|
|
|
|
const props = defineProps({
|
|
type: {
|
|
type: String,
|
|
required: true,
|
|
},
|
|
name: {
|
|
type: String,
|
|
required: true,
|
|
},
|
|
})
|
|
|
|
const id = inject('id')
|
|
const time = inject('time')
|
|
const filters = inject('filters')
|
|
|
|
const total = ref(0)
|
|
const metrics = ref([])
|
|
const top6 = ref([])
|
|
|
|
async function getLinkMetrics() {
|
|
total.value = 0
|
|
metrics.value = []
|
|
top6.value = []
|
|
const { data } = await useAPI('/api/stats/metrics', {
|
|
query: {
|
|
type: props.type,
|
|
id: id.value,
|
|
startAt: time.value.startAt,
|
|
endAt: time.value.endAt,
|
|
...filters.value,
|
|
},
|
|
})
|
|
if (Array.isArray(data)) {
|
|
const colors = colorGradation(data.length)
|
|
total.value = data.reduce((acc, cur) => acc + Number(cur.count), 0)
|
|
metrics.value = data.map((item, i) => {
|
|
item.color = colors[i]
|
|
item.percent = Math.floor(item.count / total.value * 100) || (item.count ? 1 : 0)
|
|
return item
|
|
})
|
|
top6.value = metrics.value.slice(0, 6)
|
|
}
|
|
}
|
|
|
|
watch([time, filters], getLinkMetrics, {
|
|
deep: true,
|
|
})
|
|
|
|
onMounted(() => {
|
|
getLinkMetrics()
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<Card class="flex flex-col">
|
|
<template v-if="metrics.length">
|
|
<DashboardAnalysisMetricsList
|
|
class="flex-1"
|
|
:metrics="top6"
|
|
:type="type"
|
|
/>
|
|
<CardFooter class="py-2">
|
|
<Dialog>
|
|
<DialogTrigger
|
|
as-child
|
|
class="w-full"
|
|
>
|
|
<Button
|
|
variant="link"
|
|
>
|
|
<Maximize class="w-4 h-4 mr-2" />
|
|
{{ $t('dashboard.details') }}
|
|
</Button>
|
|
</DialogTrigger>
|
|
<DialogContent class="max-w-[95svw] max-h-[95svh] md:max-w-screen-md grid-rows-[auto_minmax(0,1fr)_auto]">
|
|
<DialogHeader>
|
|
<DialogTitle>{{ name }}</DialogTitle>
|
|
</DialogHeader>
|
|
<DashboardAnalysisMetricsList
|
|
class="overflow-y-auto"
|
|
:metrics="metrics"
|
|
:type="type"
|
|
/>
|
|
</DialogContent>
|
|
</Dialog>
|
|
</CardFooter>
|
|
</template>
|
|
<template v-else>
|
|
<div class="flex justify-between items-center px-4 h-12">
|
|
<Skeleton
|
|
class="w-32 h-4 rounded-full"
|
|
/>
|
|
<Skeleton
|
|
class="w-20 h-4 rounded-full"
|
|
/>
|
|
</div>
|
|
<div
|
|
v-for="i in 3"
|
|
:key="i"
|
|
class="px-4 py-4"
|
|
>
|
|
<Skeleton
|
|
class="w-full h-4 rounded-full"
|
|
/>
|
|
</div>
|
|
</template>
|
|
</Card>
|
|
</template>
|