package handlers import ( "net/http" "strconv" "github.com/ctwj/urldb/db/converter" "github.com/ctwj/urldb/db/dto" "github.com/ctwj/urldb/db/entity" "github.com/ctwj/urldb/utils" "github.com/gin-gonic/gin" ) // GetTags 获取标签列表 func GetTags(c *gin.Context) { // 获取分页参数 page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20")) search := c.Query("search") var tags []entity.Tag var total int64 var err error if search != "" { // 搜索标签(按资源数量排序) tags, total, err = repoManager.TagRepository.SearchOrderByResourceCount(search, page, pageSize) } else { // 分页查询(按资源数量排序) tags, total, err = repoManager.TagRepository.FindWithPaginationOrderByResourceCount(page, pageSize) } if err != nil { ErrorResponse(c, err.Error(), http.StatusInternalServerError) return } // 获取每个标签的资源数量 resourceCounts := make(map[uint]int64) for _, tag := range tags { count, err := repoManager.TagRepository.GetResourceCount(tag.ID) if err != nil { continue } resourceCounts[tag.ID] = count } responses := converter.ToTagResponseList(tags, resourceCounts) // 返回分页格式的响应 SuccessResponse(c, gin.H{ "items": responses, "total": total, "page": page, "page_size": pageSize, }) } // CreateTag 创建标签 func CreateTag(c *gin.Context) { var req dto.CreateTagRequest if err := c.ShouldBindJSON(&req); err != nil { ErrorResponse(c, err.Error(), http.StatusBadRequest) return } // 首先检查是否存在已删除的同名标签 deletedTag, err := repoManager.TagRepository.FindByNameIncludingDeleted(req.Name) if err == nil && deletedTag.DeletedAt.Valid { // 如果存在已删除的同名标签,则恢复它 err = repoManager.TagRepository.RestoreDeletedTag(deletedTag.ID) if err != nil { ErrorResponse(c, "恢复已删除标签失败: "+err.Error(), http.StatusInternalServerError) return } // 重新获取恢复后的标签 restoredTag, err := repoManager.TagRepository.FindByID(deletedTag.ID) if err != nil { ErrorResponse(c, "获取恢复的标签失败: "+err.Error(), http.StatusInternalServerError) return } // 更新标签信息 restoredTag.Description = req.Description restoredTag.CategoryID = req.CategoryID err = repoManager.TagRepository.UpdateWithNulls(restoredTag) if err != nil { ErrorResponse(c, "更新恢复的标签失败: "+err.Error(), http.StatusInternalServerError) return } SuccessResponse(c, gin.H{ "message": "标签恢复成功", "tag": converter.ToTagResponse(restoredTag, 0), }) return } // 如果不存在已删除的同名标签,则创建新标签 tag := &entity.Tag{ Name: req.Name, Description: req.Description, CategoryID: req.CategoryID, } err = repoManager.TagRepository.Create(tag) if err != nil { ErrorResponse(c, err.Error(), http.StatusInternalServerError) return } SuccessResponse(c, gin.H{ "message": "标签创建成功", "tag": converter.ToTagResponse(tag, 0), }) } // GetTagByID 根据ID获取标签详情 func GetTagByID(c *gin.Context) { idStr := c.Param("id") id, err := strconv.ParseUint(idStr, 10, 32) if err != nil { ErrorResponse(c, "无效的ID", http.StatusBadRequest) return } tag, err := repoManager.TagRepository.FindByID(uint(id)) if err != nil { ErrorResponse(c, "标签不存在", http.StatusNotFound) return } // 获取资源数量 resourceCount, _ := repoManager.TagRepository.GetResourceCount(tag.ID) response := converter.ToTagResponse(tag, resourceCount) SuccessResponse(c, response) } // UpdateTag 更新标签 func UpdateTag(c *gin.Context) { idStr := c.Param("id") id, err := strconv.ParseUint(idStr, 10, 32) if err != nil { ErrorResponse(c, "无效的ID", http.StatusBadRequest) return } var req dto.UpdateTagRequest if err := c.ShouldBindJSON(&req); err != nil { ErrorResponse(c, err.Error(), http.StatusBadRequest) return } tag, err := repoManager.TagRepository.FindByID(uint(id)) if err != nil { ErrorResponse(c, "标签不存在", http.StatusNotFound) return } // 添加调试信息 utils.Debug("更新标签 - ID: %d, 请求CategoryID: %v, 当前CategoryID: %v", id, req.CategoryID, tag.CategoryID) if req.Name != "" { tag.Name = req.Name } if req.Description != "" { tag.Description = req.Description } // 处理CategoryID,包括设置为null的情况 tag.CategoryID = req.CategoryID // 添加调试信息 utils.Debug("更新后CategoryID: %v", tag.CategoryID) // 使用专门的更新方法,确保能更新null值 err = repoManager.TagRepository.UpdateWithNulls(tag) if err != nil { ErrorResponse(c, err.Error(), http.StatusInternalServerError) return } SuccessResponse(c, gin.H{"message": "标签更新成功"}) } // DeleteTag 删除标签 func DeleteTag(c *gin.Context) { idStr := c.Param("id") id, err := strconv.ParseUint(idStr, 10, 32) if err != nil { ErrorResponse(c, "无效的ID", http.StatusBadRequest) return } err = repoManager.TagRepository.Delete(uint(id)) if err != nil { ErrorResponse(c, err.Error(), http.StatusInternalServerError) return } SuccessResponse(c, gin.H{"message": "标签删除成功"}) } // GetTagByID 根据ID获取标签详情(使用全局repoManager) func GetTagByIDGlobal(c *gin.Context) { idStr := c.Param("id") id, err := strconv.ParseUint(idStr, 10, 32) if err != nil { ErrorResponse(c, "无效的ID", http.StatusBadRequest) return } tag, err := repoManager.TagRepository.FindByID(uint(id)) if err != nil { ErrorResponse(c, "标签不存在", http.StatusNotFound) return } // 获取资源数量 resourceCount, _ := repoManager.TagRepository.GetResourceCount(tag.ID) response := converter.ToTagResponse(tag, resourceCount) SuccessResponse(c, response) } // GetTags 获取标签列表(使用全局repoManager) func GetTagsGlobal(c *gin.Context) { tags, err := repoManager.TagRepository.FindAll() if err != nil { ErrorResponse(c, err.Error(), http.StatusInternalServerError) return } // 获取每个标签的资源数量 resourceCounts := make(map[uint]int64) for _, tag := range tags { count, err := repoManager.TagRepository.GetResourceCount(tag.ID) if err != nil { continue } resourceCounts[tag.ID] = count } responses := converter.ToTagResponseList(tags, resourceCounts) SuccessResponse(c, responses) } // GetTagsByCategory 根据分类ID获取标签列表 func GetTagsByCategory(c *gin.Context) { categoryIDStr := c.Param("categoryId") categoryID, err := strconv.ParseUint(categoryIDStr, 10, 32) if err != nil { ErrorResponse(c, "无效的分类ID", http.StatusBadRequest) return } // 获取分页参数 page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20")) tags, total, err := repoManager.TagRepository.FindByCategoryIDPaginated(uint(categoryID), page, pageSize) if err != nil { ErrorResponse(c, err.Error(), http.StatusInternalServerError) return } // 获取每个标签的资源数量 resourceCounts := make(map[uint]int64) for _, tag := range tags { count, err := repoManager.TagRepository.GetResourceCount(tag.ID) if err != nil { continue } resourceCounts[tag.ID] = count } responses := converter.ToTagResponseList(tags, resourceCounts) // 返回分页格式的响应 SuccessResponse(c, gin.H{ "items": responses, "total": total, "page": page, "page_size": pageSize, }) }