193 lines
5.0 KiB
Vue
193 lines
5.0 KiB
Vue
<template>
|
|
<div>
|
|
<LayoutsBreadcrumb />
|
|
|
|
<!-- Header Section -->
|
|
<rs-card class="mb-6">
|
|
<template #header>
|
|
<div class="flex items-center">
|
|
<Icon class="mr-2 text-primary" name="ic:outline-schedule"></Icon>
|
|
<h1 class="text-xl font-bold text-primary">Queue</h1>
|
|
</div>
|
|
</template>
|
|
<template #body>
|
|
<p class="text-gray-600">Manage notification queues and scheduled tasks.</p>
|
|
</template>
|
|
</rs-card>
|
|
|
|
<!-- Basic Stats -->
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6">
|
|
<rs-card v-for="(stat, index) in queueStats" :key="index">
|
|
<div class="p-4 text-center">
|
|
<div v-if="isLoading" class="animate-pulse">
|
|
<div class="h-8 bg-gray-200 rounded w-24 mx-auto mb-2"></div>
|
|
<div class="h-4 bg-gray-200 rounded w-32 mx-auto"></div>
|
|
</div>
|
|
<template v-else>
|
|
<h3 :class="['text-2xl font-bold', stat.colorClass]">
|
|
{{ stat.value }}
|
|
</h3>
|
|
<p class="text-sm text-gray-600">{{ stat.label }}</p>
|
|
</template>
|
|
</div>
|
|
</rs-card>
|
|
</div>
|
|
|
|
<!-- Main Features -->
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<rs-card
|
|
v-for="(feature, index) in features"
|
|
:key="index"
|
|
class="cursor-pointer hover:shadow-md transition-shadow"
|
|
@click="navigateTo(feature.path)"
|
|
>
|
|
<template #header>
|
|
<div class="flex items-center">
|
|
<Icon class="mr-2 text-primary" :name="feature.icon"></Icon>
|
|
<h3 class="font-semibold text-primary">{{ feature.title }}</h3>
|
|
</div>
|
|
</template>
|
|
<template #body>
|
|
<p class="text-gray-600 text-sm">{{ feature.description }}</p>
|
|
</template>
|
|
<template #footer>
|
|
<rs-button variant="outline" size="sm" class="w-full"> Open </rs-button>
|
|
</template>
|
|
</rs-card>
|
|
</div>
|
|
|
|
<!-- Error Alert -->
|
|
<rs-alert v-if="error" variant="danger" class="mt-4">
|
|
{{ error }}
|
|
</rs-alert>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
definePageMeta({
|
|
title: "Queue & Scheduler",
|
|
middleware: ["auth"],
|
|
requiresAuth: true,
|
|
breadcrumb: [
|
|
{
|
|
name: "Notification",
|
|
path: "/notification",
|
|
},
|
|
{
|
|
name: "Queue",
|
|
path: "/notification/queue",
|
|
},
|
|
],
|
|
});
|
|
|
|
const { $swal } = useNuxtApp();
|
|
|
|
// Reactive state
|
|
const isLoading = ref(true);
|
|
const error = ref(null);
|
|
const queueStats = ref([]);
|
|
|
|
// Hardcoded features
|
|
const features = ref([
|
|
{
|
|
title: "Queue Monitor",
|
|
description: "View and manage current notification queues",
|
|
icon: "ic:outline-monitor",
|
|
path: "/notification/queue/monitor",
|
|
},
|
|
{
|
|
title: "Performance",
|
|
description: "Check system performance and metrics",
|
|
icon: "ic:outline-speed",
|
|
path: "/notification/queue/performance",
|
|
},
|
|
{
|
|
title: "Batch Processing",
|
|
description: "Process notifications in batches",
|
|
icon: "ic:outline-batch-prediction",
|
|
path: "/notification/queue/batch",
|
|
},
|
|
{
|
|
title: "Failed Jobs",
|
|
description: "Handle and retry failed notifications",
|
|
icon: "ic:outline-refresh",
|
|
path: "/notification/queue/retry",
|
|
},
|
|
]);
|
|
|
|
// Fetch queue statistics
|
|
async function fetchQueueStats() {
|
|
try {
|
|
const { data } = await useFetch("/api/notifications/queue/stats", {
|
|
method: "GET",
|
|
});
|
|
|
|
console.log(data.value);
|
|
|
|
if (data.value?.success) {
|
|
queueStats.value = [
|
|
{
|
|
value: data.value.data.pending,
|
|
label: "Pending Jobs",
|
|
colorClass: "text-primary",
|
|
},
|
|
{
|
|
value: data.value.data.completed,
|
|
label: "Completed Today",
|
|
colorClass: "text-green-600",
|
|
},
|
|
{
|
|
value: data.value.data.failed,
|
|
label: "Failed Jobs",
|
|
colorClass: "text-red-600",
|
|
},
|
|
];
|
|
} else {
|
|
throw new Error(data.value?.message || "Failed to fetch queue statistics");
|
|
}
|
|
} catch (err) {
|
|
console.error("Error fetching queue stats:", err);
|
|
error.value = "Failed to load queue statistics. Please try again later.";
|
|
|
|
// Set default values for stats
|
|
queueStats.value = [
|
|
{ value: "-", label: "Pending Jobs", colorClass: "text-primary" },
|
|
{ value: "-", label: "Completed Today", colorClass: "text-green-600" },
|
|
{ value: "-", label: "Failed Jobs", colorClass: "text-red-600" },
|
|
];
|
|
} finally {
|
|
isLoading.value = false;
|
|
}
|
|
}
|
|
|
|
// Initialize data
|
|
onMounted(async () => {
|
|
try {
|
|
isLoading.value = true;
|
|
error.value = null;
|
|
await fetchQueueStats();
|
|
} catch (err) {
|
|
console.error("Error initializing queue page:", err);
|
|
error.value = "Failed to initialize the page. Please refresh to try again.";
|
|
} finally {
|
|
isLoading.value = false;
|
|
}
|
|
});
|
|
|
|
// Auto-refresh stats every 30 seconds
|
|
let refreshInterval;
|
|
onMounted(() => {
|
|
refreshInterval = setInterval(async () => {
|
|
await fetchQueueStats();
|
|
}, 30000);
|
|
});
|
|
|
|
onUnmounted(() => {
|
|
if (refreshInterval) {
|
|
clearInterval(refreshInterval);
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<style lang="scss" scoped></style>
|