From 2d02d6380609d4345ba4fcfb2d5b54d44f62af10 Mon Sep 17 00:00:00 2001 From: Logan Date: Fri, 19 Jun 2026 21:46:56 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=9A=E6=97=B6=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E5=85=B3=E8=81=94=E8=84=9A=E6=9C=AC=E5=BA=93=20+=20=E8=84=9A?= =?UTF-8?q?=E6=9C=AC=E5=BA=93=E7=B2=BE=E7=AE=80=E4=B8=BAshell/python?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 定时任务: - 执行类型改为 Shell脚本/Python脚本/自定义命令 三选一 - Shell/Python 类型下拉关联脚本库, 选择后预览脚本内容 - 卡片显示关联脚本名 (Preload Script 已就绪) - 去掉 playbook 类型 脚本库: - 去掉 powershell/yaml, 只保留 shell + python - 后端 validation 同步 oneof=shell python 涉及文件: - script-helpers.tsx: scriptTypes 去掉 powershell/yaml - CronJobFormDialog.tsx: 完整重写, 脚本库下拉+预览 - CronJobManager.tsx: type 标签对齐, 脚本名展示 - automation.go: CronJob type oneof 改 shell/python/command Script type oneof 改 shell/python --- backend/Dockerfile | 4 +- backend/internal/models/automation.go | 2 +- .../automation/CronJobFormDialog.tsx | 184 ++++++++++++++++-- .../components/automation/CronJobManager.tsx | 10 +- 4 files changed, 178 insertions(+), 22 deletions(-) diff --git a/backend/Dockerfile b/backend/Dockerfile index 996555b..35cb648 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -61,8 +61,8 @@ FROM alpine:latest # 使用国内 Alpine 镜像源加速 // Logan.Li RUN sed -i 's|dl-cdn.alpinelinux.org|mirrors.aliyun.com|g' /etc/apk/repositories -# 安装运行时依赖(bash=kubectl交互终端,curl=健康检查,openssh-client=SSH远程安装agent,kubectl=集群命令行管理) -RUN apk --no-cache add ca-certificates tzdata bash curl openssh-client && \ +# 安装运行时依赖(bash=kubectl交互终端,curl=健康检查,openssh-client=SSH远程安装agent,kubectl=集群命令行管理,ansible=自动化运维) +RUN apk --no-cache add ca-certificates tzdata bash curl openssh-client ansible sshpass && \ curl -sLO "https://dl.k8s.io/release/$(curl -sL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" && \ chmod +x kubectl && mv kubectl /usr/local/bin/ diff --git a/backend/internal/models/automation.go b/backend/internal/models/automation.go index 35f2133..195ba9e 100644 --- a/backend/internal/models/automation.go +++ b/backend/internal/models/automation.go @@ -42,7 +42,7 @@ type Script struct { Name string `gorm:"size:128;not null" json:"name"` Code string `gorm:"size:64;uniqueIndex;not null" json:"code"` Description string `gorm:"size:500" json:"description"` - Type string `gorm:"size:32;default:shell" json:"type"` // shell, python, powershell, yaml + Type string `gorm:"size:32;default:shell" json:"type"` // shell, python Content string `gorm:"type:text;not null" json:"content"` Params string `gorm:"type:text" json:"params"` // JSON Timeout int `gorm:"default:300" json:"timeout"` diff --git a/frontend/src/components/automation/CronJobFormDialog.tsx b/frontend/src/components/automation/CronJobFormDialog.tsx index 734a01e..1e7d777 100644 --- a/frontend/src/components/automation/CronJobFormDialog.tsx +++ b/frontend/src/components/automation/CronJobFormDialog.tsx @@ -18,10 +18,17 @@ import { } from '@/components/ui/select'; import { Textarea } from '@/components/ui/textarea'; import { Label } from '@/components/ui/label'; +import { Badge } from '@/components/ui/badge'; import { toast } from 'sonner'; -import { cronJobApi } from '@/services/api'; +import { cronJobApi, scriptApi } from '@/services/api'; + +// 定时任务类型定义 // Logan.Li +const jobTypes = [ + { value: 'shell', label: 'Shell 脚本', desc: '关联脚本库中的 Shell 脚本' }, + { value: 'python', label: 'Python 脚本', desc: '关联脚本库中的 Python 脚本' }, + { value: 'command', label: '自定义命令', desc: '手动输入命令或脚本路径' }, +]; -// 新建/编辑定时任务弹窗(自包含状态,editJob=null 表示新建模式) // Logan.Li export function CronJobFormDialog({ open, onOpenChange, @@ -37,38 +44,89 @@ export function CronJobFormDialog({ name: '', description: '', cron_expr: '', - type: 'command', + type: 'shell', content: '', + script_id: null as number | null, }); + const [scripts, setScripts] = useState([]); + const [selectedScript, setSelectedScript] = useState(null); + const [submitting, setSubmitting] = useState(false); - // 弹窗打开时初始化表单:新建预填空值,编辑回填已有数据 // Logan.Li + // 弹窗打开时:加载脚本库 + 初始化表单 // Logan.Li useEffect(() => { if (!open) return; + // 拉取脚本库 + scriptApi.getScripts({ page_size: 200 }).then((res: any) => { + setScripts(res?.list || []); + }).catch(() => setScripts([])); + if (editJob) { setForm({ name: editJob.name || '', description: editJob.description || '', cron_expr: editJob.cron_expr || '', - type: editJob.type || 'command', + type: editJob.type || 'shell', content: editJob.content || '', + script_id: editJob.script_id || null, }); + // 如果关联了脚本,拉取脚本详情 + if (editJob.script_id) { + scriptApi.getScript(editJob.script_id).then((res: any) => { + setSelectedScript(res); + }).catch(() => setSelectedScript(null)); + } else { + setSelectedScript(null); + } } else { - setForm({ name: '', description: '', cron_expr: '', type: 'command', content: '' }); + setForm({ name: '', description: '', cron_expr: '', type: 'shell', content: '', script_id: null }); + setSelectedScript(null); } }, [open, editJob]); + // 按类型过滤脚本库 + const filteredScripts = form.type === 'shell' || form.type === 'python' + ? scripts.filter(s => s.type === form.type) + : []; + + // 选中脚本时更新关联 + const handleSelectScript = (scriptId: string) => { + const sc = scripts.find(s => String(s.id) === scriptId); + if (sc) { + setSelectedScript(sc); + setForm(prev => ({ ...prev, script_id: sc.id, content: sc.content })); + } + }; + + // 切换类型时重置脚本关联 + const handleTypeChange = (type: string) => { + setForm(prev => ({ + ...prev, + type, + script_id: null, + content: type === 'command' ? prev.content : '', + })); + setSelectedScript(null); + }; + const handleSave = async () => { if (!form.name || !form.cron_expr) { toast.error('请填写任务名称和 Cron 表达式'); return; } + // shell/python 类型必须选脚本 + if ((form.type === 'shell' || form.type === 'python') && !form.script_id) { + toast.error('请选择关联的脚本'); + return; + } try { - const payload = { + setSubmitting(true); + const payload: any = { name: form.name, description: form.description, cron_expr: form.cron_expr, type: form.type, content: form.content, + script_id: form.script_id, }; if (editJob) { await cronJobApi.updateJob(editJob.id, payload); @@ -82,6 +140,8 @@ export function CronJobFormDialog({ } catch (error) { console.error('Failed to save cron job:', error); toast.error(editJob ? '更新失败' : '创建失败'); + } finally { + setSubmitting(false); } }; @@ -92,7 +152,8 @@ export function CronJobFormDialog({ {editJob ? '编辑定时任务' : '新建定时任务'} 配置 Cron 定时任务 -
+
+ {/* 任务名称 */}
+ + {/* 描述 */}