Files
sc-lktx-mp/sc-lktx-backend/internal/modules/certification/handler.go
huangjin fe3ad20fe2 'init'
2026-06-29 17:34:59 +08:00

237 lines
7.1 KiB
Go

// 员工认证模块:提交认证申请、查询申请状态、撤回申请
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)
}