diff --git a/module/story/model.php b/module/story/model.php index 4031d6de80..fff05ec289 100644 --- a/module/story/model.php +++ b/module/story/model.php @@ -2698,6 +2698,9 @@ class storyModel extends model $storyPairs = array(); foreach($stories as $story) { + $prefix = $story->id . ':'; + if($type == 'ignoreID') $prefix = ''; + $property = ''; if($type == 'short') { @@ -2707,7 +2710,7 @@ class storyModel extends model { $property = '(' . $this->lang->story->pri . ':' . (!empty($this->lang->story->priList[$story->pri]) ? $this->lang->story->priList[$story->pri] : 0) . ',' . $this->lang->story->estimate . ':' . $story->estimate . ')'; } - $storyPairs[$story->id] = $story->id . ':' . $story->title . ' ' . $property; + $storyPairs[$story->id] = $prefix . $story->title . ' ' . $property; } if($limit == 0) return $storyPairs; diff --git a/module/task/config/form.php b/module/task/config/form.php index ada21314b0..80d4ff38e4 100644 --- a/module/task/config/form.php +++ b/module/task/config/form.php @@ -180,15 +180,15 @@ $config->task->form->close['lastEditedBy'] = array('type' => 'string', 'requ $config->task->form->close['lastEditedDate'] = array('type' => 'datetime', 'required' => false, 'default' => $now); $config->task->form->testTask->create = array(); -$config->task->form->testTask->create['selectTestStory'] = array('type' => 'int', 'required' => false, 'default' => 0); -$config->task->form->testTask->create['testStory'] = array('type' => 'array', 'required' => false, 'default' => array()); -$config->task->form->testTask->create['testEstStarted'] = array('type' => 'array', 'required' => false, 'default' => array()); -$config->task->form->testTask->create['testDeadline'] = array('type' => 'array', 'required' => false, 'default' => array()); -$config->task->form->testTask->create['testAssignedTo'] = array('type' => 'array', 'required' => false, 'default' => array()); -$config->task->form->testTask->create['testPri'] = array('type' => 'array', 'required' => false, 'default' => array()); -$config->task->form->testTask->create['testEstimate'] = array('type' => 'array', 'required' => false, 'default' => array()); -$config->task->form->testTask->create['estStartedDitto'] = array('type' => 'array', 'required' => false, 'default' => array()); -$config->task->form->testTask->create['deadlineDitto'] = array('type' => 'array', 'required' => false, 'default' => array()); +$config->task->form->testTask->create['selectTestStory'] = array('type' => 'string', 'required' => false, 'default' => 'off'); +$config->task->form->testTask->create['testStory'] = array('type' => 'array', 'required' => false, 'default' => array()); +$config->task->form->testTask->create['testEstStarted'] = array('type' => 'array', 'required' => false, 'default' => array()); +$config->task->form->testTask->create['testDeadline'] = array('type' => 'array', 'required' => false, 'default' => array()); +$config->task->form->testTask->create['testAssignedTo'] = array('type' => 'array', 'required' => false, 'default' => array()); +$config->task->form->testTask->create['testPri'] = array('type' => 'array', 'required' => false, 'default' => array()); +$config->task->form->testTask->create['testEstimate'] = array('type' => 'array', 'required' => false, 'default' => array()); +$config->task->form->testTask->create['estStartedDitto'] = array('type' => 'array', 'required' => false, 'default' => array()); +$config->task->form->testTask->create['deadlineDitto'] = array('type' => 'array', 'required' => false, 'default' => array()); $config->task->form->recordWorkhour = array(); $config->task->form->recordWorkhour['date'] = array('type' => 'date', 'required' => true, 'default' => array()); diff --git a/module/task/control.php b/module/task/control.php index 5e1db4f79d..811601fa88 100755 --- a/module/task/control.php +++ b/module/task/control.php @@ -1200,7 +1200,7 @@ class task extends control */ public function ajaxGetTestStories(int $executionID, int $taskID = 0) { - $stories = $this->story->getExecutionStoryPairs($executionID, 0, 'all', '', '', 'active'); + $stories = $this->story->getExecutionStoryPairs($executionID, 0, 'all', '', 'ignoreID', 'active'); $testStoryIdList = $this->story->getTestStories(array_keys($stories), $executionID); $testStories = array(); foreach($stories as $testStoryID => $storyTitle) diff --git a/module/task/css/ajaxgetteststories.ui.css b/module/task/css/ajaxgetteststories.ui.css index a2d48b7867..c3f3f20121 100644 --- a/module/task/css/ajaxgetteststories.ui.css +++ b/module/task/css/ajaxgetteststories.ui.css @@ -1,2 +1,5 @@ +#testTaskTable {table-layout: fixed;} #testTaskTable tr {border: none;} -#testTaskTable tr > th, #testTaskTable tr > td {padding: 0.5rem;} +#testTaskTable tr > th:not(.c-actions) {border: 1px solid var(--table-border-color);} +#testTaskTable tr > th {background-color: #FFF; font-weight: unset;} +#testTaskTable tr > td {padding: 0;} diff --git a/module/task/js/create.ui.js b/module/task/js/create.ui.js index 42c8aa57a1..c453d7f6cb 100644 --- a/module/task/js/create.ui.js +++ b/module/task/js/create.ui.js @@ -68,33 +68,31 @@ function typeChange(e) * @access public * @return void */ -function toggleSelectTestStory(executionID) +function toggleSelectTestStory() { - if(typeof(executionID) == 'undefined') executionID = window.executionID; - - $('#testStoryBox').load($.createLink('task', 'ajaxGetTestStories', 'executionID=' + executionID + '&taskID=' + taskID)); - if(!$('#selectTestStoryBox').hasClass('hidden') && $('#selectTestStory').prop('checked')) + if(!$('[name=selectTestStory]').hasClass('hidden') && $('[name=selectTestStory]').prop('checked')) { - $('#module').closest('.form-group').addClass('hidden'); - $('#multipleBox').closest('.form-group').addClass('hidden'); - $('#story').closest('.form-row').addClass('hidden'); - $('#estStarted').closest('.form-row').addClass('hidden'); - if(!$('#estimate').hasClass('hidden')) $('#estimate').parent().prev().addClass('hidden'); - if(!$('#estimate').hasClass('hidden')) $('#estimate').parent().addClass('hidden'); - $('#testStoryBox').removeClass('hidden'); + $('[data-name=module]').addClass('hidden'); + $('[data-name=storyBox]').addClass('hidden'); + $('[data-name=datePlan]').addClass('hidden'); + $('[data-name=estimate]').addClass('hidden'); + $('[name=multiple]').closest('.checkbox-primary').addClass('hidden'); + + $('[data-name=testStoryBox]').removeClass('hidden'); + $('#testStoryBox').load($.createLink('task', 'ajaxGetTestStories', 'executionID=' + executionID + '&taskID=' + taskID)); $('[name^=multiple]').prop('checked', false); toggleTeam(); } else { - $('#module').closest('.form-group').removeClass('hidden'); - $('#multipleBox').closest('.form-group').removeClass('hidden'); - if(showFields.indexOf('story') != -1) $('#story').closest('.form-row').removeClass('hidden'); - $('#estStarted').closest('.form-row').removeClass('hidden'); - if(!$('#estimate').hasClass('hidden')) $('#estimate').parent().prev().removeClass('hidden'); - if(!$('#estimate').hasClass('hidden')) $('#estimate').parent().removeClass('hidden'); - $('#testStoryBox').addClass('hidden'); + $('[data-name=module]').removeClass('hidden'); + $('[data-name=storyBox]').removeClass('hidden'); + $('[data-name=datePlan]').removeClass('hidden'); + $('[data-name=estimate]').removeClass('hidden'); + $('[name=multiple]').closest('.checkbox-primary').removeClass('hidden'); + + $('[data-name=testStoryBox]').addClass('hidden'); } } diff --git a/module/task/lang/zh-cn.php b/module/task/lang/zh-cn.php index 1b610e6590..f072445160 100755 --- a/module/task/lang/zh-cn.php +++ b/module/task/lang/zh-cn.php @@ -276,6 +276,7 @@ $lang->task->noModule = '
您现在还没有模块信息task->createDenied = "你不能在该{$lang->projectCommon}添加任务"; $lang->task->cannotDeleteParent = '不能删除父任务。'; $lang->task->addChildTask = '因该任务已经产生消耗,为保证数据一致性,我们会帮您创建一条同名子任务记录该消耗。'; +$lang->task->selectTestStoryTip = "以下{$lang->SRCommon}将作为此任务的子任务"; $lang->task->error = new stdclass(); $lang->task->error->totalNumber = '"总计消耗"必须为数字'; diff --git a/module/task/model.php b/module/task/model.php index 227cd20eb9..73219bae24 100755 --- a/module/task/model.php +++ b/module/task/model.php @@ -1020,7 +1020,7 @@ class taskModel extends model { if(!empty($testTasks)) { - $this->config->task->create->requiredFields = str_replace(array(',estimate,', ',story,', ',estStarted,', ',deadline,', ',module,'), ',', $this->config->task->create->requiredFields); + $this->config->task->create->requiredFields = str_replace(array(',estimate,', ',story,', ',estStarted,', ',deadline,', ',module,'), ',', ",{$this->config->task->create->requiredFields},"); } $taskID = $this->create($task); diff --git a/module/task/ui/ajaxgetteststories.html.php b/module/task/ui/ajaxgetteststories.html.php index 7755aa1920..148d3a4000 100644 --- a/module/task/ui/ajaxgetteststories.html.php +++ b/module/task/ui/ajaxgetteststories.html.php @@ -24,23 +24,29 @@ foreach($testStories as $storyID => $storyTitle) ( h::td ( - picker - ( - setID("testStory{$i}"), - set::name("testStory[$i]"), - set::value($storyID), - set::items(array($storyID => $storyTitle)) - ) + setClass('border-b border-l'), + span($storyID, setClass('ml-2')) ), h::td ( picker + ( + setID("testStory{$i}"), + set::name("testStory[$i]"), + set::value($storyID), + set::items(array($storyID => $storyTitle)), + set::required(true) + ) + ), + h::td + ( + priPicker ( setID("testPri{$i}"), set::name("testPri[$i]"), set::required(true), set::value(empty($task->pri) ? 3 : $task->pri), - set::items($lang->task->priList) + set::items(array_filter($lang->task->priList)) ) ), h::td @@ -49,15 +55,22 @@ foreach($testStories as $storyID => $storyTitle) ( setID("testEstStarted{$i}"), set::name("testEstStarted[$i]"), + set::placeholder($lang->task->estStarted), set::value(empty($task->estStarted) ? '' : $task->estStarted) ) ), h::td + ( + setClass('text-center text-gray border-b'), + span('—') + ), + h::td ( datepicker ( setID("testDeadline{$i}"), set::name("testDeadline[$i]"), + set::placeholder($lang->task->deadline), set::value(empty($task->deadline) ? '' : $task->deadline) ) ), @@ -86,7 +99,7 @@ foreach($testStories as $storyID => $storyTitle) ), h::td ( - setClass('center'), + setClass('c-actions'), btnGroup ( set::items(array( @@ -99,59 +112,55 @@ foreach($testStories as $storyID => $storyTitle) $i ++; } -formGroup +h::table ( - set::label($lang->task->selectTestStory), - set::labelClass('selectStoryLabel'), - h::table + setClass('table table-form'), + setID('testTaskTable'), + h::thead ( - setClass('table table-form'), - setID('testTaskTable'), - h::thead + h::tr ( - h::tr + setClass('text-gray text-left'), + h::th('ID'), + h::th($lang->task->storyAB), + h::th ( - h::th($lang->task->storyAB), - h::th - ( - $lang->task->pri, - set::width('80px'), - setClass(isset($requiredFields['pri']) ? 'required' : '') - ), - h::th - ( - $lang->task->estStarted, - set::width('140px'), - setClass(isset($requiredFields['estStarted']) ? 'required' : '') - ), - h::th - ( - $lang->task->deadline, - set::width('140px'), - setClass(isset($requiredFields['deadline']) ? 'required' : '') - ), - h::th - ( - $lang->task->assignedTo, - set::width('100px') - ), - h::th - ( - $lang->task->estimate, - set::width('88px'), - setClass(isset($requiredFields['estimate']) ? 'required' : '') - ), - h::th - ( - $lang->actions, - set::width('70px') - ) + $lang->task->pri, + setClass(isset($requiredFields['pri']) ? 'required' : '') + ), + h::th + ( + $lang->task->datePlan, + set('colspan', 3), + setClass((isset($requiredFields['estStarted']) || isset($requiredFields['deadline'])) ? 'required' : '') + ), + h::th + ( + $lang->task->assignedTo, + ), + h::th + ( + $lang->task->estimateAB, + setClass(isset($requiredFields['estimate']) ? 'required' : '') + ), + h::th + ( + setClass('c-actions'), ) ), - h::tbody - ( - $taskTR - ) + h::col(setStyle('width', '80px')), + h::col(setStyle('width', 'auto')), + h::col(setStyle('width', '80px')), + h::col(setStyle('width', '140px')), + h::col(setStyle('width', '30px')), + h::col(setStyle('width', '140px')), + h::col(setStyle('width', '120px')), + h::col(setStyle('width', '100px')), + h::col(setStyle('width', '70px')), + ), + h::tbody + ( + $taskTR ) ); diff --git a/module/task/ui/create.field.php b/module/task/ui/create.field.php index e42f2bd410..4f97b32d42 100644 --- a/module/task/ui/create.field.php +++ b/module/task/ui/create.field.php @@ -179,3 +179,16 @@ $fields->field('taskName') $fields->field('taskEstimate') ->hidden() ->control('input'); + +/* Set test story task control. */ +$buildTestStoryBox = function($props) +{ + return div(setID('testStoryBox')); +}; + +$fields->field('testStoryBox') + ->label($lang->task->selectTestStory) + ->labelHint($lang->task->selectTestStoryTip) + ->width('full') + ->hidden() + ->control($buildTestStoryBox); diff --git a/module/task/ui/create.html.php b/module/task/ui/create.html.php index 43f022b839..3e9d4fe6db 100644 --- a/module/task/ui/create.html.php +++ b/module/task/ui/create.html.php @@ -21,10 +21,12 @@ jsVar('window.attributeList', $attributeList); jsVar('teamMemberError', $lang->task->error->teamMember); jsVar('requiredFields', $config->task->create->requiredFields); jsVar('estimateNotEmpty', sprintf($lang->error->gt, $lang->task->estimate, '0')); +jsVar('taskID', $taskID ?? 0); $fields = useFields('task.create'); +$fields->autoLoad('execution', 'execution,type,name,assignedToBox,region,lane,module,storyBox,datePlan,pri,estimate,desc,file,mailto,keywords,after,testStoryBox'); -$fields->orders('name,assignedToBox', 'desc,module,storyBox'); +$fields->orders('name,assignedToBox', 'module,testStoryBox', 'desc,module,storyBox'); $fields->fullModeOrders('type,module,storyBox', 'desc,file,mailto,keywords'); if($execution->type == 'kanban') { @@ -38,8 +40,6 @@ if(empty($features['story']) && $execution->type != 'kanban') $fields->fullModeOrders('type,module,storyBox,assignedToBox', 'desc,file,mailto,keywords'); } -$fields->autoLoad('execution', 'execution,type,name,assignedToBox,region,lane,module,storyBox,datePlan,pri,estimate,desc,file,mailto,keywords,after'); - $teamForm = array(); if(empty($task->team)) { @@ -164,7 +164,9 @@ formGridPanel on::change('[name=type]', 'typeChange'), on::change('[name=region]', 'loadLanes'), on::change('[name=multiple]', 'toggleTeam'), + on::change('[name=selectTestStory]', 'toggleSelectTestStory'), on::change('#teamTable [name^=team]', 'changeTeamMember'), + on::change('[name=execution]', 'loadAll'), on::click('[name=isShowAllModule]', 'showAllModule'), on::click('[name=copyButton]', 'copyStoryTitle'), on::click('.assignedToList .picker-multi-selection', 'removeTeamMember'), diff --git a/module/task/zen.php b/module/task/zen.php index a2810bffba..3e6f1608b3 100644 --- a/module/task/zen.php +++ b/module/task/zen.php @@ -551,6 +551,7 @@ class taskZen extends task { $formConfig = $this->config->task->form->create; if($this->post->type == 'affair') $formConfig['assignedTo']['type'] = 'array'; + if($this->post->type == 'test') $formConfig['story']['skipRequired'] = true; $execution = $this->dao->findById($executionID)->from(TABLE_EXECUTION)->fetch(); $team = $this->post->team ? array_filter($this->post->team) : array(); @@ -699,7 +700,7 @@ class taskZen extends task { /* Set data for the type of test task that has linked stories. */ $postData = form::data($this->config->task->form->testTask->create)->get(); - if(empty($postData->selectTestStory)) return array(); + if($postData->selectTestStory == 'off') return array(); $testTasks = array(); foreach($postData->testStory as $key => $storyID) @@ -714,8 +715,8 @@ class taskZen extends task $task->estStarted = !empty($postData->testEstStarted[$key]) ? $postData->testEstStarted[$key] : null; $task->deadline = !empty($postData->testDeadline[$key]) ? $postData->testDeadline[$key] : null; $task->assignedTo = !empty($postData->testAssignedTo[$key]) ? $postData->testAssignedTo[$key] : ''; - $task->estimate = (float)$postData->testEstimate[$key]; - $task->left = (float)$postData->testEstimate[$key]; + $task->estimate = !empty($postData->testEstimate[$key]) ? (float)$postData->testEstimate[$key] : 0; + $task->left = !empty($postData->testEstimate[$key]) ? (float)$postData->testEstimate[$key] : 0; $task->type = 'test'; /* Setting the task type to test to prevent duplicate tasks from being created. */ $task->vision = $this->config->vision;