feat(health): 内容管理模块 — 审核/分类/标签/富文本编辑器
Some checks failed
CI / rust-check (push) Has been cancelled
CI / rust-test (push) Has been cancelled
CI / frontend-build (push) Has been cancelled
CI / security-audit (push) Has been cancelled

后端:
- 文章审核状态机:draft → pending_review → published(含 reject/unpublish)
- 文章分类 CRUD(article_category entity + service + handler)
- 文章标签 CRUD(article_tag + article_article_tag 关联)
- 文章修订版快照(article_revision)
- 阅读计数、排序、slug、审核备注
- 新增 health.articles.review 权限

前端:
- ArticleManageList:状态标签页 + 分类筛选 + 关键字搜索 + 审核操作
- ArticleEditor:Wangeditor 富文本编辑器 + 元数据侧栏
- ArticleCategoryManage:分类 CRUD + 父子层级
- ArticleTagManage:标签 CRUD

修复:
- diagnosis_service/health_data_service/dialysis_service: 补充 key_version 字段
- ArticleCategoryManage: 补充 Select 组件导入
This commit is contained in:
iven
2026-04-26 12:51:30 +08:00
parent 49b8300fdc
commit 17b423b9b8
26 changed files with 3731 additions and 97 deletions

View File

@@ -0,0 +1,39 @@
# 内容管理模块设计讨论
> 日期: 2026-04-26 | 参与者: 用户 + AI
## 背景
HMS 项目已有文章article基础 CRUD 实现(后端 API + 小程序列表/详情页),但缺少 Web 管理后台、富文本编辑、审核流程、分类管理等核心内容管理能力。用户希望围绕内容管理功能展开发散式讨论,确定设计方向。
## 讨论要点
### 需求确认
- **定位**:综合内容平台 — 健康科普 + 医院公告 + 活动通知 + 科室介绍等
- **编辑体验**:富文本可视化编辑(非 Markdown
- **发布流程**:需要审核流程(作者提交 → 审核员审批 → 发布)
- **角色**:内容作者、审核员、患者读者(不需要独立的内容管理员角色)
- **媒体**:先做图片上传,视频/附件后续再加
### 方案选择
讨论了两个方案:
1. **方案 A在 erp-health 内扩展** — 改动最小,复用现有 CRUD + 权限体系
2. **方案 B拆分为独立 erp-content crate** — 关注点分离但工作量大
最终选择:**方案 A + 预留拆分接口**。内容管理代码放在 `content/` 子目录,通过事件总线与 health 核心通信,未来可拆分。
### 设计决策
- 数据模型articles 表 ALTER 增加 status/slug/reviewed_by 等字段 + 新增 4 张表category/tag/relation/revision
- 审核状态机draft → pending_review → published支持 reject 和 unpublish
- 富文本编辑器Wangeditor v5MIT、轻量、中文优先
- 图片存储:本地文件系统,后续可迁移至 OSS
- 新增权限码:`health.articles.review`
- 新增事件article.submitted/approved/rejected/published
## 结论
设计规格已写入 `docs/superpowers/specs/2026-04-26-content-management-design.md`,估算工作量 7-10 天(后端 3-4 天 + 前端 3-4 天 + 小程序 1-2 天)。

View File

@@ -0,0 +1,328 @@
# HMS 内容管理模块设计规格
> 日期: 2026-04-26 | 状态: Draft | 依赖: erp-health (现有 article 基础)
---
## 1. 概述
### 1.1 目标
将现有 article 基础 CRUD 扩展为综合内容管理平台,支持:
- 健康科普、医院公告、活动通知、科室介绍等多种内容类型
- 富文本可视化编辑Wangeditor
- 作者 → 审核员 → 发布的审核工作流
- 受控分类 + 多对多标签
- 图片上传
- 阅读统计
### 1.2 方案选择
**在 erp-health 内扩展 + 预留拆分接口。**
理由:内容管理与健康管理强关联(科普、体检解读),现有后端 CRUD 完整只需增强。所有 article 相关代码放在 `crates/erp-health/src/content/` 子目录,通过事件总线与 health 核心通信,未来可拆分为独立 crate。
### 1.3 角色定义
| 角色 | 职责 | 权限 |
|------|------|------|
| 内容作者 | 创建/编辑/提交文章 | `health.articles.manage` |
| 审核员 | 审核/批准/拒绝文章 | `health.articles.review` |
| 患者读者 | 小程序阅读已发布内容 | 无需权限(公开端点) |
---
## 2. 数据模型
### 2.1 articles 表改造
新增字段(在现有表基础上 ALTER
| 字段 | 类型 | 说明 |
|------|------|------|
| `status` | String(20) | `draft` / `pending_review` / `approved` / `rejected` / `published`,默认 `draft` |
| `slug` | String(可选) | URL 友好标识 |
| `content_type` | String(20) | `rich_text`(默认) / `markdown`,预留扩展 |
| `reviewed_by` | UUID(可选) | 审核人 ID |
| `reviewed_at` | DateTime(可选) | 审核时间 |
| `review_note` | Text(可选) | 审核备注/拒绝原因 |
| `view_count` | i32 | 阅读次数,默认 0 |
| `sort_order` | i32 | 置顶/排序权重,默认 0 |
**发布语义变更:** 原来通过 `published_at IS NOT NULL` 判断发布状态,改为通过 `status = 'published'` 控制。`published_at` 保留作为实际发布时间。
**现有字段保留:** id, tenant_id, title, summary, content, cover_image, category(过渡期保留,迁移完成后废弃), author, published_at, 标准字段。
### 2.2 新增 article_category 表
```sql
CREATE TABLE article_category (
id UUID PRIMARY KEY,
tenant_id UUID NOT NULL,
name VARCHAR(100) NOT NULL,
slug VARCHAR(100),
parent_id UUID REFERENCES article_category(id),
description TEXT,
sort_order INT DEFAULT 0,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_by UUID,
updated_by UUID,
deleted_at TIMESTAMPTZ,
version INT NOT NULL DEFAULT 1
);
```
### 2.3 新增 article_tag 表
```sql
CREATE TABLE article_tag (
id UUID PRIMARY KEY,
tenant_id UUID NOT NULL,
name VARCHAR(50) NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_by UUID,
updated_by UUID,
deleted_at TIMESTAMPTZ,
version INT NOT NULL DEFAULT 1
);
```
### 2.4 新增 article_article_tag 关联表
```sql
CREATE TABLE article_article_tag (
article_id UUID NOT NULL REFERENCES articles(id),
tag_id UUID NOT NULL REFERENCES article_tag(id),
PRIMARY KEY (article_id, tag_id)
);
```
### 2.5 新增 article_revision 表(预留版本历史)
```sql
CREATE TABLE article_revision (
id UUID PRIMARY KEY,
tenant_id UUID NOT NULL,
article_id UUID NOT NULL REFERENCES articles(id),
revision_number INT NOT NULL,
title VARCHAR(255) NOT NULL,
content TEXT NOT NULL,
summary TEXT,
created_by UUID,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
```
---
## 3. 审核工作流
### 3.1 状态机
```
draft ──submit()──→ pending_review ──approve()──→ published
↑ │
│ reject()
│ ↓
└─────rejected ←──────┘
(修改后重新 submit → pending_review)
published ──unpublish()──→ draft
```
| 状态 | 可见性 | 允许操作 |
|------|--------|---------|
| `draft` | 仅作者 | 编辑、提交审核、删除 |
| `pending_review` | 作者 + 审核员 | 审核员:通过/拒绝;作者:撤回 |
| `approved` | 过渡态,自动发布 | — |
| `rejected` | 作者 | 编辑后重新提交 |
| `published` | 所有人(含小程序) | 撤回、删除 |
### 3.2 事件
| 事件 | 触发时机 | 消费者 |
|------|---------|--------|
| `article.submitted` | draft → pending_review | 通知审核员 |
| `article.approved` | 审核通过 | 记录日志 |
| `article.rejected` | 审核拒绝 | 通知作者 |
| `article.published` | 正式发布 | 记录日志 |
---
## 4. API 设计
### 4.1 文章 CRUD增强已有
| Method | Path | 说明 | 权限 |
|--------|------|------|------|
| GET | `/api/v1/health/articles` | 文章列表(管理端,支持 status/category/tag 筛选) | `health.articles.list` |
| GET | `/api/v1/health/articles/{id}` | 文章详情 | `health.articles.list` |
| POST | `/api/v1/health/articles` | 创建文章(默认 draft | `health.articles.manage` |
| PUT | `/api/v1/health/articles/{id}` | 更新文章 | `health.articles.manage` |
| DELETE | `/api/v1/health/articles/{id}` | 软删除 | `health.articles.manage` |
**列表查询参数**`page`, `page_size`, `status`, `category_id`, `tag_id`, `keyword`(标题搜索)
### 4.2 审核流程
| Method | Path | 说明 | 权限 |
|--------|------|------|------|
| POST | `/api/v1/health/articles/{id}/submit` | 提交审核 | `health.articles.manage` |
| POST | `/api/v1/health/articles/{id}/approve` | 审核通过并发布 | `health.articles.review` |
| POST | `/api/v1/health/articles/{id}/reject` | 审核拒绝body: `{ "note": "..." }`) | `health.articles.review` |
| POST | `/api/v1/health/articles/{id}/unpublish` | 撤回发布 | `health.articles.manage` |
### 4.3 分类管理
| Method | Path | 说明 | 权限 |
|--------|------|------|------|
| GET | `/api/v1/health/article-categories` | 分类列表(树形) | `health.articles.list` |
| POST | `/api/v1/health/article-categories` | 创建分类 | `health.articles.manage` |
| PUT | `/api/v1/health/article-categories/{id}` | 更新分类 | `health.articles.manage` |
| DELETE | `/api/v1/health/article-categories/{id}` | 删除分类 | `health.articles.manage` |
### 4.4 标签管理
| Method | Path | 说明 | 权限 |
|--------|------|------|------|
| GET | `/api/v1/health/article-tags` | 标签列表 | `health.articles.list` |
| POST | `/api/v1/health/article-tags` | 创建标签 | `health.articles.manage` |
| DELETE | `/api/v1/health/article-tags/{id}` | 删除标签 | `health.articles.manage` |
### 4.5 图片上传
| Method | Path | 说明 | 权限 |
|--------|------|------|------|
| POST | `/api/v1/health/articles/upload-image` | 上传图片,返回 `{ url }` | `health.articles.manage` |
图片存储:本地文件系统 `uploads/articles/{tenant_id}/{yyyy-MM}/{uuid}.{ext}`,后续可迁移至 OSS。
### 4.6 权限变更
新增权限码:
| 权限码 | 名称 | 说明 |
|--------|------|------|
| `health.articles.review` | 审核资讯 | 新增 |
保留已有:
| 权限码 | 名称 |
|--------|------|
| `health.articles.list` | 查看资讯 |
| `health.articles.manage` | 管理资讯 |
---
## 5. Web 前端
### 5.1 新增页面
| 页面 | 路由 | 组件 |
|------|------|------|
| 文章列表 | `/health/articles` | `ArticleManageList` |
| 创建文章 | `/health/articles/new` | `ArticleEditor` |
| 编辑文章 | `/health/articles/:id/edit` | `ArticleEditor` |
| 文章详情/预览 | `/health/articles/:id` | `ArticlePreview` |
| 分类管理 | `/health/article-categories` | `ArticleCategoryManage` |
| 标签管理 | `/health/article-tags` | `ArticleTagManage` |
### 5.2 文章列表页
- 状态 Tab 筛选:全部 | 草稿 | 待审核 | 已发布 | 已拒绝
- 分类下拉筛选
- 标题关键词搜索
- 表格列:标题、分类、标签、状态(色块)、作者、阅读数、发布时间、操作
- 操作按钮根据状态和权限动态显示:
- 草稿:编辑、删除、提交审核
- 待审核:查看(审核员可看到审核/拒绝)
- 已发布:查看、撤回
- 已拒绝:编辑、重新提交
### 5.3 富文本编辑器
**选型Wangeditor v5**
- MIT 协议,轻量(~200KB
- 中文优先React 集成简单(`@wangeditor/editor-for-react`
- 支持图片上传 hook对接后端 upload-image API
- 支持标题/列表/链接/表格等常用格式
编辑器页面布局:
- 左侧:富文本编辑区域
- 右侧标题、分类选择、标签选择、摘要、封面图上传、slug
- 底部:保存草稿 / 提交审核 按钮
### 5.4 侧边栏菜单
在健康管理分组下新增「内容管理」菜单项,图标使用 `FileTextOutlined`
---
## 6. 小程序端增强
### 6.1 文章列表页改造
- 增加顶部分类 Tab从 article-category API 获取)
- 下拉刷新 + 无限滚动
- 搜索框(标题关键词)
### 6.2 文章详情页改造
- 增加 `view_count` 展示
- 进入详情页时调用阅读计数 APIPOST 或 PUT 递增)
### 6.3 新增 API 调用
- `GET /api/v1/health/articles` — 增加 `category_id``keyword` 参数
- `POST /api/v1/health/articles/{id}/view` — 阅读计数
---
## 7. 实施步骤
### Phase 1后端增强3-4 天)
1. 数据库迁移articles 表 ALTER + article_category/article_tag/article_article_tag/article_revision 四张新表
2. Entity 定义:修改 Article entity + 新增 ArticleCategory、ArticleTag、ArticleArticleTag、ArticleRevision
3. Service 层ArticleService 增强(状态机、审核、搜索)+ CategoryService + TagService + RevisionService
4. Handler 层:新增审核/分类/标签/上传端点
5. 权限注册:新增 `health.articles.review`
6. 事件发布article.submitted/approved/rejected/published
7. 图片上传:文件存储端点
### Phase 2Web 前端3-4 天)
1. 安装 Wangeditor 依赖
2. 文章列表页(筛选、状态 Tab、表格
3. 文章编辑页(富文本编辑器 + 元数据表单)
4. 文章预览/审核页
5. 分类管理页
6. 标签管理页
7. 路由注册 + 侧边栏菜单
### Phase 3小程序增强1-2 天)
1. 文章列表分类 Tab
2. 搜索功能
3. 阅读计数
4. API 调用适配
### 总估算7-10 天
---
## 8. 验收标准
- [ ] 作者可创建/编辑文章(富文本),保存为草稿
- [ ] 作者可提交审核
- [ ] 审核员可看到待审列表,通过或拒绝
- [ ] 已发布文章在小程序端可见
- [ ] 分类和标签可管理
- [ ] 图片可上传并在编辑器中插入
- [ ] 阅读计数正确递增
- [ ] `cargo check` + `cargo test` 通过
- [ ] 前端 `pnpm build` 通过