docs: 整理文档结构并创建索引(任务 2.3/20)

This commit is contained in:
张翔
2026-04-12 16:24:51 +08:00
parent 1f52d47ed5
commit 5cd7d48bf2
33 changed files with 1140 additions and 1176 deletions
+164
View File
@@ -0,0 +1,164 @@
# 联系方式配置说明
## 📋 联系方式总结
### 实际联系方式(对外)
| 联系类型 | 邮箱 | 用途 |
|----------|------|------|
| **运维告警** | ops@novalon.cn | 监控告警、系统故障通知 |
| **业务咨询** | contact@novalon.cn | 用户联系、业务咨询、表单提交 |
### 系统内部配置(不对)
| 配置项 | 邮箱 | 用途 |
|--------|------|------|
| **管理员账号** | contact@novalon.cn | CMS后台登录、系统管理 |
| **公司邮箱** | contact@novalon.cn | 接收联系表单邮件 |
| **Resend API** | re_72PzbVrr_DiwTnB1ZDT7TyqCsgLoAfKfU | 邮件发送服务 |
## 📧 配置文件更新
### 1. 生产环境配置
文件: `.env.production`
```env
# 管理员账号(CMS后台登录)
ADMIN_EMAIL=contact@novalon.cn
# 公司邮箱(接收联系表单邮件)
COMPANY_EMAIL=contact@novalon.cn
# Resend API(邮件发送服务)
RESEND_API_KEY=re_72PzbVrr_DiwTnB1ZDT7TyqCsgLoAfKfU
```
### 2. 测试配置更新
文件: `e2e/global-setup.ts`
```typescript
// 测试登录账号
await page.locator('#email').fill('contact@novalon.cn');
```
### 3. 文档更新
所有文档已更新,移除了不存在的"技术支持"联系方式。
## 📊 监控和告警配置
### Sentry 错误监控
- **告警邮箱**: ops@novalon.cn
- **告警类型**: Critical Errors
- **响应时间**: 立即
### UptimeRobot 可用性监控
- **告警邮箱**: ops@novalon.cn
- **告警类型**: Down, Up, SSL Expiry
- **监控频率**: 5分钟
### Google Analytics 访问统计
- **测量 ID**: G-LGTLCR15KM
- **追踪类型**: 用户行为、页面浏览、事件追踪
## 📝 业务流程
### 用户联系流程
1. **用户访问联系页面**
- 填写联系表单
- 提交表单
2. **系统处理**
- 表单提交到 `/api/contact`
- 使用 Resend API 发送邮件
- 邮件发送到: contact@novalon.cn
3. **管理员处理**
- 管理员登录: contact@novalon.cn
- 查看收到的邮件
- 回复用户咨询
### 系统监控流程
1. **错误发生**
- Sentry 捕获错误
- 发送告警到: ops@novalon.cn
2. **网站故障**
- UptimeRobot 检测到故障
- 发送告警到: ops@novalon.cn
3. **运维响应**
- 运维团队收到告警
- 检查系统状态
- 修复问题
- 通知相关人员
## 🔐 安全考虑
### 账号分离
- **管理员账号**: contact@novalon.cn(仅用于系统管理)
- **运维告警**: ops@novalon.cn(用于系统监控)
- **业务咨询**: contact@novalon.cn(用于用户联系)
### 权限控制
- 管理员账号仅限内部使用
- 不对外公开管理员登录信息
- 定期更换密码
## 📞 联系方式使用指南
### 对于用户
- **业务咨询**: contact@novalon.cn
- 通过网站联系表单提交
- 邮件会在 24 小时内回复
### 对于运维团队
- **系统告警**: ops@novalon.cn
- 监控系统自动发送告警
- 需要立即响应和处理
### 对于管理员
- **系统登录**: contact@novalon.cn
- 访问 CMS 管理后台
- 管理网站内容和用户
## ✅ 配置检查清单
- [x] 生产环境配置更新
- [x] 测试配置更新
- [x] 文档联系方式统一
- [x] 监控告警配置
- [x] 邮件服务配置
- [x] 账号权限分离
## 📚 相关文档
- [轻量级监控配置](LIGHTWEIGHT_MONITORING.md)
- [生产部署指南](PRODUCTION_DEPLOYMENT_LIGHTWEIGHT.md)
- [Google Analytics 集成](GOOGLE_ANALYTICS_SETUP.md)
- [项目 README](../README.md)
## 🎯 总结
现在所有联系方式已经统一配置完成:
1. **对外联系**: contact@novalon.cn
- 用户联系表单
- 业务咨询
- 管理员登录
2. **运维告警**: ops@novalon.cn
- Sentry 错误告警
- UptimeRobot 可用性告警
- 系统故障通知
3. **邮件服务**: Resend API
- API Key: re_72PzbVrr_DiwTnB1ZDT7TyqCsgLoAfKfU
- 发件人: alertmanager@novalon.cn / contact@novalon.cn
- SMTP: smtp.resend.com:587
所有配置文件和文档都已经更新完成,联系方式现在统一且准确!
+512
View File
@@ -0,0 +1,512 @@
# API版本控制指南
## 概述
API版本控制是API设计的重要部分,它允许我们在不破坏现有客户端的情况下演进API。本项目采用URL路径版本控制策略。
## 版本控制策略
### URL路径版本控制
使用URL路径中的版本号来区分不同版本的API:
```
/api/v1/endpoint # 版本1
/api/v2/endpoint # 版本2
```
**优点**
- ✅ 清晰明了,易于理解
- ✅ 便于缓存和路由
- ✅ 支持多版本并存
- ✅ 客户端易于使用
**缺点**
- ❌ URL较长
- ❌ 需要维护多个版本
### 版本命名规则
- **主版本号**`v1`, `v2`, `v3`...
- **格式**`/api/v{major}/`
- **示例**
- `/api/v1/content`
- `/api/v1/admin/users`
## 目录结构
### 当前结构(向后兼容)
```
src/app/api/
├── admin/
│ ├── config/
│ ├── content/
│ ├── upload/
│ └── users/
├── auth/
├── config/
├── content/
├── docs/
└── health/
```
### 版本化结构(推荐)
```
src/app/api/
├── v1/ # 版本1 API
│ ├── admin/
│ │ ├── config/
│ │ ├── content/
│ │ ├── upload/
│ │ └── users/
│ ├── auth/
│ ├── config/
│ ├── content/
│ └── health/
├── admin/ # 向后兼容(重定向到v1)
├── auth/
├── config/
├── content/
├── docs/ # OpenAPI文档(无版本)
└── health/
```
## 实施步骤
### 步骤1:创建版本化API
#### 创建v1目录
```bash
mkdir -p src/app/api/v1
```
#### 迁移现有API
将现有API复制到v1目录:
```bash
# 复制admin API
cp -r src/app/api/admin src/app/api/v1/
# 复制其他API
cp -r src/app/api/auth src/app/api/v1/
cp -r src/app/api/config src/app/api/v1/
cp -r src/app/api/content src/app/api/v1/
cp -r src/app/api/health src/app/api/v1/
```
### 步骤2:更新API路由
#### 更新v1 API路由
在v1版本的API中,更新路由路径:
```typescript
// src/app/api/v1/admin/content/route.ts
/**
* @openapi
* /api/v1/admin/content:
* get:
* tags:
* - Admin
* - Content
* summary: 获取内容列表 (v1)
* description: 管理员获取内容列表,支持分页、筛选和搜索
* operationId: getAdminContentV1
* ...
*/
export async function GET(request: NextRequest) {
// 实现代码
}
```
### 步骤3:创建向后兼容层
#### 创建重定向中间件
```typescript
// src/middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const { pathname } = request.nextUrl;
// 如果访问旧API路径,重定向到v1版本
const legacyApiPaths = [
'/api/admin',
'/api/auth',
'/api/config',
'/api/content',
'/api/health',
];
const isLegacyApi = legacyApiPaths.some(path =>
pathname.startsWith(path) && !pathname.includes('/v1/')
);
if (isLegacyApi) {
const url = request.nextUrl.clone();
url.pathname = pathname.replace('/api/', '/api/v1/');
// 返回重定向响应(可选:也可以内部重写)
// return NextResponse.redirect(url);
// 或者内部重写(URL不变,但使用新路径)
return NextResponse.rewrite(url);
}
return NextResponse.next();
}
export const config = {
matcher: '/api/:path*',
};
```
### 步骤4:更新客户端代码
#### 更新API客户端
```typescript
// src/lib/api-client.ts
const API_VERSION = 'v1';
const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || '';
export class ApiClient {
private baseUrl: string;
constructor(version: string = API_VERSION) {
this.baseUrl = `${API_BASE_URL}/api/${version}`;
}
async get(endpoint: string, options?: RequestInit) {
const response = await fetch(`${this.baseUrl}${endpoint}`, {
...options,
method: 'GET',
});
return response.json();
}
async post(endpoint: string, data: any, options?: RequestInit) {
const response = await fetch(`${this.baseUrl}${endpoint}`, {
...options,
method: 'POST',
headers: {
'Content-Type': 'application/json',
...options?.headers,
},
body: JSON.stringify(data),
});
return response.json();
}
}
// 使用示例
const apiClient = new ApiClient('v1');
const content = await apiClient.get('/admin/content');
```
## 版本生命周期
### 版本状态
| 状态 | 描述 | 持续时间 |
|------|------|----------|
| **Current** | 当前推荐版本 | 无限期 |
| **Supported** | 仍受支持,但不推荐新功能 | 6-12个月 |
| **Deprecated** | 即将废弃,计划移除 | 3-6个月 |
| **Sunset** | 已移除,不再可用 | - |
### 版本废弃流程
1. **公告**:提前6个月通知废弃计划
2. **警告**:在响应头中添加`Deprecation``Sunset`
3. **迁移期**:提供迁移指南和工具
4. **移除**:在预定日期移除旧版本
#### 添加废弃头
```typescript
// src/app/api/v1/admin/content/route.ts
export async function GET(request: NextRequest) {
const response = NextResponse.json(data);
// 添加废弃警告
response.headers.set('Deprecation', 'true');
response.headers.set('Sunset', 'Sat, 31 Dec 2026 23:59:59 GMT');
response.headers.set('Link', '</api/v2/admin/content>; rel="successor-version"');
return response;
}
```
## 版本间差异处理
### 向后兼容的变更
以下变更不需要增加主版本号:
- ✅ 添加新的可选参数
- ✅ 添加新的响应字段
- ✅ 添加新的端点
- ✅ 修复bug
### 需要新版本的变更
以下变更需要增加主版本号:
- ❌ 移除或重命名端点
- ❌ 移除或重命名请求/响应字段
- ❌ 修改必填参数
- ❌ 修改认证方式
- ❌ 修改错误响应格式
## 多版本并存示例
### 场景:修改内容API响应格式
#### v1版本(旧)
```typescript
// src/app/api/v1/admin/content/route.ts
/**
* @openapi
* /api/v1/admin/content:
* get:
* responses:
* 200:
* content:
* application/json:
* schema:
* type: object
* properties:
* items:
* type: array
* pagination:
* type: object
*/
export async function GET(request: NextRequest) {
const items = await db.select().from(content);
return NextResponse.json({
items,
pagination: { page: 1, limit: 20, total: items.length },
});
}
```
#### v2版本(新)
```typescript
// src/app/api/v2/admin/content/route.ts
/**
* @openapi
* /api/v2/admin/content:
* get:
* responses:
* 200:
* content:
* application/json:
* schema:
* type: object
* properties:
* data:
* type: array
* meta:
* type: object
*/
export async function GET(request: NextRequest) {
const items = await db.select().from(content);
return NextResponse.json({
data: items, // 改名:items -> data
meta: { // 改名:pagination -> meta
page: 1,
limit: 20,
total: items.length,
hasNext: items.length === 20,
},
});
}
```
## 测试策略
### 版本兼容性测试
```typescript
// src/app/api/__tests__/version-compatibility.test.ts
import { describe, it, expect } from '@jest/globals';
describe('API Version Compatibility', () => {
it('should return same data structure in v1 and v2', async () => {
const v1Response = await fetch('/api/v1/admin/content');
const v2Response = await fetch('/api/v2/admin/content');
const v1Data = await v1Response.json();
const v2Data = await v2Response.json();
// 验证数据一致性
expect(v1Data.items.length).toBe(v2Data.data.length);
expect(v1Data.pagination.total).toBe(v2Data.meta.total);
});
it('should redirect legacy API to v1', async () => {
const response = await fetch('/api/admin/content');
expect(response.url).toContain('/api/v1/admin/content');
});
});
```
## 文档更新
### 更新OpenAPI文档
```typescript
// src/app/api/docs/route.ts
const options = {
definition: {
openapi: '3.0.0',
info: {
title: '睿新致远 API',
version: '1.0.0',
description: `
## API版本
当前支持以下版本:
- **v1** (Current): 当前推荐版本
- **v2** (Beta): 测试版本,包含新功能
### 版本状态
| 版本 | 状态 | 发布日期 | 废弃日期 |
|------|------|----------|----------|
| v1 | Current | 2024-01-01 | - |
| v2 | Beta | 2024-06-01 | - |
`,
},
servers: [
{
url: '/api/v1',
description: 'API v1 (Current)',
},
{
url: '/api/v2',
description: 'API v2 (Beta)',
},
],
},
};
```
## 最佳实践
### ✅ 推荐做法
1. **提前规划版本策略**
- 在API设计初期就考虑版本控制
- 为未来变更预留空间
2. **保持向后兼容**
- 尽可能保持旧版本可用
- 提供充足的迁移时间
3. **清晰的文档**
- 明确标注版本差异
- 提供迁移指南
4. **版本废弃通知**
- 提前通知用户
- 使用HTTP头传递废弃信息
### ❌ 避免的做法
1. **不要频繁变更主版本**
- 主版本变更应该谨慎
- 考虑向后兼容的替代方案
2. **不要突然移除旧版本**
- 给用户足够的迁移时间
- 提供迁移工具和文档
3. **不要忽略版本测试**
- 确保多版本并存时功能正常
- 测试版本兼容性
## 监控和分析
### 版本使用统计
```typescript
// src/lib/api-analytics.ts
export async function trackApiVersion(request: NextRequest) {
const { pathname } = request.nextUrl;
const version = pathname.match(/\/api\/v(\d+)\//)?.[1] || 'legacy';
// 发送到分析服务
await analytics.track('api_request', {
version,
endpoint: pathname,
method: request.method,
timestamp: new Date().toISOString(),
});
}
```
### 版本使用报告
定期生成版本使用报告:
```markdown
## API版本使用报告(2024年6月)
### 请求分布
| 版本 | 请求数 | 占比 | 趋势 |
|------|--------|------|------|
| v1 | 150,000 | 75% | ↓ |
| v2 | 50,000 | 25% | ↑ |
### 废弃版本使用
| 版本 | 请求数 | 废弃日期 | 建议 |
|------|--------|----------|------|
| legacy | 1,000 | 2024-12-31 | 尽快迁移到v1 |
```
## 参考资源
- [API版本控制最佳实践](https://www.postman.com/api-platform/api-versioning/)
- [REST API版本控制](https://restfulapi.net/versioning/)
- [语义化版本控制](https://semver.org/)
- [HTTP废弃头规范](https://datatracker.ietf.org/doc/html/rfc8594)
## 总结
API版本控制已集成到项目中,提供了:
**清晰的版本管理**
**向后兼容支持**
**平滑的版本迁移**
**版本使用监控**
**完善的文档支持**
通过合理的版本控制策略,可以:
- 保护现有客户端
- 安全地演进API
- 提供良好的开发者体验
- 维护API的长期健康
+382
View File
@@ -0,0 +1,382 @@
# API 文档
## API 概述
项目使用 Next.js API Routes 实现服务端接口,主要用于处理联系表单提交等后端逻辑。
## 基础信息
- **基础 URL**: `/api`
- **内容类型**: `application/json`
- **字符编码**: `UTF-8`
## 接口列表
### 1. 联系表单 API
#### 提交联系表单
**接口地址**
```
POST /api/contact
```
**请求头**
| 参数 | 类型 | 必填 | 描述 |
|------|------|------|------|
| Content-Type | string | 是 | application/json |
**请求参数**
| 参数 | 类型 | 必填 | 描述 |
|------|------|------|------|
| name | string | 是 | 联系人姓名 |
| email | string | 是 | 联系人邮箱 |
| phone | string | 否 | 联系人电话 |
| subject | string | 是 | 咨询主题 |
| message | string | 是 | 咨询内容 |
| website | string | 否 | 蜜罐字段(用于反垃圾) |
| submitTime | string | 否 | 表单提交时间戳 |
| mathHash | string | 否 | 数学验证码哈希 |
| mathTimestamp | string | 否 | 数学验证码时间戳 |
| mathAnswer | number | 否 | 数学验证码答案 |
**请求示例**
```json
{
"name": "张三",
"email": "zhangsan@example.com",
"phone": "13800138000",
"subject": "产品咨询",
"message": "我想了解贵公司的软件开发服务。",
"submitTime": "1709827200000",
"mathHash": "MTAwLTE3MDk4MjcxMDAwMDA=",
"mathTimestamp": "1709827100000",
"mathAnswer": 100
}
```
**响应参数**
| 参数 | 类型 | 描述 |
|------|------|------|
| success | boolean | 请求是否成功 |
| message | string | 成功消息(成功时) |
| error | string | 错误消息(失败时) |
**成功响应**
```json
{
"success": true,
"message": "消息已发送,我们会尽快与您联系!"
}
```
**错误响应**
```json
{
"success": false,
"error": "请填写必填字段"
}
```
**错误码说明**
| HTTP 状态码 | 错误信息 | 描述 |
|-------------|----------|------|
| 200 | - | 蜜罐字段被填充(静默拒绝) |
| 400 | 请填写必填字段 | 缺少必填字段 |
| 400 | 请输入有效的邮箱地址 | 邮箱格式不正确 |
| 400 | 提交过快,请稍后再试 | 提交时间间隔过短 |
| 400 | 验证码错误,请重新计算 | 数学验证码错误 |
| 500 | 发送失败,请稍后重试 | 邮件发送失败 |
## 安全机制
### 1. 蜜罐字段 (Honeypot)
通过隐藏字段 `website` 检测机器人提交:
```tsx
// 前端隐藏字段
<input name="website" className="hidden" tabIndex={-1} autoComplete="off" />
// 后端检测
if (website) {
// 检测到机器人,静默返回成功
return NextResponse.json({ success: true });
}
```
### 2. 提交时间验证
验证表单提交时间间隔,防止快速自动提交:
```tsx
if (submitTime) {
const timeDiff = Date.now() - parseInt(submitTime);
if (timeDiff < 2000) {
// 提交过快,拒绝请求
return NextResponse.json({ success: false, error: '提交过快' });
}
}
```
### 3. 数学验证码
使用数学运算验证码防止机器人:
```tsx
// 前端生成验证码
const num1 = Math.floor(Math.random() * 10) + 1;
const num2 = Math.floor(Math.random() * 10) + 1;
const answer = num1 + num2;
const timestamp = Date.now();
const hash = btoa(`${answer}-${timestamp}`);
// 后端验证
const expectedHash = btoa(`${mathAnswer}-${mathTimestamp}`);
if (expectedHash !== mathHash) {
return NextResponse.json({ success: false, error: '验证码错误' });
}
```
### 4. 邮箱验证
验证邮箱格式:
```tsx
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
return NextResponse.json({ success: false, error: '请输入有效的邮箱地址' });
}
```
### 5. XSS 防护
使用 DOMPurify 清理用户输入:
```tsx
import DOMPurify from 'dompurify';
const sanitizedName = DOMPurify.sanitize(name);
```
## 邮件服务
### Resend 配置
项目使用 Resend 服务发送邮件:
```env
RESEND_API_KEY=re_xxxxx
COMPANY_EMAIL=contact@novalon.cn
```
### 邮件模板
邮件使用 HTML 模板,包含:
- 公司品牌头部
- 表单数据展示
- 时间戳信息
- 响应式设计
**邮件模板结构**
```html
<html>
<head>
<style>
/* 响应式样式 */
</style>
</head>
<body>
<div class="container">
<div class="header">
<!-- 公司品牌 -->
</div>
<div class="content">
<!-- 表单数据 -->
</div>
<div class="footer">
<!-- 页脚信息 -->
</div>
</div>
</body>
</html>
```
## Server Actions
### 联系表单 Server Action
位于 `src/app/(marketing)/contact/actions.ts`
```tsx
'use server';
export async function submitContactForm(formData: FormData) {
// 服务端表单处理逻辑
}
```
**优势:**
- 无需创建 API 路由
- 自动 CSRF 保护
- 类型安全
- 更简洁的错误处理
## 环境变量
### 必需配置
```env
# Resend API 密钥
RESEND_API_KEY=re_xxxxx
# 公司邮箱
COMPANY_EMAIL=contact@novalon.cn
```
### 可选配置
```env
# 环境
NODE_ENV=production
# 站点 URL
NEXT_PUBLIC_SITE_URL=https://www.novalon.cn
```
## 请求限制
### 速率限制
建议在生产环境配置速率限制:
```typescript
// 示例:使用 Upstash Redis
import { Ratelimit } from '@upstash/ratelimit';
import { Redis } from '@upstash/redis';
const ratelimit = new Ratelimit({
redis: Redis.fromEnv(),
limiter: Ratelimit.slidingWindow(10, '1 m'),
});
const { success } = await ratelimit.limit(ip);
if (!success) {
return NextResponse.json({ error: '请求过于频繁' }, { status: 429 });
}
```
## CORS 配置
API 路由默认不允许跨域请求。如需配置 CORS:
```typescript
export async function POST(request: NextRequest) {
const response = NextResponse.json({ success: true });
response.headers.set('Access-Control-Allow-Origin', 'https://www.novalon.cn');
response.headers.set('Access-Control-Allow-Methods', 'POST');
return response;
}
```
## 错误处理
### 统一错误响应格式
```typescript
interface ApiResponse {
success: boolean;
message?: string;
error?: string;
data?: unknown;
}
```
### 错误日志
```typescript
try {
await resend.emails.send({ ... });
} catch (error) {
console.error('邮件发送失败:', error);
return NextResponse.json(
{ success: false, error: '发送失败,请稍后重试' },
{ status: 500 }
);
}
```
## 测试接口
### 使用 cURL
```bash
curl -X POST http://localhost:3000/api/contact \
-H "Content-Type: application/json" \
-d '{
"name": "测试用户",
"email": "test@example.com",
"subject": "测试主题",
"message": "测试消息内容"
}'
```
### 使用 Playwright
```typescript
// e2e/src/tests/api/contact.spec.ts
test('提交联系表单', async ({ request }) => {
const response = await request.post('/api/contact', {
data: {
name: '测试用户',
email: 'test@example.com',
subject: '测试主题',
message: '测试消息内容',
},
});
expect(response.ok()).toBeTruthy();
const data = await response.json();
expect(data.success).toBe(true);
});
```
## API 版本控制
当前项目 API 不包含版本号。如需版本控制,建议:
```
/api/v1/contact
/api/v2/contact
```
## 监控与日志
### 推荐集成
- **Sentry** - 错误监控
- **LogRocket** - 会话回放
- **Vercel Analytics** - 性能监控
### 日志格式
```typescript
console.log({
timestamp: new Date().toISOString(),
level: 'info',
message: '联系表单提交',
data: { email, subject },
});
```
+535
View File
@@ -0,0 +1,535 @@
# 组件文档
## 组件概述
项目组件采用分层架构设计,分为基础 UI 组件、布局组件、业务区块组件和视觉效果组件。
## 组件分类
### 1. UI 基础组件 (`src/components/ui/`)
基于 shadcn/ui 的可复用基础组件,遵循 Radix UI 的无状态设计原则。
#### Button 按钮
```tsx
import { Button } from '@/components/ui/button';
// 基础用法
<Button></Button>
// 变体
<Button variant="default"></Button>
<Button variant="destructive"></Button>
<Button variant="outline"></Button>
<Button variant="secondary"></Button>
<Button variant="ghost"></Button>
<Button variant="link"></Button>
// 尺寸
<Button size="default"></Button>
<Button size="sm"></Button>
<Button size="lg"></Button>
<Button size="icon"></Button>
```
#### Card 卡片
```tsx
import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from '@/components/ui/card';
<Card>
<CardHeader>
<CardTitle></CardTitle>
<CardDescription></CardDescription>
</CardHeader>
<CardContent></CardContent>
<CardFooter></CardFooter>
</Card>
```
#### Input 输入框
```tsx
import { Input } from '@/components/ui/input';
<Input
type="text"
placeholder="请输入..."
className="w-full"
/>
```
#### Textarea 文本域
```tsx
import { Textarea } from '@/components/ui/textarea';
<Textarea
placeholder="请输入内容..."
rows={4}
className="w-full"
/>
```
#### Dialog 对话框
```tsx
import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription } from '@/components/ui/dialog';
<Dialog>
<DialogTrigger asChild>
<Button></Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle></DialogTitle>
<DialogDescription></DialogDescription>
</DialogHeader>
{/* 内容 */}
</DialogContent>
</Dialog>
```
#### DropdownMenu 下拉菜单
```tsx
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem } from '@/components/ui/dropdown-menu';
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost"></Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem>1</DropdownMenuItem>
<DropdownMenuItem>2</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
```
#### Toast 提示
```tsx
import { Toast, ToastAction } from '@/components/ui/toast';
<Toast>
<ToastTitle></ToastTitle>
<ToastDescription></ToastDescription>
<ToastAction></ToastAction>
</Toast>
```
#### Badge 徽章
```tsx
import { Badge } from '@/components/ui/badge';
<Badge></Badge>
<Badge variant="secondary"></Badge>
<Badge variant="destructive"></Badge>
<Badge variant="outline"></Badge>
```
#### 特殊 UI 组件
| 组件 | 描述 |
|------|------|
| `RippleButton` | 水波纹效果按钮 |
| `SealButton` | 印章风格按钮 |
| `GlassCard` | 毛玻璃效果卡片 |
| `AnimatedCard` | 动画卡片 |
| `InsightCard` | 洞察卡片 |
| `TestimonialCard` | 客户评价卡片 |
| `LoadingSkeleton` | 加载骨架屏 |
| `OptimizedImage` | 优化图片组件 |
| `ErrorBoundary` | 错误边界组件 |
| `BackButton` | 返回按钮 |
| `AnimatedNumber` | 数字动画 |
| `FlipClock` | 翻页时钟 |
| `PageHeader` | 页面头部 |
| `PageTransitions` | 页面过渡 |
| `ScrollAnimations` | 滚动动画 |
### 2. 布局组件 (`src/components/layout/`)
#### Header 页头导航
```tsx
import { Header } from '@/components/layout/header';
// 在布局中使用
<Header />
```
**功能特性:**
- 响应式导航菜单
- 滚动时样式变化
- 移动端汉堡菜单
- 键盘导航支持
- 焦点陷阱
#### Footer 页脚
```tsx
import { Footer } from '@/components/layout/footer';
// 在布局中使用
<Footer />
```
**功能特性:**
- 公司信息展示
- 快速链接
- 服务项目
- 联系方式
- 微信公众号二维码
#### MobileMenu 移动端菜单
```tsx
import { MobileMenu } from '@/components/layout/mobile-menu';
// 由 Header 内部调用
```
#### MobileTabBar 移动端底部导航
```tsx
import { MobileTabBar } from '@/components/layout/mobile-tab-bar';
// 在根布局中使用
<MobileTabBar />
```
#### Breadcrumb 面包屑
```tsx
import { Breadcrumb } from '@/components/layout/breadcrumb';
<Breadcrumb items={[
{ label: '首页', href: '/' },
{ label: '服务', href: '/services' },
{ label: '软件开发' },
]} />
```
### 3. 页面区块组件 (`src/components/sections/`)
#### HeroSection 首页 Hero 区域
```tsx
import { HeroSection } from '@/components/sections/hero-section';
<HeroSection />
```
**功能特性:**
- 动态背景效果
- 公司标语展示
- CTA 按钮
- 统计数据展示
- 滚动动画
#### ServicesSection 核心业务区块
```tsx
import { ServicesSection } from '@/components/sections/services-section';
<ServicesSection />
```
**功能特性:**
- 服务卡片网格
- 图标 + 标题 + 描述
- 悬停效果
- 链接到详情页
#### ProductsSection 产品服务区块
```tsx
import { ProductsSection } from '@/components/sections/products-section';
<ProductsSection />
```
#### CasesSection 成功案例区块
```tsx
import { CasesSection } from '@/components/sections/cases-section';
<CasesSection />
```
#### AboutSection 关于我们区块
```tsx
import { AboutSection } from '@/components/sections/about-section';
<AboutSection />
```
#### NewsSection 新闻动态区块
```tsx
import { NewsSection } from '@/components/sections/news-section';
<NewsSection />
```
#### ContactSection 联系区块
```tsx
import { ContactSection } from '@/components/sections/contact-section';
<ContactSection />
```
#### InsightsSection 洞察区块
```tsx
import { InsightsSection } from '@/components/sections/insights-section';
<InsightsSection />
```
#### TestimonialsSection 客户评价区块
```tsx
import { TestimonialsSection } from '@/components/sections/testimonials-section';
<TestimonialsSection />
```
### 4. 视觉效果组件 (`src/components/effects/`)
#### 渐变效果
| 组件 | 描述 |
|------|------|
| `GradientFlow` | 流动渐变背景 |
| `GradientFlowOptimized` | 优化的流动渐变 |
| `GradientAnimation` | 渐变动画 |
| `GradientGrid` | 渐变网格 |
| `GradientOrbs` | 渐变球体 |
| `MeshGradient` | 网格渐变 |
#### 粒子效果
| 组件 | 描述 |
|------|------|
| `DataParticleFlow` | 数据粒子流动 |
| `ParticleGalaxy` | 粒子星系 |
| `SubtleParticles` | 微妙粒子 |
| `MouseInteractiveParticles` | 鼠标交互粒子 |
#### 几何效果
| 组件 | 描述 |
|------|------|
| `GeometricShapes` | 几何形状 |
| `GeometricAbstract` | 几何抽象 |
| `GridLines` | 网格线 |
| `TechGridFlow` | 科技网格 |
#### 其他效果
| 组件 | 描述 |
|------|------|
| `GlowEffect` | 发光效果 |
| `ParallaxEffect` | 视差效果 |
| `FluidWaveBackground` | 流体波浪背景 |
| `InkTechFusion` | 水墨科技融合 |
| `SubtleDots` | 微妙点阵 |
| `SealAnimationEnhanced` | 印章动画增强 |
| `AdvancedFloatingEffects` | 高级浮动效果 |
### 5. SEO 组件 (`src/components/seo/`)
#### StructuredData 结构化数据
```tsx
import { OrganizationSchema, WebsiteSchema } from '@/components/seo/structured-data';
// 在布局中使用
<OrganizationSchema />
<WebsiteSchema />
```
**支持的 Schema 类型:**
- Organization - 组织信息
- Website - 网站信息
- BreadcrumbList - 面包屑
- Article - 文章
### 6. 分析组件 (`src/components/analytics/`)
#### WebVitals 性能监控
```tsx
import { WebVitals } from '@/components/analytics/web-vitals';
// 在根布局中使用
<WebVitals />
```
**监控指标:**
- LCP (Largest Contentful Paint)
- FID (First Input Delay)
- CLS (Cumulative Layout Shift)
- TTFB (Time to First Byte)
- INP (Interaction to Next Paint)
## 自定义 Hooks (`src/hooks/`)
### useMediaQuery 媒体查询
```tsx
import { useMediaQuery } from '@/hooks/use-media-query';
const isMobile = useMediaQuery('(max-width: 768px)');
```
### useScrollReveal 滚动显示
```tsx
import { useScrollReveal } from '@/hooks/use-scroll-reveal';
const { ref, isVisible } = useScrollReveal();
```
### useFocusTrap 焦点陷阱
```tsx
import { useFocusTrap } from '@/hooks/use-focus-trap';
const focusTrapRef = useFocusTrap<HTMLDivElement>(isActive);
```
### useIntersectionObserver 交叉观察
```tsx
import { useIntersectionObserver } from '@/hooks/use-intersection-observer';
const { ref, entry } = useIntersectionObserver({
threshold: 0.5,
});
```
## 工具函数 (`src/lib/`)
### utils.ts 通用工具
```tsx
import { cn, formatNumber, formatCurrency, debounce, throttle } from '@/lib/utils';
// 类名合并
cn('base-class', conditional && 'active-class');
// 数字格式化
formatNumber(1234567); // '1,234,567'
// 货币格式化
formatCurrency(1234.56); // '¥1,234.56'
// 防抖
const debouncedFn = debounce(fn, 300);
// 节流
const throttledFn = throttle(fn, 100);
```
### constants.ts 常量配置
```tsx
import { COMPANY_INFO, NAVIGATION, STATS, SERVICES } from '@/lib/constants';
// 公司信息
COMPANY_INFO.name; // '四川睿新致远科技有限公司'
COMPANY_INFO.email; // 'contact@novalon.cn'
COMPANY_INFO.phone; // '028-88888888'
// 导航配置
NAVIGATION; // NavigationItem[]
// 统计数据
STATS; // StatItem[]
// 服务数据
SERVICES; // Service[]
```
### animations.tsx 动画组件
```tsx
import { GradientText, MagneticButton, BlurReveal, CounterWithEffect } from '@/lib/animations';
// 渐变文字
<GradientText></GradientText>
// 磁性按钮
<MagneticButton>
<Button></Button>
</MagneticButton>
// 模糊显示
<BlurReveal></BlurReveal>
// 数字计数器
<CounterWithEffect value={100} />
```
### 其他工具模块
| 模块 | 描述 |
|------|------|
| `colors.ts` | 颜色工具函数 |
| `gradients.ts` | 渐变配置 |
| `sanitize.ts` | XSS 防护清理 |
| `csrf.ts` | CSRF Token 生成 |
| `email-templates.ts` | 邮件模板 |
| `color-contrast.ts` | 颜色对比度检查 |
## 组件开发规范
### 1. 命名规范
- 组件文件:PascalCase (如 `Button.tsx`)
- 组件名称:与文件名一致
- Props 接口:`ComponentNameProps`
- 导出方式:命名导出
### 2. 文件结构
```tsx
// 1. 导入
import { useState } from 'react';
import { cn } from '@/lib/utils';
// 2. 类型定义
interface ButtonProps {
variant?: 'default' | 'outline';
children: React.ReactNode;
}
// 3. 组件定义
export function Button({ variant = 'default', children }: ButtonProps) {
return <button className={cn('btn', variant)}>{children}</button>;
}
// 4. 默认导出(可选)
export default Button;
```
### 3. 样式规范
- 优先使用 Tailwind CSS 类名
- 使用 `cn()` 合并条件类名
- 避免内联样式
- 遵循移动优先原则
### 4. 可访问性规范
- 提供适当的 ARIA 属性
- 支持键盘导航
- 管理焦点状态
- 提供跳过链接
+466
View File
@@ -0,0 +1,466 @@
# OpenAPI文档使用指南
## 概述
OpenAPI(原名Swagger)是一个用于描述、生成、消费和可视化RESTful Web服务的规范。本项目已集成OpenAPI文档,提供交互式API文档界面。
## 访问文档
### 开发环境
启动开发服务器后,访问:
```
http://localhost:3000/api-docs
```
### 生产环境
部署后访问:
```
https://your-domain.com/api-docs
```
## 文档结构
### API端点
| 端点 | 方法 | 描述 | 认证 |
|------|------|------|------|
| `/api/health` | GET | 健康检查 | 无 |
| `/api/admin/content` | GET | 获取内容列表 | 需要管理员权限 |
| `/api/admin/content` | POST | 创建新内容 | 需要管理员权限 |
### 数据模型
#### Content(内容)
```typescript
interface Content {
id: number;
type: 'news' | 'case' | 'product' | 'service';
title: string;
content: string;
status: 'draft' | 'published' | 'archived';
createdAt: Date;
updatedAt: Date;
}
```
#### User(用户)
```typescript
interface User {
id: number;
name: string;
email: string;
role: 'admin' | 'editor' | 'viewer';
}
```
#### Config(配置)
```typescript
interface Config {
key: string;
value: string;
description: string;
}
```
## 使用Swagger UI
### 浏览API
1. 访问 `/api-docs`
2. 点击任意API端点展开详情
3. 查看请求参数、响应格式和示例
### 测试API
#### 无需认证的API
1. 点击"Try it out"按钮
2. 填写必要参数
3. 点击"Execute"执行请求
4. 查看响应结果
示例:健康检查API
```bash
curl -X GET "http://localhost:3000/api/health" -H "accept: application/json"
```
#### 需要认证的API
1. 先登录获取访问令牌
2. 点击页面右上角的"Authorize"按钮
3. 输入Bearer令牌:`Bearer your-access-token`
4. 点击"Authorize"确认
5. 现在可以测试需要认证的API
示例:获取内容列表
```bash
curl -X GET "http://localhost:3000/api/admin/content?page=1&limit=20" \
-H "accept: application/json" \
-H "Authorization: Bearer your-access-token"
```
## 为API添加文档
### 步骤1:添加JSDoc注释
在API路由文件中添加JSDoc注释:
```typescript
/**
* @openapi
* /api/your-endpoint:
* get:
* tags:
* - YourTag
* summary: 简短描述
* description: 详细描述
* operationId: getYourData
* parameters:
* - name: id
* in: path
* required: true
* schema:
* type: integer
* responses:
* 200:
* description: 成功响应
* content:
* application/json:
* schema:
* type: object
* properties:
* success:
* type: boolean
* data:
* type: object
*/
export async function GET(request: NextRequest) {
// API实现
}
```
### 步骤2:定义请求体
对于POST/PUT请求:
```typescript
/**
* @openapi
* /api/your-endpoint:
* post:
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* required:
* - name
* - email
* properties:
* name:
* type: string
* email:
* type: string
* format: email
*/
```
### 步骤3:引用共享Schema
使用`$ref`引用共享数据模型:
```typescript
/**
* @openapi
* /api/admin/content:
* get:
* responses:
* 200:
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/Content'
*/
```
## OpenAPI规范文件
### 获取规范文件
访问以下端点获取原始OpenAPI规范:
```
GET /api/docs
```
### 使用规范文件
1. **导入到Postman**
- 打开Postman
- 点击"Import"
- 选择"Link"
- 输入:`http://localhost:3000/api/docs`
- 点击"Import"
2. **生成客户端代码**
- 使用OpenAPI Generator
- 支持多种语言:TypeScript, Python, Java等
3. **API测试**
- 导入到测试工具
- 自动生成测试用例
## 最佳实践
### ✅ 推荐做法
1. **完整的描述**
- 提供清晰的summary和description
- 说明参数的作用和限制
- 提供示例值
2. **准确的类型定义**
- 使用正确的数据类型
- 标注必填字段
- 定义枚举值
3. **完整的响应定义**
- 定义所有可能的响应状态码
- 提供错误响应格式
- 包含示例数据
4. **合理的标签分组**
- 按功能模块分组
- 使用一致的命名
- 避免过多标签
### ❌ 避免的做法
1. **不要省略错误响应**
```typescript
// ❌ 不好
responses:
* 200:
* description: 成功
// ✅ 好
responses:
* 200:
* description: 成功
* 400:
* description: 参数错误
* 401:
* description: 未授权
* 500:
* description: 服务器错误
```
2. **不要使用模糊的描述**
```typescript
// ❌ 不好
summary: 获取数据
// ✅ 好
summary: 获取内容列表
description: 管理员获取内容列表,支持分页、筛选和搜索
```
3. **不要忽略认证要求**
```typescript
// ✅ 始终标注认证要求
security:
* - bearerAuth: []
```
## 高级功能
### 添加示例
```typescript
/**
* @openapi
* /api/admin/content:
* post:
* requestBody:
* content:
* application/json:
* examples:
* newsExample:
* summary: 新闻示例
* value:
* type: news
* title: 新闻标题
* content: 新闻内容
*/
```
### 添加标签描述
在`/api/docs/route.ts`中:
```typescript
tags: [
{
name: 'Content',
description: '内容管理相关接口',
},
{
name: 'Admin',
description: '管理员相关接口',
},
],
```
### 添加服务器配置
```typescript
servers: [
{
url: 'http://localhost:3000',
description: '开发服务器',
},
{
url: 'https://api.novalon.cn',
description: '生产服务器',
},
],
```
## CI/CD集成
### 验证OpenAPI规范
```bash
# 安装验证工具
npm install -g @redocly/cli
# 验证规范
redocly lint http://localhost:3000/api/docs
```
### 生成文档
```bash
# 安装Redoc
npm install -g redoc
# 生成静态HTML文档
redocly build-docs http://localhost:3000/api/docs -o api-docs.html
```
### GitHub Actions示例
```yaml
name: API Documentation
on:
push:
branches: [main]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install dependencies
run: npm ci
- name: Start server
run: npm run dev &
env:
CI: true
- name: Wait for server
run: npx wait-on http://localhost:3000/api/docs
- name: Validate OpenAPI spec
run: npx @redocly/cli lint http://localhost:3000/api/docs
```
## 故障排查
### 问题1:文档页面无法加载
**症状**:访问`/api-docs`显示加载中或空白页
**解决方案**
```bash
# 检查API端点是否正常
curl http://localhost:3000/api/docs
# 检查浏览器控制台错误
# 打开开发者工具查看Network和Console标签
```
### 问题2API不显示在文档中
**症状**:某些API端点未出现在文档中
**解决方案**
```typescript
// 检查JSDoc注释格式
// 确保使用 @openapi 标签
/**
* @openapi // ← 必须是这个标签
* /api/your-endpoint:
* get:
*/
// 检查apis路径配置
apis: [
'./src/app/api/**/route.ts', // ← 确保路径正确
],
```
### 问题3:认证失败
**症状**:使用Authorize按钮后仍然无法访问需要认证的API
**解决方案**
```bash
# 确保令牌格式正确
Bearer your-access-token # ← 注意Bearer前缀
# 检查令牌是否有效
curl -H "Authorization: Bearer your-token" http://localhost:3000/api/admin/content
```
## 参考资源
- [OpenAPI规范](https://swagger.io/specification/)
- [Swagger UI文档](https://swagger.io/tools/swagger-ui/)
- [swagger-jsdoc文档](https://github.com/surnet/swagger-jsdoc)
- [OpenAPI Generator](https://openapi-generator.tech/)
- [Redoc文档](https://redocly.com/docs/redoc/)
## 总结
OpenAPI文档已完全集成到项目中,提供了:
**交互式API文档**
**自动生成规范**
**在线测试功能**
**认证支持**
**多格式导出**
通过合理使用OpenAPI文档,可以:
- 提升API可用性
- 减少沟通成本
- 自动化API测试
- 生成客户端SDK