@zzp123/mcp-zentao 1.11.1 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +47 -0
- package/dist/api/zentaoApi.d.ts +37 -4
- package/dist/api/zentaoApi.js +210 -53
- package/dist/index.js +17 -12
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,53 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.13.0] - 2025-11-07
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **产品和需求列表字段过滤功能** 📦
|
|
12
|
+
- 为 `getProducts` 添加 `fields` 参数支持
|
|
13
|
+
- 为 `getProductStories` 添加 `fields` 参数支持
|
|
14
|
+
- 支持三种字段级别:
|
|
15
|
+
- `basic`: 基本信息(产品:id, name, code, status;需求:id, title, assignedTo, openedBy)
|
|
16
|
+
- `default`: 默认信息(产品:包含 PO/QD/RD 等;需求:包含 status/stage/pri 等,**默认使用**)
|
|
17
|
+
- `full`: 完整信息(所有字段)
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
- **优化列表接口默认返回数据**
|
|
21
|
+
- 产品列表默认使用 `default` 字段级别,返回核心管理信息
|
|
22
|
+
- 需求列表默认使用 `basic` 字段级别,只返回最基本的4个字段
|
|
23
|
+
- 显著减少数据传输量,提升列表查询响应速度
|
|
24
|
+
|
|
25
|
+
### Improved
|
|
26
|
+
- **性能优化**
|
|
27
|
+
- 列表接口数据量大幅减少,特别适合快速浏览和搜索场景
|
|
28
|
+
- 减少不必要的字段传输,降低网络开销
|
|
29
|
+
- 需要详细信息时可按需设置 `fields='full'`
|
|
30
|
+
|
|
31
|
+
## [1.12.0] - 2025-11-07
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
- **字段级别过滤功能** 📦
|
|
35
|
+
- 为 `getMyBugs` 和 `getProductBugs` 添加 `fields` 参数
|
|
36
|
+
- 支持三种字段级别:
|
|
37
|
+
- `basic`: 基本信息(8个核心字段:id, title, status, pri, severity, assignedTo, openedBy, openedDate)
|
|
38
|
+
- `default`: 默认信息(18个常用字段,适合列表展示,**默认使用**)
|
|
39
|
+
- `full`: 完整信息(所有字段)
|
|
40
|
+
- 显著减少数据传输量,提升响应速度
|
|
41
|
+
|
|
42
|
+
### Changed
|
|
43
|
+
- **优化默认返回数据**
|
|
44
|
+
- 默认使用 `default` 字段级别,只返回列表展示所需的字段
|
|
45
|
+
- 保持默认每页 20 条记录不变
|
|
46
|
+
- 需要完整信息时可设置 `fields='full'`
|
|
47
|
+
|
|
48
|
+
### Improved
|
|
49
|
+
- **性能优化**
|
|
50
|
+
- 使用 default 模式减少约 60% 的数据传输量
|
|
51
|
+
- 使用 basic 模式减少约 80% 的数据传输量
|
|
52
|
+
- 更快的响应速度和更低的网络开销
|
|
53
|
+
- 更适合移动端和弱网络环境使用
|
|
54
|
+
|
|
8
55
|
## [1.11.1] - 2025-11-07
|
|
9
56
|
|
|
10
57
|
### Fixed
|
package/dist/api/zentaoApi.d.ts
CHANGED
|
@@ -8,7 +8,30 @@ export declare class ZentaoAPI {
|
|
|
8
8
|
private request;
|
|
9
9
|
getMyTasks(status?: TaskStatus): Promise<Task[]>;
|
|
10
10
|
getTaskDetail(taskId: number): Promise<Task>;
|
|
11
|
-
|
|
11
|
+
/**
|
|
12
|
+
* 过滤产品字段
|
|
13
|
+
* @param product 原始产品对象
|
|
14
|
+
* @param fields 字段级别
|
|
15
|
+
*/
|
|
16
|
+
private filterProductFields;
|
|
17
|
+
/**
|
|
18
|
+
* 过滤需求字段
|
|
19
|
+
* @param story 原始需求对象
|
|
20
|
+
* @param fields 字段级别
|
|
21
|
+
*/
|
|
22
|
+
private filterStoryFields;
|
|
23
|
+
/**
|
|
24
|
+
* 获取产品列表
|
|
25
|
+
* @param fields 返回字段级别('basic'基本/'default'默认/'full'完整,默认'default')
|
|
26
|
+
* @returns Promise<产品列表>
|
|
27
|
+
*/
|
|
28
|
+
getProducts(fields?: 'basic' | 'default' | 'full'): Promise<Product[]>;
|
|
29
|
+
/**
|
|
30
|
+
* 过滤 Bug 字段
|
|
31
|
+
* @param bug 原始 Bug 对象
|
|
32
|
+
* @param fields 字段级别
|
|
33
|
+
*/
|
|
34
|
+
private filterBugFields;
|
|
12
35
|
/**
|
|
13
36
|
* 获取 Bug 列表
|
|
14
37
|
*
|
|
@@ -18,9 +41,10 @@ export declare class ZentaoAPI {
|
|
|
18
41
|
* @param limit 每页数量(默认20,最大100)
|
|
19
42
|
* @param branch 分支筛选('all'所有分支/'0'主干/分支ID,默认'all')
|
|
20
43
|
* @param order 排序字段(如:'id_desc'、'pri_desc'等,默认'id_desc')
|
|
44
|
+
* @param fields 返回字段级别('basic'基本/'default'默认/'full'完整,默认'default')
|
|
21
45
|
* @returns Promise<Bug列表及分页信息>
|
|
22
46
|
*/
|
|
23
|
-
getMyBugs(status?: BugStatus, productId?: number, page?: number, limit?: number, branch?: string, order?: string): Promise<{
|
|
47
|
+
getMyBugs(status?: BugStatus, productId?: number, page?: number, limit?: number, branch?: string, order?: string, fields?: 'basic' | 'default' | 'full'): Promise<{
|
|
24
48
|
page: number;
|
|
25
49
|
total: number;
|
|
26
50
|
limit: number;
|
|
@@ -35,9 +59,10 @@ export declare class ZentaoAPI {
|
|
|
35
59
|
* @param status Bug状态筛选(支持多种状态,详见BugStatus类型)
|
|
36
60
|
* @param branch 分支筛选('all'所有分支/'0'主干/分支ID,默认'all')
|
|
37
61
|
* @param order 排序字段(如:'id_desc'、'pri_desc'等,默认'id_desc')
|
|
62
|
+
* @param fields 返回字段级别('basic'基本/'default'默认/'full'完整,默认'default')
|
|
38
63
|
* @returns Promise<Bug列表及分页信息>
|
|
39
64
|
*/
|
|
40
|
-
getProductBugs(productId: number, page?: number, limit?: number, status?: BugStatus, branch?: string, order?: string): Promise<{
|
|
65
|
+
getProductBugs(productId: number, page?: number, limit?: number, status?: BugStatus, branch?: string, order?: string, fields?: 'basic' | 'default' | 'full'): Promise<{
|
|
41
66
|
page: number;
|
|
42
67
|
total: number;
|
|
43
68
|
limit: number;
|
|
@@ -80,7 +105,15 @@ export declare class ZentaoAPI {
|
|
|
80
105
|
deleteTask(taskId: number): Promise<{
|
|
81
106
|
message: string;
|
|
82
107
|
}>;
|
|
83
|
-
|
|
108
|
+
/**
|
|
109
|
+
* 获取产品需求列表
|
|
110
|
+
* @param productId 产品ID
|
|
111
|
+
* @param page 页码(从1开始,默认1)
|
|
112
|
+
* @param limit 每页数量(默认20,最大100)
|
|
113
|
+
* @param fields 返回字段级别('basic'基本/'default'默认/'full'完整,默认'basic')
|
|
114
|
+
* @returns Promise<需求列表及分页信息>
|
|
115
|
+
*/
|
|
116
|
+
getProductStories(productId: number, page?: number, limit?: number, fields?: 'basic' | 'default' | 'full'): Promise<{
|
|
84
117
|
page: number;
|
|
85
118
|
total: number;
|
|
86
119
|
limit: number;
|
package/dist/api/zentaoApi.js
CHANGED
|
@@ -91,26 +91,146 @@ export class ZentaoAPI {
|
|
|
91
91
|
throw error;
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
|
-
|
|
94
|
+
/**
|
|
95
|
+
* 过滤产品字段
|
|
96
|
+
* @param product 原始产品对象
|
|
97
|
+
* @param fields 字段级别
|
|
98
|
+
*/
|
|
99
|
+
filterProductFields(product, fields) {
|
|
100
|
+
if (fields === 'full') {
|
|
101
|
+
return product;
|
|
102
|
+
}
|
|
103
|
+
if (fields === 'basic') {
|
|
104
|
+
// 基本信息:只返回核心字段
|
|
105
|
+
return {
|
|
106
|
+
id: product.id,
|
|
107
|
+
name: product.name,
|
|
108
|
+
code: product.code,
|
|
109
|
+
status: product.status
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
// default: 默认字段(id, 名称, 状态, 负责人)
|
|
113
|
+
return {
|
|
114
|
+
id: product.id,
|
|
115
|
+
name: product.name,
|
|
116
|
+
code: product.code,
|
|
117
|
+
status: product.status,
|
|
118
|
+
type: product.type,
|
|
119
|
+
PO: product.PO,
|
|
120
|
+
QD: product.QD,
|
|
121
|
+
RD: product.RD,
|
|
122
|
+
createdBy: product.createdBy,
|
|
123
|
+
createdDate: product.createdDate
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* 过滤需求字段
|
|
128
|
+
* @param story 原始需求对象
|
|
129
|
+
* @param fields 字段级别
|
|
130
|
+
*/
|
|
131
|
+
filterStoryFields(story, fields) {
|
|
132
|
+
if (fields === 'full') {
|
|
133
|
+
return story;
|
|
134
|
+
}
|
|
135
|
+
if (fields === 'basic') {
|
|
136
|
+
// 基本信息:只返回核心字段
|
|
137
|
+
return {
|
|
138
|
+
id: story.id,
|
|
139
|
+
title: story.title,
|
|
140
|
+
assignedTo: story.assignedTo,
|
|
141
|
+
openedBy: story.openedBy
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
// default: 默认字段(id, 标题, 状态, 指派人, 创建人)
|
|
145
|
+
return {
|
|
146
|
+
id: story.id,
|
|
147
|
+
title: story.title,
|
|
148
|
+
status: story.status,
|
|
149
|
+
stage: story.stage,
|
|
150
|
+
pri: story.pri,
|
|
151
|
+
assignedTo: story.assignedTo,
|
|
152
|
+
openedBy: story.openedBy,
|
|
153
|
+
openedDate: story.openedDate,
|
|
154
|
+
estimate: story.estimate,
|
|
155
|
+
product: story.product,
|
|
156
|
+
plan: story.plan
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* 获取产品列表
|
|
161
|
+
* @param fields 返回字段级别('basic'基本/'default'默认/'full'完整,默认'default')
|
|
162
|
+
* @returns Promise<产品列表>
|
|
163
|
+
*/
|
|
164
|
+
async getProducts(fields) {
|
|
95
165
|
try {
|
|
96
|
-
|
|
166
|
+
const finalFields = fields || 'default';
|
|
167
|
+
console.log(`正在获取产品列表 (fields=${finalFields})...`);
|
|
97
168
|
const response = await this.request('GET', '/products');
|
|
98
169
|
console.log('产品列表响应:', response);
|
|
170
|
+
let products = [];
|
|
99
171
|
if (Array.isArray(response)) {
|
|
100
|
-
|
|
172
|
+
products = response;
|
|
101
173
|
}
|
|
102
|
-
else if (response && typeof response === 'object') {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
174
|
+
else if (response && typeof response === 'object' && Array.isArray(response.products)) {
|
|
175
|
+
products = response.products;
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
throw new Error(`获取产品列表失败: 响应格式不正确 ${JSON.stringify(response)}`);
|
|
106
179
|
}
|
|
107
|
-
|
|
180
|
+
// 应用字段过滤
|
|
181
|
+
const filteredProducts = products.map(product => this.filterProductFields(product, finalFields));
|
|
182
|
+
return filteredProducts;
|
|
108
183
|
}
|
|
109
184
|
catch (error) {
|
|
110
185
|
console.error('获取产品列表失败:', error);
|
|
111
186
|
throw error;
|
|
112
187
|
}
|
|
113
188
|
}
|
|
189
|
+
/**
|
|
190
|
+
* 过滤 Bug 字段
|
|
191
|
+
* @param bug 原始 Bug 对象
|
|
192
|
+
* @param fields 字段级别
|
|
193
|
+
*/
|
|
194
|
+
filterBugFields(bug, fields) {
|
|
195
|
+
if (fields === 'full') {
|
|
196
|
+
return bug;
|
|
197
|
+
}
|
|
198
|
+
if (fields === 'basic') {
|
|
199
|
+
// 基本信息:只返回最核心的字段
|
|
200
|
+
return {
|
|
201
|
+
id: bug.id,
|
|
202
|
+
title: bug.title,
|
|
203
|
+
status: bug.status,
|
|
204
|
+
pri: bug.pri,
|
|
205
|
+
severity: bug.severity,
|
|
206
|
+
assignedTo: bug.assignedTo,
|
|
207
|
+
openedBy: bug.openedBy,
|
|
208
|
+
openedDate: bug.openedDate
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
// default: 默认字段(适合列表展示)
|
|
212
|
+
return {
|
|
213
|
+
id: bug.id,
|
|
214
|
+
title: bug.title,
|
|
215
|
+
status: bug.status,
|
|
216
|
+
statusName: bug.statusName,
|
|
217
|
+
pri: bug.pri,
|
|
218
|
+
severity: bug.severity,
|
|
219
|
+
type: bug.type,
|
|
220
|
+
assignedTo: bug.assignedTo,
|
|
221
|
+
assignedDate: bug.assignedDate,
|
|
222
|
+
openedBy: bug.openedBy,
|
|
223
|
+
openedDate: bug.openedDate,
|
|
224
|
+
deadline: bug.deadline,
|
|
225
|
+
resolvedBy: bug.resolvedBy,
|
|
226
|
+
resolvedDate: bug.resolvedDate,
|
|
227
|
+
confirmed: bug.confirmed,
|
|
228
|
+
module: bug.module,
|
|
229
|
+
moduleTitle: bug.moduleTitle,
|
|
230
|
+
product: bug.product,
|
|
231
|
+
productName: bug.productName
|
|
232
|
+
};
|
|
233
|
+
}
|
|
114
234
|
/**
|
|
115
235
|
* 获取 Bug 列表
|
|
116
236
|
*
|
|
@@ -120,9 +240,10 @@ export class ZentaoAPI {
|
|
|
120
240
|
* @param limit 每页数量(默认20,最大100)
|
|
121
241
|
* @param branch 分支筛选('all'所有分支/'0'主干/分支ID,默认'all')
|
|
122
242
|
* @param order 排序字段(如:'id_desc'、'pri_desc'等,默认'id_desc')
|
|
243
|
+
* @param fields 返回字段级别('basic'基本/'default'默认/'full'完整,默认'default')
|
|
123
244
|
* @returns Promise<Bug列表及分页信息>
|
|
124
245
|
*/
|
|
125
|
-
async getMyBugs(status, productId, page, limit, branch, order) {
|
|
246
|
+
async getMyBugs(status, productId, page, limit, branch, order, fields) {
|
|
126
247
|
if (!productId) {
|
|
127
248
|
// 如果没有提供产品ID,获取第二个可用的产品(索引为1)
|
|
128
249
|
const products = await this.getProducts();
|
|
@@ -138,6 +259,7 @@ export class ZentaoAPI {
|
|
|
138
259
|
const finalPage = page || 1;
|
|
139
260
|
const finalBranch = branch || 'all';
|
|
140
261
|
const finalOrder = order || 'id_desc';
|
|
262
|
+
const finalFields = fields || 'default';
|
|
141
263
|
// 构建查询参数
|
|
142
264
|
const queryParams = new URLSearchParams();
|
|
143
265
|
queryParams.append('branch', finalBranch);
|
|
@@ -149,29 +271,37 @@ export class ZentaoAPI {
|
|
|
149
271
|
queryParams.append('status', status);
|
|
150
272
|
}
|
|
151
273
|
try {
|
|
152
|
-
console.log(`正在获取产品 ${productId} 的Bug列表,参数: status=${status || 'all'}, branch=${finalBranch}, page=${finalPage}, limit=${finalLimit}, order=${finalOrder}`);
|
|
274
|
+
console.log(`正在获取产品 ${productId} 的Bug列表,参数: status=${status || 'all'}, branch=${finalBranch}, page=${finalPage}, limit=${finalLimit}, order=${finalOrder}, fields=${finalFields}`);
|
|
153
275
|
const response = await this.request('GET', `/products/${productId}/bugs?${queryParams.toString()}`);
|
|
154
276
|
console.log(`Bug列表响应: 获取到 ${response.bugs?.length || 0} 条数据`);
|
|
277
|
+
let bugs = [];
|
|
278
|
+
if (Array.isArray(response)) {
|
|
279
|
+
bugs = response;
|
|
280
|
+
}
|
|
281
|
+
else if (response && typeof response === 'object' && Array.isArray(response.bugs)) {
|
|
282
|
+
bugs = response.bugs;
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
throw new Error(`获取Bug列表失败: 响应格式不正确 ${JSON.stringify(response)}`);
|
|
286
|
+
}
|
|
287
|
+
// 应用字段过滤
|
|
288
|
+
const filteredBugs = bugs.map(bug => this.filterBugFields(bug, finalFields));
|
|
155
289
|
if (Array.isArray(response)) {
|
|
156
|
-
// 如果返回的是数组,转换为标准格式
|
|
157
290
|
return {
|
|
158
291
|
page: finalPage,
|
|
159
|
-
total:
|
|
292
|
+
total: filteredBugs.length,
|
|
160
293
|
limit: finalLimit,
|
|
161
|
-
bugs:
|
|
294
|
+
bugs: filteredBugs
|
|
162
295
|
};
|
|
163
296
|
}
|
|
164
|
-
else
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
};
|
|
172
|
-
}
|
|
297
|
+
else {
|
|
298
|
+
return {
|
|
299
|
+
page: response.page || finalPage,
|
|
300
|
+
total: response.total || filteredBugs.length,
|
|
301
|
+
limit: response.limit || finalLimit,
|
|
302
|
+
bugs: filteredBugs
|
|
303
|
+
};
|
|
173
304
|
}
|
|
174
|
-
throw new Error(`获取Bug列表失败: 响应格式不正确 ${JSON.stringify(response)}`);
|
|
175
305
|
}
|
|
176
306
|
catch (error) {
|
|
177
307
|
console.error('获取Bug列表失败:', error);
|
|
@@ -187,16 +317,18 @@ export class ZentaoAPI {
|
|
|
187
317
|
* @param status Bug状态筛选(支持多种状态,详见BugStatus类型)
|
|
188
318
|
* @param branch 分支筛选('all'所有分支/'0'主干/分支ID,默认'all')
|
|
189
319
|
* @param order 排序字段(如:'id_desc'、'pri_desc'等,默认'id_desc')
|
|
320
|
+
* @param fields 返回字段级别('basic'基本/'default'默认/'full'完整,默认'default')
|
|
190
321
|
* @returns Promise<Bug列表及分页信息>
|
|
191
322
|
*/
|
|
192
|
-
async getProductBugs(productId, page, limit, status, branch, order) {
|
|
323
|
+
async getProductBugs(productId, page, limit, status, branch, order, fields) {
|
|
193
324
|
try {
|
|
194
325
|
// 默认每页20条,最多100条
|
|
195
326
|
const finalLimit = limit ? Math.min(limit, 100) : 20;
|
|
196
327
|
const finalPage = page || 1;
|
|
197
328
|
const finalBranch = branch || 'all';
|
|
198
329
|
const finalOrder = order || 'id_desc';
|
|
199
|
-
|
|
330
|
+
const finalFields = fields || 'default';
|
|
331
|
+
console.log(`正在获取产品 ${productId} 的Bug列表 (status=${status || 'all'}, branch=${finalBranch}, page=${finalPage}, limit=${finalLimit}, order=${finalOrder}, fields=${finalFields})...`);
|
|
200
332
|
// 构建查询参数
|
|
201
333
|
const queryParams = new URLSearchParams();
|
|
202
334
|
queryParams.append('branch', finalBranch);
|
|
@@ -209,26 +341,34 @@ export class ZentaoAPI {
|
|
|
209
341
|
}
|
|
210
342
|
const response = await this.request('GET', `/products/${productId}/bugs?${queryParams.toString()}`);
|
|
211
343
|
console.log(`产品Bug列表响应: 获取到 ${response.bugs?.length || 0} 条数据`);
|
|
344
|
+
let bugs = [];
|
|
345
|
+
if (Array.isArray(response)) {
|
|
346
|
+
bugs = response;
|
|
347
|
+
}
|
|
348
|
+
else if (response && typeof response === 'object' && Array.isArray(response.bugs)) {
|
|
349
|
+
bugs = response.bugs;
|
|
350
|
+
}
|
|
351
|
+
else {
|
|
352
|
+
throw new Error(`获取产品Bug列表失败: 响应格式不正确 ${JSON.stringify(response)}`);
|
|
353
|
+
}
|
|
354
|
+
// 应用字段过滤
|
|
355
|
+
const filteredBugs = bugs.map(bug => this.filterBugFields(bug, finalFields));
|
|
212
356
|
if (Array.isArray(response)) {
|
|
213
|
-
// 如果返回的是数组,转换为标准格式
|
|
214
357
|
return {
|
|
215
358
|
page: finalPage,
|
|
216
|
-
total:
|
|
359
|
+
total: filteredBugs.length,
|
|
217
360
|
limit: finalLimit,
|
|
218
|
-
bugs:
|
|
361
|
+
bugs: filteredBugs
|
|
219
362
|
};
|
|
220
363
|
}
|
|
221
|
-
else
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
};
|
|
229
|
-
}
|
|
364
|
+
else {
|
|
365
|
+
return {
|
|
366
|
+
page: response.page || finalPage,
|
|
367
|
+
total: response.total || filteredBugs.length,
|
|
368
|
+
limit: response.limit || finalLimit,
|
|
369
|
+
bugs: filteredBugs
|
|
370
|
+
};
|
|
230
371
|
}
|
|
231
|
-
throw new Error(`获取产品Bug列表失败: 响应格式不正确 ${JSON.stringify(response)}`);
|
|
232
372
|
}
|
|
233
373
|
catch (error) {
|
|
234
374
|
console.error('获取产品Bug列表失败:', error);
|
|
@@ -681,38 +821,55 @@ export class ZentaoAPI {
|
|
|
681
821
|
throw error;
|
|
682
822
|
}
|
|
683
823
|
}
|
|
684
|
-
|
|
824
|
+
/**
|
|
825
|
+
* 获取产品需求列表
|
|
826
|
+
* @param productId 产品ID
|
|
827
|
+
* @param page 页码(从1开始,默认1)
|
|
828
|
+
* @param limit 每页数量(默认20,最大100)
|
|
829
|
+
* @param fields 返回字段级别('basic'基本/'default'默认/'full'完整,默认'basic')
|
|
830
|
+
* @returns Promise<需求列表及分页信息>
|
|
831
|
+
*/
|
|
832
|
+
async getProductStories(productId, page, limit, fields) {
|
|
685
833
|
try {
|
|
686
834
|
// 默认每页20条,最多100条
|
|
687
835
|
const finalLimit = limit ? Math.min(limit, 100) : 20;
|
|
688
836
|
const finalPage = page || 1;
|
|
689
|
-
|
|
837
|
+
const finalFields = fields || 'basic'; // 默认只返回基本字段
|
|
838
|
+
console.log(`正在获取产品 ${productId} 的需求列表 (page=${finalPage}, limit=${finalLimit}, fields=${finalFields})...`);
|
|
690
839
|
// 构建查询参数
|
|
691
840
|
const queryParams = new URLSearchParams();
|
|
692
841
|
queryParams.append('page', finalPage.toString());
|
|
693
842
|
queryParams.append('limit', finalLimit.toString());
|
|
694
843
|
const response = await this.request('GET', `/products/${productId}/stories?${queryParams.toString()}`);
|
|
695
844
|
console.log(`产品需求列表响应: 获取到 ${response.stories?.length || 0} 条数据`);
|
|
845
|
+
let stories = [];
|
|
846
|
+
if (Array.isArray(response)) {
|
|
847
|
+
stories = response;
|
|
848
|
+
}
|
|
849
|
+
else if (response && typeof response === 'object' && Array.isArray(response.stories)) {
|
|
850
|
+
stories = response.stories;
|
|
851
|
+
}
|
|
852
|
+
else {
|
|
853
|
+
throw new Error(`获取产品需求列表失败: 响应格式不正确 ${JSON.stringify(response)}`);
|
|
854
|
+
}
|
|
855
|
+
// 应用字段过滤
|
|
856
|
+
const filteredStories = stories.map(story => this.filterStoryFields(story, finalFields));
|
|
696
857
|
if (Array.isArray(response)) {
|
|
697
|
-
// 如果返回的是数组,转换为标准格式
|
|
698
858
|
return {
|
|
699
859
|
page: finalPage,
|
|
700
|
-
total:
|
|
860
|
+
total: filteredStories.length,
|
|
701
861
|
limit: finalLimit,
|
|
702
|
-
stories:
|
|
862
|
+
stories: filteredStories
|
|
703
863
|
};
|
|
704
864
|
}
|
|
705
|
-
else
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
};
|
|
713
|
-
}
|
|
865
|
+
else {
|
|
866
|
+
return {
|
|
867
|
+
page: response.page || finalPage,
|
|
868
|
+
total: response.total || filteredStories.length,
|
|
869
|
+
limit: response.limit || finalLimit,
|
|
870
|
+
stories: filteredStories
|
|
871
|
+
};
|
|
714
872
|
}
|
|
715
|
-
throw new Error(`获取产品需求列表失败: 响应格式不正确 ${JSON.stringify(response)}`);
|
|
716
873
|
}
|
|
717
874
|
catch (error) {
|
|
718
875
|
console.error('获取产品需求列表失败:', error);
|
package/dist/index.js
CHANGED
|
@@ -78,10 +78,12 @@ server.tool("getTaskDetail", {
|
|
|
78
78
|
};
|
|
79
79
|
});
|
|
80
80
|
// Add getProducts tool
|
|
81
|
-
server.tool("getProducts",
|
|
81
|
+
server.tool("getProducts", "获取产品列表 - 只返回核心字段(id, 名称, 负责人)", {
|
|
82
|
+
fields: z.enum(['basic', 'default', 'full']).optional().describe("返回字段级别:'basic'(id/名称/状态)、'default'(+负责人/创建人,默认)、'full'(完整字段)")
|
|
83
|
+
}, async ({ fields }) => {
|
|
82
84
|
if (!zentaoApi)
|
|
83
85
|
throw new Error("Please initialize Zentao API first");
|
|
84
|
-
const products = await zentaoApi.getProducts();
|
|
86
|
+
const products = await zentaoApi.getProducts(fields);
|
|
85
87
|
return {
|
|
86
88
|
content: [{ type: "text", text: JSON.stringify(products, null, 2) }]
|
|
87
89
|
};
|
|
@@ -114,11 +116,12 @@ server.tool("getMyBugs", "获取Bug列表 - 支持多种状态筛选(指派给
|
|
|
114
116
|
page: z.number().optional().describe("页码,从1开始,默认为1"),
|
|
115
117
|
limit: z.number().optional().describe("每页数量,默认20,最大100"),
|
|
116
118
|
branch: z.string().optional().describe("分支筛选:'all'(所有分支,默认)、'0'(主干分支)、分支ID"),
|
|
117
|
-
order: z.string().optional().describe("排序方式,如 id_desc(ID降序), pri_desc(优先级降序), openedDate_desc(创建时间降序)等,默认id_desc")
|
|
118
|
-
|
|
119
|
+
order: z.string().optional().describe("排序方式,如 id_desc(ID降序), pri_desc(优先级降序), openedDate_desc(创建时间降序)等,默认id_desc"),
|
|
120
|
+
fields: z.enum(['basic', 'default', 'full']).optional().describe("返回字段级别:'basic'(基本字段)、'default'(默认字段,推荐)、'full'(完整字段),默认'default'")
|
|
121
|
+
}, async ({ status, productId, page, limit, branch, order, fields }) => {
|
|
119
122
|
if (!zentaoApi)
|
|
120
123
|
throw new Error("Please initialize Zentao API first");
|
|
121
|
-
const result = await zentaoApi.getMyBugs(status, productId, page, limit, branch, order);
|
|
124
|
+
const result = await zentaoApi.getMyBugs(status, productId, page, limit, branch, order, fields);
|
|
122
125
|
// 返回分页信息和数据
|
|
123
126
|
const summary = {
|
|
124
127
|
summary: `当前第 ${result.page} 页,共 ${result.total} 个Bug,本页显示 ${result.bugs.length} 个`,
|
|
@@ -162,11 +165,12 @@ server.tool("getProductBugs", "获取指定产品的Bug列表 - 支持多种状
|
|
|
162
165
|
'bysearch' // 自定义搜索
|
|
163
166
|
]).optional().describe("Bug状态筛选,默认返回所有状态"),
|
|
164
167
|
branch: z.string().optional().describe("分支筛选:'all'(所有分支,默认)、'0'(主干分支)、分支ID"),
|
|
165
|
-
order: z.string().optional().describe("排序方式,如 id_desc(ID降序), pri_desc(优先级降序), openedDate_desc(创建时间降序)等,默认id_desc")
|
|
166
|
-
|
|
168
|
+
order: z.string().optional().describe("排序方式,如 id_desc(ID降序), pri_desc(优先级降序), openedDate_desc(创建时间降序)等,默认id_desc"),
|
|
169
|
+
fields: z.enum(['basic', 'default', 'full']).optional().describe("返回字段级别:'basic'(基本字段)、'default'(默认字段,推荐)、'full'(完整字段),默认'default'")
|
|
170
|
+
}, async ({ productId, page, limit, status, branch, order, fields }) => {
|
|
167
171
|
if (!zentaoApi)
|
|
168
172
|
throw new Error("Please initialize Zentao API first");
|
|
169
|
-
const result = await zentaoApi.getProductBugs(productId, page, limit, status, branch, order);
|
|
173
|
+
const result = await zentaoApi.getProductBugs(productId, page, limit, status, branch, order, fields);
|
|
170
174
|
// 返回分页信息和数据
|
|
171
175
|
const summary = {
|
|
172
176
|
summary: `当前第 ${result.page} 页,共 ${result.total} 个Bug,本页显示 ${result.bugs.length} 个`,
|
|
@@ -667,14 +671,15 @@ server.tool("deleteTask", {
|
|
|
667
671
|
};
|
|
668
672
|
});
|
|
669
673
|
// Add getProductStories tool
|
|
670
|
-
server.tool("getProductStories", {
|
|
674
|
+
server.tool("getProductStories", "获取产品需求列表 - 默认只返回核心字段(id, 标题, 指派人, 创建人)", {
|
|
671
675
|
productId: z.number(),
|
|
672
676
|
page: z.number().optional().describe("页码,从1开始,默认为1"),
|
|
673
|
-
limit: z.number().optional().describe("每页数量,默认20,最大100")
|
|
674
|
-
|
|
677
|
+
limit: z.number().optional().describe("每页数量,默认20,最大100"),
|
|
678
|
+
fields: z.enum(['basic', 'default', 'full']).optional().describe("字段级别:\n- basic: 基本信息(id, title, assignedTo, openedBy)\n- default: 常用信息(包含basic + status, stage, pri等)\n- full: 完整信息(所有字段)")
|
|
679
|
+
}, async ({ productId, page, limit, fields }) => {
|
|
675
680
|
if (!zentaoApi)
|
|
676
681
|
throw new Error("Please initialize Zentao API first");
|
|
677
|
-
const result = await zentaoApi.getProductStories(productId, page, limit);
|
|
682
|
+
const result = await zentaoApi.getProductStories(productId, page, limit, fields);
|
|
678
683
|
// 返回分页信息和数据
|
|
679
684
|
const summary = {
|
|
680
685
|
summary: `当前第 ${result.page} 页,共 ${result.total} 条需求,本页显示 ${result.stories.length} 条`,
|