From dbc85eef48818087bf72f93eb3a692d54b49b997 Mon Sep 17 00:00:00 2001 From: wangyidong Date: Fri, 11 Apr 2025 15:43:38 +0800 Subject: [PATCH] * [perf story #72339] Adjust type field for programplan create for ipd. --- module/programplan/control.php | 16 ++--- module/programplan/js/create.ui.js | 86 +++++++++++++++++---------- module/programplan/ui/create.html.php | 82 ++++++------------------- module/programplan/zen.php | 4 +- 4 files changed, 77 insertions(+), 111 deletions(-) diff --git a/module/programplan/control.php b/module/programplan/control.php index 67bd8eb8a7..e9486c28ff 100644 --- a/module/programplan/control.php +++ b/module/programplan/control.php @@ -113,23 +113,15 @@ class programplan extends control $project = $this->project->getById($projectID); $programPlan = $this->project->getById($planID); $productList = $this->session->hasProduct ? $this->product->getProductPairsByProject($projectID) : array(); - $executions = !empty($planID) ? $this->loadModel('execution')->getChildExecutions($planID, 'order_asc,grade_asc', 'all') : array(); - $plans = $this->programplan->getStage($planID ?: $projectID, $this->productID, 'all', 'order_asc,grade_asc'); - if(!empty($planID) and in_array($project->model, array('ipd', 'waterfallplus'))) + $plans = $this->programplan->getStage($projectID, $this->productID, 'all', 'order_asc,grade_asc'); + if($planID) { - if(!empty($plans)) + foreach($plans as $planID => $plan) { - $executionType = 'stage'; - unset($this->lang->programplan->typeList['agileplus']); - } - elseif(!empty($executions)) - { - $executionType = 'agileplus'; - unset($this->lang->programplan->typeList['stage']); + if($plan->path == $programPlan->path || strpos($plan->path, $programPlan->path) !== 0) unset($plans[$planID]); } } - if(!empty($executions)) $plans = $executions; $plans = $this->programplanZen->sortPlans($plans); /* Set programplan typeList. */ diff --git a/module/programplan/js/create.ui.js b/module/programplan/js/create.ui.js index 0a28abf4af..5ecff95a3c 100644 --- a/module/programplan/js/create.ui.js +++ b/module/programplan/js/create.ui.js @@ -78,6 +78,7 @@ window.handleRenderRow = function($row, index, data) $row.attr('data-level', level); $row.find(nestedTextSelector).attr('title', text).text(text).append(``); // 创建隐藏表单域用于向服务器提交当前行层级信息。 + /* 追加 parent 属性,以记录父级index。 */ $row.attr('data-parent', '-1'); if($prevRow.length == 1) { @@ -110,21 +111,25 @@ window.handleRenderRow = function($row, index, data) { let $typePicker = info[0]; - let dataExist = (typeof data != 'undefined' && typeof data.id != 'undefined'); - let options = {}; - options.disabled = level == 0 ? true : false; + let dataExist = (typeof data != 'undefined' && typeof data.type != 'undefined'); + let options = {}; + options.disabled = (planID == 0 && level == 0) ? true : false; if(dataExist) options.disabled = true; + let prevType = ''; if(level > 0) { - let parentID = $row.attr('data-parent'); - let $parentRow = $row.parent().find('tr[data-index="' + parentID + '"]'); - let $firstChildRow = $parentRow.next(); - if($firstChildRow.attr('data-index') != $row.attr('data-index')) + let parentID = $row.attr('data-parent'); + let $parentRow = $row.parent().find('tr[data-index="' + parentID + '"]'); + let $firstChild = $parentRow.next(); + if($firstChild.length > 0) { - let pickerOptions = JSON.parse($firstChildRow.find('[data-name="type"]').find('.picker-box').attr('zui-create-picker')); - let prevType = pickerOptions.defaultValue; - options.items = []; + let $firstType = $firstChild.find('[data-name="type"]').find('[name^=type]'); + if($firstType.length > 0) prevType = $firstType.val(); + } + if(prevType && $firstChild.attr('data-index') != $row.attr('data-index')) + { + options.items = []; for(i in $typePicker.options.items) { let item = $typePicker.options.items[i]; @@ -134,15 +139,30 @@ window.handleRenderRow = function($row, index, data) } } } + else if(level == 0 && planID && $row.attr('data-index') > 0) + { + options.items = []; + for(i in $typePicker.options.items) + { + let item = $typePicker.options.items[i]; + if(item.value == '') continue; + if(initType == 'stage' && item.value == 'stage') options.items.push(item); + if(initType != 'stage' && item.value != 'stage') options.items.push(item); + } + } + $typePicker.render(options); - if(!dataExist && typeof prevType != 'undefined' && prevType != 'stage') $typePicker.$.setValue('sprint'); + if(!dataExist) + { + if(level > 0 && prevType != '' && prevType != 'stage') $typePicker.$.setValue('sprint'); + if(level == 0 && planID) $typePicker.$.setValue(initType); + } }); if(project.model == 'ipd') { - $row.find('[data-name="ACTIONS"]').find('[data-type="sort"]').addClass('hidden'); - if(level == 0) $row.find('[data-name="ACTIONS"]').find('[data-type="addSibling"]').addClass('disabled').prop('disabled', true); - if(level == 0) $row.find('[data-name="type"]').find('.picker-box').on('inited', function(e, info){ info[0].render({disabled: true}); }); + if(planID == 0)$row.find('[data-name="ACTIONS"]').find('[data-type="sort"]').addClass('hidden'); + if(level == 0 && planID == 0) $row.find('[data-name="ACTIONS"]').find('[data-type="addSibling"]').addClass('disabled').prop('disabled', true); $row.find('[data-name="attribute"]').find('.picker-box').on('inited', function(e, info){ info[0].render({disabled: true}); }); @@ -175,13 +195,15 @@ window.handleRenderRow = function($row, index, data) info[0].render({items: items, disabled: disabled}); }); - if(level > 0) + const $enabled = $row.find('td[data-name=enabled]'); + if($enabled.length > 0) { - const $enabled = $row.find('td[data-name=enabled]'); const $checkbox = $enabled.find('input[type=checkbox]'); - $checkbox.attr('disabled', 'disabled').attr('title', cropStageTip); + if(level > 0) $checkbox.attr('disabled', 'disabled').attr('title', cropStageTip); - $rootRow = $prevRow; + if($enabled.find('input.hidden').length == 0) $enabled.append("") + + let $rootRow = $row; while($rootRow.length == 1) { if($rootRow.attr('data-level') == 0) break; @@ -191,7 +213,7 @@ window.handleRenderRow = function($row, index, data) { $row.addClass('disabled'); $checkbox.prop('checked', false); - $enabled.append("") + $enabled.find('input.hidden').val('off'); } } @@ -287,6 +309,10 @@ window.changeEnabled = function(obj) const $row = $target.closest('tr'); $row.toggleClass('disabled', !$target.prop('checked')) + let $checkbox = $row.find('[data-name=enabled]').find('input[type=checkbox]'); + if($row.find('[data-name=enabled]').find('input.hidden') == 0) $row.find('[data-name=enabled]').append(""); + $row.find('[data-name=enabled]').find('input.hidden').val($target.prop('checked') ? 'on' : 'off'); + let $nextRow = $row.next(); while(true) { @@ -294,17 +320,12 @@ window.changeEnabled = function(obj) if($nextRow.attr('data-level') == 0) break; $nextRow.toggleClass('disabled', !$target.prop('checked')) - if($target.prop('checked')) - { - $nextRow.find('[data-name=enabled]').find('input[type=checkbox]').prop('checked', true); - $nextRow.find('[data-name=enabled]').find('input.hidden').remove(); - } - else - { - let $nextCheckbox = $nextRow.find('[data-name=enabled]').find('input[type=checkbox]'); - $nextCheckbox.prop('checked', false); - $nextRow.find('[data-name=enabled]').append("") - } + + let $nextCheckbox = $nextRow.find('[data-name=enabled]').find('input[type=checkbox]'); + if($nextRow.find('[data-name=enabled]').find('input.hidden') == 0) $nextRow.find('[data-name=enabled]').append(""); + + $nextCheckbox.prop('checked', $target.prop('checked')); + $nextRow.find('[data-name=enabled]').find('input.hidden').val($target.prop('checked') ? 'on' : 'off'); $nextRow = $nextRow.next(); } @@ -363,7 +384,6 @@ window.changeType = function(obj) } } - $nextRow = $row.next(); if($nextRow.length == 0) return; if($nextRow.attr('data-level') < level) return; @@ -372,7 +392,9 @@ window.changeType = function(obj) $nextRow.find('[data-name="ACTIONS"]').find('[data-type="addSub"]').toggleClass('disabled', type != 'stage').prop('disabled', type != 'stage'); let $nextTypePicker = $nextRow.find('.picker-box[data-name=type]').zui('picker'); - let nextTypeItems = []; + if($nextTypePicker == undefined) return; + + let nextTypeItems = []; for(i in typeList) { if(i == '') continue; diff --git a/module/programplan/ui/create.html.php b/module/programplan/ui/create.html.php index 64b029c7b1..b854e9cc29 100644 --- a/module/programplan/ui/create.html.php +++ b/module/programplan/ui/create.html.php @@ -66,77 +66,28 @@ $fnGenerateStageByProductList = function() use ($productID, $productList, $proje /* Generate checkboxes for sub-stage management. */ $fnGenerateSubPlanManageFields = function() use ($lang, $planID, $project, $executionType, $canParallel) { - if((empty($planID) && $project->model != 'ipd') || !in_array($project->model, array('waterfallplus', 'ipd'))) return div(); + if(!(empty($planID) && $project->model == 'ipd')) return div(); - if(empty($planID) && $project->model == 'ipd') + foreach($lang->programplan->parallelList as $key => $value) { - foreach($lang->programplan->parallelList as $key => $value) - { - $items[] = div(setClass('px-1'), checkbox - ( - set::type('radio'), - set::name('parallel'), - set::text($value), - set::value($key), - set::checked($key == $project->parallel), - set::disabled($canParallel), - on::change('window.onChangeParallel') - )); - } - - return div + $items[] = div(setClass('px-1'), checkbox ( - setClass('flex w-1/2 items-center'), - div(setClass('font-bold'), $lang->programplan->parallel . ':'), - $items, - html($lang->programplan->parallelTip) - ); + set::type('radio'), + set::name('parallel'), + set::text($value), + set::value($key), + set::checked($key == $project->parallel), + set::disabled($canParallel), + on::change('window.onChangeParallel') + )); } - $typeList = $lang->programplan->typeList; - - $items = array(); - if(count($typeList) > 1) - { - foreach($typeList as $key => $value) - { - $items[] = div(setClass('px-1'), checkbox - ( - set::type('radio'), - set::name('executionType'), - set::text($value), - set::value($key), - on::change('window.onChangeExecutionType'), - set::checked($key == $executionType) - )); - } - } - else - { - $items[] = div(setClass('px-1'), zget($typeList, $executionType)); - } - - /* Append method tip. */ - $items[] = icon( - 'help', - setID('methodTip'), - setClass('ml-2 text-gray'), - setData(array('toggle' => 'tooltip', 'title' => $lang->programplan->methodTip, 'placement' => 'right', 'type' => 'white', 'class-name' => 'text-gray border border-light')), - ); - - $items[] = tooltip( - set::_to('#methodTip'), - set::title($lang->programplan->methodTip), - set::placement('right'), - set::type('white'), - setClass('text-darker border border-light') - ); - return div ( setClass('flex w-1/2 items-center'), - div(setClass('font-bold'), $lang->programplan->subPlanManage . ':'), - $items + div(setClass('font-bold'), $lang->programplan->parallel . ':'), + $items, + html($lang->programplan->parallelTip) ); }; @@ -185,9 +136,9 @@ $fnGenerateFields = function() use ($config, $lang, $requiredFields, $showFields } /* Field for agileplus. */ - if($name == 'type' && !empty($planID) && in_array($project->model, array('waterfallplus', 'ipd'))) + if($name == 'type' && in_array($project->model, array('waterfallplus', 'ipd'))) { - $field['hidden'] = $executionType == 'stage'; + $field['hidden'] = false; $field['items'] = $lang->execution->typeList; } if($name == 'milestone') $field['width'] = '100px'; @@ -274,6 +225,7 @@ jsVar('planID', $planID); jsVar('type', $executionType); jsVar('project', $project); jsVar('plans', $plans); +jsVar('initType', ($planID && $plans) ? reset($plans)->type : 'stage'); jsVar('planGrade', $programPlan ? $programPlan->grade + 1 : 1); jsVar('syncData', $syncData); jsVar('cropStageTip', $lang->programplan->cropStageTip); diff --git a/module/programplan/zen.php b/module/programplan/zen.php index f00ee46df5..d23184e624 100644 --- a/module/programplan/zen.php +++ b/module/programplan/zen.php @@ -355,8 +355,8 @@ class programplanZen extends programplan if($field) $visibleFields[$field] = ''; } - if($viewData->project->model == 'waterfallplus' && $viewData->executionType == 'stage') $createRequiredFields = 'type,' . trim($createRequiredFields, ','); - if($viewData->project->model == 'ipd' && $viewData->executionType == 'stage' ) $createRequiredFields = 'enabled,point,type,' . trim($createRequiredFields, ','); + if($viewData->project->model == 'waterfallplus') $createRequiredFields = 'type,' . trim($createRequiredFields, ','); + if($viewData->project->model == 'ipd') $createRequiredFields = ($viewData->planID ? 'type,' : 'enabled,point,type,') . trim($createRequiredFields, ','); foreach(explode(',', $createRequiredFields) as $field) { if($field)