* Finish task #96577.
This commit is contained in:
@@ -65,11 +65,17 @@ $config->story->form->batchEdit['assignedTo'] = array('type' => 'string', 'wid
|
||||
$config->story->form->batchEdit['source'] = array('type' => 'string', 'width' => '160px', 'control' => 'select', 'required' => false, 'default' => '', 'options' => array_filter($lang->story->sourceList));
|
||||
$config->story->form->batchEdit['sourceNote'] = array('type' => 'string', 'width' => '200px', 'control' => 'text', 'required' => false, 'default' => '', 'filter' => 'trim');
|
||||
$config->story->form->batchEdit['status'] = array('type' => 'string', 'width' => '80px', 'control' => 'static', 'required' => false, 'default' => 0, 'options' => array_filter($lang->story->statusList));
|
||||
$config->story->form->batchEdit['stage'] = array('type' => 'string', 'width' => '100px', 'control' => 'select', 'required' => false, 'default' => 0, 'options' => array_filter($lang->story->stageList));
|
||||
$config->story->form->batchEdit['stage'] = array('type' => 'string', 'width' => '120px', 'control' => 'select', 'required' => false, 'default' => 0, 'options' => array_filter($lang->story->stageList));
|
||||
$config->story->form->batchEdit['closedBy'] = array('type' => 'string', 'width' => '136px', 'control' => 'select', 'required' => false, 'default' => '', 'options' => 'users');
|
||||
$config->story->form->batchEdit['closedReason'] = array('type' => 'string', 'width' => '80px', 'control' => 'select', 'required' => false, 'default' => '', 'options' => array_filter($lang->story->reasonList));
|
||||
$config->story->form->batchEdit['keywords'] = array('type' => 'string', 'width' => '200px', 'control' => 'text', 'required' => false, 'default' => '', 'filter' => 'trim');
|
||||
|
||||
$config->story->form->batchClose = array();
|
||||
$config->story->form->batchClose['title'] = array('type' => 'string', 'width' => '300px', 'control' => 'text', 'required' => false, 'filter' => 'trim', 'base' => true);
|
||||
$config->story->form->batchClose['status'] = array('type' => 'string', 'width' => '90px', 'control' => 'select', 'required' => false, 'default' => 0, 'options' => array_filter($lang->story->statusList));
|
||||
$config->story->form->batchClose['closedReason'] = array('type' => 'string', 'width' => '300px', 'control' => 'select', 'required' => true, 'default' => '');
|
||||
$config->story->form->batchClose['comment'] = array('type' => 'string', 'control' => 'text', 'required' => false, 'default' => '', 'filter' => 'trim');
|
||||
|
||||
$config->story->form->change = array();
|
||||
$config->story->form->change['reviewer'] = array('type' => 'array', 'control' => 'multi-select', 'required' => true, 'default' => '', 'filter' => 'join', 'options' => '');
|
||||
$config->story->form->change['title'] = array('type' => 'string', 'control' => 'text', 'required' => true, 'filter' => 'trim');
|
||||
|
||||
+24
-88
@@ -1166,17 +1166,31 @@ class story extends control
|
||||
*/
|
||||
public function batchClose($productID = 0, $executionID = 0, $storyType = 'story', $from = '')
|
||||
{
|
||||
$this->app->loadLang('bug');
|
||||
if(!$this->post->storyIdList) return print(js::locate($this->session->storyList, 'parent'));
|
||||
if(!$this->post->storyIdList) return $this->send(array('result' => 'success', 'load' => $this->session->storyList));
|
||||
$storyIdList = $this->post->storyIdList;
|
||||
$storyIdList = array_unique($storyIdList);
|
||||
|
||||
$this->app->loadLang('bug');
|
||||
$this->story->replaceURLang($storyType);
|
||||
|
||||
if($this->post->comment)
|
||||
{
|
||||
$stories = $this->storyZen->buildStoriesForBatchClose();
|
||||
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
|
||||
$this->story->batchClose($stories);
|
||||
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
|
||||
$this->loadModel('score')->create('ajax', 'batchOther');
|
||||
return $this->send(array('result' => 'success', 'load' => $this->session->storyList));
|
||||
}
|
||||
|
||||
$this->storyZen->setMenuForBatchClose($productID, $executionID, $from);
|
||||
|
||||
/* Get edited stories. */
|
||||
$stories = $this->story->getByList($storyIdList);
|
||||
$ignoreTwins = array();
|
||||
$twinsCount = array();
|
||||
$stories = $this->story->getByList($storyIdList);
|
||||
$ignoreTwins = array();
|
||||
$twinsCount = array();
|
||||
foreach($stories as $story)
|
||||
{
|
||||
if(!empty($ignoreTwins) and isset($ignoreTwins[$story->id]))
|
||||
@@ -1185,16 +1199,9 @@ class story extends control
|
||||
continue;
|
||||
}
|
||||
|
||||
if($story->parent == -1)
|
||||
{
|
||||
$skipStory[] = $story->id;
|
||||
unset($stories[$story->id]);
|
||||
}
|
||||
if($story->status == 'closed')
|
||||
{
|
||||
$closedStory[] = $story->id;
|
||||
unset($stories[$story->id]);
|
||||
}
|
||||
if($story->parent == -1) $skipStory[] = $story->id;
|
||||
if($story->status == 'closed') $closedStory[] = $story->id;
|
||||
if($story->parent == -1 || $story->status == 'closed') unset($stories[$story->id]);
|
||||
|
||||
if(!empty($story->twins))
|
||||
{
|
||||
@@ -1207,86 +1214,15 @@ class story extends control
|
||||
}
|
||||
}
|
||||
|
||||
if($this->post->comments)
|
||||
{
|
||||
$allChanges = $this->story->batchClose();
|
||||
|
||||
if($allChanges)
|
||||
{
|
||||
foreach($allChanges as $storyID => $changes)
|
||||
{
|
||||
$preStatus = $stories[$storyID]->status;
|
||||
$isChanged = $stories[$storyID]->changedBy ? true : false;
|
||||
if($preStatus == 'reviewing') $preStatus = $isChanged ? 'changing' : 'draft';
|
||||
|
||||
$actionID = $this->action->create('story', $storyID, 'Closed', htmlSpecialString($this->post->comments[$storyID]), ucfirst($this->post->closedReasons[$storyID]) . ($this->post->duplicateStoryIDList[$storyID] ? ':' . (int)$this->post->duplicateStoryIDList[$storyID] : '') . "|$preStatus");
|
||||
$this->action->logHistory($actionID, $changes);
|
||||
|
||||
if(!empty($stories[$storyID]->twins)) $this->story->syncTwins($storyID, $stories[$storyID]->twins, $changes, 'Closed');
|
||||
}
|
||||
|
||||
$this->dao->update(TABLE_STORY)->set('assignedTo')->eq('closed')->where('id')->in(array_keys($allChanges))->exec();
|
||||
}
|
||||
|
||||
if(!dao::isError()) $this->loadModel('score')->create('ajax', 'batchOther');
|
||||
return print(js::locate($this->session->storyList, 'parent'));
|
||||
}
|
||||
|
||||
$errorTips = '';
|
||||
if(isset($closedStory)) $errorTips .= sprintf($this->lang->story->closedStory, implode(',', $closedStory));
|
||||
if(isset($skipStory)) $errorTips .= sprintf($this->lang->story->skipStory, implode(',', $skipStory));
|
||||
if(isset($skipStory) || isset($closedStory)) echo js::alert($errorTips);
|
||||
|
||||
/* The stories of a product. */
|
||||
if($this->app->tab == 'product')
|
||||
{
|
||||
$this->product->setMenu($productID);
|
||||
$product = $this->product->getByID($productID);
|
||||
$this->view->title = $product->name . $this->lang->colon . $this->lang->story->batchClose;
|
||||
}
|
||||
/* The stories of a execution. */
|
||||
elseif($executionID)
|
||||
{
|
||||
$this->lang->story->menu = $this->lang->execution->menu;
|
||||
$this->lang->story->menuOrder = $this->lang->execution->menuOrder;
|
||||
$this->execution->setMenu($executionID);
|
||||
$execution = $this->execution->getByID($executionID);
|
||||
$this->view->title = $execution->name . $this->lang->colon . $this->lang->story->batchClose;
|
||||
}
|
||||
else
|
||||
{
|
||||
if($this->app->tab == 'project')
|
||||
{
|
||||
$this->project->setMenu($this->session->project);
|
||||
$this->view->title = $this->lang->story->batchEdit;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->lang->story->menu = $this->lang->my->menu;
|
||||
$this->lang->story->menuOrder = $this->lang->my->menuOrder;
|
||||
|
||||
if($from == 'work') $this->lang->my->menu->work['subModule'] = 'story';
|
||||
if($from == 'contribute') $this->lang->my->menu->contribute['subModule'] = 'story';
|
||||
|
||||
$this->view->title = $this->lang->story->batchEdit;
|
||||
}
|
||||
}
|
||||
|
||||
/* Judge whether the editedStories is too large and set session. */
|
||||
$countInputVars = count($stories) * $this->config->story->batchClose->columns;
|
||||
$showSuhosinInfo = common::judgeSuhosinSetting($countInputVars);
|
||||
if($showSuhosinInfo) $this->view->suhosinInfo = extension_loaded('suhosin') ? sprintf($this->lang->suhosinInfo, $countInputVars) : sprintf($this->lang->maxVarsInfo, $countInputVars);
|
||||
|
||||
unset($this->lang->story->reasonList['subdivided']);
|
||||
|
||||
$this->view->moduleOptionMenu = $this->tree->getOptionMenu($productID, 'story');
|
||||
$this->view->plans = $this->loadModel('productplan')->getPairs($productID);
|
||||
$this->view->productID = $productID;
|
||||
$this->view->stories = $stories;
|
||||
$this->view->storyIdList = $storyIdList;
|
||||
$this->view->storyType = $storyType;
|
||||
$this->view->reasonList = $this->lang->story->reasonList;
|
||||
$this->view->twinsCount = $twinsCount;
|
||||
$this->view->errorTips = $errorTips;
|
||||
|
||||
$this->display();
|
||||
}
|
||||
@@ -2374,6 +2310,6 @@ class story extends control
|
||||
$story = $this->story->getByID($storyID);
|
||||
$stories = $this->story->getProductStoryPairs($story->product, $story->branch, 0, 'all', 'id_desc', 0, '', $story->type);
|
||||
|
||||
return print html::select("duplicateStoryIDList[$storyID]", $stories, '', "class='form-control' placeholder='{$this->lang->bug->placeholder->duplicate}'");
|
||||
return print html::select("duplicateStory[$storyID]", $stories, '', "class='form-control' placeholder='{$this->lang->bug->placeholder->duplicate}'");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
.duplicateStoryBox{width:50%;}
|
||||
.childStoryBox{width:50%;}
|
||||
@@ -0,0 +1,47 @@
|
||||
window.renderRowData = function($row, index, story)
|
||||
{
|
||||
var $title = $row.find('.form-batch-input[data-name="title"]');
|
||||
var $status = $row.find('.form-batch-input[data-name="status"]');
|
||||
|
||||
$title.attr('disabled', 'disabled').attr('title', story.title).after("<input type='hidden' name='title[" + story.id + "]' value='" + story.title + "' />");
|
||||
$status.attr('disabled', 'disabled');
|
||||
|
||||
if(story.twins)
|
||||
{
|
||||
$title.wrap("<div class='input-group'></div>");
|
||||
$title.after("<span class='input-group-addon'>" + langTwins + "<span class='text-secondary'>" + twinsCount[story.id] + "</span></span>");
|
||||
}
|
||||
|
||||
var $closedReason = $row.find('.form-batch-input[data-name="closedReason"]');
|
||||
$closedReason.attr('onchange', 'setDuplicateAndChild(this)').wrap("<div class='input-group'></div>");
|
||||
|
||||
var appendStoryHtml = "<span class='duplicateStoryBox" + (story.closedReason != 'duplicate' ? " hidden" : '') + "'>";
|
||||
appendStoryHtml += "<select class='form-control form-batch-input' name='duplicateStory[" + story.id + "]' id='duplicateStory_" + index + "' data-name='duplicateStory' data-id='" + story.id + "' onmouseenter='getDuplicateStories(this)'>";
|
||||
appendStoryHtml += "<option value=''></option>";
|
||||
appendStoryHtml += '</select></span>';
|
||||
$closedReason.after(appendStoryHtml);
|
||||
|
||||
if(story.status == 'draft') $closedReason.find('option[value="cancel"]').remove();
|
||||
};
|
||||
|
||||
window.setDuplicateAndChild = function(obj)
|
||||
{
|
||||
var $this = $(obj);
|
||||
$this.closest('.input-group').find('.duplicateStoryBox').toggleClass('hidden', $this.val() != 'duplicate');
|
||||
};
|
||||
|
||||
window.getDuplicateStories = function(obj)
|
||||
{
|
||||
var $this = $(obj);
|
||||
var options = $this.find('option').length;
|
||||
if(options <= 1)
|
||||
{
|
||||
var storyID = $this.data('id');
|
||||
var link = $.createLink('story', 'ajaxGetStoryPairs', 'storyID=' + storyID);
|
||||
|
||||
$this.closest('.duplicateStoryBox').load(link, function()
|
||||
{
|
||||
$(this).find('select').addClass('form-batch-input').attr('data-name', 'duplicateStory');
|
||||
});
|
||||
}
|
||||
};
|
||||
+29
-54
@@ -1723,76 +1723,51 @@ class storyModel extends model
|
||||
/**
|
||||
* Batch close story.
|
||||
*
|
||||
* @param array $stories
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function batchClose()
|
||||
public function batchClose(array $stories)
|
||||
{
|
||||
/* Init vars. */
|
||||
$stories = array();
|
||||
$allChanges = array();
|
||||
$now = helper::now();
|
||||
$data = fixer::input('post')->get();
|
||||
$storyIdList = $data->storyIdList ? $data->storyIdList : array();
|
||||
|
||||
$oldStories = $this->getByList($storyIdList);
|
||||
foreach($storyIdList as $storyID)
|
||||
{
|
||||
$oldStory = $oldStories[$storyID];
|
||||
if($oldStory->parent == -1) continue;
|
||||
if($oldStory->status == 'closed') continue;
|
||||
|
||||
$story = new stdclass();
|
||||
$story->lastEditedBy = $this->app->user->account;
|
||||
$story->lastEditedDate = $now;
|
||||
$story->closedBy = $this->app->user->account;
|
||||
$story->closedDate = $now;
|
||||
$story->assignedDate = $now;
|
||||
$story->status = 'closed';
|
||||
$story->stage = 'closed';
|
||||
|
||||
$story->closedReason = $data->closedReasons[$storyID];
|
||||
$story->duplicateStory = $data->duplicateStoryIDList[$storyID] ? $data->duplicateStoryIDList[$storyID] : $oldStory->duplicateStory;
|
||||
$story->childStories = $data->childStoriesIDList[$storyID] ? $data->childStoriesIDList[$storyID] : $oldStory->childStories;
|
||||
|
||||
if($story->closedReason != 'done') $story->plan = '';
|
||||
|
||||
$stories[$storyID] = $story;
|
||||
unset($story);
|
||||
}
|
||||
|
||||
$this->loadModel('action');
|
||||
$oldStories = $this->getByList(array_keys($stories));
|
||||
foreach($stories as $storyID => $story)
|
||||
{
|
||||
if(!$story->closedReason) continue;
|
||||
if(empty($story->closedReason)) continue;
|
||||
|
||||
$oldStory = $oldStories[$storyID];
|
||||
|
||||
$this->dao->update(TABLE_STORY)->data($story)
|
||||
->autoCheck()
|
||||
$this->dao->update(TABLE_STORY)->data($story, 'comment')->autoCheck()
|
||||
->checkIF($story->closedReason == 'duplicate', 'duplicateStory', 'notempty')
|
||||
->where('id')->eq($storyID)->exec();
|
||||
|
||||
if(!dao::isError())
|
||||
{
|
||||
/* Update parent story status. */
|
||||
if($oldStory->parent > 0) $this->updateParentStatus($storyID, $oldStory->parent);
|
||||
$this->setStage($storyID);
|
||||
$allChanges[$storyID] = common::createChanges($oldStory, $story);
|
||||
if(dao::isError()) return dao::$errors[] = 'story#' . $storyID . dao::getError(true);
|
||||
|
||||
if(($this->config->edition == 'biz' || $this->config->edition == 'max') && $oldStory->feedback && !isset($feedbacks[$oldStory->feedback]))
|
||||
{
|
||||
$feedbacks[$oldStory->feedback] = $oldStory->feedback;
|
||||
$this->loadModel('feedback')->updateStatus('story', $oldStory->feedback, $story->status, $oldStory->status);
|
||||
}
|
||||
}
|
||||
else
|
||||
/* Update parent story status. */
|
||||
if($oldStory->parent > 0) $this->updateParentStatus($storyID, $oldStory->parent);
|
||||
$this->setStage($storyID);
|
||||
|
||||
$changes = common::createChanges($oldStory, $story);
|
||||
if($changes)
|
||||
{
|
||||
helper::end(js::error('story#' . $storyID . dao::getError(true)));
|
||||
$preStatus = $oldStory->status;
|
||||
$isChanged = $oldStory->changedBy ? true : false;
|
||||
if($preStatus == 'reviewing') $preStatus = $isChanged ? 'changing' : 'draft';
|
||||
|
||||
$actionID = $this->action->create('story', $storyID, 'Closed', $story->comment, ucfirst($story->closedReason) . ($story->duplicateStory ? ':' . (int)$story->duplicateStory : '') . "|{$preStatus}");
|
||||
$this->action->logHistory($actionID, $changes);
|
||||
|
||||
if(!empty($oldStory->twins)) $this->syncTwins($storyID, $oldStory->twins, $changes, 'Closed');
|
||||
}
|
||||
if(!dao::isError()) $this->loadModel('score')->create('story', 'close', $storyID);
|
||||
|
||||
if($this->config->edition != 'open' && $oldStory->feedback && !isset($feedbacks[$oldStory->feedback]))
|
||||
{
|
||||
$feedbacks[$oldStory->feedback] = $oldStory->feedback;
|
||||
$this->loadModel('feedback')->updateStatus('story', $oldStory->feedback, $story->status, $oldStory->status);
|
||||
}
|
||||
|
||||
$this->loadModel('score')->create('story', 'close', $storyID);
|
||||
}
|
||||
|
||||
return $allChanges;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* The UI view file of story module of ZenTaoPMS.
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
|
||||
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* @author Wang Yidong <yidong@easycorp.ltd>
|
||||
* @package story
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
namespace zin;
|
||||
|
||||
jsVar('twinsCount', $twinsCount);
|
||||
jsVar('langTwins', $lang->story->twins . ': ');
|
||||
if(!empty($errorTips)) js("zui.Modal.alert({message: '{$errorTips}', icon: 'icon-exclamation-sign', iconClass: 'warning-pale rounded-full icon-2x'});\n");
|
||||
|
||||
unset($lang->story->reasonList['subdivided']);
|
||||
$fields = $config->story->form->batchClose;
|
||||
$fields['closedReason']['options'] = array_filter($lang->story->reasonList);
|
||||
|
||||
$items = array();
|
||||
$items['storyIdList'] = array('name' => 'storyIdList', 'label' => '', 'control' => 'hidden', 'hidden' => true);
|
||||
$items['id'] = array('name' => 'id', 'label' => $lang->idAB, 'control' => 'index', 'width' => '60px');
|
||||
foreach($fields as $fieldName => $field)
|
||||
{
|
||||
$items[$fieldName] = array('name' => $fieldName, 'label' => zget($lang->story, $fieldName), 'control' => $field['control'], 'width' => $field['width'], 'required' => $field['required'], 'items' => zget($field, 'options', array()));
|
||||
}
|
||||
$items['comment']['label'] = $lang->comment;
|
||||
|
||||
/* Build form field value for batch edit. */
|
||||
$fieldNameList = array_keys($items);
|
||||
$data = array();
|
||||
foreach($stories as $storyID => $story)
|
||||
{
|
||||
$data[$storyID] = $story;
|
||||
foreach($fieldNameList as $fieldName)
|
||||
{
|
||||
if($fieldName == 'storyIdList') $data[$storyID]->storyIdList = $story->id;
|
||||
if(!isset($story->$fieldName)) $story->$fieldName = '';
|
||||
}
|
||||
}
|
||||
|
||||
formBatchPanel
|
||||
(
|
||||
set::title($lang->story->batchClose),
|
||||
set::mode('edit'),
|
||||
set::items($items),
|
||||
set::data(array_values($data)),
|
||||
set::onRenderRow(jsRaw('renderRowData')),
|
||||
);
|
||||
|
||||
render();
|
||||
@@ -17,7 +17,7 @@ jsVar('meeting', isset($meetings) ? $meetings : array());
|
||||
jsVar('researchReports', isset($researchReports) ? $researchReports : array());
|
||||
jsVar('productStoryList', $productStoryList);
|
||||
|
||||
if(!empty($twinsTip)) js("zui.Modal.alert('{$twinsTip}');\n");
|
||||
if(!empty($twinsTip)) js("zui.Modal.alert({message: '{$twinsTip}', icon: 'icon-exclamation-sign', iconClass: 'warning-pale rounded-full icon-2x'});\n");
|
||||
|
||||
$fields = $config->story->form->batchEdit;
|
||||
|
||||
|
||||
+92
-2
@@ -140,7 +140,7 @@ class storyZen extends story
|
||||
* @access protected
|
||||
* @return void
|
||||
*/
|
||||
protected function setMenuForBatchEdit(int $productID, string $branch = '', int $executionID = 0, string $from): void
|
||||
protected function setMenuForBatchEdit(int $productID, string $branch = '', int $executionID = 0, string $from = ''): void
|
||||
{
|
||||
$this->view->hiddenPlan = false;
|
||||
if($this->app->tab == 'product')
|
||||
@@ -185,6 +185,54 @@ class storyZen extends story
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置批量关闭需求页面的导航。
|
||||
* Set menu for batch close.
|
||||
*
|
||||
* @param int $productID
|
||||
* @param int $executionID
|
||||
* @param string $from
|
||||
* @access protected
|
||||
* @return void
|
||||
*/
|
||||
protected function setMenuForBatchClose(int $productID, int $executionID = 0, string $from = ''): void
|
||||
{
|
||||
/* The stories of a product. */
|
||||
if($this->app->tab == 'product')
|
||||
{
|
||||
$this->product->setMenu($productID);
|
||||
$product = $this->product->getByID($productID);
|
||||
$this->view->title = $product->name . $this->lang->colon . $this->lang->story->batchClose;
|
||||
}
|
||||
/* The stories of a execution. */
|
||||
elseif($executionID)
|
||||
{
|
||||
$this->lang->story->menu = $this->lang->execution->menu;
|
||||
$this->lang->story->menuOrder = $this->lang->execution->menuOrder;
|
||||
$this->execution->setMenu($executionID);
|
||||
$execution = $this->execution->getByID($executionID);
|
||||
$this->view->title = $execution->name . $this->lang->colon . $this->lang->story->batchClose;
|
||||
}
|
||||
else
|
||||
{
|
||||
if($this->app->tab == 'project')
|
||||
{
|
||||
$this->project->setMenu($this->session->project);
|
||||
$this->view->title = $this->lang->story->batchClose;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->lang->story->menu = $this->lang->my->menu;
|
||||
$this->lang->story->menuOrder = $this->lang->my->menuOrder;
|
||||
|
||||
if($from == 'work') $this->lang->my->menu->work['subModule'] = 'story';
|
||||
if($from == 'contribute') $this->lang->my->menu->contribute['subModule'] = 'story';
|
||||
|
||||
$this->view->title = $this->lang->story->batchClose;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果是看板执行,设置界面中要用到关于看板的视图变量。
|
||||
* Set view vars for kanban.
|
||||
@@ -874,7 +922,49 @@ class storyZen extends story
|
||||
|
||||
if($story->closedBy && empty($story->closedReason)) dao::$errors['closedReason'] = sprintf($this->lang->error->notempty, $this->lang->story->closedReason);
|
||||
if($story->closedReason == 'done' && empty($story->stage)) dao::$errors['stage'] = sprintf($this->lang->error->notempty, $this->lang->story->stage);
|
||||
if($story->closedReason == 'duplicate' && empty($story->duplicateStory)) dao::$errors['stage'] = sprintf($this->lang->error->notempty, $this->lang->story->duplicateStory);
|
||||
if($story->closedReason == 'duplicate' && empty($story->duplicateStory)) dao::$errors['duplicateStory'] = sprintf($this->lang->error->notempty, $this->lang->story->duplicateStory);
|
||||
}
|
||||
|
||||
return $stories;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建批量关闭需求数据。
|
||||
* Build stories for batch close.
|
||||
*
|
||||
* @access protected
|
||||
* @return array
|
||||
*/
|
||||
protected function buildStoriesForBatchClose(): array
|
||||
{
|
||||
$fields = $this->config->story->form->batchClose;
|
||||
$account = $this->app->user->account;
|
||||
$now = helper::now();
|
||||
|
||||
$fields['duplicateStory'] = array('type' => 'int', 'required' => false, 'default' => 0);
|
||||
|
||||
$data = form::batchData($fields)->get();
|
||||
$oldStories = $this->story->getByList(array_keys($data));
|
||||
$stories = array();
|
||||
foreach($data as $storyID => $story)
|
||||
{
|
||||
$oldStory = $oldStories[$storyID];
|
||||
if($oldStory->parent == -1) continue;
|
||||
if($oldStory->status == 'closed') continue;
|
||||
|
||||
$story->lastEditedBy = $account;
|
||||
$story->lastEditedDate = $now;
|
||||
$story->closedBy = $account;
|
||||
$story->closedDate = $now;
|
||||
$story->assignedTo = 'closed';
|
||||
$story->assignedDate = $now;
|
||||
$story->status = 'closed';
|
||||
$story->stage = 'closed';
|
||||
|
||||
if($story->closedReason != 'done') $story->plan = '';
|
||||
if($story->closedReason == 'duplicate' && empty($story->duplicateStory)) dao::$errors['duplicateStory'] = sprintf($this->lang->error->notempty, $this->lang->story->duplicateStory);
|
||||
|
||||
$stories[$storyID] = $story;
|
||||
}
|
||||
|
||||
return $stories;
|
||||
|
||||
Reference in New Issue
Block a user