/
itp_practice
/
itp_frontend
Обзор
Документация
Войти
/
itp_practice
/
itp_frontend
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
master
src/views/Admin/ProcessManagerView.vue
314 строк
11 KB
vivanenko
fix subsriptions
29 май 2025, 14:09
29 май 2025, 14:09
7130aba
Код
Авторство
О чём код?
<template> <div class="container mx-auto px-4 py-8"> <div class="flex justify-between items-center mb-6"> <h2 class="text-2xl font-bold">Process Manager</h2> <div class="space-x-2"> <button @click="showStartModal = true" class="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600 transition-colors" > Start New Tap Process </button> <button @click="handleReloadConfig" class="bg-gray-500 text-white px-4 py-2 rounded hover:bg-gray-600 transition-colors" > Reload Config </button> </div> </div> <!-- Tabs --> <div class="mb-6 border-b"> <nav class="-mb-px flex space-x-8"> <button @click="activeTab = 'taps'" :class="[ 'py-2 px-1 border-b-2 font-medium text-sm', activeTab === 'taps' ? 'border-blue-500 text-blue-600' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300' ]" > Tap Processes </button> <button @click="activeTab = 'all'" :class="[ 'py-2 px-1 border-b-2 font-medium text-sm', activeTab === 'all' ? 'border-blue-500 text-blue-600' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300' ]" > All Processes </button> </nav> </div> <div v-if="store.loading" class="text-center py-4"> <div class="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600 mx-auto"></div> <p class="mt-2 text-gray-600">Loading...</p> </div> <div v-else-if="store.error" class="text-center py-4 bg-red-50 text-red-600 rounded-lg"> {{ store.error }} </div> <!-- Tap Processes Tab --> <template v-else-if="activeTab === 'taps'"> <div v-if="!store.tapProcesses?.length" class="text-center py-8 bg-white rounded-lg shadow"> <p class="text-gray-500">No tap processes running.</p> <button @click="showStartModal = true" class="mt-4 bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600 transition-colors" > Start Your First Tap Process </button> </div> <div v-else class="overflow-x-auto bg-white rounded-lg shadow"> <table class="min-w-full"> <thead class="bg-gray-50"> <tr> <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Tap ID</th> <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Process Name</th> <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th> <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">PID</th> <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Uptime</th> <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th> </tr> </thead> <tbody class="bg-white divide-y divide-gray-200"> <tr v-for="process in store.tapProcesses" :key="process.name"> <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ process.tap_id }}</td> <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ process.name }}</td> <td class="px-6 py-4 whitespace-nowrap"> <ProcessStatusBadge :status="process.statename" /> </td> <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ process.pid || '-' }}</td> <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ formatUptime(process.start) }}</td> <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900"> <button v-if="process.statename === 'RUNNING'" @click="handleStop(process.tap_id)" class="text-red-600 hover:text-red-800 mr-3" > Stop </button> <button v-else-if="process.statename === 'STOPPED'" @click="handleStart(process.tap_id)" class="text-green-600 hover:text-green-800 mr-3" > Start </button> <button @click="handleRestart(process.tap_id)" class="text-blue-600 hover:text-blue-800 mr-3" :disabled="process.statename !== 'RUNNING'" :class="{ 'opacity-50 cursor-not-allowed': process.statename !== 'RUNNING' }" > Restart </button> <button @click="showLogs(process.tap_id)" class="text-gray-600 hover:text-gray-800" > Logs </button> </td> </tr> </tbody> </table> </div> </template> <!-- All Processes Tab --> <template v-else-if="activeTab === 'all'"> <div v-if="!store.allProcesses?.length" class="text-center py-8 bg-white rounded-lg shadow"> <p class="text-gray-500">No processes found.</p> </div> <div v-else class="overflow-x-auto bg-white rounded-lg shadow"> <table class="min-w-full"> <thead class="bg-gray-50"> <tr> <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Name</th> <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Group</th> <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th> <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">PID</th> <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Uptime</th> <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Description</th> </tr> </thead> <tbody class="bg-white divide-y divide-gray-200"> <tr v-for="process in store.allProcesses" :key="process.name"> <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ process.name }}</td> <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ process.group }}</td> <td class="px-6 py-4 whitespace-nowrap"> <ProcessStatusBadge :status="process.statename" /> </td> <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ process.pid || '-' }}</td> <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ formatUptime(process.start) }}</td> <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{{ process.description }}</td> </tr> </tbody> </table> </div> </template> <!-- Start Modal --> <div v-if="showStartModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"> <div class="bg-white p-6 rounded-lg w-full max-w-md"> <h3 class="text-lg font-bold mb-4">Start New Tap Process</h3> <form @submit.prevent="handleStartSubmit"> <div class="mb-4"> <label class="block text-sm font-medium text-gray-700">Tap ID</label> <input v-model.number="startForm.tap_id" type="number" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500" required min="1" > </div> <div class="flex justify-end space-x-3"> <button type="button" @click="closeStartModal" class="px-4 py-2 border rounded hover:bg-gray-100" > Cancel </button> <button type="submit" class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600" > Start Process </button> </div> </form> </div> </div> <!-- Logs Modal --> <LogsModal v-if="showLogsModal" :tap-id="selectedTapId" @close="closeLogsModal" /> </div> </template> <script setup> import { ref, onMounted, watch } from 'vue'; import { useProcessManagerStore } from '@/stores/processManager'; import ProcessStatusBadge from '@/components/common/ProcessStatusBadge.vue'; import LogsModal from '@/components/common/LogsModal.vue'; import { useAlerts } from '@/composables/useAlerts'; const store = useProcessManagerStore(); const activeTab = ref('taps'); const showStartModal = ref(false); const showLogsModal = ref(false); const selectedTapId = ref(null); const startForm = ref({ tap_id: '' }); const { showSuccess, showError } = useAlerts(); const formatUptime = (startTime) => { if (!startTime || startTime === 0) return '-'; const start = new Date(startTime * 1000); const now = new Date(); const diff = now - start; const days = Math.floor(diff / (1000 * 60 * 60 * 24)); const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60)); if (days > 0) return `${days}d ${hours}h`; if (hours > 0) return `${hours}h ${minutes}m`; return `${minutes}m`; }; const handleStart = async (tapId) => { const result = await store.startTapProcess(tapId); if (result.success) { showSuccess(result.message); } else { showError(`Error: ${result.message}`); } }; const handleStop = async (tapId) => { if (!confirm(`Are you sure you want to stop tap process ${tapId}?`)) return; const result = await store.stopTapProcess(tapId); if (result.success) { showSuccess(result.message); } else { showError(`Error: ${result.message}`); } }; const handleRestart = async (tapId) => { if (!confirm(`Are you sure you want to restart tap process ${tapId}?`)) return; const result = await store.restartTapProcess(tapId); if (result.success) { showSuccess(result.message); } else { showError(`Error: ${result.message}`); } }; const handleStartSubmit = async () => { const result = await store.startTapProcess(startForm.value.tap_id); if (result.success) { closeStartModal(); showSuccess(result.message); } else { showError(`Error: ${result.message}`); } }; const handleReloadConfig = async () => { const result = await store.reloadConfig(); if (result.success) { showSuccess(result.message); } else { showError(`Error: ${result.message}`); } }; const showLogs = (tapId) => { selectedTapId.value = tapId; showLogsModal.value = true; }; const closeStartModal = () => { showStartModal.value = false; startForm.value.tap_id = ''; }; const closeLogsModal = () => { showLogsModal.value = false; selectedTapId.value = null; }; watch(activeTab, (newTab) => { if (newTab === 'taps') { store.fetchTapProcesses(); } else if (newTab === 'all') { store.fetchAllProcesses(); } }); onMounted(() => { store.fetchTapProcesses(); }); </script>