diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..33b6c22 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,151 @@ +# 更新日志 + +本文档记录了三算命项目的所有重要更改。 + +格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/), +并且本项目遵循 [语义化版本](https://semver.org/lang/zh-CN/)。 + +## [未发布] + +### 计划中 +- 添加更多命理分析类型 +- 实现分析结果导出功能 +- 添加用户收藏夹功能 +- 支持多语言国际化 +- 添加移动端原生应用 + +## [1.0.0] - 2024-01-01 + +### 新增 +- 🎉 项目初始发布 +- ✨ 八字命理分析功能 + - 四柱排盘计算 + - 五行平衡分析 + - 格局判断 + - 性格特质解读 + - 事业财运分析 + - 健康运势预测 +- ✨ 紫微斗数分析功能 + - 星盘排布计算 + - 十二宫位分析 + - 主星特质解读 + - 四化飞星系统 + - 大限流年分析 +- ✨ 易经占卜功能 + - 梅花易数起卦 + - 卦象详细解读 + - 变卦分析 + - 人生指导建议 +- ✨ 用户系统 + - 用户注册登录 + - 个人资料管理 + - 分析历史记录 + - 数据安全保护 +- ✨ 现代化界面 + - 响应式设计 + - 中国风UI主题 + - 流畅的交互动画 + - 无障碍设计支持 + +### 技术特性 +- 🛠️ React 18.3.1 + TypeScript +- 🛠️ Vite 6.0.1 构建工具 +- 🛠️ Tailwind CSS 样式框架 +- 🛠️ Radix UI 组件库 +- 🛠️ Supabase 后端服务 +- 🛠️ Edge Functions 服务端逻辑 +- 🛠️ PostgreSQL 数据库 +- 🛠️ JWT 用户认证 +- 🛠️ 实时数据同步 + +### 安全特性 +- 🔒 行级安全策略 (RLS) +- 🔒 数据传输加密 +- 🔒 用户输入验证 +- 🔒 CORS 安全配置 +- 🔒 环境变量保护 + +### 性能优化 +- ⚡ 代码分割和懒加载 +- ⚡ 图片懒加载 +- ⚡ 静态资源缓存 +- ⚡ CDN 加速 +- ⚡ 数据库查询优化 + +### 开发体验 +- 🔧 完整的 TypeScript 类型定义 +- 🔧 ESLint 代码规范检查 +- 🔧 Prettier 代码格式化 +- 🔧 Git Hooks 预提交检查 +- 🔧 VS Code 开发配置 +- 🔧 热重载开发服务器 + +### 文档 +- 📚 详细的 README 文档 +- 📚 API 接口文档 +- 📚 部署指南 +- 📚 开发指南 +- 📚 贡献指南 + +## 版本说明 + +### 版本号格式 + +本项目使用语义化版本号:`主版本号.次版本号.修订号` + +- **主版本号**:不兼容的 API 修改 +- **次版本号**:向下兼容的功能性新增 +- **修订号**:向下兼容的问题修正 + +### 更新类型说明 + +- `新增` - 新功能 +- `更改` - 对现有功能的更改 +- `弃用` - 即将移除的功能 +- `移除` - 已移除的功能 +- `修复` - 问题修复 +- `安全` - 安全相关的修复 + +### 发布周期 + +- **主版本**:根据重大功能更新发布,无固定周期 +- **次版本**:每月发布,包含新功能和改进 +- **修订版本**:根据需要发布,主要用于修复问题 + +### 支持政策 + +- **当前版本**:完全支持,包括新功能开发和问题修复 +- **前一个主版本**:仅提供安全更新和重要问题修复 +- **更早版本**:不再提供支持,建议升级 + +### 升级指南 + +#### 从 0.x 升级到 1.0.0 + +由于这是首个正式版本,不存在升级问题。 + +#### 未来版本升级 + +我们将在每个版本发布时提供详细的升级指南,包括: + +1. **破坏性更改**:列出所有不兼容的更改 +2. **迁移步骤**:提供详细的迁移指导 +3. **新功能介绍**:说明新增功能的使用方法 +4. **配置更改**:说明配置文件的更改 +5. **数据库迁移**:提供数据库结构更改的迁移脚本 + +### 反馈和建议 + +如果您在使用过程中遇到问题或有改进建议,请通过以下方式联系我们: + +- [GitHub Issues](https://github.com/patdelphi/suanming/issues) - 问题报告和功能请求 +- [GitHub Discussions](https://github.com/patdelphi/suanming/discussions) - 讨论和建议 +- [项目主页](https://github.com/patdelphi/suanming) - 项目信息和文档 + +### 贡献者 + +感谢所有为本项目做出贡献的开发者和用户! + +--- + +**注意**:本更新日志将持续更新,记录项目的所有重要更改。建议用户在升级前仔细阅读相关版本的更新内容。 \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9a21b30 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 三算命 (Suanming) Project Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index 74872fd..c92e294 100644 --- a/README.md +++ b/README.md @@ -1,50 +1,208 @@ -# React + TypeScript + Vite +# 三算命 - AI智能命理分析平台 -This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. +一个基于现代Web技术构建的智能命理分析平台,融合传统中华命理学说与AI技术,为用户提供专业的八字命理、紫微斗数、易经占卜等服务。 -Currently, two official plugins are available: +## 🌟 项目特色 -- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh -- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh +- **传统与现代结合**:将千年传承的中华命理学说与现代AI技术完美融合 +- **多元化分析**:支持八字命理、紫微斗数、易经占卜三大主流命理体系 +- **智能化算法**:采用先进的算法确保分析结果的准确性和个性化 +- **现代化界面**:采用现代化UI设计,提供优雅的用户体验 +- **数据安全**:基于Supabase的安全数据存储和用户认证系统 -## Expanding the ESLint configuration +## 🎯 核心功能 -If you are developing a production application, we recommend updating the configuration to enable type aware lint rules: +### 八字命理分析 +- **四柱排盘**:精确计算年、月、日、时四柱干支 +- **五行分析**:深度分析五行平衡与缺失 +- **格局判断**:识别命格特点和层次 +- **运势预测**:提供大运、流年运势分析 +- **性格解读**:基于八字特征分析性格特质 +- **事业指导**:提供职业发展建议 -- Configure the top-level `parserOptions` property like this: +### 紫微斗数分析 +- **星盘排布**:精确计算紫微星盘和十二宫位 +- **主星分析**:解读命宫主星特质 +- **宫位解读**:详细分析十二宫位含义 +- **四化飞星**:分析化禄、化权、化科、化忌 +- **大限分析**:提供人生各阶段运势预测 +- **流年运势**:年度运势详细解读 -```js -export default tseslint.config({ - languageOptions: { - // other options... - parserOptions: { - project: ['./tsconfig.node.json', './tsconfig.app.json'], - tsconfigRootDir: import.meta.dirname, - }, - }, -}) +### 易经占卜 +- **梅花易数**:采用传统梅花易数起卦方法 +- **卦象解读**:详细解释卦象含义和象征 +- **变卦分析**:分析卦象变化和发展趋势 +- **人生指导**:提供决策建议和人生智慧 +- **时机把握**:分析最佳行动时机 + +## 🛠️ 技术栈 + +### 前端技术 +- **React 18.3.1** - 现代化前端框架 +- **TypeScript** - 类型安全的JavaScript超集 +- **Vite 6.0.1** - 快速的构建工具 +- **React Router 6** - 客户端路由管理 +- **Tailwind CSS** - 实用优先的CSS框架 +- **Radix UI** - 高质量的无障碍UI组件库 +- **Lucide React** - 美观的图标库 +- **React Hook Form** - 高性能表单库 +- **Zod** - TypeScript优先的模式验证 + +### 后端服务 +- **Supabase** - 开源的Firebase替代方案 +- **PostgreSQL** - 可靠的关系型数据库 +- **Edge Functions** - 服务端逻辑处理 +- **实时数据库** - 实时数据同步 +- **身份认证** - 安全的用户认证系统 + +### 开发工具 +- **ESLint** - 代码质量检查 +- **TypeScript ESLint** - TypeScript代码规范 +- **PostCSS** - CSS后处理器 +- **Autoprefixer** - CSS自动前缀 + +## 🚀 快速开始 + +### 环境要求 +- Node.js >= 18.0.0 +- pnpm >= 8.0.0 (推荐) 或 npm >= 9.0.0 + +### 安装步骤 + +1. **克隆项目** +```bash +git clone https://github.com/patdelphi/suanming.git +cd suanming ``` -- Replace `tseslint.configs.recommended` to `tseslint.configs.recommendedTypeChecked` or `tseslint.configs.strictTypeChecked` -- Optionally add `...tseslint.configs.stylisticTypeChecked` -- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and update the config: - -```js -// eslint.config.js -import react from 'eslint-plugin-react' - -export default tseslint.config({ - // Set the react version - settings: { react: { version: '18.3' } }, - plugins: { - // Add the react plugin - react, - }, - rules: { - // other rules... - // Enable its recommended rules - ...react.configs.recommended.rules, - ...react.configs['jsx-runtime'].rules, - }, -}) +2. **安装依赖** +```bash +pnpm install +# 或者使用 npm +npm install ``` + +3. **环境配置** + +创建 `.env.local` 文件并配置以下环境变量: +```env +VITE_SUPABASE_URL=your_supabase_project_url +VITE_SUPABASE_ANON_KEY=your_supabase_anon_key +``` + +4. **启动开发服务器** +```bash +pnpm dev +# 或者使用 npm +npm run dev +``` + +5. **访问应用** + +打开浏览器访问 `http://localhost:5173` + +### 构建部署 + +```bash +# 构建生产版本 +pnpm build + +# 预览构建结果 +pnpm preview +``` + +## 📁 项目结构 + +``` +src/ +├── components/ # 可复用组件 +│ ├── ui/ # 基础UI组件 +│ ├── Layout.tsx # 布局组件 +│ ├── AnalysisResultDisplay.tsx # 分析结果展示 +│ └── ... +├── pages/ # 页面组件 +│ ├── HomePage.tsx # 首页 +│ ├── AnalysisPage.tsx # 分析页面 +│ ├── HistoryPage.tsx # 历史记录 +│ └── ... +├── contexts/ # React上下文 +│ └── AuthContext.tsx # 认证上下文 +├── hooks/ # 自定义Hook +├── lib/ # 工具库 +│ ├── supabase.ts # Supabase客户端 +│ └── utils.ts # 工具函数 +├── types/ # TypeScript类型定义 +└── data/ # 静态数据 +``` + +## 🎨 设计特色 + +- **中国风设计**:采用传统中国元素和配色方案 +- **响应式布局**:完美适配桌面端和移动端 +- **无障碍设计**:遵循WCAG无障碍设计标准 +- **暗色模式**:支持明暗主题切换 +- **动画效果**:流畅的交互动画提升用户体验 + +## 🔐 安全特性 + +- **用户认证**:基于Supabase的安全认证系统 +- **数据加密**:敏感数据传输和存储加密 +- **权限控制**:细粒度的用户权限管理 +- **输入验证**:严格的前后端数据验证 +- **HTTPS支持**:全站HTTPS加密传输 + +## 📱 功能模块 + +### 用户系统 +- 用户注册/登录 +- 个人资料管理 +- 分析历史记录 +- 收藏夹功能 + +### 分析系统 +- 多种分析类型选择 +- 实时分析结果生成 +- 详细报告导出 +- 结果分享功能 + +### 数据管理 +- 分析记录存储 +- 数据备份恢复 +- 隐私设置管理 + +## 🤝 贡献指南 + +我们欢迎所有形式的贡献,包括但不限于: + +- 🐛 Bug报告 +- 💡 功能建议 +- 📝 文档改进 +- 🔧 代码贡献 + +### 开发流程 + +1. Fork本项目 +2. 创建特性分支 (`git checkout -b feature/AmazingFeature`) +3. 提交更改 (`git commit -m 'Add some AmazingFeature'`) +4. 推送到分支 (`git push origin feature/AmazingFeature`) +5. 创建Pull Request + +## 📄 许可证 + +本项目采用 MIT 许可证 - 查看 [LICENSE](LICENSE) 文件了解详情。 + +## 🙏 致谢 + +- 感谢所有贡献者的辛勤付出 +- 感谢开源社区提供的优秀工具和库 +- 感谢传统命理学大师们的智慧传承 + +## 📞 联系我们 + +- 项目主页:[https://github.com/patdelphi/suanming](https://github.com/patdelphi/suanming) +- 问题反馈:[Issues](https://github.com/patdelphi/suanming/issues) +- 功能建议:[Discussions](https://github.com/patdelphi/suanming/discussions) + +--- + +**三算命** - 让传统智慧与现代技术完美融合,为您的人生提供智慧指引。 diff --git a/docs/API.md b/docs/API.md new file mode 100644 index 0000000..2c461b5 --- /dev/null +++ b/docs/API.md @@ -0,0 +1,441 @@ +# API 文档 + +本文档描述了三算命平台的后端API接口,所有API都基于Supabase Edge Functions实现。 + +## 基础信息 + +- **Base URL**: `https://your-project.supabase.co/functions/v1` +- **认证方式**: Bearer Token (Supabase JWT) +- **数据格式**: JSON +- **字符编码**: UTF-8 + +## 通用响应格式 + +### 成功响应 +```json +{ + "data": { + "record_id": "uuid", + "analysis": { + // 分析结果数据 + } + } +} +``` + +### 错误响应 +```json +{ + "error": { + "code": "ERROR_CODE", + "message": "错误描述信息" + } +} +``` + +## 认证 + +所有API请求都需要在请求头中包含认证信息: + +```http +Authorization: Bearer +Content-Type: application/json +``` + +## API 接口 + +### 1. 八字命理分析 + +**接口地址**: `POST /bazi-analyzer` + +**请求参数**: +```json +{ + "user_id": "string", + "birth_data": { + "name": "string", + "birth_date": "YYYY-MM-DD", + "birth_time": "HH:MM", + "gender": "male|female", + "birth_place": "string" + } +} +``` + +**响应示例**: +```json +{ + "data": { + "record_id": "123e4567-e89b-12d3-a456-426614174000", + "analysis": { + "bazi": { + "year": "甲子", + "month": "丙寅", + "day": "戊辰", + "hour": "庚申" + }, + "wuxing": { + "wood": 2, + "fire": 1, + "earth": 2, + "metal": 2, + "water": 1 + }, + "analysis": { + "character": "性格分析内容", + "career": "事业分析内容", + "wealth": "财运分析内容", + "health": "健康分析内容", + "relationships": "感情分析内容" + } + } + } +} +``` + +### 2. 紫微斗数分析 + +**接口地址**: `POST /ziwei-analyzer` + +**请求参数**: +```json +{ + "user_id": "string", + "birth_data": { + "name": "string", + "birth_date": "YYYY-MM-DD", + "birth_time": "HH:MM", + "gender": "male|female", + "birth_place": "string" + } +} +``` + +**响应示例**: +```json +{ + "data": { + "record_id": "123e4567-e89b-12d3-a456-426614174000", + "analysis": { + "ziwei": { + "ming_gong": "子", + "ming_gong_xing": ["紫微", "天机"], + "shi_er_gong": { + "命宫": { + "branch": "子", + "main_stars": ["紫微", "天机"], + "interpretation": "命宫解读内容" + } + // ... 其他宫位 + }, + "si_hua": { + "hua_lu": { + "star": "廉贞", + "meaning": "财禄亨通,运势顺遂" + }, + "hua_quan": { + "star": "破军", + "meaning": "权力地位,事业有成" + }, + "hua_ke": { + "star": "武曲", + "meaning": "贵人相助,学业有成" + }, + "hua_ji": { + "star": "太阳", + "meaning": "需要谨慎,防范风险" + } + } + }, + "analysis": { + "character": { + "overview": "性格概述", + "personality_traits": "性格特质" + }, + "career": { + "suitable_industries": ["行业1", "行业2"], + "career_advice": "事业建议" + }, + "wealth": { + "wealth_pattern": "财富模式" + }, + "health": { + "constitution": "体质分析", + "wellness_advice": "健康建议" + }, + "relationships": { + "marriage_fortune": "婚姻运势", + "spouse_characteristics": "伴侣特质" + } + } + } + } +} +``` + +### 3. 易经占卜分析 + +**接口地址**: `POST /yijing-analyzer` + +**请求参数**: +```json +{ + "user_id": "string", + "divination_data": { + "question": "string", + "method": "梅花易数时间起卦法", + "divination_time": "YYYY-MM-DDTHH:MM:SSZ" + } +} +``` + +**响应示例**: +```json +{ + "data": { + "record_id": "123e4567-e89b-12d3-a456-426614174000", + "analysis": { + "basic_info": { + "divination_data": { + "question": "占卜问题", + "method": "梅花易数时间起卦法", + "divination_time": "2024-01-01T12:00:00Z" + }, + "hexagram_info": { + "main_hexagram": "乾为天", + "hexagram_description": "卦辞内容", + "upper_trigram": "乾", + "lower_trigram": "乾", + "detailed_interpretation": "详细解释" + } + }, + "detailed_analysis": { + "hexagram_analysis": { + "primary_meaning": "主要含义", + "judgment": "吉凶断语", + "image": "象辞解释" + }, + "changing_lines_analysis": { + "changing_line_position": "六二", + "line_meaning": "爻辞含义" + }, + "changing_hexagram": { + "name": "变卦名称", + "meaning": "变卦含义", + "transformation_insight": "变化启示" + } + }, + "life_guidance": { + "overall_fortune": "整体运势", + "career_guidance": "事业指导", + "relationship_guidance": "情感指导", + "wealth_guidance": "财运指导" + }, + "divination_wisdom": { + "key_message": "核心信息", + "action_advice": "行动建议", + "philosophical_insight": "哲学启示" + } + } + } +} +``` + +### 4. 五行分析 + +**接口地址**: `POST /bazi-wuxing-analysis` + +**请求参数**: +```json +{ + "user_id": "string", + "birth_data": { + "name": "string", + "birth_date": "YYYY-MM-DD", + "birth_time": "HH:MM", + "gender": "male|female" + } +} +``` + +**响应示例**: +```json +{ + "data": { + "record_id": "123e4567-e89b-12d3-a456-426614174000", + "analysis": { + "wuxing_distribution": { + "wood": 2, + "fire": 1, + "earth": 2, + "metal": 2, + "water": 1 + }, + "balance_analysis": { + "dominant_element": "wood", + "lacking_element": "fire", + "balance_score": 75 + }, + "recommendations": { + "colors": ["红色", "橙色"], + "directions": ["南方"], + "career_fields": ["文化教育", "艺术创作"], + "lifestyle_advice": "生活建议内容" + } + } + } +} +``` + +### 5. 八字详细分析 + +**接口地址**: `POST /bazi-details` + +**请求参数**: +```json +{ + "user_id": "string", + "birth_data": { + "name": "string", + "birth_date": "YYYY-MM-DD", + "birth_time": "HH:MM", + "gender": "male|female", + "birth_place": "string" + } +} +``` + +**响应示例**: +```json +{ + "data": { + "record_id": "123e4567-e89b-12d3-a456-426614174000", + "analysis": { + "basic_info": { + "bazi": { + "year": "甲子", + "month": "丙寅", + "day": "戊辰", + "hour": "庚申" + }, + "solar_terms": "立春后", + "lunar_info": { + "lunar_date": "农历日期", + "lunar_month": "农历月份" + } + }, + "detailed_analysis": { + "daymaster_analysis": "日主分析", + "pattern_analysis": "格局分析", + "useful_god": "用神分析", + "taboo_god": "忌神分析" + }, + "life_stages": { + "childhood": "童年运势", + "youth": "青年运势", + "middle_age": "中年运势", + "old_age": "晚年运势" + }, + "annual_fortune": [ + { + "year": 2024, + "fortune": "年运分析", + "advice": "建议事项" + } + ] + } + } +} +``` + +## 错误代码 + +| 错误代码 | 描述 | HTTP状态码 | +|---------|------|----------| +| INVALID_JSON | 请求JSON格式错误 | 400 | +| MISSING_PARAMETERS | 缺少必需参数 | 400 | +| INVALID_DATE_FORMAT | 日期格式错误 | 400 | +| INVALID_TIME_FORMAT | 时间格式错误 | 400 | +| UNAUTHORIZED | 未授权访问 | 401 | +| FORBIDDEN | 禁止访问 | 403 | +| ANALYSIS_ERROR | 分析过程错误 | 500 | +| DATABASE_ERROR | 数据库操作错误 | 500 | +| INTERNAL_ERROR | 内部服务器错误 | 500 | + +## 使用示例 + +### JavaScript/TypeScript + +```typescript +import { createClient } from '@supabase/supabase-js' + +const supabase = createClient( + 'https://your-project.supabase.co', + 'your-anon-key' +) + +// 八字分析示例 +async function analyzeBazi(birthData: any) { + const { data, error } = await supabase.functions.invoke('bazi-analyzer', { + body: { + user_id: 'user-uuid', + birth_data: birthData + } + }) + + if (error) { + console.error('分析失败:', error) + return null + } + + return data +} + +// 使用示例 +const result = await analyzeBazi({ + name: '张三', + birth_date: '1990-01-01', + birth_time: '12:00', + gender: 'male', + birth_place: '北京市' +}) +``` + +### cURL + +```bash +# 八字分析 +curl -X POST 'https://your-project.supabase.co/functions/v1/bazi-analyzer' \ + -H 'Authorization: Bearer YOUR_JWT_TOKEN' \ + -H 'Content-Type: application/json' \ + -d '{ + "user_id": "user-uuid", + "birth_data": { + "name": "张三", + "birth_date": "1990-01-01", + "birth_time": "12:00", + "gender": "male", + "birth_place": "北京市" + } + }' +``` + +## 注意事项 + +1. **请求频率限制**: 每个用户每分钟最多50次请求 +2. **数据格式**: 所有日期使用ISO 8601格式 (YYYY-MM-DD) +3. **时间格式**: 使用24小时制 (HH:MM) +4. **字符编码**: 所有文本数据使用UTF-8编码 +5. **数据安全**: 敏感信息会被加密存储 +6. **缓存策略**: 相同参数的分析结果会被缓存24小时 + +## 更新日志 + +### v1.0.0 (2024-01-01) +- 初始版本发布 +- 支持八字命理、紫微斗数、易经占卜三大分析功能 +- 完整的用户认证和数据存储功能 + +--- + +如有疑问或需要技术支持,请通过GitHub Issues联系我们。 \ No newline at end of file diff --git a/docs/DEPLOYMENT.md b/docs/DEPLOYMENT.md new file mode 100644 index 0000000..e5810c6 --- /dev/null +++ b/docs/DEPLOYMENT.md @@ -0,0 +1,521 @@ +# 部署指南 + +本文档详细说明如何将三算命平台部署到各种环境中。 + +## 目录 + +- [环境要求](#环境要求) +- [Supabase 配置](#supabase-配置) +- [前端部署](#前端部署) + - [Vercel 部署](#vercel-部署) + - [Netlify 部署](#netlify-部署) + - [GitHub Pages 部署](#github-pages-部署) + - [自托管部署](#自托管部署) +- [Edge Functions 部署](#edge-functions-部署) +- [环境变量配置](#环境变量配置) +- [域名配置](#域名配置) +- [SSL 证书](#ssl-证书) +- [监控和日志](#监控和日志) +- [故障排除](#故障排除) + +## 环境要求 + +### 开发环境 +- Node.js >= 18.0.0 +- pnpm >= 8.0.0 (推荐) 或 npm >= 9.0.0 +- Git >= 2.0.0 + +### 生产环境 +- 支持静态文件托管的服务器或CDN +- Supabase 项目 (后端服务) +- 域名 (可选) +- SSL 证书 (推荐) + +## Supabase 配置 + +### 1. 创建 Supabase 项目 + +1. 访问 [Supabase](https://supabase.com) 并创建账户 +2. 创建新项目 +3. 等待项目初始化完成 +4. 记录项目URL和API密钥 + +### 2. 数据库设置 + +在 Supabase SQL 编辑器中执行以下SQL创建必要的表: + +```sql +-- 创建用户资料表 +CREATE TABLE IF NOT EXISTS user_profiles ( + id UUID REFERENCES auth.users(id) PRIMARY KEY, + username TEXT UNIQUE, + full_name TEXT, + avatar_url TEXT, + birth_date DATE, + birth_time TIME, + birth_place TEXT, + gender TEXT CHECK (gender IN ('male', 'female')), + created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), + updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() +); + +-- 创建命理分析记录表 +CREATE TABLE IF NOT EXISTS numerology_readings ( + id UUID DEFAULT gen_random_uuid() PRIMARY KEY, + user_id UUID REFERENCES auth.users(id) NOT NULL, + reading_type TEXT NOT NULL CHECK (reading_type IN ('bazi', 'ziwei', 'yijing', 'wuxing')), + name TEXT, + birth_date DATE, + birth_time TIME, + gender TEXT CHECK (gender IN ('male', 'female')), + birth_place TEXT, + input_data JSONB, + results JSONB, + analysis JSONB, + status TEXT DEFAULT 'pending' CHECK (status IN ('pending', 'processing', 'completed', 'failed')), + created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), + updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() +); + +-- 创建索引 +CREATE INDEX IF NOT EXISTS idx_numerology_readings_user_id ON numerology_readings(user_id); +CREATE INDEX IF NOT EXISTS idx_numerology_readings_type ON numerology_readings(reading_type); +CREATE INDEX IF NOT EXISTS idx_numerology_readings_created_at ON numerology_readings(created_at DESC); + +-- 启用行级安全策略 +ALTER TABLE user_profiles ENABLE ROW LEVEL SECURITY; +ALTER TABLE numerology_readings ENABLE ROW LEVEL SECURITY; + +-- 用户资料访问策略 +CREATE POLICY "Users can view own profile" ON user_profiles + FOR SELECT USING (auth.uid() = id); + +CREATE POLICY "Users can update own profile" ON user_profiles + FOR UPDATE USING (auth.uid() = id); + +CREATE POLICY "Users can insert own profile" ON user_profiles + FOR INSERT WITH CHECK (auth.uid() = id); + +-- 命理分析记录访问策略 +CREATE POLICY "Users can view own readings" ON numerology_readings + FOR SELECT USING (auth.uid() = user_id); + +CREATE POLICY "Users can insert own readings" ON numerology_readings + FOR INSERT WITH CHECK (auth.uid() = user_id); + +CREATE POLICY "Users can update own readings" ON numerology_readings + FOR UPDATE USING (auth.uid() = user_id); +``` + +### 3. 认证设置 + +1. 在 Supabase 控制台中,转到 "Authentication" > "Settings" +2. 配置站点URL为你的域名 +3. 启用邮箱确认 (可选) +4. 配置第三方登录提供商 (可选) + +## 前端部署 + +### Vercel 部署 + +Vercel 是推荐的部署平台,提供优秀的性能和开发体验。 + +#### 自动部署 (推荐) + +1. 将代码推送到 GitHub 仓库 +2. 访问 [Vercel](https://vercel.com) 并登录 +3. 点击 "New Project" +4. 导入你的 GitHub 仓库 +5. 配置环境变量: + ``` + VITE_SUPABASE_URL=your_supabase_project_url + VITE_SUPABASE_ANON_KEY=your_supabase_anon_key + ``` +6. 点击 "Deploy" + +#### 手动部署 + +```bash +# 安装 Vercel CLI +npm i -g vercel + +# 登录 Vercel +vercel login + +# 构建项目 +npm run build + +# 部署 +vercel --prod +``` + +### Netlify 部署 + +#### 自动部署 + +1. 将代码推送到 GitHub 仓库 +2. 访问 [Netlify](https://netlify.com) 并登录 +3. 点击 "New site from Git" +4. 选择你的 GitHub 仓库 +5. 配置构建设置: + - Build command: `npm run build` + - Publish directory: `dist` +6. 配置环境变量 +7. 点击 "Deploy site" + +#### 手动部署 + +```bash +# 安装 Netlify CLI +npm install -g netlify-cli + +# 构建项目 +npm run build + +# 部署 +netlify deploy --prod --dir=dist +``` + +### GitHub Pages 部署 + +1. 在项目根目录创建 `.github/workflows/deploy.yml`: + +```yaml +name: Deploy to GitHub Pages + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + build-and-deploy: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: '18' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Build + run: npm run build + env: + VITE_SUPABASE_URL: ${{ secrets.VITE_SUPABASE_URL }} + VITE_SUPABASE_ANON_KEY: ${{ secrets.VITE_SUPABASE_ANON_KEY }} + + - name: Deploy to GitHub Pages + uses: peaceiris/actions-gh-pages@v3 + if: github.ref == 'refs/heads/main' + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./dist +``` + +2. 在 GitHub 仓库设置中配置 Secrets +3. 启用 GitHub Pages + +### 自托管部署 + +#### 使用 Nginx + +1. 构建项目: +```bash +npm run build +``` + +2. 将 `dist` 目录上传到服务器 + +3. 配置 Nginx: +```nginx +server { + listen 80; + server_name your-domain.com; + root /path/to/your/dist; + index index.html; + + # 处理 SPA 路由 + location / { + try_files $uri $uri/ /index.html; + } + + # 静态资源缓存 + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + } + + # 安全头 + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + add_header Referrer-Policy "no-referrer-when-downgrade" always; + add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always; +} +``` + +#### 使用 Apache + +1. 在 `dist` 目录创建 `.htaccess` 文件: +```apache +RewriteEngine On +RewriteBase / + +# 处理 SPA 路由 +RewriteRule ^index\.html$ - [L] +RewriteCond %{REQUEST_FILENAME} !-f +RewriteCond %{REQUEST_FILENAME} !-d +RewriteRule . /index.html [L] + +# 静态资源缓存 + + ExpiresActive On + ExpiresDefault "access plus 1 year" + +``` + +## Edge Functions 部署 + +### 1. 准备 Edge Functions + +在 Supabase 项目中创建以下 Edge Functions: + +- `bazi-analyzer` - 八字命理分析 +- `ziwei-analyzer` - 紫微斗数分析 +- `yijing-analyzer` - 易经占卜分析 +- `bazi-wuxing-analysis` - 五行分析 +- `bazi-details` - 八字详细分析 + +### 2. 部署 Edge Functions + +```bash +# 安装 Supabase CLI +npm install -g supabase + +# 登录 Supabase +supabase login + +# 链接到你的项目 +supabase link --project-ref your-project-ref + +# 部署所有函数 +supabase functions deploy + +# 或部署单个函数 +supabase functions deploy bazi-analyzer +``` + +### 3. 设置环境变量 + +```bash +# 为 Edge Functions 设置环境变量 +supabase secrets set SUPABASE_URL=your_supabase_url +supabase secrets set SUPABASE_SERVICE_ROLE_KEY=your_service_role_key +``` + +## 环境变量配置 + +### 开发环境 (.env.local) +```env +VITE_SUPABASE_URL=https://your-project.supabase.co +VITE_SUPABASE_ANON_KEY=your_anon_key +``` + +### 生产环境 +根据部署平台配置相应的环境变量: + +- **Vercel**: 在项目设置中添加环境变量 +- **Netlify**: 在站点设置中添加环境变量 +- **GitHub Actions**: 在仓库 Secrets 中添加 +- **自托管**: 在构建脚本中设置 + +## 域名配置 + +### 1. DNS 设置 + +根据部署平台配置 DNS 记录: + +- **Vercel**: 添加 CNAME 记录指向 `cname.vercel-dns.com` +- **Netlify**: 添加 CNAME 记录指向 Netlify 提供的域名 +- **自托管**: 添加 A 记录指向服务器 IP + +### 2. 自定义域名 + +在部署平台的控制台中添加自定义域名,并等待 DNS 传播完成。 + +## SSL 证书 + +大多数现代部署平台都会自动提供 SSL 证书: + +- **Vercel**: 自动提供 Let's Encrypt 证书 +- **Netlify**: 自动提供 Let's Encrypt 证书 +- **GitHub Pages**: 支持自定义域名的 HTTPS + +对于自托管,可以使用 Certbot 获取免费的 Let's Encrypt 证书: + +```bash +# 安装 Certbot +sudo apt install certbot python3-certbot-nginx + +# 获取证书 +sudo certbot --nginx -d your-domain.com + +# 设置自动续期 +sudo crontab -e +# 添加以下行: +0 12 * * * /usr/bin/certbot renew --quiet +``` + +## 监控和日志 + +### 1. 应用监控 + +推荐使用以下监控服务: + +- **Vercel Analytics**: Vercel 内置分析 +- **Google Analytics**: 网站流量分析 +- **Sentry**: 错误监控和性能监控 + +### 2. Supabase 监控 + +在 Supabase 控制台中可以查看: +- API 使用情况 +- 数据库性能 +- Edge Functions 日志 +- 认证统计 + +### 3. 日志配置 + +在生产环境中启用适当的日志级别: + +```typescript +// 生产环境日志配置 +if (import.meta.env.PROD) { + console.log = () => {} // 禁用 console.log + console.warn = () => {} // 禁用 console.warn + // 保留 console.error 用于错误报告 +} +``` + +## 故障排除 + +### 常见问题 + +#### 1. 构建失败 + +**问题**: 构建过程中出现错误 + +**解决方案**: +- 检查 Node.js 版本是否符合要求 +- 清除缓存:`rm -rf node_modules package-lock.json && npm install` +- 检查环境变量是否正确配置 + +#### 2. 路由不工作 + +**问题**: SPA 路由在生产环境中不工作 + +**解决方案**: +- 确保服务器配置了正确的回退规则 +- 检查 `vite.config.ts` 中的 base 配置 + +#### 3. API 调用失败 + +**问题**: 无法连接到 Supabase + +**解决方案**: +- 检查环境变量是否正确 +- 验证 Supabase URL 和 API 密钥 +- 检查网络连接和 CORS 设置 + +#### 4. 认证问题 + +**问题**: 用户无法登录或注册 + +**解决方案**: +- 检查 Supabase 认证设置 +- 验证站点 URL 配置 +- 检查邮箱确认设置 + +### 性能优化 + +#### 1. 代码分割 + +```typescript +// 使用动态导入进行代码分割 +const AnalysisPage = lazy(() => import('./pages/AnalysisPage')) +const HistoryPage = lazy(() => import('./pages/HistoryPage')) +``` + +#### 2. 图片优化 + +- 使用 WebP 格式 +- 实现懒加载 +- 使用 CDN 加速 + +#### 3. 缓存策略 + +```nginx +# Nginx 缓存配置 +location ~* \.(js|css)$ { + expires 1y; + add_header Cache-Control "public, immutable"; +} + +location ~* \.(png|jpg|jpeg|gif|ico|svg)$ { + expires 6M; + add_header Cache-Control "public"; +} +``` + +## 安全检查清单 + +- [ ] 启用 HTTPS +- [ ] 配置安全头 +- [ ] 启用 Supabase RLS +- [ ] 验证环境变量安全 +- [ ] 定期更新依赖 +- [ ] 配置 CSP 策略 +- [ ] 启用错误监控 +- [ ] 设置备份策略 + +## 维护和更新 + +### 1. 定期更新 + +```bash +# 检查过时的依赖 +npm outdated + +# 更新依赖 +npm update + +# 安全审计 +npm audit +npm audit fix +``` + +### 2. 数据库维护 + +- 定期备份数据库 +- 监控数据库性能 +- 清理过期数据 +- 优化查询性能 + +### 3. 监控和告警 + +设置适当的监控和告警机制: +- 应用错误率 +- 响应时间 +- 数据库连接 +- 磁盘空间使用 + +--- + +如需更多帮助,请查看我们的 [FAQ](FAQ.md) 或在 GitHub Issues 中提问。 \ No newline at end of file diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md new file mode 100644 index 0000000..3520b28 --- /dev/null +++ b/docs/DEVELOPMENT.md @@ -0,0 +1,1070 @@ +# 开发指南 + +本文档为开发者提供详细的项目架构说明、开发流程和最佳实践。 + +## 目录 + +- [项目架构](#项目架构) +- [技术栈详解](#技术栈详解) +- [开发环境设置](#开发环境设置) +- [代码规范](#代码规范) +- [组件开发](#组件开发) +- [状态管理](#状态管理) +- [API 集成](#api-集成) +- [测试策略](#测试策略) +- [性能优化](#性能优化) +- [调试技巧](#调试技巧) +- [贡献流程](#贡献流程) + +## 项目架构 + +### 整体架构 + +``` +三算命平台 +├── 前端应用 (React + TypeScript) +│ ├── 用户界面层 +│ ├── 业务逻辑层 +│ ├── 数据访问层 +│ └── 工具函数层 +├── 后端服务 (Supabase) +│ ├── 数据库 (PostgreSQL) +│ ├── 认证服务 +│ ├── Edge Functions +│ └── 实时订阅 +└── 部署平台 (Vercel/Netlify) + ├── CDN 加速 + ├── 自动部署 + └── 环境管理 +``` + +### 前端架构 + +``` +src/ +├── components/ # 组件层 +│ ├── ui/ # 基础UI组件 +│ │ ├── Button.tsx +│ │ ├── Card.tsx +│ │ ├── Input.tsx +│ │ └── Select.tsx +│ ├── Layout.tsx # 布局组件 +│ ├── AnalysisResultDisplay.tsx # 业务组件 +│ └── ErrorBoundary.tsx # 错误边界 +├── pages/ # 页面层 +│ ├── HomePage.tsx # 首页 +│ ├── AnalysisPage.tsx # 分析页面 +│ ├── HistoryPage.tsx # 历史记录 +│ └── ProfilePage.tsx # 用户资料 +├── contexts/ # 状态管理层 +│ └── AuthContext.tsx # 认证上下文 +├── hooks/ # 自定义Hook层 +│ └── use-mobile.tsx # 移动端检测 +├── lib/ # 工具函数层 +│ ├── supabase.ts # Supabase客户端 +│ └── utils.ts # 通用工具 +├── types/ # 类型定义层 +│ └── index.ts # TypeScript类型 +└── data/ # 静态数据层 +``` + +### 数据流架构 + +``` +用户交互 → 组件状态 → Context/Hook → API调用 → Supabase → 数据库 + ↓ ↓ ↓ ↓ ↓ ↓ + UI更新 ← 状态更新 ← 数据处理 ← 响应处理 ← Edge Function ← 查询结果 +``` + +## 技术栈详解 + +### 前端核心技术 + +#### React 18.3.1 +- **并发特性**: 使用 Suspense 和 lazy loading +- **Hooks**: 优先使用函数组件和 Hooks +- **错误边界**: 实现全局错误处理 + +```typescript +// 示例:使用 Suspense 进行代码分割 +import { Suspense, lazy } from 'react' + +const AnalysisPage = lazy(() => import('./pages/AnalysisPage')) + +function App() { + return ( + 加载中...}> + + + ) +} +``` + +#### TypeScript +- **严格模式**: 启用所有严格类型检查 +- **类型定义**: 为所有 API 响应定义类型 +- **泛型使用**: 提高代码复用性 + +```typescript +// 示例:API 响应类型定义 +interface BaziAnalysisResult { + bazi: { + year: string + month: string + day: string + hour: string + } + wuxing: { + wood: number + fire: number + earth: number + metal: number + water: number + } + analysis: { + character: string + career: string + wealth: string + health: string + relationships: string + } +} +``` + +#### Tailwind CSS +- **实用优先**: 使用原子化 CSS 类 +- **响应式设计**: 移动端优先的设计方法 +- **自定义主题**: 中国风配色和字体 + +```typescript +// tailwind.config.js 自定义配置 +module.exports = { + theme: { + extend: { + colors: { + 'chinese-red': '#DC143C', + 'chinese-gold': '#FFD700', + 'chinese-black': '#2C2C2C' + }, + fontFamily: { + 'chinese': ['Noto Sans SC', 'sans-serif'] + } + } + } +} +``` + +### 后端服务架构 + +#### Supabase +- **数据库**: PostgreSQL 关系型数据库 +- **认证**: JWT 基础的用户认证 +- **实时**: WebSocket 实时数据同步 +- **Edge Functions**: Deno 运行时的服务端函数 + +```typescript +// Supabase 客户端配置 +import { createClient } from '@supabase/supabase-js' + +const supabaseUrl = import.meta.env.VITE_SUPABASE_URL +const supabaseKey = import.meta.env.VITE_SUPABASE_ANON_KEY + +export const supabase = createClient(supabaseUrl, supabaseKey, { + auth: { + autoRefreshToken: true, + persistSession: true, + detectSessionInUrl: true + } +}) +``` + +## 开发环境设置 + +### 1. 环境要求 + +```bash +# 检查 Node.js 版本 +node --version # >= 18.0.0 + +# 检查 pnpm 版本 +pnpm --version # >= 8.0.0 + +# 检查 Git 版本 +git --version # >= 2.0.0 +``` + +### 2. 项目初始化 + +```bash +# 克隆项目 +git clone https://github.com/patdelphi/suanming.git +cd suanming + +# 安装依赖 +pnpm install + +# 复制环境变量模板 +cp .env.example .env.local + +# 编辑环境变量 +vim .env.local +``` + +### 3. 开发服务器 + +```bash +# 启动开发服务器 +pnpm dev + +# 启动并打开浏览器 +pnpm dev --open + +# 指定端口 +pnpm dev --port 3000 +``` + +### 4. 开发工具配置 + +#### VS Code 推荐扩展 + +```json +// .vscode/extensions.json +{ + "recommendations": [ + "bradlc.vscode-tailwindcss", + "esbenp.prettier-vscode", + "dbaeumer.vscode-eslint", + "ms-vscode.vscode-typescript-next", + "formulahendry.auto-rename-tag", + "christian-kohler.path-intellisense" + ] +} +``` + +#### VS Code 设置 + +```json +// .vscode/settings.json +{ + "editor.formatOnSave": true, + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.codeActionsOnSave": { + "source.fixAll.eslint": true + }, + "typescript.preferences.importModuleSpecifier": "relative", + "tailwindCSS.experimental.classRegex": [ + ["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"], + ["cx\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"], + ["cn\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"] + ] +} +``` + +## 代码规范 + +### ESLint 配置 + +```javascript +// eslint.config.js +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import tseslint from 'typescript-eslint' + +export default tseslint.config( + { ignores: ['dist'] }, + { + extends: [js.configs.recommended, ...tseslint.configs.recommended], + files: ['**/*.{ts,tsx}'], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + }, + plugins: { + 'react-hooks': reactHooks, + 'react-refresh': reactRefresh, + }, + rules: { + ...reactHooks.configs.recommended.rules, + 'react-refresh/only-export-components': [ + 'warn', + { allowConstantExport: true }, + ], + '@typescript-eslint/no-unused-vars': 'warn', + '@typescript-eslint/no-explicit-any': 'warn', + }, + }, +) +``` + +### 命名规范 + +```typescript +// 组件命名:PascalCase +const AnalysisResultDisplay: React.FC = () => {} + +// Hook 命名:camelCase,以 use 开头 +const useAuth = () => {} + +// 常量命名:SCREAMING_SNAKE_CASE +const API_BASE_URL = 'https://api.example.com' + +// 类型命名:PascalCase,接口以 I 开头(可选) +interface UserProfile { + id: string + name: string +} + +// 枚举命名:PascalCase +enum AnalysisType { + BAZI = 'bazi', + ZIWEI = 'ziwei', + YIJING = 'yijing' +} +``` + +### 文件组织规范 + +```typescript +// 导入顺序 +// 1. React 相关 +import React, { useState, useEffect } from 'react' + +// 2. 第三方库 +import { useNavigate } from 'react-router-dom' +import { toast } from 'sonner' + +// 3. 内部组件 +import { Button } from '../ui/Button' +import { Card } from '../ui/Card' + +// 4. 内部工具 +import { supabase } from '../../lib/supabase' +import { cn } from '../../lib/utils' + +// 5. 类型定义 +import type { AnalysisResult } from '../../types' +``` + +## 组件开发 + +### 组件结构模板 + +```typescript +// components/ExampleComponent.tsx +import React from 'react' +import { cn } from '../../lib/utils' + +// 组件属性接口 +interface ExampleComponentProps { + title: string + description?: string + variant?: 'default' | 'primary' | 'secondary' + className?: string + children?: React.ReactNode + onClick?: () => void +} + +// 组件实现 +const ExampleComponent: React.FC = ({ + title, + description, + variant = 'default', + className, + children, + onClick +}) => { + return ( +
+

{title}

+ {description &&

{description}

} + {children} +
+ ) +} + +export default ExampleComponent +``` + +### UI 组件开发 + +使用 `class-variance-authority` 创建可变样式组件: + +```typescript +// components/ui/Button.tsx +import { cva, type VariantProps } from 'class-variance-authority' +import { cn } from '../../lib/utils' + +const buttonVariants = cva( + 'inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none ring-offset-background', + { + variants: { + variant: { + default: 'bg-primary text-primary-foreground hover:bg-primary/90', + destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90', + outline: 'border border-input hover:bg-accent hover:text-accent-foreground', + secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80', + ghost: 'hover:bg-accent hover:text-accent-foreground', + link: 'underline-offset-4 hover:underline text-primary' + }, + size: { + default: 'h-10 py-2 px-4', + sm: 'h-9 px-3 rounded-md', + lg: 'h-11 px-8 rounded-md' + } + }, + defaultVariants: { + variant: 'default', + size: 'default' + } + } +) + +export interface ButtonProps + extends React.ButtonHTMLAttributes, + VariantProps { + asChild?: boolean +} + +const Button = React.forwardRef( + ({ className, variant, size, asChild = false, ...props }, ref) => { + return ( + ) + expect(screen.getByRole('button')).toBeInTheDocument() + expect(screen.getByText('Click me')).toBeInTheDocument() + }) + + it('should handle click events', () => { + const handleClick = vi.fn() + render() + + fireEvent.click(screen.getByRole('button')) + expect(handleClick).toHaveBeenCalledTimes(1) + }) + + it('should apply variant styles', () => { + render() + const button = screen.getByRole('button') + expect(button).toHaveClass('bg-destructive') + }) +}) +``` + +### E2E 测试 + +```typescript +// e2e/auth.spec.ts +import { test, expect } from '@playwright/test' + +test.describe('Authentication', () => { + test('should allow user to sign in', async ({ page }) => { + await page.goto('/login') + + await page.fill('[data-testid="email"]', 'test@example.com') + await page.fill('[data-testid="password"]', 'password123') + await page.click('[data-testid="sign-in-button"]') + + await expect(page).toHaveURL('/dashboard') + await expect(page.locator('[data-testid="user-menu"]')).toBeVisible() + }) + + test('should show error for invalid credentials', async ({ page }) => { + await page.goto('/login') + + await page.fill('[data-testid="email"]', 'invalid@example.com') + await page.fill('[data-testid="password"]', 'wrongpassword') + await page.click('[data-testid="sign-in-button"]') + + await expect(page.locator('[data-testid="error-message"]')).toBeVisible() + }) +}) +``` + +## 性能优化 + +### 代码分割 + +```typescript +// 路由级别的代码分割 +import { lazy, Suspense } from 'react' +import { Routes, Route } from 'react-router-dom' + +const HomePage = lazy(() => import('./pages/HomePage')) +const AnalysisPage = lazy(() => import('./pages/AnalysisPage')) +const HistoryPage = lazy(() => import('./pages/HistoryPage')) + +function App() { + return ( + 加载中...}> + + } /> + } /> + } /> + + + ) +} +``` + +### 组件优化 + +```typescript +// 使用 React.memo 优化组件渲染 +import React, { memo, useMemo, useCallback } from 'react' + +interface ExpensiveComponentProps { + data: any[] + onItemClick: (id: string) => void +} + +const ExpensiveComponent = memo(({ data, onItemClick }) => { + // 使用 useMemo 缓存计算结果 + const processedData = useMemo(() => { + return data.map(item => ({ + ...item, + processed: expensiveCalculation(item) + })) + }, [data]) + + // 使用 useCallback 缓存事件处理函数 + const handleClick = useCallback((id: string) => { + onItemClick(id) + }, [onItemClick]) + + return ( +
+ {processedData.map(item => ( +
handleClick(item.id)}> + {item.processed} +
+ ))} +
+ ) +}) + +function expensiveCalculation(item: any) { + // 模拟昂贵的计算 + return item.value * Math.random() +} +``` + +### 图片优化 + +```typescript +// 图片懒加载组件 +import React, { useState, useRef, useEffect } from 'react' + +interface LazyImageProps { + src: string + alt: string + className?: string + placeholder?: string +} + +const LazyImage: React.FC = ({ + src, + alt, + className, + placeholder = '/placeholder.jpg' +}) => { + const [isLoaded, setIsLoaded] = useState(false) + const [isInView, setIsInView] = useState(false) + const imgRef = useRef(null) + + useEffect(() => { + const observer = new IntersectionObserver( + ([entry]) => { + if (entry.isIntersecting) { + setIsInView(true) + observer.disconnect() + } + }, + { threshold: 0.1 } + ) + + if (imgRef.current) { + observer.observe(imgRef.current) + } + + return () => observer.disconnect() + }, []) + + return ( + {alt} setIsLoaded(true)} + style={{ + opacity: isLoaded ? 1 : 0.5, + transition: 'opacity 0.3s ease' + }} + /> + ) +} +``` + +## 调试技巧 + +### React DevTools + +```typescript +// 在开发环境中启用 React DevTools +if (import.meta.env.DEV) { + // 为组件添加显示名称 + Component.displayName = 'ComponentName' + + // 添加调试信息 + console.log('Component rendered with props:', props) +} +``` + +### 错误边界 + +```typescript +// components/ErrorBoundary.tsx +import React, { Component, ErrorInfo, ReactNode } from 'react' + +interface Props { + children: ReactNode + fallback?: ReactNode +} + +interface State { + hasError: boolean + error?: Error +} + +export class ErrorBoundary extends Component { + public state: State = { + hasError: false + } + + public static getDerivedStateFromError(error: Error): State { + return { hasError: true, error } + } + + public componentDidCatch(error: Error, errorInfo: ErrorInfo) { + console.error('ErrorBoundary caught an error:', error, errorInfo) + + // 发送错误报告到监控服务 + if (import.meta.env.PROD) { + // Sentry.captureException(error, { extra: errorInfo }) + } + } + + public render() { + if (this.state.hasError) { + return this.props.fallback || ( +
+

出现了一些问题

+

请刷新页面重试

+ {import.meta.env.DEV && ( +
+ 错误详情 +
{this.state.error?.stack}
+
+ )} +
+ ) + } + + return this.props.children + } +} +``` + +### 性能监控 + +```typescript +// lib/performance.ts +export const measurePerformance = (name: string, fn: () => void) => { + if (import.meta.env.DEV) { + const start = performance.now() + fn() + const end = performance.now() + console.log(`${name} took ${end - start} milliseconds`) + } else { + fn() + } +} + +// 使用示例 +measurePerformance('Data Processing', () => { + // 执行数据处理逻辑 + processLargeDataSet(data) +}) +``` + +## 贡献流程 + +### 1. 开发流程 + +```bash +# 1. 创建功能分支 +git checkout -b feature/new-feature + +# 2. 开发和测试 +npm run dev +npm run test +npm run lint + +# 3. 提交代码 +git add . +git commit -m "feat: add new feature" + +# 4. 推送分支 +git push origin feature/new-feature + +# 5. 创建 Pull Request +``` + +### 2. 提交信息规范 + +``` +type(scope): description + +[optional body] + +[optional footer] +``` + +类型说明: +- `feat`: 新功能 +- `fix`: 修复bug +- `docs`: 文档更新 +- `style`: 代码格式调整 +- `refactor`: 代码重构 +- `test`: 测试相关 +- `chore`: 构建过程或辅助工具的变动 + +### 3. Code Review 检查清单 + +- [ ] 代码符合项目规范 +- [ ] 包含适当的测试 +- [ ] 文档已更新 +- [ ] 性能影响已评估 +- [ ] 安全性已考虑 +- [ ] 向后兼容性已确认 +- [ ] UI/UX 符合设计规范 + +--- + +更多开发相关问题,请参考 [FAQ](FAQ.md) 或在 GitHub Issues 中讨论。 \ No newline at end of file