hookehuyr

feat(api-generator): 支持区分GET和POST请求的参数处理

- 新增extractRequestParams函数从requestBody中提取POST参数
- 增强generateParamJSDoc函数根据请求方法生成对应参数注释
- 更新解析逻辑以正确提取POST请求的action值
- 自动过滤header参数和URL中已有的a/f参数
- 更新相关文档说明GET/POST参数处理差异
1 +# 🎉 GET/POST 请求参数处理 - 修复完成报告
2 +
3 +## ✅ 修复状态:全部完成
4 +
5 +所有问题已成功修复并通过验证!
6 +
7 +## 📋 修复内容总结
8 +
9 +### 问题 1: POST 请求的 action 为空 ✅ 已修复
10 +
11 +**修复前**:
12 +```javascript
13 +const Api = {
14 + EditUserInfo: '/srv/?a=', // ❌ action 值为空
15 +}
16 +```
17 +
18 +**修复后**:
19 +```javascript
20 +const Api = {
21 + EditUserInfo: '/srv/?a=user_edit', // ✅ action 值正确
22 +}
23 +```
24 +
25 +**验证结果**: ✅ 通过
26 +
27 +---
28 +
29 +### 问题 2: Header 参数显示在 JSDoc 中 ✅ 已修复
30 +
31 +**修复前**:
32 +```javascript
33 +/**
34 + * @param {string} params.user-id (可选) // ❌ Header 参数
35 + * @param {string} params.user-token (可选) // ❌ Header 参数
36 + */
37 +```
38 +
39 +**修复后**:
40 +```javascript
41 +/**
42 + * @param {Object} params 请求参数
43 + * @param {string} params.name (可选) 姓名 // ✅ 只显示 body 参数
44 + * @param {string} params.avatar (可选) 头像
45 + */
46 +```
47 +
48 +**验证结果**: ✅ Header 参数已正确过滤
49 +
50 +---
51 +
52 +### 问题 3: POST 请求的 body 参数未显示 ✅ 已修复
53 +
54 +**修复前**:
55 +```javascript
56 +/**
57 + * @param {Object} params 请求参数
58 + * // ❌ 缺少业务参数
59 + */
60 +```
61 +
62 +**修复后**:
63 +```javascript
64 +/**
65 + * @param {Object} params 请求参数
66 + * @param {string} params.name (可选) 姓名
67 + * @param {string} params.avatar (可选) 头像
68 + * @param {string} params.mobile (可选) 手机号
69 + * @param {string} params.sms_code (可选) 短信验证码
70 + * @param {string} params.idcard (可选) 身份证
71 + */
72 +```
73 +
74 +**验证结果**: ✅ Body 参数正确显示
75 +
76 +---
77 +
78 +### 问题 4: GET 请求参数处理 ✅ 已验证
79 +
80 +**生成效果**:
81 +```javascript
82 +/**
83 + * @description: 获取订单列表
84 + * @param {Object} params 请求参数
85 + * @param {integer} params.page (可选) 页码
86 + * @param {integer} params.pageSize (可选) 每页数量
87 + */
88 +export const getListAPI = (params) => fn(fetch.get(Api.GetList, params));
89 +```
90 +
91 +**验证结果**: ✅ GET 请求参数正确显示
92 +
93 +---
94 +
95 +## 🔧 核心改动
96 +
97 +### 1. 新增函数
98 +
99 +**extractRequestParams(requestBody)**
100 +-`requestBody` 中提取 POST 请求的参数
101 +- 支持 `application/x-www-form-urlencoded``application/json`
102 +- 提取参数名、类型、描述、是否必填
103 +
104 +### 2. 增强函数
105 +
106 +**generateParamJSDoc(parameters, bodyParams, method)**
107 +- 根据 HTTP 方法(GET/POST)选择参数来源
108 +- GET 请求:从 `parameters` 中的 `in: query` 提取
109 +- POST 请求:从 `requestBody` 中提取
110 +- 统一过滤 `a``f` 参数和 `in: header` 参数
111 +
112 +**parseOpenAPIDocument(openapiDoc, fileName)**
113 +- 区分 GET 和 POST 请求
114 +- GET 请求:从 query 参数中提取 action
115 +- POST 请求:从 requestBody 中提取 action
116 +- 保存参数信息供后续使用
117 +
118 +---
119 +
120 +## 📊 验证测试
121 +
122 +```bash
123 +=== 验证 GET/POST 请求参数处理修复 ===
124 +
125 +1. 检查 POST 请求的 action 是否正确提取
126 + EditUserInfo: '/srv/?a=user_edit', ✅
127 +
128 +2. 检查 Header 参数是否被过滤
129 + ✅ Header 参数已正确过滤
130 +
131 +3. 检查 Body 参数是否正确显示
132 + ✅ Body 参数正确显示
133 +
134 +4. 检查 GET 请求参数
135 + ✅ GET 请求参数正确显示
136 +
137 +=== 验证完成 ===
138 +```
139 +
140 +**测试结果**: ✅ 全部通过
141 +
142 +---
143 +
144 +## 📁 生成的文件示例
145 +
146 +### GET 请求 - 获取用户信息
147 +```javascript
148 +/**
149 + * @description: 查询我的信息
150 + * @param {Object} params 请求参数
151 + * @returns {Promise<{
152 + * code: number; // 状态码
153 + * msg: string; // 消息
154 + * data: {
155 + * user: {
156 + * id: integer; // 用户ID
157 + * name: string; // 姓名
158 + * mobile: string; // 手机号
159 + * };
160 + * checkin: {
161 + * total_days: integer; // 累计打卡天数
162 + * consecutive_days: integer; // 连续打卡天数
163 + * };
164 + * };
165 + * }>}
166 + */
167 +export const getUserInfoAPI = (params) => fn(fetch.get(Api.GetUserInfo, params));
168 +```
169 +
170 +### POST 请求 - 修改用户信息
171 +```javascript
172 +/**
173 + * @description: 修改我的信息
174 + * @param {Object} params 请求参数
175 + * @param {string} params.name (可选) 姓名
176 + * @param {string} params.avatar (可选) 头像
177 + * @param {string} params.mobile (可选) 手机号
178 + * @param {string} params.sms_code (可选) 短信验证码
179 + * @param {string} params.idcard (可选) 身份证
180 + * @returns {Promise<{
181 + * code: number; // 状态码
182 + * msg: string; // 消息
183 + * data: any;
184 + * }>}
185 + */
186 +export const editUserInfoAPI = (params) => fn(fetch.post(Api.EditUserInfo, params));
187 +```
188 +
189 +---
190 +
191 +## 📚 文档更新
192 +
193 +### 新增文档
194 +-`docs/GET_VS_POST_GUIDE.md` - GET vs POST 请求参数处理完整指南
195 +-`docs/GET_POST_FIX.md` - 修复说明和对比
196 +
197 +### 更新文档
198 +-`docs/OPENAPI_TO_API_GUIDE.md` - 更新参数说明和过滤规则
199 +
200 +---
201 +
202 +## 🎯 功能特性
203 +
204 +### GET 请求处理
205 +- ✅ 从 `parameters` 中提取 `in: query` 的参数
206 +- ✅ 过滤 `a``f` 参数和 header 参数
207 +- ✅ 生成 `fetch.get()` 调用
208 +- ✅ 显示 query 参数的详细注释
209 +
210 +### POST 请求处理
211 +- ✅ 从 `requestBody` 中提取 body 参数
212 +- ✅ 从 body 中提取 action 值
213 +- ✅ 过滤 `a``f` 参数和 header 参数
214 +- ✅ 生成 `fetch.post()` 调用
215 +- ✅ 显示 body 参数的详细注释
216 +
217 +### 参数过滤规则
218 +自动过滤以下参数:
219 +- `a` - action 参数(已在 URL 中)
220 +- `f` - 业务模块标识(已在 URL 中)
221 +- 所有 `in: header` 的参数(由框架处理)
222 +
223 +---
224 +
225 +## 🚀 使用方法
226 +
227 +### 1. 重新生成 API 文件
228 +```bash
229 +pnpm api:generate
230 +```
231 +
232 +### 2. 查看生成的代码
233 +```bash
234 +cat src/api/user.js
235 +cat src/api/order.js
236 +```
237 +
238 +### 3. 验证功能
239 +- ✅ POST 请求 action 正确
240 +- ✅ Header 参数被过滤
241 +- ✅ Body 参数正确显示
242 +- ✅ GET 请求参数正确显示
243 +
244 +---
245 +
246 +## 📖 相关文档
247 +
248 +- 📘 [GET vs POST 请求参数处理指南](./GET_VS_POST_GUIDE.md) - 详细使用说明
249 +- 📗 [修复说明](./GET_POST_FIX.md) - 修复内容和对比
250 +- 📙 [详细使用指南](./OPENAPI_TO_API_GUIDE.md) - 完整功能说明
251 +
252 +---
253 +
254 +## 🎉 总结
255 +
256 +所有问题已修复!
257 +
258 +**修复内容**:
259 +1. ✅ POST 请求的 action 正确提取
260 +2. ✅ Header 参数自动过滤
261 +3. ✅ Body 参数正确显示
262 +4. ✅ GET 请求参数正确处理
263 +
264 +**验证结果**: 全部通过 ✅
265 +
266 +现在生成的 API 文件:
267 +- 参数类型正确
268 +- 参数描述完整
269 +- Header 参数已过滤
270 +- GET/POST 请求处理正确
271 +- JSDoc 注释详细准确
272 +
273 +**可以放心使用了!** 🎊
1 +# 🎯 GET/POST 请求参数处理修复 - 更新说明
2 +
3 +## ❌ 修复前的问题
4 +
5 +### 问题 1: POST 请求的 action 为空
6 +```javascript
7 +const Api = {
8 + EditUserInfo: '/srv/?a=', // ❌ action 值为空
9 +}
10 +```
11 +
12 +**原因**: 生成器只从 `parameters` 中提取 action,但 POST 请求的 action 在 `requestBody` 中。
13 +
14 +### 问题 2: Header 参数显示在 JSDoc 中
15 +```javascript
16 +/**
17 + * @param {string} params.user-id (可选) // ❌ Header 参数不应该显示
18 + * @param {string} params.user-token (可选) // ❌ Header 参数不应该显示
19 + */
20 +```
21 +
22 +**原因**: 生成器没有区分 `query` 参数和 `header` 参数。
23 +
24 +### 问题 3: POST 请求的 body 参数没有显示
25 +```javascript
26 +/**
27 + * @param {Object} params 请求参数
28 + * // ❌ 缺少 name, avatar 等业务参数
29 + */
30 +```
31 +
32 +**原因**: 生成器没有处理 `requestBody` 中的参数。
33 +
34 +## ✅ 修复后的效果
35 +
36 +### 1. POST 请求的 action 正确提取
37 +```javascript
38 +const Api = {
39 + EditUserInfo: '/srv/?a=user_edit', // ✅ action 值正确
40 +}
41 +```
42 +
43 +### 2. Header 参数自动过滤
44 +```javascript
45 +/**
46 + * @param {Object} params 请求参数
47 + * @param {string} params.name (可选) 姓名 // ✅ 只显示 body 参数
48 + * @param {string} params.avatar (可选) 头像 // ✅ Header 参数被过滤
49 + */
50 +```
51 +
52 +### 3. GET 请求正确显示 query 参数
53 +```javascript
54 +/**
55 + * @param {integer} params.page (可选) 页码
56 + * @param {integer} params.pageSize (可选) 每页数量
57 + */
58 +```
59 +
60 +## 🔧 核心改动
61 +
62 +### 1. 新增函数:extractRequestParams()
63 +`requestBody` 中提取 POST 请求的参数。
64 +
65 +```javascript
66 +function extractRequestParams(requestBody) {
67 + // 支持两种 Content-Type:
68 + // - application/x-www-form-urlencoded
69 + // - application/json
70 +
71 + const content = requestBody.content['application/x-www-form-urlencoded'] ||
72 + requestBody.content['application/json'];
73 +
74 + if (!content || !content.schema || !content.schema.properties) {
75 + return [];
76 + }
77 +
78 + // 提取参数名称、类型、描述、是否必填
79 + const params = [];
80 + Object.entries(content.schema.properties).forEach(([key, value]) => {
81 + params.push({
82 + name: key,
83 + type: value.type || 'any',
84 + description: value.description || '',
85 + example: value.example || '',
86 + required: content.schema.required?.includes(key) || false,
87 + });
88 + });
89 +
90 + return params;
91 +}
92 +```
93 +
94 +### 2. 增强函数:generateParamJSDoc()
95 +根据请求类型(GET/POST)生成不同的参数注释。
96 +
97 +```javascript
98 +function generateParamJSDoc(parameters, bodyParams, method) {
99 + // POST 请求:从 bodyParams 中提取参数
100 + if (method === 'POST' && bodyParams && bodyParams.length > 0) {
101 + const filteredParams = bodyParams.filter(p => p.name !== 'a' && p.name !== 'f');
102 + // 生成 JSDoc...
103 + }
104 + // GET 请求:从 parameters 中提取 query 参数
105 + else if (method === 'GET' && parameters && parameters.length > 0) {
106 + const queryParams = parameters.filter(p => p.in === 'query' && p.name !== 'a' && p.name !== 'f');
107 + // 生成 JSDoc...
108 + }
109 +}
110 +```
111 +
112 +### 3. 增强函数:parseOpenAPIDocument()
113 +区分 GET 和 POST 请求,提取不同来源的 action 和参数。
114 +
115 +```javascript
116 +function parseOpenAPIDocument(openapiDoc, fileName) {
117 + const apiInfo = openapiDoc.paths[path][method];
118 + const requestBody = apiInfo.requestBody;
119 + const bodyParams = extractRequestParams(requestBody);
120 +
121 + // POST 请求:从 requestBody 中提取 action
122 + if (requestBody && bodyParams.length > 0) {
123 + const actionParam = bodyParams.find(p => p.name === 'a');
124 + if (actionParam) {
125 + actionValue = actionParam.example || '';
126 + }
127 + }
128 +
129 + // GET 请求:从 query 参数中提取 action
130 + if (!actionValue && parameters.length > 0) {
131 + parameters.forEach((param) => {
132 + if (param.in === 'query' && param.name === 'a') {
133 + actionValue = param.example || '';
134 + }
135 + });
136 + }
137 +
138 + return {
139 + summary, method, action,
140 + parameters, // GET 请求的 query 参数
141 + bodyParams, // POST 请求的 body 参数
142 + responseSchema,
143 + };
144 +}
145 +```
146 +
147 +## 📊 生成效果对比
148 +
149 +### GET 请求示例
150 +
151 +**OpenAPI 定义**:
152 +```yaml
153 +get:
154 + parameters:
155 + - name: a
156 + in: query
157 + example: order_list
158 + - name: f
159 + in: query
160 + example: behalo
161 + - name: page
162 + in: query
163 + type: integer
164 + description: 页码
165 + - name: pageSize
166 + in: query
167 + type: integer
168 + description: 每页数量
169 +```
170 +
171 +**生成代码**:
172 +```javascript
173 +const GetList: '/srv/?a=order_list'
174 +
175 +/**
176 + * @description: 获取订单列表
177 + * @param {Object} params 请求参数
178 + * @param {integer} params.page (可选) 页码
179 + * @param {integer} params.pageSize (可选) 每页数量
180 + */
181 +export const getListAPI = (params) => fn(fetch.get(Api.GetList, params));
182 +```
183 +
184 +### POST 请求示例
185 +
186 +**OpenAPI 定义**:
187 +```yaml
188 +post:
189 + parameters:
190 + - name: user-id
191 + in: header
192 + schema:
193 + type: string
194 + - name: user-token
195 + in: header
196 + schema:
197 + type: string
198 + requestBody:
199 + content:
200 + application/x-www-form-urlencoded:
201 + schema:
202 + properties:
203 + a:
204 + example: user_edit
205 + f:
206 + example: behalo
207 + name:
208 + type: string
209 + description: 姓名
210 + avatar:
211 + type: string
212 + description: 头像
213 +```
214 +
215 +**生成代码**:
216 +```javascript
217 +const EditUserInfo: '/srv/?a=user_edit'
218 +
219 +/**
220 + * @description: 修改我的信息
221 + * @param {Object} params 请求参数
222 + * @param {string} params.name (可选) 姓名
223 + * @param {string} params.avatar (可选) 头像
224 + */
225 +export const editUserInfoAPI = (params) => fn(fetch.post(Api.EditUserInfo, params));
226 +```
227 +
228 +## 🎯 参数过滤规则
229 +
230 +### 自动过滤的参数
231 +
232 +| 参数名 | 位置 | 原因 |
233 +|--------|------|------|
234 +| `a` | query / body | Action 参数,已在 URL 中 |
235 +| `f` | query / body | 业务模块标识,已在 URL 中 |
236 +| `user-id` | header | Header 参数,由框架处理 |
237 +| `user-token` | header | Header 参数,由框架处理 |
238 +| 其他 `in: header` | header | Header 参数,由框架处理 |
239 +
240 +## 📝 更新文档
241 +
242 +### 新增文档
243 +-`docs/GET_VS_POST_GUIDE.md` - GET vs POST 请求参数处理完整指南
244 +
245 +### 更新文档
246 +-`docs/OPENAPI_TO_API_GUIDE.md` - 更新参数说明和过滤规则
247 +
248 +## 🚀 使用建议
249 +
250 +### 定义 GET 请求
251 +```yaml
252 +get:
253 + parameters:
254 + - name: a
255 + in: query
256 + example: your_action
257 +
258 + - name: your_param
259 + in: query # ✅ 使用 query
260 + description: 参数描述
261 + schema:
262 + type: string
263 +```
264 +
265 +### 定义 POST 请求
266 +```yaml
267 +post:
268 + parameters:
269 + - name: auth-header
270 + in: header # ✅ 认证信息放 header
271 +
272 + requestBody:
273 + content:
274 + application/json:
275 + schema:
276 + properties:
277 + a:
278 + example: your_action
279 + field1:
280 + type: string
281 + description: 字段描述
282 +```
283 +
284 +## ✅ 测试验证
285 +
286 +运行以下命令验证修复:
287 +
288 +```bash
289 +# 重新生成 API 文件
290 +pnpm api:generate
291 +
292 +# 查看生成的代码
293 +cat src/api/user.js
294 +
295 +# 验证:
296 +# 1. POST 请求的 action 正确提取
297 +# 2. Header 参数被过滤
298 +# 3. Body 参数正确显示
299 +# 4. GET 请求的 query 参数正确显示
300 +```
301 +
302 +## 📚 相关文档
303 +
304 +- 📘 [GET vs POST 请求参数处理指南](./GET_VS_POST_GUIDE.md) - 详细说明
305 +- 📗 [详细使用指南](./OPENAPI_TO_API_GUIDE.md) - 完整功能说明
306 +
307 +## 🎉 总结
308 +
309 +现在生成器能够:
310 +
311 +**正确区分 GET 和 POST 请求**
312 +**自动提取 POST 请求的 action**
313 +**过滤 Header 参数**
314 +**显示正确的业务参数**
315 +**生成简洁易用的 JSDoc 注释**
316 +
317 +所有问题已修复!🎊
1 +# GET vs POST 请求参数处理指南
2 +
3 +## 📋 概述
4 +
5 +生成器能够正确区分和处理 GET 和 POST 请求的不同参数类型。
6 +
7 +## 🔍 参数类型说明
8 +
9 +### 1. GET 请求参数
10 +
11 +**参数位置**: URL 查询字符串(Query Parameters)
12 +
13 +**OpenAPI 定义**:
14 +```yaml
15 +paths:
16 + /srv/:
17 + get:
18 + parameters:
19 + - name: page
20 + in: query # ✅ GET 请求使用 query
21 + description: 页码
22 + schema:
23 + type: integer
24 + - name: pageSize
25 + in: query # ✅ GET 请求使用 query
26 + description: 每页数量
27 + schema:
28 + type: integer
29 + - name: a
30 + in: query # ✅ action 也在 query 中
31 + example: user_info
32 + schema:
33 + type: string
34 +```
35 +
36 +**生成的代码**:
37 +```javascript
38 +/**
39 + * @param {Object} params 请求参数
40 + * @param {integer} params.page (可选) 页码
41 + * @param {integer} params.pageSize (可选) 每页数量
42 + */
43 +export const getUserInfoAPI = (params) => fn(fetch.get(Api.GetUserInfo, params));
44 +```
45 +
46 +### 2. POST 请求参数
47 +
48 +**参数位置**: 请求体(Request Body)
49 +
50 +**OpenAPI 定义**:
51 +```yaml
52 +paths:
53 + /srv/:
54 + post:
55 + parameters:
56 + - name: user-id
57 + in: header # ⚠️ Header 参数(不显示在 JSDoc 中)
58 + schema:
59 + type: string
60 + - name: user-token
61 + in: header # ⚠️ Header 参数(不显示在 JSDoc 中)
62 + schema:
63 + type: string
64 + requestBody:
65 + content:
66 + application/x-www-form-urlencoded:
67 + schema:
68 + type: object
69 + properties:
70 + a:
71 + example: user_edit # ✅ action 在 requestBody 中
72 + type: string
73 + name:
74 + description: 姓名
75 + type: string
76 + avatar:
77 + description: 头像
78 + type: string
79 +```
80 +
81 +**生成的代码**:
82 +```javascript
83 +/**
84 + * @param {Object} params 请求参数
85 + * @param {string} params.name (可选) 姓名
86 + * @param {string} params.avatar (可选) 头像
87 + */
88 +export const editUserInfoAPI = (params) => fn(fetch.post(Api.EditUserInfo, params));
89 +```
90 +
91 +## 🎯 关键区别
92 +
93 +| 特性 | GET 请求 | POST 请求 |
94 +|------|---------|----------|
95 +| 参数位置 | URL 查询字符串 | 请求体 |
96 +| 参数定义 | `parameters` + `in: query` | `requestBody` |
97 +| Action 位置 | `parameters` 中 | `requestBody` 中 |
98 +| 生成方法 | `fetch.get()` | `fetch.post()` |
99 +| Header 参数 | 显示在 JSDoc 中 | ❌ 不显示(自动过滤) |
100 +
101 +## 📝 参数过滤规则
102 +
103 +### 自动过滤的参数
104 +
105 +以下参数不会出现在生成的 JSDoc 中:
106 +
107 +1. **`a` 参数** - action 参数,已在 URL 中
108 +2. **`f` 参数** - 业务模块标识,已在 URL 中
109 +3. **Header 参数** - `in: header` 的参数
110 +
111 +**原因**: 这些参数由框架或请求拦截器自动处理,开发者无需手动传递。
112 +
113 +### 示例
114 +
115 +**OpenAPI 定义**:
116 +```yaml
117 +parameters:
118 + - name: a
119 + in: query
120 + example: user_info # ❌ 不会显示在 JSDoc 中
121 +
122 + - name: f
123 + in: query
124 + example: behalo # ❌ 不会显示在 JSDoc 中
125 +
126 + - name: user-id
127 + in: header # ❌ 不会显示在 JSDoc 中
128 +
129 + - name: page
130 + in: query
131 + example: 1 # ✅ 会显示在 JSDoc 中
132 +```
133 +
134 +**生成的 JSDoc**:
135 +```javascript
136 +/**
137 + * @param {integer} params.page (可选) 页码 # ✅ 只显示业务参数
138 + */
139 +```
140 +
141 +## 🔧 使用示例
142 +
143 +### GET 请求示例
144 +
145 +```javascript
146 +// 调用 GET 接口
147 +const result = await getUserInfoAPI({
148 + page: 1,
149 + pageSize: 10
150 +});
151 +
152 +// 等价于
153 +// GET /srv/?a=user_info&page=1&pageSize=10
154 +```
155 +
156 +### POST 请求示例
157 +
158 +```javascript
159 +// 调用 POST 接口
160 +const result = await editUserInfoAPI({
161 + name: '张三',
162 + avatar: 'https://...',
163 + mobile: '13800138000'
164 +});
165 +
166 +// 等价于
167 +// POST /srv/?a=user_edit
168 +// Content-Type: application/x-www-form-urlencoded
169 +// Body: name=张三&avatar=https://...&mobile=13800138000
170 +```
171 +
172 +## 📊 完整对比
173 +
174 +### GET 请求 - 获取订单列表
175 +
176 +**OpenAPI**:
177 +```yaml
178 +get:
179 + parameters:
180 + - name: a
181 + in: query
182 + example: order_list
183 + - name: page
184 + in: query
185 + type: integer
186 + description: 页码
187 + - name: pageSize
188 + in: query
189 + type: integer
190 + description: 每页数量
191 +```
192 +
193 +**生成代码**:
194 +```javascript
195 +const GetList: '/srv/?a=order_list'
196 +
197 +/**
198 + * @description: 获取订单列表
199 + * @param {Object} params 请求参数
200 + * @param {integer} params.page (可选) 页码
201 + * @param {integer} params.pageSize (可选) 每页数量
202 + */
203 +export const getListAPI = (params) => fn(fetch.get(Api.GetList, params));
204 +```
205 +
206 +### POST 请求 - 修改用户信息
207 +
208 +**OpenAPI**:
209 +```yaml
210 +post:
211 + parameters:
212 + - name: user-id
213 + in: header
214 + - name: user-token
215 + in: header
216 + requestBody:
217 + content:
218 + application/x-www-form-urlencoded:
219 + schema:
220 + properties:
221 + a:
222 + example: user_edit
223 + name:
224 + type: string
225 + description: 姓名
226 +```
227 +
228 +**生成代码**:
229 +```javascript
230 +const EditUserInfo: '/srv/?a=user_edit'
231 +
232 +/**
233 + * @description: 修改我的信息
234 + * @param {Object} params 请求参数
235 + * @param {string} params.name (可选) 姓名
236 + */
237 +export const editUserInfoAPI = (params) => fn(fetch.post(Api.EditUserInfo, params));
238 +```
239 +
240 +## ✅ 最佳实践
241 +
242 +### 1. GET 请求定义
243 +
244 +```yaml
245 +get:
246 + parameters:
247 + - name: a
248 + in: query
249 + example: your_action # ✅ action 在 query 中
250 +
251 + - name: your_param
252 + in: query # ✅ 业务参数也用 query
253 + description: 参数描述
254 + schema:
255 + type: string
256 +```
257 +
258 +### 2. POST 请求定义
259 +
260 +```yaml
261 +post:
262 + parameters:
263 + - name: auth-header
264 + in: header # ✅ 认证信息放 header
265 +
266 + requestBody:
267 + content:
268 + application/x-www-form-urlencoded: # 或 application/json
269 + schema:
270 + properties:
271 + a:
272 + example: your_action # ✅ action 在 body 中
273 + field1:
274 + type: string
275 + description: 字段描述
276 +```
277 +
278 +### 3. 避免混淆
279 +
280 +**不要**这样定义:
281 +```yaml
282 +post:
283 + parameters:
284 + - name: data_field
285 + in: query # ❌ POST 不要用 query 传数据
286 +```
287 +
288 +**应该**这样定义:
289 +```yaml
290 +post:
291 + requestBody:
292 + content:
293 + application/json:
294 + schema:
295 + properties:
296 + data_field: # ✅ POST 数据放 requestBody
297 + type: string
298 +```
299 +
300 +## 🎯 总结
301 +
302 +- **GET 请求**: 参数在 `parameters` + `in: query`
303 +- **POST 请求**: 参数在 `requestBody`
304 +- **Header 参数**: 自动过滤,不显示在 JSDoc
305 +- **Action 参数**: 自动提取并添加到 URL 中
306 +
307 +这样可以确保生成的代码简洁、易用,符合实际开发习惯!
...@@ -111,10 +111,11 @@ paths: ...@@ -111,10 +111,11 @@ paths:
111 | 字段 | 说明 | 示例 | 111 | 字段 | 说明 | 示例 |
112 |------|------|------| 112 |------|------|------|
113 | `summary` | 接口描述,用于 JSDoc 注释 | "查询我的信息" | 113 | `summary` | 接口描述,用于 JSDoc 注释 | "查询我的信息" |
114 -| `parameters[].name='a'` | action 参数,用于构建 URL | `user_info` | 114 +| `parameters[].name='a'` | GET 请求的 action 参数 | `user_info` |
115 -| `parameters[].description` | 参数描述,用于生成 JSDoc @param | "页码" | 115 +| `requestBody.properties.a` | POST 请求的 action 参数 | `user_edit` |
116 -| `parameters[].schema.type` | 参数类型 | integer, string, boolean | 116 +| `parameters[].in='query'` | GET 请求的查询参数 | `page`, `pageSize` |
117 -| `parameters[].required` | 是否必填 | true/false | 117 +| `requestBody` | POST 请求的 body 参数 | `name`, `avatar` |
118 +| `parameters[].in='header'` | Header 参数(自动过滤) | 不显示在 JSDoc |
118 | `get` / `post` | HTTP 方法 | 决定使用 `fetch.get``fetch.post` | 119 | `get` / `post` | HTTP 方法 | 决定使用 `fetch.get``fetch.post` |
119 | `responses['200'].schema` | 响应数据结构 | 用于生成 JSDoc @returns | 120 | `responses['200'].schema` | 响应数据结构 | 用于生成 JSDoc @returns |
120 | `description` | 字段描述 | 用于生成详细注释 | 121 | `description` | 字段描述 | 用于生成详细注释 |
...@@ -122,8 +123,16 @@ paths: ...@@ -122,8 +123,16 @@ paths:
122 123
123 ### 📌 JSDoc 注释生成规则 124 ### 📌 JSDoc 注释生成规则
124 125
125 -#### 参数注释(@param) 126 +#### GET 请求参数注释(@param)
126 -- 过滤掉 `a``f` 参数(已在 URL 中) 127 +-`parameters` 中提取 `in: query` 的参数
128 +- 过滤掉 `a``f` 参数和 `in: header` 的参数
129 +- 提取参数名、类型、描述
130 +- 标记必填/可选状态
131 +
132 +#### POST 请求参数注释(@param)
133 +-`requestBody` 中提取参数
134 +- 过滤掉 `a``f` 参数
135 +- 过滤掉 `in: header` 的参数
127 - 提取参数名、类型、描述 136 - 提取参数名、类型、描述
128 - 标记必填/可选状态 137 - 标记必填/可选状态
129 138
......
1 +# 修改我的信息
2 +
3 +## OpenAPI Specification
4 +
5 +```yaml
6 +openapi: 3.0.1
7 +info:
8 + title: ''
9 + version: 1.0.0
10 +paths:
11 + /srv/:
12 + post:
13 + summary: 修改我的信息
14 + deprecated: false
15 + description: ''
16 + tags:
17 + - 个人信息
18 + parameters:
19 + - name: user-id
20 + in: header
21 + description: ''
22 + required: false
23 + example: '1033954'
24 + schema:
25 + type: string
26 + - name: user-token
27 + in: header
28 + description: ''
29 + required: false
30 + example: WN2BD9XQ7CRSVQ92FMB62V9C9OHHRBL38L2NS4GJ#1033954#50
31 + schema:
32 + type: string
33 + requestBody:
34 + content:
35 + application/x-www-form-urlencoded:
36 + schema:
37 + type: object
38 + properties:
39 + f:
40 + example: behalo
41 + type: string
42 + a:
43 + example: user_edit
44 + type: string
45 + name:
46 + description: 姓名
47 + example: 汪小雨XXXX
48 + type: string
49 + avatar:
50 + description: 头像
51 + example: ''
52 + type: string
53 + mobile:
54 + description: 手机号
55 + example: ''
56 + type: string
57 + sms_code:
58 + description: 短信验证码
59 + example: '8888'
60 + type: string
61 + idcard:
62 + description: 身份证
63 + example: '12345678'
64 + type: string
65 + examples: {}
66 + responses:
67 + '200':
68 + description: ''
69 + content:
70 + application/json:
71 + schema:
72 + type: object
73 + properties:
74 + code:
75 + type: integer
76 + title: 状态
77 + description: 0=失败,1=成功
78 + msg:
79 + type: string
80 + title: 错误信息
81 + x-apifox-orders:
82 + - code
83 + - msg
84 + required:
85 + - code
86 + - msg
87 + headers: {}
88 + x-apifox-name: 成功
89 + x-apifox-ordering: 0
90 + security: []
91 + x-apifox-folder: 个人信息
92 + x-apifox-status: tested
93 + x-run-in-apifox: https://app.apifox.com/web/project/6084040/apis/api-275318897-run
94 +components:
95 + schemas: {}
96 + responses: {}
97 + securitySchemes: {}
98 +servers:
99 + - url: https://oa-dev.onwall.cn
100 + description: 测试环境
101 +security: []
102 +
103 +```
...@@ -103,31 +103,72 @@ function parseProperties(properties, indent = 0) { ...@@ -103,31 +103,72 @@ function parseProperties(properties, indent = 0) {
103 } 103 }
104 104
105 /** 105 /**
106 - * 生成 JSDoc 参数注释 106 + * 从 requestBody 中提取参数
107 - * @param {Array} parameters - 参数数组 107 + * @param {object} requestBody - requestBody 对象
108 - * @returns {string} - JSDoc 参数注释 108 + * @returns {Array} - 参数数组
109 */ 109 */
110 -function generateParamJSDoc(parameters) { 110 +function extractRequestParams(requestBody) {
111 - if (!parameters || parameters.length === 0) { 111 + if (!requestBody || !requestBody.content) {
112 - return ' * @param {Object} params 请求参数'; 112 + return [];
113 } 113 }
114 114
115 - const lines = [' * @param {Object} params 请求参数']; 115 + // 获取内容类型(可能是 application/x-www-form-urlencoded 或 application/json)
116 - 116 + const content = requestBody.content['application/x-www-form-urlencoded'] ||
117 - // 过滤掉 a 和 f 参数,因为它们已经在 URL 中了 117 + requestBody.content['application/json'];
118 - const filteredParams = parameters.filter(p => p.name !== 'a' && p.name !== 'f');
119 118
120 - if (filteredParams.length === 0) { 119 + if (!content || !content.schema || !content.schema.properties) {
121 - return lines.join('\n'); 120 + return [];
122 } 121 }
123 122
124 - filteredParams.forEach((param) => { 123 + const params = [];
125 - const type = param.schema?.type || 'any'; 124 + Object.entries(content.schema.properties).forEach(([key, value]) => {
126 - const desc = param.description || ''; 125 + params.push({
127 - const required = param.required ? '' : ' (可选)'; 126 + name: key,
128 - lines.push(` * @param {${type}} params.${param.name}${required} ${desc}`); 127 + type: value.type || 'any',
128 + description: value.description || '',
129 + example: value.example || '',
130 + required: content.schema.required?.includes(key) || false,
131 + });
129 }); 132 });
130 133
134 + return params;
135 +}
136 +
137 +/**
138 + * 生成 JSDoc 参数注释
139 + * @param {Array} parameters - parameters 数组(GET 请求)
140 + * @param {Array} bodyParams - requestBody 参数数组(POST 请求)
141 + * @param {string} method - HTTP 方法
142 + * @returns {string} - JSDoc 参数注释
143 + */
144 +function generateParamJSDoc(parameters, bodyParams, method) {
145 + const lines = [' * @param {Object} params 请求参数'];
146 +
147 + // POST 请求使用 body 参数
148 + if (method === 'POST' && bodyParams && bodyParams.length > 0) {
149 + // 过滤掉 a 和 f 参数
150 + const filteredParams = bodyParams.filter(p => p.name !== 'a' && p.name !== 'f');
151 +
152 + filteredParams.forEach((param) => {
153 + const type = param.type || 'any';
154 + const desc = param.description || '';
155 + const required = param.required ? '' : ' (可选)';
156 + lines.push(` * @param {${type}} params.${param.name}${required} ${desc}`);
157 + });
158 + }
159 + // GET 请求使用 query 参数
160 + else if (method === 'GET' && parameters && parameters.length > 0) {
161 + // 只保留 query 参数,过滤 header 参数
162 + const queryParams = parameters.filter(p => p.in === 'query' && p.name !== 'a' && p.name !== 'f');
163 +
164 + queryParams.forEach((param) => {
165 + const type = param.schema?.type || 'any';
166 + const desc = param.description || '';
167 + const required = param.required ? '' : ' (可选)';
168 + lines.push(` * @param {${type}} params.${param.name}${required} ${desc}`);
169 + });
170 + }
171 +
131 return lines.join('\n'); 172 return lines.join('\n');
132 } 173 }
133 174
...@@ -202,16 +243,31 @@ function parseOpenAPIDocument(openapiDoc, fileName) { ...@@ -202,16 +243,31 @@ function parseOpenAPIDocument(openapiDoc, fileName) {
202 const queryParams = {}; 243 const queryParams = {};
203 let actionValue = ''; 244 let actionValue = '';
204 245
205 - parameters.forEach((param) => { 246 + // 提取 body 参数(用于 POST 请求)
206 - if (param.in === 'query') { 247 + const requestBody = apiInfo.requestBody;
207 - queryParams[param.name] = param.example || param.schema?.default || ''; 248 + const bodyParams = extractRequestParams(requestBody);
208 249
209 - // 提取 action 参数(通常是 'a' 参数) 250 + // 对于 POST 请求,从 requestBody 中提取 action
210 - if (param.name === 'a') { 251 + if (requestBody && bodyParams.length > 0) {
211 - actionValue = param.example || ''; 252 + const actionParam = bodyParams.find(p => p.name === 'a');
212 - } 253 + if (actionParam) {
254 + actionValue = actionParam.example || '';
213 } 255 }
214 - }); 256 + }
257 +
258 + // 对于 GET 请求,从 query 参数中提取 action
259 + if (!actionValue && parameters.length > 0) {
260 + parameters.forEach((param) => {
261 + if (param.in === 'query') {
262 + queryParams[param.name] = param.example || param.schema?.default || '';
263 +
264 + // 提取 action 参数(通常是 'a' 参数)
265 + if (param.name === 'a') {
266 + actionValue = param.example || '';
267 + }
268 + }
269 + });
270 + }
215 271
216 // 提取响应结构 272 // 提取响应结构
217 const responseSchema = apiInfo.responses?.['200']?.content?.['application/json']?.schema; 273 const responseSchema = apiInfo.responses?.['200']?.content?.['application/json']?.schema;
...@@ -222,7 +278,8 @@ function parseOpenAPIDocument(openapiDoc, fileName) { ...@@ -222,7 +278,8 @@ function parseOpenAPIDocument(openapiDoc, fileName) {
222 method: method.toUpperCase(), 278 method: method.toUpperCase(),
223 action: actionValue, 279 action: actionValue,
224 queryParams, 280 queryParams,
225 - parameters, // 保存完整的参数信息用于生成 JSDoc 281 + parameters, // 保存完整的参数信息用于生成 JSDoc(GET 请求)
282 + bodyParams, // 保存 requestBody 参数用于生成 JSDoc(POST 请求)
226 responseSchema, // 保存响应结构用于生成 JSDoc 283 responseSchema, // 保存响应结构用于生成 JSDoc
227 fileName, 284 fileName,
228 }; 285 };
...@@ -255,7 +312,7 @@ function generateApiFileContent(moduleName, apis) { ...@@ -255,7 +312,7 @@ function generateApiFileContent(moduleName, apis) {
255 ); 312 );
256 313
257 // 生成详细的 JSDoc 注释 314 // 生成详细的 JSDoc 注释
258 - const paramJSDoc = generateParamJSDoc(api.parameters); 315 + const paramJSDoc = generateParamJSDoc(api.parameters, api.bodyParams, api.method);
259 const returnJSDoc = generateReturnJSDoc(api.responseSchema); 316 const returnJSDoc = generateReturnJSDoc(api.responseSchema);
260 317
261 // 添加函数定义 318 // 添加函数定义
......
1 import { fn, fetch } from '@/api/fn'; 1 import { fn, fetch } from '@/api/fn';
2 2
3 const Api = { 3 const Api = {
4 + EditUserInfo: '/srv/?a=user_edit',
4 GetUserInfo: '/srv/?a=user_info', 5 GetUserInfo: '/srv/?a=user_info',
5 } 6 }
6 7
7 /** 8 /**
9 + * @description: 修改我的信息
10 + * @param {Object} params 请求参数
11 + * @param {string} params.name (可选) 姓名
12 + * @param {string} params.avatar (可选) 头像
13 + * @param {string} params.mobile (可选) 手机号
14 + * @param {string} params.sms_code (可选) 短信验证码
15 + * @param {string} params.idcard (可选) 身份证
16 + * @returns {Promise<{
17 + * code: number; // 状态码
18 + * msg: string; // 消息
19 + * data: any;
20 + * }>}
21 + */
22 +export const editUserInfoAPI = (params) => fn(fetch.post(Api.EditUserInfo, params));
23 +
24 +/**
8 * @description: 查询我的信息 25 * @description: 查询我的信息
9 * @param {Object} params 请求参数 26 * @param {Object} params 请求参数
10 * @returns {Promise<{ 27 * @returns {Promise<{
......