Merge branch 'sprint/215_liumengyi_60476' into 'master'

Sprint/215 liumengyi 60476

See merge request easycorp/zentaopms!4485
This commit is contained in:
王怡栋
2022-07-12 09:20:31 +00:00
12 changed files with 152 additions and 23 deletions

View File

@@ -2476,11 +2476,12 @@ class execution extends control
unset($this->lang->kanban->type['all']);
}
$kanbanGroup = $this->kanban->getExecutionKanban($executionID, $browseType, $groupBy);
if($groupBy == 'story' and $browseType == 'task' and !isset($this->lang->kanban->orderList[$orderBy])) $orderBy = 'pri_asc';
$kanbanGroup = $this->kanban->getExecutionKanban($executionID, $browseType, $groupBy, '', $orderBy);
if(empty($kanbanGroup))
{
$this->kanban->createExecutionLane($executionID, $browseType, $groupBy);
$kanbanGroup = $this->kanban->getExecutionKanban($executionID, $browseType, $groupBy);
$kanbanGroup = $this->kanban->getExecutionKanban($executionID, $browseType, $groupBy, '', $orderBy);
}
/* Determines whether an object is editable. */
@@ -4110,11 +4111,15 @@ class execution extends control
* @param string $groupBy
* @param string $from execution|RD
* @param string $searchValue
* @param string $orderBy
* @access public
* @return array
*/
public function ajaxUpdateKanban($executionID = 0, $enterTime = '', $browseType = '', $groupBy = '', $from = 'execution', $searchValue = '')
public function ajaxUpdateKanban($executionID = 0, $enterTime = '', $browseType = '', $groupBy = '', $from = 'execution', $searchValue = '', $orderBy = 'id_asc')
{
$this->loadModel('kanban');
if($groupBy == 'story' and $browseType == 'task' and !isset($this->lang->kanban->orderList[$orderBy])) $orderBy = 'pri_asc';
$enterTime = date('Y-m-d H:i:s', $enterTime);
$lastEditedTime = $this->dao->select("max(lastEditedTime) as lastEditedTime")->from(TABLE_KANBANLANE)->where('execution')->eq($executionID)->fetch('lastEditedTime');
@@ -4122,7 +4127,7 @@ class execution extends control
if($from == 'RD') $this->session->set('rdSearchValue', $searchValue);
if(strtotime($lastEditedTime) < 0 or $lastEditedTime > $enterTime or $groupBy != 'default' or !empty($searchValue))
{
$kanbanGroup = $from == 'execution' ? $this->loadModel('kanban')->getExecutionKanban($executionID, $browseType, $groupBy, $searchValue) : $this->loadModel('kanban')->getRDKanban($executionID, $browseType, 'id_asc', 0, $groupBy, $searchValue);
$kanbanGroup = $from == 'execution' ? $this->kanban->getExecutionKanban($executionID, $browseType, $groupBy, $searchValue, $orderBy) : $this->kanban->getRDKanban($executionID, $browseType, $orderBy, 0, $groupBy, $searchValue);
return print(json_encode($kanbanGroup));
}
}

View File

@@ -36,6 +36,7 @@
.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: 85px !important;}
.region .kanban-header-col > .title > span.storyColumn {max-width: 100% !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;}

View File

@@ -29,6 +29,7 @@
.kanban-affixed .kanban-header-col > .title > .text,
.kanban-affixed .kanban-header-col > .title > .count {color: #fff!important;}
.kanban-header-col > .title > .text {max-width: 110px !important;}
.kanban-header-col > .title > .storyColumn.text {max-width: 100% !important;}
#kanbanContainer {margin: 0;}
#kanbanContainer > .panel-body {overflow: auto;}

View File

@@ -547,6 +547,15 @@ function renderEstStarted(estStarted, status)
*/
function renderStoryItem(item, $item, col)
{
if(groupBy == 'story' && item.id == '0')
{
$('.storyCell').css('width', '100%');
$parentItem = $item[0] == undefined ? $('.storyCell') : $item.parent();
$parentItem.addClass('text-center storyCell');
$parentItem.css('line-height', ($parentItem.parent().height() - 20) + 'px');
$item.replaceWith('<span class="text-muted">' + item.title + '</span>');
return;
}
var scaleSize = window.kanbanScaleSize;
if(+$item.attr('data-scale-size') !== scaleSize) $item.empty().attr('data-scale-size', scaleSize);
@@ -749,6 +758,14 @@ addColumnRenderer('task', renderTaskItem);
*/
function renderCount($count, count, column)
{
if(groupBy == 'story' && column.type == 'story')
{
$count.prev().addClass('storyColumn');
$count.prev().parent().append('<span class="caret changeOrderBy"></span>');
$count.remove();
return;
}
/* Render WIP. */
var limit = !column.limit || column.limit == '-1' ? '<i class="icon icon-md icon-infinite"></i>' : column.limit;
if($count.parent().find('.limit').length)
@@ -793,6 +810,9 @@ function tips()
*/
function renderHeaderCol($column, column, $header, kanbanData)
{
if(groupBy == 'story' && column.type == 'story') return;
console.log(groupBy);
console.log(column.type);
/* Render group header. */
var privs = kanbanData.actions;
var columnPrivs = kanbanData.columns[0].actions;
@@ -850,6 +870,11 @@ function renderHeaderCol($column, column, $header, kanbanData)
*/
function renderLaneName($lane, lane, $kanban, columns, kanban)
{
if(groupBy == 'story')
{
$lane.hide();
return;
}
if(groupBy != 'default') return;
var canEditLaneColor = lane.actions.includes('editLaneColor');
var canEditLaneName = lane.actions.includes('editLaneName');
@@ -1375,7 +1400,7 @@ function handleSortCards(event)
}
else
{
$.get(createLink('execution', 'ajaxUpdateKanban', "executionID=" + executionID + "&entertime=0&browseType=" + browseType + "&groupBy=" + groupBy + '&from=RD'), function(data)
$.get(createLink('execution', 'ajaxUpdateKanban', "executionID=" + executionID + "&entertime=0&browseType=" + browseType + "&groupBy=" + groupBy + '&from=RD' + '&serachValue=' + rdSearchValue + '&orderBy=' + orderBy), function(data)
{
if(data && lastUpdateData !== data)
{
@@ -1567,6 +1592,12 @@ $(function()
$('.color0 .cardcolor').css('border', '1px solid #fff');
});
$(document).on('click', '#kanban span.caret.changeOrderBy', function(event)
{
orderBy = orderBy == 'pri_desc' ? 'pri_asc' : 'pri_desc';
searchCards(rdSearchValue);
})
/* Init sortable */
var sortType = '';
var $cards = null;
@@ -1694,7 +1725,7 @@ $(function()
{
if(rdSearchValue == '')
{
$.get(createLink('execution', 'ajaxUpdateKanban', "executionID=" + executionID + "&entertime=" + entertime + "&browseType=" + browseType + "&groupBy=" + groupBy + '&from=RD&searchValue=' + rdSearchValue), function(data)
$.get(createLink('execution', 'ajaxUpdateKanban', "executionID=" + executionID + "&entertime=" + entertime + "&browseType=" + browseType + "&groupBy=" + groupBy + '&from=RD&searchValue=' + rdSearchValue + '&orderBy=' + orderBy), function(data)
{
if(lastUpdateData == '') lastUpdateData = data;
if(data && lastUpdateData !== data)
@@ -1800,7 +1831,7 @@ function toggleRDSearchBox()
function searchCards(value)
{
rdSearchValue = value;
$.get(createLink('execution', 'ajaxUpdateKanban', "executionID=" + executionID + "&entertime=0&browseType=" + browseType + "&groupBy=" + groupBy + '&from=RD&searchValue=' + rdSearchValue), function(data)
$.get(createLink('execution', 'ajaxUpdateKanban', "executionID=" + executionID + "&entertime=0&browseType=" + browseType + "&groupBy=" + groupBy + '&from=RD&searchValue=' + rdSearchValue + '&orderBy=' + orderBy), function(data)
{
lastUpdateData = data;
kanbanData = $.parseJSON(data);

View File

@@ -128,6 +128,15 @@ function renderEstStarted(estStarted, status)
*/
function renderStoryItem(item, $item, col)
{
if(groupBy == 'story' && item.id == '0')
{
$('.storyCell').css('width', '100%');
$parentItem = $item[0] == undefined ? $('.storyCell') : $item.parent();
$parentItem.addClass('text-center storyCell');
$parentItem.css('line-height', ($parentItem.parent().height() - 20) + 'px');
$item.replaceWith('<span class="text-muted">' + item.title + '</span>');
return;
}
var scaleSize = window.kanbanScaleSize;
if($item.attr('data-scale-size') !== scaleSize) $item.empty().attr('data-scale-size', scaleSize);
@@ -330,6 +339,14 @@ addColumnRenderer('task', renderTaskItem);
*/
function renderColumnCount($count, count, col)
{
if(groupBy == 'story' && col.type == 'story')
{
$count.prev().addClass('storyColumn');
$count.prev().parent().append('<span class="caret changeOrderBy"></span>');
$count.remove();
return;
}
var text = count + '/' + (col.limit < 0 ? '<i class="icon icon-infinite"></i>' : col.limit);
$count.html(text + '<i class="icon icon-arrow-up"></i>');
@@ -370,7 +387,7 @@ function tips()
function renderHeaderCol($col, col, $header, kanban)
{
if(col.asParent) $col = $col.children('.kanban-header-col');
if($col.children('.actions').context != undefined) return;
if($col.children('.actions').context != undefined || (groupBy == 'story' && col.type == 'story')) return;
var $actions = $('<div class="actions createButton" />');
var printStoryButton = printTaskButton = printBugButton = false;
@@ -410,6 +427,11 @@ function renderHeaderCol($col, col, $header, kanban)
*/
function renderLaneName($name, lane, $kanban, columns, kanban)
{
if(groupBy == 'story')
{
$name.hide();
return;
}
if(lane.id != 'story' && lane.id != 'task' && lane.id != 'bug') return false;
if(!$name.children('.actions').length && (priv.canSetLane || priv.canMoveLane))
{
@@ -1167,7 +1189,7 @@ function handleSortCards(event)
}
else
{
$.get(createLink('execution', 'ajaxUpdateKanban', "executionID=" + executionID + "&entertime=0&browseType=" + browseType + "&groupBy=" + groupBy + '&from=execution'), function(data)
$.get(createLink('execution', 'ajaxUpdateKanban', "executionID=" + executionID + "&entertime=0&browseType=" + browseType + "&groupBy=" + groupBy + '&from=execution' + '&searchValue=' + searchValue + '&orderBy=' + orderBy), function(data)
{
if(data && lastUpdateData !== data)
{
@@ -1252,6 +1274,12 @@ $(function()
event.preventDefault();
});
$(document).on('click', '#kanbans span.caret.changeOrderBy', function(event)
{
orderBy = orderBy == 'pri_desc' ? 'pri_asc' : 'pri_desc';
searchCards(searchValue);
})
/* Init contextmenu */
$('#kanbans').on('click', '[data-contextmenu]', function(event)
{
@@ -1311,7 +1339,7 @@ $(function()
lastUpdateData = '';
setInterval(function()
{
$.get(createLink('execution', 'ajaxUpdateKanban', "executionID=" + executionID + "&entertime=" + entertime + "&browseType=" + browseType + "&groupBy=" + groupBy + '&from=execution&searchValue=' + searchValue), function(data)
$.get(createLink('execution', 'ajaxUpdateKanban', "executionID=" + executionID + "&entertime=" + entertime + "&browseType=" + browseType + "&groupBy=" + groupBy + '&from=execution&searchValue=' + searchValue + '&orderBy' + orderBy), function(data)
{
if(lastUpdateData == '') lastUpdateData = data;
if(data && lastUpdateData !== data)
@@ -1447,7 +1475,7 @@ function toggleSearchBox()
function searchCards(value)
{
searchValue = value;
$.get(createLink('execution', 'ajaxUpdateKanban', "executionID=" + executionID + "&entertime=0&browseType=" + browseType + "&groupBy=" + groupBy + '&from=execution&searchValue=' + value), function(data)
$.get(createLink('execution', 'ajaxUpdateKanban', "executionID=" + executionID + "&entertime=0&browseType=" + browseType + "&groupBy=" + groupBy + '&from=execution&searchValue=' + value + '&orderBy=' + orderBy), function(data)
{
lastUpdateData = data;
var kanbanData = $.parseJSON(data);

View File

@@ -118,6 +118,11 @@ js::set('priv',
)
);
?>
<?php if($groupBy == 'story' and $browseType == 'task'):?>
<style>
.kanban-cols {left: 0px !important;}
</style>
<?php endif;?>
<div id='mainMenu' class='clearfix'>
<div class='btn-toolbar pull-left'>
<div class="input-control space c-type">

View File

@@ -10,6 +10,11 @@
?>
<?php include '../../common/view/header.html.php';?>
<?php include '../../common/view/kanban.html.php';?>
<?php if($groupBy == 'story' and $browseType == 'task'):?>
<style>
.kanban-cols {left: 0px !important;}
</style>
<?php endif;?>
<div id='mainMenu' class='clearfix'>
<div class='btn-toolbar pull-left'>
<div class="input-control space c-type">
@@ -220,4 +225,5 @@ js::set('priv',
<?php js::set('displayCards', $execution->displayCards);?>
<?php js::set('needLinkProducts', $lang->execution->needLinkProducts);?>
<?php js::set('hourUnit', $config->hourUnit);?>
<?php js::set('orderBy', $storyOrder);?>
<?php include '../../common/view/footer.html.php';?>

View File

@@ -215,6 +215,9 @@ $lang->kanban->error->childLimitNote = 'The sum of products in the child colu
$lang->kanban->error->importObjNotEmpty = 'Please select at least one import object.';
$lang->kanban->error->childLimitEmpty = 'Please set the WIP quantity of the sub column before operation.';
$lang->kanban->orderList['pri_asc'] = 'Story Priority Ascending';
$lang->kanban->orderList['pri_desc'] = 'Story Priority Descending';
$lang->kanban->importList = array();
$lang->kanban->importList['off'] = 'Import is not enabled';
$lang->kanban->importList['on'] = 'Enable the import function, you can only import content that you have permission to view.';

View File

@@ -215,6 +215,9 @@ $lang->kanban->error->childLimitNote = 'The sum of products in the child colu
$lang->kanban->error->importObjNotEmpty = 'Please select at least one import object.';
$lang->kanban->error->childLimitEmpty = 'Please set the WIP quantity of the sub column before operation.';
$lang->kanban->orderList['pri_asc'] = 'Story Priority Ascending';
$lang->kanban->orderList['pri_desc'] = 'Story Priority Descending';
$lang->kanban->importList = array();
$lang->kanban->importList['off'] = 'Import is not enabled';
$lang->kanban->importList['on'] = 'Enable import function (You can import content that you have permission to view as cards.)';

View File

@@ -215,6 +215,9 @@ $lang->kanban->error->childLimitNote = 'The sum of products in the child colu
$lang->kanban->error->importObjNotEmpty = 'Please select at least one import object.';
$lang->kanban->error->childLimitEmpty = 'Please set the WIP quantity of the sub column before operation.';
$lang->kanban->orderList['pri_asc'] = 'Story Priorité Ascendante';
$lang->kanban->orderList['pri_desc'] = 'Story Priorité Descendante';
$lang->kanban->importList = array();
$lang->kanban->importList['off'] = 'Import is not enabled';
$lang->kanban->importList['on'] = 'Enable the import function, you can only import content that you have permission to view.';

View File

@@ -215,6 +215,9 @@ $lang->kanban->error->childLimitNote = '子列在制品数量之和不能大
$lang->kanban->error->importObjNotEmpty = '请至少选择一个导入对象';
$lang->kanban->error->childLimitEmpty = '请先设置子列的在制品数量后再操作';
$lang->kanban->orderList['pri_asc'] = '需求优先级正序排序';
$lang->kanban->orderList['pri_desc'] = '需求优先级倒序排序';
$lang->kanban->importList = array();
$lang->kanban->importList['off'] = '不启用导入功能';
$lang->kanban->importList['on'] = '启用导入功能(可以导入自己有权查看的内容作为卡片)';

View File

@@ -872,7 +872,7 @@ class kanbanModel extends model
*/
public function getRDKanban($executionID, $browseType = 'all', $orderBy = 'id_desc', $regionID = 0, $groupBy = 'default', $searchValue = '')
{
if($groupBy != 'default' and $groupBy != '') return $this->getKanban4Group($executionID, $browseType, $groupBy, $searchValue);
if($groupBy != 'default' and $groupBy != '') return $this->getKanban4Group($executionID, $browseType, $groupBy, $searchValue, $orderBy);
$kanbanData = array();
$actions = array('sortGroup');
@@ -1393,9 +1393,9 @@ class kanbanModel extends model
* @access public
* @return array
*/
public function getExecutionKanban($executionID, $browseType = 'all', $groupBy = 'default', $searchValue = '')
public function getExecutionKanban($executionID, $browseType = 'all', $groupBy = 'default', $searchValue = '', $orderBy = 'pri_asc')
{
if($groupBy != 'default') return $this->getKanban4Group($executionID, $browseType, $groupBy, $searchValue);
if($groupBy != 'default') return $this->getKanban4Group($executionID, $browseType, $groupBy, $searchValue, $orderBy);
$lanes = $this->dao->select('*')->from(TABLE_KANBANLANE)
->where('execution')->eq($executionID)
@@ -1516,11 +1516,12 @@ class kanbanModel extends model
* @param string $browseType
* @param string $groupBy
* @param string $searchValue
* @param string $orderBy
*
* @access public
* @return array
*/
public function getKanban4Group($executionID, $browseType, $groupBy, $searchValue = '')
public function getKanban4Group($executionID, $browseType, $groupBy, $searchValue = '', $orderBy = 'pri_asc')
{
/* Get card data. */
$cardList = array();
@@ -1546,7 +1547,8 @@ class kanbanModel extends model
if($browseType == 'bug') $bugCardMenu = $this->getKanbanCardMenu($executionID, $cardList, 'bug');
if($browseType == 'task') $taskCardMenu = $this->getKanbanCardMenu($executionID, $cardList, 'task');
$lanes = $this->getLanes4Group($executionID, $browseType, $groupBy, $cardList);
if($groupBy == 'story' and $browseType == 'task' and !isset($this->lang->kanban->orderList[$orderBy])) $orderBy = 'pri_asc';
$lanes = $this->getLanes4Group($executionID, $browseType, $groupBy, $cardList, $orderBy);
if(empty($lanes)) return array();
$execution = $this->loadModel('execution')->getByID($executionID);
@@ -1593,6 +1595,33 @@ class kanbanModel extends model
$laneData['type'] = $browseType;
$laneData['defaultCardType'] = $browseType;
if($browseType == 'task' and $groupBy == 'story')
{
$columnData[0]['id'] = 0;
$columnData[0]['type'] = 'story';
$columnData[0]['name'] = zget($this->lang->kanban->orderList, $orderBy, '');
$columnData[0]['color'] = '#333';
$columnData[0]['limit'] = '-1';
$columnData[0]['laneType'] = $browseType;
$columnData[0]['asParent'] = false;
$columnData[0]['parentType'] = '';
$columnData[0]['actions'] = array();
if(empty($searchValue) or strpos($lane->name, $searchValue) !== false)
{
$cardData = array();
$cardData['id'] = $laneID;
$cardData['title'] = $lane->name;
$cardData['order'] = 1;
$cardData['pri'] = $lane->pri;
$cardData['estimate'] = '';
$cardData['assignedTo'] = $lane->assignedTo;
$cardData['deadline'] = '';
$cardData['severity'] = '';
$laneData['cards']['story'][] = $cardData;
}
}
/* Construct kanban column data. */
foreach($columns as $column)
{
@@ -1684,9 +1713,11 @@ class kanbanModel extends model
* @param string $browseType
* @param string $groupBy
* @param array $cardList
* @param string $orderBy
*
* @return array
*/
public function getLanes4Group($executionID, $browseType, $groupBy, $cardList)
public function getLanes4Group($executionID, $browseType, $groupBy, $cardList, $orderBy = 'pri_asc')
{
$lanes = array();
$groupByList = array();
@@ -1719,7 +1750,14 @@ class kanbanModel extends model
$objectPairs += $this->dao->select('id,title')->from(TABLE_STORY)
->where('deleted')->eq(0)
->andWhere('id')->in($groupByList)
->orderBy($orderBy)
->fetchPairs();
$objects = $this->dao->select('*')->from(TABLE_STORY)
->where('deleted')->eq(0)
->andWhere('id')->in($groupByList)
->orderBy($orderBy)
->fetchAll('id');
}
else
{
@@ -1747,12 +1785,14 @@ class kanbanModel extends model
if(!isset($groupByList[$objectType]) and $objectType and !in_array($objectType, array('feature', 'design'))) continue;
$lane = new stdclass();
$lane->id = $groupBy . $objectType;
$lane->type = $browseType;
$lane->execution = $executionID;
$lane->name = $objectName;
$lane->order = $order;
$lane->color = $this->config->kanban->laneColorList[$laneColor];
$lane->id = $groupBy . $objectType;
$lane->type = $browseType;
$lane->execution = $executionID;
$lane->name = $objectName;
$lane->order = $order;
$lane->color = $this->config->kanban->laneColorList[$laneColor];
$lane->pri = (isset($objects) and isset($objects[$objectType]->pri)) ? $objects[$objectType]->pri : '';
$lane->assignedTo = (isset($objects) and isset($objects[$objectType]->assignedTo)) ? $objects[$objectType]->assignedTo : '';
$order += 1;
$laneColor += 1;