* finish task #1804.
This commit is contained in:
@@ -366,6 +366,10 @@ $lang->suhosinInfo = "Warming:data is too large! Please enlarge the setting of <
|
||||
$lang->noResultsMatch = "No results match";
|
||||
$lang->chooseUsersToMail = "Choose users to mail...";
|
||||
|
||||
$lang->date = new stdclass();
|
||||
$lang->date->day = 'Day';
|
||||
$lang->date->month = 'Month';
|
||||
|
||||
/* Date times. */
|
||||
define('DT_DATETIME1', 'Y-m-d H:i:s');
|
||||
define('DT_DATETIME2', 'y-m-d H:i');
|
||||
|
||||
@@ -366,6 +366,10 @@ $lang->suhosinInfo = "警告:数据太多,请在php.ini中修改<font color=
|
||||
$lang->noResultsMatch = "没有匹配结果";
|
||||
$lang->chooseUsersToMail = "选择要发信通知的用户...";
|
||||
|
||||
$lang->date = new stdclass();
|
||||
$lang->date->day = '天';
|
||||
$lang->date->month = '月';
|
||||
|
||||
/* 时间格式设置。*/
|
||||
define('DT_DATETIME1', 'Y-m-d H:i:s');
|
||||
define('DT_DATETIME2', 'y-m-d H:i');
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
$config->project = new stdclass();
|
||||
$config->project->defaultWorkhours = 7;
|
||||
$config->project->orderBy = 'isDone, status';
|
||||
$config->project->maxBurnDay = '30';
|
||||
$config->project->maxBurnDay = '31';
|
||||
|
||||
global $lang, $app;
|
||||
$app->loadLang('task');
|
||||
|
||||
+16
-44
@@ -673,12 +673,11 @@ class project extends control
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function burn($projectID = 0, $type = 'noweekend')
|
||||
public function burn($projectID = 0, $type = 'noweekend', $interval = 0)
|
||||
{
|
||||
$this->loadModel('report');
|
||||
$project = $this->commonAction($projectID);
|
||||
$projectInfo = $this->project->getByID($project->id);
|
||||
$maxDays = $this->config->project->maxBurnDay;
|
||||
|
||||
/* Header and position. */
|
||||
$title = $project->name . $this->lang->colon . $this->lang->project->burn;
|
||||
@@ -686,51 +685,19 @@ class project extends control
|
||||
$position[] = $this->lang->project->burn;
|
||||
|
||||
/* Get date list. */
|
||||
if($projectInfo->days <= $maxDays)
|
||||
{
|
||||
$dateList = $this->project->getDateList($projectInfo->begin, $projectInfo->end, $type);
|
||||
}
|
||||
else
|
||||
{
|
||||
$today = date('Y-m-d');
|
||||
if($today > $projectInfo->end)
|
||||
{
|
||||
$begin = $projectInfo->begin;
|
||||
$end = date('Y-m-d', strtotime($projectInfo->begin) + 30 * 24 * 3600);
|
||||
}
|
||||
else
|
||||
{
|
||||
$endDays = helper::diffDate($projectInfo->end, $today);
|
||||
$endDays = $endDays > 15 ? 15 : $endDays;
|
||||
$beginDays = $endDays > 15 ? 15 : (30 - $endDays);
|
||||
list($dateList, $interval) = $this->project->getDateList($projectInfo->begin, $projectInfo->end, $type, $interval);
|
||||
|
||||
$begin = date('Y-m-d', strtotime("-$beginDays days"));
|
||||
$begin = $begin > $projectInfo->begin ? $begin : $projectInfo->begin;
|
||||
$end = date('Y-m-d', strtotime("+$endDays days"));
|
||||
$end = $end > $projectInfo->end ? $projectInfo->end : $end;
|
||||
}
|
||||
$dateList = $this->project->getDateList($begin, $end, $type);
|
||||
}
|
||||
|
||||
$sets = $this->project->getBurnDataFlot($project->id, $maxDays);
|
||||
$sets = $this->project->getBurnDataFlot($project->id);
|
||||
$limitJSON = '[]';
|
||||
$baselineJSON = '[]';
|
||||
if($projectInfo->days <= $maxDays)
|
||||
{
|
||||
$firstBurn = empty($sets) ? 0 : reset($sets);
|
||||
$firstTime = isset($firstBurn->value) ? $firstBurn->value : 0;
|
||||
$days = count($dateList) - 1;
|
||||
$rate = $firstTime / $days;
|
||||
$baselineJSON = '[';
|
||||
foreach($dateList as $i => $date) $baselineJSON .='[' . $i . ',' . ($days - $i) * $rate . '],';
|
||||
$baselineJSON = rtrim($baselineJSON, ',') . ']';
|
||||
}
|
||||
else
|
||||
{
|
||||
$limitJSON = '[';
|
||||
foreach($dateList as $i => $date) $limitJSON .= "[$i, 0],";
|
||||
$limitJSON = rtrim($limitJSON, ',') . ']';
|
||||
}
|
||||
|
||||
$firstBurn = empty($sets) ? 0 : reset($sets);
|
||||
$firstTime = isset($firstBurn->value) ? $firstBurn->value : 0;
|
||||
$days = count($dateList) - 1;
|
||||
$rate = $firstTime / $days;
|
||||
$baselineJSON = '[';
|
||||
foreach($dateList as $i => $date) $baselineJSON .='[' . $i . ',' . ($days - $i) * $rate . '],';
|
||||
$baselineJSON = rtrim($baselineJSON, ',') . ']';
|
||||
|
||||
$flotJSON['data'] = $this->report->createSingleJSON($sets, $dateList);
|
||||
$flotJSON['limit'] = $limitJSON;
|
||||
@@ -740,6 +707,9 @@ class project extends control
|
||||
|
||||
$charts = $this->report->createJSChartFlot($project->name, $flotJSON, 900, 400);
|
||||
|
||||
$dayList = array_fill(1, floor(count($dateList) / $this->config->project->maxBurnDay) + 5, '');
|
||||
foreach($dayList as $key => $val) $dayList[$key] = ($key + 1) . $this->lang->date->day;
|
||||
|
||||
/* Assign. */
|
||||
$this->view->title = $title;
|
||||
$this->view->position = $position;
|
||||
@@ -747,6 +717,8 @@ class project extends control
|
||||
$this->view->charts = $charts;
|
||||
$this->view->projectID = $projectID;
|
||||
$this->view->type = $type;
|
||||
$this->view->interval = $interval;
|
||||
$this->view->dayList = array('full' => 1 . $this->lang->date->day) + $dayList;
|
||||
|
||||
$this->display();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
.pr-25px{padding-right:25px;}
|
||||
#burn h1{font-size:14px;}
|
||||
.icon-question-sign{color:#666}
|
||||
#computeBurn{padding:2px 10px;}
|
||||
@@ -0,0 +1,13 @@
|
||||
$('#interval').change(function()
|
||||
{
|
||||
location.href = createLink('project', 'burn', 'projectID=' + projectID + '&type=' + type + '&interval=' + $(this).val());
|
||||
})
|
||||
|
||||
var weekendType = $('#weekend').attr('checked');
|
||||
$('#weekend').click(function()
|
||||
{
|
||||
weekendType = weekendType ? 'noweekend' : 'widthweekend';
|
||||
params = 'projectID=' + projectID + '&type=' + weekendType;
|
||||
if(interval) params = params + '&interval=' + interval;
|
||||
location.href = createLink('project', 'burn', params);
|
||||
})
|
||||
@@ -53,7 +53,7 @@ $lang->project->noProduct = 'No product';
|
||||
$lang->project->select = '--select project--';
|
||||
$lang->project->createStory = "Create story";
|
||||
$lang->project->all = 'All';
|
||||
$lang->project->typeDesc = 'No burndown for waterfall, no story in OPS';
|
||||
$lang->project->typeDesc = 'No burndown and story in OPS';
|
||||
$lang->project->mine = 'I charge : ';
|
||||
$lang->project->other = 'Other : ';
|
||||
|
||||
@@ -174,7 +174,7 @@ $lang->project->groupSummary = "<strong>%s</strong> tasks in this group, wait
|
||||
$lang->project->wbs = "WBS";
|
||||
$lang->project->batchWBS = "Batch WBS";
|
||||
$lang->project->largeBurnChart = 'View large';
|
||||
$lang->project->howToUpdateBurn = "<a href='http://api.zentao.net/goto.php?item=burndown&lang=zh-cn' target='_blank'>How?</a>";
|
||||
$lang->project->howToUpdateBurn = "<a href='http://api.zentao.net/goto.php?item=burndown&lang=zh-cn' title='How to update burndown?' target='_blank'><i class='icon-question-sign'></i></a>";
|
||||
$lang->project->whyNoStories = "There no active stories to added to this project. Please check the linked product.";
|
||||
$lang->project->doneProjects = 'Done';
|
||||
$lang->project->unDoneProjects = 'Undone';
|
||||
@@ -194,8 +194,8 @@ $lang->project->linkStory = 'Link story';
|
||||
$lang->project->createTask = 'Create task';
|
||||
$lang->project->goback = 'Go back';
|
||||
$lang->project->linkProduct = 'Select product to link...';
|
||||
$lang->project->withWeekend = 'Show weekend';
|
||||
$lang->project->noWeekend = 'Remove weekend';
|
||||
$lang->project->weekend = 'Weekend';
|
||||
$lang->project->interval = 'Interval';
|
||||
|
||||
/* Report. */
|
||||
$lang->project->charts = new stdclass();
|
||||
|
||||
@@ -53,7 +53,7 @@ $lang->project->noProduct = '无产品项目';
|
||||
$lang->project->select = '--请选择项目--';
|
||||
$lang->project->createStory = "新增需求";
|
||||
$lang->project->all = '所有';
|
||||
$lang->project->typeDesc = '长期项目禁用燃尽图,运维项目禁用燃尽图和需求。';
|
||||
$lang->project->typeDesc = '运维项目禁用燃尽图和需求。';
|
||||
$lang->project->mine = '我负责:';
|
||||
$lang->project->other = '其他:';
|
||||
|
||||
@@ -106,7 +106,7 @@ $lang->project->dynamic = '动态';
|
||||
$lang->project->build = '版本列表';
|
||||
$lang->project->testtask = '测试任务';
|
||||
$lang->project->burn = '燃尽图';
|
||||
$lang->project->computeBurn = '更新燃尽图';
|
||||
$lang->project->computeBurn = '更新';
|
||||
$lang->project->burnData = '燃尽图数据';
|
||||
$lang->project->team = '团队成员';
|
||||
$lang->project->doc = '文档列表';
|
||||
@@ -174,7 +174,7 @@ $lang->project->groupSummary = "本组共 <strong>%s</strong> 个任务,未
|
||||
$lang->project->wbs = "分解任务";
|
||||
$lang->project->batchWBS = "批量分解";
|
||||
$lang->project->largeBurnChart = '点击查看大图';
|
||||
$lang->project->howToUpdateBurn = "<a href='http://api.zentao.net/goto.php?item=burndown&lang=zh-cn' target='_blank'>如何更新?</a>";
|
||||
$lang->project->howToUpdateBurn = "<a href='http://api.zentao.net/goto.php?item=burndown&lang=zh-cn' target='_blank' title='如何更新燃尽图?'><i class='icon-question-sign'></i></a>";
|
||||
$lang->project->whyNoStories = "看起来没有需求可以关联。请检查下项目关联的产品中有没有需求,而且要确保它们已经审核通过。";
|
||||
$lang->project->doneProjects = '已结束';
|
||||
$lang->project->unDoneProjects = '未结束';
|
||||
@@ -194,8 +194,8 @@ $lang->project->linkStory = '关联需求';
|
||||
$lang->project->createTask = '添加任务';
|
||||
$lang->project->goback = '返回项目首页';
|
||||
$lang->project->linkProduct = '选择产品关联...';
|
||||
$lang->project->withWeekend = '显示周末';
|
||||
$lang->project->noWeekend = '去除周末';
|
||||
$lang->project->weekend = '周末';
|
||||
$lang->project->interval = '间隔';
|
||||
|
||||
/* 统计。*/
|
||||
$lang->project->charts = new stdclass();
|
||||
|
||||
@@ -1288,11 +1288,10 @@ class projectModel extends model
|
||||
* Get burn data for flot
|
||||
*
|
||||
* @param int $projectID
|
||||
* @param int $itemCounts
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function getBurnDataFlot($projectID = 0, $itemCounts = 30)
|
||||
public function getBurnDataFlot($projectID = 0)
|
||||
{
|
||||
/* Get project and burn counts. */
|
||||
$project = $this->getById($projectID);
|
||||
@@ -1304,7 +1303,6 @@ class projectModel extends model
|
||||
$burnData = array();
|
||||
foreach($sets as $date => $set)
|
||||
{
|
||||
if($count > $itemCounts) break;
|
||||
if($date > $project->end) continue;
|
||||
|
||||
$burnData[$date] = $set;
|
||||
@@ -1495,12 +1493,25 @@ class projectModel extends model
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getDateList($begin, $end, $type)
|
||||
public function getDateList($begin, $end, $type, $interval = '')
|
||||
{
|
||||
$begin = strtotime($begin);
|
||||
$end = strtotime($end);
|
||||
|
||||
$days = ($end - $begin) / 3600 / 24;
|
||||
if($type == 'noweekend')
|
||||
{
|
||||
$mod = $days % 7;
|
||||
$days = $days - floor($days / 7) * 2;
|
||||
$days = $mod == 6 ? $days - 1 : $days;
|
||||
}
|
||||
|
||||
if(!$interval) $interval = floor($days / $this->config->project->maxBurnDay);
|
||||
|
||||
$dateList = array();
|
||||
$date = $begin;
|
||||
$spaces = (int)$interval;
|
||||
$counter = 0;
|
||||
while($date <= $end)
|
||||
{
|
||||
/* Remove weekend when type is noweekend.*/
|
||||
@@ -1514,10 +1525,18 @@ class projectModel extends model
|
||||
}
|
||||
}
|
||||
|
||||
$counter ++;
|
||||
if($counter <= $spaces)
|
||||
{
|
||||
$date += 24 * 3600;
|
||||
continue;
|
||||
}
|
||||
|
||||
$counter = 0;
|
||||
$dateList[] = date('m/d/Y', $date);
|
||||
$date += 24 * 3600;
|
||||
}
|
||||
|
||||
return $dateList;
|
||||
return array($dateList, $interval);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,12 +13,33 @@
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<?php include './taskheader.html.php';?>
|
||||
<script>$('#burnTab').addClass('active');</script>
|
||||
<div class='a-center'>
|
||||
<?php
|
||||
echo $charts;
|
||||
common::printLink('project', 'computeBurn', 'reload=yes', $lang->project->computeBurn, 'hiddenwin');
|
||||
echo html::a(inlink('burn', "projectID=$projectID&type=" . ($type == 'noweekend' ? 'withweekend' : 'noweekend')), ($type == 'noweekend' ? $lang->project->withWeekend : $lang->project->noWeekend));
|
||||
<table width='950' align='center' class='bd-none' id='burn'>
|
||||
<tr>
|
||||
<td class='a-right pr-25px' style='vertical-align:middle'>
|
||||
<?php
|
||||
$checked = ($type == 'noweekend') ? '' : "weekend";
|
||||
echo html::checkbox('', array('weekend' => $lang->project->weekend), $checked);
|
||||
|
||||
if($interval)
|
||||
{
|
||||
echo $lang->project->interval;
|
||||
echo html::select('interval', $dayList, $interval);
|
||||
}
|
||||
|
||||
common::printLink('project', 'computeBurn', 'reload=yes', $lang->project->computeBurn, 'hiddenwin', "title='{$lang->project->computeBurn}{$lang->project->burn}' class='btn' id='computeBurn'");
|
||||
echo $lang->project->howToUpdateBurn;
|
||||
?>
|
||||
</div>
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class='a-center'>
|
||||
<?php echo $charts; ?>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<?php
|
||||
js::set('projectID', $projectID);
|
||||
js::set('type', $type);
|
||||
js::set('interval', $interval);
|
||||
?>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class='f-left'>
|
||||
<?php
|
||||
echo "<span id='allTab'>"; common::printLink('project', 'task', "project=$projectID&type=all", $lang->project->allTasks); echo '</span>' ;
|
||||
if($project->type == 'sprint') print "<span id='burnTab'>" and common::printLink('project', 'burn', "project=$projectID", $lang->project->burn); print '</span>' ;
|
||||
if($project->type == 'sprint' or $project->type == 'waterfall') print "<span id='burnTab'>" and common::printLink('project', 'burn', "project=$projectID", $lang->project->burn); print '</span>' ;
|
||||
echo "<span id='assignedtomeTab'>"; common::printLink('project', 'task', "project=$projectID&type=assignedtome", $lang->project->assignedToMe); echo '</span>' ;
|
||||
|
||||
echo "<span id='statusTab'>";
|
||||
|
||||
+34
-2
@@ -92,7 +92,6 @@ EOT;
|
||||
return <<<EOT
|
||||
<!--[if lte IE 8]><script language="javascript" type="text/javascript" src="{$jsRoot}jquery/flot/excanvas.min.js"></script><![endif]-->
|
||||
<script language="javascript" type="text/javascript" src="{$jsRoot}jquery/flot/jquery.flot.min.js"></script>
|
||||
<h1>$projectName {$this->lang->project->burn}</h1>
|
||||
<div id="placeholder" style="width:$width;height:$height;margin:0 auto"></div>
|
||||
<script type="text/javascript">
|
||||
$(function ()
|
||||
@@ -102,6 +101,8 @@ $(function ()
|
||||
var baseline = $baselineJSON;
|
||||
var dateList = $dateListJSON;
|
||||
var ticks = $ticksJSON;
|
||||
var firstMon = 0;
|
||||
var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
|
||||
function showTooltip(x, y, contents)
|
||||
{
|
||||
$('<div id="tooltip">' + contents + '</div>').css
|
||||
@@ -121,7 +122,37 @@ $(function ()
|
||||
series: {lines:{show: true, lineWidth: 2}, points: {show: true},hoverable: true},
|
||||
legend: {noColumns: 1},
|
||||
grid: { hoverable: true, clickable: true },
|
||||
xaxis: { ticks:ticks, tickFormatter: function(val) {tick = new Date(dateList[val]);if(dateList[val] != undefined){return tick.getDate() + '/' + (tick.getMonth() + 1)}else{return ''}}},
|
||||
xaxis:
|
||||
{
|
||||
ticks:ticks,
|
||||
tickFormatter: function(val)
|
||||
{
|
||||
tick = new Date(dateList[val]);
|
||||
if(dateList[val] != undefined)
|
||||
{
|
||||
var month = tick.getMonth() + 1;
|
||||
var dateTail = '';
|
||||
if(firstMon != month)
|
||||
{
|
||||
dateTail = '<br />/' + month;
|
||||
firstMon = month;
|
||||
}
|
||||
|
||||
if(config.clientLang == 'en')
|
||||
{
|
||||
title = months[month-1] + ' ' + tick.getDate();
|
||||
}
|
||||
else
|
||||
{
|
||||
title = month + '{$this->lang->date->month}' + tick.getDate();
|
||||
}
|
||||
|
||||
if(ticks.length <= 30) dateTail = '/' + month;
|
||||
return '<span title="' + title + '">' + tick.getDate() + dateTail + '</span>';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
},
|
||||
yaxis: {mode: null, min: 0, minTickSize: [1, "day"]}};
|
||||
|
||||
var placeholder = $("#placeholder");
|
||||
@@ -171,6 +202,7 @@ $(function ()
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<h1>$projectName {$this->lang->project->burn}</h1>
|
||||
EOT;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user