diff --git a/module/action/lang/en.php b/module/action/lang/en.php index 3b96649611..332d02b3cd 100755 --- a/module/action/lang/en.php +++ b/module/action/lang/en.php @@ -25,6 +25,7 @@ $lang->action->undelete = 'Restore'; $lang->action->hideOne = 'Hide'; $lang->action->hideAll = 'Hide All'; $lang->action->editComment = 'Edit'; +$lang->action->create = 'Create Comment'; $lang->action->comment = 'Comment'; $lang->action->trashTips = 'Note: All Deletion in ZenTao are logical.'; @@ -53,6 +54,14 @@ $lang->action->dynamic->all = 'All'; $lang->action->dynamic->hidden = 'Hidden'; $lang->action->dynamic->search = 'Search'; +$lang->action->periods['all'] = $lang->action->dynamic->all; +$lang->action->periods['today'] = $lang->action->dynamic->today; +$lang->action->periods['yesterday'] = $lang->action->dynamic->yesterday; +$lang->action->periods['thisweek'] = $lang->action->dynamic->thisWeek; +$lang->action->periods['lastweek'] = $lang->action->dynamic->lastWeek; +$lang->action->periods['thismonth'] = $lang->action->dynamic->thisMonth; +$lang->action->periods['lastmonth'] = $lang->action->dynamic->lastMonth; + $lang->action->objectTypes['product'] = $lang->productCommon; $lang->action->objectTypes['story'] = 'Story'; $lang->action->objectTypes['productplan'] = 'Plan'; diff --git a/module/action/lang/zh-cn.php b/module/action/lang/zh-cn.php index cec1875adc..5fd841c37c 100755 --- a/module/action/lang/zh-cn.php +++ b/module/action/lang/zh-cn.php @@ -54,6 +54,14 @@ $lang->action->dynamic->all = '所有'; $lang->action->dynamic->hidden = '已隐藏'; $lang->action->dynamic->search = '搜索'; +$lang->action->periods['all'] = $lang->action->dynamic->all; +$lang->action->periods['today'] = $lang->action->dynamic->today; +$lang->action->periods['yesterday'] = $lang->action->dynamic->yesterday; +$lang->action->periods['thisweek'] = $lang->action->dynamic->thisWeek; +$lang->action->periods['lastweek'] = $lang->action->dynamic->lastWeek; +$lang->action->periods['thismonth'] = $lang->action->dynamic->thisMonth; +$lang->action->periods['lastmonth'] = $lang->action->dynamic->lastMonth; + $lang->action->objectTypes['product'] = $lang->productCommon; $lang->action->objectTypes['story'] = '需求'; $lang->action->objectTypes['productplan'] = '计划'; diff --git a/module/action/model.php b/module/action/model.php index c933e90787..04cbb03805 100755 --- a/module/action/model.php +++ b/module/action/model.php @@ -967,25 +967,6 @@ class actionModel extends model $this->file->updateObjectID($this->post->uid, $action->objectID, $action->objectType); } - /** - * Get action count. - * - * @param string $type - * @param string $id - * @access public - * @return int - */ - public function getCount($type = 'account', $id = '') - { - if($type == 'account' and empty($id)) $id = $this->app->user->account; - return $this->dao->select('count(*) AS count')->from(TABLE_ACTION) - ->where('1=1') - ->beginIF($type == 'account')->andWhere('actor')->eq($id)->fi() - ->beginIF($type == 'product')->andWhere('product')->like("%,$id,%")->fi() - ->beginIF($type == 'project')->andWhere('project')->eq($id)->fi() - ->fetch('count'); - } - /** * Build date group by actions * diff --git a/module/block/control.php b/module/block/control.php index 5e73475605..c8e9bc0d06 100644 --- a/module/block/control.php +++ b/module/block/control.php @@ -696,16 +696,30 @@ class block extends control /** * Print statistic block. + * + * @param string $module + * @access public + * @return void + */ + public function printStatisticBlock($module = 'product') + { + $func = 'print' . ucfirst($module) . 'StatisticBlock'; + $this->view->module = $module; + $this->$func(); + } + + /** + * Print product statistic block. * * @access public * @return void */ - public function printStatisticBlock() + public function printProductStatisticBlock() { if(!empty($this->params->type) and preg_match('/[^a-zA-Z0-9_]/', $this->params->type)) die(); $status = isset($this->params->type) ? $this->params->type : ''; - $orderBy = isset($this->params->type) ? $this->params->orderBy : 'id_asc'; + $orderBy = isset($this->params->orderBy) ? $this->params->orderBy : 'id_asc'; $num = isset($this->params->num) ? (int)$this->params->num : 0; /* Get products. */ @@ -830,6 +844,127 @@ class block extends control $this->view->products = $products; } + /** + * Print project statistic block. + * + * @access public + * @return void + */ + public function printProjectStatisticBlock() + { + if(!empty($this->params->type) and preg_match('/[^a-zA-Z0-9_]/', $this->params->type)) die(); + + $status = isset($this->params->type) ? $this->params->type : ''; + $orderBy = isset($this->params->orderBy) ? $this->params->orderBy : 'id_asc'; + $num = isset($this->params->num) ? (int)$this->params->num : 0; + + /* Get projects. */ + $projects = $this->loadModel('project')->getList($status); + foreach($projects as $projectID => $project) + { + if(!$this->project->checkPriv($project)) unset($projects[$projectID]); + } + $projectIDList = array_keys($projects); + if(!$projectIDList) + { + $this->view->projects = $projects; + return false; + } + $projects = $this->dao->select('*')->from(TABLE_PROJECT) + ->where('id')->in($projectIDList) + ->orderBy($orderBy) + ->beginIF($this->viewType != 'json')->limit($num)->fi() + ->fetchAll('id'); + + + /* Get tasks. */ + $yesterday = date('Y-m-d', strtotime('-1 day')); + $tasks = $this->dao->select("project, count(id) as totalTasks, count(status not in ('wait,doing,pause') or null) as undoneTasks, count(finishedDate like '{$yesterday}%' or null) as yesterdayFinished, sum(if(status != 'cancel', estimate, 0)) as totalEstimate, sum(if(status != 'cancel', consumed, 0)) as totalConsumed, sum(if(status != 'cancel', `left`, 0)) as totalLeft")->from(TABLE_TASK) + ->where('project')->in($projectIDList) + ->andWhere('deleted')->eq(0) + ->andWhere('parent')->eq(0) + ->groupBy('project') + ->fetchAll('project'); + + foreach($tasks as $projectID => $task) + { + foreach($task as $key => $value) + { + if($key == 'project') continue; + $projects[$projectID]->$key = $value; + } + } + + /* Get stories. */ + $stories = $this->dao->select("t1.project, count(t2.status) as totalStories, count(t2.status != 'closed' or null) as unclosedStories, count(t2.stage = 'released' or null) as releasedStories")->from(TABLE_PROJECTSTORY)->alias('t1') + ->leftJoin(TABLE_STORY)->alias('t2')->on('t1.story = t2.id') + ->where('t1.project')->in($projectIDList) + ->andWhere('t2.deleted')->eq(0) + ->groupBy('project') + ->fetchAll('project'); + + foreach($stories as $projectID => $story) + { + foreach($story as $key => $value) + { + if($key == 'project') continue; + $projects[$projectID]->$key = $value; + } + } + + /* Get bugs. */ + $bugs = $this->dao->select("project, status, count(status) as totalBugs, count(status = 'active' or null) as activeBugs, count(resolvedDate like '{$yesterday}%' or null) as yesterdayResolved")->from(TABLE_BUG) + ->where('project')->in($projectIDList) + ->andWhere('deleted')->eq(0) + ->groupBy('project') + ->fetchAll('project'); + + foreach($bugs as $projectID => $bug) + { + foreach($bug as $key => $value) + { + if($key == 'project') continue; + $projects[$projectID]->$key = $value; + } + } + + foreach($projects as $project) + { + if(!isset($projects[$project->id]->totalTasks)) + { + $projects[$project->id]->totalTasks = 0; + $projects[$project->id]->undoneTasks = 0; + $projects[$project->id]->yesterdayFinished = 0; + $projects[$project->id]->totalEstimate = 0; + $projects[$project->id]->totalConsumed = 0; + $projects[$project->id]->totalLeft = 0; + } + if(!isset($projects[$project->id]->totalBugs)) + { + $projects[$project->id]->totalBugs = 0; + $projects[$project->id]->activeBugs = 0; + $projects[$project->id]->yesterdayResolved = 0; + } + if(!isset($projects[$project->id]->totalStories)) + { + $projects[$project->id]->totalStories = 0; + $projects[$project->id]->unclosedStories = 0; + $projects[$project->id]->releasedStories = 0; + } + + $projects[$project->id]->progress = ($project->totalConsumed || $project->totalLeft) ? round($project->totalConsumed / ($project->totalConsumed + $project->totalLeft), 2) * 100 : 0; + $projects[$project->id]->taskProgress = $project->totalTasks ? round(($project->totalTasks - $project->undoneTasks) / $project->totalTasks, 2) * 100 : 0; + $projects[$project->id]->storyProgress = $project->totalStories ? round(($project->totalStories - $project->unclosedStories) / $project->totalStories, 2) * 100 : 0; + $projects[$project->id]->bugProgress = $project->totalBugs ? round(($project->totalBugs - $project->activeBugs) / $project->totalBugs, 2) * 100 : 0; + } + + $this->app->loadLang('task'); + $this->app->loadLang('story'); + $this->app->loadLang('bug'); + + $this->view->projects = $projects; + } + /** * Print overview block. * diff --git a/module/block/lang/en.php b/module/block/lang/en.php index b7c7c1defe..b7b0d5e403 100644 --- a/module/block/lang/en.php +++ b/module/block/lang/en.php @@ -266,6 +266,12 @@ $lang->block->orderByList->product['id_desc'] = 'ID Descending'; $lang->block->orderByList->product['status_asc'] = 'Status Ascending'; $lang->block->orderByList->product['status_desc'] = 'Status Descending'; +$lang->block->orderByList->project = array(); +$lang->block->orderByList->project['id_asc'] = 'ID Ascending'; +$lang->block->orderByList->project['id_desc'] = 'ID Descending'; +$lang->block->orderByList->project['status_asc'] = 'Status Ascending'; +$lang->block->orderByList->project['status_desc'] = 'Status Descending'; + $lang->block->orderByList->task = array(); $lang->block->orderByList->task['id_asc'] = 'ID Ascending'; $lang->block->orderByList->task['id_desc'] = 'ID Descending'; diff --git a/module/block/lang/zh-cn.php b/module/block/lang/zh-cn.php index 51dadb7892..7805763983 100644 --- a/module/block/lang/zh-cn.php +++ b/module/block/lang/zh-cn.php @@ -266,6 +266,12 @@ $lang->block->orderByList->product['id_desc'] = 'ID 递减'; $lang->block->orderByList->product['status_asc'] = '状态正序'; $lang->block->orderByList->product['status_desc'] = '状态倒序'; +$lang->block->orderByList->project = array(); +$lang->block->orderByList->project['id_asc'] = 'ID 递增'; +$lang->block->orderByList->project['id_desc'] = 'ID 递减'; +$lang->block->orderByList->project['status_asc'] = '状态正序'; +$lang->block->orderByList->project['status_desc'] = '状态倒序'; + $lang->block->orderByList->task = array(); $lang->block->orderByList->task['id_asc'] = 'ID 递增'; $lang->block->orderByList->task['id_desc'] = 'ID 递减'; diff --git a/module/block/model.php b/module/block/model.php index a3bee0f833..80f719019b 100644 --- a/module/block/model.php +++ b/module/block/model.php @@ -394,12 +394,28 @@ class blockModel extends model } /** - * Get product statistic params. + * Get statistic params. * * @access public * @return string */ - public function getStatisticParams() + public function getStatisticParams($module = 'product') + { + if($module == 'product') return $this->getProductStatisticParams($module); + if($module == 'project') return $this->getProjectStatisticParams($module); + + $params = new stdclass(); + $params = $this->onlyNumParams($params); + return json_encode($params); + } + + /** + * Get product statistic params. + * + * @access public + * @return void + */ + public function getProductStatisticParams() { $params = new stdclass(); $params->type['name'] = $this->lang->block->type; @@ -414,6 +430,27 @@ class blockModel extends model return json_encode($this->onlyNumParams($params)); } + /** + * Get project statistic params. + * + * @access public + * @return void + */ + public function getProjectStatisticParams() + { + $params = new stdclass(); + $params->type['name'] = $this->lang->block->type; + $params->type['options'] = $this->lang->block->typeList->project; + $params->type['control'] = 'select'; + + $params->orderBy['name'] = $this->lang->block->orderBy; + $params->orderBy['default'] = 'id_desc'; + $params->orderBy['options'] = $this->lang->block->orderByList->project; + $params->orderBy['control'] = 'select'; + + return json_encode($this->onlyNumParams($params)); + } + /** * Get product overview pararms. * diff --git a/module/block/view/productstatisticblock.html.php b/module/block/view/productstatisticblock.html.php new file mode 100644 index 0000000000..62d35963d5 --- /dev/null +++ b/module/block/view/productstatisticblock.html.php @@ -0,0 +1,164 @@ + + * @package block + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
+
+
+ +
+
+
+
+
story->total;?>
+ stories):?> +
stories);?>
+ id}", $lang->story->viewAll . '', '', 'class="btn btn-primary btn-circle btn-icon-right btn-sm"');?> + +
0
+ id}", '' . $lang->story->create, '', 'class="btn btn-primary btn-circle btn-icon-left btn-sm"');?> + +
+
    + statistic->storyStages as $stage):?> +
  • +
    + story->stageList, $stage);?> + stories ? zget($product->stories, $stage, 0) : 0;?> +
    +
  • + +
+
+ stories):?> +
+
+ plans ? array_sum($product->plans) : 0;?> + plans ? zget($product->plans, 'unexpired', 0) : 0;?> + + +
+
+
+
+ +
+ id}", "" . $lang->productplan->create, '', "class='btn btn-info'");?> +
+ +
+
+ story->planAB;?> / productplan->featureBar['browse']['unexpired'];?> +
+
+ / +
+
+
+
+ projects ? array_sum($product->projects) : 0;?> + projects ? zget($product->projects, 'doing', 0) : 0;?> + projects ? zget($product->projects, 'delay', 0) : 0;?> + + +
+ + project->delayed;?> + +
+
+
+
+ +
+ id}", "" . $lang->project->create, '', "class='btn btn-info'");?> +
+ +
+
+ projectCommon;?> / project->statusList['doing'];?> +
+
+ / +
+
+
+
+ releases ? array_sum($product->releases) : 0;?> + releases ? zget($product->releases, 'normal', 0) : 0;?> + + +
+ lastRelease):?> + release->yesterday;?> lastRelease;?> + +
+
+
+
+ +
+ id}", "" . $lang->release->create, '', "class='btn btn-info'");?> +
+ +
+
+ release->common;?> / release->statusList['normal'];?> +
+
+ / +
+
+
+
+ +
+
+ +
+
+ +
+
+
diff --git a/module/block/view/projectstatisticblock.html.php b/module/block/view/projectstatisticblock.html.php new file mode 100644 index 0000000000..264cb9ae17 --- /dev/null +++ b/module/block/view/projectstatisticblock.html.php @@ -0,0 +1,121 @@ +
+
+
+ +
+
+
+
+ +
+ task->statusList['done'];?> + progress;?>percent;?> +
+
+
+
+
project->totalEstimate;?>
+
totalEstimate;?> task->hour;?>
+
+
+ +
project->totalConsumed;?>
+
totalConsumed;?> task->hour;?>
+
+
+ +
project->totalLeft;?>
+
totalLeft;?> task->hour;?>
+
+
+
+
+
+
task->yesterdayFinished;?> yesterdayFinished;?>
+
+
+
+
+
+
+ task->allTasks;?> task->noFinished;?> +
+
+ totalTasks;?> undoneTasks;?> +
+
+
+
+
story->stageList['released'];?> releasedStories;?>
+
+
+
+
+
+ story->total;?> story->unclosed;?> +
+
+ totalStories;?> unclosedStories;?> +
+
+
+
+
bug->yesterdayResolved;?> yesterdayResolved;?>
+
+
+
+
+
+
+ bug->allBugs;?> bug->unResolved;?> +
+
+ totalBugs;?> activeBugs;?> +
+
+
+
+
+
+ +
+
+ +
+
+
+ + diff --git a/module/block/view/statisticblock.html.php b/module/block/view/statisticblock.html.php index 62d35963d5..c7357605de 100644 --- a/module/block/view/statisticblock.html.php +++ b/module/block/view/statisticblock.html.php @@ -10,155 +10,4 @@ * @link http://www.zentao.net */ ?> - -
-
-
- -
-
-
-
-
story->total;?>
- stories):?> -
stories);?>
- id}", $lang->story->viewAll . '', '', 'class="btn btn-primary btn-circle btn-icon-right btn-sm"');?> - -
0
- id}", '' . $lang->story->create, '', 'class="btn btn-primary btn-circle btn-icon-left btn-sm"');?> - -
-
    - statistic->storyStages as $stage):?> -
  • -
    - story->stageList, $stage);?> - stories ? zget($product->stories, $stage, 0) : 0;?> -
    -
  • - -
-
- stories):?> -
-
- plans ? array_sum($product->plans) : 0;?> - plans ? zget($product->plans, 'unexpired', 0) : 0;?> - - -
-
-
-
- -
- id}", "" . $lang->productplan->create, '', "class='btn btn-info'");?> -
- -
-
- story->planAB;?> / productplan->featureBar['browse']['unexpired'];?> -
-
- / -
-
-
-
- projects ? array_sum($product->projects) : 0;?> - projects ? zget($product->projects, 'doing', 0) : 0;?> - projects ? zget($product->projects, 'delay', 0) : 0;?> - - -
- - project->delayed;?> - -
-
-
-
- -
- id}", "" . $lang->project->create, '', "class='btn btn-info'");?> -
- -
-
- projectCommon;?> / project->statusList['doing'];?> -
-
- / -
-
-
-
- releases ? array_sum($product->releases) : 0;?> - releases ? zget($product->releases, 'normal', 0) : 0;?> - - -
- lastRelease):?> - release->yesterday;?> lastRelease;?> - -
-
-
-
- -
- id}", "" . $lang->release->create, '', "class='btn btn-info'");?> -
- -
-
- release->common;?> / release->statusList['normal'];?> -
-
- / -
-
-
-
- -
-
- -
-
- -
-
-
+ diff --git a/module/bug/lang/zh-cn.php b/module/bug/lang/zh-cn.php index 111bd2ab8f..da5380a683 100644 --- a/module/bug/lang/zh-cn.php +++ b/module/bug/lang/zh-cn.php @@ -103,23 +103,24 @@ $lang->bug->copy = '复制Bug'; $lang->bug->search = '搜索'; /* 查询条件列表。*/ -$lang->bug->assignToMe = '指派给我'; -$lang->bug->openedByMe = '由我创建'; -$lang->bug->resolvedByMe = '由我解决'; -$lang->bug->closedByMe = '由我关闭'; -$lang->bug->assignToNull = '未指派'; -$lang->bug->unResolved = '未解决'; -$lang->bug->toClosed = '待关闭'; -$lang->bug->unclosed = '未关闭'; -$lang->bug->unconfirmed = '未确认'; -$lang->bug->longLifeBugs = '久未处理'; -$lang->bug->postponedBugs = '被延期'; -$lang->bug->overdueBugs = '过期Bug'; -$lang->bug->allBugs = '所有Bug'; -$lang->bug->byQuery = '搜索'; -$lang->bug->needConfirm = '需求变动'; -$lang->bug->allProduct = '所有' . $lang->productCommon; -$lang->bug->my = '我的'; +$lang->bug->assignToMe = '指派给我'; +$lang->bug->openedByMe = '由我创建'; +$lang->bug->resolvedByMe = '由我解决'; +$lang->bug->closedByMe = '由我关闭'; +$lang->bug->assignToNull = '未指派'; +$lang->bug->unResolved = '未解决'; +$lang->bug->toClosed = '待关闭'; +$lang->bug->unclosed = '未关闭'; +$lang->bug->unconfirmed = '未确认'; +$lang->bug->longLifeBugs = '久未处理'; +$lang->bug->postponedBugs = '被延期'; +$lang->bug->overdueBugs = '过期Bug'; +$lang->bug->allBugs = '所有'; +$lang->bug->byQuery = '搜索'; +$lang->bug->needConfirm = '需求变动'; +$lang->bug->allProduct = '所有' . $lang->productCommon; +$lang->bug->my = '我的'; +$lang->bug->yesterdayResolved = '昨天解决'; $lang->bug->assignToMeAB = '指派给我'; $lang->bug->openedByMeAB = '由我创建'; diff --git a/module/common/lang/zh-cn.php b/module/common/lang/zh-cn.php index 613a7b73ff..6dcdecda03 100644 --- a/module/common/lang/zh-cn.php +++ b/module/common/lang/zh-cn.php @@ -17,6 +17,7 @@ $lang->at = ' 于 '; $lang->downArrow = '↓'; $lang->null = '空'; $lang->ellipsis = '…'; +$lang->percent = '%'; $lang->zentaoPMS = '禅道'; $lang->welcome = "%s项目管理系统"; @@ -241,7 +242,7 @@ $lang->project->subMenu->list->groupTask = '分组视图|project|groupTask|proje $lang->project->subMenu->qa = new stdclass(); $lang->project->subMenu->qa->bug = 'Bug|project|bug|projectID=%s'; $lang->project->subMenu->qa->build = '版本|project|build|projectID=%s'; -$lang->project->subMenu->qa->testtask = '测试单|project|testtask|projectID=%s'; +$lang->project->subMenu->qa->testtask = array('link' => '测试单|project|testtask|projectID=%s', 'subModule' => 'testreport'); $lang->project->subMenu->action = new stdclass(); $lang->project->subMenu->action->dynamic = '动态|project|dynamic|projectID=%s'; diff --git a/module/company/control.php b/module/company/control.php index 43df49b69c..5ee6686219 100644 --- a/module/company/control.php +++ b/module/company/control.php @@ -235,7 +235,6 @@ class company extends control $this->view->pager = $pager; $this->view->param = $param; $this->view->dateGroups = $this->action->buildDateGroup($actions, $direction); - $this->view->allCount = $this->action->getCount('all'); $this->view->direction = $direction; $this->display(); } diff --git a/module/company/view/dynamic.html.php b/module/company/view/dynamic.html.php index bd57fcc688..ddb9dcd48d 100644 --- a/module/company/view/dynamic.html.php +++ b/module/company/view/dynamic.html.php @@ -13,15 +13,18 @@