feat: 定时执行工单 — 新建工单+自动任务管理全面重构
后端:
- Ticket 模型新增 scheduled_at 字段 (DateTime, nullable)
- TicketStatus 新增 SCHEDULED 状态
- 状态转换图: approved→scheduled, scheduled→executing/approved
- execute_ticket: scheduled_at 在未来时进入 scheduled 状态
- ticket_scheduler.py: asyncio 后台定时执行器
- GET /tickets/scheduled/list: 列出定时执行中工单
- POST /tickets/{id}/cancel-schedule: 取消定时执行
前端:
- TicketCreatePage: 新增定时执行 checkbox + datetime-local picker (秒级精度)
- AutoTaskPage: 全面重写为真实定时任务管理页
- 实时倒计时显示 (Xh Xm 后执行)
- DB 类型图标 (MySQL/PG/Redis/MongoDB)
- SQL 预览 + 取消定时执行
- 每 30 秒自动刷新
This commit is contained in:
1 parent
478e663313
commit
ffb3d24e2a
6 files changed
+418
-262
No files matched your search
@@ -98,6 +98,8 @@ export default function TicketCreatePage() {
|
||||
const [database, setDatabase] = useState('');
|
||||
const [sqlContent, setSqlContent] = useState('');
|
||||
const [reason, setReason] = useState('');
|
||||
const [scheduledAt, setScheduledAt] = useState('');
|
||||
const [enableSchedule, setEnableSchedule] = useState(false);
|
||||
|
||||
// -- Data / Loading --
|
||||
const [instances, setInstances] = useState<InstanceItem[]>([]);
|
||||
@@ -287,6 +289,7 @@ export default function TicketCreatePage() {
|
||||
sql_content: sqlContent,
|
||||
reason: reason.trim(),
|
||||
priority: 'medium',
|
||||
scheduled_at: enableSchedule && scheduledAt ? new Date(scheduledAt).toISOString() : undefined,
|
||||
});
|
||||
navigate('/tickets');
|
||||
} catch (e: unknown) {
|
||||
@@ -700,6 +703,27 @@ export default function TicketCreatePage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 定时执行 */}
|
||||
<div className="flex items-center gap-4">
|
||||
<label className="flex items-center gap-2 cursor-pointer select-none">
|
||||
<input type="checkbox" checked={enableSchedule} onChange={(e) => setEnableSchedule(e.target.checked)}
|
||||
className="w-4 h-4 rounded border-[var(--dg-border)] bg-[var(--dg-bg-primary)] text-blue-500 focus:ring-blue-500 focus:ring-offset-0" />
|
||||
<Clock className="w-4 h-4 text-[var(--dg-text-muted)]" />
|
||||
<span className="text-sm">定时执行</span>
|
||||
</label>
|
||||
{enableSchedule && (
|
||||
<input type="datetime-local" value={scheduledAt} onChange={(e) => setScheduledAt(e.target.value)}
|
||||
step="1"
|
||||
className="px-3 py-2 bg-[var(--dg-bg-primary)] border border-[var(--dg-border)] rounded-lg text-sm focus:outline-none focus:border-blue-500 transition-colors"
|
||||
min={new Date().toISOString().slice(0, 16)} />
|
||||
)}
|
||||
{enableSchedule && scheduledAt && (
|
||||
<span className="text-xs text-[var(--dg-text-muted)]">
|
||||
将于 {new Date(scheduledAt).toLocaleString('zh-CN')} 执行
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* SQL Editor + Browser Panel */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-5 gap-4">
|
||||
<div className="lg:col-span-3 space-y-3">
|
||||
|
||||
Reference in new issue
Block a user