此代码将显示总故事数,已接受的故事数和已完成的故事数以及故事点,项目连续完成的故事点
但是如何在后续行中为所有子项目显示相同的值。我的问题是"我如何根据项目对值进行分组,以及如何访问不同的项目以获取数据
Ext.define('CustomApp', {
extend: 'Rally.app.TimeboxScopedApp',
componentCls: 'app',
scopeType: 'iteration',
comboboxConfig: {
fieldLabel: 'Select iteration:',
labelWidth: 100,
width: 300
},
onScopeChange: function() {
Ext.create('Rally.data.wsapi.Store',{
model: 'User Story',
fetch: ['FormattedID','Name','PlanEstimate','ScheduleState'],
limit: Infinity,
autoLoad: true,
filters: [this.getContext().getTimeboxScope().getQueryFilter()],
sorters: [
{
property: 'DragAndDropRank',
direction: 'DESC'
}
],
listeners: {
load: this._onStoriesLoaded,
scope: this
}
});
},
_onStoriesLoaded: function(store,records){
var myData = [];
//in case we want to track them separately:
var estimatedStories = [];
var unestimatedStories = [];
var acceptedStories = [];
var completedStories = [];
var totalPlanEstimate = 0;
var acceptedPlanEstimate = 0;
var completedPlanEstimate = 0;
//var unestimatedStories = [];
console.log(records.length);
var estimated = false;
_.each(records, function(record){
if (record.get('PlanEstimate')) {
totalPlanEstimate = record.get('PlanEstimate') + totalPlanEstimate;
console.log("totalPlanEstimate",totalPlanEstimate);
estimatedStories.push(record);
}
else{
unestimatedStories.push(record);
}
},this);
_.each(records, function(record){
if (record.get('ScheduleState') === 'Accepted') {
acceptedPlanEstimate = record.get('PlanEstimate') + acceptedPlanEstimate;
console.log("acceptedPlanEstimate",acceptedPlanEstimate);
console.log("record.getScheduleState",record.get('ScheduleState'));
acceptedStories.push(record);
}
else if(record.get('ScheduleState') === 'Completed') {
completedPlanEstimate = record.get('PlanEstimate') + completedPlanEstimate;
console.log("completedPlanEstimate",completedPlanEstimate);
console.log("record.getScheduleState",record.get('ScheduleState'));
completedStories.push(record);
}
},this);
completedPercentage = (completedStories.length)/(records.length)*100;
completedStoryPointsPercentage = (completedPlanEstimate/totalPlanEstimate*100);
var list = {
tous : records.length,
es : estimatedStories.length,
//unes : unestimatedStories.length,
acus : acceptedStories.length,
cous : completedPercentage,
tosp : totalPlanEstimate,
acsp : acceptedPlanEstimate,
cosp : completedPlanEstimate,
cospp : completedStoryPointsPercentage
};
myData.push(list);
console.log("mydata",myData);
//console.log(estimatedStories.length, unestimatedStories.length);
this._makeGrid(myData);
},
_makeGrid:function(myData){
if(this.down('#storyGrid')){
this.down('#storyGrid').destroy();
}
var gridStore = Ext.create('Rally.data.custom.Store', {
data: myData,
limit:Infinity
//groupField: 'projectname'
});
this.add({
xtype: 'rallygrid',
itemId: 'storyGrid',
store: gridStore,
showRowActionsColumn: false,
width: 800,
columnCfgs:[
{
text: 'TOTAL USER STORY', dataIndex: 'tous'
},
{
text: 'ESTIMATED', dataIndex: 'es'
},
//{
//text: 'UNESTIMATED', dataIndex: 'unes'
//},
{
text: 'ACCEPTED', dataIndex: 'acus'
},
{
text: 'COMPLETED', dataIndex: 'cous'
},
{
text: 'TOTAL STORY POINTS', dataIndex: 'tosp'
},
{
text: 'ACCEPTED STORY POINTS', dataIndex: 'acsp'
},
{
text: 'COMPLETED STORY POINTS', dataIndex: 'cosp'
},
{
text: 'COMPLETED STORY PERCENTAGE', dataIndex: 'cospp'
}
]
});
}
});

答案 0 :(得分:1)
我修改了你的代码现在你可以看到带有用户故事的网格,现在你可以指定你想要显示的字段,如团队/项目,总故事数,未估计的故事数,接受的故事数
Ext.define('CustomApp', {
extend: 'Rally.app.App',
componentCls: 'app',
launch: function() {
console.log("My First App Mypie");
//this._loadData();
this._loadIterations();
},
_loadIterations: function() {
var iterComboBox = Ext.create('Ext.Container', {
items: [{
xtype: 'rallyiterationcombobox',
storeConfig: {
listeners: {
load: function(store, records){
console.log(records);
}
}
},
listeners: {
select: function(combobox) {
var selectedIterRef = combobox.getRecord().get('_ref');
this._loadData(selectedIterRef);
},
scope: this
}
}],
renderTo: Ext.getBody().dom
}, this);
this.add(iterComboBox);
},
//Get Data from Rally
_loadData: function(selectedIterRef) {
//var selectedIterRef = this.down('#priorityComboBox').getValue().get('_ref');
console.log("selected iter", selectedIterRef);
var myStore = Ext.create('Rally.data.wsapi.Store',{
model: 'HierarchicalRequirement',
autoLoad: true,
filters: [
{
property: 'Iteration',
operator: '=',
value: selectedIterRef
}
],
listeners: {
load: function(myStore,mydata, success) {
var storeLength = mydata.length;
this._loadGrid(myStore);
},
scope: this
},
fetch: ['FormattedID']
});
},
//Create and show a grid for given stories
_loadGrid: function(myStoreStore) {
var myGrid = Ext.getCmp('myGrid');
if (myGrid) {
myGrid.destroy();
};
var mygrid = Ext.create('Rally.ui.grid.Grid',{
store: myStoreStore,
id: 'myGrid',
columnCfgs: [
'FormattedID','length'
]
});
this.add(mygrid);
console.log("What is this", this);
console.log("defectCount",length);
}
});
我的网格应用代码
prepareChart: function(iteration_data) {
//console.log("iteration_data", iteration_data);
rootParent = this.getContext().getProject().Name;
records = [];
recordHash = {};
summaryHash = {};
removable_teams = [];
for ( var i=0; i<this.teams.length; i++ ) {
team_name = null;
var count = 0;
//console.log("count, data", this.teams[i], iteration_data[i]);
Ext.Array.each(iteration_data, function(data) {
if (this.teams[i] == data.Name && data.defectstory == 0 || null || undefined && data.Rework == 0 || null || undefined) {
count += 1;
team_name = data.Name;
}
}, this);
if (count == this.sprints.length) {
removable_teams.push(team_name);
}
}
removable_teams = Ext.Array.unique(removable_teams);
Ext.Array.each(iteration_data, function(iter) {
//for (i=0; i < this.teams.length; i++){
if (!recordHash[iter.Name]) {
recordHash[iter.Name] = {
Team: iter.Name
//DefectStory: iter.defectstory
//Id: record.get('ObjectID')
};
}
if (!Ext.Array.contains(removable_teams, iter.Name)) {
recordHash[iter.Name]["DefectStory-" + iter.Sprint] = iter.defectstory;
recordHash[iter.Name]["Rework-" + iter.Sprint] = iter.Rework;
//recordHash[team.ProjectName] = {Summary: 0};
} else {
recordHash[iter.Name]["DefectStory-" + iter.Sprint] = -1;
recordHash[iter.Name]["Rework-" + iter.Sprint] = -1;
}
}, this);
Ext.Object.each(recordHash, function(key, value) {
//value["Summary"] = summaryHash[key].Total;
records.push(value);
});
//console.log("records values", records);
var cfgsValues = [];
cfgsValues.push({text: 'Team', style:"background-color: #99CCFF", dataIndex: 'Team', width: 170, renderer: function(value, meta_data, record, row, col) {
if (Ext.Array.contains(parents, value)) {
meta_data.style = 'background-color:#99CCFF';
return Ext.String.format("<div style='font-weight:bold;text-align:center'>{0}</div>", value);
} else if (rootParent == value){
//value = record.get('Team')
meta_data.style = 'background-color:#CC6699';
return Ext.String.format("<div style='font-weight:bold;text-align:center'>{0}</div>", value);
} else {
return Ext.String.format("<div style='font-weight:normal;text-align:center'>{0}</div>", value);
};
}});
Ext.Array.each(this.sprints, function(sprint) {
cfgsValues.push(
{text: sprint, style:'background-color:#99CCFF;text-align:center;font-weight:bold;', defaults: {enableColumnHide:false}, columns:[
{text: "Rework", dataIndex: 'Rework-'+sprint, width: 50, renderer: function(value, meta_data) {
var color = null;
//console.log("value value", value);
if (value == -1) {
color = "#9B9B9B";
}
else if (value < 0.05) {
color = "#92D050";
}
else if (value >= 0.05 && value <= 0.5) {
color = "#FFEB66";
}
else if (value > 0.5) {
color = "#C00000";
}
meta_data.style = "background-color:"+color+"";
if ( value == -1) {
return "";
} else if (value){
return Ext.String.format("<div style='font-weight:normal;text-align:center'>{0}</div>", Ext.Number.toFixed(value, 2));
} else {
return 0;
}
}},
{text: "D/Story", dataIndex: 'DefectStory-'+sprint, width: 50, renderer: function(value, meta_data) {
var color = null;
if (value == -1 || undefined) {
color = "#9B9B9B";
}
else if (value < 0.05) {
color = "#92D050";
}
else if (value > 0.05 && value <= 0.5) {
color = "#FFEB66";
}
else if (value > 0.5) {
color = "#C00000";
}
//meta_data.style = "background-color: "+color+"";
meta_data.style = "background-color:"+color+"";
//meta_data.style = "border:1px";
if ( value == -1) {
return "";
} else if (value){
return Ext.String.format("<div style='font-weight:normal;text-align:center'>{0}</div>", Ext.Number.toFixed(value, 2));
} else {
return 0;
}
}}
/*{text: "%", dataIndex: 'DefectStory', width: 50, renderer: function(value, meta_data, record) {
}}*/
]}
);
});
var chart = Ext.getCmp('mychart');
if (chart) {
chart.destroy();
};
Ext.Array.each(this.sprints, function(sprint) {
Ext.Array.each(records, function(record) {
if (record["DefectStory-" + sprint] == undefined) {
record["DefectStory-" + sprint] = undefined;
}
if (record["Rework-" + sprint] == undefined) {
record["Rework-" + sprint] = undefined;
}
});
});
this.add({
xtype: 'rallygrid',
id: 'mychart',
store: Ext.create('Rally.data.custom.Store', {
data: records,
pageSize: 100
}),
/*features: [{
ftype: 'groupingsummary',
groupHeaderTpl: '{Name} ({rows.length})'
}],*/
viewConfig: {
stripeRows: false,
getRowClass: function(record) {
if (record.ProjectName == rootParent) {
return 'purple-row';
};
}
},
columnCfgs: cfgsValues,
//bodyBorder: true,
//border: true,
storeConfig: {
getGroupString: function(record) {
var Team = record.get('Name');
return Team || 'No Team';
},
},
columnLines: true
});
this.globalStore = Ext.getCmp('mychart');
this.down('#grid_box').add(this.globalStore);
//this.setLoading(false);
},