diff --git a/agent/agent.go b/agent/agent.go index 9334981..c7e7388 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -68,6 +68,14 @@ func (t *AgentTask) GetTimeout() int { return t.Timeout } +func (t *AgentTask) GetWorkDir() string { + return t.WorkDir +} + +func (t *AgentTask) GetEnvs() string { + return t.Envs +} + func (t *AgentTask) GetSchedule() string { if t.Schedule != "" { return t.Schedule @@ -628,7 +636,9 @@ func (a *Agent) updateTasks(tasks []AgentTask) { // 2. 添加或更新任务 for id, task := range newTasks { oldTask, exists := a.tasks[id] - if !exists || oldTask.Schedule != task.Schedule || oldTask.Command != task.Command || oldTask.Enabled != task.Enabled { + if !exists || oldTask.Schedule != task.Schedule || oldTask.Command != task.Command || + oldTask.Enabled != task.Enabled || oldTask.Timeout != task.Timeout || + oldTask.WorkDir != task.WorkDir || oldTask.Envs != task.Envs { if task.Enabled { err := a.cronManager.AddTask(task) if err != nil { diff --git a/agent/main.go b/agent/main.go index 75bec4b..5929b33 100644 --- a/agent/main.go +++ b/agent/main.go @@ -12,6 +12,7 @@ import ( "syscall" "time" + internalLogger "github.com/engigu/baihu-panel/internal/logger" "github.com/engigu/baihu-panel/internal/utils" ) @@ -155,6 +156,7 @@ func cmdStart() { defer unlock() initLogger(logFile, true) + internalLogger.SetOutput(loggerInstance) config := &Config{Interval: 30} if err := loadConfigFile(configFile, config); err != nil { @@ -220,8 +222,9 @@ func cmdRun() { } defer unlock() - // 重启模式下只输出到文件(因为是从 daemon 进程 exec 过来的) - initLogger(logFile, isRestart) + // 前台模式始终输出到终端+文件 + initLogger(logFile, false) + internalLogger.SetOutput(loggerInstance) config := &Config{Interval: 30} if err := loadConfigFile(configFile, config); err != nil { diff --git a/internal/controllers/file_controller.go b/internal/controllers/file_controller.go index 538ddb5..09009a7 100644 --- a/internal/controllers/file_controller.go +++ b/internal/controllers/file_controller.go @@ -347,3 +347,29 @@ func (fc *FileController) UploadFiles(c *gin.Context) { utils.SuccessMsg(c, "上传成功") } + +func (fc *FileController) DownloadFile(c *gin.Context) { + filePath := c.Query("path") + if filePath == "" { + utils.BadRequest(c, "path参数必填") + return + } + + fullPath := filepath.Join(fc.workDir, filepath.Clean(filePath)) + if !strings.HasPrefix(fullPath, fc.workDir) { + utils.Forbidden(c, "访问被拒绝") + return + } + + info, err := os.Stat(fullPath) + if err != nil || info.IsDir() { + utils.NotFound(c, "文件不存在") + return + } + + c.Header("Content-Description", "File Transfer") + c.Header("Content-Transfer-Encoding", "binary") + c.Header("Content-Disposition", "attachment; filename="+filepath.Base(fullPath)) + c.Header("Content-Type", "application/octet-stream") + c.File(fullPath) +} diff --git a/internal/controllers/settings_controller.go b/internal/controllers/settings_controller.go index 6203c99..5be19b5 100644 --- a/internal/controllers/settings_controller.go +++ b/internal/controllers/settings_controller.go @@ -5,13 +5,13 @@ import ( "runtime" "strconv" + "fmt" "github.com/engigu/baihu-panel/internal/constant" "github.com/engigu/baihu-panel/internal/database" "github.com/engigu/baihu-panel/internal/models" "github.com/engigu/baihu-panel/internal/services" "github.com/engigu/baihu-panel/internal/services/tasks" "github.com/engigu/baihu-panel/internal/utils" - "fmt" "os" "time" diff --git a/internal/executor/cron.go b/internal/executor/cron.go index c005641..f123f3e 100644 --- a/internal/executor/cron.go +++ b/internal/executor/cron.go @@ -75,6 +75,8 @@ func (m *CronManager) AddTask(task CronTask) error { cmd := task.GetCommand() name := task.GetName() timeout := task.GetTimeout() + workDir := task.GetWorkDir() + envs := task.GetEnvs() entryID, err := m.cron.AddFunc(task.GetSchedule(), func() { defer func() { @@ -90,6 +92,8 @@ func (m *CronManager) AddTask(task CronTask) error { Command: cmd, Type: TaskTypeCron, Timeout: timeout, + WorkDir: workDir, + Envs: ParseEnvVars(envs), } // 如果有关联的 Scheduler,加入队列执行 diff --git a/internal/executor/executor.go b/internal/executor/executor.go index 096e294..686f75e 100644 --- a/internal/executor/executor.go +++ b/internal/executor/executor.go @@ -17,6 +17,8 @@ type Task interface { GetName() string GetCommand() string GetTimeout() int + GetWorkDir() string + GetEnvs() string } // CronTask 计划任务接口 diff --git a/internal/logger/logger.go b/internal/logger/logger.go index dcdc72d..8baa27b 100644 --- a/internal/logger/logger.go +++ b/internal/logger/logger.go @@ -104,6 +104,17 @@ func SetupFileOutput(logDir string) error { return nil } +// SetOutput 直接设置 Log 实例 +func SetOutput(l *zap.Logger) { + Log = l + Sugar = l.Sugar() +} + +// SetSugar 直接设置 Sugar 实例 +func SetSugar(s *zap.SugaredLogger) { + Sugar = s +} + // SetLevel 设置日志级别 func SetLevel(level string) { switch level { diff --git a/internal/models/env.go b/internal/models/env.go index 11d0f5b..a75017a 100644 --- a/internal/models/env.go +++ b/internal/models/env.go @@ -35,4 +35,4 @@ type Script struct { func (Script) TableName() string { return constant.TablePrefix + "scripts" -} \ No newline at end of file +} diff --git a/internal/models/task.go b/internal/models/task.go index 7ebc6f0..b97fb42 100644 --- a/internal/models/task.go +++ b/internal/models/task.go @@ -74,6 +74,14 @@ func (t *Task) GetTimeout() int { return t.Timeout } +func (t *Task) GetWorkDir() string { + return t.WorkDir +} + +func (t *Task) GetEnvs() string { + return t.Envs +} + func (t *Task) GetSchedule() string { return t.Schedule } diff --git a/internal/models/user.go b/internal/models/user.go index 6afd6c8..2daf881 100644 --- a/internal/models/user.go +++ b/internal/models/user.go @@ -20,4 +20,4 @@ type User struct { func (User) TableName() string { return constant.TablePrefix + "users" -} \ No newline at end of file +} diff --git a/internal/router/router.go b/internal/router/router.go index f53a145..56d1034 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -155,6 +155,7 @@ func Setup(c *Controllers) *gin.Engine { { files.GET("/tree", c.File.GetFileTree) files.GET("/content", c.File.GetFileContent) + files.GET("/download", c.File.DownloadFile) files.POST("/content", c.File.SaveFileContent) files.POST("/create", c.File.CreateFile) files.POST("/delete", c.File.DeleteFile) diff --git a/web/src/api/index.ts b/web/src/api/index.ts index 0d35c8d..614d5c3 100644 --- a/web/src/api/index.ts +++ b/web/src/api/index.ts @@ -152,6 +152,7 @@ export const api = { files: { tree: () => request('/files/tree'), getContent: (path: string) => request<{ path: string; content: string }>(`/files/content?path=${encodeURIComponent(path)}`), + download: (path: string) => `${API_BASE_URL}/files/download?path=${encodeURIComponent(path)}`, saveContent: (path: string, content: string) => request('/files/content', { method: 'POST', body: JSON.stringify({ path, content }) }), create: (path: string, isDir: boolean) => request('/files/create', { method: 'POST', body: JSON.stringify({ path, isDir }) }), delete: (path: string) => request('/files/delete', { method: 'POST', body: JSON.stringify({ path }) }), diff --git a/web/src/components/FileTreeNode.vue b/web/src/components/FileTreeNode.vue index 228f5bb..84deee5 100644 --- a/web/src/components/FileTreeNode.vue +++ b/web/src/components/FileTreeNode.vue @@ -1,9 +1,13 @@ @@ -272,20 +288,14 @@ onMounted(loadTree) - +
暂无文件
- +
@@ -296,24 +306,15 @@ onMounted(loadTree) {{ selectedFile || '未选择文件' }} ● 未保存 - - +
- + }" style="height: 100%" @mount="handleEditorMount" />
选择一个文件开始编辑
@@ -344,12 +342,8 @@ onMounted(loadTree)
位置: {{ selectedDir }}/
- +
完整路径: {{ createFullPath }}
@@ -369,7 +363,8 @@ onMounted(loadTree) 取消 - 删除 + 删除