Skip to content

文章管理系统设计文档

概述

文章管理系统是一个支持付费阅读的内容管理系统,允许管理员创建、编辑和管理文章,支持文章分类、标签、付费内容等功能。

核心功能

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. 保存文章

2. 文章编辑流程

1. 管理员在文章列表点击"编辑"
2. 加载文章现有数据
3. 修改文章信息
4. 使用AI功能优化内容(可选)
5. 保存修改

3. AI 生成内容流程

1. 用户点击AI生成按钮(标题/摘要/大纲/优化内容)
2. 系统获取当前内容(免费内容+付费内容)
3. 调用AI接口生成内容
4. 判断原内容是否为空:
   - 如果为空:直接替换为新内容
   - 如果不为空:显示差异对照弹框
5. 用户选择是否采纳AI生成的内容
6. 如果采纳,更新对应字段

4. 文章查看流程(前端)

1. 用户访问文章详情页
2. 系统检查用户是否已付费:
   - 如果已付费:显示完整内容(免费内容+付费内容)
   - 如果未付费:仅显示免费内容,付费内容区域显示付费提示
3. 如果文章需要付费且用户未付费:
   - 显示付费按钮
   - 用户点击付费后,扣除余额并显示完整内容

5. 分类管理流程

1. 管理员在文章列表页面点击"分类管理"按钮,进入分类管理页面
2. 在分类管理页面可以:
   - 查看所有分类列表(树形结构显示,最多3级)
   - 新增分类(名称、标识、描述、排序、启用状态、父分类)
   - 编辑分类信息(编辑时不能修改父分类)
   - 删除分类(删除前检查是否有子分类和文章使用该分类)
3. 分类嵌套规则:
   - 最多支持3级嵌套
   - 如果某个分类下有子分类,则不能关联文章
   - 如果某个分类下已关联文章,则不能创建子分类
   - 文章只能关联叶子节点分类(没有子分类的分类)
4. 文章编辑时只能选择叶子节点分类
5. 分类支持排序功能,数字越小越靠前
6. 分类支持启用/禁用状态

7. 标签管理流程

1. 管理员在文章列表页面点击"标签管理"按钮,进入标签管理页面
2. 在标签管理页面可以:
   - 查看所有标签列表
   - 新增标签(名称、标识)
   - 编辑标签信息
   - 删除标签(删除前检查是否有文章使用该标签)
3. 文章编辑时输入标签:
   - 支持模糊查询已有标签
   - 支持逗号分隔输入多个标签
   - 如果输入的标签不存在,回车时自动创建新标签
   - 标签自动生成 slug(基于标签名称)

6. 文章编辑时的分类校验流程

1. 用户访问文章编辑页面(新增或编辑)
2. 系统自动加载分类列表
3. 如果分类列表为空:
   - 弹出确认提示框:"当前没有可用的文章分类,需要先创建分类才能添加文章。是否前往分类管理页面?"
   - 用户点击"前往添加":跳转到分类管理页面(/articles/categories)
   - 用户点击"取消"或关闭弹框:返回文章列表页面(/articles)
4. 如果分类列表不为空:
   - 正常显示文章编辑表单
   - 分类字段为必填项,未选择分类时无法提交表单
   - 表单验证会提示"请选择文章分类"

实现要点

  • 分类字段(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:文章相关API

    • apiGetArticleList:查询文章列表
    • 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";
  • 详细规范请参考 代码规范文档

注意事项

  1. 文章价格:价格以分为单位存储,前端显示时需要转换为元(除以100)
  2. 内容合并content 字段是免费内容和付费内容的合并,用于全文搜索等场景
  3. 标签关联:文章和标签通过 article_tag_relation 中间表实现多对多关联,提高查询性能
  4. 标签输入:支持模糊查询、自动创建、逗号分隔输入多个标签
  5. 标签删除:删除标签前必须确保没有文章使用该标签(后端会自动检查中间表)
  6. 分类嵌套:分类支持最多3级嵌套,通过 parent_id 字段实现
  7. 分类关联约束
    • 文章只能关联叶子节点分类(没有子分类的分类)
    • 如果分类下有子分类,不能关联文章
    • 如果分类下已关联文章,不能创建子分类
    • 删除分类前必须确保没有子分类和文章使用该分类(后端会自动检查)
  8. 分类唯一性:分类名称和标识全局唯一(不管父分类)
  9. 分类管理:分类管理页面独立于文章编辑页面,提供完整的分类CRUD功能
  10. 分类必填:文章分类为必填字段,新增或编辑文章时必须选择分类
  11. 分类列表校验:访问文章编辑页面时,如果分类列表为空,系统会提示用户先创建分类
  12. API验证:所有分类和标签相关的API接口都使用Zod进行参数验证,确保数据安全
  13. 类型定义:API类型定义统一放在 typings/ 目录,确保前后端类型一致性
  14. 类型导入:从第三方库导入类型时,必须使用 type 关键字(如:import { type FormInstance } from "element-plus"
  15. AI功能:需要接入真实的AI服务接口(当前为模拟实现)

后续优化方向

  1. AI功能完善:接入真实的AI服务,实现真正的智能生成和优化
  2. 全文搜索:基于 content 字段实现全文搜索功能
  3. 文章统计:添加文章阅读量、付费转化率等统计功能
  4. 评论系统:为文章添加评论功能
  5. 文章推荐:基于分类、标签实现文章推荐功能
  6. SEO优化:添加文章SEO相关字段和功能

中小微企业级建站程序。十年Web开发经验提炼而成,基于Vue3+Node.js,功能强大,支持多种业务场景。