diff --git a/internal/service/task.go b/internal/service/task.go
index 8202584..b370a1a 100644
--- a/internal/service/task.go
+++ b/internal/service/task.go
@@ -429,6 +429,21 @@ func (s *TaskService) executeOnDevice(task *models.Task, did string) {
s.updateDeviceStatus(task.ID, did, models.TaskSuccess, 1.0, "")
s.appendAuditLog(task, did, models.TaskSuccess, "")
+ case "time_sync":
+ nowMS := time.Now().UnixMilli()
+ body, _ := json.Marshal(map[string]int64{"unix_ms": nowMS})
+ _, code, err := s.agent.Do("POST", dev.IP, dev.AgentPort, "/v1/time/set", body)
+ if err != nil {
+ s.updateDeviceStatus(task.ID, did, models.TaskFailed, 0, err.Error())
+ return
+ }
+ if code >= 400 {
+ s.updateDeviceStatus(task.ID, did, models.TaskFailed, 0, fmt.Sprintf("agent error: %d", code))
+ return
+ }
+ s.updateDeviceStatus(task.ID, did, models.TaskSuccess, 1.0, "")
+ s.appendAuditLog(task, did, models.TaskSuccess, "")
+
case "face_gallery_reload":
_, code, err := s.agent.Do("POST", dev.IP, dev.AgentPort, "/v1/face-gallery/reload", nil)
if err != nil {
diff --git a/internal/web/ui.go b/internal/web/ui.go
index 31de51a..238525c 100644
--- a/internal/web/ui.go
+++ b/internal/web/ui.go
@@ -1753,7 +1753,7 @@ func (u *UI) actionDevicesBatchAction(w http.ResponseWriter, r *http.Request) {
typeStr := ""
switch action {
- case "media_start", "media_restart", "media_stop", "reload", "rollback":
+ case "media_start", "media_restart", "media_stop", "reload", "rollback", "time_sync":
typeStr = action
default:
u.render(w, r, "devices", u.deviceOverviewPageData(r, deviceIDs, "不支持的操作: "+action))
diff --git a/internal/web/ui/templates/devices.html b/internal/web/ui/templates/devices.html
index ced14da..01a497b 100644
--- a/internal/web/ui/templates/devices.html
+++ b/internal/web/ui/templates/devices.html
@@ -47,6 +47,10 @@
{{if $allOffline}}
{{end}}
+ {{$drift := false}}{{range .DeviceRows}}{{if and (gt .TimeDriftSec 5) (hasString $.SelectedDeviceIDs .Device.DeviceID)}}{{$drift = true}}{{end}}{{end}}
+ {{if $drift}}
+
+ {{end}}
下发设备分配
清空选择