Merge branch 'sprint/182_liumengyi_47334' into 'kanban'
* Finish task #47334.Add default view of professional RD Kanban. See merge request easycorp/zentaopms!1354
This commit is contained in:
@@ -1263,8 +1263,7 @@ class execution extends control
|
||||
}
|
||||
|
||||
$project = $this->project->getByID($projectID);
|
||||
|
||||
if(!empty($projectID) and $project->model == 'kanban')
|
||||
if(!empty($project) and $project->model == 'kanban')
|
||||
{
|
||||
$this->lang->execution->createExec = str_replace($this->lang->execution->common, $this->lang->execution->kanban, $this->lang->execution->createExec);
|
||||
$this->lang->execution->execName = str_replace($this->lang->execution->common, $this->lang->execution->kanban, $this->lang->execution->execName);
|
||||
@@ -1962,12 +1961,34 @@ class execution extends control
|
||||
* @param int $executionID
|
||||
* @param string $browseType
|
||||
* @param string $orderBy
|
||||
* @param string $group
|
||||
* @param string $groupBy
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function kanban($executionID, $browseType = 'all', $orderBy = 'id_asc', $group = 'all')
|
||||
public function kanban($executionID, $browseType = 'all', $orderBy = 'id_asc', $groupBy = 'all')
|
||||
{
|
||||
unset($this->lang->execution->menu);
|
||||
|
||||
$users = $this->loadModel('user')->getPairs('noletter|nodeleted');
|
||||
$kanbanData = $this->loadModel('kanban')->getRDKanban($executionID, $browseType, $orderBy, $groupBy);
|
||||
$execution = $this->execution->getById($executionID);
|
||||
|
||||
$userList = array();
|
||||
$avatarPairs = $this->dao->select('account, avatar')->from(TABLE_USER)->where('deleted')->eq(0)->fetchPairs();
|
||||
foreach($avatarPairs as $account => $avatar)
|
||||
{
|
||||
if(!$avatar) continue;
|
||||
$userList[$account]['avatar'] = $avatar;
|
||||
}
|
||||
|
||||
$this->view->title = $this->lang->kanban->view;
|
||||
$this->view->users = $users;
|
||||
$this->view->regions = $kanbanData;
|
||||
$this->view->execution = $execution;
|
||||
$this->view->userList = $userList;
|
||||
$this->view->browseType = $browseType;
|
||||
$this->view->orderBy = $orderBy;
|
||||
$this->view->groupBy = $groupBy;
|
||||
$this->display();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,58 +1,110 @@
|
||||
#main {padding-bottom: 10px;}
|
||||
#main > .container {max-width: 1960px!important; padding: 0 10px}
|
||||
#TRAction .icon {padding: 0px 6px; font-size: 14px}
|
||||
|
||||
.kanban + .kanban {margin-top: 15px}
|
||||
.kanban-card > .title {display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis}
|
||||
.kanban-card > .infos {position: relative; margin-top: 5px}
|
||||
.kanban-card > .infos > .info + .info {margin-left: 8px}
|
||||
.kanban-card > .infos > .info-id,
|
||||
.kanban-card > .infos > .info-deadline,
|
||||
.kanban-card > .infos > .info-estimate {font-size: 12px; position: relative; top: 2px}
|
||||
.kanban-card > .infos > .label-pri {min-width: 16px; line-height: 14px; height: 16px; padding: 0}
|
||||
.kanban-card > .infos > .label-severity {transform: scale(.75)}
|
||||
.kanban-card > .infos > .avatar {position: absolute; right: 0; top: 0}
|
||||
.kanban-card > .actions {position: absolute; top: 4px; right: 4px; opacity: 0;}
|
||||
.has-error .form-control {border-color: #ff4268!important;}
|
||||
.has-error .form-control:focus {box-shadow: inset 0 1px 1px rgb(0 0 0 / 8%), 0 0 6px #f5b2a5!important;}
|
||||
.has-error .form-control::placeholder {color: #ff4268!important;}
|
||||
|
||||
.label.text-red {background: #ff4268 !important; color: #ffffff;}
|
||||
|
||||
.dropdown-menu > li {padding: 0 10px;}
|
||||
.dropdown-menu > li > a > .icon {position: relative; left: -5px;}
|
||||
|
||||
#kanbanContainer {padding-bottom: 0; margin-bottom: 0;}
|
||||
#kanbanContainer.fullscreen {overflow: auto;}
|
||||
|
||||
.region {border: 1px solid #dcdcdc; background-color: #fff;}
|
||||
.region + .region {margin-top: 20px;}
|
||||
.region .region-header {padding: 10px;}
|
||||
.region .region-header span {font-size: 14px; color: #999EAB}
|
||||
.region .region-header label {color: #999; background: transparent; border: 1px solid #ddd; margin-left: 10px; margin-right: 10px}
|
||||
.region .region-header .action {float: right}
|
||||
.region .region-header .icon-double-angle-up,.icon-double-angle-down {cursor: pointer;}
|
||||
.region .kanban-header-sub-cols .kanban-header-col > .title {max-width: 100% !important;min-width:240px;}
|
||||
.region .sort .region-header {cursor: move;}
|
||||
|
||||
.region .kanban {padding: 0px 10px 10px 10px; min-height: unset; overflow: auto}
|
||||
.region .kanban .form-actions {margin: 0;}
|
||||
.region .kanban .form-actions .btn {margin-right: 10px; min-width: 50px;}
|
||||
|
||||
.region .kanban-board + .kanban-board {margin-top: 20px;}
|
||||
.region .kanban-board > .kanban-header > .kanban-group-header {padding: 8px 2px; width: 20px;}
|
||||
.region .kanban-board > .kanban-header > .kanban-group-header:hover {cursor: move;}
|
||||
.region .kanban-board.sort > .kanban-header {padding-left: 0;}
|
||||
|
||||
.region .kanban-header {border-bottom: none!important; min-width: max-content; min-width: -moz-max-content;}
|
||||
.region .kanban-header-col > .title {max-width: 80% !important;}
|
||||
.region .kanban-header-col > .title {margin: 0}
|
||||
.region .kanban-header-col > .title > span {display: inline-block; overflow: hidden; padding-right:2px; position: initial; max-width: 140px !important;}
|
||||
.region .kanban-header-col > .title > .text-grey {opacity: .5; font-weight: bold; color: #8b91a2;}
|
||||
.region .kanban-header-col > .title > .count {opacity: .5; font-weight: bold; color: #8b91a2;}
|
||||
.region .kanban-header-col > .title > .error {color: #333333; padding-left: 2px; font-size: 10px; padding-top: 1px; padding-right: 2px;}
|
||||
.kanban-affixed .kanban-header-col > .title > .text {color: #fff!important}
|
||||
.region .kanban-header-col > .actions {position: relative; right: -30px;}
|
||||
.region .kanban-header-parent-col > .actions {position: absolute; right: 0px;}
|
||||
.region .kanban-header-sub-cols .actions {position: absolute; right: 0px;}
|
||||
|
||||
.region .kanban-lane {position: relative; border-bottom: none!important; min-height: 200px !important}
|
||||
|
||||
.region .kanban-lane > .kanban-lane-name > .text {margin: auto 0; max-height: 150px; overflow: hidden; text-overflow: ellipsis}
|
||||
.region .kanban-lane > .kanban-lane-name > .actions {position: absolute; top: 0; left: 0; right: 0; opacity: 0;}
|
||||
.region .kanban-lane > .kanban-lane-name > .actions > a {display: block; width: 20px; height: 20px; line-height: 20px; text-align: center; opacity: .7; color: #fff;}
|
||||
.region .kanban-lane > .kanban-lane-name > .actions > a:hover {background-color: rgba(0,0,0,.2); opacity: 1;}
|
||||
.region .kanban-lane > .kanban-lane-name:hover > .actions {opacity: 1;}
|
||||
.region .kanban-lane.sort > .kanban-lane-name {cursor: move;}
|
||||
|
||||
.region .kanban-lane-col {max-height: unset !important; overflow: auto!important; position: relative;}
|
||||
.region .kanban-lane-col.has-scrollbar > .kanban-lane-actions {position: absolute; background-color: inherit; bottom: 0; left: 0; right: 0;}
|
||||
|
||||
.region .kanban-lane-items {overflow: auto; padding-bottom: 10px;}
|
||||
|
||||
.region .kanban-item {position: relative}
|
||||
.region .kanban-item > .kanban-card > .title:hover {color: #2272eb}
|
||||
.region .kanban-item > .kanban-card > .info {margin-top: 5px; position: relative;}
|
||||
.region .kanban-item > .kanban-card > .info > .pri {height: 14px; border-width: 1px; font-size: 12px; line-height: 12px; min-width: 14px; padding: 0 1px;}
|
||||
.region .kanban-item > .kanban-card > .info > .estimate{margin-left: 4px; color: #999; background-color: rgb(255, 255, 255); padding: 3px 0px}
|
||||
.region .kanban-item > .kanban-card > .info > .time {margin-left: 4px; font-size: 12px; background: rgb(242, 242, 242)}
|
||||
.region .kanban-item > .kanban-card > .info > .user {position: absolute; right: 0; top: -2px}
|
||||
.region .kanban-item > .kanban-card > .info > .user > .avatar {display: inline-block; width: 24px; height: 24px; line-height: 24px; margin-right: 0px; margin-left: 2px}
|
||||
.region .kanban-item > .kanban-card > .info > .user > span {display: inline-block; color: transparent; width: 2px; height: 2px; background-color: #8990a2; position: sticky; border-radius: 50%; top: 3px; margin: 0 7px;}
|
||||
.region .kanban-item > .kanban-card > .info > .user > span:before,
|
||||
.region .kanban-item > .kanban-card > .info > .user > span:after {content: ''; display: block; position: absolute; width: 2px; height: 2px; background-color: #8990a2; top: 0; border-radius: 50%}
|
||||
.region .kanban-item > .kanban-card > .info > .user > span:before {left: -4px;}
|
||||
.region .kanban-item > .kanban-card > .info > .user > span:after {right: -4px;}
|
||||
.region .kanban-item > .kanban-card > .actions > a {display: block; float: left; width: 20px; height: 20px; line-height: 20px; text-align: center; border-radius: 4px; opacity: .7;}
|
||||
.region .kanban-item > .kanban-card > .actions > a:hover {background-color: rgba(0,0,0,.075); opacity: 1;}
|
||||
.region .kanban-item:hover > .actions {opacity: 1;}
|
||||
.region .kanban-item .has-color .title,
|
||||
.region .kanban-item .has-color .actions .icon-more-v,
|
||||
.region .kanban-item .has-color .info > .label-pri,
|
||||
.region .kanban-item .has-color .info > .estimate,
|
||||
.region .kanban-item .has-color .info > .user .lable-teamSumCount,
|
||||
.region .kanban-item .has-color .info > .label-light {color: #FFFFFF;}
|
||||
.region .kanban-item .has-color .info > .label-pri {border-color: #FFFFFF;}
|
||||
.region .kanban-item .item-more {position: absolute; right: 6px; top: 0px;}
|
||||
|
||||
.kanban-card {height: auto !important; padding: 8px 14px !important}
|
||||
.kanban-card > .title {word-break: break-all;}
|
||||
.kanban-card > .info {position: relative; margin-top: 5px}
|
||||
.kanban-card > .info > .info + .info {margin-left: 8px}
|
||||
.kanban-card:hover > .actions {opacity: 1;}
|
||||
.kanban-card > .actions {position: absolute; top: 4px; right: 4px; opacity: 0;}
|
||||
.kanban-card > .actions > a {display: block; float: left; width: 20px; height: 20px; line-height: 20px; text-align: center; border-radius: 4px; opacity: .7;}
|
||||
.kanban-card > .actions > a:hover {background-color: rgba(0,0,0,.075); opacity: 1;}
|
||||
|
||||
.kanban-header-col > .actions {padding-top: 22px}
|
||||
.kanban-header-parent-col .kanban-header-col > .actions {padding-top: 6px; padding-right: 2px;}
|
||||
.kanban-header-col > .actions > a {display: block; float: left; width: 20px; height: 20px; line-height: 20px; text-align: center; border-radius: 4px; opacity: .7;}
|
||||
.kanban-header-col > .actions > a:hover {background-color: rgba(0,0,0,.075); opacity: 1;}
|
||||
.cardcolor {width:40px; height: 14px; float: left; margin-left: 5px; margin-right: 5px; margin-top: 2px; border-radius: 2px;}
|
||||
#cardcolormenu {padding:2px 2px; width: 100px;}
|
||||
|
||||
.kanban-lane-name > .actions {position: absolute; top: 0; left: 0; right: 0; opacity: 0;}
|
||||
.kanban-lane-name:hover > .actions {opacity: 1;}
|
||||
.kanban-lane-name > .actions > a {display: block; width: 20px; height: 20px; line-height: 20px; text-align: center; opacity: .7; color: #fff;}
|
||||
.kanban-lane-name > .actions > a:hover {background-color: rgba(0,0,0,.2); opacity: 1;}
|
||||
.kanban-col[data-type=ADD] {display: none;}
|
||||
.kanban-col[data-type=EMPTY] {display: none;}
|
||||
.kanban-item:hover .title {padding-right: 10px;}
|
||||
.gray .actions {display:none;}
|
||||
|
||||
.kanban-affixed .kanban-header-col > .title > .text,
|
||||
.kanban-affixed .kanban-header-col > .title > .count {color: #fff!important;}
|
||||
|
||||
#kanbanContainer {margin: 0;}
|
||||
#kanbanContainer > .panel-body {overflow: auto;}
|
||||
#kanbans .kanban {min-height: initial;}
|
||||
#kanbans .kanban-lane {min-height: 150px; margin-top: 2px;}
|
||||
#kanbans .kanban-affixed > .kanban-header {top: 100px;}
|
||||
#kanbans .kanban-card[data-scale-size="4"] {padding: 8px;}
|
||||
#kanbans .kanban-card[data-scale-size="3"] {padding: 3px 4px;}
|
||||
#kanbans .kanban-card[data-scale-size="3"] > .title {white-space: normal; max-height: 100%;}
|
||||
#kanbans .kanban-card[data-scale-size="2"] {padding: 3px 4px; overflow: hidden;}
|
||||
#kanbans .kanban-card[data-scale-size="2"] > .title {display: inline; line-height: 18px; white-space: normal; max-height: 100%; word-break: break-all;}
|
||||
#kanbans .kanban-card[data-scale-size="2"] > .infos {display: inline-block; height: 18px; vertical-align: top; margin: 0;}
|
||||
#kanbans .kanban-card[data-scale-size="2"] > .infos > .info-pri {transform: scale(.8); vertical-align: top;}
|
||||
#kanbans .kanban-card[data-scale-size="2"] > .infos > .avatar {display: inline-block; transform: scale(.8); position: relative; top: -2px; vertical-align: top; margin-right: -1px;}
|
||||
.c-type {width: 150px !important; overflow: unset;}
|
||||
.c-group {width: 190px !important; overflow: unset;}
|
||||
.c-type {margin-left: 0px !important;}
|
||||
|
||||
#kanbanScaleControl {width: 100px;}
|
||||
#kanbanScaleControl .input-group-addon {background: #fff; padding: 5px;}
|
||||
#kanbanScaleControl > .input-group-btn:first-child > .btn {border-radius: 16px 0 0 16px; border-right-color: transparent;}
|
||||
#kanbanScaleControl > .input-group-btn:last-child > .btn {border-radius: 0 16px 16px 0; border-left-color: transparent;}
|
||||
#kanbanScaleControl > .input-group-btn > .btn:hover {border-color: #b8bfce;}
|
||||
|
||||
#type_chosen .icon-kanban {padding-right: 10px; font-size: 15px;}
|
||||
|
||||
.dropdown-menu a {text-align: left;}
|
||||
.scrollbar-hover {max-height: 2000px; overflow: scroll !important;}
|
||||
.c-type {width: 150px !important; overflow: unset;}
|
||||
.c-group {width: 190px !important; overflow: unset;}
|
||||
.c-type {margin-left: 0px !important;}
|
||||
|
||||
+663
-1027
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
function changeView(view)
|
||||
{
|
||||
var link = createLink('execution', 'kanban', "executionID=" + executionID + '&type=' + view);
|
||||
var link = createLink('execution', 'taskKanban', "executionID=" + executionID + '&type=' + view);
|
||||
location.href = link;
|
||||
}
|
||||
|
||||
@@ -597,7 +597,7 @@ function changeCardColType(card, fromColType, toColType, kanbanID)
|
||||
}
|
||||
else if(toColType == 'fixed')
|
||||
{
|
||||
if(fromColType == 'fixing' || fromColType == 'confirmed' || fromColType == 'unconfirmed')
|
||||
if(fromColType == 'fixing' || fromColType == 'confirmed' || fromColType == 'unconfirmed')
|
||||
{
|
||||
var link = createLink('bug', 'resolve', 'bugID=' + objectID, '', true);
|
||||
showIframe = true;
|
||||
@@ -1055,7 +1055,7 @@ $('#type').change(function()
|
||||
})
|
||||
}
|
||||
|
||||
var link = createLink('execution', 'kanban', "executionID=" + executionID + '&type=' + type);
|
||||
var link = createLink('execution', 'taskKanban', "executionID=" + executionID + '&type=' + type);
|
||||
location.href = link;
|
||||
});
|
||||
|
||||
@@ -1065,6 +1065,6 @@ $('.c-group').change(function()
|
||||
|
||||
var type = $('#type').val();
|
||||
var group = $('#group').val();
|
||||
var link = createLink('execution', 'kanban', 'executionID=' + executionID + '&type=' + type + '&orderBy=order_asc' + '&groupBy=' + group);
|
||||
var link = createLink('execution', 'taskKanban', 'executionID=' + executionID + '&type=' + type + '&orderBy=order_asc' + '&groupBy=' + group);
|
||||
location.href = link;
|
||||
});
|
||||
|
||||
@@ -2480,7 +2480,7 @@ class executionModel extends model
|
||||
|
||||
/**
|
||||
* Get members by execution id list.
|
||||
*
|
||||
*
|
||||
* @param array $executionIdList
|
||||
* @access public
|
||||
* @return void
|
||||
|
||||
@@ -1,15 +1,42 @@
|
||||
<?php
|
||||
/**
|
||||
* The kanban view file of execution module of ZenTaoPMS.
|
||||
* The kanban file of execution module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2012 青岛易软天创网络科技有限公司 (QingDao Nature Easy Soft Network Technology Co,LTD www.cnezsoft.com)
|
||||
* @author Wang Yidong, Zhu Jinyong
|
||||
* @copyright Copyright 2009-2022 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
|
||||
* @license ZPL (http://zpl.pub/page/zplv12.html)
|
||||
* @author Mengyi Liu<liumengyi@easycorp.ltd>
|
||||
* @package execution
|
||||
* @version $Id: kanban.html.php $
|
||||
* @version $Id: kanban.html.php 935 2022-01-11 16:49:24Z $
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
?>
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<?php include '../../common/view/kanban.html.php';?>
|
||||
|
||||
<?php
|
||||
$laneCount = 0;
|
||||
foreach($regions as $region) $laneCount += $region->laneCount;
|
||||
|
||||
js::set('regions', $regions);
|
||||
js::set('execution', $execution);
|
||||
js::set('kanbanLang', $lang->kanban);
|
||||
js::set('kanbanlaneLang', $lang->kanbanlane);
|
||||
js::set('kanbancolumnLang', $lang->kanbancolumn);
|
||||
js::set('kanbancardLang', $lang->kanbancard);
|
||||
js::set('executionID', $execution->id);
|
||||
js::set('laneCount', $laneCount);
|
||||
js::set('userList', $userList);
|
||||
js::set('noAssigned', $lang->kanbancard->noAssigned);
|
||||
js::set('users', $users);
|
||||
js::set('colorListLang', $lang->kanbancard->colorList);
|
||||
js::set('colorList', $this->config->kanban->cardColorList);
|
||||
|
||||
$canSortRegion = commonModel::hasPriv('kanban', 'sortRegion') && count($regions) > 1;
|
||||
$canEditRegion = commonModel::hasPriv('kanban', 'editRegion');
|
||||
$canDeleteRegion = commonModel::hasPriv('kanban', 'deleteRegion');
|
||||
$canCreateLane = commonModel::hasPriv('kanban', 'createLane');
|
||||
?>
|
||||
|
||||
<div id='mainMenu' class='clearfix'>
|
||||
<div class='btn-toolbar pull-left'>
|
||||
<div class="input-control space c-type">
|
||||
@@ -32,144 +59,33 @@
|
||||
<button class='btn btn-icon' type='button' data-type='+'><i class='icon icon-plus-solid-circle text-muted'></i></button>
|
||||
</span>
|
||||
</div>
|
||||
<div class='btn-toolbar pull-right'>
|
||||
<?php
|
||||
$link = $this->createLink('task', 'export', "execution=$executionID&orderBy=$orderBy&type=kanban");
|
||||
if(common::hasPriv('task', 'export')) echo html::a($link, "<i class='icon-export muted'></i> " . $lang->export, '', "class='btn btn-link iframe export' data-width='700'");
|
||||
?>
|
||||
<?php if($canBeChanged):?>
|
||||
<div class='btn-group' style="margin-right: 0">
|
||||
<button type='button' class='btn btn-link dropdown-toggle' data-toggle='dropdown' id='importAction'>
|
||||
<i class='icon-import muted'></i> <?php echo $lang->import ?>
|
||||
<span class='caret'></span>
|
||||
</button>
|
||||
<ul class='dropdown-menu' id='importActionMenu'>
|
||||
<?php
|
||||
$misc = common::hasPriv('execution', 'importTask') ? '' : "class=disabled";
|
||||
$link = common::hasPriv('execution', 'importTask') ? $this->createLink('execution', 'importTask', "execution=$execution->id") : '#';
|
||||
echo "<li $misc>" . html::a($link, $lang->execution->importTask, '', $misc) . "</li>";
|
||||
|
||||
$misc = common::hasPriv('execution', 'importBug') ? '' : "class=disabled";
|
||||
$link = common::hasPriv('execution', 'importBug') ? $this->createLink('execution', 'importBug', "execution=$execution->id") : '#';
|
||||
echo "<li $misc>" . html::a($link, $lang->execution->importBug, '', $misc) . "</li>";
|
||||
?>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
echo "<div class='btn-group menu-actions'>";
|
||||
echo html::a('javascript:;', "<i class='icon icon-ellipsis-v'></i>", '', "data-toggle='dropdown' class='btn btn-link'");
|
||||
echo "<ul class='dropdown-menu pull-right'>";
|
||||
if(common::hasPriv('execution', 'printKanban')) echo '<li>' .html::a($this->createLink('execution', 'printKanban', "executionID=$executionID"), "<i class='icon-printer muted'></i> " . $lang->execution->printKanban, '', "class='iframe btn btn-link' id='printKanban' title='{$lang->execution->printKanban}' data-width='500'") . '</li>';
|
||||
echo '<li>' .html::a('javascript:fullScreen()', "<i class='icon-fullscreen muted'></i> " . $lang->execution->fullScreen, '', "class='btn btn-link' title='{$lang->execution->fullScreen}' data-width='500'") . '</li>';
|
||||
echo '</ul></div>';
|
||||
?>
|
||||
<?php
|
||||
$checkObject = new stdclass();
|
||||
$checkObject->execution = $executionID;
|
||||
$canCreateTask = common::hasPriv('task', 'create', $checkObject);
|
||||
$canBatchCreateTask = common::hasPriv('task', 'batchCreate', $checkObject);
|
||||
$canCreateBug = common::hasPriv('bug', 'create');
|
||||
$canBatchCreateBug = common::hasPriv('bug', 'batchCreate');
|
||||
$canCreateStory = ($productID and common::hasPriv('story', 'create'));
|
||||
$canBatchCreateStory = ($productID and common::hasPriv('story', 'batchCreate'));
|
||||
$canLinkStory = ($productID and common::hasPriv('execution', 'linkStory'));
|
||||
$canLinkStoryByPlane = ($productID and common::hasPriv('execution', 'importplanstories'));
|
||||
$hasStoryButton = ($canCreateStory or $canBatchCreateStory or $canLinkStory or $canLinkStoryByPlane);
|
||||
$hasTaskButton = ($canCreateTask or $canBatchCreateTask);
|
||||
$hasBugButton = ($canCreateBug or $canBatchCreateBug);
|
||||
?>
|
||||
<?php if($canCreateTask or $canBatchCreateTask or $canCreateBug or $canBatchCreateBug or $canCreateStory or $canBatchCreateStory or $canLinkStory or $canLinkStoryByPlane):?>
|
||||
<div class='dropdown' id='createDropdown'>
|
||||
<button class='btn btn-primary' type='button' data-toggle='dropdown'><i class='icon icon-plus'></i> <?php echo $this->lang->create;?> <span class='caret'></span></button>
|
||||
<ul class='dropdown-menu pull-right'>
|
||||
<?php if($canCreateStory) echo '<li>' . html::a(helper::createLink('story', 'create', "productID=$productID&branch=0&moduleID=0&story=0&execution=$execution->id", '', true), $lang->execution->createStory, '', "class='iframe'") . '</li>';?>
|
||||
<?php if($canBatchCreateStory) echo '<li>' . html::a(helper::createLink('story', 'batchCreate', "productID=$productID&branch=0&moduleID=0&story=0&execution=$execution->id", '', true), $lang->execution->batchCreateStroy, '', "class='iframe' data-width='90%'") . '</li>';?>
|
||||
<?php if($canLinkStory) echo '<li>' . html::a(helper::createLink('execution', 'linkStory', "execution=$execution->id", '', true), $lang->execution->linkStory, '', "class='iframe' data-width='90%'") . '</li>';?>
|
||||
<?php if($canLinkStoryByPlane) echo '<li>' . html::a('#linkStoryByPlan', $lang->execution->linkStoryByPlan, '', 'data-toggle="modal"') . '</li>';?>
|
||||
<?php if($hasStoryButton and $hasBugButton) echo '<li class="divider"></li>';?>
|
||||
<?php if($canCreateBug) echo '<li>' . html::a(helper::createLink('bug', 'create', "productID=$productID&branch=0&extra=executionID=$execution->id", '', true), $lang->bug->create, '', "class='iframe'") . '</li>';?>
|
||||
<?php if($canBatchCreateBug) echo '<li>' . html::a(helper::createLink('bug', 'batchCreate', "productID=$productID&branch=0&executionID=$execution->id", '', true), $lang->bug->batchCreate, '', "class='iframe'") . '</li>';?>
|
||||
<?php if(($hasStoryButton or $hasBugButton) and $hasTaskButton) echo '<li class="divider"></li>';?>
|
||||
<?php if($canCreateTask) echo '<li>' . html::a(helper::createLink('task', 'create', "execution=$execution->id", '', true), $lang->task->create, '', "class='iframe'") . '</li>';?>
|
||||
<?php if($canBatchCreateTask) echo '<li>' . html::a(helper::createLink('task', 'batchCreate', "execution=$execution->id", '', true), $lang->execution->batchCreateTask, '', "class='iframe'") . '</li>';?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
<?php else:?>
|
||||
<?php $canCreateTask = $canBatchCreateTask = $canCreateBug = $canBatchCreateBug = $canCreateStory = $canBatchCreateStory = $canLinkStory = $canLinkStoryByPlane = false;?>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class='panel' id='kanbanContainer'>
|
||||
<div class='panel-body'>
|
||||
<div id='kanbans'></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="linkStoryByPlan">
|
||||
<div class="modal-dialog mw-500px">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="icon icon-close"></i></button>
|
||||
<h4 class="modal-title"><?php echo $lang->execution->linkStoryByPlan;?></h4><?php echo '(' . $lang->execution->linkStoryByPlanTips . ')';?>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class='input-group'>
|
||||
<?php echo html::select('plan', $allPlans, '', "class='form-control chosen' id='plan'");?>
|
||||
<span class='input-group-btn'><?php echo html::commonButton($lang->execution->linkStory, "id='toStoryButton'", 'btn btn-primary');?></span>
|
||||
<div id="kanban" data-id='<?php echo $execution->id;?>'>
|
||||
<?php foreach($regions as $region):?>
|
||||
<div class="region<?php if($canSortRegion) echo ' sort';?>" data-id="<?php echo $region->id;?>">
|
||||
<div class="region-header dropdown">
|
||||
<span class="strong"><?php echo $region->name;?></span>
|
||||
<label class="label label-region"><?php echo $this->lang->kanbanlane->common . ' ' . $region->laneCount;?></label>
|
||||
<span><i class="icon icon-chevron-double-up" data-id="<?php echo $region->id;?>"></i></span>
|
||||
<span class='regionActions'>
|
||||
<?php if($canEditRegion || $canCreateLane || $canDeleteRegion):?>
|
||||
<button class="btn btn-link action" type="button" data-toggle="dropdown"><i class="icon icon-ellipsis-v"></i></button>
|
||||
<ul class="dropdown-menu pull-right">
|
||||
<?php if($canEditRegion) echo '<li>' . html::a(helper::createLink('kanban', 'editRegion', "regionID={$region->id}", '', 1), '<i class="icon icon-edit"></i>' . $this->lang->kanban->editRegion, '', 'class="iframe" data-toggle="modal" data-width="600px"') . '</li>';?>
|
||||
<?php if($canCreateLane) echo '<li>' . html::a(helper::createLink('kanban', 'createLane', "executionID={$execution->id}®ionID={$region->id}", '', 1), '<i class="icon icon-plus"></i>' . $this->lang->kanban->createLane, '', "class='iframe'") . '</li>';?>
|
||||
<?php if($canDeleteRegion and count($regions) > 1) echo '<li>' . html::a(helper::createLink('kanban', 'deleteRegion', "regionID={$region->id}"), '<i class="icon icon-trash"></i>' . $this->lang->kanban->deleteRegion, "hiddenwin") . '</li>';?>
|
||||
</ul>
|
||||
<?php endif;?>
|
||||
</span>
|
||||
</div>
|
||||
<div id='kanban<?php echo $region->id;?>' data-id='<?php echo $region->id;?>' class='kanban'></div>
|
||||
</div>
|
||||
<?php endforeach;?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php js::set('executionID', $executionID);?>
|
||||
<?php js::set('productID', $productID);?>
|
||||
<?php js::set('kanbanGroup', $kanbanGroup);?>
|
||||
<?php js::set('kanbanList', array_keys($kanbanGroup));?>
|
||||
<?php js::set('browseType', $browseType);?>
|
||||
<?php js::set('groupBy', $groupBy);?>
|
||||
<?php
|
||||
js::set('priv',
|
||||
array(
|
||||
'canEditName' => common::hasPriv('kanban', 'setColumn'),
|
||||
'canSetWIP' => common::hasPriv('kanban', 'setWIP'),
|
||||
'canSetLane' => common::hasPriv('kanban', 'setLane'),
|
||||
'canMoveLane' => common::hasPriv('kanban', 'laneMove'),
|
||||
'canSortCards' => common::hasPriv('kanban', 'cardsSort'),
|
||||
'canCreateTask' => $canCreateTask,
|
||||
'canBatchCreateTask' => $canBatchCreateTask,
|
||||
'canCreateBug' => $canCreateBug,
|
||||
'canBatchCreateBug' => $canBatchCreateBug,
|
||||
'canCreateStory' => $canCreateStory,
|
||||
'canBatchCreateStory' => $canBatchCreateStory,
|
||||
'canLinkStory' => $canLinkStory,
|
||||
'canLinkStoryByPlane' => $canLinkStoryByPlane,
|
||||
'canAssignTask' => common::hasPriv('task', 'assignto'),
|
||||
'canAssignStory' => common::hasPriv('story', 'assignto'),
|
||||
'canFinishTask' => common::hasPriv('task', 'finish'),
|
||||
'canPauseTask' => common::hasPriv('task', 'pause'),
|
||||
'canCancelTask' => common::hasPriv('task', 'cancel'),
|
||||
'canCloseTask' => common::hasPriv('task', 'close'),
|
||||
'canActivateTask' => common::hasPriv('task', 'activate'),
|
||||
'canStartTask' => common::hasPriv('task', 'start'),
|
||||
'canAssignBug' => common::hasPriv('bug', 'assignto'),
|
||||
'canConfirmBug' => common::hasPriv('bug', 'confirmBug'),
|
||||
'canActivateBug' => common::hasPriv('bug', 'activate')
|
||||
)
|
||||
);
|
||||
?>
|
||||
<?php js::set('executionLang', $lang->execution);?>
|
||||
<?php js::set('storyLang', $lang->story);?>
|
||||
<?php js::set('taskLang', $lang->task);?>
|
||||
<?php js::set('bugLang', $lang->bug);?>
|
||||
<?php js::set('editName', $lang->execution->editName);?>
|
||||
<?php js::set('setWIP', $lang->execution->setWIP);?>
|
||||
<?php js::set('sortColumn', $lang->execution->sortColumn);?>
|
||||
<?php js::set('kanbanLang', $lang->kanban);?>
|
||||
<?php js::set('deadlineLang', $lang->task->deadlineAB);?>
|
||||
<?php js::set('noAssigned', $lang->task->noAssigned);?>
|
||||
<?php js::set('userList', $userList);?>
|
||||
<?php js::set('entertime', time());?>
|
||||
<div id='archivedCards'></div>
|
||||
<div id='archivedColumns'></div>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
echo "<li id='kanbanTab'>"; common::printLink('execution', 'kanban', "executionID=$executionID", $lang->execution->kanban); echo '</li>';
|
||||
echo "<li id='kanbanTab'>"; common::printLink('execution', 'taskKanban', "executionID=$executionID", $lang->execution->kanban); echo '</li>';
|
||||
if($execution->type == 'sprint' or $execution->type == 'waterfall')
|
||||
{
|
||||
echo "<li id='burnTab'>";
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* The kanban view file of execution module of ZenTaoPMS.
|
||||
* The task kanban view file of execution module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2012 青岛易软天创网络科技有限公司 (QingDao Nature Easy Soft Network Technology Co,LTD www.cnezsoft.com)
|
||||
* @author Wang Yidong, Zhu Jinyong
|
||||
* @package execution
|
||||
* @version $Id: kanban.html.php $
|
||||
* @version $Id: taskkanban.html.php $
|
||||
*/
|
||||
?>
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
|
||||
+156
-6
@@ -614,6 +614,62 @@ class kanbanModel extends model
|
||||
return $kanbanData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a RD kanban data.
|
||||
*
|
||||
* @param int $executionID
|
||||
* @param string $browseType all|story|task|bug
|
||||
* @param string $orderBy
|
||||
* @param string $groupBy
|
||||
*
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getRDKanban($executionID, $browseType = 'all', $orderBy = 'id_desc', $groupBy = 'all')
|
||||
{
|
||||
$kanbanData = array();
|
||||
$actions = array('sortGroup');
|
||||
$regions = $this->getRegionPairs($executionID);
|
||||
$regionIDList = array_keys($regions);
|
||||
$groupGroup = $this->getGroupGroupByRegions($regionIDList);
|
||||
$laneGroup = $this->getLaneGroupByRegions($regionIDList, $browseType);
|
||||
$columnGroup = $this->getRDColumnGroupByRegions($regionIDList, array_keys($laneGroup));
|
||||
$cardGroup = $this->getCardGroupByExecution($executionID, $browseType, $orderBy);
|
||||
|
||||
foreach($regions as $regionID => $regionName)
|
||||
{
|
||||
$region = new stdclass();
|
||||
$region->id = $regionID;
|
||||
$region->name = $regionName;
|
||||
$region->laneCount = 0;
|
||||
|
||||
$groups = zget($groupGroup, $regionID, array());
|
||||
foreach($groups as $group)
|
||||
{
|
||||
$lanes = zget($laneGroup, $group->id, array());
|
||||
if(!$lanes) continue;
|
||||
|
||||
foreach($lanes as $lane) $lane->items = array();
|
||||
|
||||
$group->columns = zget($columnGroup, $group->id, array());
|
||||
$group->lanes = $lanes;
|
||||
$group->actions = array();
|
||||
|
||||
foreach($actions as $action)
|
||||
{
|
||||
if(commonModel::hasPriv('kanban', $action)) $group->actions[] = $action;
|
||||
}
|
||||
|
||||
$region->groups[] = $group;
|
||||
$region->laneCount += count($lanes);
|
||||
}
|
||||
|
||||
$kanbanData[$regionID] = $region;
|
||||
}
|
||||
|
||||
return $kanbanData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get region by id.
|
||||
*
|
||||
@@ -660,15 +716,17 @@ class kanbanModel extends model
|
||||
/**
|
||||
* Get lane group by regions.
|
||||
*
|
||||
* @param array $regions
|
||||
* @param array $regions
|
||||
* @param string $browseType
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getLaneGroupByRegions($regions)
|
||||
public function getLaneGroupByRegions($regions, $browseType = 'all')
|
||||
{
|
||||
$laneGroup = $this->dao->select('*')->from(TABLE_KANBANLANE)
|
||||
->where('deleted')->eq('0')
|
||||
->andWhere('region')->in($regions)
|
||||
->beginIf($browseType != 'all')->andWhere('type')->eq($browseType)->fi()
|
||||
->orderBy('order')
|
||||
->fetchGroup('group');
|
||||
|
||||
@@ -781,6 +839,96 @@ class kanbanModel extends model
|
||||
return $cardGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get RD column group by regions.
|
||||
*
|
||||
* @param array $regions
|
||||
* @param array $groupIDList
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getRDColumnGroupByRegions($regions, $groupIDList = array())
|
||||
{
|
||||
$columnGroup = $this->dao->select("*")->from(TABLE_KANBANCOLUMN)
|
||||
->where('deleted')->eq('0')
|
||||
->andWhere('region')->in($regions)
|
||||
->beginIF(!empty($groupIDList))->andWhere('`group`')->in($groupIDList)->fi()
|
||||
->orderBy('id_asc')
|
||||
->fetchGroup('group');
|
||||
|
||||
$actions = array('setColumn', 'setWIP', 'deleteColumn');
|
||||
|
||||
/* Group by parent. */
|
||||
$parentColumnGroup = array();
|
||||
foreach($columnGroup as $group => $columns)
|
||||
{
|
||||
foreach($columns as $column)
|
||||
{
|
||||
$column->actions = array();
|
||||
/* Judge column action priv. */
|
||||
foreach($actions as $action)
|
||||
{
|
||||
if($this->isClickable($column, $action)) $column->actions[] = $action;
|
||||
}
|
||||
|
||||
if($column->parent > 0) continue;
|
||||
|
||||
$parentColumnGroup[$group][] = $column;
|
||||
}
|
||||
}
|
||||
|
||||
$columnData = array();
|
||||
foreach($parentColumnGroup as $group => $parentColumns)
|
||||
{
|
||||
foreach($parentColumns as $parentColumn)
|
||||
{
|
||||
$columnData[$group][] = $parentColumn;
|
||||
foreach($columnGroup[$group] as $column)
|
||||
{
|
||||
if($column->parent == $parentColumn->id)
|
||||
{
|
||||
$parentColumn->asParent = true;
|
||||
|
||||
if(strpos(',developing,developed,', $column->type) !== false) $column->parentType = 'develop';
|
||||
if(strpos(',testing,tested,', $column->type) !== false) $column->parentType = 'test';
|
||||
if(strpos(',fixing,fixed,', $column->type) !== false) $column->parentType = 'resolving';
|
||||
|
||||
$columnData[$group][] = $column;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $columnData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get card group by execution id.
|
||||
*
|
||||
* @param int $kanbanID
|
||||
* @param string $browseType all|task|bug|story
|
||||
* @param string $orderBy
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getCardGroupByExecution($executionID, $browseType = 'all', $orderBy = 'id_asc')
|
||||
{
|
||||
$cards = $this->dao->select("id, title, pri, type, severity, assignedTo, '' as estimate, deadline")->from(TABLE_BUG)
|
||||
->where('deleted')->eq(0)
|
||||
->andWhere('execution')->eq($executionID)
|
||||
->fetchAll('id');
|
||||
/*
|
||||
$cards .= $this->dao->select("id, name, pri, '' as severity, assignedTo, deadline")->from(TABLE_TASK)
|
||||
->where('deleted')->eq(0)
|
||||
->andWhere('execution')->eq($executionID)
|
||||
->fetchAll('id');
|
||||
*/
|
||||
|
||||
$planList = $this->loadModel('execution')->getById($executionID);
|
||||
|
||||
return $cards;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Kanban by execution id.
|
||||
*
|
||||
@@ -1634,10 +1782,12 @@ class kanbanModel extends model
|
||||
foreach($columnList as $type => $name)
|
||||
{
|
||||
$data = new stdClass();
|
||||
$data->lane = $laneID;
|
||||
$data->name = $name;
|
||||
$data->color = '#333';
|
||||
$data->type = $type;
|
||||
$data->lane = $laneID;
|
||||
$data->name = $name;
|
||||
$data->color = '#333';
|
||||
$data->type = $type;
|
||||
$data->group = $groupID;
|
||||
$data->region = $regionID;
|
||||
|
||||
if(strpos(',developing,developed,', $type) !== false) $data->parent = $devColumnID;
|
||||
if(strpos(',testing,tested,', $type) !== false) $data->parent = $testColumnID;
|
||||
|
||||
Reference in New Issue
Block a user