* finish task #2580.
This commit is contained in:
@@ -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
@@ -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'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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}
|
||||
@@ -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');
|
||||
});
|
||||
});
|
||||
@@ -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';
|
||||
|
||||
@@ -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'] = '增量';
|
||||
|
||||
@@ -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§ion=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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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';?>
|
||||
@@ -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 : ' ';?></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 </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>
|
||||
@@ -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';?>
|
||||
@@ -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>' ;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user