# 文章与活动发布系统设计文档 **日期:** 2026-06-09 **状态:** 设计稿 v1 --- ## 1. 概述 在 浠艾福(CFC) 平台中新增文章和活动发布功能: - **文章**: 任何登录用户可发布,需运营审核后展示 - **活动**: 仅活动管理员可发布,无需审核 - **分类**: 独立分类体系 + 五维能量维度(body/mind/wisdom/action/wealth)关联 - **展示**: 微信小程序嵌入各页面的内容模块 --- ## 2. 架构选择 **方案 B**: 统一内容表 + 扩展表 - `contents` 表存储文章和活动的公共字段 - `activities_ext` 表存储活动的独有字段 - 文章独有字段少,直接放在 contents 表中 --- ## 3. 数据模型 ### 3.1 contents 表 — 统一内容基表 ```sql CREATE TABLE IF NOT EXISTS contents ( id BIGINT AUTO_INCREMENT PRIMARY KEY, title VARCHAR(200) NOT NULL COMMENT '标题', summary VARCHAR(500) COMMENT '摘要', content TEXT COMMENT '富文本内容(HTML)', cover_image VARCHAR(500) COMMENT '封面图URL', type VARCHAR(20) NOT NULL COMMENT 'article/activity', category_id BIGINT COMMENT '分类ID', energy_dimension VARCHAR(20) COMMENT 'body/mind/wisdom/action/wealth', author_id BIGINT NOT NULL COMMENT '发布者用户ID', status VARCHAR(20) NOT NULL DEFAULT 'draft' COMMENT 'draft/pending/approved/rejected', reject_reason VARCHAR(500) COMMENT '驳回原因', view_count INT DEFAULT 0 COMMENT '浏览量', publish_time DATETIME COMMENT '发布时间', created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX idx_type_status (type, status), INDEX idx_energy_dimension (energy_dimension), INDEX idx_author_id (author_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='统一内容表'; ``` ### 3.2 activities_ext 表 — 活动扩展 ```sql CREATE TABLE IF NOT EXISTS activities_ext ( id BIGINT AUTO_INCREMENT PRIMARY KEY, content_id BIGINT NOT NULL UNIQUE COMMENT '关联contents.id', location VARCHAR(300) COMMENT '活动地点', start_time DATETIME COMMENT '开始时间', end_time DATETIME COMMENT '结束时间', max_participants INT COMMENT '最大参与人数', sign_up_deadline DATETIME COMMENT '报名截止时间', contact_phone VARCHAR(20) COMMENT '联系电话', created_at DATETIME DEFAULT CURRENT_TIMESTAMP, INDEX idx_start_time (start_time), FOREIGN KEY (content_id) REFERENCES contents(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='活动扩展信息'; ``` ### 3.3 content_categories 表 — 内容分类 ```sql CREATE TABLE IF NOT EXISTS content_categories ( id BIGINT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50) NOT NULL COMMENT '分类名称', energy_dimension VARCHAR(20) COMMENT '关联能量维度', sort_order INT DEFAULT 0 COMMENT '排序', type VARCHAR(20) NOT NULL COMMENT 'article/activity/both', status VARCHAR(20) DEFAULT 'active' COMMENT 'active/inactive', created_at DATETIME DEFAULT CURRENT_TIMESTAMP, INDEX idx_type (type), INDEX idx_energy_dimension (energy_dimension) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='内容分类'; ``` --- ## 4. 后端 API ### 4.1 文章 API (`controller/article/ArticleController.java`) | 端点 | 方法 | 说明 | 权限 | |------|------|------|------| | `/api/articles/create` | POST | 创建文章(draft) | 登录用户 | | `/api/articles/submit` | POST | 提交审核(draft→pending) | 作者 | | `/api/articles/update` | POST | 更新文章 | 作者 | | `/api/articles/list` | POST | 已发布文章列表(分页) | 公开 | | `/api/articles/detail` | POST | 文章详情 | 公开 | | `/api/articles/my` | POST | 我的文章列表 | 登录用户 | ### 4.2 文章审核 API (`controller/admin/ArticleAdminController.java`) | 端点 | 方法 | 说明 | 权限 | |------|------|------|------| | `/api/admin/articles/pending` | POST | 待审核列表 | admin | | `/api/admin/articles/approve` | POST | 审核通过 | admin | | `/api/admin/articles/reject` | POST | 审核驳回 | admin | ### 4.3 活动 API (`controller/activity/ActivityController.java`) | 端点 | 方法 | 说明 | 权限 | |------|------|------|------| | `/api/activities/create` | POST | 创建活动 | admin | | `/api/activities/update` | POST | 更新活动 | admin | | `/api/activities/list` | POST | 活动列表(分页) | 公开 | | `/api/activities/detail` | POST | 活动详情 | 公开 | ### 4.4 分类 API (`controller/content/ContentCategoryController.java`) | 端点 | 方法 | 说明 | 权限 | |------|------|------|------| | `/api/content-categories/list` | POST | 分类列表 | 公开 | | `/api/content-categories/create` | POST | 创建分类 | admin | | `/api/content-categories/update` | POST | 更新分类 | admin | | `/api/content-categories/delete` | POST | 删除分类 | admin | --- ## 5. 文件结构 ### 后端 (cfc-backend) ``` src/main/java/com/etotem/cfc/ ├── config/DatabaseInitializer.java # DDL迁移(追加) ├── entity/ │ ├── Content.java # 统一内容实体 │ ├── ActivityExt.java # 活动扩展实体 │ └── ContentCategory.java # 分类实体 ├── mapper/ │ ├── ContentMapper.java │ ├── ActivityExtMapper.java │ └── ContentCategoryMapper.java ├── service/ │ ├── ArticleService.java # 文章业务+审核 │ ├── ActivityService.java # 活动业务 │ └── ContentCategoryService.java # 分类业务 ├── controller/ │ ├── article/ArticleController.java │ ├── admin/ArticleAdminController.java │ ├── activity/ActivityController.java │ └── content/ContentCategoryController.java ├── dto/ │ ├── ArticleCreateDTO.java │ ├── ArticleUpdateDTO.java │ ├── ActivityCreateDTO.java │ ├── ActivityUpdateDTO.java │ └── ContentCategoryDTO.java ``` ### 前端 (cfc-frontend) ``` pages/ ├── article/ │ ├── index.vue # 文章列表 │ └── detail.vue # 文章详情 └── activity/ ├── index.vue # 活动列表 └── detail.vue # 活动详情 components/ ├── article-card.vue # 文章卡片组件 └── activity-card.vue # 活动卡片组件 ``` ### 测试 ``` src/test/java/com/etotem/cfc/ ├── controller/ │ ├── ArticleControllerTest.java │ ├── ArticleAdminControllerTest.java │ ├── ActivityControllerTest.java │ └── ContentCategoryControllerTest.java └── service/ ├── ArticleServiceTest.java ├── ActivityServiceTest.java └── ContentCategoryServiceTest.java ``` --- ## 6. 状态机 ### 文章状态流转 ``` draft ──submit──→ pending ──approve──→ approved │ │ ├──reject──→ rejected │ │ │ └──withdraw→ withdrawn │ │ rejected ──resubmit──→ pending withdrawn ──resubmit──→ pending ``` ### 活动状态 活动由 admin 直接发布,无需审核: ``` draft ──publish──→ published ──close──→ closed ``` --- ## 7. 测试用例 ### ArticleControllerTest (~15 用例) - createArticle_Success — 创建文章(draft) - createArticle_NoTitle — 标题为空 - createArticle_NoContent — 内容为空 - submitArticle_Success — 提交审核 - submitArticle_AlreadyApproved — 已审核文章不能提交 - updateArticle_Success — 更新文章 - updateArticle_NotAuthor — 非作者不能更新 - getArticleList_Success — 已发布文章列表 - getArticleList_ByCategory — 按分类筛选 - getArticleList_ByEnergyDimension — 按能量维度筛选 - getArticleDetail_Success — 文章详情 - getArticleDetail_NotFound — 文章不存在 - getMyArticles_Success — 我的文章列表 - getMyArticles_Empty — 没有文章 ### ArticleAdminControllerTest (~10 用例) - getPendingList_Success — 待审核列表 - approveArticle_Success — 审核通过 - approveArticle_NotPending — 非待审状态不能通过 - approveArticle_NotFound — 文章不存在 - rejectArticle_Success — 审核驳回 - rejectArticle_WithReason — 驳回带原因 ### ActivityControllerTest (~10 用例) - createActivity_Success — 创建活动 - createActivity_MissingRequired — 缺少必填字段 - updateActivity_Success — 更新活动 - getActivityList_Success — 活动列表 - getActivityList_ByEnergyDimension — 按能量维度筛选 - getActivityDetail_Success — 活动详情 ### ContentCategoryControllerTest (~8 用例) - createCategory_Success — 创建分类 - createCategory_Duplicate — 分类名重复 - updateCategory_Success — 更新分类 - deleteCategory_Success — 删除分类 - getCategoryList_Success — 分类列表 - getCategoryList_ByEnergyDimension — 按能量维度查分类 ### ArticleServiceTest (~10 用例) - submitReview_Success — 提交审核状态变化 - approve_Success — 审核通过状态变化 - reject_Success — 审核驳回状态变化 - reject_WithReason — 驳回带原因 - submit_FromWrongStatus — 错误状态不能提交 - approve_FromWrongStatus — 非待审不能通过 - getUserArticles_Success — 用户文章列表 - searchByEnergyDimension — 按能量维度搜索 --- ## 8. 前端页面设计 ### 文章列表页 (pages/article/index.vue) - 顶部筛选:分类滚动条 + 能量维度标签 - 文章卡片列表:封面图、标题、摘要、作者、发布时间 - 点击进入详情 ### 文章详情页 (pages/article/detail.vue) - 富文本渲染(rich-text 组件) - 作者信息、发布时间、浏览量 - 能量维度标签展示 ### 活动列表页 (pages/activity/index.vue) - 时间筛选(进行中/即将开始/已结束) - 活动卡片:封面、标题、时间、地点 ### 活动详情页 (pages/activity/detail.vue) - 基本信息 + 富文本内容 - 报名信息、地点、时间 ### 嵌入组件 (components/article-card.vue / activity-card.vue) - 横滑推荐卡片 - 用于首页、发现页等嵌入 --- ## 9. 与现有系统的集成 - **认证复用**: 使用现有 JWT 认证,`@RequestAttribute("userId")` 获取用户 - **角色权限**: admin 角色可访问审核/活动管理 API - **数据库**: 通过 DatabaseInitializer 执行 DDL 迁移 - **MediaController**: 图片上传复用现有文件上传接口 - **统一响应**: 使用 `Result` 包装 - **统一 @PostMapping**: 遵循项目规范 --- ## 10. 验收标准 - [x] articles 表可正常创建和迁移 - [x] activities_ext 表可正常创建和迁移 - [x] content_categories 表可正常创建和迁移,含 5 条能量维度默认分类 - [x] 文章 CRUD API 正常工作 - [x] 文章提交-审核-通过/驳回 状态流转正常 - [x] 活动 CRUD API 正常工作 - [x] 分类 CRUD API 正常工作 - [x] 所有 Controller 测试通过 - [x] 所有 Service 测试通过 - [x] 小程序页面展示正常