package controller import ( "encoding/json" "net/http" "strconv" "time" "ezops/model" "github.com/gin-gonic/gin" "gorm.io/gorm" ) type flowStep struct { Name string `json:"name"` ApproverRole string `json:"approver_role"` StepType string `json:"step_type"` // audit, execute } // ListProcesses 获取审批流程列表 // Logan.Li func (h *ApprovalHandler) ListProcesses(c *gin.Context) { var query model.PageQuery c.ShouldBindQuery(&query) db := h.db.Model(&model.ApprovalProcess{}). Preload("Template"). Preload("ApplicantUser"). Preload("Steps", func(db *gorm.DB) *gorm.DB { return db.Order("step ASC") }) if status := c.Query("status"); status != "" { db = db.Where("status = ?", status) } if category := c.Query("category"); category != "" { db = db.Joins("JOIN sys_approval_templates ON sys_approval_templates.id = approval_processes.template_id"). Where("sys_approval_templates.category = ?", category) } var total int64 db.Count(&total) var processes []model.ApprovalProcess db.Order("created_at DESC").Offset(query.GetOffset()).Limit(query.GetLimit()).Find(&processes) // Preload approver user for each step for i := range processes { for j := range processes[i].Steps { h.db.Preload("ApproverUser").First(&processes[i].Steps[j], processes[i].Steps[j].ID) } } c.JSON(http.StatusOK, model.Response{ Code: 200, Message: "success", Data: model.ListResponse{ List: processes, Total: total, }, }) } // GetProcess 获取审批流程详情 // Logan.Li func (h *ApprovalHandler) GetProcess(c *gin.Context) { id, _ := strconv.Atoi(c.Param("id")) var process model.ApprovalProcess if err := h.db.Preload("Template").Preload("ApplicantUser"). Preload("Steps.ApproverUser").Preload("Steps", func(db *gorm.DB) *gorm.DB { return db.Order("step ASC") }).First(&process, id).Error; err != nil { c.JSON(http.StatusNotFound, model.Response{ Code: 404, Message: "流程不存在", }) return } c.JSON(http.StatusOK, model.Response{ Code: 200, Message: "success", Data: process, }) } // CreateProcess 创建审批流程 — 使用审批流程配置 (sys_approval_workflows) // Logan.Li func (h *ApprovalHandler) CreateProcess(c *gin.Context) { var req model.CreateApprovalProcessRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, model.Response{ Code: 400, Message: "请求参数错误: " + err.Error(), }) return } userIDVal, _ := c.Get("userID") userID := toUint(userIDVal) var template model.ApprovalTemplate if err := h.db.First(&template, req.TemplateID).Error; err != nil { c.JSON(http.StatusNotFound, model.Response{Code: 404, Message: "模板不存在"}) return } // 查找该分类下的默认/活跃审批流程配置 var workflow model.ApprovalWorkflow if err := h.db.Where("category = ? AND is_active = ?", template.Category, true). Order("is_default DESC").First(&workflow).Error; err != nil { // 无工作流配置,回退到模板 flow_config } // 获取工作流步骤(跳过 submit 类型) var workflowSteps []model.ApprovalWorkflowStep stepCount := 1 var approvalSteps []struct { name string stepType string approverIDs []uint } if workflow.ID > 0 { h.db.Where("workflow_id = ?", workflow.ID).Order("step_number ASC").Find(&workflowSteps) for _, ws := range workflowSteps { if ws.StepType == "submit" { continue // 提交步骤由申请人完成,不生成审批节点 } stepCount++ approvalSteps = append(approvalSteps, struct { name string stepType string approverIDs []uint }{ws.Name, ws.StepType, ParseApproverIDs(ws.ApproverIDs)}) } } totalSteps := len(approvalSteps) if totalSteps == 0 { totalSteps = 1 } process := model.ApprovalProcess{ TemplateID: req.TemplateID, Title: req.Title, Applicant: userID, FormData: req.FormData, Status: "pending", CurrentStep: 1, TotalSteps: totalSteps, } tx := h.db.Begin() if err := tx.Create(&process).Error; err != nil { tx.Rollback() c.JSON(http.StatusInternalServerError, model.Response{Code: 500, Message: "创建失败: " + err.Error()}) return } // 创建审批步骤(仅 audit + execute) for i, as := range approvalSteps { stepType := as.stepType if stepType == "" { // 最后一步默认执行,其余审核 if i == len(approvalSteps)-1 { stepType = "execute" } else { stepType = "audit" } } approverID := uint(1) // 默认管理员 if len(as.approverIDs) > 0 { approverID = as.approverIDs[0] } step := model.ApprovalStep{ ProcessID: process.ID, Step: i + 1, StepType: stepType, Approver: approverID, Status: "pending", Comment: as.name, // 存步骤名称 } if err := tx.Create(&step).Error; err != nil { tx.Rollback() c.JSON(http.StatusInternalServerError, model.Response{Code: 500, Message: "创建步骤失败"}) return } } tx.Commit() // 重新加载完整数据 h.db.Preload("Template").Preload("ApplicantUser").Preload("Steps.ApproverUser").First(&process, process.ID) c.JSON(http.StatusOK, model.Response{ Code: 200, Message: "申请已提交", Data: process, }) } // ParseApproverIDs 解析审批人JSON数组 func ParseApproverIDs(raw string) []uint { if raw == "" { return nil } var ids []uint if err := json.Unmarshal([]byte(raw), &ids); err != nil { return nil } return ids } func toUint(v interface{}) uint { switch val := v.(type) { case float64: return uint(val) case uint: return val case int: return uint(val) default: return 0 } } // ApproveProcess 审批通过 // Logan.Li func (h *ApprovalHandler) ApproveProcess(c *gin.Context) { id, _ := strconv.Atoi(c.Param("id")) var req model.ApproveRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, model.Response{Code: 400, Message: "请求参数错误"}) return } userIDVal, _ := c.Get("userID") approverID := toUint(userIDVal) var process model.ApprovalProcess if err := h.db.First(&process, id).Error; err != nil { c.JSON(http.StatusNotFound, model.Response{Code: 404, Message: "流程不存在"}) return } if process.Status != "pending" { c.JSON(http.StatusBadRequest, model.Response{Code: 400, Message: "该申请已处理"}) return } now := time.Now() // 查找当前步骤 var currentStep model.ApprovalStep if err := h.db.Where("process_id = ? AND step = ?", process.ID, process.CurrentStep).First(¤tStep).Error; err != nil { // 无步骤记录(旧数据兼容):直接通过 h.db.Model(&process).Updates(map[string]interface{}{ "status": "approved", "approved_at": &now, }) h.db.Preload("Template").Preload("ApplicantUser").Preload("Steps.ApproverUser").First(&process, process.ID) c.JSON(http.StatusOK, model.Response{Code: 200, Message: "审批通过", Data: process}) return } tx := h.db.Begin() // 更新当前步骤为通过 tx.Model(¤tStep).Updates(map[string]interface{}{ "status": "approved", "approver": approverID, "comment": req.Comment, "approved_at": &now, }) // 推进到下一步 或 标记全部通过 if process.CurrentStep >= process.TotalSteps { tx.Model(&process).Updates(map[string]interface{}{ "status": "approved", "approved_at": &now, }) } else { tx.Model(&process).Update("current_step", process.CurrentStep+1) } tx.Commit() h.db.Preload("Template").Preload("ApplicantUser").Preload("Steps.ApproverUser").First(&process, process.ID) c.JSON(http.StatusOK, model.Response{ Code: 200, Message: "审批通过", Data: process, }) } // RejectProcess 审批拒绝 // Logan.Li func (h *ApprovalHandler) RejectProcess(c *gin.Context) { id, _ := strconv.Atoi(c.Param("id")) var req model.ApproveRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, model.Response{Code: 400, Message: "请求参数错误"}) return } userIDVal, _ := c.Get("userID") approverID := toUint(userIDVal) var process model.ApprovalProcess if err := h.db.First(&process, id).Error; err != nil { c.JSON(http.StatusNotFound, model.Response{Code: 404, Message: "流程不存在"}) return } if process.Status != "pending" { c.JSON(http.StatusBadRequest, model.Response{Code: 400, Message: "该申请已处理"}) return } now := time.Now() tx := h.db.Begin() // 更新当前步骤为拒绝 tx.Model(&model.ApprovalStep{}).Where("process_id = ? AND step = ?", process.ID, process.CurrentStep). Updates(map[string]interface{}{ "status": "rejected", "approver": approverID, "comment": req.Comment, "approved_at": &now, }) tx.Model(&process).Updates(map[string]interface{}{ "status": "rejected", "rejected_at": &now, "reject_reason": req.Comment, }) tx.Commit() h.db.Preload("Template").Preload("ApplicantUser").Preload("Steps.ApproverUser").First(&process, process.ID) c.JSON(http.StatusOK, model.Response{ Code: 200, Message: "已拒绝", Data: process, }) }