diff --git a/db/update16.4.sql b/db/update16.4.sql index 2f2265fb9c..6bf006bb0e 100644 --- a/db/update16.4.sql +++ b/db/update16.4.sql @@ -24,3 +24,5 @@ ALTER TABLE `zt_task` MODIFY `activatedDate` datetime NOT NULL AFTER `lastEdited ALTER TABLE `zt_user` ADD `visions` varchar(20) NOT NULL AFTER `visits`; UPDATE `zt_user` SET `visions`='rnd,lite'; + +ALTER TABLE `zt_productplan` ADD `closedReason` varchar(20) NOT NULL AFTER `order`; diff --git a/db/zentao.sql b/db/zentao.sql index 06102bbea8..f6d23ba9b8 100644 --- a/db/zentao.sql +++ b/db/zentao.sql @@ -983,6 +983,7 @@ CREATE TABLE IF NOT EXISTS `zt_productplan` ( `begin` date NOT NULL, `end` date NOT NULL, `order` text NOT NULL, + `closedReason` varchar(20) NOT NULL `deleted` enum('0','1') NOT NULL default '0', PRIMARY KEY (`id`), KEY `product` (`product`), diff --git a/module/productplan/control.php b/module/productplan/control.php index 100e743442..b943dbf59d 100644 --- a/module/productplan/control.php +++ b/module/productplan/control.php @@ -188,21 +188,31 @@ class productplan extends control * @access public * @return void */ - public function batchChangeStatus($status) + public function batchChangeStatus($status, $productID) { - if($this->post->planIDList) + $this->loadModel('product')->setMenu($productID); + $this->loadModel('action'); + $planIDList = $this->post->planIDList; + + if($status !== 'closed') { - $planIDList = $this->post->planIDList; - unset($_POST['planIDList']); - $allChanges = $this->productplan->batchChangeStatus($planIDList, $status); - if(dao::isError()) die(js::error(dao::getError())); - foreach($allChanges as $planID => $changes) + $this->productplan->batchChangeStatus($status); + return print(js::reload('parent')); + } + else + { + if($this->post->comments) { - $this->loadModel('action'); - $actionID = $this->action->create('productplan', $planID, 'edited'); - $this->action->logHistory($actionID, $changes); + $allChanges = $this->productplan->batchChangeStatus($status); + return print(js::locate(inlink('browse', "product=$productID"), 'parent')); } - die(js::reload('parent')); + + $plans = $this->dao->select('*')->from(TABLE_PRODUCTPLAN)->where('id')->in($planIDList)->fetchAll('id'); + + $this->view->reasonList = $this->lang->productplan->closedReasonList; + $this->view->plans = $plans; + $this->view->productID = $productID; + $this->display(); } } @@ -466,23 +476,25 @@ class productplan extends control * Close a plan. * * @param int $planID - * @param string $confirm * @access public * @return void */ - public function close($planID, $confirm = 'no') + public function close($planID) { - if($confirm == 'no') - { - die(js::confirm($this->lang->productplan->confirmClose, $this->createLink('productplan', 'close', "planID=$planID&confirm=yes"), 'parent')); - } - else + $plan = $this->productplan->getById($planID); + + if(!empty($_POST)) { $this->productplan->updateStatus($planID, 'closed', 'closed'); - - if(dao::isError()) die(js::error(dao::getError())); - die(js::reload('parent')); + if(dao::isError()) return print(js::error(dao::getError())); + return print(js::reload('parent.parent')); } + + $this->view->productplan = $plan; + $this->view->reasonList = $this->lang->productplan->closedReasonList; + $this->view->actions = $this->loadModel('action')->getList('productplan', $planID); + $this->view->users = $this->loadModel('user')->getPairs(); + $this->display(); } /** diff --git a/module/productplan/js/browse.js b/module/productplan/js/browse.js index d1b1ca9318..46fa3e8083 100644 --- a/module/productplan/js/browse.js +++ b/module/productplan/js/browse.js @@ -154,7 +154,7 @@ function createCardMenu(options) if(privs.includes('edit')) items.push({label: productplanLang.edit, icon: 'edit', url: createLink('productplan', 'edit', "planID=" + card.id)}); if(privs.includes('start')) items.push({label: productplanLang.start, icon: 'start', url: createLink('productplan', 'start', "planID=" + card.id), attrs: {'target': 'hiddenwin'}}); if(privs.includes('finish')) items.push({label: productplanLang.finish, icon: 'checked', url: createLink('productplan', 'finish', "planID=" + card.id), attrs: {'target': 'hiddenwin'}}); - if(privs.includes('close')) items.push({label: productplanLang.close, icon: 'off', url: createLink('productplan', 'close', "planID=" + card.id), attrs: {'target': 'hiddenwin'}}); + if(privs.includes('close')) items.push({label: productplanLang.close, icon: 'off', url: createLink('productplan', 'close', "planID=" + card.id, '', true), className: 'iframe', attrs: {'data-toggle': 'modal'}}); if(privs.includes('activate')) items.push({label: productplanLang.activate, icon: 'magic', url: createLink('productplan', 'activate', "planID=" + card.id), attrs: {'target': 'hiddenwin'}}); if(privs.includes('delete')) items.push({label: productplanLang.delete, icon: 'trash', url: createLink('productplan', 'delete', "planID=" + card.id), attrs: {'target': 'hiddenwin'}}); diff --git a/module/productplan/lang/en.php b/module/productplan/lang/en.php index 40bded7944..deffacf4d9 100644 --- a/module/productplan/lang/en.php +++ b/module/productplan/lang/en.php @@ -32,8 +32,10 @@ $lang->productplan->plan = 'Plan'; $lang->productplan->allAB = 'All'; $lang->productplan->to = 'To'; $lang->productplan->more = 'More'; +$lang->productplan->comment = 'Comment'; $lang->productplan->batchUnlink = "Batch Unlink"; +$lang->productplan->batchClose = "Batch Close"; $lang->productplan->batchChangeStatus = "Batch Change Status"; $lang->productplan->unlinkAB = "Unlink"; $lang->productplan->linkStory = "Link Story"; @@ -57,6 +59,7 @@ $lang->productplan->unexpired = 'Unexpired'; $lang->productplan->all = 'All Plans'; $lang->productplan->setDate = "Set Start and end Date"; $lang->productplan->expired = "Expired"; +$lang->productplan->closedReason = "Closed Reason"; $lang->productplan->confirmDelete = "Do you want to delete this plan?"; $lang->productplan->confirmUnlinkStory = "Do you want to unlink this story?"; @@ -100,6 +103,9 @@ $lang->productplan->statusList['doing'] = 'Doing'; $lang->productplan->statusList['done'] = 'Done'; $lang->productplan->statusList['closed'] = 'Closed'; +$lang->productplan->closedReasonList['done'] = 'Done'; +$lang->productplan->closedReasonList['cancel'] = 'Cancel'; + $lang->productplan->parentActionList['startedbychild'] = 'starting the productplan sets the plan status as Doing.'; $lang->productplan->parentActionList['finishedbychild'] = 'finishing all productplan sets the plan status as Done.'; $lang->productplan->parentActionList['closedbychild'] = 'closing all productplan sets the plan status as Closed.'; diff --git a/module/productplan/lang/zh-cn.php b/module/productplan/lang/zh-cn.php index 35bb5ae9d8..f9ba7d14cf 100644 --- a/module/productplan/lang/zh-cn.php +++ b/module/productplan/lang/zh-cn.php @@ -32,8 +32,10 @@ $lang->productplan->plan = '计划'; $lang->productplan->allAB = '所有'; $lang->productplan->to = '至'; $lang->productplan->more = '更多操作'; +$lang->productplan->comment = '备注'; $lang->productplan->batchUnlink = "批量移除"; +$lang->productplan->batchClose = "批量关闭"; $lang->productplan->batchChangeStatus = "批量修改状态"; $lang->productplan->unlinkAB = "移除"; $lang->productplan->linkStory = "关联{$lang->SRCommon}"; @@ -57,6 +59,7 @@ $lang->productplan->unexpired = "未过期"; $lang->productplan->all = "所有计划"; $lang->productplan->setDate = "设置计划起止时间"; $lang->productplan->expired = "已过期"; +$lang->productplan->closedReason = "关闭原因"; $lang->productplan->confirmDelete = "您确认删除该计划吗?"; $lang->productplan->confirmUnlinkStory = "您确认移除该{$lang->SRCommon}吗?"; @@ -100,6 +103,9 @@ $lang->productplan->statusList['doing'] = '进行中'; $lang->productplan->statusList['done'] = '已完成'; $lang->productplan->statusList['closed'] = '已关闭'; +$lang->productplan->closedReasonList['done'] = '已完成'; +$lang->productplan->closedReasonList['cancel'] = '已取消'; + $lang->productplan->parentActionList['startedbychild'] = '系统判断由于子计划 开始 ,将计划状态置为 进行中 。'; $lang->productplan->parentActionList['finishedbychild'] = '系统判断由于子计划 全部完成 ,将计划状态置为 已完成 。'; $lang->productplan->parentActionList['closedbychild'] = '系统判断由于子计划 全部关闭 ,将计划状态置为 已关闭 。'; diff --git a/module/productplan/model.php b/module/productplan/model.php index 835e297dfa..2f60c25ec3 100644 --- a/module/productplan/model.php +++ b/module/productplan/model.php @@ -531,13 +531,17 @@ class productplanModel extends model $plan = new stdclass(); $plan->status = $status; + if($status == 'closed' and $this->post->closedReason) $plan->closedReason = $this->post->closedReason; + if($status !== 'closed') $plan->closedReason = ''; $this->dao->update(TABLE_PRODUCTPLAN)->data($plan)->where('id')->eq($planID)->exec(); if(dao::isError()) return false; $changes = common::createChanges($oldPlan, $plan); - $actionID = $this->loadModel('action')->create('productplan', $planID, $action); + + $comment = $this->post->comment ? $this->post->comment : ''; + $actionID = $this->loadModel('action')->create('productplan', $planID, $action, $comment); $this->action->logHistory($actionID, $changes); if($oldPlan->parent > 0) $this->updateParentStatus($oldPlan->parent); @@ -701,21 +705,45 @@ class productplanModel extends model * @access public * @return array */ - public function batchChangeStatus($planIDList, $status) + public function batchChangeStatus($status) { - $now = helper::now(); + $this->loadModel('action'); $allChanges = array(); + + $planIDList = $this->post->planIDList; + if($status == 'closed') $closedReasons = $this->post->closedReasons; + $oldPlans = $this->getByIDList($planIDList, $status); + foreach($planIDList as $planID) { $oldPlan = $oldPlans[$planID]; if($status == $oldPlan->status) continue; $plan = new stdclass(); - $plan->status = $status; + $plan->status = $status; + if($status == 'closed') $plan->closedReason = $closedReasons[$planID]; + if($status !== 'closed') $plan->closedReason = ''; $this->dao->update(TABLE_PRODUCTPLAN)->data($plan)->autoCheck()->where('id')->eq((int)$planID)->exec(); - if(!dao::isError()) $allChanges[$planID] = common::createChanges($oldPlan, $plan); + + if($oldPlan->parent > 0) $this->updateParentStatus($oldPlan->parent); + + if(!dao::isError()) + { + $allChanges[$planID] = common::createChanges($oldPlan, $plan); + } + else + { + return print(js::error(dao::getError())); + } + } + + foreach($allChanges as $planID => $changes) + { + $comment = $this->post->comments[$planID] ? $this->post->comments[$planID] : ''; + $actionID = $this->action->create('productplan', $planID, 'edited', $comment); + $this->action->logHistory($actionID, $changes); } return $allChanges; } @@ -975,7 +1003,7 @@ class productplanModel extends model if($plan->status != 'doing' or $plan->parent < 0) return false; break; case 'close' : - if($plan->status != 'done' or $plan->parent < 0) return false; + if($plan->status == 'closed' or $plan->parent < 0) return false; break; case 'activate' : if($plan->status == 'wait' or $plan->status == 'doing' or $plan->parent < 0) return false; diff --git a/module/productplan/view/batchchangestatus.html.php b/module/productplan/view/batchchangestatus.html.php new file mode 100755 index 0000000000..cb806191dd --- /dev/null +++ b/module/productplan/view/batchchangestatus.html.php @@ -0,0 +1,55 @@ + + * @package productplan + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
+
+

productplan->common . $lang->colon . $lang->productplan->batchClose;?>

+
+
"> + + + + + + + + + + + $plan):?> + + + + + + + + + + + +
idAB;?>productplan->title;?>productplan->status;?>productplan->closedReason;?>productplan->comment;?>
title;?>title;?> + + + + +
+ +
+
+ + +
+
+
+ diff --git a/module/productplan/view/browsebylist.html.php b/module/productplan/view/browsebylist.html.php index 2c96e7ae15..a82e76cf5e 100644 --- a/module/productplan/view/browsebylist.html.php +++ b/module/productplan/view/browsebylist.html.php @@ -1,6 +1,5 @@ id", $plan, 'list', 'play', '', '', false, $attr); common::printIcon('productplan', 'finish', "planID=$plan->id", $plan, 'list', 'checked', '', '', false, $attr); - common::printIcon('productplan', 'close', "planID=$plan->id", $plan, 'list', 'off', '', '', false, $attr); + common::printIcon('productplan', 'close', "planID=$plan->id", $plan, 'list', 'off', '', 'iframe', true); } $attr = $plan->expired ? "disabled='disabled'" : ''; @@ -224,8 +223,10 @@ productplan->statusList as $key => $status) { - $actionLink = $this->createLink('productplan', 'batchChangeStatus', "status=$key"); - echo html::a('javascript:;', $status, '', "onclick=\"setFormAction('$actionLink', 'hiddenwin')\""); + $isHiddenwin = $key == 'closed' ? '' : 'hiddenwin'; + + $actionLink = $this->createLink('productplan', 'batchChangeStatus', "status=$key&productID=$product->id"); + echo html::a('javascript:;', $status, '', "onclick=\"setFormAction('$actionLink', '$isHiddenwin')\""); } ?> diff --git a/module/productplan/view/close.html.php b/module/productplan/view/close.html.php new file mode 100644 index 0000000000..2adf0dbda7 --- /dev/null +++ b/module/productplan/view/close.html.php @@ -0,0 +1,42 @@ + + * @package productplan + * @link http://www.zentao.net + */ +?> + +
+
+
+

+ id;?> + title'>" . $productplan->title . '';?> + arrow . $lang->productplan->close;?> +

+
+
+ + + + + + + + + + + + +
productplan->closedReason;?>
productplan->comment;?>
+ +
+
+
+
+
+ diff --git a/module/story/control.php b/module/story/control.php index d157bf3530..a6f0ef9137 100644 --- a/module/story/control.php +++ b/module/story/control.php @@ -186,7 +186,7 @@ class story extends control setcookie('storyModule', 0, 0, $this->config->webRoot, '', $this->config->cookieSecure, false); $branchID = $this->post->branch ? $this->post->branch : $branch; $response['locate'] = $this->createLink('product', 'browse', "productID=$productID&branch=$branchID&browseType=¶m=0&type=$type&orderBy=id_desc"); - if($this->session->storyList and $this->app->tab != 'product') $response['locate'] = $this->session->storyList; + if($this->session->storyList) $response['locate'] = $this->session->storyList; } else {