// ============================================================================ // power_shutdown.go — 延时关机(工具页) // // 用户在工具页输入「多少分钟后关机」,调用 ShutdownDelay 下发系统关机倒计时。 // 复用 pccontrol.go 的系统命令构造(shutdown /s /t N /f),交给 Windows 系统计时, // 即使本程序退出,倒计时仍由系统执行。返回计划执行时间供前端展示。 // ============================================================================ package main import ( "fmt" "strings" "time" ) // ShutdownDelay 在指定分钟后执行关机。 // minutes 必须 > 0;返回计划执行时间(HH:MM:SS)与提示信息。 func (s *SettingsService) ShutdownDelay(minutes int) (string, error) { if minutes <= 0 { return "", fmt.Errorf("关机分钟数必须大于 0") } if minutes > 24*60 { return "", fmt.Errorf("关机分钟数过大(最多 24 小时)") } delaySec := minutes * 60 cmd := pcSystemCommand(pcPoweroff, delaySec) if cmd == nil { return "", fmt.Errorf("当前系统不支持 shutdown 命令") } // 标记为待执行(与 API 路由共用状态,便于「主机」页取消) pcMu.Lock() if pcPending { remaining := time.Until(pcExecuteAt).Round(time.Second) pcMu.Unlock() return "", fmt.Errorf("已有待执行的电源命令,剩余 %v", remaining) } pcPending = true pcPendingCmd = pcPoweroff pcExecuteAt = time.Now().Add(time.Duration(delaySec) * time.Second) pcSystemTimer = true pcLastCmd = pcPoweroff pcLastTime = time.Now() pcRequested = true pcMu.Unlock() if output, err := cmd.CombinedOutput(); err != nil { pcMu.Lock() pcPending = false pcPendingCmd = "" pcExecuteAt = time.Time{} pcSystemTimer = false pcMu.Unlock() return "", fmt.Errorf("关机命令下发失败: %v | %s", err, strings.TrimSpace(string(output))) } execAt := pcExecuteAt.Format("15:04:05") fmt.Fprintf(apiLogRing, "[SYS] 工具页延时关机 | %d 分钟后(%s)\n", minutes, execAt) return execAt, nil } // CancelShutdown 取消延时关机(工具页「取消」按钮调用)。 func (s *SettingsService) CancelShutdown() error { pcMu.Lock() if !pcPending || pcPendingCmd != pcPoweroff { pcMu.Unlock() return fmt.Errorf("当前没有待执行的关机命令") } pcPending = false pcPendingCmd = "" pcExecuteAt = time.Time{} pcSystemTimer = false pcMu.Unlock() pcAbortShutdown() fmt.Fprintln(apiLogRing, "[SYS] 工具页取消延时关机") return nil }