diff --git a/module/block/control.php b/module/block/control.php
index 35b6c0a885..18d6fd0e40 100644
--- a/module/block/control.php
+++ b/module/block/control.php
@@ -1449,14 +1449,34 @@ class block extends control
$this->display();
}
+ /**
+ * Print contribute block.
+ *
+ * @access public
+ * @return void
+ */
public function printContributeBlock()
{
$this->view->data = $this->block->getContributeBlockData();
}
+ /**
+ * Print recent program block.
+ *
+ * @access public
+ * @return void
+ */
public function printRecentprogramBlock()
{
-
+ $programs = $this->block->getRecentProject();
+
+ $this->loadModel('project');
+ foreach($programs as $programID => $program)
+ {
+ $program->teamCount = count($this->project->getTeamMembers($program->id));
+ }
+
+ $this->view->programs = $programs;
}
public function printProgramteamBlock()
@@ -1607,7 +1627,9 @@ class block extends control
*/
public function printScrumprojectBlock()
{
- $this->view->program = $this->loadModel('project')->getByID($this->session->program);
+ $this->view->projectOverview = $this->dao->select('count(*) total, count(if(status="doing", id, null)) as doing, count(if(status="closed", id, null)) as finish')->from(TABLE_PROJECT)
+ ->where('program')->eq($this->session->program)
+ ->fetch();
}
/**
diff --git a/module/block/css/dashboard.css b/module/block/css/dashboard.css
index 6d6324f9c5..97ce2ac5d6 100644
--- a/module/block/css/dashboard.css
+++ b/module/block/css/dashboard.css
@@ -26,3 +26,24 @@ body {padding-bottom: 20px;}
#dashboard .block-sm .hide-in-sm {display: none;}
#dashboard .block-dynamic .panel-body{overflow-x:hidden;}
.modal-body{padding: 10px 20px 20px 20px;}
+
+#cards {margin: 0 10px;}
+#cards > .col {width: 33.33%;}
+#cards .panel {margin: 10px 0; border: 1px solid #DCDCDC; border-radius: 2px; box-shadow: none; height: 146px; cursor: pointer;}
+#cards .panel:hover {border-color: #006AF1; box-shadow: 0 0 10px 0 rgba(0,0,100,.25);}
+#cards .panel-heading {padding: 12px 24px 10px 16px;}
+#cards .panel-body {padding: 0 16px 16px;}
+#cards .panel-actions {padding: 7px 0;}
+#cards .panel-actions .dropdown-menu > li > a {padding-left: 5px; text-align: left;}
+#cards .panel-actions .dropdown-menu > li > a > i {opacity: .5; display: inline-block; margin-right: 4px; width: 18px; text-align: center;}
+#cards .panel-actions .dropdown-menu > li > a:hover > i {opacity: 1;}
+#cards .project-type-label {padding: 1px 2px;}
+#cards .project-name {font-size: 16px; font-weight: normal; display: inline-block; max-width: 80%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: middle;}
+#cards .project-infos {font-size: 12px;}
+#cards .project-infos > span {display: inline-block; line-height: 12px;}
+#cards .project-infos > span > .icon {font-size: 12px; display: inline-block; position: relative; top: -1px}
+#cards .project-infos > span + span {margin-left: 15px;}
+#cards .project-detail {position: absolute; bottom: 16px; left: 16px; right: 16px; font-size: 12px;}
+#cards .project-detail > p {margin-bottom: 8px;}
+#cards .project-detail .progress {height: 4px;}
+#cards .project-detail .progress-text-left .progress-text {width: 50px; left: -50px;}
diff --git a/module/block/lang/de.php b/module/block/lang/de.php
index d47e52bf16..c551adf31c 100644
--- a/module/block/lang/de.php
+++ b/module/block/lang/de.php
@@ -50,6 +50,8 @@ $lang->block->openedStories = 'The Number Of Stories Created';
$lang->block->resolvedTasks = 'The Number Of Tasks Resolved';
$lang->block->resolvedBugs = 'The Number Of Bugs Resolved';
$lang->block->openedTestcases = 'The Number Of Test Case Created';
+$lang->block->cmmi = 'CMMI 3';
+$lang->block->scrum = 'Scrum+';
$lang->block->params = new stdclass();
$lang->block->params->name = 'Name';
diff --git a/module/block/lang/en.php b/module/block/lang/en.php
index 6b5af66058..b5416da341 100644
--- a/module/block/lang/en.php
+++ b/module/block/lang/en.php
@@ -50,6 +50,8 @@ $lang->block->openedStories = 'The Number Of Stories Created';
$lang->block->resolvedTasks = 'The Number Of Tasks Resolved';
$lang->block->resolvedBugs = 'The Number Of Bugs Resolved';
$lang->block->openedTestcases = 'The Number Of Test Case Created';
+$lang->block->cmmi = 'CMMI 3';
+$lang->block->scrum = 'Scrum+';
$lang->block->params = new stdclass();
$lang->block->params->name = 'Name';
diff --git a/module/block/lang/fr.php b/module/block/lang/fr.php
index 6e528fcec0..a3ecc79af9 100644
--- a/module/block/lang/fr.php
+++ b/module/block/lang/fr.php
@@ -50,6 +50,8 @@ $lang->block->openedStories = 'The Number Of Stories Created';
$lang->block->resolvedTasks = 'The Number Of Tasks Resolved';
$lang->block->resolvedBugs = 'The Number Of Bugs Resolved';
$lang->block->openedTestcases = 'The Number Of Test Case Created';
+$lang->block->cmmi = 'CMMI 3';
+$lang->block->scrum = 'Scrum+';
$lang->block->params = new stdclass();
$lang->block->params->name = 'Nom';
diff --git a/module/block/lang/vi.php b/module/block/lang/vi.php
index 84f76232e4..bc392ee9fd 100644
--- a/module/block/lang/vi.php
+++ b/module/block/lang/vi.php
@@ -50,6 +50,8 @@ $lang->block->openedStories = 'The Number Of Stories Created';
$lang->block->resolvedTasks = 'The Number Of Tasks Resolved';
$lang->block->resolvedBugs = 'The Number Of Bugs Resolved';
$lang->block->openedTestcases = 'The Number Of Test Case Created';
+$lang->block->cmmi = 'CMMI 3';
+$lang->block->scrum = 'Scrum+';
$lang->block->params = new stdclass();
$lang->block->params->name = 'Tên';
diff --git a/module/block/lang/zh-cn.php b/module/block/lang/zh-cn.php
index 95aae7d490..66aaeda051 100644
--- a/module/block/lang/zh-cn.php
+++ b/module/block/lang/zh-cn.php
@@ -51,6 +51,8 @@ $lang->block->openedStories = '创建的需求数';
$lang->block->resolvedTasks = '完成的任务数';
$lang->block->resolvedBugs = '解决Bug数';
$lang->block->openedTestcases = '创建用例数';
+$lang->block->cmmi = 'CMMI 3';
+$lang->block->scrum = 'Scrum+';
$lang->block->params = new stdclass();
$lang->block->params->name = '参数名称';
diff --git a/module/block/lang/zh-tw.php b/module/block/lang/zh-tw.php
index 7eb4b5e6d5..68d200e7c5 100644
--- a/module/block/lang/zh-tw.php
+++ b/module/block/lang/zh-tw.php
@@ -50,6 +50,8 @@ $lang->block->openedStories = '創建的需求數';
$lang->block->resolvedTasks = '完成的任務數';
$lang->block->resolvedBugs = '解決Bug數';
$lang->block->openedTestcases = '創建用例數';
+$lang->block->cmmi = 'CMMI 3';
+$lang->block->scrum = 'Scrum+';
$lang->block->params = new stdclass();
$lang->block->params->name = '參數名稱';
diff --git a/module/block/model.php b/module/block/model.php
index fdf85ec424..a2c633ad8f 100644
--- a/module/block/model.php
+++ b/module/block/model.php
@@ -624,6 +624,12 @@ class blockModel extends model
return $blockPairs;
}
+ /**
+ * Get contribute block data.
+ *
+ * @access public
+ * @return array
+ */
public function getContributeBlockData()
{
$data = array();
@@ -654,6 +660,75 @@ class blockModel extends model
return $data;
}
+ public function getRecentProject()
+ {
+ $projects = $this->loadModel('program')->getUserPrograms('all', 'id_desc', 3);
+ if(empty($projects)) return array();
+
+ $this->loadModel('project');
+ foreach($projects as $projectID => $project)
+ {
+ $project->teamCount = count($this->project->getTeamMembers($project->id));
+ }
+
+ $projectKeys = array_keys($projects);
+ $hours = array();
+ $emptyHour = array('totalEstimate' => 0, 'totalConsumed' => 0, 'totalLeft' => 0, 'progress' => 0);
+
+ /* Get all tasks and compute totalEstimate, totalConsumed, totalLeft, progress according to them. */
+ $tasks = $this->dao->select('id, project, estimate, consumed, `left`, status, closedReason')
+ ->from(TABLE_TASK)
+ ->where('project')->in($projectKeys)
+ ->andWhere('parent')->lt(1)
+ ->andWhere('deleted')->eq(0)
+ ->fetchGroup('project', 'id');
+
+ /* Compute totalEstimate, totalConsumed, totalLeft. */
+ foreach($tasks as $projectID => $projectTasks)
+ {
+ $hour = (object)$emptyHour;
+ foreach($projectTasks as $task)
+ {
+ if($task->status != 'cancel')
+ {
+ $hour->totalEstimate += $task->estimate;
+ $hour->totalConsumed += $task->consumed;
+ }
+ if($task->status != 'cancel' and $task->status != 'closed') $hour->totalLeft += $task->left;
+ }
+ $hours[$projectID] = $hour;
+ }
+
+ /* Compute totalReal and progress. */
+ foreach($hours as $hour)
+ {
+ $hour->totalEstimate = round($hour->totalEstimate, 1) ;
+ $hour->totalConsumed = round($hour->totalConsumed, 1);
+ $hour->totalLeft = round($hour->totalLeft, 1);
+ $hour->totalReal = $hour->totalConsumed + $hour->totalLeft;
+ $hour->progress = $hour->totalReal ? round($hour->totalConsumed / $hour->totalReal, 3) * 100 : 0;
+ }
+
+ /* Process projects. */
+ foreach($projects as $key => $project)
+ {
+ // Process the end time.
+ $project->end = date(DT_DATE1, strtotime($project->end));
+
+ /* Judge whether the project is delayed. */
+ if($project->status != 'done' and $project->status != 'closed' and $project->status != 'suspended')
+ {
+ $delay = helper::diffDate(helper::today(), $project->end);
+ if($delay > 0) $project->delay = $delay;
+ }
+
+ /* Process the hours. */
+ $project->hours = isset($hours[$project->id]) ? $hours[$project->id] : (object)$emptyHour;
+ }
+
+ return $projects;
+ }
+
/**
* Build number params.
*
diff --git a/module/block/view/recentprogramblock.html.php b/module/block/view/recentprogramblock.html.php
index e69de29bb2..b1110f8a46 100644
--- a/module/block/view/recentprogramblock.html.php
+++ b/module/block/view/recentprogramblock.html.php
@@ -0,0 +1,58 @@
+
+ $project):?>
+
+
+
+ template === 'cmmi'): ?>
+
block->cmmi; ?>
+
+
block->scrum; ?>
+
+
name;?>
+
+
+
+
+ program->membersUnit, $project->teamCount); ?>
+ program->hoursUnit, $project->hours->totalEstimate); ?>
+ budget . '' . zget($lang->program->unitList, $project->budgetUnit);?>
+
+ template === 'cmmi'): ?>
+
+
program->ongoingStage; ?>
+
project->statusList, $project->status);?>
+
+
+
+
program->lastIteration; ?>
+
+
name; ?>
+
+
+
+ hours->progress;?>%
+
+
+
+
+
+
+
+
+
+
+
diff --git a/module/block/view/scrumprojectblock.html.php b/module/block/view/scrumprojectblock.html.php
index e69de29bb2..9590d096d9 100644
--- a/module/block/view/scrumprojectblock.html.php
+++ b/module/block/view/scrumprojectblock.html.php
@@ -0,0 +1,47 @@
+
+ * @package block
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+?>
+
+block->emptyTip;?>
+
+
+
+
+
+
+ -
+ 0
+ 进行中
+
+ -
+ 100
+ 已挂起
+
+
+
+
+
diff --git a/module/issue/config.php b/module/issue/config.php
index 01d2d7364f..11cff632a4 100644
--- a/module/issue/config.php
+++ b/module/issue/config.php
@@ -1,12 +1,41 @@
issue->create = new stdclass();
-$config->issue->edit = new stdclass();
+$config->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->create->requiredFields = 'title,type,severity';
+$config->issue->edit->requiredFields = 'title,type,severity';
-$config->issue->editor = new stdclass();
+$config->issue->editor = new stdclass();
+$config->issue->editor->view = array('id' => 'comment,lastComment', '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' => 'spec,steps,desc,resolutionComment', 'tools' => 'simpleTools');
+
+global $lang;
+
+$config->issue->search['module'] = 'issue';
+
+$config->issue->search['fields']['title'] = $lang->issue->title;
+$config->issue->search['fields']['id'] = $lang->issue->id;
+$config->issue->search['fields']['pri'] = $lang->issue->pri;
+$config->issue->search['fields']['severity'] = $lang->issue->severity;
+$config->issue->search['fields']['type'] = $lang->issue->type;
+$config->issue->search['fields']['ceratedBy'] = $lang->issue->createdBy;
+$config->issue->search['fields']['createdDate'] = $lang->issue->createdDate;
+$config->issue->search['fields']['closeBy'] = $lang->issue->closeBy;
+$config->issue->search['fields']['closedDate'] = $lang->issue->closedDate;
+$config->issue->search['fields']['assignedTo'] = $lang->issue->assignedTo;
+$config->issue->search['fields']['assignedDate'] = $lang->issue->assignedDate;
+
+$config->issue->search['params']['title'] = array('operator' => 'include', 'control' => 'input', 'values' => '');
+$config->issue->search['params']['id'] = array('operator' => '=', 'control' => 'input', 'values' => '');
+$config->issue->search['params']['pri'] = array('operator' => '=', 'control' => 'select', 'values' => $lang->issue->priList);
+$config->issue->search['params']['severity'] = array('operator' => '=', 'control' => 'select', 'values' => $lang->issue->severityList);
+$config->issue->search['params']['type'] = array('operator' => '=', 'control' => 'select', 'values' => $lang->issue->typeList);
+$config->issue->search['params']['ceratedBy'] = array('operator' => '=', 'control' => 'select', 'values' => 'users');
+$config->issue->search['params']['createdDate'] = array('operator' => '=', 'control' => 'input', 'values' => '', 'class' => 'date');
+$config->issue->search['params']['closeBy'] = array('operator' => '=', 'control' => 'select', 'values' => 'users');
+$config->issue->search['params']['closedDate'] = array('operator' => '=', 'control' => 'input', 'values' => '', 'class' => 'date');
+$config->issue->search['params']['assignedTo'] = array('operator' => '=', 'control' => 'select', 'values' => 'users');
+$config->issue->search['params']['assignedDate'] = array('operator' => '=', 'control' => 'input', 'values' => '', 'class' => 'date');
diff --git a/module/issue/control.php b/module/issue/control.php
index 43eb899112..0ee036fb89 100644
--- a/module/issue/control.php
+++ b/module/issue/control.php
@@ -15,6 +15,7 @@ class issue extends control
* Get issue list data.
*
* @param string $browseType
+ * @param int param
* @param string orderBy
* @param int recTotal
* @param int recPerPage
@@ -22,13 +23,18 @@ class issue extends control
* @access public
* @return void
*/
- public function browse($browseType = 'all', $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1)
+ public function browse($browseType = 'all', $param = 0, $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);
+ /* Build the search form. */
+ $queryID = ($browseType == 'bysearch') ? (int)$param : 0;
+ $actionURL = $this->createLink('issue', 'browse', "browseType=bysearch&queryID=myQueryID");
+ $this->issue->buildSearchForm($actionURL, $queryID);
+
$this->view->title = $this->lang->issue->common . $this->lang->colon . $this->lang->issue->browse;
$this->view->position[] = $this->lang->issue->browse;
@@ -36,9 +42,10 @@ class issue extends control
$this->view->recTotal = $recTotal;
$this->view->recPerPage = $recPerPage;
$this->view->pageID = $pageID;
+ $this->view->param = $param;
$this->view->orderBy = $orderBy;
$this->view->browseType = $browseType;
- $this->view->issueList = $this->issue->getIssueList($browseType, $orderBy, $pager);
+ $this->view->issueList = $this->issue->getIssueList($browseType, $queryID, $orderBy, $pager);
$this->view->users = $this->loadModel('user')->getPairs('noletter|pofirst|nodeleted');
$this->display();
@@ -80,7 +87,7 @@ class issue extends control
if($_POST)
{
$results = $this->issue->batchCreate();
- if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
+ if(dao::isError()) $this->send(array('result' => 'fail', 'message' => dao::getError()));
$this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => inLink('browse', 'browseType=all')));
}
diff --git a/module/issue/lang/zh-cn.php b/module/issue/lang/zh-cn.php
index 662743a67d..372b862b7a 100644
--- a/module/issue/lang/zh-cn.php
+++ b/module/issue/lang/zh-cn.php
@@ -31,6 +31,7 @@ $lang->issue->resolved = '解决';
$lang->issue->id = '编号';
$lang->issue->delete = '删除';
+$lang->issue->search = '搜索';
$lang->issue->basicInfo = '基本信息';
$lang->issue->active = '激活';
$lang->issue->assign = '指派';
diff --git a/module/issue/model.php b/module/issue/model.php
index a6ec774167..fdf2188bea 100644
--- a/module/issue/model.php
+++ b/module/issue/model.php
@@ -57,17 +57,53 @@ class issueModel extends model
return $issueID;
}
+ /**
+ * Get stakeholder issue list data.
+ * @param string $owner
+ * @param string $activityID
+ * @param object $pager
+ *
+ * @access public
+ * @return object
+ */
+ public function getStakeholderIssue($owner = '', $activityID = 0, $pager = null)
+ {
+ $issueList = $this->dao->select('*')->from(TABLE_ISSUE)
+ ->where('deleted')->eq('0')
+ ->beginIF($owner)->andWhere('owner')->eq($owner)->fi()
+ ->beginIF($activityID)->andWhere('activity')->eq($activityID)->fi()
+ ->orderBy('id_desc')
+ ->page($pager)
+ ->fetchAll();
+
+ return $issueList;
+ }
+
/**
* Get question list data.
*
* @param string $browseType
+ * @param int $queryID
* @param string $orderBy
* @param object $pager
* @access public
* @return object
*/
- public function getIssueList($browseType = 'all', $orderBy = 'id_desc', $pager = null)
+ public function getIssueList($browseType = 'all', $queryID = 0, $orderBy = 'id_desc', $pager = null)
{
+ $issueQuery = '';
+ if($browseType == 'bysearch')
+ {
+ $query = $queryID ? $this->loadModel('search')->getQuery($queryID) : '';
+ if($query)
+ {
+ $this->session->set('issueQuery', $query->sql);
+ $this->session->set('issueForm', $query->form);
+ }
+ if($this->session->issueQuery == false) $this->session->set('issueQuery', ' 1=1');
+ $issueQuery = $this->session->issueQuery;
+ }
+
$issueList = $this->dao->select('*')->from(TABLE_ISSUE)
->where('program')->eq($this->session->program)
->andWhere('deleted')->eq('0')
@@ -76,6 +112,7 @@ class issueModel extends model
->beginIF($browseType == 'closed')->andWhere('status')->eq('closed')->fi()
->beginIF($browseType == 'suspended')->andWhere('status')->eq('suspended')->fi()
->beginIF($browseType == 'cancelled')->andWhere('status')->eq('canceled')->fi()
+ ->beginIF($browseType == 'bysearch')->andWhere($issueQuery)->fi()
->orderBy($orderBy)
->page($pager)
->fetchAll();
@@ -83,6 +120,11 @@ class issueModel extends model
return $issueList;
}
+ public function getActivityList()
+ {
+ return $this->dao->select('id,name')->from(TABLE_ACTIVITY)->where('deleted')->eq('0')->orderBy('id_desc')->fetchPairs();
+ }
+
public function getBlockIssues($browseType = 'all', $limit = 15, $orderBy = 'id_desc')
{
$issueList = $this->dao->select('*')->from(TABLE_ISSUE)
@@ -268,7 +310,7 @@ class issueModel extends model
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)));
+ if($field and empty($issue["$field"])) return dao::$errors['message'][] = sprintf($this->lang->error->notempty, $this->lang->issue->$field);
}
$issues[] = $issue;
@@ -353,4 +395,19 @@ class issueModel extends model
return $this->dao->lastInsertID();
}
+ /**
+ * Build search form.
+ *
+ * @param string $actionURL
+ * @param int $queryID
+ * @access public
+ * @return void
+ */
+ public function buildSearchForm($actionURL, $queryID)
+ {
+ $this->config->issue->search['actionURL'] = $actionURL;
+ $this->config->issue->search['queryID'] = $queryID;
+
+ $this->loadModel('search')->setSearchParams($this->config->issue->search);
+ }
}
diff --git a/module/issue/view/browse.html.php b/module/issue/view/browse.html.php
index dd2c11198c..17aa5a0853 100644
--- a/module/issue/view/browse.html.php
+++ b/module/issue/view/browse.html.php
@@ -20,6 +20,7 @@
echo html::a($this->createLink('issue', 'browse', 'browseType=' . $label), '' . $labelName . '', '', "class='btn btn-link $active'");
}
?>
+ issue->search;?>
" . $lang->issue->create, '', "class='btn btn-primary'");?>
@@ -28,22 +29,23 @@
+
noData;?>
diff --git a/module/issue/view/create.html.php b/module/issue/view/create.html.php
index d1b607a15b..d770e503ac 100644
--- a/module/issue/view/create.html.php
+++ b/module/issue/view/create.html.php
@@ -13,10 +13,10 @@
-
-
-
issue->create;?>
-
+
+ issue->create;?>
+
+