VSTS仪表板小部件开发:遍历Epic下Feature及工作项实现状态报告
解决方案:遍历Epic下的Feature及子WorkItem(无需预先知道ID)
嘿,我来帮你搞定这个需求!你完全不需要依赖getWorkItem()/getWorkItems()必须传ID的限制——咱们可以用Azure DevOps(原VSTS)原生的**Work Item Query Language (WIQL)**来批量查询工作项,完美适配你不知道具体ID的场景。
步骤1:查询特定Epic下的所有Feature
首先要做的是用WIQL定位目标Epic下的所有Feature,核心是利用工作项的层级链接关系(Epic和Feature是父子层级)。
WIQL查询语句示例
SELECT [System.Id], [System.Title], [System.State] FROM WorkItems WHERE [System.WorkItemType] = 'Feature' AND [System.LinkTypes.Hierarchy-Reverse] = '<你的Epic ID>' ORDER BY [System.Id]
简单解释:System.LinkTypes.Hierarchy-Reverse表示“父项是指定ID”,这样就能精准筛选出所有属于该Epic的Feature。
仪表板小部件中执行查询(JavaScript示例)
用VSS SDK的WorkItemTrackingHttpClient来实现查询逻辑:
import * as WorkItemTracking from "azure-devops-extension-api/WorkItemTracking"; async function getFeaturesUnderEpic(epicId) { const workItemClient = await WorkItemTracking.getClient(); const wiqlQuery = { query: `SELECT [System.Id], [System.Title], [System.State] FROM WorkItems WHERE [System.WorkItemType] = 'Feature' AND [System.LinkTypes.Hierarchy-Reverse] = '${epicId}'` }; const queryResult = await workItemClient.queryByWiql(wiqlQuery); // 如果有结果,批量获取完整的工作项数据 if (queryResult.workItems?.length) { const ids = queryResult.workItems.map(item => item.id); return workItemClient.getWorkItems(ids); } return []; }
步骤2:查询每个Feature下的所有子WorkItem
拿到Feature列表后,我们再针对每个Feature,用WIQL查询其下的所有子工作项(比如Task、Bug等),同样利用层级链接关系。
WIQL查询语句示例(针对单个Feature)
SELECT [System.Id], [System.Title], [System.State], [System.WorkItemType] FROM WorkItems WHERE [System.LinkTypes.Hierarchy-Reverse] = '<Feature ID>' ORDER BY [System.WorkItemType], [System.Id]
批量获取子项的代码示例
async function getChildWorkItemsForFeatures(features) { const workItemClient = await WorkItemTracking.getClient(); const featureChildMap = new Map(); for (const feature of features) { const featureId = feature.id; const wiqlQuery = { query: `SELECT [System.Id], [System.Title], [System.State], [System.WorkItemType] FROM WorkItems WHERE [System.LinkTypes.Hierarchy-Reverse] = '${featureId}'` }; const queryResult = await workItemClient.queryByWiql(wiqlQuery); if (queryResult.workItems?.length) { const ids = queryResult.workItems.map(item => item.id); const childItems = await workItemClient.getWorkItems(ids); featureChildMap.set(featureId, childItems); } else { featureChildMap.set(featureId, []); } } return featureChildMap; }
步骤3:判断工作项是否完成
工作项的完成状态取决于你项目的流程模板(比如Scrum、Agile、CMMI),通常通过System.State字段判断:
- Scrum模板:完成状态为
Done - Agile模板:完成状态为
Done或Closed - CMMI模板:完成状态为
Closed
你可以根据自己的项目模板调整判断逻辑:
function isWorkItemCompleted(item) { const completedStates = ['Done', 'Closed']; // 按需修改 const itemState = item.fields['System.State']; return completedStates.includes(itemState); }
整合逻辑生成状态报告
最后把所有步骤串起来,生成每个Feature的状态汇总:
async function generateEpicStatusReport(epicId) { // 1. 获取Epic下的所有Feature const features = await getFeaturesUnderEpic(epicId); // 2. 获取每个Feature的子工作项 const featureChildMap = await getChildWorkItemsForFeatures(features); // 3. 生成报告数据 const report = features.map(feature => { const childItems = featureChildMap.get(feature.id) || []; const completedChildren = childItems.filter(isWorkItemCompleted); return { featureId: feature.id, featureTitle: feature.fields['System.Title'], featureState: feature.fields['System.State'], totalChildren: childItems.length, completedChildren: completedChildren.length, completionRate: childItems.length > 0 ? (completedChildren.length / childItems.length * 100).toFixed(2) + '%' : 'N/A' }; }); console.log('Epic状态报告:', report); return report; }
额外优化建议
- 批量查询提升效率:如果Feature数量较多,可以合并WIQL查询,一次性获取所有Feature的子项,减少API调用次数
- 处理分页:如果查询结果超过100条(默认分页上限),需要处理
queryResult.continuationToken来获取完整数据 - 权限检查:确保小部件的权限足够访问目标项目的工作项数据
内容的提问来源于stack exchange,提问作者user8463863
相关产品推荐
相关产品推荐

