Răsfoiți Sursa

feat(article-center): add publish, my-posts, and audit endpoints

Sisyphus 4 luni în urmă
părinte
comite
079ecaedef

+ 20 - 0
cfc-backend/src/main/java/com/etotem/cfc/controller/admin/AdminArticleController.java

@@ -116,6 +116,26 @@ public class AdminArticleController {
         return Result.success("操作成功");
     }
 
+    @PostMapping("/audit")
+    public Result<String> audit(@RequestBody Map<String, Object> body,
+                                 @RequestAttribute("userId") Long adminId) {
+        Long articleId = Long.valueOf(body.get("id").toString());
+        String auditStatus = (String) body.get("auditStatus");
+        String auditReason = (String) body.get("auditReason");
+        if (!"approved".equals(auditStatus) && !"rejected".equals(auditStatus)) {
+            return Result.error("审核状态不正确");
+        }
+        if ("rejected".equals(auditStatus) && (auditReason == null || auditReason.trim().isEmpty())) {
+            return Result.error("驳回时必须填写原因");
+        }
+        try {
+            articleService.auditArticle(articleId, auditStatus, auditReason, adminId);
+            return Result.success("审核完成");
+        } catch (RuntimeException e) {
+            return Result.error(e.getMessage());
+        }
+    }
+
     @PostMapping("/upload/image")
     public Result<String> uploadImage(@RequestParam("file") MultipartFile file) {
         if (file.isEmpty()) {

+ 34 - 0
cfc-backend/src/main/java/com/etotem/cfc/controller/content/ArticleController.java

@@ -13,6 +13,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import org.springframework.web.bind.annotation.*;
 import javax.annotation.Resource;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -153,4 +154,37 @@ public class ArticleController {
             return Result.error(e.getMessage());
         }
     }
+
+    @PostMapping("/publish")
+    public Result<Map<String, Object>> publish(@RequestBody Map<String, Object> body,
+                                                @RequestAttribute("userId") Long userId,
+                                                @RequestAttribute("role") String role) {
+        String title = (String) body.get("title");
+        String content = (String) body.get("content");
+        String coverImage = (String) body.get("coverImage");
+        String visibility = (String) body.get("visibility");
+        String relatedDimensions = (String) body.get("relatedDimensions");
+
+        if (title == null || title.trim().isEmpty()) {
+            return Result.error("标题不能为空");
+        }
+        if (content == null || content.trim().isEmpty()) {
+            return Result.error("正文不能为空");
+        }
+
+        Article article = articleService.publishByUser(title, content, coverImage, visibility, relatedDimensions, userId, role);
+        Map<String, Object> result = new HashMap<>();
+        result.put("id", article.getId());
+        result.put("status", article.getStatus());
+        result.put("auditStatus", article.getAuditStatus());
+        return Result.success(result);
+    }
+
+    @PostMapping("/my-posts")
+    public Result<Page<Article>> myPosts(@RequestBody Map<String, Object> body,
+                                          @RequestAttribute("userId") Long userId) {
+        int page = body.get("page") != null ? Integer.parseInt(body.get("page").toString()) : 1;
+        int size = body.get("size") != null ? Integer.parseInt(body.get("size").toString()) : 20;
+        return Result.success(articleService.getMyPosts(userId, page, size));
+    }
 }

+ 74 - 0
cfc-backend/src/main/java/com/etotem/cfc/service/ArticleService.java

@@ -550,4 +550,78 @@ public class ArticleService {
         result.put("pointsEarned", pointsEarned);
         return result;
     }
+
+    /**
+     * 用户发布文章(成长记录)
+     * @param visibility private=仅家庭(直接发布), public=公开(需审核)
+     */
+    @Transactional
+    public Article publishByUser(String title, String content, String coverImage, String visibility,
+                                  String relatedDimensions, Long userId, String userRole) {
+        Article article = new Article();
+        article.setTitle(title);
+        article.setContent(content);
+        article.setCoverImage(coverImage);
+        article.setAuthorType("parent");
+        article.setCreatedBy(userId);
+        article.setWordCount(calculateWordCount(content));
+
+        // 可见范围
+        article.setVisibility(visibility != null ? visibility : "private");
+
+        // 关联维度
+        article.setRelatedDimensions(relatedDimensions);
+
+        // 公开文章需要审核,家庭内部可见直接发布
+        if ("public".equals(visibility)) {
+            article.setStatus("draft");
+            article.setAuditStatus("pending");
+        } else {
+            article.setStatus("published");
+            article.setAuditStatus("approved");
+            article.setPublishedAt(new Date());
+        }
+
+        article.setArticleType("original");
+        article.setViewCount(0);
+        article.setCreatedAt(new Date());
+        article.setUpdatedAt(new Date());
+        articleMapper.insert(article);
+        return article;
+    }
+
+    /**
+     * 获取我的发布列表
+     */
+    public Page<Article> getMyPosts(Long userId, int page, int size) {
+        LambdaQueryWrapper<Article> wrapper = new LambdaQueryWrapper<Article>()
+                .eq(Article::getCreatedBy, userId)
+                .in(Article::getAuthorType, "parent", "child")
+                .orderByDesc(Article::getCreatedAt);
+        return articleMapper.selectPage(new Page<>(page, size), wrapper);
+    }
+
+    /**
+     * 管理员审核文章
+     */
+    @Transactional
+    public void auditArticle(Long articleId, String auditStatus, String auditReason, Long auditorId) {
+        Article article = articleMapper.selectById(articleId);
+        if (article == null) {
+            throw new RuntimeException("文章不存在");
+        }
+        article.setAuditStatus(auditStatus);
+        article.setAuditorId(auditorId);
+        article.setAuditedAt(new Date());
+        if ("approved".equals(auditStatus)) {
+            article.setStatus("published");
+            article.setPublishedAt(new Date());
+            article.setAuditReason(null);
+        } else if ("rejected".equals(auditStatus)) {
+            article.setStatus("draft");
+            article.setAuditReason(auditReason);
+        }
+        article.setUpdatedAt(new Date());
+        articleMapper.updateById(article);
+    }
 }