Merge branch 'master' of github.com:easysoft/zentaopms

This commit is contained in:
wangyidong
2016-03-11 09:32:02 +08:00
25 changed files with 648 additions and 71 deletions

View File

@@ -878,6 +878,110 @@ class bug extends control
$this->display();
}
/**
* Link related bugs.
*
* @param int $bugID
* @param string $bugs
* @param string $browseType
* @param int $param
* @access public
* @return void
*/
public function linkBugs($bugID, $bugs = '', $browseType = '', $param = 0)
{
/* Link bugs. */
if(!empty($_POST))
{
$bugs = $this->bug->linkBugs($bugID, $bugs);
if(isonlybody()) die(js::closeModal('parent.parent', '', "function(){parent.parent.loadLinkedBugs('$bugID', '$bugs')}"));
die(js::locate($this->createLink('bug', 'edit', "bugID=$bugID"), 'parent'));
}
/* Get bug, productID and queryID. */
$bug = $this->bug->getById($bugID);
$productID = $this->product->saveState($bug->product, $this->products);
$queryID = ($browseType == 'bysearch') ? (int)$param : 0;
/* Set the menu. */
$this->bug->setMenu($this->products, $productID, $bug->branch);
/* Build the search form. */
$actionURL = $this->createLink('bug', 'linkBugs', "bugID=$bugID&bugs=$bugs&browseType=bySearch&queryID=myQueryID", '', true);
$this->bug->buildSearchForm($productID, $this->products, $queryID, $actionURL);
$this->loadModel('search')->setSearchParams($this->config->bug->search);
/* Get bugs to link. */
$allBugs = array();
if($browseType == 'bySearch') $allBugs = $this->bug->getBySearch($bug->product, $quueryID, 'id', null);
/* Assign. */
$this->view->title = $this->lang->bug->linkBugs . "BUG #$bug->id $bug->title - " . $this->products[$productID];
$this->view->position[] = html::a($this->createLink('product', 'view', "productID=$productID"), $this->products[$productID]);
$this->view->position[] = html::a($this->createLink('bug', 'view', "bugID=$bugID"), $bug->title);
$this->view->position[] = $this->lang->bug->linkBugs;
$this->view->bug = $bug;
$this->view->allBugs = $allBugs;
$this->view->users = $this->loadModel('user')->getPairs('noletter');
$this->display();
}
/**
* AJAX: get linked bugs.
*
* @param int $bugID
* @param string $linkedBugs
* @access public
* @return string
*/
public function ajaxGetLinkedBugs($bugID, $linkedBugs = '')
{
/* Get bug and linked bugs. */
$bug = $this->bug->getById($bugID);
$bugs = $this->bug->getLinkedBugs($linkedBugs);
/* Build linkBug list.*/
$output = "<ul class='list-unstyled'>";
$output .= html::a(inlink('linkBugs', "bugID=$bugID&bugs=$bug->linkBug", '', true), $this->lang->bug->linkBugs, '', "class='iframe' data-width='85%'");
foreach($bugs as $bugId => $title)
{
$output .= '<li>';
$output .= html::a(inlink('view', "bugID=$bugId"), "#$bugId " . $title);
$output .= html::a("javascript:deleteLinkedBug($bugID, $bugId)", '<i class="icon-remove"></i>', '', "title='{$this->lang->unlink}' style='float:right'");
$output .= '</li>';
}
$output .= '</ul>';
die($output);
}
/**
* AJAX: delete a linked bug.
*
* @param int $bugID
* @param int $deleteBug
* @access public
* @return string
*/
public function ajaxDeleteLinkedBug($bugID, $deleteBug)
{
/* Get bug and bugs. */
$bug = $this->bug->getById($bugID);
$bugs = $this->bug->deleteLinkedBug($bugID, $deleteBug);
/* Build linkBug list. */
$output = "<ul class='list-unstyled'>";
$output .= html::a(inlink('linkBugs', "bugID=$bugID&bugs=$bug->linkBug", '', true), $this->lang->bug->linkBugs, '', "class='iframe' data-width='85%'");
foreach($bugs as $bugId => $title)
{
$output .= '<li>' . html::a(inlink('view', "bugID=$bugId"), "#$bugId " . $title) . html::a("javascript:deleteLinkedBug($bugID, $bugId)", '<i class="icon-remove"></i>', '', "style='float:right'");
}
$output .= '</ul>';
die($output);
}
/**
* Batch close bugs.
*

View File

@@ -2,3 +2,4 @@
.col-side .chosen-container {width: 218px!important}
.col-side .chosen-container[id^="openedBuild"] {width: 172px!important}
.col-side .chosen-container[id^="resolvedBuild"] {width: 172px!important}
#linkBugBox > .list-unstyled > li {margin-left:-56px}

View File

@@ -54,3 +54,31 @@ function loadModuleRelated()
productID = $('#product').val();
setStories(moduleID, productID);
}
/**
* Delete a linked bug.
*
* @param int $bugID
* @param int $deleteBug
* @access public
* @return void
*/
function deleteLinkedBug(bugID, deleteBug)
{
deleteLink = createLink('bug', 'ajaxDeleteLinkedBug', 'bugID=' + bugID + '&deleteBug=' + deleteBug);
$('#linkBugBox').load(deleteLink);
}
/**
* Load linked bugs.
*
* @param int $bugID
* @param string $linkedBugs
* @access public
* @return void
*/
function loadLinkedBugs(bugID, linkedBugs)
{
bugLink = createLink('bug', 'ajaxGetLinkedBugs', 'bugID=' + bugID + '&linkedBugs=' + linkedBugs);
$('#linkBugBox').load(bugLink);
}

View File

@@ -60,6 +60,7 @@ $lang->bug->duplicateBug = 'Duplicate';
$lang->bug->lastEditedBy = 'Last Edited By';
$lang->bug->lastEditedDate = 'Last Edited Date';
$lang->bug->linkBug = 'Related';
$lang->bug->linkBugs = 'Link bugs';
$lang->bug->case = 'Case';
$lang->bug->files = 'Files';
$lang->bug->keywords = 'Keywords';
@@ -359,6 +360,8 @@ $lang->bug->action->tostory = array('main' => '$date, To story by <stro
$lang->bug->action->totask = array('main' => '$date, To task by <strong>$actor</strong>, ID is <strong>$extra</strong>.');
$lang->bug->action->linked2plan = array('main' => '$date, Link to plan by <strong>$actor</strong>,ID is <strong>$extra</strong>。');
$lang->bug->action->unlinkedfromplan = array('main' => '$date, Unlink from plan <strong>$extra</strong> by <strong>$actor</strong>.');
$lang->bug->action->linked2bug = array('main' => '$date, linked related bugs <strong>$extra</strong> by <strong>$actor</strong>.');
$lang->bug->action->unlinkedbug = array('main' => '$date, removed related bugs <strong>$extra</strong> by <strong>$actor</strong>.');
$lang->bug->placeholder = new stdclass();
$lang->bug->placeholder->chooseBuilds = 'Choose builds...';

View File

@@ -60,6 +60,7 @@ $lang->bug->duplicateBug = '重复ID';
$lang->bug->lastEditedBy = '最后修改者';
$lang->bug->lastEditedDate = '最后修改日期';
$lang->bug->linkBug = '相关Bug';
$lang->bug->linkBugs = '关联Bug';
$lang->bug->case = '相关用例';
$lang->bug->files = '附件';
$lang->bug->keywords = '关键词';
@@ -359,6 +360,8 @@ $lang->bug->action->tostory = array('main' => '$date, 由 <strong>$acto
$lang->bug->action->totask = array('main' => '$date, 由 <strong>$actor</strong> 导入为<strong>任务</strong>,编号为 <strong>$extra</strong>。');
$lang->bug->action->linked2plan = array('main' => '$date, 由 <strong>$actor</strong> 关联到计划 <strong>$extra</strong>。');
$lang->bug->action->unlinkedfromplan = array('main' => '$date, 由 <strong>$actor</strong> 从计划 <strong>$extra</strong> 移除。');
$lang->bug->action->linked2bug = array('main' => '$date, 由 <strong>$actor</strong> 关联相关Bug <strong>$extra</strong>。');
$lang->bug->action->unlinkedbug = array('main' => '$date, 由 <strong>$actor</strong> 移除相关Bug <strong>$extra</strong>。');
$lang->bug->placeholder = new stdclass();
$lang->bug->placeholder->chooseBuilds = '选择相关版本...';

View File

@@ -794,6 +794,64 @@ class bugModel extends model
$this->dao->update(TABLE_BUG)->data($bug)->autoCheck()->where('id')->eq((int)$bugID)->exec();
}
/**
* Link bugs.
*
* @param int $bugID
* @param string $bugs
* @access public
* @return string
*/
public function linkBugs($bugID, $bugs = '')
{
if($this->post->bugs == false) return $bugs;
$bugs = implode(',', $this->post->bugs) . ',' . trim($bugs, ',');
$this->dao->update(TABLE_BUG)->set('linkBug')->eq(trim($bugs, ','))->where('id')->eq($bugID)->exec();
if(dao::isError()) die(js::error(dao::getError()));
$this->loadModel('action')->create('bug', $bugID, 'linked2Bug', '', implode(',', $this->post->bugs));
return $bugs;
}
/**
* Delete a linked bug.
*
* @param int $bugID
* @param int $deleteBug
* @access public
* @return array
*/
public function deleteLinkedBug($bugID, $deleteBug = 0)
{
$bug = $this->getById($bugID);
$bugs = explode(',', trim($bug->linkBug, ','));
foreach($bugs as $key => $bugId)
{
if($bugId == $deleteBug) unset($bugs[$key]);
}
$bugs = implode(',', $bugs);
$this->dao->update(TABLE_BUG)->set('linkBug')->eq($bugs)->where('id')->eq($bugID)->exec();
if(dao::isError()) die(js::error(dao::getError()));
$this->loadModel('action')->create('bug', $bugID, 'unLinkedBug', '', $deleteBug);
return $this->getLinkedBugs($bugs);
}
/**
* Get linked bugs.
*
* @param string $bugs
* @access public
* @return array
*/
public function getLinkedBugs($bugs)
{
return $this->dao->select('id, title')->from(TABLE_BUG)->where('id')->in($bugs)->fetchPairs();
}
/**
* Build search form.
*

View File

@@ -230,9 +230,25 @@ js::set('oldResolvedBuild' , $bug->resolvedBuild);
<fieldset>
<legend><?php echo $lang->bug->legendMisc;?></legend>
<table class='table table-form'>
<tr>
<tr class='text-top'>
<th class='w-80px'><?php echo $lang->bug->linkBug;?></th>
<td><?php echo html::input('linkBug', $bug->linkBug, 'class="form-control"');?></td>
<td id='linkBugBox'>
<ul class='list-unstyled'>
<?php echo html::a($this->createLink('bug', 'linkBugs', "bugID=$bug->id&bugs=$bug->linkBug", '', true), $lang->bug->linkBugs, '', "class='iframe' data-width='85%'");?>
<?php
if(isset($bug->linkBugTitles))
{
foreach($bug->linkBugTitles as $linkBugID => $linkBugTitle)
{
echo '<li>';
echo html::a(inlink('view', "bugID=$linkBugID"), "#$linkBugID " . $linkBugTitle);
echo html::a("javascript:deleteLinkedBug($bug->id, $linkBugID)", '<i class="icon-remove"></i>', '', "title='{$lang->unlink}' style='float:right'");
echo '</li>';
}
}
?>
</ul>
</td>
</tr>
<?php if($bug->case):?>
<tr>

View File

@@ -0,0 +1,74 @@
<?php
/**
* The link bug view of bug module of ZenTaoPMS.
*
* @copyright Copyright 2009-2015 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author Fei Chen <chenfei@cnezsoft.com>
* @package bug
* @version $Id: linkbugs.html.php 4129 2016-03-08 09:00:12Z chenfei $
* @link http://www.zentao.net
*/
?>
<?php include '../../common/view/header.html.php';?>
<div class='container'>
<div id='titlebar'>
<div class='heading'>
<span class='prefix'><?php echo html::icon($lang->icons['bug']);?> <strong><?php echo $bug->id;?></strong></span>
<strong><?php echo html::a($this->createLink('bug', 'view', "bugID=$bug->id"), $bug->title, '_blank');?></strong>
<small class='text-muted'> <?php echo $lang->bug->linkBugs;?> <?php echo html::icon($lang->icons['link']);?></small>
</div>
<div id='querybox' class='show'></div>
</div>
<form method='post' class='form-condensed' target='hiddenwin' id='linkBugsForm'>
<table class='table table-condensed table-hover table-striped tablesorter' id='bugList'>
<?php if($allBugs):?>
<thead>
<tr>
<th class='w-id'><?php echo $lang->idAB;?></th>
<th class='w-pri'><?php echo $lang->priAB;?></th>
<th><?php echo $lang->bug->product;?></th>
<th><?php echo $lang->bug->title;?></th>
<th><?php echo $lang->bug->statusAB;?></th>
<th class='w-user'><?php echo $lang->openedByAB;?></th>
<th class='w-user'><?php echo $lang->assignedToAB;?></th>
</tr>
</thead>
<tbody>
<?php $bugCount = 0;?>
<?php foreach($allBugs as $bugDetail):?>
<?php if(in_array($bugDetail->id, explode(',', $bug->linkBug))) continue;?>
<?php if($bugDetail->id == $bug->id) continue;?>
<?php $bugLink = $this->createLink('bug', 'view', "bugID=$bugDetail->id");?>
<tr class='text-center'>
<td class='text-left'>
<input type='checkbox' name='bugs[]' value='<?php echo $bugDetail->id;?>'/>
<?php echo html::a($bugLink, sprintf('%03d', $bugDetail->id));?>
</td>
<td><span class='<?php echo 'pri' . zget($lang->bug->priList, $bugDetail->pri, $bugDetail->pri)?>'><?php echo zget($lang->bug->priList, $bugDetail->pri, $bugDetail->pri);?></span></td>
<td><?php echo html::a($this->createLink('product', 'browse', "productID=$bugDetail->product&branch=$bugDetail->branch"), $products[$bugDetail->product], '_blank');?></td>
<td class='text-left nobr' title="<?php echo $bugDetail->title?>"><?php echo html::a($bugLink, $bugDetail->title);?></td>
<td><?php echo $lang->bug->statusList[$bug->status];?></td>
<td><?php echo $users[$bugDetail->openedBy];?></td>
<td><?php echo $users[$bugDetail->assignedTo];?></td>
</tr>
<?php $bugCount ++;?>
<?php endforeach;?>
</tbody>
<tfoot>
<tr>
<td colspan='7' class='text-left'>
<div class='table-actions clearfix'>
<?php if($bugCount) echo html::selectButton() . html::submitButton();?>
</div>
</td>
</tr>
</tfoot>
<?php endif;?>
</table>
</form>
</div>
<script type='text/javascript'>
$(function(){ajaxGetSearchForm();});
</script>
<?php include '../../common/view/footer.html.php';?>

View File

@@ -279,10 +279,13 @@
</div>
<div class='tab-pane' id='legendMisc'>
<table class='table table-data table-condensed table-borderless table-fixed'>
<?php if($bug->case):?>
<tr>
<th class='w-60px'><?php echo $lang->bug->fromCase;?></th>
<td><?php if($bug->case) echo html::a($this->createLink('testcase', 'view', "caseID=$bug->case"), "#$bug->case $bug->caseTitle", '_blank');?></td>
<td><?php echo html::a($this->createLink('testcase', 'view', "caseID=$bug->case"), "#$bug->case $bug->caseTitle", '_blank');?></td>
</tr>
<?php endif;?>
<?php if($bug->toCases):?>
<tr>
<th><?php echo $lang->bug->toCase;?></th>
<td>
@@ -294,8 +297,9 @@
?>
</td>
</tr>
<tr>
<th><?php echo $lang->bug->linkBug;?></th>
<?php endif;?>
<tr class='text-top'>
<th class='w-60px'><?php echo $lang->bug->linkBug;?></th>
<td>
<?php
if(isset($bug->linkBugTitles))
@@ -308,14 +312,18 @@
?>
</td>
</tr>
<?php if($bug->toStory != 0):?>
<tr>
<th><?php echo $lang->bug->toStory;?></th>
<td><?php if($bug->toStory != 0) echo html::a($this->createLink('story', 'view', "storyID=$bug->toStory"), "#$bug->toStory $bug->toStoryTitle", '_blank');?></td>
<td><?php echo html::a($this->createLink('story', 'view', "storyID=$bug->toStory"), "#$bug->toStory $bug->toStoryTitle", '_blank');?></td>
</tr>
<?php endif;?>
<?php if($bug->toTask != 0):?>
<tr>
<th><?php echo $lang->bug->toTask;?></th>
<td><?php if($bug->toTask != 0) echo html::a($this->createLink('task', 'view', "taskID=$bug->toTask"), "#$bug->toTask $bug->toTaskTitle", '_blank');?></td>
<td><?php echo html::a($this->createLink('task', 'view', "taskID=$bug->toTask"), "#$bug->toTask $bug->toTaskTitle", '_blank');?></td>
</tr>
<?php endif;?>
</table>
</div>
</div>

View File

@@ -916,52 +916,37 @@ class story extends control
*/
public function linkStory($storyID, $type = '', $stories = '', $browseType = '', $param = 0)
{
/* Get story, product, and products. */
$story = $this->story->getById($storyID);
$product = $this->product->getById($story->product);
$products = $this->product->getPairs();
/* Set menu. */
$this->product->setMenu($products, $product->id, $story->branch);
$queryID = ($browseType == 'bySearch') ? (int)$param : 0;
$browseLink = $this->createLink('story', 'edit', "storyID=$storyID");
$branches = $product->type != 'normal' ? $this->loadModel('branch')->getPairs($story->product) : array();
$this->commonAction($storyID);
/* Link stories. */
if(!empty($_POST))
{
$stories = $this->story->linkStories($storyID, $type, $stories);
if(isonlybody()) die(js::closeModal('parent.parent', '', "function(){parent.parent.loadLinkedStories('$storyID', '$type', '$stories')}"));
die(js::locate($browseLink, 'parent'));
die(js::locate($this->createLink('story', 'edit', "storyID=$storyID"), 'parent'));
}
/* Get story, product, products, and queryID. */
$story = $this->story->getById($storyID);
$products = $this->product->getPairs();
$queryID = ($browseType == 'bySearch') ? (int)$param : 0;
/* Build search form. */
$actionURL = $this->createLink('story', 'linkStory', "storyID=$storyID&type=$type&stories=$stories&browseType=bySearch&queryID=myQueryID", '', true);
$this->loadModel('product')->buildSearchForm($story->product, $products, $queryID, $actionURL);
$this->loadModel('search')->setSearchParams($this->config->product->search);
/* Get stories to link. */
if($browseType == 'bySearch')
{
$allStories = $this->story->getBySearch($story->product, $queryID, 'id', null);
}
else
{
$allStories = $this->story->getProductStories($story->product);
}
$allStories = array();
if($browseType == 'bySearch') $allStories = $this->story->getBySearch($story->product, $queryID, 'id', null);
/* Assign. */
$this->view->title = $this->lang->story->linkStory;
$this->view->position[] = html::a($browseLink, $story->title);
$this->view->position[] = $this->lang->story->linkStory;
$this->view->product = $product;
$this->view->products = $products;
$this->view->branches = $branches;
$this->view->type = $type;
$this->view->story = $story;
$this->view->allStories = $allStories;
$this->view->users = $this->loadModel('user')->getPairs('noletter');
$this->view->title = $this->lang->story->linkStory . "STORY" . $this->lang->colon .$this->lang->story->linkStory;
$this->view->position[] = $this->lang->story->linkStory;
$this->view->type = $type;
$this->view->allStories = $allStories;
$this->view->users = $this->loadModel('user')->getPairs('noletter');
$this->display();
}

View File

@@ -1,2 +1,3 @@
.col-side .chosen-container .chosen-drop {width: 216px!important}
.col-side .chosen-container {width: 218px!important}
#linkStoriesBox > .list-unstyled > li ,#childStoriesBox > .list-unstyled > li {margin-left:-56px}

View File

@@ -14,13 +14,15 @@
<div class='container'>
<div id='titlebar'>
<div class='heading' style='margin-bottom: 15px'>
<span class='prefix'><?php echo html::icon($lang->icons['story']);?></span>
<strong><small><?php echo html::icon($lang->icons['link']);?></small> <?php echo $lang->story->linkStory;?></strong>
<span class='prefix'><?php echo html::icon($lang->icons['story']);?> <strong><?php echo $story->id;?></strong></span>
<strong><?php echo html::a($this->createLink('story', 'view', "storyID=$story->id"), $story->title);?></strong>
<small><?php echo $lang->story->linkStory;?></small>
</div>
<div id='querybox' class='show'></div>
</div>
<form method='post' class='form-condensed' target='hiddenwin' id='linkStoryForm'>
<table class='table table-form'>
<table class='table table-condensed table-hover table-striped tablesorter table-fixed' id='storyList'>
<?php if($allStories):?>
<thead>
<tr>
<th class='w-id'><?php echo $lang->idAB;?></th>
@@ -28,9 +30,6 @@
<th><?php echo $lang->story->product;?></th>
<th><?php echo $lang->story->title;?></th>
<th><?php echo $lang->story->plan;?></th>
<?php if($product->type != 'normal'):?>
<th><?php echo $lang->product->branchName[$product->type];?></th>
<?php endif;?>
<th class='w-user'><?php echo $lang->openedByAB;?></th>
<th class='w-80px'><?php echo $lang->story->estimateAB;?></th>
</tr>
@@ -39,20 +38,17 @@
<?php $storyCount = 0;?>
<?php foreach($allStories as $storyDetail):?>
<?php if(in_array($storyDetail->id, explode(',', $story->$type))) continue;?>
<?php if($storyDetail->id == $story->id) continue;?>
<?php $storyLink = $this->createLink('story', 'view', "storyID=$storyDetail->id");?>
<tr class='text-center'>
<td class='text-left'>
<input type='checkbox' name='stories[]' value='<?php echo $storyDetail->id;?>'/>
<input type='hidden' name='products[]' value='<?php echo $storyDetail->product;?>'/>
<?php echo html::a($storyLink, sprintf('%03d', $storyDetail->id));?>
</td>
<td><span class='<?php echo 'pri' . zget($lang->story->priList, $storyDetail->pri, $storyDetail->pri)?>'><?php echo zget($lang->story->priList, $storyDetail->pri, $storyDetail->pri);?></span></td>
<td><?php echo html::a($this->createLink('product', 'browse', "productID=$storyDetail->product&branch=$storyDetail->branch"), $products[$storyDetail->product], '_blank');?></td>
<td class='text-left nobr' title="<?php echo $storyDetail->title?>"><?php echo html::a($storyLink, $storyDetail->title, '_blank');?></td>
<td><?php echo $storyDetail->planTitle;?></td>
<?php if($product->type != 'normal'):?>
<td><?php if(isset($branches[$storyDetail->branch])) echo $branches[$storyDetail->branch];?></td>
<?php endif;?>
<td><?php echo $users[$storyDetail->openedBy];?></td>
<td><?php echo $storyDetail->estimate;?></td>
</tr>
@@ -60,14 +56,15 @@
<?php endforeach;?>
</tbody>
<tfoot>
<tr>
<td colspan='<?php echo $product->type == 'normal' ? '7' :'8';?>' class='text-left'>
<div class='table-actions clearfix'>
<?php if($storyCount) echo html::selectButton() . html::submitButton();?>
</div>
</td>
</tr>
<tr>
<td colspan='7' class='text-left'>
<div class='table-actions clearfix'>
<?php if($storyCount) echo html::selectButton() . html::submitButton();?>
</div>
</td>
</tr>
</tfoot>
<?php endif;?>
</table>
</form>
</div>

View File

@@ -620,6 +620,112 @@ class testcase extends control
die(js::locate($this->session->caseList));
}
/**
* Link related cases.
*
* @param int $caseID
* @param string $cases
* @param string $browseType
* @param int $param
* @access public
* @return void
*/
public function linkCases($caseID, $cases, $browseType = '', $param = 0)
{
/* Link cases. */
if(!empty($_POST))
{
$cases = $this->testcase->linkCases($caseID, $cases);
if(isonlybody()) die(js::closeModal('parent.parent', '', "function(){parent.parent.loadLinkedCases('$caseID', '$cases')}"));
die($this->locate(inlink('edit', "caseID=$caseID"), 'parent'));
}
/* Get test cases, and queryID. */
$case = $this->testcase->getById($caseID);
$queryID = ($browseType == 'bysearch') ? (int)$param : 0;
/* Set menu. */
$this->testcase->setMenu($this->products, $case->product, $case->branch);
/* Get cases to link. */
$allCases = array();
$allCases = $this->testcase->getBySearch($case->product, $queryID, 'id', null);
/* Build the search form. */
$actionURL = $this->createLink('testcase', 'linkCases', "caseID=$caseID&cases=$cases&browseType=bySearch&queryID=myQueryID" );
$this->testcase->buildSearchForm($case->product, $this->products, $queryID, $actionURL);
$this->loadModel('search')->setSearchParams($this->config->testcase->search);
/* Assign. */
$this->view->title = $case->title . $this->lang->colon . $this->lang->testcase->linkCases;
$this->view->position[] = html::a($this->createLink('product', 'view', "productID=$case->product"), $this->products[$case->product]);
$this->view->position[] = html::a($this->createLink('testcase', 'view', "caseID=$caseID"), $case->title);
$this->view->position[] = $this->lang->testcase->linkCases;
$this->view->case = $case;
$this->view->allCases = $allCases;
$this->view->users = $this->loadModel('user')->getPairs('noletter');
$this->display();
}
/**
* AJAX: Get linked cases.
*
* @param int $caseID
* @param string $cases
* @access public
* @return string
*/
public function ajaxGetLinkedCases($caseID, $linkedCases = '')
{
/* Get case and linked cases. */
$case = $this->testcase->getById($caseID);
$cases = $this->testcase->getLinkedCases($linkedCases);
/* Build linkCase list. */
$output = "<ul class='list-unstyled'>";
$output .= html::a($this->createLink('testcase', 'linkCases', "caseID=$caseID&cases=$case->linkCase", '', true), $this->lang->testcase->linkCases, '', "class='iframe' data-width='85%'");
foreach($cases as $caseId => $caseTitle)
{
$output .= '<li>';
$output .= html::a(inlink('view', "caseID=$caseId"), "#$caseId " . $caseTitle);
$output .= html::a("javascript:deleteLinkedCase($caseID, $caseId)", '<i class="icon-remove"></i>', '', "title='{$this->lang->unlink}' style='float:right'");
$output .= '</li>';
}
$output .= '</ul>';
die($output);
}
/**
* AJAX: Delete linked case.
*
* @param int $caseID
* @param int $deleteCase
* @access public
* @return string
*/
public function ajaxDeleteLinkedCase($caseID, $deleteCase = 0)
{
/* Get case and linked cases. */
$case = $this->testcase->getById($caseID);
$cases = $this->testcase->deleteLinkedCase($caseID, $deleteCase);
/* Build linkCase list. */
$output = "<ul class='list-unstyled'>";
$output .= html::a($this->createLink('testcase', 'linkCases', "caseID=$caseID&cases=$cases", '', true), $this->lang->testcase->linkCases, '', "class='iframe' data-width='85%'");
foreach($cases as $caseId => $caseTitle)
{
$output .= '<li>';
$output .= html::a(inlink('view', "caseID=$caseId"), "#$caseId " . $caseTitle);
$output .= html::a("javascript:deleteLinkedCase($caseID, $caseId)", '<i class="icon-remove"></i>', '', "title='{$this->lang->unlink}' style='float:right'");
$output .= '</li>';
}
$output .= '</ul>';
die($output);
}
/**
* Confirm testcase changed.
*

View File

@@ -2,3 +2,4 @@
.col-side .chosen-container {width: 218px!important}
.table-form > tbody > tr > td .btn.addbutton {display:block; margin:1px 0px; width:40px; padding:1px 6px;}
.table-form > tbody > tr > td .btn.delbutton {display:block; margin:1px 0px; width:40px; padding:1px 6px;}
#linkCaseBox > .list-unstyled > li {margin-left:-56px}

View File

@@ -17,3 +17,32 @@ $(document).ready(function()
{
$("#story").chosen(defaultChosenOptions);
});
/**
* Delete linked case.
*
* @param int $caseID
* @param int $deleteCase
* @access public
* @return void
*/
function deleteLinkedCase(caseID, deleteCase)
{
deleteLink = createLink('testcase', 'ajaxDeleteLinkedCase', 'caseID=' + caseID + '&deleteCase=' + deleteCase);
$('#linkCaseBox').load(deleteLink);
}
/**
* Load linked cases.
*
* @param int $caseID
* @param string $linkedCases
* @access public
* @return void
*/
function loadLinkedCases(caseID, linkedCases)
{
caseLink = createLink('testcase', 'ajaxGetLinkedCases', 'caseID=' + caseID + '&linkedCases=' + linkedCases);
$('#linkCaseBox').load(caseLink);
}

View File

@@ -38,6 +38,7 @@ $lang->testcase->scriptedDate = 'Scripted date';
$lang->testcase->scriptedStatus = 'Scripted status';
$lang->testcase->scriptedLocation = 'Script location';
$lang->testcase->linkCase = 'Related cases';
$lang->testcase->linkCases = 'Link cases';
$lang->testcase->stage = 'Stage';
$lang->testcase->lastEditedByAB = 'Last edited by';
$lang->testcase->lastEditedDateAB = 'Last edited date';
@@ -164,3 +165,7 @@ $lang->testcase->noFunction = 'Iconv and mb_convert_encoding does not exist, yo
$lang->testcase->noRequire = "In the row of %s, the %s is a required field";
$lang->testcase->searchStories = 'Type to search stories';
$lang->testcase->action = new stdclass();
$lang->testcase->action->linked2case = array('main' => '$date, linked related cases <strong>$extra</strong> by <strong>$actor</strong>.');
$lang->testcase->action->unlinkedcase = array('main' => '$date, removed related cases <strong>$extra</strong> by <strong>$actor</strong>.');

View File

@@ -38,6 +38,7 @@ $lang->testcase->scriptedDate = '编写日期';
$lang->testcase->scriptedStatus = '脚本状态';
$lang->testcase->scriptedLocation = '脚本位置';
$lang->testcase->linkCase = '相关用例';
$lang->testcase->linkCases = '关联用例';
$lang->testcase->stage = '适用阶段';
$lang->testcase->lastEditedByAB = '修改者';
$lang->testcase->lastEditedDateAB = '修改日期';
@@ -164,3 +165,7 @@ $lang->testcase->noFunction = '不存在iconv和mb_convert_encoding转码方法
$lang->testcase->noRequire = "%s行的“%s”是必填字段不能为空";
$lang->testcase->searchStories = '键入来搜索需求';
$lang->testcase->action = new stdclass();
$lang->testcase->action->linked2case = array('main' => '$date, 由 <strong>$actor</strong> 关联相关用例 <strong>$extra</strong>。');
$lang->testcase->action->unlinkedcase = array('main' => '$date, 由 <strong>$actor</strong> 移除相关用例 <strong>$extra</strong>。');

View File

@@ -437,6 +437,64 @@ class testcaseModel extends model
}
}
/**
* Link cases.
*
* @param int $caseID
* @param string $cases
* @access public
* @return array
*/
public function linkCases($caseID, $cases = '')
{
if($this->post->cases == false) return $cases;
$cases = implode(',', $this->post->cases) . ',' . trim($cases, ',');
$this->dao->update(TABLE_CASE)->set('linkCase')->eq(trim($cases, ','))->where('id')->eq($caseID)->exec();
if(dao::isError()) die(js::error(dao::getError()));
$this->loadModel('action')->create('case', $caseID, 'linked2Case', '', implode(',', $this->post->cases));
return $cases;
}
/**
* Delete linked case.
*
* @param int $caseID
* @param int $deleteCase
* @access public
* @return array
*/
public function deleteLinkedCase($caseID, $deleteCase = 0)
{
$case = $this->getById($caseID);
$cases = explode(',', trim($case->linkCase, ','));
foreach($cases as $key => $caseId)
{
if($caseId == $deleteCase) unset($cases[$key]);
}
$cases = implode(',', $cases);
$this->dao->update(TABLE_CASE)->set('linkCase')->eq($cases)->where('id')->eq($caseID)->exec();
if(dao::isError()) die(js::error(dao::getError()));
$this->loadModel('action')->create('case', $caseID, 'unLinkedCase', '', $deleteCase);
return $this->getLinkedCases($cases);
}
/**
* Get linked cases.
*
* @param string $cases
* @access public
* @return array
*/
public function getLinkedCases($cases)
{
return $this->dao->select('id, title')->from(TABLE_CASE)->where('id')->in($cases)->fetchPairs();
}
/**
* Batch update testcases.
*

View File

@@ -140,9 +140,25 @@
<th><?php echo $lang->testcase->keywords;?></th>
<td><?php echo html::input('keywords', $case->keywords, 'class=form-control');?></td>
</tr>
<tr>
<tr class='text-top'>
<th><?php echo $lang->testcase->linkCase;?></th>
<td><?php echo html::input('linkCase', $case->linkCase, 'class=form-control');?></td>
<td id='linkCaseBox'>
<ul class='list-unstyled'>
<?php echo html::a($this->createLink('testcase', 'linkCases', "caseID=$case->id&case=$case->linkCase", '', true), $lang->testcase->linkCases, '', "class='iframe' data-width='85%'");?>
<?php
if(isset($case->linkCaseTitles))
{
foreach($case->linkCaseTitles as $linkCaseID => $linkCaseTitle)
{
echo '<li>';
echo html::a($this->createLink('testcase', 'view', "caseID=$linkCaseID"), "#$linkCaseID $linkCaseTitle", '_blank');
echo html::a("javascript:deleteLinkedCase($case->id, $linkCaseID)", '<i class="icon-remove"></i>', '', "style='float:right'");
echo '</li>';
}
}
?>
</ul>
</td>
</tr>
</table>
</fieldset>

View File

@@ -0,0 +1,70 @@
<?php
/**
* The linkcases view file of testcase module of ZenTaoPMS.
*
* @copyright Copyright 2009-2015 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author Fei Chen <chenfei@cnezsoft.com>
* @package testcase
* @version $Id: linkcases.html.php 4411 2016-03-09 11:02:04Z Chen Fei $
* @link http://www.zentao.net
*/
?>
<?php include '../../common/view/header.html.php';?>
<?php include '../../common/view/tablesorter.html.php';?>
<div id='titlebar'>
<div class='heading'>
<span class='prefix'><?php echo html::icon($lang->icons['testcase']);?> <strong><?php echo $case->id;?></strong></span>
<strong><?php echo html::a($this->createLink('case', 'view', 'caseID=' . $case->id), $case->title, '_blank');?></strong>
<small class='text-muted'> <?php echo $lang->testcase->linkCases;?> <?php echo html::icon($lang->icons['link']);?></small>
</div>
<div id='querybox' class='show'></div>
</div>
<form method='post' class='form-condensed' target='hiddenwin' id='linkCasesForm'>
<table class='table table-condensed table-hover table-striped tablesorter' id='caseList'>
<?php if($allCases):?>
<thead>
<tr>
<th class='w-id'><?php echo $lang->idAB;?></th>
<th class='w-pri'><?php echo $lang->priAB;?></th>
<th><?php echo $lang->testcase->title;?></th>
<th class='w-type'><?php echo $lang->testcase->type;?></th>
<th class='w-user'><?php echo $lang->openedByAB;?></th>
<th class='w-status'><?php echo $lang->statusAB;?></th>
</tr>
</thead>
<tbody>
<?php $caseCount = 0;?>
<?php foreach($allCases as $caseDetail):?>
<?php if(in_array($caseDetail->id, explode(',', $case->linkCase))) continue;?>
<?php if($caseDetail->id == $case->id) continue;?>
<tr class='text-center'>
<td class='text-left'>
<input type='checkbox' name='cases[]' value='<?php echo $caseDetail->id;?>' />
<?php echo html::a($this->createLink('testcase', 'view', "testcaseID=$caseDetail->id"), sprintf('%03d', $caseDetail->id));?>
</td>
<td><span class='<?php echo 'pri' . zget($lang->testcase->priList, $caseDetail->pri, $caseDetail->pri)?>'><?php echo zget($lang->testcase->priList, $caseDetail->pri, $caseDetail->pri)?></span></td>
<td class='text-left'><?php echo html::a($this->createLink('testcase', 'view', "caseID=$caseDetail->id"), $caseDetail->title, '_blank');?></td>
<td><?php echo $lang->testcase->typeList[$caseDetail->type];?></td>
<td><?php echo $users[$caseDetail->openedBy];?></td>
<td class='case-<?php echo $caseDetail->status?>'><?php echo $lang->testcase->statusList[$caseDetail->status];?></td>
</tr>
<?php $caseCount ++;?>
<?php endforeach;?>
</tbody>
<tfoot>
<tr>
<td colspan='7'>
<div class='table-actions clearfix'>
<?php if($caseCount) echo html::selectButton() . html::submitButton();?>
</div>
</td>
</tr>
</tfoot>
<?php endif;?>
</table>
</form>
<script type='text/javascript'>
$(function(){ajaxGetSearchForm();});
</script>
<?php include '../../common/view/footer.html.php';?>

View File

@@ -231,10 +231,13 @@
<fieldset>
<legend><?php echo $lang->testcase->legendLinkBugs;?></legend>
<table class='table table-data table-condensed table-borderless'>
<?php if($case->fromBug):?>
<tr>
<th class='w-60px'><?php echo $lang->testcase->fromBug;?></th>
<td><?php if($case->fromBug) echo html::a($this->createLink('bug', 'view', "bugID=$case->fromBug"), $case->fromBugTitle);?></td>
<td><?php echo html::a($this->createLink('bug', 'view', "bugID=$case->fromBug"), $case->fromBugTitle);?></td>
</tr>
<?php endif;?>
<?php if($case->toBugs):?>
<tr>
<th valign="top"><?php echo $lang->testcase->toBug;?></th>
<td>
@@ -246,6 +249,7 @@
?>
</td>
</tr>
<?php endif;?>
</table>
</fieldset>

File diff suppressed because one or more lines are too long

4
www/js/kindeditor/themes/default/default.css Executable file → Normal file

File diff suppressed because one or more lines are too long

View File

@@ -686,13 +686,20 @@ body {font-size: 13px; color:#141414;padding-bottom: 40px;}
#searchbox {display: none}
}
.fixedTfootAction{position: fixed; bottom: 40px; background: #fff; border-top: 1px solid #bbb}
.fixedTheadOfList{position: fixed; top: 0px; z-index:10;}
.warning{color:red;}
.nofixed td{white-space:normal;}
#passwordStrength{display:none;}
.datatable.head-fixed > .datatable-head .table > thead > tr > th {background-color: #fff; border-bottom-color: #bbb}
.fixedTfootAction {position: fixed; bottom: 40px; box-shadow: 0 -3px 4px rgba(0,0,0,0.05)}
.table > .fixedTfootAction > tr > td {background: #F8FAFE; border-top-color: #bbb}
.fixedTheadOfList {position: fixed; top: 0px; z-index:10;}
.datatable.head-fixed > .datatable-head .table > thead > tr > th, .fixedTheadOfList > thead > tr > th {background-color: #114f8e; border-bottom-color: #bbb; color: #aaa}
.tablesorter.fixedTheadOfList thead tr .headerSortUp > a:after,
.tablesorter.fixedTheadOfList thead tr .headerSortDown > a:after,
.tablesorter.datatable.head-fixed thead tr .headerSortUp > a:after,
.tablesorter.datatable.head-fixed thead tr .headerSortDown > a:after,
.datatable.head-fixed > .datatable-head .table > thead > tr > th a, .fixedTheadOfList > thead > tr > th a {color: #fff}
.datatable.head-fixed > .datatable-head .table > thead > tr > th .header a, .fixedTheadOfList > thead > tr > th .header a {color: #ccc}

File diff suppressed because one or more lines are too long