Files
Mycontent/soul-api/internal/handler/admin_super_articles.go
乘风 99d65dc664 feat: add super article management features and enhance UI
- Introduced a new page for managing user-specific articles, allowing users to view and edit their submissions.
- Implemented article audit status handling, including visual indicators for pending, approved, and rejected articles.
- Enhanced the article detail view with audit feedback and editing capabilities for articles in pending or rejected states.
- Updated the UI to dynamically reflect ownership and article status, improving user experience and clarity.

This update aims to streamline article management for users and provide better feedback on article submission statuses.
2026-05-09 17:49:45 +08:00

130 lines
3.5 KiB
Go

package handler
import (
"net/http"
"strconv"
"strings"
"soul-api/internal/database"
"soul-api/internal/model"
"github.com/gin-gonic/gin"
)
// AdminSuperArticlesList GET /api/admin/super-articles?status=pending|approved|rejected|all&page=&pageSize=
func AdminSuperArticlesList(c *gin.Context) {
status := strings.TrimSpace(strings.ToLower(c.Query("status")))
if status == "" {
status = "pending"
}
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("pageSize", "20"))
if page < 1 {
page = 1
}
if pageSize < 1 || pageSize > 100 {
pageSize = 20
}
db := database.DB()
q := db.Model(&model.SuperArticle{})
if status != "all" {
q = q.Where("audit_status = ?", status)
}
var total int64
if err := q.Count(&total).Error; err != nil {
c.JSON(http.StatusOK, gin.H{"success": false, "error": err.Error()})
return
}
var rows []model.SuperArticle
if err := q.Order("updated_at DESC").
Offset((page - 1) * pageSize).
Limit(pageSize).
Find(&rows).Error; err != nil {
c.JSON(http.StatusOK, gin.H{"success": false, "error": err.Error()})
return
}
idSet := map[string]bool{}
var uids []string
for _, r := range rows {
u := strings.TrimSpace(r.UserID)
if u == "" || idSet[u] {
continue
}
idSet[u] = true
uids = append(uids, u)
}
authorMap := loadSuperArticleAuthorMap(uids)
list := make([]gin.H, 0, len(rows))
for _, r := range rows {
a := authorMap[strings.TrimSpace(r.UserID)]
list = append(list, gin.H{
"id": r.ID,
"userId": r.UserID,
"title": r.Title,
"content": r.Content,
"images": parseSuperArticleImagesJSON(r.Images),
"auditStatus": strings.TrimSpace(r.AuditStatus),
"rejectReason": strings.TrimSpace(r.RejectReason),
"authorNickname": strings.TrimSpace(a.Nickname),
"authorAvatar": strings.TrimSpace(a.Avatar),
"createdAt": r.CreatedAt,
"updatedAt": r.UpdatedAt,
})
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"list": list,
"total": total,
"page": page,
"pageSize": pageSize,
})
}
// AdminSuperArticleReview PUT /api/admin/super-articles/:id/review
// body: { "action": "approve" | "reject", "rejectReason": "..." }
func AdminSuperArticleReview(c *gin.Context) {
idRaw := strings.TrimSpace(c.Param("id"))
id, err := strconv.ParseUint(idRaw, 10, 64)
if err != nil || id == 0 {
c.JSON(http.StatusOK, gin.H{"success": false, "error": "参数错误"})
return
}
var req struct {
Action string `json:"action"`
RejectReason string `json:"rejectReason"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusOK, gin.H{"success": false, "error": "参数错误"})
return
}
act := strings.TrimSpace(strings.ToLower(req.Action))
if act != "approve" && act != "reject" {
c.JSON(http.StatusOK, gin.H{"success": false, "error": "action 须为 approve 或 reject"})
return
}
db := database.DB()
var row model.SuperArticle
if err := db.First(&row, id).Error; err != nil {
c.JSON(http.StatusOK, gin.H{"success": false, "error": "记录不存在"})
return
}
if act == "approve" {
row.AuditStatus = model.SuperArticleAuditApproved
row.RejectReason = ""
} else {
row.AuditStatus = model.SuperArticleAuditRejected
row.RejectReason = strings.TrimSpace(req.RejectReason)
if row.RejectReason == "" {
row.RejectReason = "未填写原因"
}
}
if err := db.Save(&row).Error; err != nil {
c.JSON(http.StatusOK, gin.H{"success": false, "error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"success": true})
}