Merge branch 'master' of https://gitlab.zcorp.cc/easycorp/zentaopms into sprint/master_lanzongjun_fixbug

This commit is contained in:
Zongjun Lan
2022-04-22 08:47:36 +08:00
33 changed files with 372 additions and 235 deletions
+1 -1
View File
@@ -54,7 +54,7 @@ class storiesEntry extends entry
if(!$productID and isset($this->requestBody->product)) $productID = $this->requestBody->product;
if(!$productID) return $this->sendError(400, 'Need product id.');
$fields = 'title,spec,verify,reviewer,type,parent,plan,module,moduleOptionMenu,source,sourceNote,category,pri,estimate,mailto,keywords,notifyemail,uid';
$fields = 'title,spec,verify,reviewer,type,parent,plan,module,moduleOptionMenu,source,sourceNote,category,pri,estimate,mailto,keywords,notifyemail,uid,URS';
$this->batchSetPost($fields);
/* If reviewer is not post, set needNotReview. */
+3 -1
View File
@@ -753,7 +753,9 @@ class branchModel extends model
->andWhere('product')->eq($productID)
->fetchGroup('project');
$this->dao->delete()->from(TABLE_PROJECTPRODUCT)->where('branch')->in($mergedBranches . ",$targetBranch")->exec();
$this->dao->delete()->from(TABLE_PROJECTPRODUCT)->where('branch')->in($mergedBranches . ",$targetBranch")
->andWhere('product')->eq($productID)
->exec();
foreach($linkedProject as $projectID => $projectProducts)
{
$plan = 0;
+1 -1
View File
@@ -341,7 +341,7 @@ function loadExecutionRelated(executionID)
loadExecutionTasks(executionID);
loadExecutionStories(executionID);
loadExecutionBuilds(executionID);
loadAssignedTo(executionID);
loadAssignedTo(executionID, $('#assignedTo').val());
loadTestTasks($('#product').val(), executionID);
}
else
+6 -1
View File
@@ -145,7 +145,12 @@ if($this->app->tab == 'project') js::set('objectID', $bug->project);
</tr>
<tr>
<th><?php echo $lang->bug->assignedTo;?></th>
<td><?php echo html::select('assignedTo', $users, $bug->assignedTo, "class='form-control chosen'");?></td>
<td>
<div class='input-group'>
<?php echo html::select('assignedTo', $users, $bug->assignedTo, "class='form-control chosen'");?>
<span class='input-group-btn'><?php echo html::commonButton($lang->bug->allUsers, "class='btn btn-default' onclick='loadAllUsers()' data-toggle='tooltip'");?></span>
</div>
</td>
</tr>
<tr>
<th><?php echo $lang->bug->deadline;?></th>
+1
View File
@@ -20,3 +20,4 @@
.doc-fullscreen .fullscreen-btn > .icon-fullscreen:before {content: '\e972';}
.right-icon a {color: #1183fb;}
.cell th,td {word-break: break-word;}
.main-actions {width: 100% !important;}
+6
View File
@@ -129,3 +129,9 @@ $config->execution->kanbanSetting->colorList['pause'] = '#fdc137';
$config->execution->kanbanSetting->colorList['done'] = '#0BD986';
$config->execution->kanbanSetting->colorList['cancel'] = '#CBD0DB';
$config->execution->kanbanSetting->colorList['closed'] = '#838A9D';
$config->execution->gantt = new stdclass();
$config->execution->gantt->linkType['end']['begin'] = 0;
$config->execution->gantt->linkType['begin']['begin'] = 1;
$config->execution->gantt->linkType['end']['end'] = 2;
$config->execution->gantt->linkType['begin']['end'] = 3;
+12
View File
@@ -477,4 +477,16 @@ $lang->execution->statusColorList['doing'] = '#0BD986';
$lang->execution->statusColorList['suspended'] = '#fdc137';
$lang->execution->statusColorList['closed'] = '#838A9D';
if(!isset($lang->execution->gantt)) $lang->execution->gantt = new stdclass();
$lang->execution->gantt->color[0] = 'bbb';
$lang->execution->gantt->color[1] = 'ff5d5d';
$lang->execution->gantt->color[2] = 'ff9800';
$lang->execution->gantt->color[3] = '16a8f8';
$lang->execution->gantt->color[4] = '00da88';
$lang->execution->gantt->exportImg = 'Export as Image';
$lang->execution->gantt->exportPDF = 'Export as PDF';
$lang->execution->gantt->exporting = 'Exporting...';
$lang->execution->gantt->exportFail = 'Failed to export.';
$lang->execution->boardColorList = array('#32C5FF', '#006AF1', '#9D28B2', '#FF8F26', '#7FBB00', '#424BAC', '#66c5f8', '#EC2761');
+12
View File
@@ -477,4 +477,16 @@ $lang->execution->statusColorList['doing'] = '#0BD986';
$lang->execution->statusColorList['suspended'] = '#fdc137';
$lang->execution->statusColorList['closed'] = '#838A9D';
if(!isset($lang->execution->gantt)) $lang->execution->gantt = new stdclass();
$lang->execution->gantt->color[0] = 'bbb';
$lang->execution->gantt->color[1] = 'ff5d5d';
$lang->execution->gantt->color[2] = 'ff9800';
$lang->execution->gantt->color[3] = '16a8f8';
$lang->execution->gantt->color[4] = '00da88';
$lang->execution->gantt->exportImg = '导出图片';
$lang->execution->gantt->exportPDF = '导出 PDF';
$lang->execution->gantt->exporting = '正在导出……';
$lang->execution->gantt->exportFail = '导出失败。';
$lang->execution->boardColorList = array('#32C5FF', '#006AF1', '#9D28B2', '#FF8F26', '#7FBB00', '#424BAC', '#66c5f8', '#EC2761');
+1
View File
@@ -20,3 +20,4 @@ table.diff {margin-bottom: 0px;}
.label-exchange {background-color: #566F7C; cursor: pointer;}
.label-exchange i {padding: 0;}
.btn-download {border-right: none;}
.body-modal #back {display: none;}
+1
View File
@@ -9,3 +9,4 @@ td.acl {white-space: nowrap;}
.c-openedBy ,.c-acl ,.c-prs ,.c-common {width:110px !important;}
.c-bugs ,.c-type {width:120px !important;}
.c-release {padding-right: 20px !important;}
.c-feedback {padding-right: 20px !important;}
+1
View File
@@ -563,6 +563,7 @@ class productModel extends model
if($currentModule == 'product' and strpos($this->config->product->showBranchMethod, $currentMethod) !== false) $isShowBranch = true;
if($this->app->tab == 'qa' and strpos(',testsuite,testreport,testtask,', ",$currentModule,") === false) $isShowBranch = true;
if($this->app->tab == 'qa' and $currentModule == 'testtask' and strpos(',create,edit,browseunits,importunitresult,unitcases,', ",$currentMethod,") === false) $isShowBranch = true;
if($currentModule == 'testcase' and $currentMethod == 'showimport') $isShowBranch = false;
if($isShowBranch)
{
$this->lang->product->branch = sprintf($this->lang->product->branch, $this->lang->product->branchName[$currentProduct->type]);
+1 -1
View File
@@ -37,7 +37,7 @@
</div>
</div>
<?php endif;?>
<div class="detail">
<div class="detail pm-detail">
<div class="detail-title"><strong><?php echo $lang->product->manager;?></strong></div>
<div class="detail-content">
<table class="table table-data">
+1 -1
View File
@@ -83,7 +83,7 @@ class programplan extends control
$selectCustom = $this->loadModel('setting')->getItem("owner={$owner}&module={$module}&section={$section}&key={$object}");
if(strpos($selectCustom, 'date') !== false) $dateDetails = 0;
$plans = $this->programplan->getDataForGantt($projectID, $this->productID, $baselineID);
$plans = $this->programplan->getDataForGantt($projectID, $this->productID, $baselineID, $selectCustom, false);
}
if($type == 'lists')
+24 -10
View File
@@ -169,12 +169,12 @@ class programplanModel extends model
}
$datas = array();
$planIDList = array();
$planIdList = array();
$isMilestone = "<icon class='icon icon-flag icon-sm red'></icon> ";
$stageIndex = array();
foreach($plans as $plan)
{
$planIDList[$plan->id] = $plan->id;
$planIdList[$plan->id] = $plan->id;
$start = helper::isZeroDate($plan->begin) ? '' : $plan->begin;
$end = helper::isZeroDate($plan->end) ? '' : $plan->end;
@@ -216,10 +216,7 @@ class programplanModel extends model
if(empty($selectCustom)) $selectCustom = $this->loadModel('setting')->getItem("owner={$owner}&module={$module}&section={$section}&key={$object}");
$tasks = array();
if(strpos($selectCustom, 'task') !== false)
{
$tasks = $this->dao->select('*')->from(TABLE_TASK)->where('deleted')->eq(0)->andWhere('execution')->in($planIDList)->fetchAll('id');
}
if(strpos($selectCustom, 'task') !== false) $tasks = $this->dao->select('*')->from(TABLE_TASK)->where('deleted')->eq(0)->andWhere('execution')->in($planIdList)->fetchAll('id');
if($baselineID)
{
@@ -254,10 +251,12 @@ class programplanModel extends model
$data->deadline = $end;
$data->realBegan = $realBegan;
$data->realEnd = $realEnd;
$data->pri = $task->pri;
$data->parent = $task->parent > 0 ? $task->execution . '-' . $task->parent : $task->execution;
$data->open = true;
$progress = $task->consumed ? round($task->consumed / ($task->left + $task->consumed), 3) * 100 : 0;
$data->taskProgress = $progress . '%';
$progress = $task->consumed ? round($task->consumed / ($task->left + $task->consumed), 3) : 0;
$data->progress = $progress;
$data->taskProgress = ($progress * 100) . '%';
$data->start_date = $data->realBegan ? $data->realBegan : $data->begin;
$data->endDate = $data->realEnd ? $data->realEnd : $data->deadline;
$data->duration = 0;
@@ -286,11 +285,26 @@ class programplanModel extends model
/* Calculate the progress of the phase. */
foreach($stageIndex as $index => $stage)
{
$progress = empty($stage['progress']['totalConsumed']) ? 0 : round($stage['progress']['totalConsumed'] / $stage['progress']['totalReal'], 3) * 100;
$progress .= '%';
$progress = empty($stage['progress']['totalConsumed']) ? 0 : round($stage['progress']['totalConsumed'] / $stage['progress']['totalReal'], 3);
$datas['data'][$index]->progress = $progress;
$progress = ($progress * 100) . '%';
$datas['data'][$index]->taskProgress = $progress;
}
$datas['links'] = array();
if($this->config->edition != 'open')
{
$relations = $this->dao->select('*')->from(TABLE_RELATIONOFTASKS)->where('execution')->in($planIdList)->orderBy('task,pretask')->fetchAll();
foreach($relations as $relation)
{
$link['source'] = $relation->execution . '-' . $relation->pretask;
$link['target'] = $relation->execution . '-' . $relation->task;
$link['type'] = $this->config->execution->gantt->linkType[$relation->condition][$relation->action];
$datas['links'][] = $link;
}
}
return $returnJson ? json_encode($datas) : $datas;
}
+57 -30
View File
@@ -22,11 +22,34 @@
.gantt_task_content{display: none;}
.checkbox-primary {margin-top: 0px; margin-left: 10px;}
form {display: block; margin-top: 0em; margin-block-end: 1em;}
<?php if($selectCustom == 'task'):?>
.gantt_grid .gantt_grid_scale{width:100% !important;}
.gantt_grid .gantt_grid_data{width:100% !important;}
.gantt_grid .gantt_grid_data .gantt_row{width:100% !important;}
<?php endif;?>
.gantt_task_progress {background: rgba(0,0,0,.1)}
#ganttPris > span {display: inline-block; line-height: 20px; min-width: 20px; border-radius: 2px;}
.gantt_task_line {background: #<?php echo $lang->execution->gantt->color[0]?>; border-color: #<?php echo $lang->execution->gantt->color[0]?>;}
.gantt_task_line.pri-1 {background: #<?php echo $lang->execution->gantt->color[1]?>; border-color: #<?php echo $lang->execution->gantt->color[1]?>}
.gantt_task_line.pri-2 {background: #<?php echo $lang->execution->gantt->color[2]?>; border-color: #<?php echo $lang->execution->gantt->color[2]?>}
.gantt_task_line.pri-3 {background: #<?php echo $lang->execution->gantt->color[3]?>; border-color: #<?php echo $lang->execution->gantt->color[3]?>}
.gantt_task_line.pri-4 {background: #<?php echo $lang->execution->gantt->color[4]?>; border-color: #<?php echo $lang->execution->gantt->color[4]?>}
.gantt_task_line.gantt_selected {box-shadow: 0 1px 1px rgba(0,0,0,.05), 0 2px 6px 0 rgba(0,0,0,.045)}
.gantt_link_arrow_right {border-left-color: #2196F3;}
.gantt_link_arrow_left {border-right-color: #2196F3;}
.gantt_task_link .gantt_line_wrapper div{background-color: #2196F3;}
.gantt_critical_link .gantt_line_wrapper>div {background-color: #e63030 !important;}
.gantt_critical_link.start_to_start .gantt_link_arrow_right {border-left-color: #e63030 !important;}
.gantt_critical_link.finish_to_start .gantt_link_arrow_right {border-left-color: #e63030 !important;}
.gantt_critical_link.start_to_finish .gantt_link_arrow_left {border-right-color: #e63030 !important;}
.gantt_critical_link.finish_to_finish .gantt_link_arrow_left {border-right-color: #e63030 !important;}
.gantt_task_link.start_to_start .gantt_line_wrapper div { background-color: #DD55EA; }
.gantt_task_link.start_to_start:hover .gantt_line_wrapper div { box-shadow: 0 0 5px 0px #DD55EA; }
.gantt_task_link.start_to_start .gantt_link_arrow_right { border-left-color: #DD55EA; }
.gantt_task_link.finish_to_start .gantt_line_wrapper div { background-color: #7576ba; }
.gantt_task_link.finish_to_start:hover .gantt_line_wrapper div { box-shadow: 0 0 5px 0px #7576ba; }
.gantt_task_link.finish_to_start .gantt_link_arrow_right { border-left-color: #7576ba; }
.gantt_task_link.finish_to_finish .gantt_line_wrapper div { background-color: #55d822; }
.gantt_task_link.finish_to_finish:hover .gantt_line_wrapper div { box-shadow: 0 0 5px 0px #55d822; }
.gantt_task_link.finish_to_finish .gantt_link_arrow_left { border-right-color: #55d822; }
.gantt_task_link.start_to_finish .gantt_line_wrapper div { background-color: #975000; }
.gantt_task_link.start_to_finish:hover .gantt_line_wrapper div { box-shadow: 0 0 5px 0px #975000; }
.gantt_task_link.start_to_finish .gantt_link_arrow_left { border-right-color: #975000; }
</style>
<?php js::set('customUrl', $this->createLink('programplan', 'ajaxCustom'));?>
<?php js::set('dateDetails', $dateDetails);?>
@@ -35,9 +58,15 @@ form {display: block; margin-top: 0em; margin-block-end: 1em;}
<div id='mainContent' class='main-content load-indicator' data-loading='<?php echo $lang->programplan->exporting;?>'>
<form class="main-form form-ajax">
<div class="example">
<?php echo html::commonButton($lang->programplan->full, 'id="fullScreenBtn"', 'btn btn-primary btn-sm')?>
<?php if($app->rawModule == 'review' and $app->rawMethod == 'assess') unset($lang->programplan->stageCustom->date); ?>
<?php echo html::checkbox('stageCustom', $lang->programplan->stageCustom, $selectCustom);?>
<?php echo html::commonButton($lang->programplan->full, 'id="fullScreenBtn"', 'btn btn-primary btn-sm')?>
<?php if($app->rawModule == 'review' and $app->rawMethod == 'assess') unset($lang->programplan->stageCustom->date); ?>
<?php echo html::checkbox('stageCustom', $lang->programplan->stageCustom, $selectCustom);?>
<div class='btn btn-link' id='ganttPris'>
<strong><?php echo $lang->task->pri . " : "?></strong>
<?php foreach($lang->execution->gantt->color as $pri => $color):?>
<span style="background:#<?php echo $color?>"><?php echo $pri;?></span> &nbsp;
<?php endforeach;?>
</div>
</div>
</form>
<div id='ganttContainer'>
@@ -75,15 +104,14 @@ function drawGanttToCanvas(exportType, successCallback, errorCallback)
var $ganttContainer = $('#ganttContainer');
var $ganttDataArea = $ganttView.find('.gantt_data_area');
var $ganttDridData = $ganttView.find('.gantt_grid_data');
var ganttHeight = $ganttView.find('.gantt_task_bg').outerHeight() + $ganttView.find('.gantt_grid_scale').outerHeight() + 1;
var ganttHeight = $ganttView.find('.gantt_grid_scale').outerHeight();
ganttHeight += <?php echo count($plans['data'])?> * 25;
<?php if($selectCustom == 'task'):?>
var ganttWidth = $ganttDridData.width() - 100;
var ganttHeight = $ganttView.find('.gantt_grid_scale').outerHeight();
$ganttDridData.find('.gantt_row').each(function() {ganttHeight += $(this).outerHeight();});
<?php else:?>
var ganttWidth = $ganttDataArea.outerWidth() + $ganttDridData.outerWidth();
var ganttHeight = $ganttView.find('.gantt_task_bg').outerHeight() + $ganttView.find('.gantt_grid_scale').outerHeight() + 1;
var ganttWidth = $ganttDataArea.outerWidth() + $ganttDridData.outerWidth();
<?php endif;?>
$ganttContainer.css(
@@ -245,13 +273,14 @@ function updateCriticalPath()
$("#fullScreenBtn").on("click", function()
{
$("#mainContent").css("z-index", "9999");
$("#ganttView").css("z-index", "9999");
$("#mainContent").css("z-index", "5");
$("#ganttView").css("z-index", "5");
});
function exitHandler()
{
if (module == 'review' && method == 'assess' && !document.fullscreenElement && !document.webkitIsFullScreen && !document.mozFullScreen && !document.msFullscreenElement) {
if (module == 'review' && method == 'assess' && !document.fullscreenElement && !document.webkitIsFullScreen && !document.mozFullScreen && !document.msFullscreenElement)
{
location.reload();
}
}
@@ -268,7 +297,7 @@ $(function()
$('#ganttView').css('height', Math.max(200, Math.floor($(window).height() - $('#footer').outerHeight() - $('#header').outerHeight() - $('#mainMenu').outerHeight() - 80)));
};
var ganttData = $.parseJSON(<?php echo json_encode($plans);?>);
var ganttData = $.parseJSON(<?php echo json_encode(json_encode($plans));?>);
if(!ganttData.data) ganttData.data = [];
gantt.config.readonly = true;
@@ -304,19 +333,7 @@ $(function()
if((module == 'review' && method == 'assess') || dateDetails)
{
layout = gantt.config.layout;
gantt.config.layout = {
css: "gantt_container",
cols: [
{
rows:[
{view: "grid", scrollX: "gridScroll", scrollable: true, scrollY: "scrollVer"},
{view: "scrollbar", id: "gridScroll", group:"horizontal"}
]
}
]
};
gantt.config.show_chart = false;
}
var date2Str = gantt.date.date_to_str(gantt.config.task_date);
@@ -329,11 +346,21 @@ $(function()
title: todayTips + ": " + date2Str(today)
});
gantt.templates.task_class = function(start, end, task){return 'pri-' + (task.pri || 0);};
gantt.templates.scale_cell_class = function(date)
{
if(date.getDay() == 0 || date.getDay() == 6) return 'weekend';
};
gantt.templates.link_class = function(link)
{
var types = gantt.config.links;
if(link.type == types.finish_to_start) return 'finish_to_start';
if(link.type == types.start_to_start) return 'start_to_start';
if(link.type == types.finish_to_finish) return 'finish_to_finish';
if(link.type == types.start_to_finish) return 'start_to_finish';
};
gantt.templates.timeline_cell_class = function(item, date)
{
if(date.getDay() == 0 || date.getDay() == 6) return 'weekend';
+2
View File
@@ -20,3 +20,5 @@ table.diff {margin-bottom: 0px;}
.label-exchange {background-color: #566F7C; cursor: pointer;}
.label-exchange i {padding: 0;}
.btn-download {border-right: none;}
.body-modal .repo-diff {display: none;}
.body-modal #mainMenu {padding-bottom: 40px;}
+8
View File
@@ -295,6 +295,14 @@ $(function()
$chosen.toggleClass('chosen-up', $drop.height() + $drop.offset().top - $(document).scrollTop() > $(window).height());
});
$searchForm.find('.picker-select').each(function()
{
var $select = $(this);
var pickerOptions = {chosenMode: true}
if($select.attr('data-pickertype') == 'remote') pickerOptions.remote = $select.attr('data-pickerremote');
$select.picker(pickerOptions);
});
/* Toggle user queries action. */
$('#toggle-queries').click(function()
{
+2 -2
View File
@@ -137,8 +137,8 @@ $lang->story->comment = '备注';
$lang->story->children = "子需求";
$lang->story->childrenAB = "子";
$lang->story->linkStories = "相关{$lang->SRCommon}";
$lang->story->childStories = "细分{$lang->SRCommon}";
$lang->story->duplicateStory = "重复{$lang->SRCommon}ID";
$lang->story->childStories = "细分需求";
$lang->story->duplicateStory = "重复需求ID";
$lang->story->reviewResult = '评审意见';
$lang->story->preVersion = '之前版本';
$lang->story->keywords = '关键词';
+2 -2
View File
@@ -136,8 +136,8 @@ $lang->story->comment = '備註';
$lang->story->children = "子需求";
$lang->story->childrenAB = "子";
$lang->story->linkStories = "相關{$lang->SRCommon}";
$lang->story->childStories = "細分{$lang->SRCommon}";
$lang->story->duplicateStory = "重複{$lang->SRCommon}ID";
$lang->story->childStories = "細分需求";
$lang->story->duplicateStory = "重複需求ID";
$lang->story->reviewResult = '評審意見';
$lang->story->preVersion = '之前版本';
$lang->story->keywords = '關鍵詞';
+12 -3
View File
@@ -4275,7 +4275,10 @@ class storyModel extends model
$stories[$id]->tasks = $this->loadModel('task')->getStoryTasks($id);
if($this->config->edition == 'max')
{
$stories[$id]->designs = $this->dao->select('id, name')->from(TABLE_DESIGN)->where('story')->eq($id)->fetchAll('id');
$stories[$id]->designs = $this->dao->select('id, name')->from(TABLE_DESIGN)
->where('story')->eq($id)
->andWhere('deleted')->eq('0')
->fetchAll('id');
$stories[$id]->revisions = $this->dao->select('BID, extra')->from(TABLE_RELATION)
->where('AType')->eq('design')
->andWhere('BType')->eq('commit')
@@ -4345,7 +4348,10 @@ class storyModel extends model
$stories[$id]->tasks = $this->loadModel('task')->getStoryTasks($id);
if($this->config->edition == 'max')
{
$stories[$id]->designs = $this->dao->select('id, name')->from(TABLE_DESIGN)->where('story')->eq($id)->fetchAll('id');
$stories[$id]->designs = $this->dao->select('id, name')->from(TABLE_DESIGN)
->where('story')->eq($id)
->andWhere('deleted')->eq('0')
->fetchAll('id');
$stories[$id]->revisions = $this->dao->select('BID, extra')->from(TABLE_RELATION)
->where('AType')->eq('design')
->andWhere('BType')->eq('commit')
@@ -4385,7 +4391,10 @@ class storyModel extends model
$track[$id]->task = $this->loadModel('task')->getStoryTasks($id);
if($this->config->edition == 'max')
{
$track[$id]->design = $this->dao->select('id, name')->from(TABLE_DESIGN)->where('story')->eq($id)->fetchAll('id');
$track[$id]->design = $this->dao->select('id, name')->from(TABLE_DESIGN)
->where('story')->eq($id)
->andWhere('deleted')->eq('0')
->fetchAll('id');
$track[$id]->revision = $this->dao->select('BID, extra')->from(TABLE_RELATION)->where('AType')->eq('design')->andWhere('BType')->eq('commit')->andWhere('AID')->in(array_keys($track[$id]->design))->fetchPairs();
}
}
+1 -1
View File
@@ -244,7 +244,7 @@
<table class='table table-form'>
<?php if($story->status == 'closed'):?>
<tr id='duplicateStoryBox'>
<th class='w-70px'><?php echo $lang->story->duplicateStory;?></th>
<th class='w-90px'><?php echo $lang->story->duplicateStory;?></th>
<td><?php echo html::input('duplicateStory', $story->duplicateStory == 0 ? '' : $story->duplicateStory, "class='form-control'");?></td>
</tr>
<?php endif;?>
+3 -3
View File
@@ -1913,7 +1913,7 @@ class testcase extends control
$caseLang = $this->lang->testcase;
$caseConfig = $this->config->testcase;
$branches = $this->loadModel('branch')->getPairs($productID);
$branches = $this->loadModel('branch')->getPairs($productID, 'active');
$stories = $this->loadModel('story')->getProductStoryPairs($productID, $branch);
$fields = $this->testcase->getImportFields($productID);
$fields = array_flip($fields);
@@ -2093,7 +2093,7 @@ class testcase extends control
$this->view->stories = $stories;
$this->view->modules = $modules;
$this->view->cases = $this->dao->select('id, module, story, stage, status, pri, type')->from(TABLE_CASE)->where('product')->eq($productID)->andWhere('deleted')->eq(0)->fetchAll('id');
$this->view->cases = $this->testcase->getByProduct($productID);
$this->view->caseData = $caseData;
$this->view->stepData = $stepData;
$this->view->productID = $productID;
@@ -2103,7 +2103,7 @@ class testcase extends control
$this->view->allPager = $allPager;
$this->view->pagerID = $pagerID;
$this->view->branch = $branch;
$this->view->product = $this->products[$productID];
$this->view->product = $this->product->getByID($productID);
$this->view->maxImport = $maxImport;
$this->view->dataInsert = $insert;
+2
View File
@@ -1,8 +1,10 @@
.table table td,.outer .table table tbody > tr:last-child td {padding: 2px 0 2px 5px !important; border: none !important;}
.c-branch {width: 120px;}
.c-line-number {width: 50px;}
.c-id {width: 40px;}
.c-story, .c-module, .c-type {width: 120px;}
.c-stage {width: 160px;}
.c-condition {width: 80px;}
.c-step {width: 300px;}
.form-actions .btn {margin-right: 20px;}
.table td textarea {height: 32px;}
-35
View File
@@ -27,38 +27,3 @@ $(document).ready(function()
}
});
});
/**
* Set modules.
*
* @param int $branchID
* @param int $productID
* @param int $num
* @access public
* @return void
*/
function setModules(branchID, productID, num)
{
moduleLink = createLink('tree', 'ajaxGetModules', 'productID=' + productID + '&viewType=story&branch=' + branchID + '&num=' + num);
$.get(moduleLink, function(modules)
{
if(!modules) modules = '<select id="module' + num + '" name="module[' + num + ']" class="form-control"></select>';
$('#module' + num).replaceWith(modules);
$("#module" + num + "_chosen").remove();
$("#module" + num).next('.picker').remove();
$("#module" + num).attr('onchange', "loadStories("+ productID + ", this.value, " + num + ")").chosen();
});
loadStories(productID, 0, num);
/* If the branch of the current row is inconsistent with the one below, clear the module and story of the nex row. */
var nextBranchID = $('#branch' + (num + 1)).val();
if(nextBranchID != branchID)
{
$('#module' + (num + 1)).find("option[value='ditto']").remove();
$('#module' + (num + 1)).trigger("chosen:updated");
$('#plan' + (num + 1)).find("option[value='ditto']").remove();
$('#plan' + (num + 1)).trigger("chosen:updated");
}
}
+35
View File
@@ -390,3 +390,38 @@ function loadStories(productID, moduleID, num)
}
});
}
/**
* Set modules.
*
* @param int $branchID
* @param int $productID
* @param int $num
* @access public
* @return void
*/
function setModules(branchID, productID, num)
{
moduleLink = createLink('tree', 'ajaxGetModules', 'productID=' + productID + '&viewType=story&branch=' + branchID + '&num=' + num);
$.get(moduleLink, function(modules)
{
if(!modules) modules = '<select id="module' + num + '" name="module[' + num + ']" class="form-control"></select>';
$('#module' + num).replaceWith(modules);
$("#module" + num + "_chosen").remove();
$("#module" + num).next('.picker').remove();
$("#module" + num).attr('onchange', "loadStories("+ productID + ", this.value, " + num + ")").chosen();
});
loadStories(productID, 0, num);
/* If the branch of the current row is inconsistent with the one below, clear the module and story of the nex row. */
var nextBranchID = $('#branch' + (num + 1)).val();
if(nextBranchID != branchID)
{
$('#module' + (num + 1)).find("option[value='ditto']").remove();
$('#module' + (num + 1)).trigger("chosen:updated");
$('#plan' + (num + 1)).find("option[value='ditto']").remove();
$('#plan' + (num + 1)).trigger("chosen:updated");
}
}
+12
View File
@@ -10,6 +10,12 @@ $("[name^='branch']").each(function()
$(this).attr('id', 'branch' + id.match(/\d+/));
});
$("[name^='module']").each(function()
{
var id = $(this).attr('id');
$(this).attr('id', 'module' + id.match(/\d+/));
});
$("[name^='story']").each(function()
{
var id = $(this).attr('id');
@@ -19,6 +25,7 @@ $("[name^='story']").each(function()
var moduleID = $('#module' + num).val();
var storyID = $("#story" + num).val();
var storyLink = createLink('story', 'ajaxGetProductStories', 'productID=' + productID + '&branch=' + branchID + '&moduleID=' + moduleID + '&storyID=0&onlyOption=false&status=noclosed&limit=50&type=full&hasParent=1&executionID=0&number=' + num);
$.get(storyLink, function(stories)
{
if(!stories) stories = '<select id="story' + num + '" name="story[' + num + ']" class="form-control"></select>';
@@ -29,3 +36,8 @@ $("[name^='story']").each(function()
$('#story' + num).val(storyID).trigger('chosen:updated');
});
});
$(function()
{
if(parseInt($('.c-name').css('width')) < 90) $('.c-name').css('width', '90px');
});
+15
View File
@@ -643,6 +643,21 @@ class testcaseModel extends model
return $this->appendData($cases);
}
/**
* Get cases by product id.
*
* @param int $productID
* @access public
* @return array
*/
public function getByProduct($productID)
{
return $this->dao->select('*')->from(TABLE_CASE)
->where('deleted')->eq(0)
->andWhere('product')->eq($productID)
->fetchAll('id');
}
/**
* Get cases of a story.
*
+4 -10
View File
@@ -133,21 +133,15 @@
</div>
<?php endif;?>
<?php if(empty($productID) or common::canModify('product', $product)):?>
<?php if(!empty($productID)): ?>
<?php if(!empty($productID) and (common::hasPriv('testcase', 'import') or common::hasPriv('testcase', 'importFromLib'))): ?>
<div class='btn-group'>
<button type='button' class='btn btn-link dropdown-toggle' data-toggle='dropdown' id='importAction'><i class='icon icon-import muted'></i> <?php echo $lang->import ?><span class='caret'></span></button>
<ul class='dropdown-menu pull-right' id='importActionMenu'>
<?php
$printImportBtn = (common::hasPriv('testcase', 'import') and $branch !== 'all') ? true : false;
$class = $printImportBtn ? '' : "class=disabled";
$misc = $printImportBtn ? "class='export'" : "class=disabled";
$link = $printImportBtn ? $this->createLink('testcase', 'import', "productID=$productID&branch=$branch") : '#';
echo "<li $class>" . html::a($link, $lang->testcase->fileImport, '', $misc . "data-app={$this->app->tab}") . "</li>";
if(common::hasPriv('testcase', 'import')) echo "<li>" . html::a($this->createlink('testcase', 'import', "productID=$productID&branch=$branch"), $lang->testcase->fileImport, '', "class='export' data-app={$app->tab}") . "</li>";
$class = common::hasPriv('testcase', 'importFromLib') ? '' : "class=disabled";
$misc = common::hasPriv('testcase', 'importFromLib') ? "data-app='{$this->app->tab}'" : "class=disabled";
$link = common::hasPriv('testcase', 'importFromLib') ? $this->createLink('testcase', 'importFromLib', "productID=$productID&branch=$branch&libID=0&orderBy=id_desc&browseType=&queryID=10&recTotal=0&recPerPage=20&pageID=1&projectID=$projectID") : '#';
echo "<li $class>" . html::a($link, $lang->testcase->importFromLib, '', $misc . "data-app={$this->app->tab}") . "</li>";
$link = $this->createLink('testcase', 'importFromLib', "productID=$productID&branch=$branch&libID=0&orderBy=id_desc&browseType=&queryID=10&recTotal=0&recPerPage=20&pageID=1&projectID=$projectID");
if(common::hasPriv('testcase', 'importFromLib')) echo "<li>" . html::a($link, $lang->testcase->importFromLib, '', "data-app={$app->tab}") . "</li>";
?>
</ul>
</div>
+138 -130
View File
@@ -27,140 +27,148 @@ $(function()
<h2><?php echo $lang->testcase->import;?></h2>
</div>
<form target='hiddenwin' method='post'>
<table class='table table-form' id='showData'>
<thead>
<tr>
<th class='c-line-number'><?php echo $lang->lineNumber?></th>
<th class='c-id'><?php echo $lang->idAB?></th>
<th class='required'><?php echo $lang->testcase->title?></th>
<th class='c-module'><?php echo $lang->testcase->module?></th>
<th class='c-story'><?php echo $lang->testcase->story?></th>
<th class='c-pri-box'><?php echo $lang->testcase->pri?></th>
<th class='c-type required'><?php echo $lang->testcase->type?></th>
<th class='c-stage'><?php echo $lang->testcase->stage?></th>
<th><?php echo $lang->testcase->precondition?></th>
<?php if(!empty($appendFields)):?>
<?php foreach($appendFields as $appendField):?>
<th class='c-extend'><?php echo $lang->testcase->{$appendField->field}?></th>
<?php endforeach;?>
<?php endif;?>
<th class='c-step'>
<table class='w-p100 table-borderless'>
<tr>
<th class="no-padding"><?php echo $lang->testcase->stepDesc?></th>
<th class="no-padding"><?php echo $lang->testcase->stepExpect?></th>
</tr>
</table>
</th>
</tr>
</thead>
<tbody>
<?php
$insert = true;
$addID = 1;
?>
<?php foreach($caseData as $key => $case):?>
<?php if(empty($case->title)) continue;?>
<tr valign='top' class='text-left'>
<td><?php echo $addID;?></td>
<td>
<?php
if(!empty($case->id))
{
echo $case->id . html::hidden("id[$key]", $case->id);
$insert = false;
}
else
{
echo "<sub class='gray' style='vertical-align:sub;'>{$lang->testcase->new}</sub>";
}
echo html::hidden("product[$key]", $productID);
if(!empty($branches))
{
$branchID = $branch;
if(isset($case->branch)) $branchID = $case->branch;
if(!empty($case->id) and !empty($cases[$case->id]->branch)) $branchID = $cases[$case->id]->branch;
echo html::hidden("branch[$key]", $branchID);
}
echo html::hidden("keywords[$key]", isset($case->keywords) ? $case->keywords : "");
?>
</td>
<td><?php echo html::input("title[$key]", htmlSpecialString($case->title, ENT_QUOTES), "class='form-control'")?></td>
<td style='overflow:visible'>
<?php $caseModules = (isset($case->branch) and $case->branch != 0) ? $modules[BRANCH_MAIN] + $modules[$case->branch] : $modules[BRANCH_MAIN];?>
<?php echo html::select("module[$key]", $caseModules, isset($case->module) ? $case->module : ((!empty($case->id) and isset($cases[$case->id])) ? $cases[$case->id]->module : ''), "class='form-control chosen moduleChange' onchange='loadStories($productID, this.value, $key)'")?>
</td>
<td style='overflow:visible'>
<?php $storyID = isset($case->story) ? $case->story : ((!empty($case->id) and isset($cases[$case->id])) ? $cases[$case->id]->story : '');?>
<?php echo html::select("story[$key]", array($storyID => zget($stories, $storyID, '')), $storyID, "class='form-control chosen storyChange'")?></td>
<td><?php echo html::select("pri[$key]", $lang->testcase->priList, isset($case->pri) ? $case->pri : ((!empty($case->id) and isset($cases[$case->id])) ? $cases[$case->id]->pri : ''), "class='form-control chosen'")?></td>
<td><?php echo html::select("type[$key]", $lang->testcase->typeList, isset($case->type) ? $case->type : '', "class='form-control chosen'")?></td>
<td style='overflow:visible'><?php echo html::select("stage[$key][]", $lang->testcase->stageList, !empty($case->stage) ? $case->stage : ((!empty($case->id) and isset($cases[$case->id])) ? $cases[$case->id]->stage : ''), "multiple='multiple' class='form-control chosen'")?></td>
<td><?php echo html::textarea("precondition[$key]", isset($case->precondition) ? htmlSpecialString($case->precondition) : "", "class='form-control'")?></td>
<?php if(!empty($appendFields)):?>
<?php $this->loadModel('flow');?>
<?php foreach($appendFields as $appendField):?>
<td><?php echo $this->flow->buildControl($appendField, zget($case, $appendField->field, ''), "{$appendField->field}[$key]");?></td>
<?php endforeach;?>
<?php endif;?>
<td>
<?php if(isset($stepData[$key]['desc'])):?>
<table class='w-p100 bd-0'>
<?php $hasStep = false;?>
<?php foreach($stepData[$key]['desc'] as $id => $desc):?>
<?php if(empty($desc['content'])) continue;?>
<tr class='step'>
<?php $hasStep = true;?>
<td><?php echo $id . html::hidden("stepType[$key][$id]", $desc['type'])?></td>
<td><?php echo html::textarea("desc[$key][$id]", htmlSpecialString($desc['content']), "class='form-control'")?></td>
<td><?php if($desc['type'] != 'group') echo html::textarea("expect[$key][$id]", isset($stepData[$key]['expect'][$id]['content']) ? htmlSpecialString($stepData[$key]['expect'][$id]['content']) : '', "class='form-control'")?></td>
</tr>
<div class="table-responsive">
<table class='table table-form' id='showData'>
<thead>
<tr>
<th class='c-line-number'><?php echo $lang->lineNumber?></th>
<th class='c-id'><?php echo $lang->idAB?></th>
<?php if($product->type != 'normal'):?>
<th class='c-branch'><?php echo $lang->testcase->branch?></th>
<?php endif;?>
<th class='c-name required'><?php echo $lang->testcase->title?></th>
<th class='c-module'><?php echo $lang->testcase->module?></th>
<th class='c-story'><?php echo $lang->testcase->story?></th>
<th class='c-pri-box'><?php echo $lang->testcase->pri?></th>
<th class='c-type required'><?php echo $lang->testcase->type?></th>
<th class='c-stage'><?php echo $lang->testcase->stage?></th>
<th class='c-condition'><?php echo $lang->testcase->precondition?></th>
<?php if(!empty($appendFields)):?>
<?php foreach($appendFields as $appendField):?>
<th class='c-extend'><?php echo $lang->testcase->{$appendField->field}?></th>
<?php endforeach;?>
<?php if(!$hasStep):?>
<tr class='step'>
<td><?php echo '1' . html::hidden("stepType[$key][1]", 'step')?></td>
<td><?php echo html::textarea("desc[$key][1]", '', "class='form-control'")?></td>
<td><?php echo html::textarea("expect[$key][1]", '', "class='form-control'")?></td>
</tr>
<?php endif;?>
</table>
<?php else:?>
<table class='w-p100 bd-0'>
<tr class='step'>
<td><?php echo '1' . html::hidden("stepType[$key][1]", 'step')?></td>
<td><?php echo html::textarea("desc[$key][1]", '', "class='form-control'")?></td>
<td><?php echo html::textarea("expect[$key][1]", '', "class='form-control'")?></td>
</tr>
</table>
<?php endif;?>
</td>
</tr>
<?php $addID ++;?>
<?php endforeach;?>
</tbody>
<tfoot>
<tr>
<td colspan='10' class='text-center form-actions'>
<th class='c-step'>
<table class='w-p100 table-borderless'>
<tr>
<th class="no-padding"><?php echo $lang->testcase->stepDesc?></th>
<th class="c-expect no-padding"><?php echo $lang->testcase->stepExpect?></th>
</tr>
</table>
</th>
</tr>
</thead>
<tbody>
<?php
$insert = true;
$addID = 1;
?>
<?php foreach($caseData as $key => $case):?>
<?php if(empty($case->title)) continue;?>
<tr valign='top' class='text-left'>
<td><?php echo $addID;?></td>
<td>
<?php
if(!empty($case->id))
{
echo $case->id . html::hidden("id[$key]", $case->id);
$insert = false;
}
else
{
echo "<sub class='gray' style='vertical-align:sub;'>{$lang->testcase->new}</sub>";
}
echo html::hidden("product[$key]", $productID);
echo html::hidden("keywords[$key]", isset($case->keywords) ? $case->keywords : "");
?>
</td>
<?php $branchID = $branch;?>
<?php if($product->type != 'normal'):?>
<?php
$submitText = $isEndPage ? $this->lang->save : $this->lang->file->saveAndNext;
if(!$insert and $dataInsert === '')
{
echo "<button type='button' data-toggle='modal' data-target='#importNoticeModal' class='btn btn-primary btn-wide'>{$submitText}</button>";
}
else
{
echo html::submitButton($submitText);
if($dataInsert !== '') echo html::hidden('insert', $dataInsert);
}
echo html::hidden('isEndPage', $isEndPage ? 1 : 0);
echo html::hidden('pagerID', $pagerID);
echo html::linkButton($lang->goback, $this->inlink('browse', "productID=$productID"), 'self', '', 'btn btn-wide');
echo sprintf($lang->file->importPager, $allCount, $pagerID, $allPager);
if(isset($case->branch)) $branchID = $case->branch;
if(!isset($branches[$branchID])) $branchID = $branch;
?>
</td>
</tr>
</tfoot>
</table>
<td><?php echo html::select("branch[$key]", $branches, $branchID, "class='form-control chosen' onchange='setModules(this.value, $productID, $key)'");?></td>
<?php endif;?>
<td><?php echo html::input("title[$key]", htmlSpecialString($case->title, ENT_QUOTES), "class='form-control'")?></td>
<td style='overflow:visible'>
<?php
$caseModules = ($branchID and isset($modules[$branchID])) ? $modules[BRANCH_MAIN] + $modules[$branchID] : $modules[BRANCH_MAIN];
?>
<?php echo html::select("module[$key]", $caseModules, isset($case->module) ? $case->module : ((!empty($case->id) and isset($cases[$case->id])) ? $cases[$case->id]->module : ''), "class='form-control chosen moduleChange' onchange='loadStories($productID, this.value, $key)'")?>
</td>
<td style='overflow:visible'>
<?php $storyID = isset($case->story) ? $case->story : ((!empty($case->id) and isset($cases[$case->id])) ? $cases[$case->id]->story : '');?>
<?php echo html::select("story[$key]", array($storyID => zget($stories, $storyID, '')), $storyID, "class='form-control chosen storyChange'")?></td>
<td><?php echo html::select("pri[$key]", $lang->testcase->priList, isset($case->pri) ? $case->pri : ((!empty($case->id) and isset($cases[$case->id])) ? $cases[$case->id]->pri : ''), "class='form-control chosen'")?></td>
<td><?php echo html::select("type[$key]", $lang->testcase->typeList, isset($case->type) ? $case->type : '', "class='form-control chosen'")?></td>
<td style='overflow:visible'><?php echo html::select("stage[$key][]", $lang->testcase->stageList, !empty($case->stage) ? $case->stage : ((!empty($case->id) and isset($cases[$case->id])) ? $cases[$case->id]->stage : ''), "multiple='multiple' class='form-control chosen'")?></td>
<td><?php echo html::textarea("precondition[$key]", isset($case->precondition) ? htmlSpecialString($case->precondition) : "", "class='form-control'")?></td>
<?php if(!empty($appendFields)):?>
<?php $this->loadModel('flow');?>
<?php foreach($appendFields as $appendField):?>
<td><?php echo $this->flow->buildControl($appendField, zget($case, $appendField->field, ''), "{$appendField->field}[$key]");?></td>
<?php endforeach;?>
<?php endif;?>
<td>
<?php if(isset($stepData[$key]['desc'])):?>
<table class='w-p100 bd-0'>
<?php $hasStep = false;?>
<?php foreach($stepData[$key]['desc'] as $id => $desc):?>
<?php if(empty($desc['content'])) continue;?>
<tr class='step'>
<?php $hasStep = true;?>
<td><?php echo $id . html::hidden("stepType[$key][$id]", $desc['type'])?></td>
<td><?php echo html::textarea("desc[$key][$id]", htmlSpecialString($desc['content']), "class='form-control'")?></td>
<td><?php if($desc['type'] != 'group') echo html::textarea("expect[$key][$id]", isset($stepData[$key]['expect'][$id]['content']) ? htmlSpecialString($stepData[$key]['expect'][$id]['content']) : '', "class='form-control'")?></td>
</tr>
<?php endforeach;?>
<?php if(!$hasStep):?>
<tr class='step'>
<td><?php echo '1' . html::hidden("stepType[$key][1]", 'step')?></td>
<td><?php echo html::textarea("desc[$key][1]", '', "class='form-control'")?></td>
<td><?php echo html::textarea("expect[$key][1]", '', "class='form-control'")?></td>
</tr>
<?php endif;?>
</table>
<?php else:?>
<table class='w-p100 bd-0'>
<tr class='step'>
<td><?php echo '1' . html::hidden("stepType[$key][1]", 'step')?></td>
<td><?php echo html::textarea("desc[$key][1]", '', "class='form-control'")?></td>
<td><?php echo html::textarea("expect[$key][1]", '', "class='form-control'")?></td>
</tr>
</table>
<?php endif;?>
</td>
</tr>
<?php $addID ++;?>
<?php endforeach;?>
</tbody>
<tfoot>
<tr>
<td colspan='10' class='text-center form-actions'>
<?php
$submitText = $isEndPage ? $this->lang->save : $this->lang->file->saveAndNext;
if(!$insert and $dataInsert === '')
{
echo "<button type='button' data-toggle='modal' data-target='#importNoticeModal' class='btn btn-primary btn-wide'>{$submitText}</button>";
}
else
{
echo html::submitButton($submitText);
if($dataInsert !== '') echo html::hidden('insert', $dataInsert);
}
echo html::hidden('isEndPage', $isEndPage ? 1 : 0);
echo html::hidden('pagerID', $pagerID);
echo html::linkButton($lang->goback, $this->inlink('browse', "productID=$productID"), 'self', '', 'btn btn-wide');
echo sprintf($lang->file->importPager, $allCount, $pagerID, $allPager);
?>
</td>
</tr>
</tfoot>
</table>
</div>
<?php if(!$insert and $dataInsert === '') include '../../common/view/noticeimport.html.php';?>
</form>
</div>
+2 -1
View File
@@ -1704,7 +1704,8 @@ class testtaskModel extends model
elseif(!isset($existCases[$case->title]))
{
$this->dao->insert(TABLE_CASE)->data($case, 'steps')->exec();
$caseID = $this->dao->lastInsertID();
$caseID = $this->dao->lastInsertID();
$case->steps = isset($case->steps) ? $case->steps : array();
foreach($case->steps as $caseStep)
{
$caseStep->case = $caseID;
+2
View File
@@ -359,6 +359,8 @@ class todo extends control
$this->view->todo = $this->todo->getById($todoID);
$this->view->members = $this->loadModel('user')->getPairs('noclosed');
$this->view->times = date::buildTimeList($this->config->todo->times->begin, $this->config->todo->times->end, $this->config->todo->times->delta);
$this->view->actions = $this->loadModel('action')->getList('todo', $todoID);
$this->view->users = $this->user->getPairs('noletter');
$this->view->time = date::now();
$this->display();
}
+2
View File
@@ -63,6 +63,8 @@
<tr><td colspan='3' class='text-center form-actions'><?php echo html::submitButton();?></td></tr>
</tfoot>
</table>
<hr class='small' />
<div class='main'><?php include '../../common/view/action.html.php';?></div>
</form>
</div>
</div>
File diff suppressed because one or more lines are too long