diff --git a/.gitignore b/.gitignore index 5c49168..ffb73ce 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,12 @@ node_modules/ out/ .swc/ +# Next.js specific +.next/types/ +.next/server/ +.next/build-manifest.json +.next/react-loadable-manifest.json + # Production build/ dist/ @@ -68,19 +74,75 @@ venv.bak/ virtualenv/ virtualenvs/ +# Python E2E Tests +e2e-tests/.pytest_cache/ +e2e-tests/__pycache__/ +e2e-tests/.venv/ +e2e-tests/venv/ +e2e-tests/*.egg-info/ + # Playwright test-results/ -!test-results/.gitkeep -!test-results/performance/.gitkeep -!test-results/accessibility/.gitkeep playwright-report/ playwright/.cache/ *.traces/ playwright-traces/ -# Allure Reports +# E2E test results and reports (comprehensive) +e2e/test-results/ +e2e/test-results/**/ +e2e/playwright-report/ +e2e/playwright-report/**/ +e2e/playwright/.cache/ +e2e/allure-results/ +e2e/allure-results/**/ +e2e/allure-report/ +e2e/.last-run.json +e2e/junit.xml + +# Test result files (screenshots, videos, traces) +e2e/test-results/**/*.png +e2e/test-results/**/*.jpg +e2e/test-results/**/*.jpeg +e2e/test-results/**/*.webp +e2e/test-results/**/*.avif +e2e/test-results/**/*.gif +e2e/test-results/**/*.webm +e2e/test-results/**/*.mp4 +e2e/test-results/**/*.zip +e2e/test-results/**/*.json +e2e/test-results/**/*.xml +e2e/test-results/**/*.html + +# Playwright report media files +e2e/playwright-report/**/*.png +e2e/playwright-report/**/*.jpg +e2e/playwright-report/**/*.webm +e2e/playwright-report/**/*.mp4 +e2e/playwright-report/**/*.zip +e2e/playwright-report/data/ +e2e/playwright-report/index.html + +# Allure test results and reports allure-results/ allure-report/ +e2e/allure-*/ +test-framework/allure-*/ +e2e-tests/allure-*/ +e2e/allure-results/**/*.png +e2e/allure-results/**/*.jpg +e2e/allure-results/**/*.webp +e2e/allure-results/**/*.webm +e2e/allure-results/**/*.json +e2e/allure-results/**/*.xml +test-framework/allure-results/**/*.png +test-framework/allure-results/**/*.jpg + +# Test Framework Reports +test-framework/reports/ +e2e/test-report.md +e2e-tests/results/ +e2e-tests/reports/ # Testing coverage/ @@ -183,9 +245,12 @@ dist-ssr/ # Three.js *.three.json -# Image optimization -*.avif -*.webp +# Image optimization - only ignore in specific directories +# Keep public images and visual regression snapshots +# test-results/**/*.avif +# test-results/**/*.webp +# test-results/**/*.png +# test-results/**/*.jpg # Temporary files *.tmp @@ -202,36 +267,63 @@ test-screenshot.png hero-check.png playwright-test-not-portal.js -# CI/CD -.gitlab-ci-local/ -.github/workflows/*.local.yml -.woodpecker/ +# Test screenshots and images - ignore all test output +# Allure attachments +e2e/allure-results/**/*.png +e2e/allure-results/**/*.jpg +e2e/allure-results/**/*.webp +test-framework/allure-results/**/*.png +test-framework/allure-results/**/*.jpg -# Documentation -docs/plans/*.md.bak +# Playwright test results (all media files) +test-results/**/*.png +test-results/**/*.jpg +test-results/**/*.jpeg +test-results/**/*.webp +test-results/**/*.avif +test-results/**/*.gif +test-results/**/*.webm +test-results/**/*.mp4 +test-results/**/*.zip -# Database -*.db -*.sqlite -*.sqlite3 +# Build output images +dist/**/*.png +dist/**/*.jpg +dist/**/*.jpeg +dist/**/*.webp +dist/**/*.avif +dist/**/*.gif -# Archives -*.7z -*.dmg -*.gz -*.iso -*.jar -*.rar -*.tar -*.zip +# IMPORTANT: Visual regression snapshots should be committed to version control +# These are in: e2e/src/tests/visual/**/*-snapshots/ +# Git will track them because they are not in test-results/ or allure-results/ -# Package manager locks (keep package-lock.json) -yarn.lock -pnpm-lock.yaml +# Test analysis scripts output +e2e/analyze-results.js +test-framework/analyze-*.py +test-framework/debug-*.py +test-framework/verify-*.ts -# Sentry -.sentryclirc -*.sentryclirc +# Test baseline images (keep visual regression snapshots) +# Note: Visual regression snapshots in e2e/src/tests/visual/*-snapshots/ should be committed -# docs -docs/ +# Performance audit results +lighthouse-reports/ +performance-baseline.json + +# Test data exports +test-data-*.json +test-results-*.json + +# Additional E2E test artifacts +e2e/blob-report/ +e2e/report/ +e2e/.auth/ +e2e/state/ +e2e/storage-state.json + +# Test execution artifacts +*.trace +*.trace.zip +trace.zip +network-logs/ diff --git a/README.md b/README.md index 0f2dbff..b8edcd5 100644 --- a/README.md +++ b/README.md @@ -1,31 +1,37 @@ # Novalon Website -这是一个基于 Next.js 16 构建的现代化静态网站项目,采用 React 19 和 TypeScript 技术栈。 +四川睿新致远科技有限公司官方网站 - 企业数字化转型服务商 + +## 项目概述 + +本项目是四川睿新致远科技有限公司的企业官网,采用 Next.js 16 + React 19 + TypeScript 技术栈构建,提供现代化的企业展示、产品服务介绍、案例展示、新闻动态和在线咨询等功能。 + +### 核心功能 + +- **首页展示** - Hero 区域、核心业务、产品服务、成功案例、关于我们、新闻动态 +- **服务详情** - 软件开发、云服务、数据分析、信息安全等服务详细介绍 +- **产品展示** - 产品列表和详情页面 +- **案例展示** - 成功案例列表和详情 +- **新闻动态** - 公司新闻、产品发布、合作动态、行业资讯 +- **在线咨询** - 联系表单、公司信息展示 +- **响应式设计** - 完美适配桌面端、平板和移动设备 +- **SEO 优化** - 结构化数据、元信息优化 ## 技术栈 -- **框架**: Next.js 16.1.6 (App Router) -- **语言**: TypeScript 5 -- **UI 库**: React 19.2.3 + React DOM 19.2.3 -- **样式**: Tailwind CSS v4 + CSS Variables -- **组件库**: shadcn/ui (基于 Radix UI) -- **动画**: Framer Motion 12.29.2 -- **图标**: Lucide React 0.563.0 -- **工具库**: - - `clsx` - 条件类名合并 - - `tailwind-merge` - Tailwind 类名智能合并 - - `class-variance-authority` - CVA 变体管理 - - `zod` - 数据验证 - -## 项目特性 - -- ✨ **现代化 UI** - 基于 shadcn/ui 的精美组件设计 -- 🎨 **主题支持** - CSS Variables 驱动的深色/浅色主题 -- 📱 **响应式设计** - 完美适配各种屏幕尺寸 -- 🚀 **静态导出** - 支持静态 HTML 输出 -- 🔧 **类型安全** - 完整的 TypeScript 支持 -- 📦 **代码分割** - 自动按路由代码分割 -- 🎯 **路径别名** - 使用 `@/*` 别名导入 +| 类别 | 技术 | 版本 | +|------|------|------| +| 框架 | Next.js | 16.1.6 | +| UI 库 | React | 19.2.3 | +| 语言 | TypeScript | 5.x | +| 样式 | Tailwind CSS | 4.x | +| 组件库 | shadcn/ui (Radix UI) | - | +| 动画 | Framer Motion | 12.x | +| 图标 | Lucide React | 0.563.0 | +| 邮件服务 | Resend | 6.9.2 | +| 数据验证 | Zod | 4.3.6 | +| 图表 | @antv/g2 | 5.4.8 | +| 3D 效果 | Three.js | 0.183.1 | ## 快速开始 @@ -38,42 +44,35 @@ ```bash npm install -# 或 -yarn install -# 或 -pnpm install -# 或 -bun install +``` + +### 环境变量配置 + +复制环境变量示例文件: + +```bash +cp .env.example .env.local +``` + +配置必要的环境变量: + +```env +RESEND_API_KEY=your_resend_api_key +COMPANY_EMAIL=contact@novalon.cn ``` ### 开发模式 -启动开发服务器: - ```bash npm run dev -# 或 -yarn dev -# 或 -pnpm dev -# 或 -bun dev ``` -访问 [http://localhost:3000](http://localhost:3000) +访问 http://localhost:3000 ### 构建生产版本 -构建静态导出: - ```bash npm run build -# 或 -yarn build -# 或 -pnpm build -# 或 -bun build ``` 输出目录: `dist/` @@ -82,24 +81,6 @@ bun build ```bash npm start -# 或 -yarn start -# 或 -pnpm start -# 或 -bun start -``` - -### 代码检查 - -```bash -npm run lint -# 或 -yarn lint -# 或 -pnpm lint -# 或 -bun lint ``` ## 项目结构 @@ -107,149 +88,113 @@ bun lint ``` novalon-website/ ├── src/ -│ ├── app/ # Next.js App Router 页面 -│ │ ├── layout.tsx # 根布局文件 -│ │ ├── page.tsx # 首页 -│ │ ├── globals.css # 全局样式 -│ │ └── [routes]/ # 动态路由 -│ ├── components/ # React 组件 -│ │ ├── ui/ # shadcn/ui 基础组件 -│ │ └── ... # 业务组件 -│ ├── lib/ # 工具函数和配置 -│ │ └── utils.ts # cn() 工具函数 -│ └── assets/ # 静态资源 -├── public/ # 公共静态资源 -├── dist/ # 构建输出目录(静态导出) -├── next.config.ts # Next.js 配置 -├── tsconfig.json # TypeScript 配置 -├── tailwind.config.* # Tailwind CSS 配置 -├── components.json # shadcn/ui 配置 -└── package.json +│ ├── app/ # Next.js App Router +│ │ ├── (marketing)/ # 营销页面路由组 +│ │ │ ├── page.tsx # 首页 +│ │ │ ├── about/ # 关于我们 +│ │ │ ├── cases/ # 成功案例 +│ │ │ ├── contact/ # 联系我们 +│ │ │ ├── news/ # 新闻动态 +│ │ │ ├── products/ # 产品服务 +│ │ │ ├── services/ # 核心业务 +│ │ │ └── solutions/ # 解决方案 +│ │ ├── api/ # API 路由 +│ │ │ └── contact/ # 联系表单 API +│ │ ├── layout.tsx # 根布局 +│ │ ├── error.tsx # 错误页面 +│ │ └── not-found.tsx # 404 页面 +│ ├── components/ # React 组件 +│ │ ├── ui/ # 基础 UI 组件 +│ │ ├── layout/ # 布局组件 +│ │ ├── sections/ # 页面区块组件 +│ │ ├── effects/ # 视觉效果组件 +│ │ ├── seo/ # SEO 组件 +│ │ └── analytics/ # 分析组件 +│ ├── lib/ # 工具函数 +│ ├── hooks/ # 自定义 Hooks +│ └── contexts/ # React Context +├── e2e/ # E2E 测试 +│ ├── src/ +│ │ ├── tests/ # 测试用例 +│ │ ├── pages/ # Page Object +│ │ ├── fixtures/ # 测试 Fixtures +│ │ └── config/ # 测试配置 +│ └── playwright.config.ts +├── public/ # 静态资源 +├── docs/ # 项目文档 +└── dist/ # 构建输出 ``` -## 路径别名 +## 页面路由 -项目配置了以下路径别名: +| 路由 | 描述 | +|------|------| +| `/` | 首页 | +| `/about` | 关于我们 | +| `/services` | 核心业务列表 | +| `/services/[id]` | 业务详情 | +| `/products` | 产品服务列表 | +| `/products/[id]` | 产品详情 | +| `/cases` | 成功案例列表 | +| `/cases/[id]` | 案例详情 | +| `/news` | 新闻动态列表 | +| `/news/[slug]` | 新闻详情 | +| `/contact` | 联系我们 | +| `/privacy` | 隐私政策 | +| `/terms` | 服务条款 | -| 别名 | 映射路径 | 示例 | -| -------------- | --------------------- | ---------------------- | -| `@/*` | `./src/*` | `@/components/Button` | -| `@/components` | `./src/components` | @/components/ui/button | -| `@/lib` | `./src/lib` | @/lib/utils | -| `@/ui` | `./src/components/ui` | @/ui/button | -| `@/hooks` | `./src/hooks` | @/hooks/useToggle | +## NPM 脚本 -## 主要依赖 +| 命令 | 描述 | +|------|------| +| `npm run dev` | 启动开发服务器 | +| `npm run build` | 构建生产版本 | +| `npm start` | 启动生产服务器 | +| `npm run lint` | 运行 ESLint 检查 | +| `npm run test` | 运行 E2E 测试 | +| `npm run test:smoke` | 运行冒烟测试 | +| `npm run check:contrast` | 检查颜色对比度 | +| `npm run check:headings` | 检查标题层级 | -### 生产依赖 +## 测试 -| 依赖 | 版本 | 用途 | -| ------------------------ | ------- | ----------------- | -| next | 16.1.6 | React 全栈框架 | -| react | 19.2.3 | UI 库 | -| react-dom | 19.2.3 | React DOM 渲染 | -| framer-motion | 12.29.2 | 动画库 | -| lucide-react | 0.563.0 | 图标库 | -| @radix-ui/react-\* | - | 无状态可访问组件 | -| tailwind-merge | 3.4.0 | Tailwind 类名合并 | -| class-variance-authority | 0.7.1 | 变体类名管理 | -| clsx | 2.1.1 | 条件类名合并 | -| zod | 4.3.6 | 数据验证 | +项目使用 Playwright 进行 E2E 测试,测试框架位于 `e2e/` 目录。 -### 开发依赖 +### 测试类型 -| 依赖 | 版本 | 用途 | -| ------------------ | ------ | ------------------- | -| typescript | 5 | 类型系统 | -| tailwindcss | 4 | CSS 框架 | -| @types/node | 20 | Node.js 类型 | -| @types/react | 19 | React 类型 | -| @types/react-dom | 19 | React DOM 类型 | -| eslint | 9 | 代码检查 | -| eslint-config-next | 16.1.6 | Next.js ESLint 配置 | +- **冒烟测试** - 基础功能验证 +- **回归测试** - 功能完整性验证 +- **性能测试** - Core Web Vitals +- **响应式测试** - 多设备适配 +- **可访问性测试** - WCAG 合规 +- **安全测试** - XSS、CSRF 防护 +- **视觉回归测试** - UI 一致性 -## 配置说明 +### 运行测试 -### Next.js 配置 (`next.config.ts`) - -```typescript -import type { NextConfig } from "next"; - -const nextConfig: NextConfig = { - output: "export", // 静态导出模式 - distDir: "dist", // 输出目录 - images: { - unoptimized: true, // 静态导出需要禁用图片优化 - }, -}; - -export default nextConfig; +```bash +cd e2e +npm install +npm run test ``` -### TypeScript 配置 (`tsconfig.json`) +## CI/CD -- 目标: ES2017 -- 模块: ESNext (bundler) -- 严格模式: 启用 -- JSX: react-jsx -- 路径别名: `@/*` → `./src/*` +项目使用 Woodpecker CI 进行持续集成,配置文件为 `.woodpecker.yml`。 -### Tailwind CSS +CI 流水线包括: +- E2E 测试(全量、冒烟、回归、性能、响应式、视觉) -使用 Tailwind CSS v4,采用 CSS-first 配置方式,通过 CSS Variables 实现主题定制。 +## 文档 -### shadcn/ui 配置 +详细文档位于 `docs/` 目录: -- 风格: New York -- RSC 支持: 启用 -- CSS 变量: 启用 -- 前缀: 空 -- RTL: 禁用 -- 图标库: Lucide - -## 构建输出 - -运行 `npm run build` 后: - -- 静态文件输出到 `dist/` 目录 -- 包含静态 HTML、CSS、JavaScript 文件 -- 图片未优化(因为使用了 `unoptimized: true`) - -可以直接部署到任何静态托管服务: - -- Vercel -- Netlify -- GitHub Pages -- AWS S3 + CloudFront -- 阿里云 OSS -- 腾讯云 COS - -## 命令速查 - -| 命令 | 描述 | -| --------------- | ------------------------ | -| `npm run dev` | 启动开发服务器 | -| `npm run build` | 构建生产版本(静态导出) | -| `npm run start` | 启动生产服务器 | -| `npm run lint` | 运行 ESLint 检查 | - -## 浏览器支持 - -- Chrome (最新 2 个版本) -- Firefox (最新 2 个版本) -- Safari (最新 2 个版本) -- Edge (最新 2 个版本) - -## 学习资源 - -- [Next.js 文档](https://nextjs.org/docs) -- [React 文档](https://react.dev) -- [TypeScript 文档](https://www.typescriptlang.org/docs) -- [Tailwind CSS 文档](https://tailwindcss.com/docs) -- [shcn/ui 文档](https://ui.shadcn.com) -- [Framer Motion 文档](https://www.framer.com/motion) -- [Lucide 图标](https://lucide.dev) +- [架构文档](docs/architecture.md) - 系统架构设计 +- [组件文档](docs/components.md) - 组件使用指南 +- [API 文档](docs/api.md) - API 接口说明 +- [测试文档](docs/testing.md) - 测试策略和指南 +- [部署文档](docs/deployment.md) - 部署流程说明 ## 许可证 -本项目仅供学习和参考使用。 +Copyright © 2026 四川睿新致远科技有限公司 diff --git a/docs/api.md b/docs/api.md new file mode 100644 index 0000000..3c6a609 --- /dev/null +++ b/docs/api.md @@ -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 +// 前端隐藏字段 + + +// 后端检测 +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 + + + + + +
+
+ +
+
+ +
+ +
+ + +``` + +## 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 }, +}); +``` diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 0000000..7ef2815 --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,368 @@ +# 系统架构文档 + +## 架构概述 + +Novalon Website 采用现代化的前端架构设计,基于 Next.js 16 的 App Router 模式,实现了一个高性能、可维护的企业官网系统。 + +## 技术架构 + +### 整体架构图 + +``` +┌─────────────────────────────────────────────────────────────┐ +│ 客户端 (Browser) │ +├─────────────────────────────────────────────────────────────┤ +│ React 19 + TypeScript + Tailwind CSS + Framer Motion │ +├─────────────────────────────────────────────────────────────┤ +│ Next.js 16 App Router │ +│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ +│ │ Pages │ │ Layouts │ │ Loading │ │ +│ │ (路由页面) │ │ (布局组件) │ │ (加载状态) │ │ +│ └─────────────┘ └─────────────┘ └─────────────┘ │ +├─────────────────────────────────────────────────────────────┤ +│ 组件层 (Components) │ +│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ +│ │ UI 组件 │ │ 布局组件 │ │ 业务组件 │ │ +│ │ (shadcn) │ │ (Layout) │ │ (Sections) │ │ +│ └─────────────┘ └─────────────┘ └─────────────┘ │ +├─────────────────────────────────────────────────────────────┤ +│ 服务层 (Services) │ +│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ +│ │ API Routes │ │ Server │ │ Utilities │ │ +│ │ (Next.js) │ │ Actions │ │ (lib) │ │ +│ └─────────────┘ └─────────────┘ └─────────────┘ │ +├─────────────────────────────────────────────────────────────┤ +│ 外部服务 (External) │ +│ ┌─────────────┐ ┌─────────────┐ │ +│ │ Resend │ │ CDN │ │ +│ │ (邮件服务) │ │ (静态资源) │ │ +│ └─────────────┘ └─────────────┘ │ +└─────────────────────────────────────────────────────────────┘ +``` + +### 技术选型理由 + +| 技术 | 选型理由 | +|------|----------| +| Next.js 16 | 支持 App Router、静态导出、SEO 优化、服务端渲染 | +| React 19 | 最新特性、并发渲染、服务端组件支持 | +| TypeScript | 类型安全、开发体验提升、代码可维护性 | +| Tailwind CSS 4 | 原子化 CSS、快速开发、CSS-in-JS 零运行时 | +| Framer Motion | 声明式动画、手势支持、性能优秀 | +| shadcn/ui | 可定制、无依赖锁定、Radix UI 基础 | + +## 目录结构设计 + +### App Router 路由组织 + +``` +src/app/ +├── layout.tsx # 根布局 - 全局 Provider、字体、元数据 +├── error.tsx # 全局错误边界 +├── not-found.tsx # 404 页面 +├── globals.css # 全局样式 +│ +├── (marketing)/ # 营销页面路由组 +│ ├── layout.tsx # 营销布局 - Header + Footer +│ ├── page.tsx # 首页 +│ ├── about/ # 关于我们 +│ ├── services/ # 核心业务 +│ │ ├── page.tsx # 列表页 +│ │ └── [id]/ # 详情页 (动态路由) +│ ├── products/ # 产品服务 +│ ├── cases/ # 成功案例 +│ ├── news/ # 新闻动态 +│ │ ├── page.tsx # 列表页 +│ │ └── [slug]/ # 详情页 +│ └── contact/ # 联系我们 +│ ├── page.tsx # 页面 +│ └── actions.ts # Server Actions +│ +├── api/ # API 路由 +│ └── contact/route.ts # 联系表单 API +│ +├── privacy/ # 隐私政策 +├── terms/ # 服务条款 +└── preview/ # 预览页面 +``` + +### 组件目录组织 + +``` +src/components/ +├── ui/ # 基础 UI 组件 (shadcn/ui) +│ ├── button.tsx # 按钮 +│ ├── card.tsx # 卡片 +│ ├── dialog.tsx # 对话框 +│ ├── input.tsx # 输入框 +│ ├── textarea.tsx # 文本域 +│ ├── dropdown-menu.tsx # 下拉菜单 +│ ├── toast.tsx # 提示 +│ └── ... +│ +├── layout/ # 布局组件 +│ ├── header.tsx # 页头导航 +│ ├── footer.tsx # 页脚 +│ ├── mobile-menu.tsx # 移动端菜单 +│ ├── mobile-tab-bar.tsx # 移动端底部导航 +│ └── breadcrumb.tsx # 面包屑 +│ +├── sections/ # 页面区块组件 +│ ├── hero-section.tsx # Hero 区域 +│ ├── services-section.tsx # 服务区块 +│ ├── products-section.tsx # 产品区块 +│ ├── cases-section.tsx # 案例区块 +│ ├── about-section.tsx # 关于区块 +│ ├── news-section.tsx # 新闻区块 +│ └── contact-section.tsx # 联系区块 +│ +├── effects/ # 视觉效果组件 +│ ├── gradient-flow.tsx # 渐变流动 +│ ├── data-particle-flow.tsx # 数据粒子 +│ ├── geometric-shapes.tsx # 几何图形 +│ ├── glow-effect.tsx # 发光效果 +│ └── ... +│ +├── seo/ # SEO 组件 +│ └── structured-data.tsx # 结构化数据 +│ +└── analytics/ # 分析组件 + └── web-vitals.tsx # Web Vitals 监控 +``` + +## 核心模块设计 + +### 1. 路由系统 + +#### 路由组 (Route Groups) + +使用 `(marketing)` 路由组将营销相关页面组织在一起,共享相同的布局: + +```tsx +// src/app/(marketing)/layout.tsx +export default function MarketingLayout({ children }) { + return ( +
+
+ +
{children}
+
+
+ ); +} +``` + +#### 动态路由 + +支持动态路由参数,如服务详情、产品详情、案例详情、新闻详情: + +```tsx +// src/app/(marketing)/services/[id]/page.tsx +export default function ServiceDetailPage({ params }) { + return ; +} +``` + +### 2. 状态管理 + +#### Context 使用 + +- `ThemeProvider` - 主题状态管理 +- `WebVitals` - 性能指标监控 + +#### 本地状态 + +组件内部使用 React Hooks 管理本地状态: +- `useState` - 组件状态 +- `useEffect` - 副作用处理 +- `useCallback` - 回调优化 +- `useRef` - DOM 引用 + +### 3. 数据流 + +``` +┌─────────────┐ ┌─────────────┐ ┌─────────────┐ +│ 用户交互 │ ──▶ │ 表单验证 │ ──▶ │ API 请求 │ +└─────────────┘ └─────────────┘ └─────────────┘ + │ + ▼ +┌─────────────┐ ┌─────────────┐ ┌─────────────┐ +│ UI 更新 │ ◀── │ 状态更新 │ ◀── │ 响应处理 │ +└─────────────┘ └─────────────┘ └─────────────┘ +``` + +### 4. 样式系统 + +#### Tailwind CSS 配置 + +- CSS Variables 驱动主题 +- 响应式断点:sm, md, lg, xl, 2xl +- 自定义颜色变量 + +#### 类名管理 + +使用 `cn()` 工具函数合并类名: + +```tsx +import { cn } from '@/lib/utils'; + + + +// 变体 + + + + + + + +// 尺寸 + + + + +``` + +#### Card 卡片 + +```tsx +import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from '@/components/ui/card'; + + + + 标题 + 描述文字 + + 内容区域 + 底部操作 + +``` + +#### Input 输入框 + +```tsx +import { Input } from '@/components/ui/input'; + + +``` + +#### Textarea 文本域 + +```tsx +import { Textarea } from '@/components/ui/textarea'; + +