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>