hookehuyr

docs: 重组文档结构并清理 API 文件

主要变更:
- 将文档从 docs/ 根目录移动到子目录(guides/, reports/, decisions/)
- 删除旧的 src/api/index.js 和 src/api/order.js 文件
- 添加 Apifox 测试脚本(debug, endpoints, export)
- 更新 Claude Code 设置以支持新的文档结构

文档结构优化:
- docs/guides/ - 操作指南和集成指南
- docs/reports/ - 技术报告和问题分析
- docs/decisions/ - 技术决策记录

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
......@@ -55,7 +55,10 @@
"Bash(pnpm dev:weapp:*)",
"Bash(tee:*)",
"Bash(node:*)",
"Bash(~/.claude/bin/check-changelog.sh:*)"
"Bash(~/.claude/bin/check-changelog.sh:*)",
"Bash(pnpm api:generate:*)",
"Bash(do if [ -d \"/Users/huyirui/program/itomix/git/manulife-weapp/docs/$dir\" ])",
"Bash(then echo \"=== $dir/ ===\" ls -1 /Users/huyirui/program/itomix/git/manulife-weapp/docs/$dir/*.md)"
]
}
}
......
# Docs 目录结构说明
## 📁 目录结构
```
docs/
├── README.md # 文档总索引(保留在顶层)
├── CHANGELOG.md # 变更日志(保留在顶层)
├── lessons-learned.md # 经验教训总结(保留在顶层)
├── PreDocs/ # 前期项目文档
│ └── 臻奇智荟圈小程序项目需求20260123a.docx
├── decisions/ # 技术决策记录
│ └── decisions.md
├── plan/ # 开发计划
│ ├── 项目开发计划.md
│ ├── 前端开发计划.md
│ └── 前端开发计划-调整版.md
├── guides/ # 指南文档
│ ├── START_HERE.md # 新人入门指南
│ ├── API_USAGE_EXAMPLES.md # API 使用示例
│ ├── API_DIFF_GUIDE.md # API 差异指南
│ ├── GET_VS_POST_GUIDE.md # GET vs POST 指南
│ ├── OPENAPI_TO_API_GUIDE.md # OpenAPI 转 API 指南
│ ├── JSDOC_GENERATION_GUIDE.md # JSDoc 生成指南
│ ├── apifox-integration-guide.md # Apifox 集成指南
│ ├── changelog-check-guide.md # CHANGELOG 检查指南
│ └── 腾讯元宝AI接入说明.md # 腾讯元宝 AI 接入说明
├── reports/ # 问题修复与实施报告
│ ├── COMPLETION_REPORT.md # 完成报告
│ ├── FINAL_FIX_REPORT.md # 最终修复报告
│ ├── IMPLEMENTATION_SUMMARY.md # 实施总结
│ ├── GET_POST_FIX.md # GET/POST 修复
│ ├── RENAME_TEST_REPORT.md # 重命名测试报告
│ ├── apifox-setup-summary.md # Apifox 设置总结
│ ├── changelog-check-report-20260201.md # CHANGELOG 检查报告
│ ├── changes-summary.md # 变更总结
│ ├── DOCUMENT_ICONS_UPDATE.md # 文档图标更新
│ ├── search-fix-summary.md # 搜索修复总结
│ └── search-problems-analysis.md # 搜索问题分析
├── design/ # UI/UX 设计文档
│ └── manulife-V1/
│ ├── done/ # 已完成的设计稿
│ │ ├── 首页/
│ │ ├── 入职相关/
│ │ ├── 签单相关/
│ │ ├── 资料知识库/
│ │ ├── 资料列表/
│ │ ├── 产品详情/
│ │ ├── 计划书/
│ │ ├── 我的/
│ │ ├── 我的收藏/
│ │ ├── 修改头像/
│ │ ├── 意见反馈/
│ │ └── 帮助中心/
│ └── 录入计划书/
│ ├── 方案A/
│ └── 方案B/
└── mcp/ # MCP 相关文档
├── MCP_配置测试指南.md
└── 如何切换到独立Apifox项目.md
```
## 📝 文档说明
### 顶层文档(核心文档)
| 文件 | 说明 |
|------|------|
| `README.md` | 文档总索引,快速了解项目文档结构 |
| `CHANGELOG.md` | 项目变更日志,记录所有功能、修复和优化 |
| `lessons-learned.md` | 开发经验教训,包含最佳实践和常见陷阱 |
### decisions/ - 技术决策记录
记录项目中的重要技术决策和设计权衡。
### plan/ - 开发计划
存放各种开发计划文档,包括整体计划和调整版计划。
### guides/ - 指南文档
开发过程中使用的各种指南文档,帮助开发者快速上手。
### reports/ - 问题修复与实施报告
记录问题修复过程、实施总结和测试报告。
### design/ - UI/UX 设计文档
存放 UI/UX 设计稿和生成的代码。
### mcp/ - MCP 相关文档
MCP (Model Context Protocol) 相关配置和测试指南。
## 🔍 快速查找
- **我是新开发者,想快速上手** → 阅读 `guides/START_HERE.md`
- **我想了解项目的历史变更** → 查看 `CHANGELOG.md`
- **我遇到了开发问题** → 查看 `lessons-learned.md``reports/`
- **我需要添加新功能** → 先查看 `decisions/` 了解技术决策
- **我需要修改 UI** → 查看 `design/` 中的设计稿
---
**整理日期**: 2026-02-02
#!/usr/bin/env node
/**
* Apifox API 响应调试工具
*
* 功能:输出完整的 API 响应,帮助诊断问题
*/
const fs = require('fs');
const path = require('path');
const https = require('https');
// 加载配置
function loadConfig() {
const envPath = path.join(__dirname, '../.env.apifox');
const env = fs.readFileSync(envPath, 'utf-8');
const config = {};
env.split('\n').forEach(line => {
const [key, ...valueParts] = line.split('=');
const value = valueParts.join('=');
if (key && !key.startsWith('#') && value) {
config[key.trim()] = value.trim();
}
});
return config;
}
// 发送 HTTPS 请求
function httpsRequest(options) {
return new Promise((resolve, reject) => {
console.log(`📡 请求 URL: https://${options.hostname}${options.path}`);
console.log(`📋 请求头:`, JSON.stringify(options.headers, null, 2));
const req = https.request(options, (res) => {
console.log(`\n📊 响应状态码: ${res.statusCode}`);
console.log(`📋 响应头:`, JSON.stringify(res.headers, null, 2));
const chunks = [];
res.on('data', chunk => {
chunks.push(chunk);
});
res.on('end', () => {
const raw = Buffer.concat(chunks).toString('utf8').trim();
if (!raw) {
console.log('⚠️ 响应体为空');
resolve({ raw: null, statusCode: res.statusCode });
return;
}
console.log(`\n📦 响应体长度: ${raw.length} 字符`);
console.log(`📄 响应体内容:`);
console.log('---开始---');
console.log(raw);
console.log('---结束---\n');
try {
const json = JSON.parse(raw.replace(/^\uFEFF/, ''));
resolve(json);
} catch (err) {
console.error(`❌ JSON 解析失败: ${err.message}`);
resolve({ raw, parseError: err.message });
}
});
});
req.on('error', (err) => {
console.error(`❌ 请求失败: ${err.message}`);
reject(err);
});
req.end();
});
}
// 主函数
async function main() {
console.log('🔍 Apifox API 响应调试工具\n');
const config = loadConfig();
// 测试获取接口列表
console.log('========================================');
console.log('测试: 获取接口列表');
console.log('========================================\n');
const options = {
hostname: 'api.apifox.com',
path: `/api/v1/projects/${config.VITE_APIFOX_PROJECT_ID}/apis?pageSize=10`,
method: 'GET',
headers: {
'Authorization': `Bearer ${config.VITE_APIFOX_TOKEN}`,
'Content-Type': 'application/json'
}
};
try {
const response = await httpsRequest(options);
console.log('========================================');
console.log('解析结果');
console.log('========================================\n');
if (response.parseError) {
console.log(`❌ 无法解析 JSON`);
console.log(`原始响应:`, response.raw);
} else {
console.log(`✅ JSON 解析成功`);
console.log(`响应类型: ${typeof response}`);
console.log(`响应键:`, Object.keys(response));
console.log(`\ndata 类型: ${typeof response.data}`);
console.log(`data 是数组: ${Array.isArray(response.data)}`);
console.log(`data 长度: ${response.data?.length || 0}`);
console.log(`total: ${response.total}`);
if (response.data && response.data.length > 0) {
console.log(`\n第一个接口示例:`);
console.log(JSON.stringify(response.data[0], null, 2));
}
}
} catch (err) {
console.error(`\n❌ 请求失败: ${err.message}`);
}
}
main();
#!/usr/bin/env node
/**
* 测试不同的 Apifox API 端点
*/
const fs = require('fs');
const path = require('path');
const https = require('https');
// 加载配置
function loadConfig() {
const envPath = path.join(__dirname, '../.env.apifox');
const env = fs.readFileSync(envPath, 'utf-8');
const config = {};
env.split('\n').forEach(line => {
const [key, ...valueParts] = line.split('=');
const value = valueParts.join('=');
if (key && !key.startsWith('#') && value) {
config[key.trim()] = value.trim();
}
});
return config;
}
// 发送 HTTPS 请求
function httpsRequest(options) {
return new Promise((resolve, reject) => {
const req = https.request(options, (res) => {
const chunks = [];
res.on('data', chunk => {
chunks.push(chunk);
});
res.on('end', () => {
const raw = Buffer.concat(chunks).toString('utf8').trim();
if (!raw) {
resolve({ statusCode: res.statusCode, data: null, headers: res.headers });
return;
}
try {
const json = JSON.parse(raw.replace(/^\uFEFF/, ''));
resolve({ statusCode: res.statusCode, data: json, headers: res.headers });
} catch (err) {
resolve({ statusCode: res.statusCode, raw, parseError: err.message, headers: res.headers });
}
});
});
req.on('error', reject);
req.end();
});
}
// 测试端点
async function testEndpoint(config, endpointPath, description) {
console.log(`\n测试: ${description}`);
console.log(`端点: ${endpointPath}`);
const options = {
hostname: 'api.apifox.com',
path: endpointPath,
method: 'GET',
headers: {
'Authorization': `Bearer ${config.VITE_APIFOX_TOKEN}`,
'Content-Type': 'application/json'
}
};
try {
const response = await httpsRequest(options);
console.log(`状态码: ${response.statusCode}`);
console.log(`Content-Type: ${response.headers['content-type']}`);
console.log(`Content-Length: ${response.headers['content-length']}`);
if (response.parseError) {
console.log(`❌ JSON 解析失败: ${response.parseError}`);
console.log(`原始响应 (前 200 字符): ${response.raw?.substring(0, 200)}`);
} else if (response.data) {
console.log(` 成功`);
// 显示响应结构
if (Array.isArray(response.data)) {
console.log(` - data 是数组,长度: ${response.data.length}`);
} else if (typeof response.data === 'object') {
console.log(` - data 是对象,键: ${Object.keys(response.data).join(', ')}`);
}
// 如果有接口数据,显示第一个
if (Array.isArray(response.data) && response.data.length > 0) {
console.log(` - 第一个接口:`, JSON.stringify(response.data[0]).substring(0, 150));
}
} else {
console.log(`⚠️ 响应为空`);
}
return response.statusCode === 200 && response.data && (Array.isArray(response.data) ? response.data.length > 0 : true);
} catch (err) {
console.log(`❌ 请求失败: ${err.message}`);
return false;
}
}
// 主函数
async function main() {
const config = loadConfig();
const projectId = config.VITE_APIFOX_PROJECT_ID;
console.log('='.repeat(60));
console.log('测试不同的 Apifox API 端点');
console.log('='.repeat(60));
// 尝试不同的端点
const endpoints = [
{ path: `/api/v1/projects/${projectId}/apis?pageSize=10`, desc: '当前使用的端点 (/apis)' },
{ path: `/api/v1/projects/${projectId}/interfaces?pageSize=10`, desc: '尝试 /interfaces' },
{ path: `/v1/projects/${projectId}/apis?pageSize=10`, desc: '不带 /api 前缀' },
{ path: `/api/v1/projects/${projectId}/api-lists?pageSize=10`, desc: '尝试 /api-lists' },
{ path: `/api/v1/projects/${projectId}/endpoints?pageSize=10`, desc: '尝试 /endpoints' },
];
let successCount = 0;
for (const endpoint of endpoints) {
const success = await testEndpoint(config, endpoint.path, endpoint.desc);
if (success) successCount++;
}
console.log('\n' + '='.repeat(60));
console.log(`测试完成!成功: ${successCount}/${endpoints.length}`);
console.log('='.repeat(60));
}
main();
#!/usr/bin/env node
/**
* 测试 Apifox 导出 API
*/
const fs = require('fs');
const path = require('path');
const https = require('https');
// 加载配置
function loadConfig() {
const envPath = path.join(__dirname, '../.env.apifox');
const env = fs.readFileSync(envPath, 'utf-8');
const config = {};
env.split('\n').forEach(line => {
const [key, ...valueParts] = line.split('=');
const value = valueParts.join('=');
if (key && !key.startsWith('#') && value) {
config[key.trim()] = value.trim();
}
});
return config;
}
// 发送 HTTPS 请求
function httpsRequest(options) {
return new Promise((resolve, reject) => {
const req = https.request(options, (res) => {
const chunks = [];
res.on('data', chunk => {
chunks.push(chunk);
});
res.on('end', () => {
const raw = Buffer.concat(chunks).toString('utf8').trim();
if (!raw) {
resolve({ statusCode: res.statusCode, data: null, headers: res.headers });
return;
}
try {
const json = JSON.parse(raw.replace(/^\uFEFF/, ''));
resolve({ statusCode: res.statusCode, data: json, headers: res.headers });
} catch (err) {
resolve({ statusCode: res.statusCode, raw, headers: res.headers });
}
});
});
req.on('error', reject);
req.end();
});
}
// 主函数
async function main() {
const config = loadConfig();
const projectId = config.VITE_APIFOX_PROJECT_ID;
console.log('='.repeat(60));
console.log('测试 Apifox 导出 API');
console.log('='.repeat(60));
// 尝试导出 OpenAPI 格式
const exportEndpoints = [
{ path: `/api/v1/projects/${projectId}/export-openapi`, desc: '导出 OpenAPI' },
{ path: `/api/v1/projects/${projectId}/export-openapi/3.0.0`, desc: '导出 OpenAPI 3.0' },
{ path: `/api/v1/projects/${projectId}/export-openapi/3.0.0/json`, desc: '导出 OpenAPI 3.0 JSON' },
];
for (const endpoint of exportEndpoints) {
console.log(`\n测试: ${endpoint.desc}`);
console.log(`端点: ${endpoint.path}`);
const options = {
hostname: 'api.apifox.com',
path: endpoint.path,
method: 'GET',
headers: {
'Authorization': `Bearer ${config.VITE_APIFOX_TOKEN}`,
'Content-Type': 'application/json',
'X-Apifox-Version': '2024-06-14' // 尝试添加版本头
}
};
try {
const response = await httpsRequest(options);
console.log(`状态码: ${response.statusCode}`);
console.log(`Content-Type: ${response.headers['content-type']}`);
console.log(`Content-Length: ${response.headers['content-length']}`);
if (response.statusCode === 200 && response.raw) {
console.log(`✅ 成功获取数据 (${response.raw.length} 字符)`);
// 尝试解析为 JSON
try {
const json = JSON.parse(response.raw);
console.log(` - JSON 解析成功`);
console.log(` - 顶层键: ${Object.keys(json).join(', ')}`);
// 检查是否有接口数据
if (json.paths) {
const pathCount = Object.keys(json.paths).length;
console.log(` - OpenAPI paths 数量: ${pathCount}`);
if (pathCount > 0) {
console.log(` ✓ 找到接口数据!`);
// 保存到文件
const outputPath = path.join(__dirname, `../test-openapi-${Date.now()}.json`);
fs.writeFileSync(outputPath, JSON.stringify(json, null, 2), 'utf-8');
console.log(` - 已保存到: ${outputPath}`);
return; // 找到数据就退出
}
}
} catch (err) {
console.log(` - JSON 解析失败,可能是其他格式`);
}
} else if (response.data) {
console.log(`✅ 响应包含 data 字段`);
console.log(` - data 键: ${Object.keys(response.data).join(', ')}`);
} else {
console.log(`⚠️ 响应为空`);
}
} catch (err) {
console.log(`❌ 请求失败: ${err.message}`);
}
}
console.log('\n' + '='.repeat(60));
}
main();
/**
* @description API 接口定义
* @Template: 在此定义您的业务 API 接口地址
*/
// import { fn, fetch } from '@/api/fn';
// ==================== 业务 API 接口示例 ====================
// 请根据实际业务需求修改或添加接口
import { fn, fetch } from '@/api/fn';
const Api = {
GetDetail: '/srv/?a=order_detail',
GetList: '/srv/?a=order_list',
}
/**
* @description: 获取订单详情
* @param {Object} params 请求参数
* @param {integer} params.id 订单ID
* @returns {Promise<{
* code: number; // 状态码
* msg: string; // 消息
* data: {
* order: {
* id: integer; // 订单ID
* order_no: string; // 订单号
* total_amount: number; // 订单总金额
* status: string; // 订单状态
* items: array; // 订单商品列表
* };
* };
* }>}
*/
export const getDetailAPI = (params) => fn(fetch.get(Api.GetDetail, params));
/**
* @description: 获取订单列表
* @param {Object} params 请求参数
* @param {integer} params.page (可选) 页码
* @param {integer} params.pageSize (可选) 每页数量
* @returns {Promise<{
* code: number; // 状态码
* msg: string; // 消息
* data: {
* list: Array<{
* id: integer; // 订单ID
* order_no: string; // 订单号
* status: string; // 订单状态
* total_amount: number; // 订单金额
* }>;
* };
* }>}
*/
export const getListAPI = (params) => fn(fetch.get(Api.GetList, params));