| 279 | } |
| 280 | |
| 281 | async function startRun() { |
| 282 | const modeNode = document.getElementById('selfcheck-mode-select'); |
| 283 | const runBtn = document.getElementById('selfcheck-run-btn'); |
| 284 | if (!modeNode || !runBtn) return; |
| 285 | |
| 286 | loading.show(runBtn, '执行中...'); |
| 287 | try { |
| 288 | const payload = { mode: modeNode.value, source: 'manual', run_async: true }; |
| 289 | const result = await api.post('/selfcheck/runs', payload); |
| 290 | const run = result?.run || null; |
| 291 | if (run?.id) { |
| 292 | selfcheckState.selectedRunId = Number(run.id); |
| 293 | } |
| 294 | toast.success(result?.message || '自检任务已启动'); |
| 295 | await loadRuns(); |
| 296 | } catch (error) { |
| 297 | const message = parseErrorMessage(error); |
| 298 | toast.error(`启动失败: ${message}`); |
| 299 | } finally { |
| 300 | loading.hide(runBtn); |
| 301 | } |
| 302 | } |
| 303 | |
| 304 | async function saveSchedule() { |
| 305 | const btn = document.getElementById('selfcheck-save-schedule-btn'); |