<think>我们正在构建一个完整的前后端分离的博客系统。由于项目规模较大,我将分步骤提供关键部分的代码和解释。
首先,我们需要创建Django后端项目,然后创建React前端项目。
步骤:
1. 创建Django项目并设置虚拟环境(使用Poetry)
2. 配置Django使用MySQL数据库
3. 创建Django应用(用户管理、博客、评论、搜索等)
4. 使用Django REST Framework构建API
5. 配置JWT认证
6. 配置Swagger生成API文档
7. 创建React前端项目,使用Vite、TypeScript、Ant Design和Redux Toolkit
8. 实现前端路由、页面和组件
9. 前后端联调
10. 部署方案
由于篇幅限制,我将提供关键部分的代码示例和架构设计。
一、后端项目设置
1. 使用Poetry初始化项目
```bash
poetry new blog_backend
cd blog_backend
poetry add django djangorestframework django-cors-headers mysqlclient drf_yasg djangorestframework-simplejwt pillow
```
2. 创建Django项目
```bash
poetry run django-admin startproject blog .
```
3. 创建应用
```bash
poetry run python manage.py startapp users
poetry run python manage.py startapp blog
poetry run python manage.py startapp comments
poetry run python manage.py startapp media
poetry run python manage.py startapp search
```
4. 配置数据库(MySQL)
在settings.py中配置:
```python
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'blogdb',
'USER': 'root',
'PASSWORD': 'yourpassword',
'HOST': 'localhost',
'PORT': '3306',
'OPTIONS': {
'charset': 'utf8mb4',
}
}
}
```
5. 配置Django REST Framework和JWT
在settings.py中添加:
```python
INSTALLED_APPS = [
...
'rest_framework',
'corsheaders',
'drf_yasg',
'users',
'blog',
...
]
MIDDLEWARE = [
...
'corsheaders.middleware.CorsMiddleware',
...
]
# 跨域设置
CORS_ORIGIN_ALLOW_ALL = True # 开发阶段可以允许所有,生产环境应设置具体域名
# DRF配置
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_simplejwt.authentication.JWTAuthentication',
),
}
# JWT设置
from datetime import timedelta
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=60),
'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
}
```
6. 用户模型设计(users/models.py)
扩展Django的AbstractUser:
```python
from django.db import models
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
bio = models.TextField(max_length=500, blank=True)
avatar = models.ImageField(upload_to='avatars/', blank=True, null=True)
role = models.CharField(max_length=20, choices=[
('user', '普通用户'),
('author', '作者'),
('admin', '管理员'),
], default='user')
class Meta:
verbose_name = '用户'
verbose_name_plural = verbose_name
def __str__(self):
return self.username
```
然后在settings.py中设置AUTH_USER_MODEL:
```python
AUTH_USER_MODEL = 'users.User'
```
7. 用户注册和登录API(users/views.py)
使用DRF的APIView:
```python
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .serializers import UserRegisterSerializer, UserLoginSerializer
from django.contrib.auth import authenticate
from rest_framework_simplejwt.tokens import RefreshToken
class UserRegisterView(APIView):
def post(self, request):
serializer = UserRegisterSerializer(data=request.data)
if serializer.is_valid():
user = serializer.save()
# 创建JWT token
refresh = RefreshToken.for_user(user)
return Response({
'refresh': str(refresh),
'access': str(refresh.access_token),
}, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class UserLoginView(APIView):
def post(self, request):
serializer = UserLoginSerializer(data=request.data)
if serializer.is_valid():
username = serializer.validated_data['username']
password = serializer.validated_data['password']
user = authenticate(username=username, password=password)
if user:
refresh = RefreshToken.for_user(user)
return Response({
'refresh': str(refresh),
'access': str(refresh.access_token),
})
else:
return Response({'error': 'Invalid Credentials'}, status=status.HTTP_401_UNAUTHORIZED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
```
8. 序列化器(users/serializers.py)
```python
from rest_framework import serializers
from .models import User
class UserRegisterSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True)
class Meta:
model = User
fields = ['username', 'email', 'password', 'bio', 'avatar']
def create(self, validated_data):
user = User.objects.create_user(
username=validated_data['username'],
email=validated_data['email'],
password=validated_data['password'],
bio=validated_data.get('bio', ''),
avatar=validated_data.get('avatar', None)
)
return user
class UserLoginSerializer(serializers.Serializer):
username = serializers.CharField()
password = serializers.CharField()
```
9. 配置URL(users/urls.py)
```python
from django.urls import path
from .views import UserRegisterView, UserLoginView
urlpatterns = [
path('register/', UserRegisterView.as_view(), name='register'),
path('login/', UserLoginView.as_view(), name='login'),
]
```
10. 在项目总路由中引入(blog/urls.py)
```python
from django.urls import path, include
urlpatterns = [
...
path('api/users/', include('users.urls')),
...
]
```
以上是用户注册和登录的API实现。接下来,我们设计博客文章模型。
二、博客文章模块(blog应用)
1. 模型设计(blog/models.py)
```python
from django.db import models
from django.contrib.auth import get_user_model
from django.urls import reverse
from django.utils.text import slugify
User = get_user_model()
class Category(models.Model):
name = models.CharField(max_length=50)
def __str__(self):
return self.name
class Tag(models.Model):
name = models.CharField(max_length=50)
def __str__(self):
return self.name
class Post(models.Model):
title = models.CharField(max_length=200)
slug = models.SlugField(max_length=200, unique=True, blank=True)
content = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
author = models.ForeignKey(User, on_delete=models.CASCADE)
category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True)
tags = models.ManyToManyField(Tag)
is_published = models.BooleanField(default=False)
published_date = models.DateTimeField(null=True, blank=True)
views = models.PositiveIntegerField(default=0)
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)
super().save(*args, **kwargs)
def get_absolute_url(self):
return reverse('post-detail', args=[str(self.slug)])
def __str__(self):
return self.title
class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')
author = models.ForeignKey(User, on_delete=models.CASCADE)
content = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
parent = models.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='replies')
likes = models.PositiveIntegerField(default=0)
dislikes = models.PositiveIntegerField(default=0)
class Meta:
ordering = ['created_at']
def __str__(self):
return f'Comment by {self.author} on {self.post}'
```
注意:这里将评论设计为自关联,以实现多级评论。
2. 序列化器(blog/serializers.py)
```python
from rest_framework import serializers
from .models import Post, Category, Tag, Comment
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = ['id', 'name']
class TagSerializer(serializers.ModelSerializer):
class Meta:
model = Tag
fields = ['id', 'name']
class CommentSerializer(serializers.ModelSerializer):
author = serializers.ReadOnlyField(source='author.username')
replies = serializers.SerializerMethodField()
class Meta:
model = Comment
fields = ['id', 'author', 'content', 'created_at', 'parent', 'replies', 'likes', 'dislikes']
def get_replies(self, obj):
if obj.replies.exists():
return CommentSerializer(obj.replies.all(), many=True).data
return []
class PostSerializer(serializers.ModelSerializer):
author = serializers.ReadOnlyField(source='author.username')
category = CategorySerializer(read_only=True)
tags = TagSerializer(many=True, read_only=True)
class Meta:
model = Post
fields = ['id', 'title', 'slug', 'content', 'created_at', 'updated_at', 'author', 'category', 'tags', 'is_published', 'published_date', 'views']
```
3. 视图(blog/views.py)
使用DRF的视图集(ViewSet)和ModelViewSet:
```python
from rest_framework import viewsets
from .models import Post, Comment
from .serializers import PostSerializer, CommentSerializer
from rest_framework.permissions import IsAuthenticatedOrReadOnly, IsAuthenticated
from .permissions import IsOwnerOrReadOnly
class PostViewSet(viewsets.ModelViewSet):
queryset = Post.objects.all()
serializer_class = PostSerializer
permission_classes = [IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly]
def perform_create(self, serializer):
serializer.save(author=self.request.user)
class CommentViewSet(viewsets.ModelViewSet):
queryset = Comment.objects.all()
serializer_class = CommentSerializer
permission_classes = [IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly]
def perform_create(self, serializer):
serializer.save(author=self.request.user)
```
4. 权限(blog/permissions.py)
```python
from rest_framework import permissions
class IsOwnerOrReadOnly(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
return True
return obj.author == request.user
```
5. 路由(blog/urls.py)
```python
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from . import views
router = DefaultRouter()
router.register(r'posts', views.PostViewSet)
router.register(r'comments', views.CommentViewSet)
urlpatterns = [
path('', include(router.urls)),
]
```
然后在项目总路由中包含它。
三、数据库迁移
执行迁移命令:
```bash
poetry run python manage.py makemigrations
poetry run python manage.py migrate
```
四、配置媒体文件
在settings.py中:
```python
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
```
在urls.py中添加:
```python
from django.conf import settings
from django.conf.urls.static import static
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
```
五、配置Swagger
在项目总urls.py中添加:
```python
from django.urls import path
from rest_framework import permissions
from drf_yasg.views import get_schema_view
from drf_yasg import openapi
schema_view = get_schema_view(
openapi.Info(
title="Blog API",
default_version='v1',
description="API documentation for the Blog project",
),
public=True,
permission_classes=[permissions.AllowAny],
)
urlpatterns = [
...
path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
...
]
```
六、前端项目创建(使用Vite和React)
1. 创建项目
```bash
npm create vite@latest blog_frontend -- --template react-ts
cd blog_frontend
npm install
npm install antd @ant-design/icons axios react-router-dom@6 @reduxjs/toolkit react-redux
```
2. 设置代理(vite.config.ts)
在vite.config.ts中添加代理,解决跨域问题:
```javascript
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
server: {
proxy: {
'/api': {
target: 'http://localhost:8000',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
}
}
})
```
3. 配置Redux Toolkit
创建store.ts:
```typescript
import { configureStore } from '@reduxjs/toolkit'
import authReducer from './features/authSlice'
export const store = configureStore({
reducer: {
auth: authReducer
}
})
export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch
```
创建authSlice.ts:
```typescript
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
interface AuthState {
user: string | null
token: string | null
}
const initialState: AuthState = {
user: null,
token: null
}
const authSlice = createSlice({
name: 'auth',
initialState,
reducers: {
setCredentials: (state, action: PayloadAction<{ user: string, token: string }>) => {
state.user = action.payload.user
state.token = action.payload.token
},
logout: (state) => {
state.user = null
state.token = null
}
}
})
export const { setCredentials, logout } = authSlice.actions
export default authSlice.reducer
```
4. 创建登录页面(Login.tsx)
使用Ant Design组件:
```tsx
import { LockOutlined, UserOutlined } from '@ant-design/icons'
import { Button, Checkbox, Form, Input } from 'antd'
import React from 'react'
import { useDispatch } from 'react-redux'
import { setCredentials } from './features/authSlice'
import axios from 'axios'
const Login: React.FC = () => {
const dispatch = useDispatch()
const onFinish = async (values: any) => {
try {
const response = await axios.post('/api/users/login/', {
username: values.username,
password: values.password
})
const { access: token } = response.data
dispatch(setCredentials({ user: values.username, token }))
// 保存token到localStorage
localStorage.setItem('token', token)
} catch (error) {
console.error('Login failed:', error)
}
}
return (
<Form
name="normal_login"
initialValues={{ remember: true }}
onFinish={onFinish}
>
<Form.Item
name="username"
rules={[{ required: true, message: 'Please input your Username!' }]}
>
<Input prefix={<UserOutlined />} placeholder="Username" />
</Form.Item>
<Form.Item
name="password"
rules={[{ required: true, message: 'Please input your Password!' }]}
>
<Input
prefix={<LockOutlined />}
type="password"
placeholder="Password"
/>
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit" block>
Log in
</Button>
</Form.Item>
</Form>
)
}
export default Login
```
由于项目功能模块众多,无法在此一一展示所有代码。以上提供了关键部分的代码示例。
七、部署方案
1. 后端部署:可以使用Gunicorn + Nginx部署Django项目
2. 前端部署:使用Vite构建,将生成的dist目录部署到Nginx服务器
八、数据库设计(MySQL)
根据前面的模型设计,生成数据库表。建议使用InnoDB引擎,并为常用查询字段添加索引,如文章的标题、创建时间,用户的用户名等。
九、关键技术点和解决方案
- 前后端分离:使用Django REST Framework提供API,前端使用React独立开发
- JWT认证:使用simplejwt库实现,前端在请求头中添加Authorization: Bearer <token>
- 评论树:通过自关联模型实现多级评论,序列化时递归生成嵌套结构
- 热力图:使用ECharts或D3.js实现,前后端配合统计数据
十、完整开发流程
1. 克隆项目
2. 后端:使用Poetry安装依赖,配置MySQL,执行迁移,运行开发服务器
3. 前端:npm安装依赖,运行开发服务器
4. 访问前端地址(如http://localhost:5173)进行开发
由于项目需求详细且复杂,以上是一个基础框架。在实际开发中,需要根据需求逐步完善各模块功能。
§§相关问题§§:
1. 如何实现用户贡献热力图?
2. 如何在前端实现多级评论的展示?
3. 如何优化Django的查询性能?
4. 如何进行前后端的API联调?
</think>以下是为您设计的完整前后端分离博客项目解决方案。由于项目规模较大,我将分模块展示核心代码和实现思路:
### 1. 项目结构
```
blog-project/
├── backend/ # Django 后端
│ ├── blog/ # 主应用
│ ├── users/ # 用户管理
│ ├── media/ # 媒体管理
│ ├── search/ # 搜索模块
│ ├── core/ # 核心配置
│ └── manage.py
├── frontend/ # React 前端
│ ├── src/
│ │ ├── features/ # 功能模块
│ │ ├── components/ # 通用组件
│ │ ├── api/ # API 服务
│ │ └── App.tsx
│ └── vite.config.ts
└── docker-compose.yml # 容器化部署
```
### 2. 数据库设计 (MySQL)
```sql
-- 用户表
CREATE TABLE `users` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`username` VARCHAR(150) UNIQUE NOT NULL,
`email` VARCHAR(254) UNIQUE NOT NULL,
`password` VARCHAR(128) NOT NULL,
`avatar` VARCHAR(200) NULL,
`role` ENUM('user', 'author', 'admin') DEFAULT 'user',
`last_login` DATETIME NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 博客文章表
CREATE TABLE `posts` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`title` VARCHAR(200) NOT NULL,
`slug` VARCHAR(200) UNIQUE NOT NULL,
`content` LONGTEXT NOT NULL,
`author_id` INT NOT NULL,
`status` ENUM('draft', 'published') DEFAULT 'draft',
`created_at` DATETIME NOT NULL,
`updated_at` DATETIME NOT NULL,
FOREIGN KEY (`author_id`) REFERENCES `users`(`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 评论表(支持多级回复)
CREATE TABLE `comments` (
`id` BIGINT AUTO_INCREMENT PRIMARY KEY,
`post_id` INT NOT NULL,
`user_id` INT NOT NULL,
`parent_id` BIGINT NULL,
`content` TEXT NOT NULL,
`created_at` DATETIME NOT NULL,
FOREIGN KEY (`post_id`) REFERENCES `posts`(`id`),
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`),
FOREIGN KEY (`parent_id`) REFERENCES `comments`(`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
```
### 3. 后端核心实现 (Django)
#### 用户认证模块 (users/views.py)
```python
from rest_framework.views import APIView
from rest_framework_simplejwt.tokens import RefreshToken
from rest_framework import status
from .serializers import UserRegisterSerializer
class RegisterView(APIView):
def post(self, request):
serializer = UserRegisterSerializer(data=request.data)
if serializer.is_valid():
user = serializer.save()
# 生成JWT令牌
refresh = RefreshToken.for_user(user)
return Response({
'access': str(refresh.access_token),
'refresh': str(refresh)
}, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class UserActivityView(APIView):
authentication_classes = [JWTAuthentication]
def get(self, request):
# 实现用户贡献热力图数据
user = request.user
activity = UserActivity.objects.filter(user=user).annotate(
week=ExtractWeek('date'),
weekday=ExtractWeekDay('date')
).values('week', 'weekday').annotate(count=Count('id'))
return Response({
"activity_map": activity,
"username": user.username
})
```
#### 博客文章API (blog/views.py)
```python
class PostViewSet(viewsets.ModelViewSet):
queryset = Post.objects.select_related('author').prefetch_related('tags')
serializer_class = PostSerializer
filterset_class = PostFilter
permission_classes = [IsAuthenticatedOrReadOnly]
def perform_create(self, serializer):
serializer.save(author=self.request.user)
@action(detail=True, methods=['POST'])
def upload_image(self, request, pk=None):
# 富文本编辑器图片上传
image = request.FILES.get('image')
img = Image.open(image)
img = img.convert('RGB')
img.thumbnail((1200, 1200))
output = BytesIO()
img.save(output, format='JPEG', quality=85)
output.seek(0)
image_file = InMemoryUploadedFile(
output, 'ImageField', f"{uuid4()}.jpg",
'image/jpeg', sys.getsizeof(output), None
)
media = Media.objects.create(
file=image_file,
user=request.user,
media_type='image'
)
return Response({
'url': media.file.url
}, status=HTTP_201_CREATED)
```
### 4. 前端核心实现 (React + TypeScript)
#### API服务层 (frontend/src/api/client.ts)
```typescript
import axios, { AxiosRequestConfig } from 'axios';
const api = axios.create({
baseURL: import.meta.env.VITE_API_URL,
});
// JWT 认证拦截器
api.interceptors.request.use(config => {
const token = localStorage.getItem('access_token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
// 响应拦截器
api.interceptors.response.use(
response => response,
async error => {
const originalRequest = error.config;
if (error.response.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
const refreshToken = localStorage.getItem('refresh_token');
const { data } = await api.post('/auth/token/refresh/', { refresh: refreshToken });
localStorage.setItem('access_token', data.access);
return api(originalRequest);
}
return Promise.reject(error);
}
);
export default api;
```
#### 用户热力图组件 (frontend/src/components/ActivityHeatmap.tsx)
```tsx
import { Tooltip } from 'antd';
import { useEffect, useState } from 'react';
const ActivityHeatmap = () => {
const [activities, setActivities] = useState<Record<string, number>>({});
useEffect(() => {
api.get('/user/activity/').then(res => {
const map: Record<string, number> = {};
res.data.activity_map.forEach((item: any) => {
map[`${item.week}-${item.weekday}`] = item.count;
});
setActivities(map);
});
}, []);
const renderGrid = () => {
const grids = [];
for (let week = 1; week <= 54; week++) {
for (let day = 1; day <= 7; day++) {
const key = `${week}-${day}`;
const count = activities[key] || 0;
// 根据活动次数计算颜色深浅
const colorIntensity = count > 0 ? Math.min(4, Math.floor(count / 3)) : 0;
const color = `bg-green-${colorIntensity > 0 ? 300 + colorIntensity * 100 : 100}`;
grids.push(
<Tooltip
key={key}
title={`Week ${week}, Day ${day}: ${count} activities`}
>
<div
className={`w-3 h-3 m-0.5 ${color} rounded-sm hover:border hover:border-gray-500`}
/>
</Tooltip>
);
}
}
return grids;
};
return (
<div className="flex flex-wrap max-w-4xl">
{renderGrid()}
</div>
);
};
```
### 5. 关键技术解决方案
#### JWT 认证流程
```mermaid
sequenceDiagram
participant F as Frontend
participant B as Backend
F->>B: POST /auth/login/ (credentials)
B-->>F: {access, refresh} tokens
F->>B: API请求 (Authorization: Bearer <access>)
alt Token过期
B-->>F: 401 Unauthorized
F->>B: POST /auth/token/refresh/ (refresh token)
B-->>F: 新的access token
F->>B: 重试原始请求
end
```
#### 性能优化策略
1. **数据库层**:
- 使用`select_related`和`prefetch_related`减少查询次数
- 添加复合索引(如用户活动表的(date, user_id))
2. **API层**:
- 使用Django Cache Framework缓存频繁访问数据
```python
from django.core.cache import cache
def get_popular_posts():
key = 'popular_posts'
posts = cache.get(key)
if not posts:
posts = Post.objects.filter(status='published') \
.annotate(like_count=Count('likes')) \
.order_by('-like_count')[:10]
cache.set(key, posts, timeout=60*15) # 15分钟缓存
return posts
```
3. **前端优化**:
- 使用React.lazy进行路由懒加载
```tsx
const Editor = lazy(() => import('./components/RichTextEditor'));
<Suspense fallback={<Spin />}>
<Editor />
</Suspense>
```
### 6. 部署方案 (Docker)
```yaml
# docker-compose.yml
version: '3.8'
services:
db:
image: mysql:8.4
environment:
MYSQL_DATABASE: blogdb
MYSQL_USER: bloguser
MYSQL_PASSWORD: securepass
MYSQL_ROOT_PASSWORD: rootpass
volumes:
- mysql_data:/var/lib/mysql
backend:
build: ./backend
command: gunicorn core.wsgi:application --bind 0.0.0.0:8000
volumes:
- ./backend:/app
- media_volume:/app/media
ports:
- "8000:8000"
depends_on:
- db
frontend:
build:
context: ./frontend
dockerfile: Dockerfile
ports:
- "5173:80"
depends_on:
- backend
volumes:
mysql_data:
media_volume:
```
### 7. 完整开发流程
1. **环境准备**:
```bash
# 后端
poetry install
python manage.py migrate
python manage.py runserver
# 前端
npm install
npm run dev
```
2. **测试数据生成**:
```python
# 使用django-seed生成测试数据
from django_seed import Seed
seeder = Seed.seeder()
seeder.add_entity(User, 10)
seeder.add_entity(Post, 50)
seeder.execute()
```
3. **API文档访问**:
```
http://localhost:8000/swagger/
```
4. **生产部署**:
```bash
docker-compose up -d --build
```
### 8. 关键技术点
1. **富文本编辑器**:使用Quill.js封装React组件
2. **深度评论系统**:使用MPTT算法实现多级评论
3. **实时搜索**:Elasticsearch集成实现模糊匹配
4. **主题切换**:CSS变量+React Context实现
```tsx
const ThemeContext = createContext<ThemeContextType>({
darkMode: false,
toggleTheme: () => {}
});
const ThemeProvider = ({children}: Props) => {
const [darkMode, setDarkMode] = useState(false);
useEffect(() => {
// 应用CSS变量
document.documentElement.style.setProperty(
'--bg-primary',
darkMode ? '#1a1a1a' : '#ffffff'
);
}, [darkMode]);
return (
<ThemeContext.Provider value={{
darkMode,
toggleTheme: () => setDarkMode(!darkMode)
}}>
{children}
</ThemeContext.Provider>
);
};
```
5. **贡献热力图**:D3.js + 后端聚合计算
6. **媒体处理**:使用Pillow进行图片压缩和格式转换