更新功能:数据字典和定时任务

This commit is contained in:
2026-02-18 10:43:25 +08:00
parent 6623c656f4
commit 790b3140a7
15 changed files with 2847 additions and 25 deletions

View File

@@ -0,0 +1,178 @@
<template>
<a-modal title="任务详情" :open="visible" :footer="null" @cancel="handleCancel" width="800px">
<a-descriptions bordered :column="2" v-if="task">
<a-descriptions-item label="任务名称">{{ task.name }}</a-descriptions-item>
<a-descriptions-item label="任务类型">
<a-tag :color="getTypeColor(task.type)">{{ getTypeText(task.type) }}</a-tag>
</a-descriptions-item>
<a-descriptions-item label="命令/类" :span="2">
<code class="command-code">{{ task.command }}</code>
</a-descriptions-item>
<a-descriptions-item label="Cron表达式">
<code class="cron-code">{{ task.expression }}</code>
</a-descriptions-item>
<a-descriptions-item label="时区">{{ task.timezone }}</a-descriptions-item>
<a-descriptions-item label="状态" :span="2">
<a-tag :color="task.is_active ? 'success' : 'error'">
{{ task.is_active ? '启用' : '禁用' }}
</a-tag>
</a-descriptions-item>
<a-descriptions-item label="上次运行时间" :span="2">
{{ task.last_run_at ? formatDate(task.last_run_at) : '未运行' }}
</a-descriptions-item>
<a-descriptions-item label="下次运行时间" :span="2">
{{ task.next_run_at ? formatDate(task.next_run_at) : '-' }}
</a-descriptions-item>
<a-descriptions-item label="运行次数">
<a-tag color="success">成功: {{ task.run_count || 0 }}</a-tag>
</a-descriptions-item>
<a-descriptions-item label="失败次数">
<a-tag :color="task.failed_count > 0 ? 'error' : 'default'">
失败: {{ task.failed_count || 0 }}
</a-tag>
</a-descriptions-item>
<a-descriptions-item label="后台运行" :span="2">
{{ task.run_in_background ? '是' : '否' }}
</a-descriptions-item>
<a-descriptions-item label="描述" :span="2">
{{ task.description || '-' }}
</a-descriptions-item>
</a-descriptions>
<!-- 最后输出 -->
<div v-if="task.last_output" class="output-section">
<a-divider>最后输出</a-divider>
<pre class="output-content">{{ task.last_output }}</pre>
</div>
<!-- 底部按钮 -->
<div class="dialog-footer">
<a-space>
<a-button @click="handleCancel">关闭</a-button>
<a-button type="primary" @click="handleRun">
<template #icon><PlayCircleOutlined /></template>
立即执行
</a-button>
</a-space>
</div>
</a-modal>
</template>
<script setup>
import { ref, computed } from 'vue'
import { message } from 'ant-design-vue'
import { PlayCircleOutlined } from '@ant-design/icons-vue'
import systemApi from '@/api/system'
const props = defineProps({
visible: {
type: Boolean,
default: false
},
record: {
type: Object,
default: null
}
})
const emit = defineEmits(['update:visible', 'refresh'])
const task = computed(() => props.record)
// 获取任务类型文本
const getTypeText = (type) => {
const typeMap = {
command: '命令',
job: '任务',
closure: '闭包'
}
return typeMap[type] || type
}
// 获取任务类型颜色
const getTypeColor = (type) => {
const colorMap = {
command: 'blue',
job: 'green',
closure: 'orange'
}
return colorMap[type] || 'default'
}
// 格式化日期
const formatDate = (dateStr) => {
if (!dateStr) return '-'
const date = new Date(dateStr)
return date.toLocaleString('zh-CN')
}
// 执行任务
const handleRun = async () => {
if (!props.record) return
try {
const res = await systemApi.tasks.run.post(props.record.id)
if (res.code === 200) {
message.success('任务执行成功')
emit('refresh')
handleCancel()
} else {
message.error(res.message || '任务执行失败')
}
} catch (error) {
message.error('任务执行失败')
}
}
// 取消
const handleCancel = () => {
emit('update:visible', false)
}
</script>
<style scoped lang="scss">
.command-code {
padding: 4px 8px;
background: #f5f5f5;
border-radius: 3px;
font-family: 'Consolas', 'Monaco', monospace;
font-size: 12px;
word-break: break-all;
}
.cron-code {
padding: 2px 6px;
background: #f5f5f5;
border-radius: 3px;
font-family: 'Consolas', 'Monaco', monospace;
font-size: 12px;
}
.output-section {
margin-top: 16px;
.output-content {
padding: 12px;
background: #f5f5f5;
border-radius: 4px;
max-height: 200px;
overflow-y: auto;
font-family: 'Consolas', 'Monaco', monospace;
font-size: 12px;
white-space: pre-wrap;
word-break: break-all;
}
}
.dialog-footer {
display: flex;
justify-content: flex-end;
padding-top: 16px;
border-top: 1px solid #f0f0f0;
margin-top: 16px;
}
:deep(.ant-descriptions-item-label) {
font-weight: 500;
}
</style>