From 5e74d3bd9f18d1aef06bf3e5b90412ad51a69fa0 Mon Sep 17 00:00:00 2001 From: liumengyi Date: Wed, 8 Jun 2022 10:32:01 +0800 Subject: [PATCH 1/6] * Finish task #56454. --- module/execution/control.php | 7 ++-- module/execution/css/kanban.css | 4 ++ module/execution/js/kanban.js | 54 +++++++++++++++++++++++++-- module/execution/lang/en.php | 1 + module/execution/lang/zh-cn.php | 1 + module/execution/view/kanban.html.php | 7 ++++ module/kanban/model.php | 29 ++++++++++---- 7 files changed, 89 insertions(+), 14 deletions(-) diff --git a/module/execution/control.php b/module/execution/control.php index e89d613e03..6c0e162839 100644 --- a/module/execution/control.php +++ b/module/execution/control.php @@ -3820,17 +3820,18 @@ class execution extends control * @param string $browseType * @param string $groupBy * @param string $from execution|RD + * @param string $searchValue * @access public * @return array */ - public function ajaxUpdateKanban($executionID = 0, $enterTime = '', $browseType = '', $groupBy = '', $from = 'execution') + public function ajaxUpdateKanban($executionID = 0, $enterTime = '', $browseType = '', $groupBy = '', $from = 'execution', $searchValue = '') { $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'); - if($lastEditedTime > $enterTime or $groupBy != 'default') + if($lastEditedTime > $enterTime or $groupBy != 'default' or !empty($searchValue)) { - $kanbanGroup = $from == 'execution' ? $this->loadModel('kanban')->getExecutionKanban($executionID, $browseType, $groupBy) : $this->loadModel('kanban')->getRDKanban($executionID, $browseType, 'id_asc', 0, $groupBy); + $kanbanGroup = $from == 'execution' ? $this->loadModel('kanban')->getExecutionKanban($executionID, $browseType, $groupBy) : $this->loadModel('kanban')->getRDKanban($executionID, $browseType, 'id_asc', 0, $groupBy, $searchValue); return print(json_encode($kanbanGroup)); } } diff --git a/module/execution/css/kanban.css b/module/execution/css/kanban.css index bb8b8d5bbd..8c3aff303c 100644 --- a/module/execution/css/kanban.css +++ b/module/execution/css/kanban.css @@ -110,3 +110,7 @@ #mainMenu .divider {margin: 10px} .modal-header {padding: 15px 0;} +#rdKanbanSearch.input-group {float: left; width: min-content;} +#rdKanbanSearchInput {width: 150px;} +#rdSearchBox {display: none; width: 150px;} +.btn-link.querybox-toggle {background-color: rgba(0,0,0,0);} diff --git a/module/execution/js/kanban.js b/module/execution/js/kanban.js index 0ae0cece62..f9ea3db8ab 100644 --- a/module/execution/js/kanban.js +++ b/module/execution/js/kanban.js @@ -478,7 +478,9 @@ function renderStoryItem(item, $item, col) .attr('href', $.createLink('story', 'view', 'storyID=' + item.id + '&version=0¶m=' + execution.id, '', true)).attr('data-toggle', 'modal').attr('data-width', '95%'); $title.appendTo($item); } - $title.attr('title', item.title).find('.text').text(item.title); + var reg = new RegExp('((' + rdSearchValue + ')+)', "g"); + var title = rdSearchValue != '' ? "" + item.title.replace(reg, "$1") + "": "" + item.title + ""; + $title.attr('title', item.title).find('.text').replaceWith(title); } if(scaleSize <= 2) @@ -542,7 +544,9 @@ function renderBugItem(item, $item, col) .attr('href', $.createLink('bug', 'view', 'bugID=' + item.id, '', true)).attr('data-toggle', 'modal').attr('data-width', '80%'); $title.appendTo($item); } - $title.attr('title', item.title).find('.text').text(item.title); + var reg = new RegExp('((' + rdSearchValue + ')+)', "g"); + var title = rdSearchValue != '' ? "" + item.title.replace(reg, "$1") + "": "" + item.title + ""; + $title.attr('title', item.title).find('.text').replaceWith(title); } if(scaleSize <= 2) @@ -608,7 +612,9 @@ function renderTaskItem(item, $item, col) .attr('href', $.createLink('task', 'view', 'taskID=' + item.id, '', true)).attr('data-toggle', 'modal').attr('data-width', '80%'); $title.appendTo($item); } - $title.attr('title', item.name).find('.text').text(item.name); + var reg = new RegExp('((' + rdSearchValue + ')+)', "g"); + var name = rdSearchValue != '' ? "" + item.name.replace(reg, "$1") + "": "" + item.name + ""; + $title.attr('title', item.name).find('.text').replaceWith(name); } if(scaleSize <= 2) @@ -792,6 +798,10 @@ function updateRegion(regionID, regionData = []) if(!regionData) regionData = regions[regionID]; var data = groupBy == 'default' ? regionData.groups : regionData; + if(data == null) + { + $("div[data-id^=" + regionID + "].region").hide(); + } $region.data('zui.kanban').render(data); resetRegionHeight('open'); return true; @@ -1504,7 +1514,7 @@ $(function() var lastUpdateData; setInterval(function() { - $.get(createLink('execution', 'ajaxUpdateKanban', "executionID=" + executionID + "&entertime=" + entertime + "&browseType=" + browseType + "&groupBy=" + groupBy + '&from=RD'), function(data) + $.get(createLink('execution', 'ajaxUpdateKanban', "executionID=" + executionID + "&entertime=" + entertime + "&browseType=" + browseType + "&groupBy=" + groupBy + '&from=RD&searchValue' + rdSearchValue), function(data) { if(data && lastUpdateData !== data) { @@ -1580,3 +1590,39 @@ function resetRegionHeight(fold) $('.region').css('height', regionHeaderHeight); } } + +/** + * Toggle RDSearchBox. + * + * @access public + * @return void + */ +function toggleRDSearchBox() +{ + $('#rdSearchBox').fadeToggle(); + rdSearchValue = ''; + if($('#rdSearchBox').css('display') == 'block') + { + $(".querybox-toggle").css("color", "#0c64eb"); + } + else + { + $(".querybox-toggle").css("color", ""); + } +} + +function searchCards(value) +{ + rdSearchValue = value; + $.get(createLink('execution', 'ajaxUpdateKanban', "executionID=" + executionID + "&entertime=" + entertime + "&browseType=" + browseType + "&groupBy=" + groupBy + '&from=RD&searchValue=' + value), function(data) + { + kanbanData = $.parseJSON(data); + $('#kanban').children('.region').children("div[id^='kanban']").each(function() + { + var regionID = $(this).attr('data-id'); + if(kanbanData != null) data = groupBy == 'default' ? kanbanData[regionID] : kanbanData[groupBy]; + + updateRegion(regionID, data); + }); + }); +} diff --git a/module/execution/lang/en.php b/module/execution/lang/en.php index e7f31a3056..eb1f5940f1 100644 --- a/module/execution/lang/en.php +++ b/module/execution/lang/en.php @@ -396,6 +396,7 @@ $lang->execution->projectNotEmpty = 'Project cannot be empty.'; $lang->execution->confirmStoryToTask = $lang->SRCommon . '%s are converted to tasks in the current. Do you want to convert them anyways?'; $lang->execution->ge = "『%s』should be >= actual begin『%s』."; $lang->execution->storyDragError = "The {$lang->SRCommon} is still a draft or has been changed, please drag it after the review"; +$lang->execution->pleaseInput = "Enter"; /* Statistics. */ $lang->execution->charts = new stdclass(); diff --git a/module/execution/lang/zh-cn.php b/module/execution/lang/zh-cn.php index 7722eb13d6..35d6b21b57 100644 --- a/module/execution/lang/zh-cn.php +++ b/module/execution/lang/zh-cn.php @@ -396,6 +396,7 @@ $lang->execution->projectNotEmpty = '所属项目不能为空。'; $lang->execution->confirmStoryToTask = '%s' . $lang->SRCommon . '已经在当前' . $lang->execution->common . '中转了任务,请确认是否重复转任务。'; $lang->execution->ge = "『%s』应当不小于实际开始时间『%s』。"; $lang->execution->storyDragError = "该{$lang->SRCommon}还是草稿或已变更状态,请评审通过后再拖动"; +$lang->execution->pleaseInput = "请输入"; /* 统计。*/ $lang->execution->charts = new stdclass(); diff --git a/module/execution/view/kanban.html.php b/module/execution/view/kanban.html.php index 81d1ddb848..36f97dfc73 100644 --- a/module/execution/view/kanban.html.php +++ b/module/execution/view/kanban.html.php @@ -52,6 +52,7 @@ js::set('vision', $this->config->vision); js::set('productCount', count($productNames)); js::set('executionID', $execution->id); js::set('reviewStoryParis', $reviewStoryParis); +js::set('rdSearchValue', ''); $canSortRegion = commonModel::hasPriv('kanban', 'sortRegion') && count($regions) > 1; $canEditRegion = commonModel::hasPriv('kanban', 'editRegion'); @@ -136,7 +137,13 @@ js::set('hasTaskButton', $hasTaskButton);
+
+ +
" . $lang->searchAB, '', "class='btn btn-link querybox-toggle'"); echo html::a('javascript:fullScreen()', " " . $lang->kanban->fullScreen, '', "class='btn btn-link'"); $actions = ''; $printCreateRegion = (common::hasPriv('kanban', 'createRegion') and $groupBy == 'default'); diff --git a/module/kanban/model.php b/module/kanban/model.php index df7c270ae0..cf4bb3e966 100644 --- a/module/kanban/model.php +++ b/module/kanban/model.php @@ -808,13 +808,14 @@ class kanbanModel extends model * @param string $orderBy * @param int $regionID * @param string $groupBy + * @param string $searchValue * * @access public * @return array */ - public function getRDKanban($executionID, $browseType = 'all', $orderBy = 'id_desc', $regionID = 0, $groupBy = 'default') + public function getRDKanban($executionID, $browseType = 'all', $orderBy = 'id_desc', $regionID = 0, $groupBy = 'default', $searchValue = '') { - if($groupBy != 'default') return $this->getKanban4Group($executionID, $browseType, $groupBy); + if($groupBy != 'default') return $this->getKanban4Group($executionID, $browseType, $groupBy, $searchValue); $kanbanData = array(); $actions = array('sortGroup'); @@ -823,7 +824,7 @@ class kanbanModel extends model $groupGroup = $this->getGroupGroupByRegions($regionIDList); $laneGroup = $this->getLaneGroupByRegions($regionIDList, $browseType); $columnGroup = $this->getRDColumnGroupByRegions($regionIDList, array_keys($laneGroup)); - $cardGroup = $this->getCardGroupByExecution($executionID, $browseType, $orderBy); + $cardGroup = $this->getCardGroupByExecution($executionID, $browseType, $orderBy, $searchValue); foreach($regions as $regionID => $regionName) { @@ -838,13 +839,16 @@ class kanbanModel extends model $lanes = zget($laneGroup, $group->id, array()); if(!$lanes) continue; - foreach($lanes as $lane) + foreach($lanes as $key => $lane) { $this->refreshCards($lane); $lane->items = isset($cardGroup[$lane->id]) ? $cardGroup[$lane->id] : array(); $lane->defaultCardType = $lane->type; + if(!empty($searchValue) and count($lane->items) == 0) unset($lanes[$key]); } + $lanes = array_values($lanes); + if(!empty($searchValue) and empty($lanes)) continue; $group->columns = zget($columnGroup, $group->id, array()); $group->lanes = $lanes; $group->actions = array(); @@ -1250,10 +1254,12 @@ class kanbanModel extends model * @param int $kanbanID * @param string $browseType all|task|bug|story * @param string $orderBy + * @param string $searchValue + * * @access public * @return array */ - public function getCardGroupByExecution($executionID, $browseType = 'all', $orderBy = 'id_asc') + public function getCardGroupByExecution($executionID, $browseType = 'all', $orderBy = 'id_asc', $searchValue = '') { $cards = $this->dao->select('t1.*, t2.type as columnType') ->from(TABLE_KANBANCELL)->alias('t1') @@ -1297,12 +1303,14 @@ class kanbanModel extends model if($cell->type == 'task') { + if(!empty($searchValue) and strpos($object->name, $searchValue) === false) continue; $cardData['name'] = $object->name; $cardData['status'] = $object->status; $cardData['left'] = $object->left; } else { + if(!empty($searchValue) and strpos($object->title, $searchValue) === false) continue; $cardData['title'] = $object->title; } $cardGroup[$laneID][$cell->columnType][] = $cardData; @@ -1406,12 +1414,14 @@ class kanbanModel extends model if($lane->type == 'task') { + if(!empty($searchValue) and strpos($object->name, $searchValue) === false) continue; $cardData['name'] = $object->name; $cardData['status'] = $object->status; $cardData['left'] = $object->left; } else { + if(!empty($searchValue) and strpos($object->title, $searchValue) === false) continue; $cardData['title'] = $object->title; } @@ -1440,10 +1450,12 @@ class kanbanModel extends model * @param int $executionID * @param string $browseType * @param string $groupBy + * @param string $searchValue + * * @access public * @return array */ - public function getKanban4Group($executionID, $browseType, $groupBy) + public function getKanban4Group($executionID, $browseType, $groupBy, $searchValue = '') { /* Get card data. */ $cardList = array(); @@ -1551,21 +1563,24 @@ class kanbanModel extends model if($browseType == 'task') { + if(!empty($searchValue) and strpos($object->name, $searchValue) === false) continue; $cardData['name'] = $object->name; $cardData['status'] = $object->status; $cardData['left'] = $object->left; } else { + if(!empty($searchValue) and strpos($object->title, $searchValue) === false) continue; $cardData['title'] = $object->title; } $laneData['cards'][$column->columnType][] = $cardData; $cardOrder ++; } - if(!isset($laneData['cards'][$column->columnType])) $laneData['cards'][$column->columnType] = array(); + if(empty($searchValue) and !isset($laneData['cards'][$column->columnType])) $laneData['cards'][$column->columnType] = array(); } + if(!empty($searchValue) and empty($laneData['cards'])) continue;; $kanbanGroup[$groupBy]['id'] = $groupBy . $laneID; $kanbanGroup[$groupBy]['columns'] = array_values($columnData); $kanbanGroup[$groupBy]['lanes'][] = $laneData; From d1e74eb74a5ed859a9dd7da30db67c3239e0f60a Mon Sep 17 00:00:00 2001 From: liumengyi Date: Wed, 8 Jun 2022 13:10:13 +0800 Subject: [PATCH 2/6] * Fix bug of task #56454. --- module/execution/js/kanban.js | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/module/execution/js/kanban.js b/module/execution/js/kanban.js index f9ea3db8ab..d1a7ac0bec 100644 --- a/module/execution/js/kanban.js +++ b/module/execution/js/kanban.js @@ -478,8 +478,7 @@ function renderStoryItem(item, $item, col) .attr('href', $.createLink('story', 'view', 'storyID=' + item.id + '&version=0¶m=' + execution.id, '', true)).attr('data-toggle', 'modal').attr('data-width', '95%'); $title.appendTo($item); } - var reg = new RegExp('((' + rdSearchValue + ')+)', "g"); - var title = rdSearchValue != '' ? "" + item.title.replace(reg, "$1") + "": "" + item.title + ""; + var title = rdSearchValue != '' ? "" + item.title.replaceAll(rdSearchValue, "" + rdSearchValue + "") + "": "" + item.title + ""; $title.attr('title', item.title).find('.text').replaceWith(title); } @@ -544,8 +543,7 @@ function renderBugItem(item, $item, col) .attr('href', $.createLink('bug', 'view', 'bugID=' + item.id, '', true)).attr('data-toggle', 'modal').attr('data-width', '80%'); $title.appendTo($item); } - var reg = new RegExp('((' + rdSearchValue + ')+)', "g"); - var title = rdSearchValue != '' ? "" + item.title.replace(reg, "$1") + "": "" + item.title + ""; + var title = rdSearchValue != '' ? "" + item.title.replaceAll(rdSearchValue, "" + rdSearchValue + "") + "": "" + item.title + ""; $title.attr('title', item.title).find('.text').replaceWith(title); } @@ -612,8 +610,7 @@ function renderTaskItem(item, $item, col) .attr('href', $.createLink('task', 'view', 'taskID=' + item.id, '', true)).attr('data-toggle', 'modal').attr('data-width', '80%'); $title.appendTo($item); } - var reg = new RegExp('((' + rdSearchValue + ')+)', "g"); - var name = rdSearchValue != '' ? "" + item.name.replace(reg, "$1") + "": "" + item.name + ""; + var name = rdSearchValue != '' ? "" + item.name.replaceAll(rdSearchValue, "" + rdSearchValue + "") + "": "" + item.name + ""; $title.attr('title', item.name).find('.text').replaceWith(name); } @@ -801,7 +798,13 @@ function updateRegion(regionID, regionData = []) if(data == null) { $("div[data-id^=" + regionID + "].region").hide(); + return false; } + else + { + $("div[data-id^=" + regionID + "].region").show(); + } + $region.empty(); $region.data('zui.kanban').render(data); resetRegionHeight('open'); return true; @@ -1614,7 +1617,7 @@ function toggleRDSearchBox() function searchCards(value) { rdSearchValue = value; - $.get(createLink('execution', 'ajaxUpdateKanban', "executionID=" + executionID + "&entertime=" + entertime + "&browseType=" + browseType + "&groupBy=" + groupBy + '&from=RD&searchValue=' + value), function(data) + $.get(createLink('execution', 'ajaxUpdateKanban', "executionID=" + executionID + "&entertime=0&browseType=" + browseType + "&groupBy=" + groupBy + '&from=RD&searchValue=' + value), function(data) { kanbanData = $.parseJSON(data); $('#kanban').children('.region').children("div[id^='kanban']").each(function() From cbdefb47fd13e63b371739ec722965b6d553d57d Mon Sep 17 00:00:00 2001 From: liumengyi Date: Wed, 8 Jun 2022 13:18:21 +0800 Subject: [PATCH 3/6] * Fix bug of task #56454. --- module/execution/js/kanban.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/execution/js/kanban.js b/module/execution/js/kanban.js index d1a7ac0bec..a1241aec2e 100644 --- a/module/execution/js/kanban.js +++ b/module/execution/js/kanban.js @@ -1602,8 +1602,8 @@ function resetRegionHeight(fold) */ function toggleRDSearchBox() { - $('#rdSearchBox').fadeToggle(); rdSearchValue = ''; + $('#rdSearchBox').toggle(); if($('#rdSearchBox').css('display') == 'block') { $(".querybox-toggle").css("color", "#0c64eb"); From 0fe197894b1edd0d17278cca160aa2f410c35038 Mon Sep 17 00:00:00 2001 From: liumengyi Date: Wed, 8 Jun 2022 13:44:27 +0800 Subject: [PATCH 4/6] * Fix bug of task #56454. --- module/execution/js/kanban.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/module/execution/js/kanban.js b/module/execution/js/kanban.js index a1241aec2e..81dab0d584 100644 --- a/module/execution/js/kanban.js +++ b/module/execution/js/kanban.js @@ -1619,13 +1619,23 @@ function searchCards(value) rdSearchValue = value; $.get(createLink('execution', 'ajaxUpdateKanban', "executionID=" + executionID + "&entertime=0&browseType=" + browseType + "&groupBy=" + groupBy + '&from=RD&searchValue=' + value), function(data) { - kanbanData = $.parseJSON(data); + var kanbanData = $.parseJSON(data); + var hideAll = true; $('#kanban').children('.region').children("div[id^='kanban']").each(function() { var regionID = $(this).attr('data-id'); if(kanbanData != null) data = groupBy == 'default' ? kanbanData[regionID] : kanbanData[groupBy]; - updateRegion(regionID, data); + hideAll = hideAll && !updateRegion(regionID, data); }); + + if(hideAll && rdSearchValue != '') + { + if($('.table-empty-tip').length == 0) $('#kanban').append('

' + kanbanLang.empty + '

'); + } + else + { + $('.table-empty-tip').remove(); + } }); } From bf33186b82443e0c443cd5a7bc61e810a4c0ff89 Mon Sep 17 00:00:00 2001 From: liumengyi Date: Wed, 8 Jun 2022 13:45:14 +0800 Subject: [PATCH 5/6] * Add annotation. --- module/execution/js/kanban.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/module/execution/js/kanban.js b/module/execution/js/kanban.js index 81dab0d584..500a765daa 100644 --- a/module/execution/js/kanban.js +++ b/module/execution/js/kanban.js @@ -1614,6 +1614,13 @@ function toggleRDSearchBox() } } +/** + * Search all cards. + * + * @param string $value + * @access public + * @return void + */ function searchCards(value) { rdSearchValue = value; From d0e34c1f19576856299e770be3410b770ed44cd0 Mon Sep 17 00:00:00 2001 From: liumengyi Date: Wed, 8 Jun 2022 13:50:15 +0800 Subject: [PATCH 6/6] * Code optimize. --- module/execution/view/kanban.html.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/execution/view/kanban.html.php b/module/execution/view/kanban.html.php index 36f97dfc73..aa64075abd 100644 --- a/module/execution/view/kanban.html.php +++ b/module/execution/view/kanban.html.php @@ -139,7 +139,7 @@ js::set('hasTaskButton', $hasTaskButton);