一、创建BUG界面
1.在/opt/zbox/app/zentao/module/bug/ext/view路径下的create.yyt.html.hook.php文件中增加测试版本字段代码:
//用例编号
$html .= '<span class="input-group-addon" style="border-radius: 4px;">';
$html .= $lang->bug->caseno;
$html .= '</span>';
$html .= '<span class="input-control has-icon-right">';
$html .= '<input type="text" value style="width: 210px" name="caseno" id="caseno" autocomplete="off" class="form-control" ;">';
$html .= '</span>';
$html .= '</div>';
$html .= '<div style="visibility:hidden;color: #ff5d5d" id="casenoerror">『用例编号』不能为空</div>';
$html .= '</td>';
//测试版本
$html .= '<td valign="top">';
$html .= '<div class="input-group required" id="">';
$html .= '<span class="input-group-addon" style="border-radius: 4px;">';
$html .= $lang->bug->testBuild;
$html .= '</span>';
$html .= html::select('testBuild', $builds, empty($buildID) ? '' : $buildID, "class='chosen form-control'");
$html .= '</div>';
$html .= '<div style="visibility:hidden;color: #ff5d5d" id="testBuildError">『测试版本』不能为空</div>';
$html .= '</td>';
$html .= '</div>';
$html .= '</tr>';
?>
2、新增字段为空时的错误提示
<script>
document.getElementById('submit').onclick=function check(){
var iscasefind = document.getElementById('iscasefind').checked;
if (iscasefind==true){
document.getElementById('iscasefind').value='是';
}else{
document.getElementById('iscasefind').value='否';
}
if(document.getElementById('iscasefind').value == '是'){
var no = document.getElementById('caseno').value;
if (no==''){
document.getElementById('casenoerror').style.visibility="visible";
return false;
}else{
document.getElementById('casenoerror').style.visibility="hidden";
}
}
var testBuild = document.getElementById('testBuild').value;
if (testBuild == ''){
document.getElementById('testBuildError').style.visibility="visible";
return false;
}else{
document.getElementById('testBuildError').style.visibility="hidden";
}
}
</script>
3、在/opt/zbox/app/zentao/module/bug/ext/lang/zh-cn路径下的create.php文件里面设置测试版本字段的属性的值
<?php
/*yyt*/
$lang->bug->probability = '出现概率';
$lang->bug->iscasefind = '用例发现';
$lang->bug->caseno = '用例编号';
$lang->bug->testBuild = '测试版本';
/*yyt*/
二、在数据库表中增加字段
alter table zt_bug add column `testBuild` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL;
三、BUG预览界面自定义展示测试版本字段
1.在/opt/zbox/app/zentao/module/bug/ext/config路径下的bug模块的config.php文件的扩展文件create.php中增加字段
$config->bug->datatable->fieldList['testBuild']['title'] = 'testBuild';
$config->bug->datatable->fieldList['testBuild']['fixed'] = 'right';
$config->bug->datatable->fieldList['testBuild']['width'] = '100';
$config->bug->datatable->fieldList['testBuild']['required'] = 'no';
四、在BUG预览界面增加测试版本的下拉选项框
1、在BUG的browse.html.php文件中增加下拉框代码
<!--yyt-->
<div class="btn-group">
<button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown">
测试版本 <span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu">
<?php
if(isset($builds)){
foreach($builds as $testBuild){
$removeLink = '/zentaopms/www/index.php?m=bug&f=browse&productid=' . $productID . '&branch=' . $branch . '&browseType=' . $browseType . '&testBuild=' . $testBuild ;
echo '<li>' . '<a href=' . $removeLink . '>' . $testBuild . '</a></li>';
}
}
?>
</ul>
</div>
<!--yyt-->
新增BUG模块control.php的扩展文件ext/control/browse.php
/**
* Browse bugs.
*
* @param int $productID
* @param string $branch
* @param string $browseType
* @param int $param
* @param string $orderBy
* @param int $recTotal
* @param int $recPerPage
* @param int $pageID
* @access public
* @return void
*/
public function browse($productID = 0, $branch = '', $browseType = '',$testBuild = '', $param = 0, $orderBy = '', $recTotal = 0, $recPerPage = 20, $pageID = 1)
{
$this->loadModel('datatable');
$productID = $this->product->saveState($productID, $this->products);
$this->qa->setMenu($this->products, $productID, $branch);
/* Set browse type. */
$browseType = strtolower($browseType);
/* Set productID, moduleID, queryID and branch. */
$branch = ($branch == '') ? (int)$this->cookie->preBranch : (int)$branch;
setcookie('preProductID', $productID, $this->config->cookieLife, $this->config->webRoot, '', $this->config->cookieSecure, true);
setcookie('preBranch', (int)$branch, $this->config->cookieLife, $this->config->webRoot, '', $this->config->cookieSecure, true);
if($this->cookie->preProductID != $productID or $this->cookie->preBranch != $branch or $browseType == 'bybranch')
{
$_COOKIE['bugModule'] = 0;
setcookie('bugModule', 0, 0, $this->config->webRoot, '', $this->config->cookieSecure, false);
}
if($browseType == 'bymodule' or $browseType == '')
{
setcookie('bugModule', (int)$param, 0, $this->config->webRoot, '', $this->config->cookieSecure, false);
$_COOKIE['bugBranch'] = 0;
setcookie('bugBranch', 0, 0, $this->config->webRoot, '', $this->config->cookieSecure, false);
if($browseType == '') setcookie('treeBranch', (int)$branch, 0, $this->config->webRoot, '', $this->config->cookieSecure, false);
}
if($browseType == 'bybranch') setcookie('bugBranch', (int)$branch, 0, $this->config->webRoot, '', $this->config->cookieSecure, false);
if($browseType != 'bymodule' and $browseType != 'bybranch') $this->session->set('bugBrowseType', $browseType);
$moduleID = ($browseType == 'bymodule') ? (int)$param : (($browseType == 'bysearch' or $browseType == 'bybranch') ? 0 : ($this->cookie->bugModule ? $this->cookie->bugModule : 0));
$queryID = ($browseType == 'bysearch') ? (int)$param : 0;
/* Set session. */
$this->session->set('bugList', $this->app->getURI(true), 'qa');
/* Set moduleTree. */
if($browseType == '')
{
setcookie('treeBranch', (int)$branch, 0, $this->config->webRoot, '', $this->config->cookieSecure, false);
$browseType = 'unclosed';
}
if($this->projectID and !$productID)
{
$moduleTree = $this->tree->getBugTreeMenu($this->projectID, $productID, 0, array('treeModel', 'createBugLink'));
}
else
{
$moduleTree = $this->tree->getTreeMenu($productID, 'bug', 0, array('treeModel', 'createBugLink'), '', $browseType == '' ? $branch : (int)$this->cookie->treeBranch);
}
if(($browseType != 'bymodule' && $browseType != 'bybranch')) $this->session->set('bugBrowseType', $browseType);
if(($browseType == 'bymodule' || $browseType == 'bybranch') and $this->session->bugBrowseType == 'bysearch') $this->session->set('bugBrowseType', 'unclosed');
/* Process the order by field. */
if(!$orderBy) $orderBy = $this->cookie->qaBugOrder ? $this->cookie->qaBugOrder : 'id_desc';
setcookie('qaBugOrder', $orderBy, 0, $this->config->webRoot, '', $this->config->cookieSecure, true);
/* Append id for secend sort. */
$sort = $this->loadModel('common')->appendOrder($orderBy);
/* Load pager. */
$this->app->loadClass('pager', $static = true);
if($this->app->getViewType() == 'mhtml') $recPerPage = 10;
$pager = new pager($recTotal, $recPerPage, $pageID);
/* Get executios. */
$executions = $this->loadModel('execution')->getPairs($this->projectID, 'all', 'empty|withdelete');
/* Get product id list. */
$productIDList = $productID ? $productID : array_keys($this->products);
/* Get bugs. */
$bugs = $this->bug->getBugs($productIDList, $executions, $branch, $browseType,$testBuild, $moduleID, $queryID, $sort, $pager, $this->projectID);
/* Process the sql, get the conditon partion, save it to session. */
$this->loadModel('common')->saveQueryCondition($this->dao->get(), 'bug', $browseType == 'needconfirm' ? false : true);
/* Process bug for check story changed. */
$bugs = $this->loadModel('story')->checkNeedConfirm($bugs);
/* Process the openedBuild and resolvedBuild fields. */
$bugs = $this->bug->processBuildForBugs($bugs);
/* Get story and task id list. */
$storyIdList = $taskIdList = array();
foreach($bugs as $bug)
{
if($bug->story) $storyIdList[$bug->story] = $bug->story;
if($bug->task) $taskIdList[$bug->task] = $bug->task;
if($bug->toTask) $taskIdList[$bug->toTask] = $bug->toTask;
}
$storyList = $storyIdList ? $this->loadModel('story')->getByList($storyIdList) : array();
$taskList = $taskIdList ? $this->loadModel('task')->getByList($taskIdList) : array();
/* Build the search form. */
$actionURL = $this->createLink('bug', 'browse', "productID=$productID&branch=$branch&browseType=bySearch&testBuild=&queryID=myQueryID");
$this->config->bug->search['onMenuBar'] = 'yes';
$this->bug->buildSearchForm($productID, $this->products, $queryID, $actionURL);
$showModule = !empty($this->config->datatable->bugBrowse->showModule) ? $this->config->datatable->bugBrowse->showModule : '';
$productName = ($productID and isset($this->products[$productID])) ? $this->products[$productID] : $this->lang->product->allProduct;
/* Set view. */
$this->view->title = $productName . $this->lang->colon . $this->lang->bug->common;
$this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $productName,'','title=' . $productName);
$this->view->position[] = $this->lang->bug->common;
$this->view->productID = $productID;
$this->view->product = $this->product->getById($productID);
$this->view->projectProducts = $this->product->getProducts($this->projectID);
$this->view->productName = $productName;
$this->view->builds = $this->loadModel('build')->getProductBuildPairs($productID);
$this->view->modules = $this->tree->getOptionMenu($productID, $viewType = 'bug', $startModuleID = 0, $branch);
$this->view->moduleTree = $moduleTree;
$this->view->moduleName = $moduleID ? $this->tree->getById($moduleID)->name : $this->lang->tree->all;
$this->view->summary = $this->bug->summary($bugs);
$this->view->browseType = $browseType;
$this->view->bugs = $bugs;
$this->view->users = $this->user->getPairs('noletter');
$this->view->pager = $pager;
$this->view->param = $param;
$this->view->orderBy = $orderBy;
$this->view->moduleID = $moduleID;
$this->view->memberPairs = $this->user->getPairs('noletter|nodeleted');
$this->view->branch = $branch;
$this->view->branches = $this->loadModel('branch')->getPairs($productID, 'noempty');
$this->view->executions = $executions;
$this->view->plans = $this->loadModel('productplan')->getPairs($productID);
$this->view->stories = $storyList;
$this->view->tasks = $taskList;
$this->view->setModule = true;
$this->view->isProjectBug = ($productID and !$this->projectID) ? false : true;
$this->view->modulePairs = $showModule ? $this->tree->getModulePairs($productID, 'bug', $showModule) : array();
$this->display();
}
2、在ext/model/printCell.php扩展文件中增加testBuild字段逻辑
case 'testBuild':
$builds = array_flip($builds);
$buildID = zget($builds, $bug->testBuild, '');
if($buildID == 'trunk')
{
echo $bug->testBuild;
}
elseif($buildID and common::hasPriv('build', 'view'))
{
echo html::a(helper::createLink('build', 'view', "buildID=$buildID"), $bug->testBuild, '', "title='$bug->testBuild'");
}
break;
3、增加ext/model/processBuildForBugs.php文件
<?php
public function processBuildForBugs($bugs)
{
$productIdList = array();
foreach($bugs as $bug) $productIdList[$bug->id] = $bug->product;
$builds = $this->loadModel('build')->getProductBuildPairs(array_unique($productIdList), 0, $params = '');
/* Process the openedBuild and resolvedBuild fields. */
foreach($bugs as $key => $bug)
{
$openBuildIdList = explode(',', $bug->openedBuild);
$openedBuild = '';
//yyt
$testBuild = isset($builds[$bug->testBuild]) ? $builds[$bug->testBuild] : $bug->testBuild;
$bug->testBuild = $testBuild;
//yyt
foreach($openBuildIdList as $buildID)
{
$openedBuild .= isset($builds[$buildID]) ? $builds[$buildID] : $buildID;
$openedBuild .= ',';
}
$bug->openedBuild = rtrim($openedBuild, ',');
$bug->resolvedBuild = isset($builds[$bug->resolvedBuild]) ? $builds[$bug->resolvedBuild] : $bug->resolvedBuild;
}
return $bugs;
}
?>
4、增加ext/model/getBugs.php文件
<?php
public function getBugs($productIDList, $executions, $branch, $browseType,$testBild, $moduleID, $queryID, $sort, $pager, $projectID)
{
/* Set modules and browse type. */
$modules = $moduleID ? $this->loadModel('tree')->getAllChildId($moduleID) : '0';
$browseType = ($browseType == 'bymodule' and $this->session->bugBrowseType and $this->session->bugBrowseType != 'bysearch') ? $this->session->bugBrowseType : $browseType;
$browseType = $browseType == 'bybranch' ? 'bymodule' : $browseType;
/* Get bugs by browse type. */
$bugs = array();
if($browseType == 'all') $bugs = $this->getAllBugs($productIDList, $branch, $modules, $executions, $sort, $pager, $projectID);
elseif($browseType == 'bymodule') $bugs = $this->getModuleBugs($productIDList, $branch, $modules, $executions, $sort, $pager, $projectID);
elseif($browseType == 'assigntome') $bugs = $this->getByAssigntome($productIDList, $branch, $modules, $executions, $sort, $pager, $projectID);
elseif($browseType == 'openedbyme') $bugs = $this->getByOpenedbyme($productIDList, $branch, $modules, $executions, $sort, $pager, $projectID);
elseif($browseType == 'resolvedbyme') $bugs = $this->getByResolvedbyme($productIDList, $branch, $modules, $executions, $sort, $pager, $projectID);
elseif($browseType == 'assigntonull') $bugs = $this->getByAssigntonull($productIDList, $branch, $modules, $executions, $sort, $pager, $projectID);
elseif($browseType == 'unconfirmed') $bugs = $this->getUnconfirmed($productIDList, $branch, $modules, $executions, $sort, $pager, $projectID);
elseif($browseType == 'unresolved') $bugs = $this->getByStatus($productIDList, $branch, $modules, $executions, 'unresolved', $sort, $pager, $projectID);
elseif($browseType == 'unclosed') $bugs = $this->getByStatus($productIDList, $branch, $modules, $executions, 'unclosed', $sort, $pager, $projectID);
elseif($browseType == 'toclosed') $bugs = $this->getByStatus($productIDList, $branch, $modules, $executions, 'toclosed', $sort, $pager, $projectID);
elseif($browseType == 'longlifebugs') $bugs = $this->getByLonglifebugs($productIDList, $branch, $modules, $executions, $sort, $pager, $projectID);
elseif($browseType == 'postponedbugs') $bugs = $this->getByPostponedbugs($productIDList, $branch, $modules, $executions, $sort, $pager, $projectID);
elseif($browseType == 'needconfirm') $bugs = $this->getByNeedconfirm($productIDList, $branch, $modules, $executions, $sort, $pager, $projectID);
elseif($browseType == 'bysearch') $bugs = $this->getBySearch($productIDList, $branch, $queryID, $sort, '', $pager, $projectID);
elseif($browseType == 'overduebugs') $bugs = $this->getOverdueBugs($productIDList, $branch, $modules, $executions, $sort, $pager, $projectID);
// yyt
if (!empty($testBild) and $testBild != '主干'){
foreach ($bugs as $k => $v){
$selfBuild = $this->getBuildName($v->testBuild,$v->product);
if ($selfBuild !== $testBild){
unset($bugs[$k]);
}
}
}elseif (!empty($testBild) and $testBild == '主干'){
foreach ($bugs as $k => $v){
if ($v->testBuild != 'trunk'){
unset($bugs[$k]);
}
}
}
// yyt
return $this->checkDelayedBugs($bugs);
}
?>
5、增加ext/model/getBuildName.php文件
<?php
// yyt
/**
* get bug's name of build
* @param string $openedBuild
* @param string $product
* @return mixed
*/
public function getBuildName($testBuild = '',$product = ''){
return $this->dao->select('name')->from(TABLE_BUILD)
->where('id')->eq($testBuild)
->andwhere('product')->eq($product)
->fetch(name);
}
// yyt
?>
六、在BUG详情页面增加测试版本字段
1、在bug模块的view.php中增加代码:
2、在BUG模块的model.php增加方法,用于转换版本字段的键值对
//yyt
public function processTestBuildForBug($bug){
$builds = $this->loadModel('build')->getProductBuildPairs($bug->product,0,$params = '');
$testBuild = isset($builds[$bug->testBuild]) ? $builds[$bug->testBuild] : $bug->testBuild;
$bug->testBuild = $testBuild;
return $bug;
}
//yyt
3、在view.yyt.html.hook.php文件中增加测试版本字段展示
![//测试版本
$html .= '<tr>';
$html .= '<th>';
$html .= $lang->bug->testBuild;
$html .= '</th>';
$html .= '<td>';
$html .= $bug->testBuild;
$html .= '</td>';
$html .= '</tr>';](https://img-
七、在BUG修改界面增加测试版本字段
1、在edit.yyt.html.hook.php文件中增加测试版本字段展示
//测试版本
$html .= '<tr>';
$html .= '<th>';
$html .= $lang->bug->testBuild;
$html .= '</th>';
$html .= '<td>';
$html .= '</span>';
$html .= html::select('testBuild', $openedBuilds, $bug->testBuild, "class='chosen form-control'");
$html .= '</td>';
$html .= '</tr>';
八、给预览界面的搜索功能的请求URL上增加testBuild字段,否则搜索功能将搜索不到数据
1、在BUG模块的control.php文件中的browse方法中把$actionURL变量赋值的时候增加"&testBuild="
$actionURL = $this->createLink('bug', 'browse', "productID=$productID&branch=$branch&browseType=bySearch&testBuild=&queryID=myQueryID");