// 员工认证模块:提交认证申请、查询申请状态、撤回申请 package certification import ( "time" "com.sclktx/m/v2/internal/common/model" "com.sclktx/m/v2/internal/common/response" "com.sclktx/m/v2/internal/common/utils" "github.com/gin-gonic/gin" "gorm.io/gorm" ) // Handler 角色认证处理器 type Handler struct { db *gorm.DB } // NewHandler 创建角色认证处理器 func NewHandler(db *gorm.DB) *Handler { return &Handler{db: db} } // SubmitCertificationReq 提交认证申请请求 type SubmitCertificationReq struct { RealName string `json:"real_name" binding:"required"` Phone string `json:"phone" binding:"required"` Role string `json:"role" binding:"required"` Snapshot []string `json:"snapshot" binding:"required"` DepartmentID *uint `json:"department_id"` Position string `json:"position"` } // SubmitCertification 提交角色认证申请 // @Summary 提交角色认证申请 // @Description 提交员工角色认证申请,需上传钉钉截图 // @Tags 员工认证 // @Accept json // @Produce json // @Security BearerAuth // @Param body body SubmitCertificationReq true "认证申请请求" // @Success 200 {object} response.Response "success" // @Router /api/v1/certification/submit [post] func (h *Handler) SubmitCertification(c *gin.Context) { var req SubmitCertificationReq if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "参数错误: "+err.Error()) return } userID := utils.GetUserID(c) // 检查是否已有待审核或已通过的申请 var existing model.EmployeeCertification if err := h.db.Where("user_id = ? AND status IN (0, 1)", userID).First(&existing).Error; err == nil { if existing.Status == 1 { response.BadRequest(c, "您已通过认证,无需重复申请") return } response.BadRequest(c, "您已提交申请,请等待审核") return } cert := model.EmployeeCertification{ UserID: userID, RealName: req.RealName, Phone: req.Phone, Role: req.Role, Snapshot: req.Snapshot, Position: req.Position, DepartmentID: req.DepartmentID, Status: 0, } if err := h.db.Create(&cert).Error; err != nil { response.InternalError(c, "提交失败: "+err.Error()) return } response.SuccessWithMessage(c, "提交成功,请等待管理员审核", cert) } // GetMyCertification 获取我的认证申请 // @Summary 获取我的认证申请 // @Description 获取当前用户的角色认证申请状态 // @Tags 员工认证 // @Accept json // @Produce json // @Security BearerAuth // @Success 200 {object} response.Response "success" // @Router /api/v1/certification/my [get] func (h *Handler) GetMyCertification(c *gin.Context) { userID := utils.GetUserID(c) var cert model.EmployeeCertification if err := h.db.Preload("Department").Preload("Approver").Where("user_id = ?", userID).Order("created_at DESC").First(&cert).Error; err != nil { response.Success(c, nil) return } response.Success(c, cert) } // WithdrawCertification 撤回认证申请 // @Summary 撤回认证申请 // @Description 撤回已提交但尚未处理的认证申请 // @Tags 员工认证 // @Accept json // @Produce json // @Security BearerAuth // @Param id path uint true "认证申请ID" // @Success 200 {object} response.Response "success" // @Router /api/v1/certification/{id}/withdraw [put] func (h *Handler) WithdrawCertification(c *gin.Context) { userID := utils.GetUserID(c) certID := c.Param("id") var cert model.EmployeeCertification if err := h.db.First(&cert, certID).Error; err != nil { response.NotFound(c, "申请不存在") return } if cert.UserID != userID { response.Forbidden(c, "无权操作") return } if cert.Status != 0 { response.BadRequest(c, "该申请已处理,无法撤回") return } if err := h.db.Delete(&cert).Error; err != nil { response.InternalError(c, "撤回失败") return } response.SuccessWithMessage(c, "已撤回", nil) } // AutoVerifyReq 自动认证请求 type AutoVerifyReq struct { RealName string `json:"real_name" binding:"required"` Phone string `json:"phone" binding:"required"` } // AutoVerify 自动认证:姓名+手机号 → 匹配 pending_employees → 直接认证为员工 // @Summary 自动认证为员工 // @Description 输入姓名和手机号,系统自动匹配通讯录导入数据,匹配成功直接认证为员工 // @Tags 员工认证 // @Accept json // @Produce json // @Security BearerAuth // @Param body body AutoVerifyReq true "认证请求" // @Success 200 {object} response.Response "success" // @Router /api/v1/certification/auto-verify [post] func (h *Handler) AutoVerify(c *gin.Context) { var req AutoVerifyReq if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "请输入姓名和手机号") return } userID := utils.GetUserID(c) // 查当前用户角色 var user model.User if err := h.db.First(&user, userID).Error; err != nil { response.InternalError(c, "用户不存在") return } if user.Role == "employee" { response.BadRequest(c, "您已经是认证员工,无需重复申请") return } // 查找 pending_employees var pending model.PendingEmployee if err := h.db.Where("phone = ?", req.Phone).First(&pending).Error; err != nil { response.BadRequest(c, "未找到您的认证信息,请联系管理员导入通讯录") return } // 检查是否已被其他用户匹配 if pending.IsMatched { if pending.MatchedUserID != nil && *pending.MatchedUserID == userID { // 已匹配当前用户但角色尚未升级 → 修复 if user.Role != "employee" { goto doMatch } response.BadRequest(c, "您已认证成为员工,如有问题请联系管理员") } else { response.BadRequest(c, "该手机号已被其他用户认证,如有问题请联系管理员") } return } doMatch: // 执行认证 now := time.Now() ud := model.UserDepartment{ UserID: userID, DepartmentID: pending.DepartmentID, DepartmentName: pending.DepartmentName, Position: pending.Position, EmployeeType: pending.EmployeeType, EmployeeStatus: 1, } h.db.Where("user_id = ?", userID).Assign(ud).FirstOrCreate(&model.UserDepartment{UserID: userID}) h.db.Model(&user).Update("role", "employee") h.db.Model(&pending).Updates(map[string]interface{}{ "is_matched": true, "matched_user_id": &userID, "matched_at": &now, }) // 如果用户还没有真实姓名,同步填入 if user.RealName == "" { h.db.Model(&user).Update("real_name", req.RealName) } response.SuccessWithMessage(c, "认证成功", gin.H{ "department_name": pending.DepartmentName, "position": pending.Position, }) } // RegisterRoutes 注册认证路由(需要 JWT 认证) func (h *Handler) RegisterRoutes(r *gin.RouterGroup) { r.POST("/certification/submit", h.SubmitCertification) r.GET("/certification/my", h.GetMyCertification) r.PUT("/certification/:id/withdraw", h.WithdrawCertification) r.POST("/certification/auto-verify", h.AutoVerify) }