feat: v0.3.1 — Go/Gin 后端重写 + gh-ost 集成
架构变更: - Python/FastAPI → Go/Gin 重写(Python 后端保留在 backend-python/) - GORM + SQLite(兼容现有数据库表结构) - JWT 认证 + RBAC 权限中间件 Go 后端结构: - cmd/server/main.go — 入口,端口 9000 - config/config.go — 环境变量配置 - internal/model/ — GORM 模型(30张表,完全兼容 SQLite) - internal/handler/ — auth/instance/ticket/dashboard/ghost handler - internal/middleware/ — JWT 认证 + CORS - internal/ghost/ — gh-ost 集成模块(同步/异步执行,任务管理) - router/router.go — API 路由注册(/api/v1/...) gh-ost 集成: - RunGhOst() 同步执行 - RunGhOstAsync() 异步执行 + 进度追踪 - TaskManager 管理多个并发任务 - API: POST /ghost/dry-run, /ghost/execute, GET /ghost/status/:taskId 核心 API 已对齐: - POST /auth/login (JWT) - GET /dashboard/stats, /dashboard/my-tickets - GET /tickets/statistics, CRUD + approve/execute - GET/POST/PUT/DELETE /instances - GET /users, /audit-rules, /announcements, /settings 已验证: - 登录 admin/admin123 ✅ - Dashboard 99工单/110查询/4实例 ✅ - 工单统计按角色过滤 ✅
This commit is contained in:
1 parent
43d1f3a234
commit
ca308e277d
202 files changed
+2265
-51181
No files matched your search
@@ -0,0 +1,132 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"sql-platform/config"
|
||||
"sql-platform/internal/ghost"
|
||||
"sql-platform/internal/model"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// POST /api/v1/ghost/dry-run
|
||||
func GhOstDryRun(c *gin.Context) {
|
||||
var task ghost.GhOstTask
|
||||
if err := c.ShouldBindJSON(&task); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"detail": err.Error()})
|
||||
return
|
||||
}
|
||||
task.DryRun = true
|
||||
task.Execute = false
|
||||
|
||||
result, err := ghost.RunGhOst(c.Request.Context(), task, config.C.GhOstPath)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, result)
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, result)
|
||||
}
|
||||
|
||||
// POST /api/v1/ghost/execute
|
||||
func GhOstExecute(c *gin.Context) {
|
||||
var task ghost.GhOstTask
|
||||
if err := c.ShouldBindJSON(&task); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"detail": err.Error()})
|
||||
return
|
||||
}
|
||||
task.DryRun = false
|
||||
task.Execute = true
|
||||
|
||||
taskID := ghost.RunGhOstAsync(task, config.C.GhOstPath, nil)
|
||||
c.JSON(http.StatusAccepted, gin.H{
|
||||
"task_id": taskID,
|
||||
"message": "gh-ost execution started",
|
||||
})
|
||||
}
|
||||
|
||||
// GET /api/v1/ghost/status/:taskId
|
||||
func GhOstStatus(c *gin.Context) {
|
||||
taskID := c.Param("taskId")
|
||||
status, result := ghost.Manager.GetTaskStatus(taskID)
|
||||
if status == "" {
|
||||
c.JSON(http.StatusNotFound, gin.H{"detail": "Task not found"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"task_id": taskID,
|
||||
"status": status,
|
||||
"result": result,
|
||||
})
|
||||
}
|
||||
|
||||
// GET /api/v1/ghost/tasks
|
||||
func GhOstListTasks(c *gin.Context) {
|
||||
tasks := ghost.Manager.ListTasks()
|
||||
c.JSON(http.StatusOK, tasks)
|
||||
}
|
||||
|
||||
// GET /api/v1/audit-rules
|
||||
func ListAuditRules(c *gin.Context) {
|
||||
var rules []model.AuditRule
|
||||
model.DB.Order("id").Find(&rules)
|
||||
c.JSON(http.StatusOK, rules)
|
||||
}
|
||||
|
||||
// GET /api/v1/announcements
|
||||
func ListAnnouncements(c *gin.Context) {
|
||||
var announcements []model.Announcement
|
||||
model.DB.Where("is_published = ?", true).Order("id DESC").Find(&announcements)
|
||||
c.JSON(http.StatusOK, announcements)
|
||||
}
|
||||
|
||||
// GET /api/v1/query-histories
|
||||
func ListQueryHistories(c *gin.Context) {
|
||||
_, _, _ = c.GetInt("user_id"), c.GetString("username"), c.GetString("role")
|
||||
|
||||
var histories []model.QueryHistory
|
||||
model.DB.Order("id DESC").Limit(100).Find(&histories)
|
||||
c.JSON(http.StatusOK, histories)
|
||||
}
|
||||
|
||||
// GET /api/v1/settings
|
||||
func ListSettings(c *gin.Context) {
|
||||
var settings []model.SystemSetting
|
||||
model.DB.Order("sort_order").Find(&settings)
|
||||
c.JSON(http.StatusOK, settings)
|
||||
}
|
||||
|
||||
// GET /api/v1/notifications/channels
|
||||
func ListNotificationChannels(c *gin.Context) {
|
||||
var channels []model.NotificationChannel
|
||||
model.DB.Order("id").Find(&channels)
|
||||
c.JSON(http.StatusOK, channels)
|
||||
}
|
||||
|
||||
// GET /api/v1/notifications/templates
|
||||
func ListNotificationTemplates(c *gin.Context) {
|
||||
var templates []model.NotificationTemplate
|
||||
model.DB.Order("id").Find(&templates)
|
||||
c.JSON(http.StatusOK, templates)
|
||||
}
|
||||
|
||||
// GET /api/v1/workflows
|
||||
func ListWorkflows(c *gin.Context) {
|
||||
var workflows []model.WorkflowDefinition
|
||||
model.DB.Order("id").Find(&workflows)
|
||||
c.JSON(http.StatusOK, workflows)
|
||||
}
|
||||
|
||||
// GET /api/v1/instance-groups
|
||||
func ListInstanceGroups(c *gin.Context) {
|
||||
var groups []model.InstanceGroup
|
||||
model.DB.Order("id").Find(&groups)
|
||||
c.JSON(http.StatusOK, groups)
|
||||
}
|
||||
|
||||
// POST /api/v1/notifications/test
|
||||
func TestNotification(c *gin.Context) {
|
||||
_ = time.Now()
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Notification sent (placeholder)"})
|
||||
}
|
||||
Reference in new issue
Block a user