* finish task #1959, #1958.

This commit is contained in:
Catouse
2014-12-10 09:50:56 +08:00
parent 8753c1f52a
commit 85ba11c7ea
12 changed files with 209 additions and 12 deletions
+1
View File
@@ -16,6 +16,7 @@ $lang->dot = '.';
$lang->at = ' at ';
$lang->downArrow = '↓';
$lang->null = '空';
$lang->ellipsis = '...';
$lang->zentaoPMS = 'zentao';
$lang->welcome = "%s PMS";
+1
View File
@@ -16,6 +16,7 @@ $lang->dot = '。';
$lang->at = ' 于 ';
$lang->downArrow = '↓';
$lang->null = '空';
$lang->ellipsis = '…';
$lang->zentaoPMS = '禅道';
$lang->welcome = "%s项目管理系统";
+1
View File
@@ -16,6 +16,7 @@ $lang->dot = '。';
$lang->at = ' 于 ';
$lang->downArrow = '↓';
$lang->null = '空';
$lang->ellipsis = '…';
$lang->zentaoPMS = '禪道';
$lang->welcome = "%s項目管理系統";
+55 -5
View File
@@ -898,10 +898,48 @@ class story extends control
* @param int $moduleID
* @param int $storyID
* @param string $onlyOption
* @param string $status
* @param int $limit
* @access public
* @return void
*/
public function ajaxGetProductStories($productID, $moduleID = 0, $storyID = 0, $onlyOption = 'false', $status = '')
public function ajaxGetProductStories($productID, $moduleID = 0, $storyID = 0, $onlyOption = 'false', $status = '', $limit = 0)
{
if($moduleID)
{
$moduleID = $this->loadModel('tree')->getStoryModule($moduleID);
$moduleID = $this->tree->getAllChildID($moduleID);
}
$storyStatus = '';
if($status == 'noclosed')
{
$storyStatus = $this->lang->story->statusList;
unset($storyStatus['closed']);
$storyStatus = array_keys($storyStatus);
}
$stories = $this->story->getProductStoryPairs($productID, $moduleID, $storyStatus, 'id_desc', $limit);
$select = html::select('story', $stories, $storyID, "class='form-control'");
/* If only need options, remove select wrap. */
if($onlyOption == 'true') die(substr($select, strpos($select, '>') + 1, -10));
die($select);
}
/**
* AJAX: search stories of a product as json
*
* @param string $key
* @param int $productID
* @param int $moduleID
* @param int $storyID
* @param string $status
* @param int $limit
* @access public
* @return void
*/
public function ajaxSearchProductStories($key, $productID, $moduleID = 0, $storyID = 0, $status = 'noclosed', $limit = 50)
{
if($moduleID)
{
@@ -918,11 +956,23 @@ class story extends control
}
$stories = $this->story->getProductStoryPairs($productID, $moduleID, $storyStatus);
$select = html::select('story', $stories, $storyID, "class='form-control'");
$result = array();
$i = 0;
foreach ($stories as $id => $story)
{
if($limit > 0 && $i > $limit) break;
if(('#' . $id) === $key || stripos($story, $key) !== false)
{
$result[$id] = $story;
$i++;
}
}
if($i < 1)
{
$result['info'] = $this->lang->noResultsMatch;
}
/* If only need options, remove select wrap. */
if($onlyOption == 'true') die(substr($select, strpos($select, '>') + 1, -10));
die($select);
die(json_encode($result));
}
/**
+12 -3
View File
@@ -945,10 +945,11 @@ class storyModel extends model
* @param array|string $moduleIds
* @param string $status
* @param string $order
* @param int $limit
* @access public
* @return array
*/
public function getProductStoryPairs($productID = 0, $moduleIds = 0, $status = 'all', $order = 'id_desc')
public function getProductStoryPairs($productID = 0, $moduleIds = 0, $status = 'all', $order = 'id_desc', $limit = 0)
{
$stories = $this->dao->select('t1.id, t1.title, t1.module, t1.pri, t1.estimate, t2.name AS product')
->from(TABLE_STORY)->alias('t1')->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t1.product = t2.id')
@@ -960,7 +961,7 @@ class storyModel extends model
->orderBy($order)
->fetchAll();
if(!$stories) return array();
return $this->formatStories($stories);
return $this->formatStories($stories, 'full', $limit);
}
/**
@@ -1379,10 +1380,11 @@ class storyModel extends model
*
* @param array $stories
* @param string $type
* @param int $limit
* @access public
* @return void
*/
public function formatStories($stories, $type = 'full')
public function formatStories($stories, $type = 'full', $limit = 0)
{
/* Get module names of stories. */
/*$modules = array();
@@ -1391,6 +1393,7 @@ class storyModel extends model
/* Format these stories. */
$storyPairs = array('' => '');
$i = 0;
foreach($stories as $story)
{
if($type == 'short')
@@ -1402,6 +1405,12 @@ class storyModel extends model
$property = '(' . $this->lang->story->pri . ':' . $story->pri . ',' . $this->lang->story->estimate . ':' . $story->estimate . ')';
}
$storyPairs[$story->id] = $story->id . ':' . $story->title . $property;
if($limit > 0 && ++$i > $limit)
{
$storyPairs['showmore'] = $this->lang->more . $this->lang->ellipsis;
break;
}
}
return $storyPairs;
}
+1 -1
View File
@@ -317,7 +317,7 @@ class testcase extends control
$modules = $this->loadModel('tree')->getStoryModule($currentModuleID);
$modules = $this->tree->getAllChildID($modules);
}
$stories = $this->story->getProductStoryPairs($productID, $modules, array_keys($storyStatus));
$stories = $this->story->getProductStoryPairs($productID, $modules, array_keys($storyStatus), 'id_desc', 20);
$this->view->title = $title;
$this->view->caseTitle = $caseTitle;
+12
View File
@@ -0,0 +1,12 @@
#searchStories .searchInput {position: relative;}
#searchStories .searchInput .icon {position: absolute; display: block; left: 9px; top: 9px; z-index: 5; color: #808080;}
#storySearchInput {padding-left: 30px;}
#searchStories .modal-body {height: 300px; overflow-y: auto; padding: 0;}
#searchResult {padding-left: 0; list-style: none; width: 100%}
#searchResult > li {display: block}
#searchResult > li.tip {padding: 6px 15px; color: #808080}
#searchResult > li.loading {text-align: center; padding: 50px}
#searchResult > li.loading > .icon-spinner:before {font-size: 28px;}
#searchResult > li > a {display: block; padding: 6px 15px; color: #333; border-bottom: 1px solid #e5e5e5}
#searchResult > li > a:hover, #searchResult > li > a.selected {color: #1a4f85; background-color: #ddd;}
+1 -1
View File
@@ -47,7 +47,7 @@ function setStories()
{
moduleID = $('#module').val();
productID = $('#product').val();
link = createLink('story', 'ajaxGetProductStories', 'productID=' + productID + '&moduleID=' + moduleID + '&storyID=0&onlyOption=false&status=noclosed');
link = createLink('story', 'ajaxGetProductStories', 'productID=' + productID + '&moduleID=' + moduleID + '&storyID=0&onlyOption=false&status=noclosed&limit=20');
$.get(link, function(stories)
{
var value = $('#story').val();
+105 -2
View File
@@ -17,6 +17,109 @@ function setPreview()
$(function()
{
$("#story").chosen(defaultChosenOptions);
$("#preview").modalTrigger({width:960, type:'iframe'});
var $searchStories = $('#searchStories');
var lastSearchFn = false;
var $searchInput = $('#storySearchInput');
var $searchResult = $('#searchResult');
var $selectedItem;
var $story = $('#story');
$(document).on('change', '#story', function()
{
if($(this).val() === 'showmore')
{
$searchStories.modal('show').on('shown.zui.modal', function(){$searchInput.focus();});
}
});
$searchStories.on('hide.zui.modal', function()
{
var key = '';
if($selectedItem && $selectedItem.length)
{
key = $selectedItem.data('key');
if(!$story.children('option[value="' + key + '"]').length)
{
$story.prepend('<option value="' + key + '">' + $selectedItem.text() + '</option>');
}
}
$story.val(key).trigger("chosen:updated");
$selectedItem = null;
});
var selectItem = function(item)
{
$selectedItem = $(item).first();
$searchStories.modal('hide');
};
$searchResult.on('click', 'a', function(){selectItem(this);}).on('mouseenter', 'a', function()
{
$searchResult.find('a.selected').removeClass('selected');
$(this).addClass('selected');
}).on('mouseleave', 'a', function()
{
$(this).removeClass('selected');
});
$searchInput.on('paste change keyup', function()
{
if(lastSearchFn) clearTimeout(lastSearchFn);
lastSearchFn = setTimeout(function()
{
var key = $searchInput.val() || '';
if(key && key != $searchInput.data('lastkey'))
{
$searchResult.empty().append('<li class="loading"><i class="icon-spin icon-spinner icon-2x"></i></li>');
var link = createLink('story', 'ajaxSearchProductStories', 'key=' + key + '&productID=' + $('#product').val() + '&moduleID=' + $('#module').val() + '&storyID=0&status=noclosed&limit=20');
$.getJSON(link, function(result)
{
$searchResult.empty();
if(result)
{
for(var key in result)
{
if(key === 'info')
{
$searchResult.append('<li class="tip">' + result[key] + '</li>');
}
else
{
$searchResult.append("<li><a href='javascript:;' data-key='" + key + "'>" + result[key] + "</a></li>");
}
}
$searchResult.find('li:first > a').addClass('selected');
}
});
$searchInput.data('lastkey', key);
}
else if(!key.length)
{
$searchResult.empty();
}
}, 500);
}).on('keyup', function(e)
{
var $selected = $searchResult.find('a.selected').first();
if(e.keyCode == 38) // keyup
{
var $prev = $selected.closest('li').prev().children('a');
if($prev.length)
{
$selected.removeClass('selected');
$prev.addClass('selected');
}
}
else if(e.keyCode == 40) // keydown
{
var $next = $selected.closest('li').next().children('a');
if($next.length)
{
$selected.removeClass('selected');
$next.addClass('selected');
}
}
else if(e.keyCode == 13) selectItem($selected);
});
$("#preview").modalTrigger({width:960, type:'iframe'});
})
+2
View File
@@ -156,3 +156,5 @@ $lang->testcase->buttonToList = 'Back';
$lang->testcase->errorEncode = 'No data, please select right encode and upload again!';
$lang->testcase->noFunction = 'Iconv and mb_convert_encoding does not exist, you can not turn the data into the desired coding!';
$lang->testcase->noRequire = "In the row of %s, the %s is a required field";
$lang->testcase->searchStories = 'Type to search stories';
+2
View File
@@ -156,3 +156,5 @@ $lang->testcase->buttonToList = '返回';
$lang->testcase->errorEncode = '无数据,请选择正确的编码重新上传!';
$lang->testcase->noFunction = '不存在iconv和mb_convert_encoding转码方法,不能将数据转成想要的编码!';
$lang->testcase->noRequire = "%s行的“%s”是必填字段,不能为空";
$lang->testcase->searchStories = '键入来搜索需求';
+16
View File
@@ -125,4 +125,20 @@
</table>
</form>
</div>
<div class='modal fade' id='searchStories'>
<div class='modal-dialog'>
<div class='modal-content'>
<div class='modal-header'>
<button type='button' class='close' data-dismiss='modal'>&times;</button>
<div class='searchInput w-p90'>
<input id='storySearchInput' type='text' class='form-control' placeholder='<?php echo $lang->testcase->searchStories?>'>
<i class='icon icon-search'></i>
</div>
</div>
<div class='modal-body'>
<ul id='searchResult'></ul>
</div>
</div>
</div>
</div>
<?php include '../../common/view/footer.html.php';?>