feat: 定时任务编辑入口全栈打通 + 修复ApprovalFlow编译错误 + 完成大文件拆分重构

- CronJobManager: 编辑按钮接通 onClick → openEdit(job),弹出编辑对话框预填数据,
  复用新建/编辑共用 Dialog(editingId 区分模式),标题/按钮文案动态切换,
  保存时根据 editingId 调用 createJob 或 updateJob — 消除占位按钮
- ApprovalFlow: 修复 API 方法名不匹配导致 tsc -b 编译失败
  (getInstances→getProcesses, getMyApprovals→getProcesses({status:'pending'}),
   approveInstance→approveProcess, rejectInstance→rejectProcess)
  + 添加 ApprovalFlowManager 导出别名兼容 App.tsx 导入
- 合并已完成的大文件拆分重构: automation.go→automation_cron/script/playbook,
  ldap.go→ldap_ou/ldap_users, server.go→cloud_accounts/domain/platform/region,
  user.go→user_admin; 前端 Dashboard/K8s/Server/Approval/Monitor 子组件拆分
  // Logan.Li
This commit is contained in:
attacker committed 2026-06-15 01:09:49 +08:00
1 parent 8be63ac168
commit a7e2351ad2
37 files changed
+7374 -4891

No files matched your search

@@ -49,13 +49,15 @@ export function CronJobManager() {
const [searchQuery, setSearchQuery] = useState('');
const [jobs, setJobs] = useState<any[]>([]);
const [loading, setLoading] = useState(true);
const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false);
const [isFormDialogOpen, setIsFormDialogOpen] = useState(false);
const [isLogDialogOpen, setIsLogDialogOpen] = useState(false);
const [executions, setExecutions] = useState<any[]>([]);
const [executionsLoading, setExecutionsLoading] = useState(false);
const [expandedExec, setExpandedExec] = useState<number | null>(null);
const [executingId, setExecutingId] = useState<number | null>(null);
const [newJob, setNewJob] = useState({
// editingId === null 表示新建模式;非 null 表示编辑已有任务
const [editingId, setEditingId] = useState<number | null>(null);
const [formJob, setFormJob] = useState({
name: '',
description: '',
cron_expr: '',
@@ -63,6 +65,24 @@ export function CronJobManager() {
content: '',
});
const openCreate = () => {
setEditingId(null);
setFormJob({ name: '', description: '', cron_expr: '', type: 'command', content: '' });
setIsFormDialogOpen(true);
};
const openEdit = (job: any) => {
setEditingId(job.id);
setFormJob({
name: job.name || '',
description: job.description || '',
cron_expr: job.cron_expr || '',
type: job.type || 'command',
content: job.content || '',
});
setIsFormDialogOpen(true);
};
const loadData = async () => {
try {
setLoading(true);
@@ -145,26 +165,31 @@ export function CronJobManager() {
return patterns[schedule] || schedule;
};
const handleCreateJob = async () => {
if (!newJob.name || !newJob.cron_expr) {
const handleSaveJob = async () => {
if (!formJob.name || !formJob.cron_expr) {
toast.error('请填写任务名称和 Cron 表达式');
return;
}
try {
await cronJobApi.createJob({
name: newJob.name,
description: newJob.description,
cron_expr: newJob.cron_expr,
type: newJob.type,
content: newJob.content,
});
toast.success('任务创建成功');
setIsCreateDialogOpen(false);
setNewJob({ name: '', description: '', cron_expr: '', type: 'command', content: '' });
const payload = {
name: formJob.name,
description: formJob.description,
cron_expr: formJob.cron_expr,
type: formJob.type,
content: formJob.content,
};
if (editingId !== null) {
await cronJobApi.updateJob(editingId, payload);
toast.success('任务更新成功');
} else {
await cronJobApi.createJob(payload);
toast.success('任务创建成功');
}
setIsFormDialogOpen(false);
loadData();
} catch (error) {
console.error('Failed to create cron job:', error);
toast.error('创建失败');
console.error('Failed to save cron job:', error);
toast.error(editingId !== null ? '更新失败' : '创建失败');
}
};
@@ -221,7 +246,7 @@ export function CronJobManager() {
<History className="h-4 w-4 mr-2" />
执行历史
</Button>
<Button className="bg-blue-600 hover:bg-blue-700" onClick={() => setIsCreateDialogOpen(true)}>
<Button className="bg-blue-600 hover:bg-blue-700" onClick={openCreate}>
<Plus className="h-4 w-4 mr-2" />
新建任务
</Button>
@@ -350,7 +375,13 @@ export function CronJobManager() {
>
{job.enabled ? <Pause className="h-4 w-4" /> : <Play className="h-4 w-4" />}
</Button>
<Button variant="ghost" size="icon" className="h-8 w-8 text-slate-400 hover:text-blue-400">
<Button
variant="ghost"
size="icon"
className="h-8 w-8 text-slate-400 hover:text-blue-400"
title="编辑"
onClick={() => openEdit(job)}
>
<Edit className="h-4 w-4" />
</Button>
<Button
@@ -368,19 +399,19 @@ export function CronJobManager() {
))}
</div>
{/* Create Job Dialog */}
<Dialog open={isCreateDialogOpen} onOpenChange={setIsCreateDialogOpen}>
{/* Create / Edit Job Dialog (共用) */}
<Dialog open={isFormDialogOpen} onOpenChange={setIsFormDialogOpen}>
<DialogContent className="max-w-2xl bg-slate-900 border-slate-700 text-slate-100">
<DialogHeader>
<DialogTitle>新建定时任务</DialogTitle>
<DialogTitle>{editingId !== null ? '编辑定时任务' : '新建定时任务'}</DialogTitle>
<DialogDescription className="text-slate-500">配置 Cron 定时任务</DialogDescription>
</DialogHeader>
<div className="space-y-4 py-4">
<div>
<Label className="text-slate-300">任务名称</Label>
<Input
value={newJob.name}
onChange={(e) => setNewJob({ ...newJob, name: e.target.value })}
value={formJob.name}
onChange={(e) => setFormJob({ ...formJob, name: e.target.value })}
placeholder="例如: 数据库备份"
className="bg-slate-800 border-slate-700 text-slate-100 mt-1"
/>
@@ -388,8 +419,8 @@ export function CronJobManager() {
<div>
<Label className="text-slate-300">描述</Label>
<Textarea
value={newJob.description}
onChange={(e) => setNewJob({ ...newJob, description: e.target.value })}
value={formJob.description}
onChange={(e) => setFormJob({ ...formJob, description: e.target.value })}
placeholder="任务描述..."
className="bg-slate-800 border-slate-700 text-slate-100 mt-1"
/>
@@ -398,12 +429,12 @@ export function CronJobManager() {
<Label className="text-slate-300">Cron 表达式</Label>
<div className="flex gap-2">
<Input
value={newJob.cron_expr}
onChange={(e) => setNewJob({ ...newJob, cron_expr: e.target.value })}
value={formJob.cron_expr}
onChange={(e) => setFormJob({ ...formJob, cron_expr: e.target.value })}
placeholder="0 2 * * *"
className="bg-slate-800 border-slate-700 text-slate-100 mt-1"
/>
<Select onValueChange={(v) => setNewJob({ ...newJob, cron_expr: v })}>
<Select onValueChange={(v) => setFormJob({ ...formJob, cron_expr: v })}>
<SelectTrigger className="w-48 bg-slate-800 border-slate-700 text-slate-100 mt-1">
<SelectValue placeholder="快速选择" />
</SelectTrigger>
@@ -421,19 +452,19 @@ export function CronJobManager() {
<div>
<Label className="text-slate-300">执行命令</Label>
<Textarea
value={newJob.content}
onChange={(e) => setNewJob({ ...newJob, content: e.target.value })}
value={formJob.content}
onChange={(e) => setFormJob({ ...formJob, content: e.target.value })}
placeholder="/scripts/backup.sh"
className="bg-slate-800 border-slate-700 text-slate-100 mt-1 font-mono"
/>
</div>
</div>
<DialogFooter>
<Button variant="outline" onClick={() => setIsCreateDialogOpen(false)} className="border-slate-700 text-slate-300">
<Button variant="outline" onClick={() => setIsFormDialogOpen(false)} className="border-slate-700 text-slate-300">
取消
</Button>
<Button className="bg-blue-600 hover:bg-blue-700" onClick={handleCreateJob}>
创建任务
<Button className="bg-blue-600 hover:bg-blue-700" onClick={handleSaveJob}>
{editingId !== null ? '保存修改' : '创建任务'}
</Button>
</DialogFooter>
</DialogContent>