package handler import ( "net/http" "strconv" "time" "git.zkcoi.com/zkcoi/Meshray-Manager/internal/model" "git.zkcoi.com/zkcoi/Meshray-Manager/internal/service" sqlite "git.zkcoi.com/zkcoi/Meshray-Manager/internal/store/sqlite" "github.com/gin-gonic/gin" "go.uber.org/zap" ) // PendingJoinHandler 待审核 Handler type PendingJoinHandler struct { service *service.PendingJoinService store *sqlite.Store // ← 新增 logger *zap.Logger } // NewPendingJoinHandler 创建待审核 Handler func NewPendingJoinHandler(service *service.PendingJoinService, store *sqlite.Store, logger *zap.Logger) *PendingJoinHandler { return &PendingJoinHandler{ service: service, store: store, // ← 新增 logger: logger, } } // ListPendingJoins 获取待审核列表 func (h *PendingJoinHandler) ListPendingJoins(c *gin.Context) { // 获取查询参数 networkIDStr := c.DefaultQuery("network_id", "0") status := c.DefaultQuery("status", "pending") pageStr := c.DefaultQuery("page", "1") sizeStr := c.DefaultQuery("size", "20") // 转换参数 networkID, _ := strconv.ParseUint(networkIDStr, 10, 32) page, _ := strconv.Atoi(pageStr) size, _ := strconv.Atoi(sizeStr) if page < 1 { page = 1 } if size < 1 || size > 100 { size = 20 } // 调用 Service list, total, err := h.service.ListPendingJoins(uint(networkID), status, page, size) if err != nil { h.logger.Error("获取待审核列表失败", zap.Error(err)) c.JSON(http.StatusInternalServerError, gin.H{"error": "获取失败"}) return } // 转换为响应格式 type ResponseItem struct { ID uint `json:"id"` SeedID string `json:"seed_id"` DeviceName string `json:"device_name"` RequestIP string `json:"request_ip"` Status string `json:"status"` ExpireAt string `json:"expire_at"` ApprovedAt string `json:"approved_at"` RejectedAt string `json:"rejected_at"` Reason string `json:"reason"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` NetworkID uint `json:"network_id"` NetworkName string `json:"network_name"` ApplicantIP string `json:"applicant_ip"` ApplyTime string `json:"apply_time"` Message string `json:"message"` } var responseList []ResponseItem for _, item := range list { // 通过 SeedID 关联查询 MeshSeed 获取 NetworkID var meshSeed model.MeshSeed networkName := "未知网络" networkID := uint(0) if err := h.store.DB().Where("seed_id = ?", item.SeedID).First(&meshSeed).Error; err == nil { // 查询网络信息 var network model.Network if err := h.store.DB().Where("id = ?", meshSeed.NetworkID).First(&network).Error; err == nil { networkName = network.Name networkID = uint(network.ID) } } responseList = append(responseList, ResponseItem{ ID: item.ID, SeedID: item.SeedID, DeviceName: item.DeviceName, RequestIP: item.RequestIP, Status: item.Status, ExpireAt: item.ExpireAt.Format("2006-01-02 15:04:05"), ApprovedAt: formatTime(item.ApprovedAt), RejectedAt: formatTime(item.RejectedAt), Reason: item.Reason, CreatedAt: item.CreatedAt.Format("2006-01-02 15:04:05"), UpdatedAt: item.UpdatedAt.Format("2006-01-02 15:04:05"), NetworkID: networkID, NetworkName: networkName, ApplicantIP: item.RequestIP, ApplyTime: item.CreatedAt.Format("2006-01-02 15:04:05"), Message: "", }) } c.JSON(http.StatusOK, gin.H{ "data": gin.H{ "list": responseList, "total": total, }, }) } // ApproveJoin 审核通过 func (h *PendingJoinHandler) ApproveJoin(c *gin.Context) { idStr := c.Param("id") id, _ := strconv.ParseUint(idStr, 10, 32) result, err := h.service.ApproveJoin(uint(id)) if err != nil { h.logger.Error("审核通过失败", zap.Error(err)) c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // 返回完整配置给前端 h.logger.Info("审核通过成功", zap.Uint64("id", uint64(id)), zap.String("device_name", result.Device.Name), zap.String("device_ip", result.Device.VirtualIP)) c.JSON(http.StatusOK, gin.H{ "message": "审核通过", "data": gin.H{ "device": result.Device, "private_key": result.PrivateKey, "network": result.Network, "wireguard_config": result.ConfigText, }, }) } // RejectJoin 审核拒绝 func (h *PendingJoinHandler) RejectJoin(c *gin.Context) { idStr := c.Param("id") id, _ := strconv.ParseUint(idStr, 10, 32) var req struct { Reason string `json:"reason"` } if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "参数错误"}) return } if err := h.service.RejectJoin(uint(id), req.Reason); err != nil { h.logger.Error("审核拒绝失败", zap.Error(err)) c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"message": "已拒绝"}) } // CountPending 统计待审核数量 func (h *PendingJoinHandler) CountPending(c *gin.Context) { count, err := h.service.CountPending() if err != nil { h.logger.Error("统计待审核数量失败", zap.Error(err)) c.JSON(http.StatusInternalServerError, gin.H{"error": "统计失败"}) return } c.JSON(http.StatusOK, gin.H{ "data": gin.H{ "count": count, }, }) } // DeleteExpired 清理过期记录 func (h *PendingJoinHandler) DeleteExpired(c *gin.Context) { if err := h.service.DeleteExpired(); err != nil { h.logger.Error("清理过期记录失败", zap.Error(err)) c.JSON(http.StatusInternalServerError, gin.H{"error": "清理失败"}) return } c.JSON(http.StatusOK, gin.H{"message": "清理完成"}) } func formatTime(t *time.Time) string { if t == nil { return "" } return t.Format("2006-01-02 15:04:05") }