外观
文章管理系统设计文档
概述
文章管理系统是一个支持付费阅读的内容管理系统,允许管理员创建、编辑和管理文章,支持文章分类、标签、付费内容等功能。
核心功能
1. 文章管理
- 文章的创建、编辑、删除
- 文章状态管理(草稿、已发布、已删除)
- 文章置顶功能
- 文章浏览量统计
2. 付费阅读
- 支持免费内容和付费内容分离
- 文章价格设置(单位:分,0表示免费)
- 未付费用户仅能查看免费内容
- 付费用户可查看完整内容(免费内容+付费内容)
3. 分类和标签
- 文章分类管理(创建、编辑、删除)
- 文章标签管理(独立的标签管理页面,支持创建、编辑、删除)
- 标签关联(文章通过 tag_ids 关联标签,支持多标签)
- 标签输入(支持模糊查询、自动创建、逗号分隔输入)
- 分类和标签的展示和筛选
4. AI 辅助功能
- 根据内容生成文章标题
- 根据内容生成文章摘要
- 根据内容生成文章大纲
- 优化免费内容文案
- 优化付费内容文案
- 差异对照功能(AI生成内容与原内容对比)
数据库设计
1. article(文章表)
存储文章的基本信息和内容。
字段说明:
id: 主键,自增title: 文章标题(唯一)name: 文章URL标识(唯一,用于URL路径)abstract: 文章摘要(最大1000字符)thumbnail: 缩略图URL(最大400字符)views: 浏览量(默认0)content: 完整内容(mediumtext,免费内容+付费内容)free_content: 免费内容(mediumtext,未付费用户可见)paid_content: 付费内容(mediumtext,付费用户可见)price: 文章价格(单位:分,默认0表示免费)outline: 文章大纲(text)status: 发布状态(enum: draft-草稿, published-已发布, deleted-已删除)top: 是否置顶(boolean,默认false)category_id: 分类ID(关联article_category表,只能关联叶子节点分类)source_url: 来源URL(转载文章的来源地址)source_name: 来源名称(转载文章的来源名称)publish_date: 发布日期(date,必填)created_at: 创建时间updated_at: 更新时间
索引:
title: 唯一索引name: 唯一索引(status, publish_date): 用于查询已发布文章列表(category_id): 用于按分类查询(top, publish_date): 用于查询置顶文章
2. article_category(文章分类表)
存储文章分类信息。
字段说明:
id: 主键,自增name: 分类名称(唯一)slug: 分类标识(唯一,用于URL)description: 分类描述(最大500字符)sort_order: 排序顺序(默认0)is_active: 是否启用(boolean,默认true)parent_id: 父分类ID(关联article_category表,null表示顶级分类)
索引:
name: 唯一索引slug: 唯一索引(is_active, sort_order): 用于查询启用的分类列表parent_id: 用于查询子分类
3. article_tag(文章标签表)
存储文章标签信息。
字段说明:
id: 主键,自增name: 标签名称(唯一)slug: 标签标识(唯一,用于URL)
索引:
name: 唯一索引slug: 唯一索引
4. article_tag_relation(文章标签关联表)
文章和标签的多对多关联中间表。
字段说明:
article_id: 文章ID(关联article表)tag_id: 标签ID(关联article_tag表)
索引:
(article_id, tag_id): 联合唯一索引,确保同一篇文章不会重复关联同一个标签article_id: 用于查询文章的所有标签tag_id: 用于查询标签的所有文章
业务流程
1. 文章创建流程
1. 管理员在管理后台点击"新增文章"
2. 填写文章基本信息(标题、URL名称、摘要、大纲等)
3. 选择文章分类(可选)
4. 添加文章标签(可选,支持创建新标签)
5. 编辑免费内容(使用富文本编辑器)
6. 编辑付费内容(使用富文本编辑器)
7. 设置文章价格(0表示免费)
8. 设置发布状态(草稿/已发布)
9. 设置是否置顶
10. 保存文章1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
2. 文章编辑流程
1. 管理员在文章列表点击"编辑"
2. 加载文章现有数据
3. 修改文章信息
4. 使用AI功能优化内容(可选)
5. 保存修改1
2
3
4
5
2
3
4
5
3. AI 生成内容流程
1. 用户点击AI生成按钮(标题/摘要/大纲/优化内容)
2. 系统获取当前内容(免费内容+付费内容)
3. 调用AI接口生成内容
4. 判断原内容是否为空:
- 如果为空:直接替换为新内容
- 如果不为空:显示差异对照弹框
5. 用户选择是否采纳AI生成的内容
6. 如果采纳,更新对应字段1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
4. 文章查看流程(前端)
1. 用户访问文章详情页
2. 系统检查用户是否已付费:
- 如果已付费:显示完整内容(免费内容+付费内容)
- 如果未付费:仅显示免费内容,付费内容区域显示付费提示
3. 如果文章需要付费且用户未付费:
- 显示付费按钮
- 用户点击付费后,扣除余额并显示完整内容1
2
3
4
5
6
7
2
3
4
5
6
7
5. 分类管理流程
1. 管理员在文章列表页面点击"分类管理"按钮,进入分类管理页面
2. 在分类管理页面可以:
- 查看所有分类列表(树形结构显示,最多3级)
- 新增分类(名称、标识、描述、排序、启用状态、父分类)
- 编辑分类信息(编辑时不能修改父分类)
- 删除分类(删除前检查是否有子分类和文章使用该分类)
3. 分类嵌套规则:
- 最多支持3级嵌套
- 如果某个分类下有子分类,则不能关联文章
- 如果某个分类下已关联文章,则不能创建子分类
- 文章只能关联叶子节点分类(没有子分类的分类)
4. 文章编辑时只能选择叶子节点分类
5. 分类支持排序功能,数字越小越靠前
6. 分类支持启用/禁用状态1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
7. 标签管理流程
1. 管理员在文章列表页面点击"标签管理"按钮,进入标签管理页面
2. 在标签管理页面可以:
- 查看所有标签列表
- 新增标签(名称、标识)
- 编辑标签信息
- 删除标签(删除前检查是否有文章使用该标签)
3. 文章编辑时输入标签:
- 支持模糊查询已有标签
- 支持逗号分隔输入多个标签
- 如果输入的标签不存在,回车时自动创建新标签
- 标签自动生成 slug(基于标签名称)1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
6. 文章编辑时的分类校验流程
1. 用户访问文章编辑页面(新增或编辑)
2. 系统自动加载分类列表
3. 如果分类列表为空:
- 弹出确认提示框:"当前没有可用的文章分类,需要先创建分类才能添加文章。是否前往分类管理页面?"
- 用户点击"前往添加":跳转到分类管理页面(/articles/categories)
- 用户点击"取消"或关闭弹框:返回文章列表页面(/articles)
4. 如果分类列表不为空:
- 正常显示文章编辑表单
- 分类字段为必填项,未选择分类时无法提交表单
- 表单验证会提示"请选择文章分类"1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
实现要点:
- 分类字段(
category_id)在表单验证规则中设置为必填 - 在
loadCategories函数中检查分类列表是否为空 - 使用
ElMessageBox.confirm显示确认提示框 - 根据用户选择进行路由跳转
主要涉及文件
后端文件
控制器层
src/controllers/article.mts:文章相关控制器cGetArticlesListPage:获取文章列表(分页)cGetArticleDetail:获取文章详情cAddArticle:添加文章cUpdateArticle:更新文章cDeleteArticle:删除文章(软删除,更新状态为deleted)cGenerateSummary:生成文章摘要(AI功能)
src/controllers/articleCategory.mts:文章分类相关控制器cGetArticleCategories:获取所有分类列表(支持启用状态筛选)cAddArticleCategory:添加分类(使用Zod验证参数)cUpdateArticleCategory:更新分类(使用Zod验证参数)cDeleteArticleCategory:删除分类(删除前检查是否有文章使用该分类)
src/controllers/articleTag.mts:文章标签相关控制器cGetArticleTags:获取所有标签列表(支持关键词模糊查询)cAddArticleTag:添加标签(使用Zod验证参数)cUpdateArticleTag:更新标签(使用Zod验证参数)cDeleteArticleTag:删除标签(删除前检查是否有文章使用该标签)
路由层
src/routes/articles.mts:文章相关路由src/routes/articleCategory.mts:分类相关路由src/routes/articleTag.mts:标签相关路由
模型层
src/models/Article.mts:文章表模型定义src/models/ArticleCategory.mts:分类表模型定义(支持嵌套)src/models/ArticleTag.mts:标签表模型定义src/models/ArticleTagRelation.mts:文章标签关联中间表模型定义
服务层
src/services/articles.mts:文章相关业务逻辑getRandomPostList:获取随机文章列表getLatestPostList:获取最新文章列表getPostListByPage:分页查询文章列表getPostDetailByName:根据name查询文章详情getTotalPostCount:查询文章总数getMostViewedPostList:获取访问量最大的文章列表getTopPostList:查询置顶文章列表
前端文件
管理后台(apps/admin/)
apps/admin/src/views/ArticlesView/ArticlesView.vue:文章列表页面- 文章列表展示(包含分类和标签显示)
- 搜索和筛选(标题、状态、置顶)
- 分页功能
- 编辑和删除操作
- 分类管理入口按钮
- 标签管理入口按钮
apps/admin/src/views/ArticleView/ArticleView.vue:文章编辑页面- 文章基本信息编辑
- 分类选择(只显示叶子节点分类)
- 标签输入(支持模糊查询、自动创建、逗号分隔)
- 免费内容和付费内容编辑器(wangeditor)
- AI功能集成(标题、摘要、大纲、内容优化)
- 表单验证和提交
apps/admin/src/views/ArticleCategoryView/ArticleCategoryView.vue:分类管理页面- 分类列表展示(树形结构,最多3级)
- 新增分类(对话框表单,支持选择父分类)
- 编辑分类(对话框表单,编辑时不能修改父分类)
- 删除分类(带确认提示,检查子分类和文章)
- 分类状态管理(启用/禁用)
- 排序顺序设置
apps/admin/src/views/ArticleTagView/ArticleTagView.vue:标签管理页面- 标签列表展示
- 新增标签(对话框表单)
- 编辑标签(对话框表单)
- 删除标签(带确认提示)
apps/admin/src/components/AIDiffDialog/AIDiffDialog.vue:AI差异对照弹框组件- 显示原内容和AI生成内容的对比
- 用户选择是否采纳
apps/admin/src/api/articles.ts:文章相关APIapiGetArticleList:查询文章列表apiGetArticleInfo:查询文章详情apiAddArticle:添加文章apiUpdateArticle:更新文章apiDeleteArticle:删除文章apiGenerateSummary:生成文章摘要apiGetArticleCategories:获取分类列表apiAddArticleCategory:添加分类apiUpdateArticleCategory:更新分类apiDeleteArticleCategory:删除分类apiGetArticleTags:获取标签列表(支持关键词查询)apiAddArticleTag:添加标签apiUpdateArticleTag:更新标签apiDeleteArticleTag:删除标签
路由配置
apps/admin/src/router/index.ts:管理后台路由配置/articles:文章列表路由/articles/edit:文章编辑路由/articles/categories:分类管理路由/articles/tags:标签管理路由
类型定义
typings/article.d.ts:文章相关实体类型定义Article:文章类型ArticleCategory:分类类型ArticleTag:标签类型ArticleStatus:文章状态类型SimpleArticle:简化文章类型RawSimpleArticle:原始简化文章类型
typings/article.d.ts:文章相关API类型定义(已合并到 article.d.ts)ParamsApiGetArticleList:查询文章列表参数类型ReturnApiGetArticleList:查询文章列表返回类型ParamsApiGetArticleInfo:查询文章详情参数类型ReturnApiGetArticleInfo:查询文章详情返回类型ParamsApiAddArticle:添加文章参数类型ParamsApiUpdateArticle:更新文章参数类型ParamsApiDeleteArticle:删除文章参数类型ParamsApiGenerateSummary:生成摘要参数类型ReturnApiGetArticleCategories:获取分类列表返回类型ParamsApiAddArticleCategory:添加分类参数类型ParamsApiUpdateArticleCategory:更新分类参数类型ParamsApiDeleteArticleCategory:删除分类参数类型ReturnApiGetArticleTags:获取标签列表返回类型ParamsApiAddArticleTag:添加标签参数类型ParamsApiUpdateArticleTag:更新标签参数类型ParamsApiDeleteArticleTag:删除标签参数类型
注意:所有API相关的类型定义都放在 typings/ 目录下,以便跨文件复用类型。
API 接口
文章相关接口
获取文章列表
- 路径:
GET /api/articles/articles - 参数:
pageNo:页码(可选,默认1)pageSize:每页数量(可选,默认10)keyword:关键词(可选,搜索标题)status:状态(可选,draft/published/deleted)top:是否置顶(可选,0/1)
- 返回:文章列表和总数
获取文章详情
- 路径:
GET /api/articles/article-info - 参数:
id:文章ID
- 返回:文章详细信息(包含分类、标签等)
添加文章
- 路径:
POST /api/articles/add-article - 参数:文章完整信息(标题、内容、分类、标签等)
- 返回:成功或失败信息
- 约束:
category_id必须为叶子节点分类(没有子分类的分类)tag_ids为标签ID数组,通过中间表关联
更新文章
- 路径:
POST /api/articles/update-article - 参数:文章ID和更新后的信息
- 返回:成功或失败信息
- 约束:
category_id必须为叶子节点分类(没有子分类的分类)tag_ids为标签ID数组,通过中间表关联(更新时会先删除旧关联,再插入新关联)
删除文章
- 路径:
POST /api/articles/delete-article - 参数:
id:文章ID
- 返回:成功或失败信息
生成文章摘要
- 路径:
POST /api/articles/generate-summary - 参数:
content:文章内容
- 返回:生成的摘要
分类相关接口
获取所有分类
- 路径:
GET /api/articles/categories - 参数:
is_active:是否只获取启用的分类(可选,true/false)
- 返回:
list:树形结构分类列表(最多3级)flat:扁平结构分类列表(用于下拉选择)
添加分类
- 路径:
POST /api/articles/add-category - 参数(使用Zod验证):
name:分类名称(必填,字符串)slug:分类标识(必填,字符串,唯一)description:分类描述(可选,最大500字符)sort_order:排序顺序(可选,数字,默认0)is_active:是否启用(可选,布尔值,默认true)parent_id:父分类ID(可选,数字或null,null表示顶级分类)
- 返回:成功或失败信息
- 约束:
- 分类层级最多为3级
- 如果父分类下已关联文章,不能创建子分类
- 名称和标识全局唯一(不管父分类)
更新分类
- 路径:
POST /api/articles/update-category - 参数(使用Zod验证):
id:分类ID(必填)name:分类名称(可选)slug:分类标识(可选)description:分类描述(可选)sort_order:排序顺序(可选)is_active:是否启用(可选)parent_id:父分类ID(可选,数字或null,编辑时不能修改)
- 返回:成功或失败信息
- 约束:
- 如果分类下已关联文章,不能修改父分类
- 如果目标父分类下已关联文章,不能将分类移到其下
- 不能形成循环(不能将父分类设为子分类)
- 分类层级最多为3级
删除分类
- 路径:
POST /api/articles/delete-category - 参数(使用Zod验证):
id:分类ID(必填)
- 返回:成功或失败信息
- 约束:
- 如果分类下有子分类,不能删除
- 如果分类下已关联文章,不能删除
标签相关接口
获取所有标签
- 路径:
GET /api/articles/tags - 参数:
keyword:关键词(可选,用于模糊查询标签名称)
- 返回:标签列表
添加标签
- 路径:
POST /api/articles/add-tag - 参数(使用Zod验证):
name:标签名称(必填,字符串)slug:标签标识(必填,字符串,唯一)
- 返回:成功信息和标签ID
更新标签
- 路径:
POST /api/articles/update-tag - 参数(使用Zod验证):
id:标签ID(必填)name:标签名称(可选)slug:标签标识(可选)
- 返回:成功或失败信息
删除标签
- 路径:
POST /api/articles/delete-tag - 参数(使用Zod验证):
id:标签ID(必填)
- 返回:成功或失败信息(如果标签下有文章,会返回错误提示)
技术实现细节
1. 付费内容处理
- 前端编辑时,免费内容和付费内容分别使用独立的富文本编辑器
- 后端存储时,将免费内容和付费内容分别存储,同时合并存储到
content字段 - 前端展示时,根据用户付费状态决定显示内容
2. 标签管理
- 标签存储在独立的
article_tag表中 - 文章和标签通过
article_tag_relation中间表实现多对多关联 - 前端标签输入支持:
- 模糊查询已有标签(使用
el-autocomplete组件) - 逗号分隔输入多个标签
- 回车自动创建新标签(如果标签不存在)
- 自动生成 slug(基于标签名称)
- 模糊查询已有标签(使用
- 后端查询文章时,通过中间表关联查询标签信息(批量查询,性能更好)
- 删除标签前检查中间表中是否有文章使用该标签
3. AI 功能
- AI生成的内容如果与原内容不同,会显示差异对照弹框
- 用户可以选择采纳或拒绝AI生成的内容
4. 分类嵌套和关联
- 分类支持嵌套结构(最多3级),通过
parent_id字段实现 - 独立的分类管理页面,支持完整的CRUD操作
- 使用外键关联
article_category表 - 查询文章列表时使用 LEFT JOIN 获取分类名称
- 分类关联约束:
- 文章只能关联叶子节点分类(没有子分类的分类)
- 如果分类下有子分类,不能关联文章
- 如果分类下已关联文章,不能创建子分类
- 删除分类前检查是否有子分类和文章使用该分类(后端验证)
- 分类支持排序功能(sort_order字段)
- 分类支持启用/禁用状态(is_active字段)
- 分类名称和标识全局唯一(不管父分类)
5. 富文本编辑器
- 使用
@wangeditor/editor-for-vue作为富文本编辑器 - 支持图片、链接、表格等常用功能
- 免费内容和付费内容使用独立的编辑器实例
7. 类型定义管理
- 所有API相关的类型定义统一放在
typings/目录下 typings/article.d.ts:文章实体类型和API接口类型定义(包含 Article、ArticleCategory、ArticleTag 等实体类型,以及 ParamsApi*、ReturnApi* 等API接口类型)- 前端API文件(
apps/admin/src/api/articles.ts)从全局类型定义中引用类型 - 确保前后端类型一致性,便于类型检查和代码提示
类型导入规范:
- 从第三方库导入类型时,必须使用
type关键字 - 示例:
import { ElMessage, type FormInstance } from "element-plus"; - 详细规范请参考 代码规范文档
注意事项
- 文章价格:价格以分为单位存储,前端显示时需要转换为元(除以100)
- 内容合并:
content字段是免费内容和付费内容的合并,用于全文搜索等场景 - 标签关联:文章和标签通过
article_tag_relation中间表实现多对多关联,提高查询性能 - 标签输入:支持模糊查询、自动创建、逗号分隔输入多个标签
- 标签删除:删除标签前必须确保没有文章使用该标签(后端会自动检查中间表)
- 分类嵌套:分类支持最多3级嵌套,通过
parent_id字段实现 - 分类关联约束:
- 文章只能关联叶子节点分类(没有子分类的分类)
- 如果分类下有子分类,不能关联文章
- 如果分类下已关联文章,不能创建子分类
- 删除分类前必须确保没有子分类和文章使用该分类(后端会自动检查)
- 分类唯一性:分类名称和标识全局唯一(不管父分类)
- 分类管理:分类管理页面独立于文章编辑页面,提供完整的分类CRUD功能
- 分类必填:文章分类为必填字段,新增或编辑文章时必须选择分类
- 分类列表校验:访问文章编辑页面时,如果分类列表为空,系统会提示用户先创建分类
- API验证:所有分类和标签相关的API接口都使用Zod进行参数验证,确保数据安全
- 类型定义:API类型定义统一放在
typings/目录,确保前后端类型一致性 - 类型导入:从第三方库导入类型时,必须使用
type关键字(如:import { type FormInstance } from "element-plus") - AI功能:需要接入真实的AI服务接口(当前为模拟实现)
后续优化方向
- AI功能完善:接入真实的AI服务,实现真正的智能生成和优化
- 全文搜索:基于
content字段实现全文搜索功能 - 文章统计:添加文章阅读量、付费转化率等统计功能
- 评论系统:为文章添加评论功能
- 文章推荐:基于分类、标签实现文章推荐功能
- SEO优化:添加文章SEO相关字段和功能