* finish task #2580.

This commit is contained in:
wangyidong
2016-03-29 15:08:46 +08:00
parent 486b9396c0
commit 647e9bee18
11 changed files with 1098 additions and 24 deletions
+7
View File
@@ -85,3 +85,10 @@ $config->project->search['params']['finishedDate'] = array('operator' => '>=',
$config->project->search['params']['closedDate'] = array('operator' => '>=', 'control' => 'input', 'values' => '', 'class' => 'date');
$config->project->search['params']['canceledDate'] = array('operator' => '>=', 'control' => 'input', 'values' => '', 'class' => 'date');
$config->project->search['params']['lastEditedDate']= array('operator' => '>=', 'control' => 'input', 'values' => '', 'class' => 'date');
$config->printKanban = new stdClass();
$config->printKanban->col['story'] = 1;
$config->printKanban->col['wait'] = 2;
$config->printKanban->col['doing'] = 3;
$config->printKanban->col['done'] = 4;
$config->printKanban->col['closed'] = 5;
+151 -24
View File
@@ -691,8 +691,7 @@ class project extends control
public function burn($projectID = 0, $type = 'noweekend', $interval = 0)
{
$this->loadModel('report');
$project = $this->commonAction($projectID);
$projectInfo = $this->project->getByID($project->id);
$project = $this->commonAction($projectID);
/* Header and position. */
$title = $project->name . $this->lang->colon . $this->lang->project->burn;
@@ -700,23 +699,9 @@ class project extends control
$position[] = $this->lang->project->burn;
/* Get date list. */
$projectInfo = $this->project->getByID($projectID);
list($dateList, $interval) = $this->project->getDateList($projectInfo->begin, $projectInfo->end, $type, $interval, 'Y-m-d');
$sets = $this->project->getBurnDataFlot($project->id);
$limitJSON = '[]';
$baselineJSON = '[]';
$firstBurn = empty($sets) ? 0 : reset($sets);
$firstTime = isset($firstBurn->value) ? $firstBurn->value : $this->project->getTotalEstimate($projectInfo->id);
$days = count($dateList) - 1;
$rate = round($firstTime / $days, 2);
$baselineJSON = '[';
foreach($dateList as $i => $date) $baselineJSON .= ($days - $i) * $rate . ',';
$baselineJSON = rtrim($baselineJSON, ',') . ']';
$chartData['labels'] = $this->report->convertFormat($dateList, DT_DATE4);
$chartData['burnLine'] = $this->report->createSingleJSON($sets, $dateList);
$chartData['baseLine'] = $baselineJSON;
$chartData = $this->project->buildBurnData($projectID, $dateList, $type);
/* Set a space when assemble the string for english. */
$space = $this->app->getClientLang() == 'en' ? ' ' : '';
@@ -1192,6 +1177,146 @@ class project extends control
$this->display();
}
/**
* Kanban.
*
* @param int $projectID
* @param string $orderBy
* @access public
* @return void
*/
public function kanban($projectID, $orderBy = 'pri_asc')
{
/* Compatibility IE8*/
if(strpos($this->server->http_user_agent, 'MSIE 8.0') !== false) header("X-UA-Compatible: IE=EmulateIE7");
$this->project->setMenu($this->projects, $projectID);
$project = $this->loadModel('project')->getById($projectID);
$stories = $this->loadModel('story')->getProjectStories($projectID, $orderBy);
$tasks = $this->project->getKanbanTasks($projectID, "id");
$bugs = $this->loadModel('bug')->getProjectBugs($projectID);
$stories = $this->project->getKanbanGroupData($stories, $tasks, $bugs);
$this->view->title = $this->lang->project->kanban;
$this->view->position[] = html::a($this->createLink('project', 'browse', "projectID=$projectID"), $project->name);
$this->view->position[] = $this->lang->project->kanban;
$this->view->stories = $stories;
$this->view->realnames = $this->loadModel('user')->getPairs('noletter');
$this->view->orderBy = $orderBy;
$this->view->projectID = $projectID;
$this->view->project = $project;
$this->display();
}
/**
* Print kanban.
*
* @param int $projectID
* @param string $orderBy
* @access public
* @return void
*/
public function printKanban($projectID, $orderBy = 'id_asc')
{
$this->view->title = $this->lang->project->printKanban;
$contents = array('story', 'wait', 'doing', 'done', 'cancel');
if($_POST)
{
$stories = $this->loadModel('story')->getProjectStories($projectID, $orderBy);
$storySpecs = $this->story->getStorySpecs(array_keys($stories));
$order = 1;
foreach($stories as $story) $story->order = $order++;
$kanbanTasks = $this->project->getKanbanTasks($projectID, "id");
$kanbanBugs = $this->loadModel('bug')->getProjectBugs($projectID);
$users = array();
$taskAndBugs = array();
foreach($kanbanTasks as $task)
{
$storyID = $task->storyID;
$status = $task->status;
$users[] = $task->assignedTo;
$taskAndBugs[$status]["task{$task->id}"] = $task;
}
foreach($kanbanBugs as $bug)
{
$storyID = $bug->story;
$status = $bug->status;
$status = $status == 'active' ? 'wait' : ($status == 'resolved' ? ($bug->resolution == 'postponed' ? 'cancel' : 'done') : $status);
$users[] = $bug->assignedTo;
$taskAndBugs[$status]["bug{$bug->id}"] = $bug;
}
$datas = array();
foreach($contents as $content)
{
if($content != 'story' and !isset($taskAndBugs[$content])) continue;
$datas[$content] = $content == 'story' ? $stories : $taskAndBugs[$content];
}
unset($this->lang->story->stageList['']);
unset($this->lang->story->stageList['wait']);
unset($this->lang->story->stageList['planned']);
unset($this->lang->story->stageList['projected']);
unset($this->lang->story->stageList['released']);
unset($this->lang->task->statusList['']);
unset($this->lang->task->statusList['wait']);
unset($this->lang->task->statusList['closed']);
unset($this->lang->bug->statusList['']);
unset($this->lang->bug->statusList['closed']);
$originalDatas = $datas;
if($this->post->content == 'increment')
{
$prevKanbans = $this->project->getPrevKanban($projectID);
foreach($datas as $type => $data)
{
if(isset($prevKanbans[$type]))
{
$prevData = $prevKanbans[$type];
foreach($prevData as $id)
{
if(isset($data[$id])) unset($datas[$type][$id]);
}
}
}
}
$this->project->saveKanbanData($projectID, $originalDatas);
$hasBurn = $this->post->content == 'all';
if($hasBurn)
{
/* Get date list. */
$projectInfo = $this->project->getByID($projectID);
list($dateList) = $this->project->getDateList($projectInfo->begin, $projectInfo->end, 'noweekend');
$chartData = $this->project->buildBurnData($projectID, $dateList, 'noweekend');
}
$this->view->hasBurn = $hasBurn;
$this->view->datas = $datas;
$this->view->chartData = $chartData;
$this->view->storySpecs = $storySpecs;
$this->view->realnames = $this->loadModel('user')->getRealNameAndEmails($users);
$this->view->projectID = $projectID;
die($this->display());
}
$this->project->setMenu($this->projects, $projectID);
$project = $this->project->getById($projectID);
$this->view->position[] = html::a($this->createLink('project', 'browse', "projectID=$projectID"), $project->name);
$this->view->position[] = $this->lang->project->printKanban;
$this->display();
}
/**
* Delete a project.
*
@@ -1572,15 +1697,18 @@ class project extends control
{
if($confirm == 'no')
{
echo js::confirm($this->lang->project->confirmUnlinkStory, $this->createLink('project', 'unlinkstory', "projectID=$projectID&storyID=$storyID&confirm=yes"));
exit;
die(js::confirm($this->lang->project->confirmUnlinkStory, $this->createLink('project', 'unlinkstory', "projectID=$projectID&storyID=$storyID&confirm=yes")));
}
else
{
$this->project->unlinkStory($projectID, $storyID);
/* if ajax request, send result. */
if($this->server->ajax)
/* if kanban then reload and if ajax request then send result. */
if(isonlybody())
{
die(js::reload('parent'));
}
elseif(helper::isAjaxRequest())
{
if(dao::isError())
{
@@ -1594,8 +1722,7 @@ class project extends control
}
$this->send($response);
}
echo js::locate($this->app->session->storyList, 'parent');
exit;
die(js::locate($this->app->session->storyList, 'parent'));
}
}
+76
View File
@@ -0,0 +1,76 @@
table th.col-closed {width:15%}
#kanbanHeader th{border: 1px solid #ddd;}
#kanbanHeader .dropdown {display: inline-block; margin-left: 10px;}
#kanbanHeader .dropdown > a {color: #036}
#kanbanHeader th.col-closed {position: relative}
#kanbanHeader .actions {position: absolute; right: 0; top: 0; padding: 0px; background: #f1f1f1; border-left: 1px solid #ccc}
#kanbanHeader .actions .btn {display: block; border-radius: 0; width: 34px; height: 34px; position: relative; text-align: center; padding: 5px 0; color: #036}
#kanbanHeader .actions .btn-text {display: none}
#kanbanWrapper {table-layout: fixed; border-top: none}
#kanbanWrapper thead th, #kanbanWrapper thead, #kanbanWrapper thead tr {padding: 0!important; border: none!important; height: 0!important; border-bottom: none!important}
#kanbanWrapper tbody td {vertical-align: top; padding: 6px}
#kanbanWrapper tbody th {background: #f1f1f1}
#kanbanWrapper .board-shadow {height: 0; opacity: 0; transition: opacity 0.2s;}
#kanbanWrapper tbody tr.dragging td.col-droppable {background: #fff4e5}
#kanbanWrapper tbody tr.dragging td.col-droppable.drop-to {background: #ffeacc}
#kanbanWrapper tbody tr.dragging td.col-droppable.drop-to .board-task + .board-shadow {margin-top: 6px;}
#kanbanWrapper tbody tr.dragging td.col-droppable.drop-to .board-shadow {height: 28px; background: #999; background: rgba(0,0,0,0.35); opacity: 1;}
#kanbanWrapper tbody tr.dragging td.col-droppable.drop-to.drag-from .board-shadow {display: none}
#kanbanWrapper .board.drag-from {opacity: 0.8}
#kanban.dragging, .drag-shadow {cursor: move!important;}
.board {background: #333; color: #f1f1f1; color: rgba(255,255,255,0.9); opacity: 1; padding: 3px 6px; transition: all 0.2s; position:relative;}
.board + .board {margin-top: 6px;}
.board:hover {opacity: 1}
.board a {color: #f1f1f1; color: rgba(255,255,255,0.9);}
.board a:hover {color: #fff}
.board-title, .board-header, .board-footer {padding: 2px 0}
.board-title {padding-right:35px;}
.board-actions {position: absolute; right: 3px; top: 3px}
.board-actions .btn {margin: 0; color: #fff; color: rgba(255,255,255,0.5); min-width: 20px}
.board-actions .btn:hover {background: #999; color: #fff; background: rgba(255,255,255,.2);}
.ie-8 .board-actions .btn {min-width: 10px}
.board-actions > .dropdown {display: inline-block; margin-left: -5px;}
.dropdown .caret {border-top-color: #999}
.dropdown-menu > a {display: block; padding: 3px 15px; color: #333; font-size: 12px}
.dropdown-menu > a:hover {background: #f1f1f1; color: #1a53ff; text-decoration: none}
.dropdown-menu > a.disabled, .dropdown-menu > a.disabled:hover, .dropdown-menu > a.active {color: #aaa; background: none}
.board .board-footer {display: none; opacity: 0.9}
.board.show-info .board-footer {display: block; margin: 0 -6px -3px -6px; padding: 5px; background: rgba(0,0,0,0.2);}
.board-footer .board-id {display: inline-block; border: 1px solid #aaa; font-weight: normal; padding: 0px 4px; text-align: center; min-width: 20px; line-height: 16px; height: 17px; margin-right: 10px; font-size: 12px;}
.board-bug-closed .board-footer .bug-pri, .board-task-closed .board-footer .task-pri {border-color: #666}
.board-bug-closed .board-footer .board-id, .board-task-closed .board-footer .board-id {border-color: #777}
.board-footer .bug-pri, .board-footer .task-pri, .board-footer .story-pri {margin-right: 10px;}
.board-story {background: #dd7503}
.board-bug-wait,.board-task-wait {background: #2b529c}
.board-bug-doing,.board-task-doing {background: #D2322D}
.board-bug-done,.board-task-done {background: #229F24}
.board-bug-closed,.board-task-closed {background: #ddd; color: #333}
.board-bug-closed .board-title,.board-task-closed .board-title {border-bottom-color: #333}
.board-bug-closed a,.board-task-closed a {color: #222}
.board-bug-closed a:hover,.board-task-closed a:hover {color: #000}
.board-bug-closed .board-actions .btn,.board-task-closed .board-actions .btn {color: #666}
.board-bug-closed .board-actions .btn:hover,.board-task-closed .board-actions .btn:hover {color: #333; background: #ccc}
.pri-0:before, .pri-3:before {content: "3";}
.pri-1:before {content: "1";}
.pri-2:before {content: "2";}
.pri-4:before {content: "4";}
.pri-5:before {content: "5";}
.pri-6:before {content: "6";}
.story-pri {display: inline-block; width: 16px; height: 16px; text-align: center; border-radius: 8px; line-height: 16px; font-size: 12px}
.story-pri.pri-0 {background-color:#b56a00;}
.story-pri.pri-1 {background-color:#E30413;}
.story-pri.pri-2 {background-color:#E84E0E;}
.story-pri.pri-3 {background-color:#b56a00;}
.story-pri.pri-4 {background-color:#795523;}
.bug-pri,.task-pri {display: inline-block; width: 16px; height: 16px; text-align: center; border-radius: 8px; border: 1px solid #ddd; font-size: 12px}
.affix {position:fixed; top:0px; width:95%;z-index:1030;}
#kanbanHeader.affix {box-shadow: 0 3px 10px rgba(0,0,0,.1); background: }
#kanbanHeader.affix th {border-bottom: 1px solid #bbb; background: #ebf5f9}
+208
View File
@@ -0,0 +1,208 @@
$(function()
{
var boardID = '';
var onlybody = config.requestType == 'GET' ? "&onlybody=yes" : "?onlybody=yes";
$('#printKanban').modalTrigger({type:'iframe', width: 400, url: createLink('project', 'printKanban', 'projectID=' + projectID), icon: 'print'});
$(".kanbanFrame").modalTrigger({type: 'iframe', width: '80%', afterShow:function(){ $('#ajaxModal').data('cancel-reload', true)}, afterHidden: function(){refresh()}});
$.cookie('selfClose', 0, {expires:config.cookieLife, path:config.webRoot});
var $kanban = $('#kanban');
var $kanbanWrapper = $('#kanbanWrapper');
initBoards();
var statusMap =
{
task:
{
wait : {doing: 'start', done: 'finish', cancel: 'cancel'},
doing : {done: 'finish'},
done : {doing: 'activate', closed: 'close'},
cancel : {doing: 'activate', closed: 'close'},
closed : {doing: 'activate'}
},
bug:
{
wait : {done: 'resolve', cancel: 'resolve'},
doing : {},
done : {wait: 'activate', closed: 'close'},
cancel : {wait: 'activate', closed: 'close'},
closed : {wait: 'activate'}
}
};
var lastOperation;
function dropTo(id, from, to, type)
{
if(statusMap[type][from] && statusMap[type][from][to])
{
lastOperation = {id: id, from: from, to: to};
$.modalTrigger({type: 'iframe', url: createLink(type, statusMap[type][from][to], 'id=' + id) + onlybody, afterShow:function(){ $('#ajaxModal').data('cancel-reload', true)}, afterHidden: function()
{
var selfClose = $.cookie('selfClose');
$.cookie('selfClose', 0, {expires:config.cookieLife, path:config.webRoot});
if(selfClose != 1 && lastOperation)
{
$item = $('#' + type + '-' + lastOperation.id);
for(var status in statusMap[type])
{
$item.removeClass('board-' + type + '-' + status);
}
$item.addClass('board-' + type + '-' + lastOperation.from).insertBefore($item.closest('tr').find('.col-'+lastOperation.from + ' .board-shadow'));
}
else
{
$.get(createLink(type, 'ajaxGetByID', 'id=' + id), function(data)
{
$('div#' + type + '-' + id).find('.' + type + '-assignedTo small').html(data.assignedTo);
if(type == 'task')
{
$('div#task-' + id).find('.task-left').html(data.left + 'h');
if(data.story)$('div.board-story[data-id="' + data.story + '"]').find('.story-stage').html(data.storyStage);
}
}, 'json');
}
}});
return true;
}
return false;
}
function initBoards()
{
$('.col-droppable').append('<div class="board-shadow"></div>');
var $boardTasks = $kanban.find('.board-task');
$boardTasks.droppable(
{
target: '.col-droppable',
flex: true,
before: function(e)
{
if(e.element.find('.dropdown.open').length) return false;
},
start: function(e)
{
e.element.closest('td').addClass('drag-from').closest('tr').addClass('dragging');
$kanban.addClass('dragging').find('.board-item-shadow').height(e.element.outerHeight());
},
drag: function(e)
{
if(e.isNew)
{
var $dargShadow = $('.drag-shadow.board-task');
for(var status in statusMap['task'])
{
$dargShadow.removeClass('board-task-' + status);
}
$dargShadow.addClass('board-task-' + e.target.data('id'));
}
},
drop: function(e)
{
if(e.isNew && e.element.closest('tr').data('id') == e.target.closest('tr').data('id'))
{
var result = dropTo(e.element.data('id'), e.element.closest('td').data('id'), e.target.data('id'), 'task');
if(result !== false)
{
for(var status in statusMap['task'])
{
e.element.removeClass('board-task-' + status);
}
e.element.addClass('board-task-' + e.target.data('id')).insertBefore(e.target.find('.board-shadow'));
}
}
},
finish: function(e)
{
$kanban.removeClass('dragging drop-in');
$kanbanWrapper.find('tr.dragging').removeClass('dragging').find('.drop-in, .drag-from').removeClass('drop-in drag-from');
}
});
var $boardBugs = $kanban.find('.board-bug');
$boardBugs.droppable(
{
target: '.col-droppable',
flex: true,
start: function(e)
{
e.element.closest('td').addClass('drag-from').closest('tr').addClass('dragging');
$kanban.addClass('dragging').find('.board-item-shadow').height(e.element.outerHeight());
},
drag: function(e)
{
if(e.isNew)
{
var $dargShadow = $('.drag-shadow.board-bug');
for(var status in statusMap['bug'])
{
$dargShadow.removeClass('board-bug-' + status);
}
$dargShadow.addClass('board-bug-' + e.target.data('id'));
}
},
drop: function(e)
{
if(e.isNew && e.element.closest('tr').data('id') == e.target.closest('tr').data('id'))
{
var result = dropTo(e.element.data('id'), e.element.closest('td').data('id'), e.target.data('id'), 'bug');
if(result !== false)
{
for(var status in statusMap['bug'])
{
e.element.removeClass('board-bug-' + status);
}
e.element.addClass('board-bug-' + e.target.data('id')).insertBefore(e.target.find('.board-shadow'));
}
}
},
finish: function(e)
{
$kanban.removeClass('dragging drop-in');
$kanbanWrapper.find('tr.dragging').removeClass('dragging').find('.drop-in, .drag-from').removeClass('drop-in drag-from');
}
});
}
function refresh()
{
var selfClose = $.cookie('selfClose');
$.cookie('selfClose', 0, {expires:config.cookieLife, path:config.webRoot});
if(selfClose == 1)
{
$('#kanbanWrapper').wrap("<div id='tempDIV'></div>");
$('#tempDIV').load(location.href + ' #kanbanWrapper', function()
{
$('#kanbanWrapper').unwrap();
initBoards()
$(".kanbanFrame").modalTrigger({type: 'iframe', width: '80%', afterShow:function(){ $('#ajaxModal').data('cancel-reload', true)}, afterHidden: function(){refresh()}});
});
}
}
var fixH = $("#kanbanHeader").offset().top;
$(window).scroll(function()
{
var scroH = $(this).scrollTop();
if(scroH>=fixH)
{
$("#kanbanHeader").addClass('affix');
$("#kanbanHeader").width($('#kanbanWrapper').width());
}
else if(scroH<fixH)
{
$("#kanbanHeader").removeClass('affix');
$("#kanbanHeader").css('width', '100%');
}
});
$('#kanban').on('click', '.btn-info-toggle', function()
{
$btn = $(this);
$btn.find('i').toggleClass('icon-angle-down').toggleClass('icon-angle-up');
$btn.parents('.board').toggleClass('show-info');
});
});
+21
View File
@@ -216,3 +216,24 @@ $lang->project->placeholder->totalLeft = 'Total left when start project';
$lang->project->selectGroup = new stdclass();
$lang->project->selectGroup->done = '(done)';
$lang->project->orderList['pri_asc'] = "Stroy Pri Asc";
$lang->project->orderList['pri_desc'] = "Stroy Pri Desc";
$lang->project->orderList['id_asc'] = "Stroy ID Asc";
$lang->project->orderList['id_desc'] = "Stroy ID Desc";
$lang->project->orderList['stage_asc'] = "Stroy Stage Asc";
$lang->project->orderList['stage_desc'] = "Stroy Starg Desc";
$lang->project->kanban = "kanban";
$lang->project->printKanban = "Print Kanban";
$lang->project->bugList = "Bug List";
$lang->printKanban = new stdclass();
$lang->printKanban->common = 'Print Kanban';
$lang->printKanban->content = 'Content';
$lang->printKanban->print = 'Print';
$lang->printKanban->taskStatus = 'Status';
$lang->printKanban->typeList['all'] = 'All';
$lang->printKanban->typeList['increment'] = 'Increment';
+21
View File
@@ -216,3 +216,24 @@ $lang->project->placeholder->totalLeft = '项目开始时的总预计工时';
$lang->project->selectGroup = new stdclass();
$lang->project->selectGroup->done = '(已结束)';
$lang->project->orderList['pri_asc'] = "需求优先级正序";
$lang->project->orderList['pri_desc'] = "需求优先级倒序";
$lang->project->orderList['id_asc'] = "需求ID正序";
$lang->project->orderList['id_desc'] = "需求ID倒序";
$lang->project->orderList['stage_asc'] = "需求阶段正序";
$lang->project->orderList['stage_desc'] = "需求阶段倒序";
$lang->project->kanban = "看板";
$lang->project->printKanban = "打印看板";
$lang->project->bugList = "Bug列表";
$lang->printKanban = new stdclass();
$lang->printKanban->common = '看板打印';
$lang->printKanban->content = '内容';
$lang->printKanban->print = '打印';
$lang->printKanban->taskStatus = '状态';
$lang->printKanban->typeList['all'] = '全部';
$lang->printKanban->typeList['increment'] = '增量';
+133
View File
@@ -1792,4 +1792,137 @@ class projectModel extends model
$this->loadModel('search')->setSearchParams($this->config->project->search);
}
/**
* Get Kanban tasks
*
* @param int $projectID
* @param string $orderBy
* @param object $pager
* @access public
* @return void
*/
public function getKanbanTasks($projectID, $orderBy = 'status_asc, id_desc', $pager = null)
{
$tasks = $this->dao->select('t1.*, t2.id AS storyID, t2.title AS storyTitle, t2.version AS latestStoryVersion, t2.status AS storyStatus, t3.realname AS assignedToRealName')
->from(TABLE_TASK)->alias('t1')
->leftJoin(TABLE_STORY)->alias('t2')->on('t1.story = t2.id')
->leftJoin(TABLE_USER)->alias('t3')->on('t1.assignedTo = t3.account')
->where('t1.project')->eq((int)$projectID)
->andWhere('t1.deleted')->eq(0)
->orderBy($orderBy)
->page($pager)
->fetchAll();
$this->loadModel('common')->saveQueryCondition($this->dao->get(), 'task');
if($tasks) return $this->loadModel('task')->processTasks($tasks);
return array();
}
/**
* Get kanban group data.
*
* @param array $tasks
* @param array $bugs
* @access public
* @return array
*/
public function getKanbanGroupData($stories, $tasks, $bugs)
{
$stories['nostory'] = new stdclass();
foreach($tasks as $task)
{
$storyID = $task->storyID;
$status = $task->status;
if(!empty($storyID) and isset($stories[$storyID]))
{
$stories[$storyID]->tasks[$status][] = $task;
}
else
{
$noStoryTasks[$status][] = $task;
}
}
if(isset($noStoryTasks)) $stories['nostory']->tasks = $noStoryTasks;
foreach($bugs as $bug)
{
$storyID = $bug->story;
$status = $bug->status;
$status = $status == 'active' ? 'wait' : ($status == 'resolved' ? ($bug->resolution == 'postponed' ? 'cancel' : 'done') : $status);
if(!empty($storyID) and isset($stories[$storyID]))
{
$stories[$storyID]->bugs[$status][] = $bug;
}
else
{
$noStoryBugs[$status][] = $bug;
}
}
if(isset($noStoryBugs)) $stories['nostory']->bugs = $noStoryBugs;
return $stories;
}
/**
* Save Kanban Data.
*
* @param int $projectID
* @param array $kanbanDatas
* @access public
* @return void
*/
public function saveKanbanData($projectID, $kanbanDatas)
{
$data = array();
foreach($kanbanDatas as $type => $kanbanData) $data[$type] = array_keys($kanbanData);
$this->loadModel('setting')->setItem("null.project.kanban.project$projectID", json_encode($data));
}
/**
* Get Prev Kanban.
*
* @param int $projectID
* @access public
* @return array
*/
public function getPrevKanban($projectID)
{
$prevKanbans = $this->loadModel('setting')->getItem("ower=null&module=project&section=kanban&key=project$projectID");
return json_decode($prevKanbans, true);
}
/**
* Build burn data.
*
* @param int $projectID
* @param array $dateList
* @param string $type
* @access public
* @return array
*/
public function buildBurnData($projectID, $dateList, $type)
{
$this->loadModel('report');
$sets = $this->getBurnDataFlot($projectID);
$limitJSON = '[]';
$baselineJSON = '[]';
$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 .= ($days - $i) * $rate . ',';
$baselineJSON = rtrim($baselineJSON, ',') . ']';
$chartData['labels'] = $this->report->convertFormat($dateList, 'j/n');
$chartData['burnLine'] = $this->report->createSingleJSON($sets, $dateList);
$chartData['baseLine'] = $baselineJSON;
return $chartData;
}
}
+178
View File
@@ -0,0 +1,178 @@
<?php
/**
* The kanban view file of project module of ZenTaoPMS.
*
* @copyright Copyright 2009-2012 青岛易软天创网络科技有限公司 (QingDao Nature Easy Soft Network Technology Co,LTD www.cnezsoft.com)
* @author Wang Yidong, Zhu Jinyong
* @package project
* @version $Id: kanban.html.php $
*/
?>
<?php include '../../common/view/header.html.php';?>
<?php include './taskheader.html.php';?>
<?php $taskCols = array('wait', 'doing', 'done', 'cancel', 'closed'); ?>
<div id='kanban'>
<table class='boards-layout table' id='kanbanHeader'>
<thead>
<tr>
<?php if($project->type != 'ops'):?>
<th class='w-p15 col-story'>
<div class='dropdown inline-block'>
<a data-toggle='dropdown' href='javascript:;'><?php echo $lang->project->orderList[$orderBy]?> <span class='icon-caret-down'></span> </a>
<ul class='dropdown-menu text-left'>
<?php foreach ($lang->project->orderList as $key => $value):?>
<li <?php echo $orderBy == $key ? " class='active'" : '' ?>><?php echo html::a($this->createLink('project', 'kanban', "projectID=$projectID&orderBy=$key"), $value);?></li>
<?php endforeach;?>
</ul>
</div>
</th>
<?php endif;?>
<?php $endCol = array_pop($taskCols);?>
<?php foreach ($taskCols as $col):?>
<th class='col-<?php echo $col?>'><?php echo $lang->task->statusList[$col];?></th>
<?php endforeach;?>
<th class='col-<?php echo $endCol?>'><?php echo $lang->task->statusList[$endCol];?>
<div class='actions'>
<?php if(common::hasPriv('project', 'printKanban')) echo html::commonButton("<i class='icon-print'></i><span class='btn-text'> " . $lang->project->printKanban . '</span>', "id='printKanban' title='" . $lang->project->printKanban . "'", 'btn btn-sm btn-link');?>
</div>
</th>
</tr>
</thead>
</table>
<?php $taskCols[] = $endCol;?>
<table class='boards-layout table active-disabled table-bordered' id='kanbanWrapper'>
<thead>
<tr>
<?php if($project->type != 'ops'):?>
<th class='w-p15 col-story'> </th>
<?php endif;?>
<?php foreach ($taskCols as $col):?><th class='col-<?php echo $col?>'></th><?php endforeach;?>
</tr>
</thead>
<tbody>
<?php $rowIndex = 0; ?>
<?php foreach($stories as $story):?>
<tr data-id='<?php echo $rowIndex++?>'>
<?php if($project->type != 'ops'):?>
<td class='col-story'>
<?php if(!empty($story->id)):?>
<div class='board board-story' data-id='<?php echo $story->id?>'>
<div class='board-title'>
<?php echo html::a($this->createLink('story', 'view', "storyID=$story->id", '', true), $story->title, '', 'class="kanbanFrame" title="' . $story->title . '"');?>
<div class='board-actions'>
<button type='button' class='btn btn-mini btn-link btn-info-toggle'><i class='icon-angle-down'></i></button>
<div class='dropdown'>
<button type='button' class='btn btn-mini btn-link dropdown-toggle' data-toggle='dropdown'>
<span class='icon-ellipsis-v'></span>
</button>
<div class='dropdown-menu pull-right'>
<?php
echo (common::hasPriv('task', 'create')) ? html::a($this->createLink('task', 'create', "projectID=$story->project&storyID=$story->story&moduleID=$story->module", '', true), $lang->project->wbs, '', "class='kanbanFrame'") : '';
echo (common::hasPriv('project', 'unlinkStory')) ? html::a($this->createLink('project', 'unlinkStory', "projectID=$story->project&storyID=$story->story&confirm=no", '', true), $lang->project->unlinkStory, 'hiddenwin') : '';
echo (common::hasPriv('story', 'activate') and storyModel::isClickable($story, 'activate')) ? html::a($this->createLink('story', 'activate', "storyID=$story->id", '', 'true'), $lang->story->activate, '', "class='kanbanFrame'") : '';
echo (common::hasPriv('story', 'close') and storyModel::isClickable($story, 'close')) ? html::a($this->createLink('story', 'close', "storyID=$story->id", '', 'true'), $lang->story->close, '', "class='kanbanFrame'") : '';
?>
</div>
</div>
</div>
</div>
<div class='board-footer clearfix'>
<span class='story-id board-id' title='<?php echo $lang->story->id?>'><?php echo $story->id?></span>
<span class='story-pri pri-<?php echo $story->pri?>' title='<?php echo $lang->story->pri?>'></span>
<span class='story-stage' title='<?php echo $lang->story->stage?>'><?php echo $lang->story->stageList[$story->stage];?></span>
<div class='pull-right story-estimate' title='<?php echo $lang->story->estimate?>'><?php echo $story->estimate . 'h ';?></div>
</div>
</div>
<?php endif;?>
</td>
<?php endif;?>
<?php foreach ($taskCols as $col):?>
<td class='col-droppable col-<?php echo $col?>' data-id='<?php echo $col?>'>
<?php if(!empty($story->tasks[$col])):?>
<?php foreach($story->tasks[$col] as $task):?>
<div class='board board-task board-task-<?php echo $col ?>' data-id='<?php echo $task->id?>' id='task-<?php echo $task->id?>'>
<div class='board-title'>
<?php echo html::a($this->createLink('task', 'view', "taskID=$task->id", '', true), $task->name, '', 'class="kanbanFrame" title="' . $task->name . '"');?>
<div class='board-actions'>
<button type='button' class='btn btn-mini btn-link btn-info-toggle'><i class='icon-angle-down'></i></button>
<div class='dropdown'>
<button type='button' class='btn btn-mini btn-link dropdown-toggle' data-toggle='dropdown'>
<span class='icon-ellipsis-v'></span>
</button>
<div class='dropdown-menu pull-right'>
<?php
echo (common::hasPriv('task', 'assignTo') and taskModel::isClickable($task, 'assignTo')) ? html::a($this->createLink('task', 'assignTo', "projectID=$task->project&taskID=$task->id", '', 'true'), $lang->task->assignTo, '', "class='kanbanFrame'") : '';
echo (common::hasPriv('task', 'start') and taskModel::isClickable($task, 'start')) ? html::a($this->createLink('task', 'start', "taskID=$task->id", '', 'true'), $lang->task->start, '', "class='kanbanFrame'") : '';
echo (common::hasPriv('task', 'finish') and taskModel::isClickable($task, 'finish')) ? html::a($this->createLink('task', 'finish', "taskID=$task->id", '', 'true'), $lang->task->finish, '', "class='kanbanFrame'") : '';
echo (common::hasPriv('task', 'cancel') and taskModel::isClickable($task, 'cancel')) ? html::a($this->createLink('task', 'cancel', "taskID=$task->id", '', 'true'), $lang->task->cancel, '', "class='kanbanFrame'") : '';
echo (common::hasPriv('task', 'activate') and taskModel::isClickable($task, 'activate')) ? html::a($this->createLink('task', 'activate', "taskID=$task->id", '', 'true'), $lang->task->activate, '', "class='kanbanFrame'") : '';
echo (common::hasPriv('task', 'close') and taskModel::isClickable($task, 'close')) ? html::a($this->createLink('task', 'close', "taskID=$task->id", '', 'true'), $lang->task->close, '', "class='kanbanFrame'") : '';
echo (common::hasPriv('task', 'edit') and taskModel::isClickable($task, 'edit')) ? html::a($this->createLink('task', 'edit', "taskID=$task->id", '', 'true'), $lang->task->edit, '', "class='kanbanFrame'") : '';
echo (common::hasPriv('task', 'delete') and taskModel::isClickable($task, 'delete')) ? html::a($this->createLink('task', 'delete', "project=$task->project&taskID=$task->id"), $lang->task->delete, 'hiddenwin') : '';
?>
</div>
</div>
</div>
</div>
<div class='board-footer clearfix'>
<span class='task-id board-id' title='<?php echo $lang->task->id?>'><?php echo $task->id?></span>
<span class='task-pri pri-<?php echo $task->pri?>' title='<?php echo $lang->task->pri?>'></span>
<span class="task-assignedTo" title='<?php echo $lang->task->assignedTo?>'>
<?php echo html::a($this->createLink('task', 'assignTo', "projectID=$task->project&taskID=$task->id", '', true), '<i class="icon-hand-right"></i>', '', "class='kanbanFrame'")?>
<small><?php echo zget($realnames, $task->assignedTo, $task->assignedTo);?></small>
</span>
<div class='pull-right'>
<span class='task-left' title='<?php echo $lang->task->left?>'><?php echo $task->left . 'h ';?></span>
</div>
</div>
</div>
<?php endforeach?>
<?php endif?>
<?php if(!empty($story->bugs[$col])):?>
<?php foreach($story->bugs[$col] as $bug):?>
<div class='board board-bug board-bug-<?php echo $col ?>' data-id='<?php echo $bug->id?>' id='bug-<?php echo $bug->id?>'>
<div class='board-title'>
<i class="icon-bug"></i>
<?php echo html::a($this->createLink('bug', 'view', "bugID=$bug->id", '', true), $bug->title, '', 'class="kanbanFrame" title="' . $bug->title . '"');?>
<div class='board-actions'>
<button type='button' class='btn btn-mini btn-link btn-info-toggle'><i class='icon-angle-down'></i></button>
<div class='dropdown'>
<button type='button' class='btn btn-mini btn-link dropdown-toggle' data-toggle='dropdown'>
<span class='icon-ellipsis-v'></span>
</button>
<div class='dropdown-menu pull-right'>
<?php
echo (common::hasPriv('bug', 'assignTo') and bugModel::isClickable($bug, 'assignTo')) ? html::a($this->createLink('bug', 'assignTo', "bugID=$bug->id", '', 'true'), $lang->bug->assignTo, '', "class='kanbanFrame'") : '';
echo (common::hasPriv('bug', 'resolve') and bugModel::isClickable($bug, 'resolve')) ? html::a($this->createLink('bug', 'resolve', "bugID=$bug->id", '', 'true'), $lang->bug->resolve, '', "class='kanbanFrame'") : '';
echo (common::hasPriv('bug', 'activate') and bugModel::isClickable($bug, 'activate')) ? html::a($this->createLink('bug', 'activate', "bugID=$bug->id", '', 'true'), $lang->bug->activate, '', "class='kanbanFrame'") : '';
echo (common::hasPriv('bug', 'close') and bugModel::isClickable($bug, 'close')) ? html::a($this->createLink('bug', 'close', "bugID=$bug->id", '', 'true'), $lang->bug->close, '', "class='kanbanFrame'") : '';
echo (common::hasPriv('bug', 'edit') and bugModel::isClickable($bug, 'edit')) ? html::a($this->createLink('bug', 'edit', "bugID=$bug->id", '', 'true'), $lang->bug->edit, '', "class='kanbanFrame'") : '';
echo (common::hasPriv('bug', 'delete') and bugModel::isClickable($bug, 'delete')) ? html::a($this->createLink('bug', 'delete', "bugID=$bug->id"), $lang->bug->delete, 'hiddenwin') : '';
?>
</div>
</div>
</div>
</div>
<div class='board-footer clearfix'>
<span class='bug-id board-id' title='<?php echo $lang->bug->id?>'><?php echo $bug->id?></span>
<span class='bug-pri pri-<?php echo $bug->pri?>' title='<?php echo $lang->bug->pri?>'></span>
<span class="bug-assignedTo" title='<?php echo $lang->bug->assignedTo?>'>
<?php echo html::a($this->createLink('bug', 'assignTo', "bugID=$bug->id", '', true), '<i class="icon-hand-right"></i>', '', "class='kanbanFrame'")?>
<small><?php echo zget($realnames, $bug->assignedTo, $bug->assignedTo);?></small>
</span>
</div>
</div>
<?php endforeach?>
<?php endif?>
</td>
<?php endforeach;?>
</tr>
<?php endforeach;?>
</tbody>
</table>
</div>
<script>
var projectID = <?php echo $projectID?>;
$('#kanbanTab').addClass('active');
</script>
<?php include '../../common/view/footer.html.php';?>
+274
View File
@@ -0,0 +1,274 @@
<?php include '../../common/view/header.lite.html.php';?>
<?php include '../../common/view/chart.html.php';?>
<?php
$height = 7;
$width = 6.4;
$pagerH = '30.5';
$bottom = '40';
$agent = $_SERVER["HTTP_USER_AGENT"];
if(strpos($agent, "MSIE"))
{
$width = 6.6;
$height = 7.3;
$pagerH = '30.8';
$bottom = '80';
}
elseif(strpos($agent, "Firefox"))
{
$height = 6.9;
$pagerH = '29';
$bottom = '60';
}
elseif(strpos($agent, "Opera"))
{
$height = 7;
}
$today = date('n/d');
?>
<style type='text/css'>
body {margin: 0pt}
.pager{ border:1px solid #000; margin-bottom:<?php echo $bottom?>px; border-collapse:collapse; border-spacing:0px; width:21.6cm; height:<?php echo $pagerH?>cm}
.pager td{ border:1px dotted #000;}
.pager td{width:<?php echo $width?>cm; height:<?php echo $height?>cm;}
.pager .stage{border:0px; width:100%; height:auto; margin:0px;}
.pager .stage td{height:auto; border:0px; padding:0px; margin:0px;}
.board {width:<?php echo $width - 0.2?>cm; height:<?php echo $height - 0.2?>cm; font-size:12px; border: 1px solid #ccc; text-align:left}
#record{margin-bottom:0px; margin-top:5px; border:1px solid #000; width:100%; border-collapse:collapse; border-spacing:0px}
#record td{width:13%; height:14px; border:1px solid #000}
#burn{margin-top:50px;}
.board-header{overflow:hidden; padding:1px 3px 1px 3px;}
.board-id{overflow:hidden; padding:1px 3px 1px 3px; width:84%; border-bottom:2px solid #000;}
.board-pri{border:1px solid #000; position:absolute; right:0px; top:0px; font-size:20px; padding:2px;}
.board-middle{overflow:hidden}
.board-title{overflow:hidden; padding:1px 3px 1px 3px; width:95%; font-size:18px; font-weight:bold; line-height:1.15}
.board-content{overflow:hidden; padding:1px 3px 1px 3px; width:95%; font-size:14px; line-height:1.2;letter-spacing:1px;}
.board-content p{margin-bottom:0px;}
.board-footer{border-top:1px dotted #000; padding-top:5px; position:absolute; left:0px; width:100%}
.board-footer.story{bottom:0px;}
.board-footer.task{bottom:0px;}
.board-footer p{ height:14px;padding:0px 3px; margin-bottom:2px;}
</style>
<?php
$i = 0;
$dataType = '';
?>
<?php foreach($datas as $col => $data):?>
<?php foreach($data as $id => $content):?>
<?php if($col != 'story') $dataType = strpos($id, 'bug') !== false ? 'bug' : 'task';?>
<?php if($i % 12 == 0):?>
<table class='pager'>
<?php endif;?>
<?php if($i % 3 == 0):?>
<tr>
<?php endif;?>
<td valign='middle' align='center'>
<div class="board" style='position:relative'>
<div class="board-header">
<div class="board-id">
<?php
if($col != 'story')
{
$story = $dataType == 'bug' ? $content->story : $content->storyID;
echo $lang->story->common . "#<span style='font-size:20px'>" . (empty($story) ? '0' : $story) . '</span>';
echo ' <i class="icon-angle-right"></i> ';
}
?>
<?php echo $col == 'story' ? $lang->story->common : ($dataType == 'task' ? $lang->task->common : $lang->bug->common)?>
#<span style='font-size:20px;'><?php echo $content->id;?></span></div>
<span class="board-pri">P<?php echo $content->pri ? $content->pri : '&nbsp;&nbsp;';?></span>
</div>
<div class='board-middle' style='height:<?php echo ($col == 'story' or $dataType == 'bug') ? '150px' : '100px'?>'>
<div class='board-title <?php echo ($col == 'story' or $dataType == 'bug') ? 'h-40px' : 'h-100px'?>'>
<?php
$title = ($col == 'story' or strpos($id, 'bug') !== false) ? $content->title : $content->name;
echo $col == 'story' ? mb_substr($title, 0, 22, 'utf8') : mb_substr($title, 0, 85, 'utf8')
?>
</div>
<?php if($col == 'story' or $dataType == 'bug'):?>
<?php $desc = $col == 'story' ? $storySpecs[$content->id]->spec : $content->steps;?>
<div class='board-content'><?php echo mb_substr(strip_tags($desc, "<p><br/>"), 0, 90, 'utf8')?></div>
<?php endif;?>
</div>
<div class="board-footer <?php echo $col == 'story' ? 'story' : 'task'?>">
<?php if($col == 'story'):?>
<table class='stage'>
<tr>
<td style='padding-left:15px;'>
<table class='table-1'>
<tr>
<td><span><input type="checkbox" name="story<?php echo $content->id?>[]" value="developing" <?php echo $content->stage == 'developing' ? "checked" : ''?> id="story3developing"><label for="story3developing"> <?php echo $lang->story->stageList['developing']?></label></span></td>
<td><span><input type="checkbox" name="story<?php echo $content->id?>[]" value="developed" <?php echo $content->stage == 'developed' ? "checked" : ''?> id="story3developed"><label for="story3developed"> <?php echo $lang->story->stageList['developed']?></label></span></td>
<td><span><input type="checkbox" name="story<?php echo $content->id?>[]" value="testing" <?php echo $content->stage == 'testing' ? "checked" : ''?> id="story3testing"><label for="story3testing"> <?php echo $lang->story->stageList['testing']?></label></span><br /></td>
</tr>
<tr>
<td><span><input type="checkbox" name="story<?php echo $content->id?>[]" value="tested" <?php echo $content->stage == 'tested' ? "checked" : ''?> id="story3tested"><label for="story3tested"> <?php echo $lang->story->stageList['tested']?></label></span></td>
<td><span><input type="checkbox" name="story<?php echo $content->id?>[]" value="verified" <?php echo $content->stage == 'verified' ? "checked" : ''?> id="story3verified"><label for="story3verified"> <?php echo $lang->story->stageList['verified']?></label></span></td>
<td></td>
</tr>
</table>
</td>
</tr>
</table>
<?php elseif($dataType == 'bug'):?>
<div><?php echo $lang->bug->assignTo . ':'; echo empty($content->assignedTo) ? '' : $realnames[$content->assignedTo]->realname;?></div>
<div><?php echo $lang->printKanban->taskStatus . ':' . html::checkbox("bug$content->id", $lang->bug->statusList, $content->status);?></div>
<?php else:?>
<div><?php echo $lang->task->assign . ':'; echo empty($content->assignedTo) ? '' : $realnames[$content->assignedTo]->realname;?></div>
<div><?php echo $lang->printKanban->taskStatus . ':' . html::checkbox("task$content->id", $lang->task->statusList,$content->status);?></div>
<table class='table-1' id='record'>
<tr>
<td align='center'><?php echo $lang->task->date?></td>
<td align='center'><?php echo $today?></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td align='center'><?php echo $lang->task->leftThisTime?></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</table>
<?php endif;?>
</div>
</div>
</td>
<?php $i ++;?>
<?php if($i % 3 == 0):?>
</tr>
<?php endif;?>
<?php if($i % 12 == 0):?>
</table>
<p style='page-break-before:always'></p>
<?php endif;?>
<?php endforeach;?>
<?php endforeach;?>
<?php while($i % 12 != 0):?>
<td valign='middle' align='center'>
<div class="board" style='position:relative'>
<div class="board-header">
<div class="board-id"><?php echo $col == 'story' ? $lang->story->common : ($dataType == 'task' ? $lang->task->common : $lang->bug->common)?>#</div>
<span class="board-pri">P &nbsp; </span>
</div>
<div class='board-middle <?php echo $col == 'story' ? 'h-150px' : 'h-100px'?>'>
<div class='board-title <?php echo $col == 'story' ? 'h-40px' : 'h-100px'?>'>
</div>
<?php if($col == 'story'):?>
<?php endif;?>
</div>
<div class="board-footer <?php echo $col == 'story' ? 'story' : 'task'?>">
<?php if($col == 'story'):?>
<table class='stage'>
<tr>
<td style='padding-left:15px;'>
<table class='table-1'>
<tr>
<td><span><input type="checkbox" name="story<?php echo $i?>[]" value="developing" id="story3developing"><label for="story3developing"> <?php echo $lang->story->stageList['developing']?></label></span></td>
<td><span><input type="checkbox" name="story<?php echo $i?>[]" value="developed" id="story3developed"><label for="story3developed"> <?php echo $lang->story->stageList['developed']?></label></span></td>
<td><span><input type="checkbox" name="story<?php echo $i?>[]" value="testing" id="story3testing"><label for="story3testing"> <?php echo $lang->story->stageList['testing']?></label></span><br /></td>
</tr>
<tr>
<td><span><input type="checkbox" name="story<?php echo $i?>[]" value="tested" id="story3tested"><label for="story3tested"> <?php echo $lang->story->stageList['tested']?></label></span></td>
<td><span><input type="checkbox" name="story<?php echo $i?>[]" value="verified" id="story3verified"><label for="story3verified"> <?php echo $lang->story->stageList['verified']?></label></span></td>
<td></td>
</tr>
</table>
</td>
</tr>
</table>
<?php elseif($dataType == 'bug'):?>
<div><?php echo $lang->bug->assignTo . ':';?></div>
<div><?php echo $lang->printKanban->taskStatus . ':' . html::checkbox("bug$content->id", $lang->bug->statusList);?></div>
<?php else:?>
<div><?php echo $lang->task->assignedTo . ':';?></div>
<div><?php echo $lang->printKanban->taskStatus . ':' . html::checkbox("task$content->id", $lang->task->statusList);?></div>
<table class='table-1' id='record'>
<tr>
<td align='center'><?php echo $lang->task->date?></td>
<td align='center'><?php echo $today?></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td align='center'><?php echo $lang->task->leftThisTime?></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</table>
<?php endif;?>
</div>
</div>
</td>
<?php $i++;?>
<?php if($i % 3 == 0):?>
</tr>
<?php endif;?>
<?php if($i % 12 == 0):?>
</table>
<p style='page-break-before:always'></p>
<?php endif;?>
<?php endwhile;?>
<div class='chart-canvas'>
<img style="width: 790px; height: 400px;" id='chartImg'/>
<canvas id='burnChart' data-bezier-curve='false' data-responsive='true'></canvas>
</div>
</body>
<script language='Javascript'>
function initBurnChar()
{
var data =
{
labels: <?php echo json_encode($chartData['labels'])?>,
datasets: [
{
label: "<?php echo $lang->project->baseline;?>",
color: "#CCC",
fillColor: "rgba(0,0,0,0)",
showTooltips: false,
data: <?php echo $chartData['baseLine']?>
},
{
label: "<?php echo $lang->project->Left?>",
color: "#0033CC",
data: <?php echo $chartData['burnLine']?>
}]
};
var burnChart = $("#burnChart").lineChart(data, {animation: !($.zui.browser && $.zui.browser.ie === 8)});
}
$(function()
{
initBurnChar();
setTimeout(function()
{
var chartImg = $('#burnChart').get(0).toDataURL("image/png");
$('#chartImg').attr('src', chartImg);
$('#burnChart').hide();
<?php if(strpos($agent,'Chrome') !== false) echo "window.print();\n" ?>
}, 200);
$('#placeholder').prev('h1').width(700);
$('#placeholder').css('margin', 0);
$('#placeholder .tickLabels .xAxis .tickLabel').each(function()
{
var text = $(this).html();
if(text.indexOf('-') >= 0) $(this).html(text.substr(text.indexOf('-') + 1))
});
})
</script>
</html>
+28
View File
@@ -0,0 +1,28 @@
<?php
/**
* The kanban view file of project module of ZenTaoPMS.
*
* @copyright Copyright 2009-2012 青岛易软天创网络科技有限公司 (QingDao Nature Easy Soft Network Technology Co,LTD www.cnezsoft.com)
* @author Wang Yidong, Zhu Jinyong
* @package project
* @version $Id: kanban.html.php $
*/
?>
<?php if($_POST) die(include 'preview.html.php')?>
<?php include '../../common/view/header.lite.html.php';?>
<div id='titlebar'>
<div class='heading'>
<?php echo html::icon($lang->icons['task']);?> <strong><?php echo $lang->printKanban->common;?></strong>
</div>
</div>
<form target='_blank' method='post'>
<table class='table'>
<tr>
<td align='center' class='text-middle'>
<?php echo $lang->printKanban->content . ' : ' . html::radio('content', $lang->printKanban->typeList, 'all')?>
<?php echo html::submitButton($lang->printKanban->print)?>
</td>
</tr>
</table>
</form>
<?php include '../../common/view/footer.lite.html.php';?>
+1
View File
@@ -3,6 +3,7 @@
<?php
echo "<li id='unclosedTab'>"; common::printLink('project', 'task', "project=$projectID&type=unclosed", $lang->project->unclosed); echo '</li>' ;
echo "<li id='allTab'>"; common::printLink('project', 'task', "project=$projectID&type=all", $lang->project->allTasks); echo '</li>' ;
echo "<li id='kanbanTab'>"; common::printLink('project', 'kanban', "projectID=$projectID", $lang->project->kanban, '', '', false); echo '</li>';
if($project->type == 'sprint' or $project->type == 'waterfall') print "<li id='burnTab'>" and common::printLink('project', 'burn', "project=$projectID", $lang->project->burn); print '</li>' ;
echo "<li id='assignedtomeTab'>"; common::printLink('project', 'task', "project=$projectID&type=assignedtome", $lang->project->assignedToMe); echo '</li>' ;