标题 - 设计出现偏差,需求重新设计
+标题 - 设计出现偏差,需求重新设计
+diff --git a/db/update20.0.sql b/db/update20.0.sql index 93bc2f330c..7f8d18150f 100644 --- a/db/update20.0.sql +++ b/db/update20.0.sql @@ -148,23 +148,23 @@ CREATE TABLE `zt_risk` ( `remedy` text NOT NULL, `plannedClosedDate` date NOT NULL, `actualClosedDate` date NOT NULL, - `addedDate` date NOT NULL, + `createdBy` varchar(30) NOT NULL, + `createdDate` datetime NOT NULL, + `editedBy` varchar(30) NOT NULL, + `editedDate` datetime NOT NULL, `resolution` text NOT NULL, `resolvedBy` varchar(30) NOT NULL, `activateBy` varchar(30) NOT NULL, `activateDate` date NOT NULL, - `closeBy` varchar(30) NOT NULL, - `closedDate` date NOT NULL, `assignedTo` varchar(30) NOT NULL, - `assignedBy` varchar(30) NOT NULL, `cancelBy` varchar(30) NOT NULL, - `cancelDate` datetime NOT NULL, + `cancelDate` date NOT NULL, `cancelReason` char(30) NOT NULL, `hangupBy` varchar(30) NOT NULL, - `hangupdDate` datetime NOT NULL, + `hangupdDate` date NOT NULL, `trackedBy` varchar(30) NOT NULL, - `trackedDate` datetime NOT NULL, - `assignedDate` datetime NOT NULL, + `trackedDate` date NOT NULL, + `assignedDate` date NOT NULL, `deleted` enum('0','1') NOT NULL DEFAULT '0', PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; diff --git a/module/custom/lang/de.php b/module/custom/lang/de.php index 2eaf322bc8..e2e28a936f 100644 --- a/module/custom/lang/de.php +++ b/module/custom/lang/de.php @@ -133,10 +133,7 @@ $lang->custom->productProject->relation['1_2'] = 'Project - Sprint'; $lang->custom->productProject->notice = 'Please select a concept according to your team.'; -$lang->custom->workingList['full'] = 'Full Management of Dev'; -$lang->custom->workingList['onlyTest'] = 'Test Management'; -$lang->custom->workingList['onlyStory'] = 'Story Management'; -$lang->custom->workingList['onlyTask'] = 'Task Management'; +$lang->custom->workingList['full'] = 'Full Management of Dev'; $lang->custom->menuTip = 'Click to show/hide navigation bar. Drag to swtich display order.'; $lang->custom->saveFail = 'Failed to save!'; diff --git a/module/custom/lang/en.php b/module/custom/lang/en.php index ffd61eb164..12f36948d2 100644 --- a/module/custom/lang/en.php +++ b/module/custom/lang/en.php @@ -173,10 +173,7 @@ $lang->custom->productProject->relation['0_1'] = 'Program - Product - Sprint'; $lang->custom->productProject->notice = 'Select a concept that fits your team.'; -$lang->custom->workingList['full'] = 'Application Lifecycle Management'; -$lang->custom->workingList['onlyTest'] = 'Test Management'; -$lang->custom->workingList['onlyStory'] = 'Story Management'; -$lang->custom->workingList['onlyTask'] = 'Task Management'; +$lang->custom->workingList['full'] = 'Application Lifecycle Management'; $lang->custom->menuTip = 'Click to show/hide the menu. Drag to switch display order.'; $lang->custom->saveFail = 'Failed to save!'; diff --git a/module/custom/lang/fr.php b/module/custom/lang/fr.php index 71f1d1cc11..f8a6070826 100644 --- a/module/custom/lang/fr.php +++ b/module/custom/lang/fr.php @@ -133,10 +133,7 @@ $lang->custom->productProject->relation['1_2'] = 'Project - Sprint'; $lang->custom->productProject->notice = 'Sélectionnez le concept qui correspond à votre équipe.'; -$lang->custom->workingList['full'] = 'Application Lifecycle Management'; -$lang->custom->workingList['onlyTest'] = 'Gestion de la Qualité'; -$lang->custom->workingList['onlyStory'] = 'Gestion des Stories'; -$lang->custom->workingList['onlyTask'] = 'Gestion des Tâches'; +$lang->custom->workingList['full'] = 'Application Lifecycle Management'; $lang->custom->menuTip = "Cliquez pour montrer/cacher le menu. Déplacez pour changer l'ordre d'affichage."; $lang->custom->saveFail = 'Echec de la sauvegarde !'; diff --git a/module/custom/lang/zh-cn.php b/module/custom/lang/zh-cn.php index 71bc692b24..985978eded 100644 --- a/module/custom/lang/zh-cn.php +++ b/module/custom/lang/zh-cn.php @@ -173,10 +173,7 @@ $lang->custom->productProject->relation['0_1'] = '项目 - 产品 - 冲刺'; $lang->custom->productProject->notice = '请根据实际情况选择适合自己团队的概念。'; -$lang->custom->workingList['full'] = '完整研发管理工具'; -$lang->custom->workingList['onlyTest'] = '测试管理工具'; -$lang->custom->workingList['onlyStory'] = "{$lang->storyCommon}管理工具"; -$lang->custom->workingList['onlyTask'] = '任务管理工具'; +$lang->custom->workingList['full'] = '完整研发管理工具'; $lang->custom->menuTip = '点击显示或隐藏导航条目,拖拽来更改显示顺序。'; $lang->custom->saveFail = '保存失败!'; diff --git a/module/issue/config.php b/module/issue/config.php index 7ed6ebfba3..c80ed978c8 100644 --- a/module/issue/config.php +++ b/module/issue/config.php @@ -1,6 +1,12 @@ issue->create = new stdclass(); +$config->issue->edit = new stdclass(); + $config->issue->create->requiredFields = 'title,type,severity'; +$config->issue->edit->requiredFields = 'title,type,severity'; $config->issue->editor = new stdclass(); -$config->issue->editor->create = array('id' => 'desc', 'tools' => 'simpleTools'); +$config->issue->editor->create = array('id' => 'desc', 'tools' => 'simpleTools'); +$config->issue->editor->edit = array('id' => 'desc', 'tools' => 'simpleTools'); +$config->issue->editor->cancel = array('id' => 'desc', 'tools' => 'simpleTools'); +$config->issue->editor->resolve = array('id' => 'resolutionComment', 'tools' => 'simpleTools'); diff --git a/module/issue/control.php b/module/issue/control.php index d6c4231c56..30a372ce0f 100644 --- a/module/issue/control.php +++ b/module/issue/control.php @@ -24,9 +24,23 @@ class issue extends control */ public function browse($browseType = 'all', $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1) { + $browseType = strtolower($browseType); + /* Load pager */ + $this->app->loadClass('pager', true); + $pager = pager::init($recTotal, $recPerPage, $pageID); + $this->view->title = $this->lang->issue->common . $this->lang->colon . $this->lang->issue->browse; $this->view->position[] = $this->lang->issue->browse; + $this->view->pager = $pager; + $this->view->recTotal = $recTotal; + $this->view->recPerPage = $recPerPage; + $this->view->pageID = $pageID; + $this->view->orderBy = $orderBy; + $this->view->browseType = $browseType; + $this->view->issueList = $this->issue->getIssueList($browseType, $orderBy, $pager); + $this->view->users = $this->loadModel('user')->getPairs('noletter|pofirst|nodeleted'); + $this->display(); } @@ -40,8 +54,9 @@ class issue extends control { if($_POST) { - $result = $this->issue->create(); + $issueID = $this->issue->create(); if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); + $this->loadModel('action')->create('issue', $issueID, 'Opened'); $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => inLink('browse', 'browseType=all'))); } @@ -53,4 +68,235 @@ class issue extends control $this->display(); } + + /** + * batchCreate issues + * + * @access public + * @return void + */ + public function batchCreate() + { + if($_POST) + { + $results = $this->issue->batchCreate(); + if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); + $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => inLink('browse', 'browseType=all'))); + } + + $this->view->title = $this->lang->issue->common . $this->lang->colon . $this->lang->issue->batchCreate; + $this->view->position[] = $this->lang->issue->common; + $this->view->position[] = $this->lang->issue->batchCreate; + + $this->view->users = $this->loadModel('user')->getPairs('noclosed|nodeleted'); + + $this->display(); + } + + /** + * Delete a issue. + * + * @param int $issueID + * @param string $confirm yes|no + * @access public + * @return void + */ + public function delete($issueID = 0, $confirm = 'no') + { + if($confirm == 'no') + { + die(js::confirm($this->lang->issue->confirmDelete, inLink('delete', "issueID=$issueID&confirm=yes"))); + } + else + { + $this->issue->delete($issueID); + die(js::reload('parent')); + } + } + + /** + * Edit a issue. + * + * @param int $issueID + * @access public + * @return void + */ + public function edit($issueID) + { + if($_POST) + { + $changes = $this->issue->update($issueID); + if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); + + $actionID = $this->loadModel('action')->create('issue', $issueID, 'Edited'); + $this->action->logHistory($actionID, $changes); + $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => inLink('browse', 'browseType=all'))); + } + + $this->view->title = $this->lang->issue->common . $this->lang->colon . $this->lang->issue->edit; + $this->view->position[] = $this->lang->issue->common; + $this->view->position[] = $this->lang->issue->edit; + + $this->view->users = $this->loadModel('user')->getPairs('noclosed|nodeleted'); + $this->view->issue = $this->issue->getByID($issueID); + + $this->display(); + } + + /** + * Assign a issue. + * + * @param int $issueID + * @access public + * @return void + */ + public function assignTo($issueID) + { + if($_POST) + { + $changes = $this->issue->assignTo($issueID); + + if(dao::isError()) die(js::error(dao::getError())); + $actionID = $this->loadModel('action')->create('issue', $issueID, 'Edited'); + + $this->action->logHistory($actionID, $changes); + die(js::closeModal('parent.parent', 'this')); + } + + $this->view->issue = $this->issue->getByID($issueID); + $this->view->users = $this->loadModel('user')->getPairs('noclosed|nodeleted'); + + $this->display(); + } + + /** + * Close a issue. + * + * @param int $issueID + * @access public + * @return void + */ + public function close($issueID) + { + if($_POST) + { + $changes = $this->issue->close($issueID); + + if(dao::isError()) die(js::error(dao::getError())); + $actionID = $this->loadModel('action')->create('issue', $issueID, 'Edited'); + + $this->action->logHistory($actionID, $changes); + die(js::closeModal('parent.parent', 'this')); + } + + $this->view->issue = $this->issue->getByID($issueID); + + $this->display(); + } + + /** + * Cancel a issue. + * + * @param int $issueID + * @access public + * @return void + */ + public function cancel($issueID) + { + if($_POST) + { + $changes = $this->issue->cancel($issueID); + + if(dao::isError()) die(js::error(dao::getError())); + $actionID = $this->loadModel('action')->create('issue', $issueID, 'Edited'); + + $this->action->logHistory($actionID, $changes); + die(js::closeModal('parent.parent', 'this')); + } + + $this->view->issue = $this->issue->getByID($issueID); + + $this->display(); + } + + /** + * Activate a issue. + * + * @param int $issueID + * @access public + * @return void + */ + public function activate($issueID) + { + if($_POST) + { + $changes = $this->issue->activate($issueID); + + if(dao::isError()) die(js::error(dao::getError())); + $actionID = $this->loadModel('action')->create('issue', $issueID, 'Edited'); + + $this->action->logHistory($actionID, $changes); + die(js::closeModal('parent.parent', 'this')); + } + + $this->view->issue = $this->issue->getByID($issueID); + $this->view->users = $this->loadModel('user')->getPairs('noclosed|nodeleted'); + + $this->display(); + } + + /** + * Resolve a issue. + * + * @param int $issue + * @access public + * @return void + */ + public function resolve($issue) + { + if($_POST) + { + $this->issue->resolve($issue); + $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => inlink('browse'))); + } + + $this->view->title = $this->lang->issue->resolved; + $this->view->issue = $this->issue->getByID($issue); + $this->view->users = $this->loadModel('user')->getPairs('noletter'); + + $this->display(); + } + + /** + * Get question details. + * + * @param int $issueID + * @access public + * @return void + */ + public function view($issueID) + { + $this->commonAction($issueID, 'issue'); + $issue = $this->issue->getByID($issueID); + $this->view->title = $this->lang->issue->common . $this->lang->colon . $issue->title; + $this->view->position[] = $this->lang->issue->common; + $this->view->position[] = $this->lang->issue->basicInfo; + + $this->view->users = $this->loadModel('user')->getPairs('noclosed|nodeleted'); + $this->view->issue = $issue; + + $this->display(); + } + + /** + * Common actions of issue module. + * + * @param int $issueID + * @access public + * @return void + */ + public function commonAction($issueID, $object) + { + $this->view->actions = $this->loadModel('action')->getList($object, $issueID); + } } diff --git a/module/issue/lang/zh-cn.php b/module/issue/lang/zh-cn.php index fda597551e..d2ffb9cf2f 100644 --- a/module/issue/lang/zh-cn.php +++ b/module/issue/lang/zh-cn.php @@ -29,11 +29,17 @@ $lang->issue->assignedBy = '由谁指派'; $lang->issue->assignedDate = '指派时间'; $lang->issue->resolved = '解决'; -$lang->issue->create = '新建'; +$lang->issue->delete = '删除'; +$lang->issue->basicInfo = '基本信息'; +$lang->issue->active = '激活'; +$lang->issue->assign = '指派'; +$lang->issue->create = '新建问题'; +$lang->issue->edit = '编辑问题'; $lang->issue->batchCreate = '批量新建'; +$lang->issue->labelList['all'] = '全部'; $lang->issue->labelList['open'] = '开放'; -$lang->issue->labelList['assignTo'] = '指派给我'; +$lang->issue->labelList['assignto'] = '指派给我'; $lang->issue->labelList['closed'] = '已关闭'; $lang->issue->labelList['suspended'] = '已挂起'; $lang->issue->labelList['cancelled'] = '已取消'; @@ -72,4 +78,14 @@ $lang->issue->statusList['unresolved'] = '正解决'; $lang->issue->statusList['resolved'] = '已解决'; $lang->issue->statusList['canceled'] = '取消'; $lang->issue->statusList['closed'] = '已关闭'; +$lang->issue->statusList['active'] = '激活'; +$lang->issue->statusList['suspended'] = '挂起'; +$lang->issue->resolveMethods = array(); +$lang->issue->resolveMethods['resolved'] = '已解决'; +$lang->issue->resolveMethods['totask'] = '转任务'; +$lang->issue->resolveMethods['tobug'] = '转BUG'; +$lang->issue->resolveMethods['tostory'] = '转需求'; +$lang->issue->resolveMethods['torisk'] = '转风险'; + +$lang->issue->confirmDelete = '您确认删除该问题?'; diff --git a/module/issue/model.php b/module/issue/model.php index 7e2e8cc72c..0599090122 100644 --- a/module/issue/model.php +++ b/module/issue/model.php @@ -13,12 +13,20 @@ add('createdBy', $this->app->user->account) ->add('createdDate', $now) + ->add('program', $this->session->program) + ->remove('labels,files') ->addIF($this->post->assignedTo, 'assignedBy', $this->app->user->account) ->addIF($this->post->assignedTo, 'assignedDate', $now) ->stripTags($this->config->issue->editor->create['id'], $this->config->allowedTags) @@ -43,6 +51,213 @@ class issueModel extends model } $this->dao->insert(TABLE_ISSUE)->data($data)->exec(); + $issueID = $this->dao->lastInsertID(); + $this->loadModel('file')->saveUpload('issue', $issueID); + + return $issueID; + } + + /** + * Get question list data. + * + * @param string $browseType + * @param string $orderBy + * @param object $pager + * @access public + * @return object + */ + public function getIssueList($browseType = 'all', $orderBy = 'id_desc', $pager = null) + { + $issueList = $this->dao->select('*')->from(TABLE_ISSUE) + ->where('program')->eq($this->session->program) + ->andWhere('deleted')->eq('0') + ->beginIF($browseType == 'open')->andWhere('status')->eq('active')->fi() + ->beginIF($browseType == 'assignto')->andWhere('assignedTo')->eq($this->app->user->account)->fi() + ->beginIF($browseType == 'closed')->andWhere('status')->eq('closed')->fi() + ->beginIF($browseType == 'suspended')->andWhere('status')->eq('suspended')->fi() + ->beginIF($browseType == 'cancelled')->andWhere('status')->eq('canceled')->fi() + ->orderBy($orderBy) + ->page($pager) + ->fetchAll(); + + return $issueList; + } + + /** + * Delete a question. + * + * @param int $issueID + * @param int $null + * @access public + * @return object + */ + public function delete($issueID = 0, $null = null) + { + $this->dao->update(TABLE_ISSUE)->set('deleted')->eq('1')->where('id')->eq($issueID)->exec(); + } + + /** + * Get a issue details. + * + * @param int $issueID + * @access public + * @return object + */ + public function getByID($issueID) + { + return $this->dao->select('*')->from(TABLE_ISSUE)->where('id')->eq($issueID)->andWhere('deleted')->eq('0')->fetch(); + } + + /** + * Update a question. + * + * @param int $issueID + * @access public + * @return bool + */ + public function update($issueID) + { + $now = helper::now(); + $data = fixer::input('post') + ->add('editedBy', $this->app->user->account) + ->add('editedDate', $now) + ->addIF($this->post->assignedTo, 'assignedBy', $this->app->user->account) + ->addIF($this->post->assignedTo, 'assignedDate', $now) + ->stripTags($this->config->issue->editor->edit['id'], $this->config->allowedTags) + ->get(); + + if(strpos($this->config->issue->edit->requiredFields, 'type') !== false and !$this->post->type) + { + dao::$errors[] = sprintf($this->lang->error->notempty, $this->lang->issue->type); + return false; + } + + if(strpos($this->config->issue->edit->requiredFields, 'title') !== false and !$this->post->title) + { + dao::$errors[] = sprintf($this->lang->error->notempty, $this->lang->issue->title); + return false; + } + + if(strpos($this->config->issue->edit->requiredFields, 'severity') !== false and !$this->post->severity) + { + dao::$errors[] = sprintf($this->lang->error->notempty, $this->lang->issue->severity); + return false; + } + $oldIssue = $this->getByID($issueID); + + $this->dao->update(TABLE_ISSUE)->data($data)->where('id')->eq($issueID)->exec(); + return common::createChanges($oldIssue, $data); + } + + /** + * Update assignor. + * + * @param int $issueID + * @access public + * @return bool + */ + public function assignTo($issueID) + { + $data = fixer::input('post') + ->add('assignedBy', $this->app->user->account) + ->add('assignedDate', helper::now()) + ->get(); + + $oldIssue = $this->getByID($issueID); + $this->dao->update(TABLE_ISSUE)->data($data)->where('id')->eq($issueID)->exec(); + + return common::createChanges($oldIssue, $data); + } + + /** + * Close issue. + * + * @param int $issueID + * @access public + * @return bool + */ + public function close($issueID) + { + $data = fixer::input('post') + ->add('closeBy', $this->app->user->account) + ->add('status', 'closed') + ->get(); + + $oldIssue = $this->getByID($issueID); + $this->dao->update(TABLE_ISSUE)->data($data)->where('id')->eq($issueID)->exec(); + + return common::createChanges($oldIssue, $data); + } + + /** + * Cancel issue. + * + * @param int $issueID + * @access public + * @return bool + */ + public function cancel($issueID) + { + $data = fixer::input('post')->get(); + $oldIssue = $this->getByID($issueID); + $this->dao->update(TABLE_ISSUE)->data($data)->where('id')->eq($issueID)->exec(); + + return common::createChanges($oldIssue, $data); + } + + /** + * Activate issue. + * + * @param int $issueID + * @access public + * @return bool + */ + public function activate($issueID) + { + $data = fixer::input('post') + ->add('status', 'active') + ->get(); + $oldIssue = $this->getByID($issueID); + $this->dao->update(TABLE_ISSUE)->data($data)->where('id')->eq($issueID)->exec(); + + return common::createChanges($oldIssue, $data); + } + + /** + * Batch create issue. + * + * @access public + * @return void + */ + public function batchCreate() + { + $now = helper::now(); + $data = fixer::input('post')->get(); + + $issues = array(); + foreach($data->dataList as $issue) + { + if(!trim($issue['title'])) continue; + + $issue['createdBy'] = $this->app->user->account; + $issue['createdDate'] = $now; + $issue['program'] = $this->session->program; + if($issue['assignedTo']) + { + $issue['assignedBy'] = $this->app->user->account; + $issue['assignedDate'] = $now; + } + + foreach(explode(',',$this->config->issue->create->requiredFields) as $field) + { + $field = trim($field); + if($field and empty($issue["$field"])) die(js::alert(sprintf($this->lang->error->notempty, $this->lang->issue->$field))); + } + + $issues[] = $issue; + } + foreach($issues as $issue) $this->dao->insert(TABLE_ISSUE)->data($issue)->exec(); + return true; } } diff --git a/module/issue/view/activate.html.php b/module/issue/view/activate.html.php new file mode 100644 index 0000000000..70c9d980d0 --- /dev/null +++ b/module/issue/view/activate.html.php @@ -0,0 +1,43 @@ + + * @package issue + * @version $Id: complete.html.php 935 2010-07-06 07:49:24Z jajacn@126.com $ + * @link http://www.zentao.net + */ +?> + +
标题 - 设计出现偏差,需求重新设计
+标题 - 设计出现偏差,需求重新设计
+| issue->type;?> | ++ + |
|---|
| risk->id;?> | +id;?> | +
|---|---|
| risk->source;?> | +risk->sourceList, $risk->source);?> | +
| risk->category;?> | +risk->categoryList, $risk->category);?> | +
| risk->strategy;?> | +risk->strategy, $risk->strategy);?> | +
| risk->status;?> | +processStatus('risk', $risk);?> | +
| risk->impact;?> | +risk->impact, $risk->impact);?> | +
| risk->probability;?> | +risk->probability, $risk->probability);?> | +
| risk->riskindex;?> | +riskindex;?> | +
| risk->pri;?> | +pri;?>' title='risk->priList, $risk->pri)?>'>risk->priList, $risk->pri)?> | +
| risk->identifiedDate;?> | +identifiedDate == '0000-00-00' ? '' : $risk->identifiedDate;?> | +
| risk->plannedClosedDate;?> | +plannedClosedDate == '0000-00-00' ? '' : $risk->plannedClosedDate;?> | +
| risk->actualClosedDate;?> | +actualClosedDate == '0000-00-00' ? '' : $risk->actualClosedDate;?> | +
| risk->assignedTo;?> | +assignedTo);?> | +
|---|---|
| risk->trackedBy;?> | +trackedBy);?> | +
| risk->trackedDate;?> | +trackedDate == '0000-00-00' ? '' : $risk->trackedDate;?> | +
| risk->createdBy;?> | +createdBy);?> | +
| risk->createdDate;?> | +createdDate == '0000-00-00' ? '' : $risk->createdDate;?> | +
| risk->editedBy;?> | +editedBy);?> | +
| risk->editedDate;?> | +editedDate == '0000-00-00' ? '' : $risk->editedDate;?> | +
| risk->assignedDate;?> | +assignedDate == '0000-00-00' ? '' : $risk->assignedDate;?> | +
| risk->resolvedBy;?> | +resolvedBy);?> | +
| risk->actualClosedDate;?> | +actualClosedDate == '0000-00-00' ? '' : $risk->actualClosedDate;?> | +
| risk->cancelBy;?> | +cancelBy);?> | +
| risk->cancelDate;?> | +cancelDate == '0000-00-00' ? '' : $risk->cancelDate;?> | +
| risk->cancelReason;?> | +risk->cancelReasonList, $risk->cancelReason);?> | +
| risk->hangupBy;?> | +hangupBy);?> | +
| risk->hangupDate;?> | +hangupDate == '0000-00-00' ? '' : $risk->hangupDate;?> | +
| risk->activateBy;?> | +activateBy);?> | +
| risk->activateDate;?> | +activateDate == '0000-00-00' ? '' : $risk->activateDate;?> | +