Merge branch 'sgm_dropmenu' into 'kanban'

* Code for kanban drop menu.

See merge request easycorp/zentaopms!882
This commit is contained in:
李玉春
2021-12-10 03:12:09 +00:00
5 changed files with 263 additions and 35 deletions
+27
View File
@@ -184,6 +184,9 @@ class kanban extends control
public function view($kanbanID)
{
$kanban = $this->kanban->getByID($kanbanID);
$space = $this->kanban->getSpaceByID($kanban->space);
$this->kanban->setSwitcher($kanban);
$this->kanban->setHeaderActions($kanban);
$this->view->title = $this->lang->kanban->view;
@@ -404,4 +407,28 @@ class kanban extends control
return print(html::select('team[]', $users, $list->userList, "class='form-control chosen' multiple"));
}
/**
* Ajax get kanban menu.
*
* @param int $kanbanID
* @param string $moduleName
* @param string $methodName
* @access public
* @return void
*/
public function ajaxGetKanbanMenu($kanbanID, $moduleName, $methodName)
{
$kanbanIdList = $this->kanban->getCanViewObjects();
$this->view->kanbanList = $this->dao->select('*')->from(TABLE_KANBAN)
->where('deleted')->eq('0')
->andWhere('id')->in($kanbanIdList)
->fetchGroup('space');
$this->view->kanbanID = $kanbanID;
$this->view->spaceList = $this->kanban->getSpacePairs('all');
$this->view->module = $moduleName;
$this->view->method = $methodName;
$this->display();
}
}
+3 -2
View File
@@ -46,7 +46,6 @@ $lang->kanban->closedDate = 'Closed Date';
$lang->kanban->empty = 'No Kanban';
$lang->kanban->teamSumCount = '%s people in total';
$lang->kanban->aclList['open'] = 'Open (Accessible with space view permissions)';
$lang->kanban->aclList['private'] = 'Private (For the kanban team, whitelist members and space owner only)';
@@ -110,6 +109,8 @@ $lang->kanban->noGroup = 'None';
$lang->kanban->limitExceeded = 'Limit Exceeded';
$lang->kanban->fullScreen = 'Full Screen';
$lang->kanban->setting = 'Setting';
$lang->kanban->my = 'My';
$lang->kanban->other = 'Other';
$lang->kanban->error = new stdclass();
$lang->kanban->error->mustBeInt = 'The WIPs must be positive integer.';
@@ -205,4 +206,4 @@ $lang->kanbanregion = new stdclass();
$lang->kanbanregion->name = 'Kanban Region';
$lang->kanbanregion->default = 'Default Region';
$lang->kanbancard = new stdclass();
$lang->kanbancard = new stdclass();
+2
View File
@@ -109,6 +109,8 @@ $lang->kanban->noGroup = '无';
$lang->kanban->limitExceeded = '超出在制品限制';
$lang->kanban->fullScreen = '全屏';
$lang->kanban->setting = '设置';
$lang->kanban->my = '我的看板';
$lang->kanban->other = '其他';
$lang->kanban->error = new stdclass();
$lang->kanban->error->mustBeInt = '在制品数量必须是正整数。';
+56 -33
View File
@@ -403,34 +403,6 @@ class kanbanModel extends model
return $columnData;
}
/**
* Set kanban headerActions.
*
* @param object $kanban
* @access public
* @return void
*/
public function setHeaderActions($kanban)
{
$actions = '';
$actions .= "<div class='btn-group'>";
$actions .= "<a href='javascript:fullScreen();' id='fullScreenBtn' class='btn btn-link'><i class='icon icon-fullscreen'></i> {$this->lang->kanban->fullScreen}</a>";
$actions .= "<a data-toggle='dropdown' class='btn btn-link dropdown-toggle' type='button'>" . '<i class="icon icon-cog-outline"></i> ' . $this->lang->kanban->setting . '</a>';
$actions .= "<ul id='kanbanActionMenu' class='dropdown-menu text-left'>";
if(common::hasPriv('kanban', 'createRegion')) $actions .= '<li>' . html::a(helper::createLink('kanban', 'createRegion', "kanbanID=$kanban->id", '', true), '<i class="icon icon-plus"></i>' . $this->lang->kanban->createRegion, '', "class='iframe btn btn-link'") . '</li>';
$kanbanActions = '';
if(common::hasPriv('kanban', 'edit')) $kanbanActions .= '<li>' . html::a(helper::createLink('kanban', 'edit', "kanbanID=$kanban->id", '', true), '<i class="icon icon-edit"></i>' . $this->lang->kanban->edit, '', "class='iframe btn btn-link'") . '</li>';
if(common::hasPriv('kanban', 'close')) $kanbanActions .= '<li>' . html::a(helper::createLink('kanban', 'close', "kanbanID=$kanban->id", '', true), '<i class="icon icon-off"></i>' . $this->lang->kanban->close, '', "class='iframe btn btn-link'") . '</li>';
if(common::hasPriv('kanban', 'delete')) $kanbanActions .= '<li>' . html::a(helper::createLink('kanban', 'delete', "kanbanID=$kanban->id"), '<i class="icon icon-trash"></i>' . $this->lang->kanban->delete, 'hiddenwin', "class='btn btn-link'") . '</li>';
if($kanbanActions) $actions .= "<div class='divider'></div>" . $kanbanActions;
$actions .= "</ul>";
$actions .= "</div>";
$this->lang->headerActions = $actions;
}
/**
* Get Kanban by execution id.
*
@@ -613,16 +585,17 @@ class kanbanModel extends model
/**
* Get can view objects.
*
* @param string $objectType space|kanban
* @param string $objectType kanbanspace|kanban
* @access public
* @return array
*/
public function getCanViewObjects($objectType)
public function getCanViewObjects($objectType = 'kanban')
{
$table = $this->config->objectTables[$objectType];
$objects = $this->dao->select('*')->from($table)->fetchAll('id');
$table = $this->config->objectTables[$objectType];
$objects = $this->dao->select('*')->from($table)->fetchAll('id');
$spaceOwnerPairs = $this->dao->select('id,owner')->from(TABLE_KANBANSPACE)->fetchPairs();
if($this->app->user->admin) return $objects;
if($this->app->user->admin) return array_keys($objects);
$account = $this->app->user->account;
foreach($objects as $objectID => $object)
@@ -630,6 +603,7 @@ class kanbanModel extends model
if($object->acl == 'private')
{
$aclUsers = $object->owner . $object->team . $object->whitelist;
if($objectType == 'kanban') $aclUsers .= ',' . $spaceOwnerPairs[$object->space];
if(strpos(",$aclUsers,", ",$account,") === false) unset($objects[$objectID]);
}
}
@@ -1424,6 +1398,55 @@ class kanbanModel extends model
return dao::isError();
}
/**
* Set kanban headerActions.
*
* @param object $kanban
* @access public
* @return void
*/
public function setHeaderActions($kanban)
{
$actions = '';
$actions .= "<div class='btn-group'>";
$actions .= "<a href='javascript:fullScreen();' id='fullScreenBtn' class='btn btn-link'><i class='icon icon-fullscreen'></i> {$this->lang->kanban->fullScreen}</a>";
$actions .= "<a data-toggle='dropdown' class='btn btn-link dropdown-toggle' type='button'>" . '<i class="icon icon-cog-outline"></i> ' . $this->lang->kanban->setting . '</a>';
$actions .= "<ul id='kanbanActionMenu' class='dropdown-menu text-left'>";
if(common::hasPriv('kanban', 'createRegion')) $actions .= '<li>' . html::a(helper::createLink('kanban', 'createRegion', "kanbanID=$kanban->id", '', true), '<i class="icon icon-plus"></i>' . $this->lang->kanban->createRegion, '', "class='iframe btn btn-link'") . '</li>';
$kanbanActions = '';
if(common::hasPriv('kanban', 'edit')) $kanbanActions .= '<li>' . html::a(helper::createLink('kanban', 'edit', "kanbanID=$kanban->id", '', true), '<i class="icon icon-edit"></i>' . $this->lang->kanban->edit, '', "class='iframe btn btn-link'") . '</li>';
if(common::hasPriv('kanban', 'close')) $kanbanActions .= '<li>' . html::a(helper::createLink('kanban', 'close', "kanbanID=$kanban->id", '', true), '<i class="icon icon-off"></i>' . $this->lang->kanban->close, '', "class='iframe btn btn-link'") . '</li>';
if(common::hasPriv('kanban', 'delete')) $kanbanActions .= '<li>' . html::a(helper::createLink('kanban', 'delete', "kanbanID=$kanban->id"), '<i class="icon icon-trash"></i>' . $this->lang->kanban->delete, 'hiddenwin', "class='btn btn-link'") . '</li>';
if($kanbanActions) $actions .= "<div class='divider'></div>" . $kanbanActions;
$actions .= "</ul>";
$actions .= "</div>";
$this->lang->headerActions = $actions;
}
/**
* Set switcher menu.
*
* @param object $kanban
* @access public
* @return void
*/
public function setSwitcher($kanban)
{
$currentModule = $this->app->getModuleName();
$currentMethod = $this->app->getMethodName();
$kanbanLink = helper::createLink('kanban', 'ajaxGetKanbanMenu', "objectID=$kanban->id&module=$currentModule&method=$currentMethod");
$switcher = "<div class='btn-group header-btn' id='swapper'><button data-toggle='dropdown' type='button' class='btn' id='currentItem' title='{$kanban->name}'><span class='text'>{$kanban->name}</span> <span class='caret'></span></button><div id='dropMenu' class='dropdown-menu search-list' data-ride='searchList' data-url='$kanbanLink'>";
$switcher .= '<div class="input-control search-box has-icon-left has-icon-right search-example"><input type="search" class="form-control search-input" /><label class="input-control-icon-left search-icon"><i class="icon icon-search"></i></label><a class="input-control-icon-right search-clear-btn"><i class="icon icon-close icon-sm"></i></a></div>';
$switcher .= "</div></div>";
$this->lang->switcherMenu = $switcher;
}
/**
* Reset order of lane.
*
@@ -0,0 +1,175 @@
<?php js::set('module', $module);?>
<?php js::set('method', $method);?>
<style>
#navTabs {position: sticky; top: 0; background: #fff; z-index: 950;}
#navTabs>li {padding: 0px 10px; display: inline-block}
#navTabs>li>span {display: inline-block;}
#navTabs>li>a {padding: 8px 0px; display: inline-block}
#navTabs>li.active>a {font-weight: 700; color: #0c64eb;}
#navTabs>li.active>a:before {position: absolute; right: 0; bottom: -1px; left: 0; display: block; height: 2px; content: ' '; background: #0c64eb;}
#navTabs>li.active>a, .nav-tabs>li.active>a:focus, .nav-tabs>li.active>a:hover {border: none;}
#tabContent {margin-top: 10px; z-index: 900;}
.kanbanTree ul {list-style: none; margin: 0}
.kanbanTree .kanbans>ul {padding-left: 7px;}
.kanbanTree .kanbans>ul>li>div {display: flex; flex-flow: row nowrap; justify-content: flex-start; align-items: center;}
.kanbanTree .kanbans>ul>li label {background: rgba(255,255,255,0.5); line-height: unset; color: #838a9d; border: 1px solid #d8d8d8; border-radius: 2px; padding: 1px 4px;}
.kanbanTree li a i.icon {font-size: 15px !important;}
.kanbanTree li a i.icon:before {min-width: 16px !important;}
.kanbanTree li .label {position: unset; margin-bottom: 0;}
.kanbanTree li>a, div.hide-in-search>a {display: block; padding: 2px 10px 2px 5px; overflow: hidden; line-height: 20px; text-overflow: ellipsis; white-space: nowrap; border-radius: 4px;}
.kanbanTree li>a.selected {color: #e9f2fb; background-color: #0c64eb;}
.kanbanTree .tree li>.list-toggle {line-height: 24px;}
.kanbanTree .tree li.has-list.open:before {content: unset;}
#swapper li>div.hide-in-search>a:focus, #swapper li>div.hide-in-search>a:hover {color: #838a9d; cursor: default;}
a.kanbanName:focus, a.kanbanName:hover {background: #0c64eb; color: #fff !important;}
#swapper li > a {padding-top: 4px; padding-bottom: 4px;}
#swapper li {padding-top: 0; padding-bottom: 0;}
#swapper .tree li>.list-toggle {top: -1px;}
</style>
<?php
$kanbanCounts = array();
$kanbanNames = array();
$tabActive = '';
$myKanbans = 0;
$others = 0;
$dones = 0;
foreach($kanbanList as $spaceID => $spaceKanbans)
{
$kanbanCounts[$spaceID]['myKanban'] = 0;
$kanbanCounts[$spaceID]['others'] = 0;
$kanbanCounts[$spaceID]['closed'] = 0;
foreach($spaceKanbans as $kanban)
{
if($kanban->status != 'closed' and $kanban->owner == $this->app->user->account) $kanbanCounts[$spaceID]['myKanban'] ++;
if($kanban->status != 'closed' and !($kanban->owner == $this->app->user->account)) $kanbanCounts[$spaceID]['others'] ++;
if($kanban->status == 'closed') $kanbanCounts[$spaceID]['closed'] ++;
$kanbanNames[] = $kanban->name;
}
}
$kanbansPinYin = common::convert2Pinyin($kanbanNames);
$myKanbansHtml = '<ul class="tree tree-angles" data-ride="tree">';
$normalKanbansHtml = '<ul class="tree tree-angles" data-ride="tree">';
$closedKanbansHtml = '<ul class="tree tree-angles" data-ride="tree">';
foreach($kanbanList as $spaceID => $spaceKanbans)
{
/* Add the space name before kanban. */
if(isset($spaceList[$spaceID]))
{
$spaceName = zget($spaceList, $spaceID);
if($kanbanCounts[$spaceID]['myKanban']) $myKanbansHtml .= '<li><div class="hide-in-search"><a class="text-muted" title="' . $spaceName . '">' . $spaceName . '</a> <label class="label">' . $lang->kanbanspace->common . '</label></div><ul>';
if($kanbanCounts[$spaceID]['others']) $normalKanbansHtml .= '<li><div class="hide-in-search"><a class="text-muted" title="' . $spaceName . '">' . $spaceName . '</a> <label class="label">' . $lang->kanbanspace->common . '</label></div><ul>';
if($kanbanCounts[$spaceID]['closed']) $closedKanbansHtml .= '<li><div class="hide-in-search"><a class="text-muted" title="' . $spaceName . '">' . $spaceName . '</a> <label class="label">' . $lang->kanbanspace->common . '</label></div><ul>';
}
foreach($spaceKanbans as $index => $kanban)
{
$selected = $kanban->id == $kanbanID ? 'selected' : '';
$link = helper::createLink('kanban', 'view', "kanbanID=%s", '', '', $kanban->id);
$kanbanName = '<i class="icon icon-kanban"></i> ' . $kanban->name;
if($kanban->status != 'closed' and $kanban->owner == $this->app->user->account)
{
$myKanbansHtml .= '<li>' . html::a(sprintf($link, $kanban->id), $kanbanName, '', "class='$selected kanbanName' title='{$kanban->name}' data-key='" . zget($kanbansPinYin, $kanban->name, '') . "'") . '</li>';
if($selected == 'selected') $tabActive = 'myKanban';
$myKanbans ++;
}
elseif($kanban->status != 'closed' and !($kanban->owner == $this->app->user->account))
{
$normalKanbansHtml .= '<li>' . html::a(sprintf($link, $kanban->id), $kanbanName, '', "class='$selected kanbanName' title='{$kanban->name}' data-key='" . zget($kanbansPinYin, $kanban->name, '') . "'") . '</li>';
if($selected == 'selected') $tabActive = 'other';
$others ++;
}
elseif($kanban->status == 'closed')
{
$closedKanbansHtml .= '<li>' . html::a(sprintf($link, $kanban->id), $kanbanName, '', "class='$selected kanbanName' title='$kanbanName' data-key='" . zget($kanbansPinYin, $kanban->name, '') . "'") . '</li>';
if($selected == 'selected') $tabActive = 'closed';
}
/* If the kanban is the last one in the space, print the closed label. */
if(isset($spaceList[$spaceID]) and !isset($spaceKanbans[$index + 1]))
{
if($kanbanCounts[$spaceID]['myKanban']) $myKanbansHtml .= '</ul></li>';
if($kanbanCounts[$spaceID]['others']) $normalKanbansHtml .= '</ul></li>';
if($kanbanCounts[$spaceID]['closed']) $closedKanbansHtml .= '</ul></li>';
}
}
}
$myKanbansHtml .= '</ul>';
$normalKanbansHtml .= '</ul>';
$closedKanbansHtml .= '</ul>';
?>
<div class="table-row">
<div class="table-col col-left">
<div class='list-group'>
<?php $tabActive = ($myKanbans and ($tabActive == 'closed' or $tabActive == 'myKanban')) ? 'myKanban' : 'other';?>
<?php if($myKanbans): ?>
<ul class="nav nav-tabs" id="navTabs">
<li class="<?php if($tabActive == 'myKanban') echo 'active';?>"><?php echo html::a('#myKanban', $lang->kanban->my, '', "data-toggle='tab' class='not-list-item not-clear-menu'");?><span class="label label-light label-badge"><?php echo $myKanbans;?></span><li>
<li class="<?php if($tabActive == 'other') echo 'active';?>"><?php echo html::a('#other', $lang->kanban->other, '', "data-toggle='tab' class='not-list-item not-clear-menu'")?><span class="label label-light label-badge"><?php echo $others;?></span><li>
</ul>
<?php endif;?>
<div class="tab-content kanbanTree" id="tabContent">
<div class="tab-pane kanbans <?php if($tabActive == 'myKanban') echo 'active';?>" id="myKanban">
<?php echo $myKanbansHtml;?>
</div>
<div class="tab-pane kanbans <?php if($tabActive == 'other') echo 'active';?>" id="other">
<?php echo $normalKanbansHtml;?>
</div>
</div>
</div>
<div class="col-footer">
<a class='pull-right toggle-right-col not-list-item'><?php echo $lang->kanban->closed;?><i class='icon icon-angle-right'></i></a>
</div>
</div>
<div class="table-col col-right kanbanTree">
<div class='list-group kanbans'><?php echo $closedKanbansHtml;?></div>
</div>
</div>
<script>scrollToSelected();</script>
<script>
$(function()
{
$('.nav-tabs li span').hide();
$('.nav-tabs li.active').find('span').show();
$('.nav-tabs>li a').click(function()
{
if($('#swapper input[type="search"]').val() == '')
{
$(this).siblings().show();
$(this).parent().siblings('li').find('span').hide();
}
})
$('#swapper [data-ride="tree"]').tree('expand');
$('#swapper #dropMenu .search-box').on('onSearchChange', function(event, value)
{
if(value != '')
{
$('div.hide-in-search').siblings('i').addClass('hide-in-search');
$('.nav-tabs li span').hide();
}
else
{
$('div.hide-in-search').siblings('i').removeClass('hide-in-search');
$('li.has-list div.hide-in-search').removeClass('hidden');
$('.nav-tabs li.active').find('span').show();
}
})
})
</script>