Files
Ubuntu 32b43f85bd a
2026-07-03 16:58:28 +08:00

517 lines
18 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 新闻资讯模块设计方案
## 1. 概述
### 1.1 模块定位
新闻资讯模块是飞点健康 CMS 系统的核心内容管理模块,用于发布和管理企业新闻、行业资讯、产品动态等内容。该模块与顶级菜单"新闻动态"关联,提供完整的栏目管理和资讯发布功能。
### 1.2 设计目标
- 支持双格式发布:Markdown + HTML 富文本
- 复用现有成熟代码(personal-blog)
- 支持图片资源管理(可作为独立顶级模块)
- 提供良好的编辑体验和预览功能
### 1.3 功能范围
```
┌─────────────────────────────────────────────────────────────┐
│ 新闻资讯模块 │
├─────────────────┬─────────────────┬─────────────────────────┤
│ 栏目管理 │ 资讯管理 │ 图片管理 │
├─────────────────┼─────────────────┼─────────────────────────┤
│ • 创建栏目 │ • 创建资讯 │ • 上传图片 │
│ • 编辑栏目 │ • 编辑资讯 │ • 图片列表 │
│ • 删除栏目 │ • 删除资讯 │ • 插入到文章 │
│ • 栏目排序 │ • 发布/草稿 │ • 删除图片 │
│ │ • Markdown编辑 │ │
│ │ • HTML富文本 │ │
│ │ • 预览功能 │ │
└─────────────────┴─────────────────┴─────────────────────────┘
```
---
## 2. 数据库设计
### 2.1 数据表关系图
```
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ news_categories│ │ news_posts │ │ images │
│ (栏目表) │◄────────│ (资讯表) │────────►│ (图片表) │
├─────────────────┤ 1:N ├─────────────────┤ N:M ├─────────────────┤
│ id (PK) │ │ id (PK) │ │ id (PK) │
│ name │ │ title │ │ filename │
│ slug (UQ) │ │ slug (UQ) │ │ file_path │
│ description │ │ content │ │ thumb_path │
│ sort_order │ │ content_type │◄───────│ description │
│ is_enabled │ │ summary │ │ file_size │
│ created_at │ │ cover_image │◄───────│ width │
│ updated_at │ │ category_id(FK) │ │ height │
└─────────────────┘ │ is_published │ │ created_at │
│ is_draft │ └─────────────────┘
│ view_count │
│ created_at │
│ updated_at │
└─────────────────┘
│
│ 1:N
▼
┌─────────────────┐
│ news_post_images│
│ (文章图片关联) │
├─────────────────┤
│ post_id (FK) │
│ image_id (FK) │
└─────────────────┘
```
### 2.2 表结构定义
#### 2.2.1 news_categories - 栏目表
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| id | INTEGER | PK, AI | 主键 |
| name | VARCHAR(50) | NOT NULL | 栏目名称 |
| slug | VARCHAR(50) | UNIQUE, NOT NULL | URL标识(如:company-news) |
| description | VARCHAR(200) | NULL | 栏目描述 |
| sort_order | INTEGER | DEFAULT 0 | 排序权重 |
| is_enabled | BOOLEAN | DEFAULT 1 | 是否启用 |
| created_at | DATETIME | DEFAULT NOW | 创建时间 |
| updated_at | DATETIME | DEFAULT NOW | 更新时间 |
```sql
CREATE TABLE news_categories (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR(50) NOT NULL,
slug VARCHAR(50) UNIQUE NOT NULL,
description VARCHAR(200),
sort_order INTEGER DEFAULT 0,
is_enabled BOOLEAN DEFAULT 1,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
```
#### 2.2.2 news_posts - 资讯表
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| id | INTEGER | PK, AI | 主键 |
| title | VARCHAR(200) | NOT NULL | 资讯标题 |
| slug | VARCHAR(200) | UNIQUE, NOT NULL | URL友好的标识 |
| content | TEXT | NOT NULL | 内容 |
| content_type | VARCHAR(10) | DEFAULT 'markdown' | 内容类型:markdown/html |
| summary | VARCHAR(500) | NULL | 摘要(自动生成或手动填写)|
| cover_image | VARCHAR(500) | NULL | 封面图路径 |
| category_id | INTEGER | FK -> news_categories | 栏目ID(必填)|
| is_published | BOOLEAN | DEFAULT 0 | 是否发布 |
| is_draft | BOOLEAN | DEFAULT 1 | 是否草稿 |
| view_count | INTEGER | DEFAULT 0 | 浏览次数 |
| created_at | DATETIME | DEFAULT NOW | 创建时间 |
| updated_at | DATETIME | DEFAULT NOW | 更新时间 |
```sql
CREATE TABLE news_posts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title VARCHAR(200) NOT NULL,
slug VARCHAR(200) UNIQUE NOT NULL,
content TEXT NOT NULL,
content_type VARCHAR(10) DEFAULT 'markdown',
summary VARCHAR(500),
cover_image VARCHAR(500),
category_id INTEGER NOT NULL,
is_published BOOLEAN DEFAULT 0,
is_draft BOOLEAN DEFAULT 1,
view_count INTEGER DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (category_id) REFERENCES news_categories(id) ON DELETE RESTRICT
);
```
#### 2.2.3 images - 图片表(复用/扩展)
复用 personal-blog 的图片表结构,但提升为系统级资源表:
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| id | INTEGER | PK, AI | 主键 |
| filename | VARCHAR(255) | NOT NULL | 存储文件名 |
| original_name | VARCHAR(255) | NULL | 原始文件名 |
| file_path | VARCHAR(500) | NOT NULL | 文件路径 |
| thumb_path | VARCHAR(500) | NULL | 缩略图路径 |
| description | VARCHAR(500) | NULL | 图片描述 |
| file_size | INTEGER | NULL | 文件大小(字节)|
| width | INTEGER | NULL | 图片宽度 |
| height | INTEGER | NULL | 图片高度 |
| module | VARCHAR(20) | DEFAULT 'news' | 所属模块:news/product/page等 |
| created_at | DATETIME | DEFAULT NOW | 创建时间 |
```sql
CREATE TABLE images (
id INTEGER PRIMARY KEY AUTOINCREMENT,
filename VARCHAR(255) NOT NULL,
original_name VARCHAR(255),
file_path VARCHAR(500) NOT NULL,
thumb_path VARCHAR(500),
description VARCHAR(500),
file_size INTEGER,
width INTEGER,
height INTEGER,
module VARCHAR(20) DEFAULT 'news',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
```
---
## 3. 后端 API 设计
### 3.1 路由结构
```
/api/v1/
├── /news/
│ ├── GET /categories # 获取栏目列表
│ ├── POST /categories # 创建栏目
│ ├── GET /categories/{id} # 获取栏目详情
│ ├── PUT /categories/{id} # 更新栏目
│ ├── DELETE /categories/{id} # 删除栏目
│ ├── GET /posts # 获取资讯列表(分页、筛选)
│ ├── POST /posts # 创建资讯
│ ├── GET /posts/{id} # 获取资讯详情
│ ├── PUT /posts/{id} # 更新资讯
│ ├── DELETE /posts/{id} # 删除资讯
│ ├── POST /posts/{id}/publish # 发布资讯
│ ├── POST /posts/{id}/unpublish # 取消发布
│ └── GET /posts/slug/{slug} # 通过slug获取(访客端)
└── /images/
├── GET / # 获取图片列表(分页)
├── POST /upload # 上传图片
├── DELETE /{id} # 删除图片
└── POST /{id}/insert # 获取图片插入URL
```
### 3.2 核心 API 定义
#### 3.2.1 栏目管理 API
**GET /api/v1/news/categories**
```json
// Response
{
"items": [
{
"id": 1,
"name": "公司新闻",
"slug": "company-news",
"description": "飞点健康最新动态",
"sort_order": 1,
"is_enabled": true,
"post_count": 15,
"created_at": "2024-01-15T08:00:00"
}
],
"total": 5
}
```
**POST /api/v1/news/categories**
```json
// Request
{
"name": "公司新闻",
"slug": "company-news",
"description": "飞点健康最新动态",
"sort_order": 1
}
```
#### 3.2.2 资讯管理 API
**GET /api/v1/news/posts?page=1&size=10&category_id=1&keyword=xxx**
```json
// Response
{
"items": [
{
"id": 1,
"title": "飞点健康完成A轮融资",
"slug": "feidian-series-a",
"summary": "今日,飞点健康宣布完成数千万元A轮融资...",
"cover_image": "/uploads/covers/xxx.jpg",
"category": {
"id": 1,
"name": "公司新闻"
},
"content_type": "markdown",
"is_published": true,
"is_draft": false,
"view_count": 1250,
"created_at": "2024-01-20T10:30:00",
"updated_at": "2024-01-20T10:30:00"
}
],
"total": 50,
"page": 1,
"size": 10
}
```
**POST /api/v1/news/posts**
```json
// Request
{
"title": "飞点健康完成A轮融资",
"slug": "feidian-series-a",
"content": "# 飞点健康完成A轮融资\n\n今日...",
"content_type": "markdown",
"summary": "今日,飞点健康宣布完成数千万元A轮融资...",
"cover_image": "/uploads/covers/xxx.jpg",
"category_id": 1,
"is_draft": false
}
```
---
## 4. 前端设计
### 4.1 页面结构
```
/admin/news # 资讯管理首页(列表)
/admin/news/posts # 资讯列表
/admin/news/posts/new # 新建资讯
/admin/news/posts/:id/edit # 编辑资讯
/admin/news/categories # 栏目管理
/admin/images # 图片管理(可作为顶级菜单)
/news # 访客端新闻列表页
/news/:slug # 访客端新闻详情页
```
### 4.2 组件设计
#### 4.2.1 管理端组件
```
src/pages/admin/news/
├── NewsLayout.jsx # 新闻模块布局(侧边栏导航)
├── PostList.jsx # 资讯列表页
├── PostEdit.jsx # 资讯编辑页(双编辑器支持)
├── CategoryList.jsx # 栏目列表页
└── components/
├── MarkdownEditor.jsx # Markdown编辑器(复用blog)
├── HtmlEditor.jsx # HTML富文本编辑器
├── PostForm.jsx # 资讯表单(标题、栏目、封面等)
├── CategoryForm.jsx # 栏目表单
├── ImagePicker.jsx # 图片选择器
└── PostPreview.jsx # 文章预览组件
src/pages/admin/images/
├── ImageManager.jsx # 图片管理页(可作为独立模块)
└── components/
├── ImageUploader.jsx # 图片上传组件
├── ImageGrid.jsx # 图片网格展示
└── ImageDetail.jsx # 图片详情/编辑
```
#### 4.2.2 编辑器选型
| 格式 | 编辑器 | 特点 | 图片支持 |
|------|--------|------|----------|
| Markdown | react-markdown-editor-lite | 轻量、性能好 | 支持粘贴/拖拽上传 |
| HTML | TinyMCE 6 | 功能丰富、稳定 | 内置图片上传插件 |
**TinyMCE 配置要点:**
```javascript
{
plugins: 'image link media table code fullscreen',
toolbar: 'undo redo | formatselect | bold italic | alignleft aligncenter alignright | bullist numlist | image media link | table | code fullscreen',
images_upload_url: '/api/v1/images/upload',
images_upload_handler: customUploadHandler
}
```
### 4.3 路由配置
```javascript
// 添加到 AdminLayout 侧边栏
{
path: '/admin/news',
label: '新闻资讯',
icon: Newspaper,
children: [
{ path: '/admin/news/posts', label: '资讯管理' },
{ path: '/admin/news/categories', label: '栏目管理' }
]
}
// 独立图片管理(可作为顶级菜单)
{
path: '/admin/images',
label: '图片管理',
icon: Image
}
```
---
## 5. 复用代码清单
### 5.1 从 personal-blog 复用
| 组件/模块 | 源文件路径 | 目标路径 | 修改点 |
|-----------|-----------|----------|--------|
| 图片模型 | backend/models.py Image | backend/app/models/image.py | 添加 module 字段 |
| 图片上传API | backend/routers/images.py | backend/app/routers/images.py | 适配新路由前缀 |
| 图片管理页 | frontend/src/pages/admin/Images.jsx | frontend/src/pages/admin/images/ImageManager.jsx | 样式统一 |
| Markdown编辑器 | 无(需新增) | frontend/src/pages/admin/news/components/MarkdownEditor.jsx | - |
### 5.2 复用策略
1. **图片管理**:完全复用 blog 的图片表结构,添加 `module` 字段区分来源
2. **文件上传**:复用上传逻辑,统一存储到 `/uploads/news/`
3. **缩略图生成**:复用 PIL 缩略图生成逻辑
---
## 6. 访客端展示
### 6.1 新闻列表页 (/news)
- 顶部显示栏目筛选标签
- 列表展示:封面图、标题、摘要、发布时间、浏览量
- 支持分页加载
### 6.2 新闻详情页 (/news/:slug)
- 文章标题、发布时间、栏目
- 根据 content_type 渲染不同格式
- Markdown: 使用 react-markdown + remark-gfm
- HTML: 使用 dangerouslySetInnerHTML(需 XSS 过滤)
### 6.3 首页新闻模块联动
home_modules 表中 type=news 的模块,从 news_posts 表读取最新 N 条数据展示。
---
## 7. 实现步骤
### Phase 1: 数据库与后端 API(预计 2-3 天)
1. [ ] 创建数据库表(categories, posts, images)
2. [ ] 实现栏目管理 API
3. [ ] 实现资讯管理 API
4. [ ] 复用/改造图片上传 API
5. [ ] 编写 API 测试
### Phase 2: 管理端前端(预计 3-4 天)
1. [ ] 创建新闻模块路由和布局
2. [ ] 实现栏目管理页面
3. [ ] 实现 Markdown 编辑器组件
4. [ ] 实现 HTML 编辑器组件(TinyMCE 集成)
5. [ ] 实现资讯列表页
6. [ ] 实现资讯编辑页(双编辑器切换)
7. [ ] 实现图片管理页面
### Phase 3: 访客端与联调(预计 2 天)
1. [ ] 实现新闻列表页
2. [ ] 实现新闻详情页(支持 Markdown/HTML 渲染)
3. [ ] 联调首页新闻模块数据
4. [ ] 顶部菜单"新闻动态"链接配置
### Phase 4: 优化与测试(预计 1-2 天)
1. [ ] 图片懒加载优化
2. [ ] XSS 防护(HTML 内容过滤)
3. [ ] 移动端适配
4. [ ] 性能测试
---
## 8. 技术要点
### 8.1 XSS 防护
对于 HTML 格式的内容,必须做 XSS 过滤:
```python
# 后端存储前过滤(可选)
from bleach import clean
allowed_tags = ['p', 'br', 'strong', 'em', 'u', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
'ul', 'ol', 'li', 'a', 'img', 'table', 'thead', 'tbody', 'tr', 'td', 'th']
allowed_attrs = {'a': ['href', 'title'], 'img': ['src', 'alt', 'width', 'height']}
cleaned_html = clean(raw_html, tags=allowed_tags, attributes=allowed_attrs)
```
### 8.2 图片存储规范
```
uploads/
├── news/ # 新闻资讯图片
│ ├── 2024/01/ # 按年月组织
│ │ ├── xxx.jpg
│ │ └── thumbnails/ # 缩略图
│ └── ...
├── products/ # 产品图片
├── pages/ # 页面图片
└── common/ # 通用图片
```
### 8.3 slug 生成规则
```python
def generate_slug(title: str) -> str:
"""将标题转换为 URL 友好的 slug"""
# 1. 移除特殊字符
# 2. 空格替换为连字符
# 3. 转小写
# 4. 处理重复(添加数字后缀)
```
---
## 9. 扩展性考虑
### 9.1 未来可扩展功能
- [ ] 文章标签系统
- [ ] 文章评论功能
- [ ] 文章定时发布
- [ ] 文章版本历史
- [ ] 文章 SEO 元数据管理
- [ ] 多语言支持
### 9.2 图片管理升级
当前作为新闻模块子功能,后续可提升为系统级资源中心,支持:
- 图片分类/标签
- 批量上传
- 图片搜索
- 在线编辑(裁剪、滤镜)
---
## 10. 参考资源
### 10.1 编辑器文档
- TinyMCE React: https://www.tiny.cloud/docs/tinymce/6/react-cloud/
- react-markdown-editor-lite: https://github.com/HarryChen0506/react-markdown-editor-lite
### 10.2 代码参考
- personal-blog Markdown 编辑实现
- personal-blog 图片管理实现
---
*文档版本: 1.0*
*创建时间: 2026-04-20*
*作者: nanobot*