fix: console stays after deploy, auto-refresh, config retry

- 下发后留在控制台,显示状态提示,6秒自动刷新
- 任务页 SSE 自动连接(无需手动点击)
- 总览页有执行中任务时自动刷新
- config_apply 增加 3 次重试(agent 500 时)
This commit is contained in:
tian 2026-05-12 14:51:59 +08:00
parent 15f6f91fb6
commit f2b3941e4a
6 changed files with 43 additions and 10 deletions

View File

@ -9,6 +9,7 @@ import (
"path/filepath"
"strings"
"sync"
"time"
"3588AdminBackend/internal/config"
"3588AdminBackend/internal/models"
@ -307,13 +308,26 @@ func (s *TaskService) executeOnDevice(task *models.Task, did string) {
s.updateDeviceStatus(task.ID, did, models.TaskFailed, 0, "invalid payload: "+err.Error())
return
}
_, code, err := s.agent.Do("PUT", dev.IP, dev.AgentPort, "/v1/config", body)
if err != nil {
s.updateDeviceStatus(task.ID, did, models.TaskFailed, 0, err.Error())
// Retry config apply up to 3 times (media-server may be slow to reload).
var lastErr error
var lastCode int
for attempt := 0; attempt < 3; attempt++ {
if attempt > 0 {
time.Sleep(time.Duration(attempt) * 3 * time.Second)
s.updateDeviceStatus(task.ID, did, models.TaskRunning, float64(attempt)/3.0, fmt.Sprintf("重试 %d/2", attempt))
}
_, code, err := s.agent.Do("PUT", dev.IP, dev.AgentPort, "/v1/config", body)
if err == nil && code < 400 {
lastErr = nil; lastCode = code; break
}
lastErr = err; lastCode = code
}
if lastErr != nil {
s.updateDeviceStatus(task.ID, did, models.TaskFailed, 0, lastErr.Error())
return
}
if code >= 400 {
s.updateDeviceStatus(task.ID, did, models.TaskFailed, 0, fmt.Sprintf("agent error: %d", code))
if lastCode >= 400 {
s.updateDeviceStatus(task.ID, did, models.TaskFailed, 0, fmt.Sprintf("agent error: %d", lastCode))
return
}
s.updateDeviceStatus(task.ID, did, models.TaskSuccess, 1.0, "")

View File

@ -1192,11 +1192,11 @@ func (u *UI) actionConsoleSave(w http.ResponseWriter, r *http.Request) {
}
if len(taskIDs) == 1 {
http.Redirect(w, r, "/ui/console?task="+taskIDs[0], http.StatusFound)
http.Redirect(w, r, "/ui/console?msg="+url.QueryEscape("正在下发配置...")+"&task="+taskIDs[0], http.StatusFound)
return
}
if len(taskIDs) > 1 {
http.Redirect(w, r, "/ui/console?task="+taskIDs[0]+"&msg="+url.QueryEscape(fmt.Sprintf("已为 %d 台设备创建下发任务", len(taskIDs))), http.StatusFound)
http.Redirect(w, r, "/ui/console?msg="+url.QueryEscape(fmt.Sprintf("正在为 %d 台设备下发配置...", len(taskIDs))), http.StatusFound)
return
}
if len(errs) > 0 {

View File

@ -375,11 +375,17 @@
});
});
// Show saved task info from URL param
// Show saved task info and auto-refresh from URL param
(function() {
var m = location.search.match(/[?&]task=([^&]+)/);
if (m) {
document.getElementById('console-status').innerHTML = '✅ 任务 ' + m[1].substring(0,8) + ' 已创建';
document.getElementById('console-status').innerHTML = '⏳ 任务 ' + m[1].substring(0,8) + ' 执行中,页面将自动刷新...';
setTimeout(function(){ location.href = '/ui/console'; }, 6000);
}
var msg = location.search.match(/[?&]msg=([^&]+)/);
if (msg) {
document.getElementById('console-status').innerHTML = decodeURIComponent(msg[1]);
if (!m) setTimeout(function(){ document.getElementById('console-status').innerHTML = ''; }, 5000);
}
})();
})();

View File

@ -73,5 +73,10 @@
</table>
</div>
</div>
<script>
(function(){
if({{.RunningTaskCount}}>0) setTimeout(function(){location.reload()},6000);
})();
</script>
{{end}}

View File

@ -144,5 +144,13 @@ function cssEscape(s){
return String(s).replace(/[^a-zA-Z0-9_-]/g, (c) => "\\"+c);
}
syncTaskStatus();
// Auto-connect SSE and auto-refresh if task is in progress.
(function(){
var s='{{.Task.Status}}';
if(s==='running'||s==='pending'){
startSSE();
setTimeout(function(){location.reload()},8000);
}
})();
</script>
{{end}}

View File

@ -1,5 +1,5 @@
{{define "tasks"}}
<div class="card">
<div class="card" id="tasks-container">
<h2>执行历史</h2>
<div class="table-wrap" style="margin-top:10px">
<table>