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