diff --git a/backend/internal/handler/ticket.go b/backend/internal/handler/ticket.go index f017ceb..08c7f5b 100644 --- a/backend/internal/handler/ticket.go +++ b/backend/internal/handler/ticket.go @@ -217,6 +217,14 @@ func CreateTicket(c *gin.Context) { c.JSON(http.StatusBadRequest, gin.H{"detail": err.Error()}) return } + + // Auto-fill workflow_id from instance if not provided + if input.WorkflowID == nil || *input.WorkflowID == 0 { + var inst model.Instance + if model.DB.First(&inst, input.InstanceID).Error == nil && inst.WorkflowID != nil { + input.WorkflowID = inst.WorkflowID + } + } status := "pending" priority := "medium" @@ -348,14 +356,20 @@ func CreateTicket(c *gin.Context) { // POST /api/v1/tickets/:id/approve func ApproveTicket(c *gin.Context) { id := c.Param("id") - userID, _, _ := middleware.GetCurrentUser(c) - + userID, userRole, _ := middleware.GetCurrentUser(c) + + // Role check: only admin/dba/auditor can approve + if userRole != "admin" && userRole != "dba" && userRole != "auditor" { + c.JSON(http.StatusForbidden, gin.H{"detail": "权限不足:审核操作需要管理员、DBA 或审核员角色"}) + return + } + var ticket model.Ticket if err := model.DB.First(&ticket, id).Error; err != nil { c.JSON(http.StatusNotFound, gin.H{"detail": "Ticket not found"}) return } - + var input struct { Action string `json:"action" binding:"required"` // approve, reject Comment *string `json:"comment"` @@ -364,31 +378,25 @@ func ApproveTicket(c *gin.Context) { c.JSON(http.StatusBadRequest, gin.H{"detail": err.Error()}) return } - + now := time.Now() - + // Update approval record — auto-create if missing (legacy tickets) var approval model.TicketApproval if err := model.DB.Where("ticket_id = ? AND approver_id = ? AND action IS NULL", id, userID).First(&approval).Error; err != nil { - // No approval record — check if user is authorized to review - _, userRole, _ := middleware.GetCurrentUser(c) - if userRole == "admin" || userRole == "dba" { - stepName := "审核" - stepType := "audit" - approverRole := userRole - approval = model.TicketApproval{ - TicketID: ticket.ID, - StepNumber: 1, - StepName: &stepName, - StepType: &stepType, - ApproverID: &userID, - ApproverRole: &approverRole, - } - model.DB.Create(&approval) - } else { - c.JSON(http.StatusBadRequest, gin.H{"detail": "No pending approval for you"}) - return + // No approval record — authorized role can create one + stepName := "审核" + stepType := "audit" + approverRole := userRole + approval = model.TicketApproval{ + TicketID: ticket.ID, + StepNumber: 1, + StepName: &stepName, + StepType: &stepType, + ApproverID: &userID, + ApproverRole: &approverRole, } + model.DB.Create(&approval) } approval.Action = &input.Action @@ -420,7 +428,14 @@ func ApproveTicket(c *gin.Context) { // POST /api/v1/tickets/:id/execute func ExecuteTicket(c *gin.Context) { id := c.Param("id") - + + // Role check: only admin/dba can execute + _, userRole, _ := middleware.GetCurrentUser(c) + if userRole != "admin" && userRole != "dba" { + c.JSON(http.StatusForbidden, gin.H{"detail": "权限不足:执行操作需要管理员或 DBA 角色"}) + return + } + var ticket model.Ticket if err := model.DB.First(&ticket, id).Error; err != nil { c.JSON(http.StatusNotFound, gin.H{"detail": "Ticket not found"}) diff --git a/frontend/src/pages/UsersPage.tsx b/frontend/src/pages/UsersPage.tsx index d7e16f7..5087b78 100644 --- a/frontend/src/pages/UsersPage.tsx +++ b/frontend/src/pages/UsersPage.tsx @@ -487,9 +487,10 @@ export default function UsersPage() {