#feature: add project&cronjob management
This commit is contained in:
141
resources/js/components/admin/ScheduledTasks.vue
Normal file
141
resources/js/components/admin/ScheduledTasks.vue
Normal file
@@ -0,0 +1,141 @@
|
||||
<template>
|
||||
<div class="space-y-4">
|
||||
<!-- Header -->
|
||||
<div class="flex items-center justify-between bg-white p-4 rounded-lg shadow-sm border border-gray-200">
|
||||
<div>
|
||||
<h3 class="text-lg font-bold text-gray-800">定时任务管理</h3>
|
||||
<p class="text-sm text-gray-500">查看和控制系统定时任务的启用状态</p>
|
||||
</div>
|
||||
<button
|
||||
@click="loadTasks"
|
||||
:disabled="loading"
|
||||
class="px-3 py-2 bg-gray-100 text-gray-700 text-sm font-medium rounded hover:bg-gray-200 disabled:opacity-50 flex items-center gap-1"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="w-4 h-4" :class="{'animate-spin': loading}">
|
||||
<path fill-rule="evenodd" d="M15.312 11.424a5.5 5.5 0 01-9.201 2.466l-.312-.311h2.433a.75.75 0 000-1.5H3.989a.75.75 0 00-.75.75v4.242a.75.75 0 001.5 0v-2.43l.31.31a7 7 0 0011.712-3.138.75.75 0 00-1.449-.39zm1.23-3.723a.75.75 0 00.219-.53V2.929a.75.75 0 00-1.5 0v2.433l-.31-.31a7 7 0 00-11.712 3.138.75.75 0 001.449.39 5.5 5.5 0 019.201-2.466l.312.312h-2.433a.75.75 0 000 1.5h4.185a.75.75 0 00.53-.219z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
刷新
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Messages -->
|
||||
<div v-if="message" class="text-sm text-green-600 bg-green-50 px-4 py-3 rounded border border-green-100">{{ message }}</div>
|
||||
<div v-if="error" class="text-sm text-red-600 bg-red-50 px-4 py-3 rounded border border-red-100">{{ error }}</div>
|
||||
|
||||
<!-- Tasks List -->
|
||||
<div class="bg-white rounded-lg shadow-sm border border-gray-200 overflow-hidden">
|
||||
<table class="min-w-full divide-y divide-gray-200">
|
||||
<thead class="bg-gray-50">
|
||||
<tr>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">任务名称</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">命令</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">执行频率</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">状态</th>
|
||||
<th class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="bg-white divide-y divide-gray-200">
|
||||
<tr v-for="task in tasks" :key="task.name" class="hover:bg-gray-50">
|
||||
<td class="px-6 py-4">
|
||||
<div class="font-medium text-gray-900">{{ task.description }}</div>
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
<code class="text-xs bg-gray-100 px-2 py-1 rounded text-gray-700">{{ task.command }}</code>
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
<div class="text-sm text-gray-900">{{ task.frequency }}</div>
|
||||
<div class="text-xs text-gray-400 font-mono">{{ task.cron }}</div>
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
<span
|
||||
:class="task.enabled ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-600'"
|
||||
class="px-2 py-1 text-xs font-medium rounded-full"
|
||||
>
|
||||
{{ task.enabled ? '已启用' : '已禁用' }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-right">
|
||||
<button
|
||||
@click="toggleTask(task)"
|
||||
:disabled="task._toggling"
|
||||
:class="task.enabled ? 'text-red-600 hover:text-red-800' : 'text-green-600 hover:text-green-800'"
|
||||
class="text-sm font-medium disabled:opacity-50"
|
||||
>
|
||||
{{ task._toggling ? '处理中...' : (task.enabled ? '禁用' : '启用') }}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="tasks.length === 0 && !loading">
|
||||
<td colspan="5" class="px-6 py-8 text-center text-gray-400">
|
||||
暂无定时任务
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Loading -->
|
||||
<div v-if="loading" class="text-center py-8 text-gray-400">
|
||||
加载中...
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ScheduledTasks',
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
tasks: [],
|
||||
message: '',
|
||||
error: ''
|
||||
};
|
||||
},
|
||||
async mounted() {
|
||||
await this.loadTasks();
|
||||
},
|
||||
methods: {
|
||||
async loadTasks() {
|
||||
this.loading = true;
|
||||
this.error = '';
|
||||
try {
|
||||
const res = await fetch('/api/admin/scheduled-tasks');
|
||||
const data = await res.json();
|
||||
if (data.success) {
|
||||
this.tasks = (data.data.tasks || []).map(t => ({ ...t, _toggling: false }));
|
||||
} else {
|
||||
this.error = data.message || '加载失败';
|
||||
}
|
||||
} catch (e) {
|
||||
this.error = e.message;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
async toggleTask(task) {
|
||||
task._toggling = true;
|
||||
this.error = '';
|
||||
this.message = '';
|
||||
try {
|
||||
const res = await fetch(`/api/admin/scheduled-tasks/${task.name}/toggle`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ enabled: !task.enabled })
|
||||
});
|
||||
const data = await res.json();
|
||||
if (data.success) {
|
||||
task.enabled = data.data.enabled;
|
||||
this.message = `任务 ${task.name} 已${task.enabled ? '启用' : '禁用'}`;
|
||||
} else {
|
||||
this.error = data.message || '操作失败';
|
||||
}
|
||||
} catch (e) {
|
||||
this.error = e.message;
|
||||
} finally {
|
||||
task._toggling = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
Reference in New Issue
Block a user