Merge branch '20.x' of github.com:easysoft/zentaopms into 20.x
This commit is contained in:
+10
-41
@@ -701,23 +701,8 @@ class block extends control
|
||||
public function printProgramBlock()
|
||||
{
|
||||
$this->loadModel('project');
|
||||
$programs = $this->loadModel('program')->getUserPrograms('all', $this->params->orderBy, $this->params->num);
|
||||
foreach($programs as $programID => $program)
|
||||
{
|
||||
$members = $this->project->getTeamMemberPairs($programID);
|
||||
$consumed = $this->dao->select('sum(consumed) as consumed')->from(TABLE_TASK)->where('program')->eq($programID)->andWhere('deleted')->eq(0)->andWhere('parent')->lt(1)->fetch('consumed');
|
||||
$leftTasks = $this->dao->select('count(*) as leftTasks')->from(TABLE_TASK)->where('program')->eq($programID)->andWhere('deleted')->eq(0)->andWhere('status')->in('wait,doing,pause')->fetch('leftTasks');
|
||||
$leftStories = $this->dao->select('count(*) as leftStories')->from(TABLE_STORY)->where('program')->eq($programID)->andWhere('deleted')->eq(0)->andWhere('status')->eq('active')->fetch('leftStories');
|
||||
$leftBugs = $this->dao->select('count(*) as leftBugs')->from(TABLE_BUG)->where('program')->eq($programID)->andWhere('deleted')->eq(0)->andWhere('status')->eq('active')->fetch('leftBugs');
|
||||
|
||||
$program->countMembers = count($members) ? count($members) - 1 : 0;
|
||||
$program->consumed = $consumed ? $consumed : 0;
|
||||
$program->leftTasks = $leftTasks ? $leftTasks : 0;
|
||||
$program->leftStories = $leftStories ? $leftStories : 0;
|
||||
$program->leftBugs = $leftBugs ? $leftBugs : 0;
|
||||
}
|
||||
|
||||
$this->view->programs = $programs;
|
||||
$this->view->programs = $this->loadModel('program')->getUserPrograms('all', $this->params->orderBy, $this->params->num);
|
||||
$this->view->users = $this->loadModel('user')->getPairs('noletter');
|
||||
}
|
||||
|
||||
@@ -776,8 +761,8 @@ class block extends control
|
||||
$this->app->loadLang('task');
|
||||
$this->app->loadLang('story');
|
||||
|
||||
$status = isset($this->params->type) ? $this->params->type : 'all';
|
||||
$num = isset($this->params->num) ? (int)$this->params->num : 15;
|
||||
$status = isset($this->params->type) ? $this->params->type : 'all';
|
||||
$num = isset($this->params->num) ? (int)$this->params->num : 15;
|
||||
|
||||
/* Get projects. */
|
||||
$programs = $this->loadModel('program')->getUserPrograms($status, 'id_desc', $num);
|
||||
@@ -790,14 +775,6 @@ class block extends control
|
||||
foreach($programs as $programID => $program)
|
||||
{
|
||||
$program->allStories = $program->doneStories = $program->leftStories = 0;
|
||||
$program->consumed = $this->dao->select('sum(consumed) as consumed')->from(TABLE_TASK)
|
||||
->where('program')->eq($programID)
|
||||
->andWhere('deleted')->eq(0)
|
||||
->andWhere('parent')->lt(1)
|
||||
->fetch('consumed');
|
||||
|
||||
$members = $this->project->getTeamMemberPairs($programID);
|
||||
$program->countMembers = count($members) ? count($members) - 1 : 0;
|
||||
|
||||
$stories = $this->dao->select('id, status')->from(TABLE_STORY)
|
||||
->where('deleted')->eq(0)
|
||||
@@ -1088,7 +1065,7 @@ class block extends control
|
||||
$this->view->cv = $this->weekly->getCV($this->view->ev, $this->view->ac);
|
||||
|
||||
$this->view->current = $current;
|
||||
$this->view->progress = ($task->totalConsumed || $task->totalLeft) ? round($task->totalConsumed / ($task->totalConsumed + $task->totalLeft), 2) * 100 : 0;
|
||||
$this->view->progress = ($task->totalConsumed + $task->totalLeft) ? round($task->totalConsumed / ($task->totalConsumed + $task->totalLeft), 2) * 100 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1164,7 +1141,8 @@ class block extends control
|
||||
$program = $this->loadModel('project')->getByID($this->session->program);
|
||||
|
||||
$begin = $program->begin;
|
||||
$end = helper::today();
|
||||
$today = helper::today();
|
||||
$end = date('Y-m-d', strtotime("$today + 7 days"));
|
||||
|
||||
$projects = $this->project->getProjectsByProgram($program);
|
||||
$projectIdList = array_keys($projects);
|
||||
@@ -1185,10 +1163,9 @@ class block extends control
|
||||
$i ++;
|
||||
}
|
||||
|
||||
$charts['labels'][] = $this->lang->milestone->chart->time . $i . $this->lang->milestone->chart->week;
|
||||
$charts['PV'] .= $this->milestone->getPV($projectIdList, $begin, $end) . ']';
|
||||
$charts['EV'] .= $this->milestone->getEV($projectIdList, $begin, $end) . ']';
|
||||
$charts['AC'] .= $this->milestone->getAC($projectIdList, $begin, $end) . ']';
|
||||
$charts['PV'] .= ']';
|
||||
$charts['EV'] .= ']';
|
||||
$charts['AC'] .= ']';
|
||||
|
||||
$this->view->charts = $charts;
|
||||
}
|
||||
@@ -1468,15 +1445,7 @@ class block extends control
|
||||
*/
|
||||
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;
|
||||
$this->view->programs = $this->loadModel('program')->getProgramStats('all', 3, 'order_desc');
|
||||
}
|
||||
|
||||
public function printProgramteamBlock()
|
||||
|
||||
@@ -26,24 +26,3 @@ 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;}
|
||||
|
||||
@@ -660,75 +660,6 @@ 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.
|
||||
*
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<th class='w-100px'> <?php echo $lang->program->PM;?></th>
|
||||
<th class='w-80px'><?php echo $lang->program->status;?></th>
|
||||
<?php if($longBlock):?>
|
||||
<th class='w-80px'><?php echo $lang->program->countMembers;?></th>
|
||||
<th class='w-80px'><?php echo $lang->program->teamCount;?></th>
|
||||
<th class='w-80px'><?php echo $lang->task->consumed;?></th>
|
||||
<th class='w-100px'><?php echo $lang->program->budget;?></th>
|
||||
<th class='w-80px'><?php echo $lang->program->leftStories;?></th>
|
||||
@@ -34,7 +34,7 @@
|
||||
<span class="status-program status-<?php echo $program->status?>"><?php echo zget($lang->project->statusList, $program->status);?></span>
|
||||
</td>
|
||||
<?php if($longBlock):?>
|
||||
<td><?php echo $program->countMembers;?></td>
|
||||
<td><?php echo $program->teamCount;?></td>
|
||||
<td><?php echo $program->consumed;?></td>
|
||||
<td><?php echo $program->budget . ' ' . zget($lang->program->unitList, $program->budgetUnit);?></td>
|
||||
<td><?php echo $program->leftStories;?></td>
|
||||
|
||||
@@ -135,9 +135,9 @@ $(function()
|
||||
<div class="program-info">
|
||||
<div class='title'><?php echo $lang->program->allInput;?></div>
|
||||
<div class='info'>
|
||||
<span><i class='icon icon-group'></i><?php echo $program->countMembers;?></span>
|
||||
<span><i class='icon icon-clock'></i><?php echo $program->consumed;?></span>
|
||||
<span><i class='icon icon-yen'></i><?php echo $program->budget;?></span>
|
||||
<span><i class='icon icon-group'></i> <?php echo $program->countMembers;?></span>
|
||||
<span><i class='icon icon-clock'></i> <?php echo $program->consumed;?></span>
|
||||
<span><i class='icon icon-cost'></i> <?php echo $program->budget;?></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="project-info">
|
||||
|
||||
@@ -1,44 +1,68 @@
|
||||
<style>
|
||||
#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 .program-type-label {padding: 1px 2px;}
|
||||
#cards .program-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 .program-infos {font-size: 12px;}
|
||||
#cards .program-infos > span {display: inline-block; line-height: 12px;}
|
||||
#cards .program-infos > span > .icon {font-size: 12px; display: inline-block; position: relative; top: -1px}
|
||||
#cards .program-infos > span + span {margin-left: 15px;}
|
||||
#cards .program-detail {position: absolute; bottom: 16px; left: 16px; right: 16px; font-size: 12px;}
|
||||
#cards .program-detail > p {margin-bottom: 8px;}
|
||||
#cards .program-detail .progress {height: 4px;}
|
||||
#cards .program-detail .progress-text-left .progress-text {width: 50px; left: -50px;}
|
||||
</style>
|
||||
<div class='row' id='cards'>
|
||||
<?php foreach ($programs as $projectID => $project):?>
|
||||
<div class='col'>
|
||||
<div class='panel'>
|
||||
<?php foreach ($programs as $programID => $program):?>
|
||||
<div class='col' data-id='<?php echo $programID?>'>
|
||||
<div class='panel' data-url='<?php echo $this->createLink('program', 'index', "programID=$program->id");?>'>
|
||||
<div class='panel-heading'>
|
||||
<?php if($project->template === 'cmmi'): ?>
|
||||
<span class='project-type-label label label-warning label-outline'><?php echo $lang->block->cmmi; ?></span>
|
||||
<strong class='program-name' title='<?php echo $program->name;?>'><?php echo $program->name;?></strong>
|
||||
<?php if($program->template === 'cmmi'): ?>
|
||||
<span class='program-type-label label label-warning label-outline'><?php echo $lang->program->cmmi; ?></span>
|
||||
<?php else: ?>
|
||||
<span class='project-type-label label label-info label-outline'><?php echo $lang->block->scrum; ?></span>
|
||||
<span class='program-type-label label label-info label-outline'><?php echo $lang->program->scrum; ?></span>
|
||||
<?php endif; ?>
|
||||
<strong class='project-name' title='<?php echo $project->name;?>'><?php echo $project->name;?></strong>
|
||||
<nav class='panel-actions nav nav-default'>
|
||||
<li class='dropdown'>
|
||||
<a href='javascript:;' data-toggle='dropdown' class='panel-action'><i class='icon icon-ellipsis-v'></i></a>
|
||||
<ul class='dropdown-menu pull-right'>
|
||||
<li><?php common::printIcon('program', 'group', "projectID=$project->id", $project, 'button', 'group');?></li>
|
||||
<li><?php common::printIcon('program', 'manageMembers', "projectID=$project->id", $project, 'button', 'persons');?></li>
|
||||
<li><?php common::printicon('program', 'activate', "projectid=$project->id", $project, 'button', '', '', 'iframe', true);?></li>
|
||||
<li><?php if(common::hasPriv('program', 'edit')) echo html::a($this->createLink("program", "edit", "projectID=$project->id"), "<i class='icon-edit'></i> " . $lang->edit, '', "");?></li>
|
||||
<li><?php common::printIcon('program', 'start', "projectID=$project->id", $project, 'button', '', '', 'iframe', true);?></li>
|
||||
<li><?php common::printIcon('program', 'suspend', "projectID=$project->id", $project, 'button', '', '', 'iframe', true);?></li>
|
||||
<li><?php common::printIcon('program', 'close', "projectID=$project->id", $project, 'button', '', '', 'iframe', true);?></li>
|
||||
<li><?php if(common::hasPriv('program', 'delete')) echo html::a($this->createLink("project", "delete", "projectID=$project->id"), "<i class='icon-trash'></i> " . $lang->delete, 'hiddenwin', "");?></li>
|
||||
<li><?php common::printIcon('program', 'group', "programID=$program->id", $program, 'button', 'group');?></li>
|
||||
<li><?php common::printIcon('program', 'manageMembers', "programID=$program->id", $program, 'button', 'persons');?></li>
|
||||
<li><?php common::printicon('program', 'activate', "programid=$program->id", $program, 'button', '', '', 'iframe', true);?></li>
|
||||
<li><?php if(common::hasPriv('program', 'edit')) echo html::a($this->createLink("program", "edit", "programID=$program->id"), "<i class='icon-edit'></i> " . $lang->edit, '', "");?></li>
|
||||
<li><?php common::printIcon('program', 'start', "programID=$program->id", $program, 'button', '', '', 'iframe', true);?></li>
|
||||
<li><?php common::printIcon('program', 'suspend', "programID=$program->id", $program, 'button', '', '', 'iframe', true);?></li>
|
||||
<li><?php common::printIcon('program', 'close', "programID=$program->id", $program, 'button', '', '', 'iframe', true);?></li>
|
||||
<li><?php if(common::hasPriv('program', 'delete')) echo html::a($this->createLink("program", "delete", "programID=$program->id"), "<i class='icon-trash'></i> " . $lang->delete, 'hiddenwin', "");?></li>
|
||||
</ul>
|
||||
</li>
|
||||
</nav>
|
||||
</div>
|
||||
<div class='panel-body'>
|
||||
<div class='project-infos'>
|
||||
<span><i class='icon icon-group'></i> <?php printf($lang->program->membersUnit, $project->teamCount); ?></span>
|
||||
<span><i class='icon icon-clock'></i> <?php printf($lang->program->hoursUnit, $project->hours->totalEstimate); ?></span>
|
||||
<span><i class='icon icon-cost'></i> <?php echo $project->budget . '' . zget($lang->program->unitList, $project->budgetUnit);?></span>
|
||||
<div class='program-infos'>
|
||||
<span><i class='icon icon-group'></i> <?php printf($lang->program->membersUnit, $program->teamCount); ?></span>
|
||||
<span><i class='icon icon-clock'></i> <?php printf($lang->program->hoursUnit, $program->estimate); ?></span>
|
||||
<span><i class='icon icon-cost'></i> <?php echo $program->budget . '' . zget($lang->program->unitList, $program->budgetUnit);?></span>
|
||||
</div>
|
||||
<?php if($project->template === 'cmmi'): ?>
|
||||
<div class='project-detail project-stages'>
|
||||
<?php if($program->template === 'cmmi'): ?>
|
||||
<div class='program-detail program-stages'>
|
||||
<p class='text-muted'><?php echo $lang->program->ongoingStage; ?></p>
|
||||
<div class='label label-outline'><?php echo zget($lang->project->statusList, $project->status);?></div>
|
||||
<div class='label label-outline'><?php echo zget($lang->project->statusList, $program->status);?></div>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class='project-detail project-iteration'>
|
||||
<?php $project = $program->projects ? current($program->projects) : '';?>
|
||||
<div class='program-detail program-iteration'>
|
||||
<p class='text-muted'><?php echo $lang->program->lastIteration; ?></p>
|
||||
<?php if($project):?>
|
||||
<div class='row'>
|
||||
<div class='col-xs-5'><?php echo $project->name; ?></div>
|
||||
<div class='col-xs-7'>
|
||||
@@ -49,6 +73,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
@@ -5,3 +5,26 @@ $config->design->editor->create = array('id' => 'desc', 'tools' => 'simpleTools'
|
||||
$config->design->editor->edit = array('id' => 'desc', 'tools' => 'simpleTools');
|
||||
|
||||
$config->design->affectedFixedNum = 7;
|
||||
|
||||
global $lang;
|
||||
$config->design->search['module'] = 'design';
|
||||
$config->design->search['fields']['id'] = $lang->design->id;
|
||||
$config->design->search['fields']['name'] = $lang->design->name;
|
||||
$config->design->search['fields']['type'] = $lang->design->type;
|
||||
$config->design->search['fields']['commit'] = $lang->design->submission;
|
||||
$config->design->search['fields']['commitBy'] = $lang->design->commitBy;
|
||||
$config->design->search['fields']['commitDate'] = $lang->design->commitDate;
|
||||
$config->design->search['fields']['createdBy'] = $lang->design->createdBy;
|
||||
$config->design->search['fields']['createdDate'] = $lang->design->createdDate;
|
||||
$config->design->search['fields']['assignedTo'] = $lang->design->assignedTo;
|
||||
$config->design->search['fields']['story'] = $lang->design->story;
|
||||
|
||||
$config->design->search['params']['name'] = array('operator' => 'include', 'control' => 'input', 'values' => '');
|
||||
$config->design->search['params']['type'] = array('operator' => '=', 'control' => 'select', 'values' => $lang->design->typeList);
|
||||
$config->design->search['params']['commit'] = array('operator' => 'include', 'control' => 'input', 'values' => '');
|
||||
$config->design->search['params']['commitBy'] = array('operator' => '=', 'control' => 'select', 'values' => 'users');
|
||||
$config->design->search['params']['commitDate'] = array('operator' => '=', 'control' => 'input', 'values' => '', 'class' => 'date');
|
||||
$config->design->search['params']['createdBy'] = array('operator' => '=', 'control' => 'select', 'values' => 'users');
|
||||
$config->design->search['params']['createdDate'] = array('operator' => '=', 'control' => 'input', 'values' => '', 'class' => 'date');
|
||||
$config->design->search['params']['assignedTo'] = array('operator' => '=', 'control' => 'select', 'values' => 'users');
|
||||
$config->design->search['params']['story'] = array('operator' => '=', 'control' => 'select', 'values' => '');
|
||||
|
||||
@@ -23,10 +23,15 @@ class design extends control
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function browse($productID = 0, $type = 'all', $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1)
|
||||
public function browse($productID = 0, $type = 'all', $param = '', $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1)
|
||||
{
|
||||
$productID = $this->loadModel('product')->saveState($productID, $this->product->getPairs('nocode'));
|
||||
|
||||
$queryID = ($type == 'bySearch') ? (int)$param : 0;
|
||||
/* Build the search form. */
|
||||
$actionURL = $this->createLink('design', 'browse', "productID=$productID&type=bySearch&queryID=myQueryID");
|
||||
$this->design->buildSearchForm($queryID, $actionURL);
|
||||
|
||||
$this->design->setProductMenu($productID);
|
||||
$product = $this->loadModel('product')->getById($productID);
|
||||
$program = $this->loadModel('project')->getById($product->program);
|
||||
@@ -37,7 +42,7 @@ class design extends control
|
||||
if($this->app->getViewType() == 'mhtml') $recPerPager = 10;
|
||||
$pager = pager::init($recTotal, $recPerPage, $pageID);
|
||||
|
||||
$designs = $this->design->getList($productID, $type, $orderBy, $pager);
|
||||
$designs = $this->design->getList($productID, $type, $queryID, $orderBy, $pager);
|
||||
|
||||
$this->view->title = $this->lang->design->browse;
|
||||
$this->view->position[] = $this->lang->design->browse;
|
||||
@@ -99,6 +104,41 @@ class design extends control
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch create
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function batchCreate($productID = 0)
|
||||
{
|
||||
if($_POST)
|
||||
{
|
||||
$this->design->batchCreate($productID);
|
||||
|
||||
if(dao::isError())
|
||||
{
|
||||
$response['result'] = 'fail';
|
||||
$response['message'] = dao::getError();
|
||||
$this->send($response);
|
||||
}
|
||||
$response['result'] = 'success';
|
||||
$response['message'] = $this->lang->saveSuccess;
|
||||
$response['locate'] = inlink('browse');
|
||||
|
||||
$this->send($response);
|
||||
}
|
||||
|
||||
$this->view->title = $this->lang->design->batchCreate;
|
||||
$this->view->position[] = $this->lang->design->batchCreate;
|
||||
|
||||
$typeList = (array)$this->lang->design->typeList;
|
||||
|
||||
$this->view->typeList = $typeList;
|
||||
$this->view->stories = $this->loadModel('story')->getProductStoryPairs($productID);
|
||||
$this->view->users = $this->loadModel('user')->getPairs('noclosed');
|
||||
$this->display();
|
||||
}
|
||||
/**
|
||||
* View a design.
|
||||
*
|
||||
@@ -224,7 +264,7 @@ class design extends control
|
||||
}
|
||||
|
||||
public function revision($repoID)
|
||||
{
|
||||
{
|
||||
$repo = $this->dao->select('*')->from(TABLE_REPOHISTORY)->where('id')->eq($repoID)->fetch();
|
||||
$repoURL = $this->createLink('repo', 'revision', "repoID=$repo->repo&revistion=$repo->revision");
|
||||
header("location:" . $repoURL);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#featurebar{display:inline-block;}
|
||||
.modal-dialog{width:70% !important}
|
||||
table td{white-space:nowrap;text-overflow:ellipsis;overflow:hidden;}
|
||||
table td{white-space:nowrap;text-overflow:ellipsis;}
|
||||
#querybox #searchform{border-bottom: 1px solid #ddd; margin-bottom: 20px;}
|
||||
|
||||
@@ -9,16 +9,22 @@ $lang->design->actions = '操作';
|
||||
$lang->design->delete = '删除';
|
||||
$lang->design->confirmDelete = '您确定要删除这个设计吗?';
|
||||
$lang->design->edit = '变更';
|
||||
$lang->design->byQuery = '搜索';
|
||||
$lang->design->products = '所属产品';
|
||||
$lang->design->story = '相关需求';
|
||||
$lang->design->file = '附件';
|
||||
$lang->design->id = '编号';
|
||||
$lang->design->story = '需求';
|
||||
$lang->design->ditto = '同上';
|
||||
$lang->design->type = '设计类型';
|
||||
$lang->design->name = '设计名称';
|
||||
$lang->design->create = '创建设计';
|
||||
$lang->design->batchCreate = '批量创建';
|
||||
$lang->design->view = '查看设计';
|
||||
$lang->design->desc = '设计描述';
|
||||
$lang->design->product = '所属产品';
|
||||
$lang->design->basicInfo = '基础信息';
|
||||
$lang->design->commitBy = '由谁提交';
|
||||
$lang->design->commitDate = '提交时间';
|
||||
$lang->design->affectedStory = "影响{$lang->storyCommon}";
|
||||
$lang->design->affectedTasks = '影响任务';
|
||||
@@ -31,6 +37,7 @@ $lang->design->createdDate = '创建时间';
|
||||
$lang->design->basicInfo = '基本信息';
|
||||
|
||||
$lang->design->typeList = array();
|
||||
$lang->design->typeList[''] = '';
|
||||
$lang->design->typeList['HLDS'] = '概要设计';
|
||||
$lang->design->typeList['DDS'] = '详细设计';
|
||||
$lang->design->typeList['DBDS'] = '数据库设计';
|
||||
|
||||
+114
-11
@@ -53,6 +53,39 @@ class designModel extends model
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch create
|
||||
*
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function batchCreate($productID = 0)
|
||||
{
|
||||
$data = fixer::input('post')->get();
|
||||
|
||||
$this->loadModel('action');
|
||||
foreach($data->name as $i => $name)
|
||||
{
|
||||
if(!$name) continue;
|
||||
|
||||
$design = new stdclass();
|
||||
$design->story = $data->story[$i];
|
||||
$design->type = $data->type[$i];
|
||||
$design->name = $name;
|
||||
$design->product = $productID;
|
||||
$design->program = $this->session->program;
|
||||
$design->createdBy = $this->app->user->account;
|
||||
$design->createdDate = helper::now();
|
||||
|
||||
$this->dao->insert(TABLE_DESIGN)->data($design)->autoCheck()->exec();
|
||||
|
||||
$designID = $this->dao->lastInsertID();
|
||||
$this->action->create('design', $designID, 'Opened');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a design.
|
||||
*
|
||||
@@ -135,6 +168,11 @@ class designModel extends model
|
||||
|
||||
$this->dao->replace(TABLE_RELATION)->data($data)->autoCheck()->exec();
|
||||
}
|
||||
$design = new stdclass();
|
||||
$design->commit = implode(",", $revisions);
|
||||
$design->commitDate = helper::now();
|
||||
$design->commitBy = $this->app->user->account;
|
||||
$this->dao->update(TABLE_DESIGN)->data($design)->autoCheck()->where('id')->eq($designID)->exec();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -169,7 +207,7 @@ class designModel extends model
|
||||
$design->productName = $this->dao->findByID($design->product)->from(TABLE_PRODUCT)->fetch('name');
|
||||
|
||||
|
||||
$design->commit = '';
|
||||
$design->commit = '';
|
||||
$relations = $this->loadModel('common')->getRelations('design', $designID, 'commit');
|
||||
foreach($relations as $relation) $design->commit .= html::a(helper::createLink('design', 'revision', "repoID=$relation->BID"), "#$relation->BID", '_blank');
|
||||
return $this->loadModel('file')->replaceImgURL($design, 'desc');
|
||||
@@ -224,24 +262,89 @@ class designModel extends model
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getList($productID, $type = 'all', $orderBy = 'id_desc', $pager = null)
|
||||
public function getList($productID, $type = 'all', $param = 0, $orderBy = 'id_desc', $pager = null)
|
||||
{
|
||||
$designs = $this->dao->select('*')->from(TABLE_DESIGN)
|
||||
->where('deleted')->eq(0)
|
||||
->beginIF($this->session->program)->andWhere('program')->eq($this->session->program)->fi()
|
||||
->beginIF($type != 'all')->andWhere('type')->in($type)->fi()
|
||||
->andWhere('product')->eq($productID)
|
||||
->orderBy($orderBy)
|
||||
->page($pager)
|
||||
->fetchAll('id');
|
||||
if($type == 'bySearch')
|
||||
{
|
||||
$designs = $this->getBySearch($param, $orderBy, $pager);
|
||||
}
|
||||
else
|
||||
{
|
||||
$designs = $this->dao->select('*')->from(TABLE_DESIGN)
|
||||
->where('deleted')->eq(0)
|
||||
->beginIF($this->session->program)->andWhere('program')->eq($this->session->program)->fi()
|
||||
->beginIF($type != 'all')->andWhere('type')->in($type)->fi()
|
||||
->andWhere('product')->eq($productID)
|
||||
->orderBy($orderBy)
|
||||
->page($pager)
|
||||
->fetchAll('id');
|
||||
}
|
||||
|
||||
foreach($designs as $id => $design)
|
||||
{
|
||||
$design->commit = '';
|
||||
$design->commit = '';
|
||||
$relations = $this->loadModel('common')->getRelations('design', $id, 'commit');
|
||||
foreach($relations as $relation) $design->commit .= html::a(helper::createLink('design', 'revision', "repoID=$relation->BID", '', true), "#$relation->BID", '_blank');
|
||||
}
|
||||
|
||||
return $designs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get designs by search
|
||||
*
|
||||
* @param string $queryID
|
||||
* @param string $orderBy
|
||||
* @param int $pager
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function getBySearch($queryID = 0, $orderBy = 'id_desc', $pager = null)
|
||||
{
|
||||
if($queryID)
|
||||
{
|
||||
$query = $this->loadModel('search')->getQuery($queryID);
|
||||
if($query)
|
||||
{
|
||||
$this->session->set('designQuery', $query->sql);
|
||||
$this->session->set('designForm', $query->form);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->session->set('designQuery', ' 1 = 1');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if($this->session->designQuery == false) $this->session->set('designQuery', ' 1 = 1');
|
||||
}
|
||||
|
||||
$designQuery = $this->session->designQuery;
|
||||
|
||||
$designs = $this->dao->select('*')->from(TABLE_DESIGN)
|
||||
->where($designQuery)
|
||||
->andWhere('deleted')->eq('0')
|
||||
->andWhere('program')->eq($this->session->program)
|
||||
->orderBy($orderBy)
|
||||
->page($pager)
|
||||
->fetchAll('id');
|
||||
|
||||
return $designs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build search form.
|
||||
*
|
||||
* @param int $queryID
|
||||
* @param string $actionURL
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function buildSearchForm($queryID, $actionURL)
|
||||
{
|
||||
$this->config->design->search['actionURL'] = $actionURL;
|
||||
$this->config->design->search['queryID'] = $queryID;
|
||||
|
||||
$this->loadModel('search')->setSearchParams($this->config->design->search);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
/**
|
||||
* The batchCreate view of design module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2015 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
|
||||
* @license ZPL (http://zpl.pub/page/zplv12.html)
|
||||
* @author Chunsheng Wang <chunsheng@cnezsoft.com>
|
||||
* @package design
|
||||
* @version $Id: batchCreate.html.php 4903 2013-06-26 05:32:59Z wyd621@gmail.com $
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
?>
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<div id="mainContent" class="main-content fade">
|
||||
<div class="main-header">
|
||||
<h2><?php echo $lang->design->batchCreate;?></h2>
|
||||
</div>
|
||||
<form class="load-indicator main-form form-ajax" method='post' enctype='multipart/form-data' id='dataform'>
|
||||
<table class="table table-form">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class='w-50px'> <?php echo $lang->design->id;?></th>
|
||||
<th class='w-200px'><?php echo $lang->design->story;?></th>
|
||||
<th class='w-200px'><?php echo $lang->design->type;?></th>
|
||||
<th><?php echo $lang->design->name;?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php for($i = 1; $i <= 10; $i ++):?>
|
||||
<tr>
|
||||
<td><?php echo $i;?></td>
|
||||
<td><?php echo html::select("story[$i]", empty($stories) ? '' : $stories, '', "class='form-control chosen'");?></td>
|
||||
<td><?php echo html::select("type[$i]", $typeList, '', "class='form-control chosen'");?></td>
|
||||
<td><?php echo html::input("name[$i]", '', "class='form-control'");?></td>
|
||||
</tr>
|
||||
<?php endfor;?>
|
||||
<tr>
|
||||
<td colspan='4' class='form-actions text-center'>
|
||||
<?php echo html::submitButton() . html::backButton();?>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
@@ -22,12 +22,15 @@
|
||||
echo html::a(inlink('browse', "productID={$productID}&type=$key"), "<span class='text'>$label</span>" . $recTotalLabel, '', "class='btn btn-link $active'");
|
||||
}
|
||||
?>
|
||||
<a class="btn btn-link querybox-toggle" id='bysearchTab'><i class="icon icon-search muted"></i> <?php echo $lang->design->byQuery;?></a>
|
||||
</div>
|
||||
<div class='btn-toolbar pull-right'>
|
||||
<?php common::printLink('design', 'batchCreate', "productID=$productID", "<i class='icon icon-plus'></i>" . $lang->design->batchCreate, '', "class='btn btn-primary'");?>
|
||||
<?php if(common::hasPriv('design', 'create')) echo html::a($this->createLink('design', 'create', "productID=$productID&designID=0"), "<i class='icon icon-plus'></i> {$lang->design->create}", '', "class='btn btn-primary'");?>
|
||||
</div>
|
||||
</div>
|
||||
<div id="mainContent" class="main-row fade in">
|
||||
<div class="cell<?php if($type == 'bySearch') echo ' show';?>" id="queryBox" data-module='design'></div>
|
||||
<div id="mainContent" class="main-table">
|
||||
<?php if(empty($designs)):?>
|
||||
<div class="table-empty-tip">
|
||||
<p><span class="text-muted"><?php echo $lang->design->noDesign;?></span></p>
|
||||
@@ -53,8 +56,8 @@
|
||||
<tr>
|
||||
<td><?php printf('%03d', $design->id);?></td>
|
||||
<td><?php echo zget($lang->design->typeList, $design->type);?></td>
|
||||
<td title="<?php echo $design->name;?>"><?php echo html::a($this->createLink('design', 'view', "id={$design->id}"), $design->name);?></td>
|
||||
<td><?php echo $design->commit;?></td>
|
||||
<td title="<?php echo $design->name;?>" style="overflow:hidden"><?php echo html::a($this->createLink('design', 'view', "id={$design->id}"), $design->name);?></td>
|
||||
<td style="overflow:hidden"><?php echo $design->commit;?></td>
|
||||
<td><?php echo $design->createdBy;?></td>
|
||||
<td><?php echo substr($design->createdDate, 0, 11);?></td>
|
||||
<td><?php echo $design->assignedTo;?></td>
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
$lang->issue->common = 'Issue';
|
||||
$lang->issue->browse = 'List';
|
||||
$lang->issue->resolvedBy = 'Resolved By';
|
||||
$lang->issue->program = 'Linked Project';
|
||||
$lang->issue->title = 'Title';
|
||||
$lang->issue->desc = 'Description';
|
||||
$lang->issue->pri = 'Priority';
|
||||
$lang->issue->severity = 'Severity';
|
||||
$lang->issue->type = 'Type';
|
||||
$lang->issue->effectedArea = 'Impact';
|
||||
$lang->issue->activity = 'Activities';
|
||||
$lang->issue->deadline = 'Deadline';
|
||||
$lang->issue->resolution = 'Resolution';
|
||||
$lang->issue->resolutionComment = 'Comment';
|
||||
$lang->issue->resolvedDate = 'Resolved Date';
|
||||
$lang->issue->status = 'Status';
|
||||
$lang->issue->createdBy = 'CreatedBy';
|
||||
$lang->issue->createdDate = 'CreatedDate';
|
||||
$lang->issue->owner = 'Owner';
|
||||
$lang->issue->editedBy = 'EditedBy';
|
||||
$lang->issue->editedDate = 'EditedDate';
|
||||
$lang->issue->activateBy = 'ActivatedBy';
|
||||
$lang->issue->activateDate = 'ActivatedDate';
|
||||
$lang->issue->closeBy = 'ClosedBy';
|
||||
$lang->issue->closedDate = 'ClosedDate';
|
||||
$lang->issue->assignedTo = 'AssignedTo';
|
||||
$lang->issue->assignedBy = 'AssignedBy';
|
||||
$lang->issue->assignedDate = 'AssignedDate';
|
||||
$lang->issue->resolved = 'Resolved';
|
||||
$lang->issue->id = 'ID';
|
||||
|
||||
$lang->issue->delete = 'Delete';
|
||||
$lang->issue->search = 'Search';
|
||||
$lang->issue->basicInfo = 'Basic Information';
|
||||
$lang->issue->active = 'Activate';
|
||||
$lang->issue->assign = 'Assign';
|
||||
$lang->issue->create = 'Create Issue';
|
||||
$lang->issue->edit = 'Edit';
|
||||
$lang->issue->batchCreate = 'Batch Create';
|
||||
|
||||
$lang->issue->labelList['all'] = 'All';
|
||||
$lang->issue->labelList['open'] = 'Open';
|
||||
$lang->issue->labelList['assignto'] = 'AssignedToMe';
|
||||
$lang->issue->labelList['closed'] = 'Closed';
|
||||
$lang->issue->labelList['suspended'] = 'Suspended';
|
||||
$lang->issue->labelList['cancelled'] = 'Canceled';
|
||||
|
||||
$lang->issue->priList[''] = '';
|
||||
$lang->issue->priList['1'] = 1;
|
||||
$lang->issue->priList['2'] = 2;
|
||||
$lang->issue->priList['3'] = 3;
|
||||
$lang->issue->priList['4'] = 4;
|
||||
|
||||
$lang->issue->severityList[''] = '';
|
||||
$lang->issue->severityList['1'] = '1';
|
||||
$lang->issue->severityList['2'] = '2';
|
||||
$lang->issue->severityList['3'] = '3';
|
||||
$lang->issue->severityList['4'] = '4';
|
||||
|
||||
$lang->issue->typeList[''] = '';
|
||||
$lang->issue->typeList['design'] = 'Design';
|
||||
$lang->issue->typeList['code'] = 'Code';
|
||||
$lang->issue->typeList['performance'] = 'Performance';
|
||||
$lang->issue->typeList['version'] = 'Version';
|
||||
$lang->issue->typeList['storyadd'] = 'New Story';
|
||||
$lang->issue->typeList['storychanged'] = 'Story Change';
|
||||
$lang->issue->typeList['storyremoved'] = 'Story Deleted';
|
||||
$lang->issue->typeList['data'] = 'Data';
|
||||
|
||||
$lang->issue->resolutionList['resolved'] = 'Resolved';
|
||||
$lang->issue->resolutionList['tostory'] = 'To Story';
|
||||
$lang->issue->resolutionList['tobug'] = 'To Bug';
|
||||
$lang->issue->resolutionList['torisk'] = 'To Risk';
|
||||
$lang->issue->resolutionList['totask'] = 'To Task';
|
||||
|
||||
$lang->issue->statusList['unconfirmed'] = 'Unconfirmed';
|
||||
$lang->issue->statusList['confirmed'] = 'Confirmed';
|
||||
$lang->issue->statusList['unresolved'] = 'Unresolved';
|
||||
$lang->issue->statusList['resolved'] = 'Resolved';
|
||||
$lang->issue->statusList['canceled'] = 'Canceled';
|
||||
$lang->issue->statusList['closed'] = 'Closed';
|
||||
$lang->issue->statusList['active'] = 'Active';
|
||||
$lang->issue->statusList['suspended'] = 'Suspended';
|
||||
|
||||
$lang->issue->resolveMethods = array();
|
||||
$lang->issue->resolveMethods['resolved'] = 'Resolved';
|
||||
$lang->issue->resolveMethods['totask'] = 'To Task';
|
||||
$lang->issue->resolveMethods['tobug'] = 'To Bug';
|
||||
$lang->issue->resolveMethods['tostory'] = 'To Story';
|
||||
$lang->issue->resolveMethods['torisk'] = 'To Risk';
|
||||
|
||||
$lang->issue->confirmDelete = 'Do you want to delete this issue?';
|
||||
|
||||
$lang->issue->logComments = array();
|
||||
$lang->issue->logComments['totask'] = " created Task %s";
|
||||
$lang->issue->logComments['tostory'] = " created Story %s";
|
||||
$lang->issue->logComments['tobug'] = " created Bug %s" ;
|
||||
$lang->issue->logComments['torisk'] = " created Risk %s";
|
||||
@@ -41,7 +41,7 @@
|
||||
<th style="width:auto"><?php echo $lang->issue->title;?></th>
|
||||
<th class="w-60px"><?php echo $lang->issue->severity;?></th>
|
||||
<th class="w-60px"><?php echo $lang->issue->pri;?></th>
|
||||
<th class="w-80px"><?php echo $lang->issue->assignedTo;?></th>
|
||||
<th class="w-90px"><?php echo $lang->issue->assignedTo;?></th>
|
||||
<th class="w-80px"><?php echo $lang->issue->owner;?></th>
|
||||
<th class="w-100px"><?php echo $lang->issue->status;?></th>
|
||||
<th class="w-140px"><?php echo $lang->issue->createdDate;?></th>
|
||||
|
||||
@@ -172,7 +172,7 @@ class milestoneModel extends model
|
||||
$today = helper::today();
|
||||
$begin = $program->begin;
|
||||
$projectEnd = $project->end;
|
||||
$end = $today > $projectEnd ? $projectEnd : $today;
|
||||
$end = $today > $projectEnd ? $projectEnd : date('Y-m-d', strtotime("$today + 7 days"));
|
||||
|
||||
$charts['PV'] = '[';
|
||||
$charts['EV'] = '[';
|
||||
@@ -190,10 +190,9 @@ class milestoneModel extends model
|
||||
$i ++;
|
||||
}
|
||||
|
||||
$charts['labels'][] = $this->lang->milestone->chart->time . $i . $this->lang->milestone->chart->week;
|
||||
$charts['PV'] .= $this->getPV($projectIdList, $begin, $end) . ']';
|
||||
$charts['EV'] .= $this->getEV($projectIdList, $begin, $end) . ']';
|
||||
$charts['AC'] .= $this->getAC($projectIdList, $begin, $end) . ']';
|
||||
$charts['PV'] .= ']';
|
||||
$charts['EV'] .= ']';
|
||||
$charts['AC'] .= ']';
|
||||
|
||||
return $charts;
|
||||
}
|
||||
|
||||
@@ -53,18 +53,14 @@ class program extends control
|
||||
|
||||
if($programType === 'bygrid')
|
||||
{
|
||||
$projectList = $this->project->getProjectStats($status == 'byproduct' ? 'all' : $status, 0, 0, 30, $orderBy, $pager, 'program');
|
||||
foreach($projectList as $projectID => $project)
|
||||
{
|
||||
$project->teamCount = count($this->project->getTeamMembers($project->id));
|
||||
}
|
||||
$programs = $this->program->getProgramStats('all', 20, $orderBy, $pager);
|
||||
}
|
||||
else
|
||||
{
|
||||
$projectList = $this->program->getList($status, $orderBy, $pager);
|
||||
$programs = $this->program->getList($status, $orderBy, $pager);
|
||||
}
|
||||
|
||||
$this->view->projectList = $projectList;
|
||||
$this->view->programs = $programs;
|
||||
$this->view->status = $status;
|
||||
$this->view->orderBy = $orderBy;
|
||||
$this->view->pager = $pager;
|
||||
|
||||
@@ -13,16 +13,16 @@
|
||||
#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;}
|
||||
#cards .program-type-label {padding: 1px 2px;}
|
||||
#cards .program-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 .program-infos {font-size: 12px;}
|
||||
#cards .program-infos > span {display: inline-block; line-height: 12px;}
|
||||
#cards .program-infos > span > .icon {font-size: 12px; display: inline-block; position: relative; top: -1px}
|
||||
#cards .program-infos > span + span {margin-left: 15px;}
|
||||
#cards .program-detail {position: absolute; bottom: 16px; left: 16px; right: 16px; font-size: 12px;}
|
||||
#cards .program-detail > p {margin-bottom: 8px;}
|
||||
#cards .program-detail .progress {height: 4px;}
|
||||
#cards .program-detail .progress-text-left .progress-text {width: 50px; left: -50px;}
|
||||
#cards .pager {margin: 0; float: right;}
|
||||
#cards .pager .btn{border: none}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ $lang->program->setPlanduration = '设置工期';
|
||||
$lang->program->privway = '权限控制';
|
||||
$lang->program->durationEstimation = '工作量估算';
|
||||
$lang->program->progress = '项目进度';
|
||||
$lang->program->countMembers = '投入人数';
|
||||
$lang->program->teamCount = '投入人数';
|
||||
$lang->program->leftStories = '剩余需求';
|
||||
$lang->program->leftTasks = '剩余任务';
|
||||
$lang->program->leftBugs = '剩余Bug';
|
||||
|
||||
@@ -43,7 +43,7 @@ class programModel extends model
|
||||
|
||||
public function getUserPrograms($status = 'all', $orderBy = 'id_desc', $limit = 15)
|
||||
{
|
||||
return $this->dao->select('*')->from(TABLE_PROJECT)
|
||||
$programs = $this->dao->select('*')->from(TABLE_PROJECT)
|
||||
->where('iscat')->eq(0)
|
||||
->andWhere('template')->ne('')
|
||||
->andWhere('program')->eq(0)
|
||||
@@ -53,6 +53,99 @@ class programModel extends model
|
||||
->orderBy($orderBy)
|
||||
->limit($limit)
|
||||
->fetchAll('id');
|
||||
|
||||
if(empty($programs)) return array();
|
||||
$programIdList = array_keys($programs);
|
||||
|
||||
$consumes = $this->dao->select('program, sum(consumed) as consumed')->from(TABLE_TASK)
|
||||
->where('program')->in($programIdList)
|
||||
->andWhere('deleted')->eq(0)
|
||||
->andWhere('parent')->lt(1)
|
||||
->groupBy('program')
|
||||
->fetchAll('program');
|
||||
|
||||
$teams = $this->dao->select('root, count(*) as count')->from(TABLE_TEAM)
|
||||
->where('root')->in($programIdList)
|
||||
->groupBy('root')
|
||||
->fetchAll('root');
|
||||
|
||||
$leftTasks = $this->dao->select('program, count(*) as leftTasks')->from(TABLE_TASK)
|
||||
->where('program')->in($programIdList)
|
||||
->andWhere('deleted')->eq(0)
|
||||
->andWhere('status')->in('wait,doing,pause')
|
||||
->groupBy('program')
|
||||
->fetchAll('program');
|
||||
|
||||
$leftStories = $this->dao->select('program, count(*) as leftStories')->from(TABLE_STORY)
|
||||
->where('program')->in($programIdList)
|
||||
->andWhere('deleted')->eq(0)
|
||||
->andWhere('status')->eq('active')
|
||||
->groupBy('program')
|
||||
->fetchAll('program');
|
||||
|
||||
$leftBugs = $this->dao->select('program, count(*) as leftBugs')->from(TABLE_BUG)
|
||||
->where('program')->in($programIdList)
|
||||
->andWhere('deleted')->eq(0)
|
||||
->andWhere('status')->eq('active')
|
||||
->groupBy('program')
|
||||
->fetchAll('program');
|
||||
|
||||
foreach($programs as $programID => $program)
|
||||
{
|
||||
$program->teamCount = isset($teams[$programID]) ? $teams[$programID]->count : 0;
|
||||
$program->consumed = isset($consumes[$programID]) ? $consumes[$programID] : 0;
|
||||
$program->leftTasks = isset($leftTasks[$programID]) ? $leftTasks[$programID] : 0;
|
||||
$program->leftStories = isset($leftStories[$programID]) ? $leftStories[$programID] : 0;
|
||||
$program->leftBugs = isset($leftBugs[$programID]) ? $leftBugs[$programID] : 0;
|
||||
}
|
||||
|
||||
return $programs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get program stats.
|
||||
*
|
||||
* @param string $status
|
||||
* @param int $itemCounts
|
||||
* @param string $orderBy
|
||||
* @param int $pager
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function getProgramStats($status = 'undone', $itemCounts = 30, $orderBy = 'order_desc', $pager = null)
|
||||
{
|
||||
/* Init vars. */
|
||||
$this->loadModel('project');
|
||||
$programs = $this->getList($status, $orderBy, $pager);
|
||||
if(empty($programs)) return array();
|
||||
|
||||
$programIdList = array_keys($programs);
|
||||
$programs = $this->dao->select('*')->from(TABLE_PROJECT)
|
||||
->where('id')->in($programIdList)
|
||||
->orderBy($orderBy)
|
||||
->limit($itemCounts)
|
||||
->fetchAll('id');
|
||||
|
||||
$teams = $this->dao->select('root, count(*) as count')->from(TABLE_TEAM)
|
||||
->where('root')->in($programIdList)
|
||||
->groupBy('root')
|
||||
->fetchAll('root');
|
||||
|
||||
$estimates = $this->dao->select('program, sum(estimate) as estimate')->from(TABLE_TASK)
|
||||
->where('program')->in($programIdList)
|
||||
->andWhere('deleted')->eq(0)
|
||||
->andWhere('parent')->lt(1)
|
||||
->groupBy('program')
|
||||
->fetchAll('program');
|
||||
|
||||
foreach($programs as $programID => $program)
|
||||
{
|
||||
$program->projects = $this->project->getProjectStats($status, 0, 0, $itemCounts, 'id_desc', $pager, $programID);
|
||||
$program->teamCount = isset($teams[$programID]) ? $teams[$programID]->count : 0;
|
||||
$program->estimate = isset($estimates[$programID]) ? $estimates[$programID]->estimate : 0;
|
||||
}
|
||||
|
||||
return $programs;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div id='mainContent' class='main-row'>
|
||||
<?php if(empty($projectList)):?>
|
||||
<?php if(empty($programs)):?>
|
||||
<div class="table-empty-tip">
|
||||
<p><span class="text-muted"><?php echo $lang->program->noProgram;?></span> <?php common::printLink('program', 'createguide', '', "<i class='icon icon-plus'></i> " . $lang->program->create, '', "class='btn btn-info' data-toggle=modal");?></p>
|
||||
</div>
|
||||
|
||||
@@ -1,45 +1,47 @@
|
||||
<style>#mainMenu{padding-left: 10px; padding-right: 10px;}</style>
|
||||
<div class='row cell' id='cards'>
|
||||
<?php foreach ($projectList as $projectID => $project):?>
|
||||
<div class='col' data-id='<?php echo $projectID?>'>
|
||||
<div class='panel' data-url='<?php echo $this->createLink('program', 'index', "projectID=$project->id");?>'>
|
||||
<?php foreach ($programs as $programID => $program):?>
|
||||
<div class='col' data-id='<?php echo $programID?>'>
|
||||
<div class='panel' data-url='<?php echo $this->createLink('program', 'index', "programID=$program->id");?>'>
|
||||
<div class='panel-heading'>
|
||||
<strong class='project-name' title='<?php echo $project->name;?>'><?php echo $project->name;?></strong>
|
||||
<?php if($project->template === 'cmmi'): ?>
|
||||
<span class='project-type-label label label-warning label-outline'><?php echo $lang->program->cmmi; ?></span>
|
||||
<strong class='program-name' title='<?php echo $program->name;?>'><?php echo $program->name;?></strong>
|
||||
<?php if($program->template === 'cmmi'): ?>
|
||||
<span class='program-type-label label label-warning label-outline'><?php echo $lang->program->cmmi; ?></span>
|
||||
<?php else: ?>
|
||||
<span class='project-type-label label label-info label-outline'><?php echo $lang->program->scrum; ?></span>
|
||||
<span class='program-type-label label label-info label-outline'><?php echo $lang->program->scrum; ?></span>
|
||||
<?php endif; ?>
|
||||
<nav class='panel-actions nav nav-default'>
|
||||
<li class='dropdown'>
|
||||
<a href='javascript:;' data-toggle='dropdown' class='panel-action'><i class='icon icon-ellipsis-v'></i></a>
|
||||
<ul class='dropdown-menu pull-right'>
|
||||
<li><?php common::printIcon('program', 'group', "projectID=$project->id", $project, 'button', 'group');?></li>
|
||||
<li><?php common::printIcon('program', 'manageMembers', "projectID=$project->id", $project, 'button', 'persons');?></li>
|
||||
<li><?php common::printicon('program', 'activate', "projectid=$project->id", $project, 'button', '', '', 'iframe', true);?></li>
|
||||
<li><?php if(common::hasPriv('program', 'edit')) echo html::a($this->createLink("program", "edit", "projectID=$project->id"), "<i class='icon-edit'></i> " . $lang->edit, '', "");?></li>
|
||||
<li><?php common::printIcon('program', 'start', "projectID=$project->id", $project, 'button', '', '', 'iframe', true);?></li>
|
||||
<li><?php common::printIcon('program', 'suspend', "projectID=$project->id", $project, 'button', '', '', 'iframe', true);?></li>
|
||||
<li><?php common::printIcon('program', 'close', "projectID=$project->id", $project, 'button', '', '', 'iframe', true);?></li>
|
||||
<li><?php if(common::hasPriv('program', 'delete')) echo html::a($this->createLink("project", "delete", "projectID=$project->id"), "<i class='icon-trash'></i> " . $lang->delete, 'hiddenwin', "");?></li>
|
||||
<li><?php common::printIcon('program', 'group', "programID=$program->id", $program, 'button', 'group');?></li>
|
||||
<li><?php common::printIcon('program', 'manageMembers', "programID=$program->id", $program, 'button', 'persons');?></li>
|
||||
<li><?php common::printicon('program', 'activate', "programid=$program->id", $program, 'button', '', '', 'iframe', true);?></li>
|
||||
<li><?php if(common::hasPriv('program', 'edit')) echo html::a($this->createLink("program", "edit", "programID=$program->id"), "<i class='icon-edit'></i> " . $lang->edit, '', "");?></li>
|
||||
<li><?php common::printIcon('program', 'start', "programID=$program->id", $program, 'button', '', '', 'iframe', true);?></li>
|
||||
<li><?php common::printIcon('program', 'suspend', "programID=$program->id", $program, 'button', '', '', 'iframe', true);?></li>
|
||||
<li><?php common::printIcon('program', 'close', "programID=$program->id", $program, 'button', '', '', 'iframe', true);?></li>
|
||||
<li><?php if(common::hasPriv('program', 'delete')) echo html::a($this->createLink("program", "delete", "programID=$program->id"), "<i class='icon-trash'></i> " . $lang->delete, 'hiddenwin', "");?></li>
|
||||
</ul>
|
||||
</li>
|
||||
</nav>
|
||||
</div>
|
||||
<div class='panel-body'>
|
||||
<div class='project-infos'>
|
||||
<span><i class='icon icon-group'></i> <?php printf($lang->program->membersUnit, $project->teamCount); ?></span>
|
||||
<span><i class='icon icon-clock'></i> <?php printf($lang->program->hoursUnit, $project->hours->totalEstimate); ?></span>
|
||||
<span><i class='icon icon-cost'></i> <?php echo $project->budget . '' . zget($lang->program->unitList, $project->budgetUnit);?></span>
|
||||
<div class='program-infos'>
|
||||
<span><i class='icon icon-group'></i> <?php printf($lang->program->membersUnit, $program->teamCount); ?></span>
|
||||
<span><i class='icon icon-clock'></i> <?php printf($lang->program->hoursUnit, $program->estimate); ?></span>
|
||||
<span><i class='icon icon-cost'></i> <?php echo $program->budget . '' . zget($lang->program->unitList, $program->budgetUnit);?></span>
|
||||
</div>
|
||||
<?php //if($project->template === 'cmmi'): ?>
|
||||
<div class='project-detail project-stages'>
|
||||
<!--p class='text-muted'><?php echo $lang->program->ongoingStage; ?></p-->
|
||||
<div class='label label-outline'><?php echo zget($lang->project->statusList, $project->status);?></div>
|
||||
<?php if($program->template === 'cmmi'): ?>
|
||||
<div class='program-detail program-stages'>
|
||||
<p class='text-muted'><?php echo $lang->program->ongoingStage; ?></p>
|
||||
<div class='label label-outline'><?php echo zget($lang->project->statusList, $program->status);?></div>
|
||||
</div>
|
||||
<?php //else: ?>
|
||||
<!--div class='project-detail project-iteration'>
|
||||
<?php else: ?>
|
||||
<?php $project = $program->projects ? current($program->projects) : '';?>
|
||||
<div class='program-detail program-iteration'>
|
||||
<p class='text-muted'><?php echo $lang->program->lastIteration; ?></p>
|
||||
<?php if($project):?>
|
||||
<div class='row'>
|
||||
<div class='col-xs-5'><?php echo $project->name; ?></div>
|
||||
<div class='col-xs-7'>
|
||||
@@ -50,8 +52,9 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div -->
|
||||
<?php //endif; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?php $canOrder = (common::hasPriv('project', 'updateOrder') and strpos($orderBy, 'order') !== false)?>
|
||||
<?php $canOrder = (common::hasPriv('program', 'updateOrder') and strpos($orderBy, 'order') !== false)?>
|
||||
<form class='main-table' id='programForm' method='post' data-ride='table'>
|
||||
<table class='table has-sort-head table-fixed' id='programList'>
|
||||
<?php $vars = "status=$status&orderBy=%s&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}&pageID={$pager->pageID}";?>
|
||||
@@ -21,30 +21,30 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class='sortable' id='programTableList'>
|
||||
<?php foreach($projectList as $project):?>
|
||||
<tr data-id='<?php echo $project->id ?>' data-order='<?php echo $project->order ?>'>
|
||||
<?php foreach($programs as $program):?>
|
||||
<tr data-id='<?php echo $program->id ?>' data-order='<?php echo $program->order ?>'>
|
||||
<td class='c-id'>
|
||||
<?php printf('%03d', $project->id);?>
|
||||
<?php printf('%03d', $program->id);?>
|
||||
</td>
|
||||
<td class='text-left'><?php echo $project->code;?></td>
|
||||
<td class='text-left pgm-title' title='<?php echo $project->name?>'>
|
||||
<?php echo html::a(inlink('index', "programID=$project->id"), $project->name);?>
|
||||
<td class='text-left'><?php echo $program->code;?></td>
|
||||
<td class='text-left pgm-title' title='<?php echo $program->name?>'>
|
||||
<?php echo html::a(inlink('index', "programID=$program->id"), $program->name);?>
|
||||
</td>
|
||||
<td class='c-status'><span class="status-project status-<?php echo $project->status?>"><?php echo zget($lang->project->statusList, $project->status, '');?></span></td>
|
||||
<td class='text-center'><?php echo $project->begin;?></td>
|
||||
<td class='text-center'><?php echo $project->end;?></td>
|
||||
<td class='text-left'><?php echo $project->budget . ' ' . zget($lang->program->unitList, $project->budgetUnit);?></td>
|
||||
<td><?php echo zget($users, $project->PM);?></td>
|
||||
<td class='c-status'><span class="status-program status-<?php echo $program->status?>"><?php echo zget($lang->project->statusList, $program->status, '');?></span></td>
|
||||
<td class='text-center'><?php echo $program->begin;?></td>
|
||||
<td class='text-center'><?php echo $program->end;?></td>
|
||||
<td class='text-left'><?php echo $program->budget . ' ' . zget($lang->program->unitList, $program->budgetUnit);?></td>
|
||||
<td><?php echo zget($users, $program->PM);?></td>
|
||||
<td class='text-center c-actions'>
|
||||
<?php common::printIcon('program', 'group', "projectID=$project->id", $project, 'list', 'group');?>
|
||||
<?php common::printIcon('program', 'manageMembers', "projectID=$project->id", $project, 'list', 'persons');?>
|
||||
<?php common::printIcon('program', 'start', "projectID=$project->id", $project, 'list', '', '', 'iframe', true);?>
|
||||
<?php common::printIcon('program', 'activate', "projectID=$project->id", $project, 'list', '', '', 'iframe', true);?>
|
||||
<?php common::printIcon('program', 'suspend', "projectID=$project->id", $project, 'list', '', '', 'iframe', true);?>
|
||||
<?php common::printIcon('program', 'close', "projectID=$project->id", $project, 'list', '', '', 'iframe', true);?>
|
||||
<?php if(common::hasPriv('program', 'edit')) echo html::a($this->createLink("program", "edit", "projectID=$project->id"), "<i class='icon-edit'></i>", '', "class='btn' title='{$lang->edit}'");?>
|
||||
<?php common::printIcon('program', 'create', "template=&projectID=$project->id", '', 'list', 'treemap-alt', '', '', '', '', $this->lang->program->children);?>
|
||||
<?php if(common::hasPriv('program', 'delete')) echo html::a($this->createLink("program", "delete", "projectID=$project->id"), "<i class='icon-trash'></i>", 'hiddenwin', "class='btn' title='{$lang->delete}'");?>
|
||||
<?php common::printIcon('program', 'group', "programID=$program->id", $program, 'list', 'group');?>
|
||||
<?php common::printIcon('program', 'manageMembers', "programID=$program->id", $program, 'list', 'persons');?>
|
||||
<?php common::printIcon('program', 'start', "programID=$program->id", $program, 'list', '', '', 'iframe', true);?>
|
||||
<?php common::printIcon('program', 'activate', "programID=$program->id", $program, 'list', '', '', 'iframe', true);?>
|
||||
<?php common::printIcon('program', 'suspend', "programID=$program->id", $program, 'list', '', '', 'iframe', true);?>
|
||||
<?php common::printIcon('program', 'close', "programID=$program->id", $program, 'list', '', '', 'iframe', true);?>
|
||||
<?php if(common::hasPriv('program', 'edit')) echo html::a($this->createLink("program", "edit", "programID=$program->id"), "<i class='icon-edit'></i>", '', "class='btn' title='{$lang->edit}'");?>
|
||||
<?php common::printIcon('program', 'create', "template=&programID=$program->id", '', 'list', 'treemap-alt', '', '', '', '', $this->lang->program->children);?>
|
||||
<?php if(common::hasPriv('program', 'delete')) echo html::a($this->createLink("program", "delete", "programID=$program->id"), "<i class='icon-trash'></i>", 'hiddenwin', "class='btn' title='{$lang->delete}'");?>
|
||||
</td>
|
||||
<?php if($canOrder):?>
|
||||
<td class='sort-handler'><i class="icon icon-move"></i></td>
|
||||
|
||||
@@ -756,8 +756,9 @@ class projectModel extends model
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getList($status = 'all', $limit = 0, $productID = 0, $branch = 0)
|
||||
public function getList($status = 'all', $limit = 0, $productID = 0, $branch = 0, $programID = 0)
|
||||
{
|
||||
$programID = $programID ? $programID : $this->session->programID;
|
||||
if($status == 'involved') return $this->getInvolvedList($status, $limit, $productID, $branch);
|
||||
|
||||
if($productID != 0)
|
||||
@@ -767,7 +768,7 @@ class projectModel extends model
|
||||
->where('t1.product')->eq($productID)
|
||||
->andWhere('t2.deleted')->eq(0)
|
||||
->andWhere('t2.iscat')->eq(0)
|
||||
->beginIF($this->session->program)->andWhere('t2.program')->eq($this->session->program)->fi()
|
||||
->beginIF($programID)->andWhere('t2.program')->eq($programID)->fi()
|
||||
->andWhere('t2.template')->eq('')
|
||||
->beginIF($status == 'undone')->andWhere('t2.status')->notIN('done,closed')->fi()
|
||||
->beginIF($branch)->andWhere('t1.branch')->eq($branch)->fi()
|
||||
@@ -784,7 +785,7 @@ class projectModel extends model
|
||||
->beginIF($status != 'all' and $status != 'undone')->andWhere('status')->in($status)->fi()
|
||||
->beginIF(!$this->app->user->admin)->andWhere('id')->in($this->app->user->view->projects)->fi()
|
||||
->andWhere('deleted')->eq(0)
|
||||
->beginIF($this->session->program)->andWhere('program')->eq($this->session->program)->fi()
|
||||
->beginIF($programID)->andWhere('program')->eq($programID)->fi()
|
||||
->andWhere('template')->eq('')
|
||||
->orderBy('order_desc')
|
||||
->beginIF($limit)->limit($limit)->fi()
|
||||
@@ -916,10 +917,10 @@ class projectModel extends model
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function getProjectStats($status = 'undone', $productID = 0, $branch = 0, $itemCounts = 30, $orderBy = 'order_desc', $pager = null)
|
||||
public function getProjectStats($status = 'undone', $productID = 0, $branch = 0, $itemCounts = 30, $orderBy = 'order_desc', $pager = null, $programID = 0)
|
||||
{
|
||||
/* Init vars. */
|
||||
$projects = $this->getList($status, 0, $productID, $branch);
|
||||
$projects = $this->getList($status, 0, $productID, $branch, $programID);
|
||||
$projects = $this->dao->select('*')->from(TABLE_PROJECT)
|
||||
->where('id')->in(array_keys($projects))
|
||||
->orderBy($orderBy)
|
||||
|
||||
Reference in New Issue
Block a user