diff --git a/module/action/config.php b/module/action/config.php new file mode 100644 index 0000000000..564d661736 --- /dev/null +++ b/module/action/config.php @@ -0,0 +1,10 @@ +action->objectTables['bug'] = TABLE_BUG; +$config->action->objectTables['story'] = TABLE_STORY; +$config->action->objectTables['case'] = TABLE_CASE; +$config->action->objectTables['task'] = TABLE_TASK; + +$config->action->objectNameFields['bug'] = 'title'; +$config->action->objectNameFields['story'] = 'title'; +$config->action->objectNameFields['case'] = 'title'; +$config->action->objectNameFields['task'] = 'name'; diff --git a/module/action/control.php b/module/action/control.php new file mode 100644 index 0000000000..41664e9637 --- /dev/null +++ b/module/action/control.php @@ -0,0 +1,49 @@ +. + * + * @copyright Copyright 2009-2010 Chunsheng Wang + * @author Chunsheng Wang + * @package action + * @version $Id$ + * @link http://www.zentao.cn + */ +class action extends control +{ + /* 已删除记录列表。*/ + public function trash($orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1) + { + /* 设置标题和导航条。*/ + $this->view->header->title = $this->lang->action->trash; + $this->view->position[] = $this->lang->action->trash; + + /* 获取已删除记录。*/ + $this->app->loadClass('pager', $static = true); + $pager = pager::init($recTotal, $recPerPage, $pageID); + $this->view->trashes = $this->action->getTrashes($orderBy, $pager); + $this->view->users = $this->loadModel('user')->getPairs('noletter'); + $this->view->orderBy = $orderBy; + $this->view->pager = $pager; + $this->display(); + } + + /* 还原某一个对象。*/ + public function undelete($actionID) + { + $this->action->undelete($actionID); + die(js::locate(inlink('trash'), 'parent')); + } +} diff --git a/module/action/lang/zh-cn.php b/module/action/lang/zh-cn.php index 53fc552b26..3f3511fa80 100644 --- a/module/action/lang/zh-cn.php +++ b/module/action/lang/zh-cn.php @@ -21,6 +21,18 @@ * @version $Id$ * @link http://www.zentao.cn */ +$lang->action->trash = '回收站'; +$lang->action->undelete = '还原'; + +$lang->action->objectType = '对象类型'; +$lang->action->objectID = '对象ID'; +$lang->action->objectName = '对象名称'; +$lang->action->actor = '操作者'; +$lang->action->date = '日期'; + +$lang->action->objectTypes['bug'] = 'BUG'; +$lang->action->objectTypes['case'] = '用例'; + /* 用来描述操作历史记录。*/ $lang->action->desc->common = '$date, $action by $actor'; $lang->action->desc->extra = '$date, $action as $extra by $actor'; @@ -28,6 +40,8 @@ $lang->action->desc->opened = '$date, 由 $actor 创建。'; $lang->action->desc->changed = '$date, 由 $actor 变更。'; $lang->action->desc->edited = '$date, 由 $actor 编辑。'; $lang->action->desc->closed = '$date, 由 $actor 关闭。'; +$lang->action->desc->deleted = '$date, 由 $actor 删除。'; +$lang->action->desc->undeleted = '$date, 由 $actor 还原。'; $lang->action->desc->commented = '$date, 由 $actor 发表评论。'; $lang->action->desc->activated = '$date, 由 $actor 激活。'; $lang->action->desc->moved = '$date, 由 $actor 移动,之前为 "$extra"'; @@ -40,6 +54,8 @@ $lang->action->label->opened = '创建了'; $lang->action->label->changed = '变更了'; $lang->action->label->edited = '编辑了'; $lang->action->label->closed = '关闭了'; +$lang->action->label->deleted = '删除了'; +$lang->action->label->undeleted = '还原了'; $lang->action->label->commented = '评论了'; $lang->action->label->activated = '激活了'; $lang->action->label->resolved = '解决了'; diff --git a/module/action/model.php b/module/action/model.php index 31058ff87a..11619ac472 100644 --- a/module/action/model.php +++ b/module/action/model.php @@ -25,6 +25,9 @@ dao->findById((int)$actionID)->from(TABLE_ACTION)->fetch(); } + /* 获得所有的删除记录列表。*/ + public function getTrashes($orderBy, $pager) + { + $trashes = $this->dao->select('*')->from(TABLE_ACTION) + ->where('action')->eq('deleted') + ->andWhere('extra')->eq(self::CAN_UNDELETED) + ->orderBy($orderBy)->page($pager)->fetchAll(); + if(!$trashes) return array(); + + /* 将对象按照类型分开,然后查找其对应的名称。*/ + foreach($trashes as $object) $typeTrashes[$object->objectType][] = $object->objectID; + foreach($typeTrashes as $objectType => $objectIds) + { + $objectIds = array_unique($objectIds); + $table = $this->config->action->objectTables[$objectType]; + $field = $this->config->action->objectNameFields[$objectType]; + $objectNames[$objectType] = $this->dao->select("id, $field AS name")->from($table)->where('id')->in($objectIds)->fetchPairs(); + } + + /* 将name字段添加到trashes中。*/ + foreach($trashes as $trash) $trash->objectName = $objectNames[$trash->objectType][$trash->objectID]; + return $trashes; + } + /* 返回某一个action所对应的字段修改记录。*/ public function getHistory($actionID) { diff --git a/module/action/view/trash.html.php b/module/action/view/trash.html.php new file mode 100644 index 0000000000..d68db1eb9a --- /dev/null +++ b/module/action/view/trash.html.php @@ -0,0 +1,55 @@ +. + * + * @copyright Copyright 2009-2010 Chunsheng Wang + * @author Chunsheng Wang + * @package action + * @version $Id$ + * @link http://www.zentao.cn + */ +?> + + +
+ + recTotal}&recPerPage={$pager->recPerPage}"; ?> + + + + + + + + + + + + + + + + + + + + + +
action->objectType);?>action->objectID);?>action->objectName;?>action->actor);?>action->date);?>actions;?>
action->objectTypes[$action->objectType];?>objectID;?>objectName;?>actor];?>date;?>id", $lang->action->undelete, 'hiddenwin');?> +
+
show();?>
+
+ diff --git a/module/bug/control.php b/module/bug/control.php index f35404d7d3..e8753aff3f 100644 --- a/module/bug/control.php +++ b/module/bug/control.php @@ -74,7 +74,9 @@ class bug extends control $bugs = array(); if($browseType == 'all') { - $bugs = $this->dao->select('*')->from(TABLE_BUG)->where('product')->eq($productID)->orderBy($orderBy)->page($pager)->fetchAll(); + $bugs = $this->dao->select('*')->from(TABLE_BUG)->where('product')->eq($productID) + ->andWhere('deleted')->eq(0) + ->orderBy($orderBy)->page($pager)->fetchAll(); } elseif($browseType == "bymodule") { @@ -83,32 +85,44 @@ class bug extends control } elseif($browseType == 'assigntome') { - $bugs = $this->dao->findByAssignedTo($this->app->user->account)->from(TABLE_BUG)->andWhere('product')->eq($productID)->orderBy($orderBy)->page($pager)->fetchAll(); + $bugs = $this->dao->findByAssignedTo($this->app->user->account)->from(TABLE_BUG)->andWhere('product')->eq($productID) + ->andWhere('deleted')->eq(0) + ->orderBy($orderBy)->page($pager)->fetchAll(); } elseif($browseType == 'openedbyme') { - $bugs = $this->dao->findByOpenedBy($this->app->user->account)->from(TABLE_BUG)->andWhere('product')->eq($productID)->orderBy($orderBy)->page($pager)->fetchAll(); + $bugs = $this->dao->findByOpenedBy($this->app->user->account)->from(TABLE_BUG)->andWhere('product')->eq($productID) + ->andWhere('deleted')->eq(0) + ->orderBy($orderBy)->page($pager)->fetchAll(); } elseif($browseType == 'resolvedbyme') { - $bugs = $this->dao->findByResolvedBy($this->app->user->account)->from(TABLE_BUG)->andWhere('product')->eq($productID)->orderBy($orderBy)->page($pager)->fetchAll(); + $bugs = $this->dao->findByResolvedBy($this->app->user->account)->from(TABLE_BUG)->andWhere('product')->eq($productID) + ->andWhere('deleted')->eq(0) + ->orderBy($orderBy)->page($pager)->fetchAll(); } elseif($browseType == 'assigntonull') { - $bugs = $this->dao->findByAssignedTo('')->from(TABLE_BUG)->andWhere('product')->eq($productID)->orderBy($orderBy)->page($pager)->fetchAll(); + $bugs = $this->dao->findByAssignedTo('')->from(TABLE_BUG)->andWhere('product')->eq($productID) + ->andWhere('deleted')->eq(0) + ->orderBy($orderBy)->page($pager)->fetchAll(); } elseif($browseType == 'longlifebugs') { - $bugs = $this->dao->findByLastEditedDate("<", date(DT_DATE1, strtotime('-7 days')))->from(TABLE_BUG)->andWhere('product')->eq($productID)->andWhere('status')->ne('closed')->orderBy($orderBy)->page($pager)->fetchAll(); + $bugs = $this->dao->findByLastEditedDate("<", date(DT_DATE1, strtotime('-7 days')))->from(TABLE_BUG)->andWhere('product')->eq($productID) + ->andWhere('deleted')->eq(0) + ->andWhere('status')->ne('closed')->orderBy($orderBy)->page($pager)->fetchAll(); } elseif($browseType == 'postponedbugs') { - $bugs = $this->dao->findByResolution('postponed')->from(TABLE_BUG)->andWhere('product')->eq($productID)->orderBy($orderBy)->page($pager)->fetchAll(); + $bugs = $this->dao->findByResolution('postponed')->from(TABLE_BUG)->andWhere('product')->eq($productID) + ->orderBy($orderBy)->page($pager)->fetchAll(); } elseif($browseType == 'needconfirm') { $bugs = $this->dao->select('t1.*, t2.title AS storyTitle')->from(TABLE_BUG)->alias('t1')->leftJoin(TABLE_STORY)->alias('t2')->on('t1.story = t2.id') ->where("t2.status = 'active'") + ->andWhere('t1.deleted')->eq(0) ->andWhere('t2.version > t1.storyVersion') ->orderBy($orderBy) ->fetchAll(); @@ -117,7 +131,9 @@ class bug extends control { if($this->session->bugQuery == false) $this->session->set('bugQuery', ' 1 = 1'); $bugQuery = str_replace("`product` = 'all'", '1', $this->session->bugQuery); // 如果指定了搜索所有的产品,去掉这个查询条件。 - $bugs = $this->dao->select('*')->from(TABLE_BUG)->where($bugQuery)->orderBy($orderBy)->page($pager)->fetchAll(); + $bugs = $this->dao->select('*')->from(TABLE_BUG)->where($bugQuery) + ->andWhere('deleted')->eq(0) + ->orderBy($orderBy)->page($pager)->fetchAll(); } /* 处理查询语句,获取条件部分,并记录session。*/ @@ -243,7 +259,9 @@ class bug extends control public function view($bugID) { /* 查找bug信息及相关产品信息。*/ - $bug = $this->bug->getById($bugID); + $bug = $this->bug->getById($bugID); + if(!$bug) die(js::error($this->lang->notFound) . js::locate('back')); + $productID = $bug->product; $productName = $this->products[$productID]; @@ -424,6 +442,20 @@ class bug extends control die(js::reload('parent')); } + /* 删除bug。*/ + public function delete($bugID, $confirm = 'no') + { + if($confirm == 'no') + { + die(js::confirm($this->lang->bug->confirmDelete, inlink('delete', "bugID=$bugID&confirm=yes"))); + } + else + { + $this->bug->delete(TABLE_BUG, $bugID); + die(js::locate($this->session->bugList, 'parent')); + } + } + /* 获得用户的bug列表。*/ public function ajaxGetUserBugs($account = '') { diff --git a/module/bug/lang/zh-cn.php b/module/bug/lang/zh-cn.php index acc30e41ae..1dd93c609c 100644 --- a/module/bug/lang/zh-cn.php +++ b/module/bug/lang/zh-cn.php @@ -59,6 +59,7 @@ $lang->bug->lblLastEdited = '最后修改'; $lang->bug->lblResolved = '由谁解决'; $lang->bug->confirmChangeProduct = '修改产品会导致相应的项目、需求和任务发生变化,确定吗?'; +$lang->bug->confirmDelete = '您确认要删除该Bug吗?'; $lang->bug->legendBasicInfo = '基本信息'; $lang->bug->legendMailto = '抄送给'; diff --git a/module/bug/model.php b/module/bug/model.php index e42d8450f7..e4df9aa615 100644 --- a/module/bug/model.php +++ b/module/bug/model.php @@ -67,6 +67,7 @@ class bugModel extends model return $this->dao->select('*')->from(TABLE_BUG) ->where('product')->eq((int)$productID) ->onCaseOf(!empty($moduleIds))->andWhere('module')->in($moduleIds)->endCase() + ->andWhere('deleted')->eq(0) ->orderBy($orderBy)->page($pager)->fetchAll(); } @@ -79,6 +80,7 @@ class bugModel extends model ->leftJoin(TABLE_STORY)->alias('t3')->on('t1.story = t3.id') ->leftJoin(TABLE_TASK)->alias('t4')->on('t1.task = t4.id') ->where('t1.id')->eq((int)$bugID)->fetch(); + if(!$bug) return false; foreach($bug as $key => $value) if(strpos($key, 'Date') !== false and !(int)substr($value, 0, 4)) $bug->$key = ''; if($bug->mailto) { @@ -239,6 +241,7 @@ class bugModel extends model ->leftJoin(TABLE_PRODUCT)->alias('t2') ->on('t1.product=t2.id') ->where('t1.assignedTo')->eq($account) + ->andWhere('t1.deleted')->eq(0) ->query(); while($bug = $stmt->fetch()) { @@ -251,7 +254,10 @@ class bugModel extends model /* 获得某个项目的bug列表。*/ public function getProjectBugs($projectID, $orderBy = 'id_desc', $pager = null) { - return $this->dao->select('*')->from(TABLE_BUG)->where('project')->eq((int)$projectID)->orderBy($orderBy)->page($pager)->fetchAll(); + return $this->dao->select('*')->from(TABLE_BUG) + ->where('project')->eq((int)$projectID) + ->andWhere('deleted')->eq(0) + ->orderBy($orderBy)->page($pager)->fetchAll(); } /* 通过某一次测试结果获得bug的标题和步骤。*/ @@ -323,7 +329,10 @@ class bugModel extends model /* 按bug关闭日期统计。*/ public function getDataOfClosedBugsPerDay() { - return $this->dao->select('DATE_FORMAT(closedDate, "%Y-%m-%d") AS name, COUNT(*) AS value')->from(TABLE_BUG)->where($this->session->bugReportCondition)->groupBy('name')->orderBy('closedDate')->fetchAll(); + return $this->dao->select('DATE_FORMAT(closedDate, "%Y-%m-%d") AS name, COUNT(*) AS value')->from(TABLE_BUG) + ->where($this->session->bugReportCondition)->groupBy('name') + ->having('name != 0000-00-00') + ->orderBy('closedDate')->fetchAll(); } /* 按bug创建者统计。*/ diff --git a/module/bug/view/view.html.php b/module/bug/view/view.html.php index 2de2f46af8..e1481cc2d1 100644 --- a/module/bug/view/view.html.php +++ b/module/bug/view/view.html.php @@ -26,15 +26,19 @@
-
BUG #id . $lang->colon . $bug->title;?>
+
deleted) echo "class='deleted'";?>>BUG #id . $lang->colon . $bug->title;?>
id"; $browseLink = $app->session->bugList != false ? $app->session->bugList : $this->createLink('bug', 'browse', "productID=$bug->product"); - common::printLink('bug', 'edit', $params, $lang->bug->buttonEdit); - if(!($bug->status == 'active' and common::printLink('bug', 'resolve', $params, $lang->bug->buttonResolve))) echo $lang->bug->buttonResolve . ' '; - if(!($bug->status == 'resolved' and common::printLink('bug', 'close', $params, $lang->bug->buttonClose))) echo $lang->bug->buttonClose . ' '; - if(!(($bug->status == 'closed' or $bug->status == 'resolved') and common::printLink('bug', 'activate', $params, $lang->bug->buttonActivate))) echo $lang->bug->buttonActivate . ' '; + $params = "bugID=$bug->id"; + if(!$bug->deleted) + { + common::printLink('bug', 'edit', $params, $lang->bug->buttonEdit); + if(!($bug->status == 'active' and common::printLink('bug', 'resolve', $params, $lang->bug->buttonResolve))) echo $lang->bug->buttonResolve . ' '; + if(!($bug->status == 'resolved' and common::printLink('bug', 'close', $params, $lang->bug->buttonClose))) echo $lang->bug->buttonClose . ' '; + if(!(($bug->status == 'closed' or $bug->status == 'resolved') and common::printLink('bug', 'activate', $params, $lang->bug->buttonActivate))) echo $lang->bug->buttonActivate . ' '; + common::printLink('bug', 'delete', $params, $lang->delete, 'hiddenwin'); + } echo html::a($browseLink, $lang->goback); ?>
@@ -55,10 +59,14 @@
bug->buttonEdit); - if(!($bug->status == 'active' and common::printLink('bug', 'resolve', $params, $lang->bug->buttonResolve))) echo $lang->bug->buttonResolve . ' '; - if(!($bug->status == 'resolved' and common::printLink('bug', 'close', $params, $lang->bug->buttonClose))) echo $lang->bug->buttonClose . ' '; - if(!(($bug->status == 'closed' or $bug->status == 'resolved') and common::printLink('bug', 'activate', $params, $lang->bug->buttonActivate))) echo $lang->bug->buttonActivate . ' '; + if(!$bug->deleted) + { + common::printLink('bug', 'edit', $params, $lang->bug->buttonEdit); + if(!($bug->status == 'active' and common::printLink('bug', 'resolve', $params, $lang->bug->buttonResolve))) echo $lang->bug->buttonResolve . ' '; + if(!($bug->status == 'resolved' and common::printLink('bug', 'close', $params, $lang->bug->buttonClose))) echo $lang->bug->buttonClose . ' '; + if(!(($bug->status == 'closed' or $bug->status == 'resolved') and common::printLink('bug', 'activate', $params, $lang->bug->buttonActivate))) echo $lang->bug->buttonActivate . ' '; + common::printLink('bug', 'delete', $params, $lang->delete, 'hiddenwin'); + } echo html::a($browseLink, $lang->goback); ?>
diff --git a/module/common/lang/zh-cn.php b/module/common/lang/zh-cn.php index 2ff468cef7..176b34d3da 100644 --- a/module/common/lang/zh-cn.php +++ b/module/common/lang/zh-cn.php @@ -34,6 +34,7 @@ $lang->edit = '编辑'; $lang->copy = '复制'; $lang->delete = '删除'; $lang->close = '关闭'; +$lang->delete = '删除'; $lang->activate = '激活'; $lang->save = '保存'; $lang->confirm = '确认'; @@ -58,6 +59,7 @@ $lang->files = '附件 '; $lang->workingHour= '工时'; $lang->showHelp = '显示帮助'; $lang->go = 'GO!'; +$lang->notFound = '抱歉,您访问的对象并不存在!'; /* 主导航菜单。*/ $lang->menu->index = '首页|index|index'; @@ -157,9 +159,11 @@ $lang->user->menu->browse = array('link' => '用户管理|company|browse|', 'f /* 后台管理菜单设置。*/ $lang->admin->menu->browseCompany = array('link' => '公司管理|admin|browsecompany', 'subModule' => 'company'); $lang->admin->menu->convert = array('link' => '从其他系统导入|convert|index', 'subModule' => 'convert'); +$lang->admin->menu->trashes = array('link' => '回收站|action|trash', 'subModule' => 'action'); $lang->admin->menu->createCompany = array('link' => '新增公司|company|create', 'float' => 'right'); $lang->convert->menu = $lang->admin->menu; $lang->upgrade->menu = $lang->admin->menu; +$lang->action->menu = $lang->admin->menu; /*菜单设置:分组设置。*/ $lang->menugroup->release = 'product'; @@ -178,6 +182,7 @@ $lang->menugroup->testtask = 'qa'; $lang->menugroup->people = 'company'; $lang->menugroup->dept = 'company'; $lang->menugroup->todo = 'my'; +$lang->menugroup->action = 'admin'; /* 错误提示信息。*/ $lang->error->companyNotFound = "您访问的域名 %s 没有对应的公司。"; diff --git a/module/task/control.php b/module/task/control.php index 7c6890c1e4..e613783774 100644 --- a/module/task/control.php +++ b/module/task/control.php @@ -194,14 +194,12 @@ class task extends control { if($confirm == 'no') { - echo js::confirm($this->lang->task->confirmDelete, $this->createLink('task', 'delete', "projectID=$projectID&taskID=$taskID&confirm=yes")); - exit; + die(js::confirm($this->lang->task->confirmDelete, inlink('delete', "projectID=$projectID&taskID=$taskID&confirm=yes"))); } else { $this->task->delete($taskID); - echo js::locate($this->createLink('project', 'browse', "projectID=$projectID"), 'parent'); - exit; + die(js::locate($this->createLink('project', 'browse', "projectID=$projectID"), 'parent')); } } diff --git a/www/theme/default/style.css b/www/theme/default/style.css index 3d22621a6b..96f865e0fa 100644 --- a/www/theme/default/style.css +++ b/www/theme/default/style.css @@ -261,3 +261,4 @@ table.tablesorter thead tr .headerSortDown { background-image: url(./images/tabl .fail {color:red} .hand {cursor:pointer} .strong {font-weight:bold} +.deleted {text-decoration:line-through}