Merge branch 'master' of https://gitlab.zcorp.cc/easycorp/zentaopms
This commit is contained in:
+17
-5
@@ -12,6 +12,7 @@ $filter->rules->browseType = '/^by\w+$/i';
|
||||
$filter->rules->word = '/^\w+$/';
|
||||
$filter->rules->paramName = '/^[a-zA-Z0-9_\.]+$/';
|
||||
$filter->rules->paramValue = '/^[a-zA-Z0-9=_,`#+\^\/\.%\|\x7f-\xff\-]+$/';
|
||||
$filter->rules->url = '/((http|https):\/\/)(([a-zA-Z0-9\._-]+\.[a-zA-Z]{2,6})|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[0-9]{1,4})*(\/[a-zA-Z0-9\&%_\.\/-~-]*)?/';
|
||||
|
||||
$filter->default = new stdclass();
|
||||
$filter->default->moduleName = 'code';
|
||||
@@ -22,11 +23,22 @@ $filter->default->paramValue = 'reg::paramValue';
|
||||
$filter->default->get['onlybody'] = 'equal::yes';
|
||||
$filter->default->get['HTTP_X_REQUESTED_WITH'] = 'equal::XMLHttpRequest';
|
||||
|
||||
$filter->default->cookie['lang'] = 'reg::lang';
|
||||
$filter->default->cookie['theme'] = 'reg::word';
|
||||
$filter->default->cookie['fingerprint'] = 'reg::word';
|
||||
$filter->default->cookie['hideMenu'] = 'equal::true';
|
||||
$filter->default->cookie['openApp'] = 'reg::word';
|
||||
$filter->default->cookie['lang'] = 'reg::lang';
|
||||
$filter->default->cookie['theme'] = 'reg::word';
|
||||
$filter->default->cookie['fingerprint'] = 'reg::word';
|
||||
$filter->default->cookie['hideMenu'] = 'equal::true';
|
||||
$filter->default->cookie['openApp'] = 'reg::word';
|
||||
$filter->default->cookie['myGoback'] = 'reg::url';
|
||||
$filter->default->cookie['programGoback'] = 'reg::url';
|
||||
$filter->default->cookie['productGoback'] = 'reg::url';
|
||||
$filter->default->cookie['projectGoback'] = 'reg::url';
|
||||
$filter->default->cookie['executionGoback'] = 'reg::url';
|
||||
$filter->default->cookie['qaGoback'] = 'reg::url';
|
||||
$filter->default->cookie['devopsGoback'] = 'reg::url';
|
||||
$filter->default->cookie['docGoback'] = 'reg::url';
|
||||
$filter->default->cookie['reportGoback'] = 'reg::url';
|
||||
$filter->default->cookie['systemGoback'] = 'reg::url';
|
||||
$filter->default->cookie['adminGoback'] = 'reg::url';
|
||||
|
||||
$filter->my = new stdclass();
|
||||
$filter->bug = new stdclass();
|
||||
|
||||
@@ -489,13 +489,30 @@ class baseHTML
|
||||
{
|
||||
if(helper::inOnlyBodyMode()) return false;
|
||||
|
||||
global $lang;
|
||||
global $lang, $app;
|
||||
if(empty($label))
|
||||
{
|
||||
global $lang;
|
||||
global $lang, $config;
|
||||
$label = $lang->goback;
|
||||
}
|
||||
return "<a href='javascript:history.go(-1);' class='btn btn-back $class' $misc>{$label}</a>";
|
||||
|
||||
$referer = $_SERVER['HTTP_REFERER'];
|
||||
$currentModule = $app->getModuleName();
|
||||
$currentMethod = $app->getMethodName();
|
||||
$gobackCookie = $_COOKIE['openApp'] . 'Goback';
|
||||
$gobackLink = isset($_COOKIE[$gobackCookie]) ? $_COOKIE[$gobackCookie] : '';
|
||||
|
||||
/* Get the module name and method name of the referer. */
|
||||
preg_match('/((http|https):\/\/)(([a-zA-Z0-9\._-]+\.[a-zA-Z]{2,6})|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[0-9]{1,4})*(\/[a-zA-Z0-9\&%_\.\/-~-]*)?/', $referer, $refererLink);
|
||||
|
||||
/* If the link of the referer is not the link of the current page or the link of the index, the cookie and gobackLink will be updated. */
|
||||
if(!preg_match("/(\/index\.php\?m=|\/)(index|$currentModule)(&f=|-)(index|$currentMethod)(&|-|\.)?/", $refererLink[7]))
|
||||
{
|
||||
setcookie($gobackCookie, $referer, $config->cookieLife, $config->webRoot, '', $config->cookieSecure, false);
|
||||
$gobackLink = $referer;
|
||||
}
|
||||
|
||||
return "<a href='{$gobackLink}' class='btn btn-back $class' $misc>{$label}</a>";
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,3 +24,10 @@ th.c-confirmed {text-align: center;}
|
||||
.c-id {text-overflow: ellipsis; white-space: nowrap;}
|
||||
|
||||
.body-modal #mainMenu>.btn-toolbar {width: auto;}
|
||||
|
||||
body {margin-bottom: 25px;}
|
||||
#mainMenu .btn-toolbar .btn-group .dropdown-menu .btn-active-text:hover .text {color: #fff;}
|
||||
#mainMenu .btn-toolbar .btn-group .dropdown-menu .btn-active-text:hover .text:after {border-bottom: unset;}
|
||||
.btn-group a i.icon-plus {font-size: 16px;}
|
||||
.btn-group a.btn-primary {border-right: 1px solid rgba(255,255,255,0.3);}
|
||||
.btn-group button.dropdown-toggle.btn-primary {padding:6px;}
|
||||
|
||||
@@ -21,13 +21,6 @@ js::set('productID', $productID);
|
||||
js::set('branch', $branch);
|
||||
$currentBrowseType = isset($lang->bug->mySelects[$browseType]) && in_array($browseType, array_keys($lang->bug->mySelects)) ? $browseType : '';
|
||||
?>
|
||||
<style>
|
||||
#mainMenu .btn-toolbar .btn-group .dropdown-menu .btn-active-text:hover .text {color: #fff;}
|
||||
#mainMenu .btn-toolbar .btn-group .dropdown-menu .btn-active-text:hover .text:after {border-bottom: unset;}
|
||||
.btn-group a i.icon-plus {font-size: 16px;}
|
||||
.btn-group a.btn-primary {border-right: 1px solid rgba(255,255,255,0.3);}
|
||||
.btn-group button.dropdown-toggle.btn-primary {padding:6px;}
|
||||
</style>
|
||||
<?php if($config->global->flow == 'full'):?>
|
||||
<div id="mainMenu" class="clearfix">
|
||||
<div id="sidebarHeader">
|
||||
|
||||
@@ -57,10 +57,12 @@ function fullScreen()
|
||||
$('#content .detail').eq(1).addClass('hidden');
|
||||
$.cookie('isFullScreen', 1);
|
||||
};
|
||||
|
||||
var whenFailEnterFullscreen = function(error)
|
||||
{
|
||||
$.cookie('isFullScreen', 0);
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
var result = requestMethod.call(element);
|
||||
|
||||
@@ -12,10 +12,10 @@ $sessionString .= session_name() . '=' . session_id();
|
||||
<div class="info">
|
||||
<div class="version">
|
||||
<div class='btn-group'>
|
||||
<a href='javascript:;' class='btn btn-link btn-limit text-ellipsis' data-toggle='dropdown' style="max-width: 120px;">
|
||||
#<?php echo $version ? $version : $doc->version;?>
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<a href='javascript:;' class='btn btn-link btn-limit text-ellipsis' data-toggle='dropdown' style="max-width: 120px;">
|
||||
#<?php echo $version ? $version : $doc->version;?>
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class='dropdown-menu doc-version-menu' style='max-height:240px; max-width: 300px; overflow-y:auto'>
|
||||
<?php for($version = $doc->version; $version > 0; $version--): ?>
|
||||
<li><a href='javascript:void(0)' data-url='<?php echo $this->createLink('doc', 'objectLibs', "type=$objectType&objectID=$object->id&libID=$libID&docID=$doc->id&version=$version"); ?>'>#<?php echo $version; ?></a></li>
|
||||
|
||||
@@ -42,6 +42,7 @@ function addItem(obj)
|
||||
|
||||
function deleteItem(obj)
|
||||
{
|
||||
if($('.table').find('.addedItem').length <= 1) return;
|
||||
$(obj).closest('tr').remove();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
.c-dept {overflow:hidden; text-overflow: ellipsis; white-space: nowrap;}
|
||||
@@ -34,7 +34,7 @@
|
||||
<?php echo $lang->idAB;?>
|
||||
</th>
|
||||
<th><?php echo $lang->user->realname;?></th>
|
||||
<th class="w-120px"><?php echo $lang->user->dept;?></th>
|
||||
<th class="c-dept"><?php echo $lang->user->dept;?></th>
|
||||
<th class="w-120px"><?php echo $lang->user->role;?></th>
|
||||
<th class="w-120px"><?php echo $lang->user->phone;?></th>
|
||||
<th class="w-120px"><?php echo $lang->user->qq;?></th>
|
||||
@@ -50,7 +50,7 @@
|
||||
<?php printf('%03d', $user->id);?>
|
||||
</td>
|
||||
<td><?php echo $user->realname;?></td>
|
||||
<td><?php echo zget($depts, $user->dept);?></td>
|
||||
<td class='c-dept' title="<?php echo zget($depts, $user->dept);?>"><?php echo zget($depts, $user->dept);?></td>
|
||||
<td><?php echo zget($lang->user->roleList, $user->role);?></td>
|
||||
<td title="<?php echo $user->phone;?>"><?php echo $user->phone;?></td>
|
||||
<td title="<?php echo $user->qq;?>"><?php echo $user->qq;?></td>
|
||||
|
||||
@@ -1153,6 +1153,39 @@ class product extends control
|
||||
*/
|
||||
public function kanban()
|
||||
{
|
||||
$kanbanGroup = $this->product->getStats4Kanban();
|
||||
extract($kanbanGroup);
|
||||
|
||||
$products = array();
|
||||
$myProducts = array();
|
||||
$otherProducts = array();
|
||||
foreach($productList as $productID => $product)
|
||||
{
|
||||
if($product->status == 'normal' and $product->PO == $this->app->user->account)
|
||||
{
|
||||
$myProducts[$product->program][$productID] = $productID;
|
||||
}
|
||||
elseif($product->status == 'normal' and !($product->PO == $this->app->user->account))
|
||||
{
|
||||
$otherProducts[$product->program][$productID] = $productID;
|
||||
}
|
||||
}
|
||||
|
||||
$products['myProducts'] = $myProducts;
|
||||
$products['otherProducts'] = $otherProducts;
|
||||
|
||||
$this->view->title = $this->lang->product->kanban;
|
||||
$this->view->products = $products;
|
||||
$this->view->programList = array(0 => $this->lang->product->emptyProgram) + $programList;
|
||||
$this->view->productList = $productList;
|
||||
$this->view->planList = $planList;
|
||||
$this->view->projectList = $projectList;
|
||||
$this->view->projectProduct = $projectProduct;
|
||||
$this->view->latestExecutions = $projectLatestExecutions;
|
||||
$this->view->hourList = $hourList;
|
||||
$this->view->emptyHour = (object) array('totalEstimate' => 0, 'totalConsumed' => 0, 'totalLeft' => 0, 'progress' => 0);
|
||||
$this->view->releaseList = $releaseList;
|
||||
|
||||
$this->display();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
#kanban {padding: 10px;}
|
||||
.main-table tbody>tr>td {padding: 10px;}
|
||||
.table caption {background: #fff; border-top-left-radius: 2px; border-top-right-radius: 2px; margin-bottom: 0; font-weight: 500;}
|
||||
.table .program {writing-mode: vertical-lr; padding-left: 4px !important; color: #fff;}
|
||||
|
||||
.table th, .table td {border-top: 2px solid #fff; border-bottom: 2px solid #fff; border-left: 3px solid #fff; border-bottom: 3px solid #fff;}
|
||||
.table tbody tr:last-child td {border-bottom: unset;}
|
||||
td.project, td.execution {padding: 10px 0 !important;}
|
||||
|
||||
.board-item {border: 1px solid #ebebeb; padding: 3px 10px; cursor: default; border-radius: 2px; background-color: #fff; text-align: left;}
|
||||
.board-item:hover {border-color: #ccc;}
|
||||
.board {padding: 0 10px;}
|
||||
.board + .board {margin-top: 5px;}
|
||||
.board-item + .board-item {margin-top: 10px;}
|
||||
.project .board, .execution .board {padding-top: 5px; border-top: 2px solid #fff;}
|
||||
.project .board:first-child, .execution .board:first-child {padding-top: 0; border-top: unset;}
|
||||
.release .board-item {display: flex; flex-flow: row nowrap; justify-content: flex-start; align-items: center;}
|
||||
.emptyBoard {padding: 3px 10px; cursor: default;}
|
||||
|
||||
.project .table-row > .table-col:last-child, .execution .table-row > .table-col:last-child {width: 24px; padding-top: 2px;}
|
||||
@@ -131,6 +131,19 @@ $lang->product->unclosed = '未关闭';
|
||||
$lang->product->unplan = "未计划";
|
||||
$lang->product->viewByUser = '按用户查看';
|
||||
|
||||
/* Product Kanban. */
|
||||
$lang->product->myProduct = '我负责的产品';
|
||||
$lang->product->otherProduct = '其他产品';
|
||||
$lang->product->unclosedProduct = '未关闭的产品';
|
||||
$lang->product->unexpiredPlan = '未过期的计划';
|
||||
$lang->product->doing = '进行中';
|
||||
$lang->product->doingProject = '进行中的项目';
|
||||
$lang->product->doingExecution = '进行中的执行';
|
||||
$lang->product->normalRelease = '正常的发布';
|
||||
$lang->product->emptyProgram = '无项目集归属产品';
|
||||
|
||||
$lang->product->kanbanColorList = array('#32C5FF', '#006AF1', '#9D28B2', '#FF8F26', '#FFC20E', '#00A78E', '#7FBB00', '#424BAC', '#C0E9FF', '#EC2761');
|
||||
|
||||
$lang->product->allStory = '所有';
|
||||
$lang->product->allProduct = '全部' . $lang->productCommon;
|
||||
$lang->product->allProductsOfProject = '全部关联' . $lang->productCommon;
|
||||
|
||||
@@ -1520,6 +1520,62 @@ class productModel extends model
|
||||
return $stats;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get stats for product kanban.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function getStats4Kanban()
|
||||
{
|
||||
$date = date('Y-m-d');
|
||||
$this->loadModel('program');
|
||||
|
||||
$productList = $this->getList();
|
||||
$programList = $this->program->getTopPairs('', '', true);
|
||||
$projectList = $this->program->getProjectStats(0, 'doing');
|
||||
|
||||
$projectProduct = $this->dao->select('t1.product,t1.project')->from(TABLE_PROJECTPRODUCT)->alias('t1')
|
||||
->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project=t2.id')
|
||||
->where('t1.product')->in(array_keys($productList))
|
||||
->andWhere('t2.type')->eq('project')
|
||||
->andWhere('t2.status')->eq('doing')
|
||||
->andWhere('t2.deleted')->eq('0')
|
||||
->fetchGroup('product', 'project');
|
||||
|
||||
$planList = $this->dao->select('id,product,title,parent,begin,end')->from(TABLE_PRODUCTPLAN)
|
||||
->where('product')->in(array_keys($productList))
|
||||
->andWhere('deleted')->eq(0)
|
||||
->andWhere('end')->ge($date)
|
||||
->andWhere('parent')->ne(-1)
|
||||
->orderBy('begin desc')
|
||||
->fetchGroup('product', 'id');
|
||||
|
||||
$executionList = $this->dao->select('t2.*')->from(TABLE_PROJECTPRODUCT)->alias('t1')
|
||||
->leftJoin(TABLE_EXECUTION)->alias('t2')->on('t1.project=t2.id')
|
||||
->where('type')->in('stage,sprint')
|
||||
->andWhere('t2.project')->in(array_keys($projectList))
|
||||
->andWhere('t1.product')->in(array_keys($productList))
|
||||
->andWhere('status')->eq('doing')
|
||||
->andWhere('deleted')->eq('0')
|
||||
->orderBy('id_desc')
|
||||
->fetchGroup('project', 'id');
|
||||
|
||||
$projectLatestExecutions = array();
|
||||
$latestExecutionList = array();
|
||||
foreach($executionList as $projectID => $executions)
|
||||
{
|
||||
$latestExecutionList[key($executions)] = current($executions);
|
||||
$projectLatestExecutions[$projectID] = current($executions);
|
||||
}
|
||||
|
||||
$hourList = $this->loadModel('project')->computerProgress($latestExecutionList);
|
||||
|
||||
$releaseList = $this->dao->select('id,product,name,marker')->from(TABLE_RELEASE)->where('product')->in(array_keys($productList))->fetchGroup('product', 'id');
|
||||
|
||||
return array('programList' => $programList, 'productList' => $productList, 'planList' => $planList, 'projectList' => $projectList, 'projectProduct' => $projectProduct, 'projectLatestExecutions' => $projectLatestExecutions, 'hourList' => $hourList, 'releaseList' => $releaseList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get product line pairs.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
<?php
|
||||
/**
|
||||
* The html product kanban file of kanban method of product 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 Fangzhou Hu <hufangzhou@easycorp.ltd>
|
||||
* @package ZenTaoPMS
|
||||
* @version $Id
|
||||
*/
|
||||
?>
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<div id="kanban" class="main-table fade auto-fade-in" data-ride="table" data-checkable="false" data-group="true">
|
||||
<?php if(empty($productList)):?>
|
||||
<div class="table-empty-tip">
|
||||
<p><span class="text-muted"><?php echo $lang->noData;?></span></p>
|
||||
</div>
|
||||
<?php else:?>
|
||||
<?php foreach($products as $type => $programs):?>
|
||||
<div class="cell">
|
||||
<table class="table text-center" style="border-radius: 0; background: #efefef;">
|
||||
<caption><?php echo $type == 'myProducts' ? $lang->product->myProduct : $lang->product->otherProduct;?></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th rowspan="2" class="w-20px" style="border-left: unset; border-right: unset; background: #32C5FF;"></th>
|
||||
<th rowspan="2" style="border-left: 0px;"><?php echo $lang->product->unclosedProduct;?></th>
|
||||
<th rowspan="2"><?php echo $lang->product->unexpiredPlan;?></th>
|
||||
<th colspan="2"><?php echo $lang->product->doing;?></th>
|
||||
<th rowspan="2"><?php echo $lang->product->normalRelease;?></th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->product->doingProject;?></th>
|
||||
<th><?php echo $lang->product->doingExecution;;?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php $colorIndex = 0;?>
|
||||
<?php foreach($programs as $programID => $programProduct):?>
|
||||
<?php $i = 0;?>
|
||||
<?php foreach($programProduct as $productID):?>
|
||||
<tr>
|
||||
<?php if($i == 0):?>
|
||||
<td rowspan="<?php echo count($programs[$programID])?>" class="program text-ellipsis" style="background: <?php echo $this->lang->product->kanbanColorList[$colorIndex];?>"><?php echo zget($programList, $programID);?></td>
|
||||
<?php endif;?>
|
||||
<td title="<?php echo $productList[$productID]->name;?>"><?php echo html::a($this->createLink('product', 'browse', "productID=$productID"), $productList[$productID]->name, '', "title={$productList[$productID]->name}");?></td>
|
||||
<td class="plan">
|
||||
<?php if(isset($planList[$productID])):?>
|
||||
<?php foreach($planList[$productID] as $planID => $plan):?>
|
||||
<div class="board-item text-ellipsis"><?php echo html::a($this->createLink('productplan', 'view', "planID=$planID"), $plan->title, '', "title={$plan->title}");?></div>
|
||||
<?php endforeach;?>
|
||||
<?php endif;?>
|
||||
</td>
|
||||
<td class="project">
|
||||
<?php if(isset($projectProduct[$productID])):?>
|
||||
<?php foreach($projectProduct[$productID] as $projectID => $project):?>
|
||||
<div class="board">
|
||||
<?php $borderStyle = isset($project->delay) ? 'border-left: 3px solid red' : 'border-left: 3px solid #0bd986';?>
|
||||
<div class="board-item" style="<?php echo $borderStyle;?>">
|
||||
<div class="table-row">
|
||||
<div class="table-col text-ellipsis">
|
||||
<?php echo html::a($this->createLink('project', 'index', "projectID=$projectID"), $projectList[$projectID]->name, '', "title={$projectList[$projectID]->name}");?>
|
||||
</div>
|
||||
<div class="table-col">
|
||||
<div class="c-progress">
|
||||
<div class='progress-pie' data-doughnut-size='90' data-color='#3CB371' data-value='<?php echo round($projectList[$projectID]->hours->progress);?>' data-width='24' data-height='24' data-back-color='#e8edf3'>
|
||||
<div class='progress-info'><?php echo round($projectList[$projectID]->hours->progress);?></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach;?>
|
||||
<?php endif;?>
|
||||
</td>
|
||||
<td class="execution">
|
||||
<?php if(isset($projectProduct[$productID])):?>
|
||||
<?php foreach($projectProduct[$productID] as $projectID => $project):?>
|
||||
<div class="board">
|
||||
<?php
|
||||
$borderStyle = '';
|
||||
if(isset($latestExecutions[$projectID]))
|
||||
{
|
||||
$delay = helper::diffDate(helper::today(), $latestExecutions[$projectID]->end);
|
||||
$borderStyle = $delay > 0 ? 'border-left: 3px solid red' : 'border-left: 3px solid #0bd986';
|
||||
}
|
||||
?>
|
||||
<?php $boardStyle = isset($latestExecutions[$projectID]) ? 'board-item' : 'emptyBoard';?>
|
||||
<?php $executionID = isset($latestExecutions[$projectID]) ? $latestExecutions[$projectID]->id : 0;?>
|
||||
<?php $executionName = isset($latestExecutions[$projectID]) ? $latestExecutions[$projectID]->name : ''?>
|
||||
<div class="<?php echo $boardStyle;?> text-ellipsis" style="<?php echo $borderStyle;?>">
|
||||
<div class="table-row">
|
||||
<div class="table-col text-ellipsis">
|
||||
<?php if(isset($latestExecutions[$projectID])):?>
|
||||
<?php echo html::a($this->createLink('execution', 'task', "executionID=$executionID"), $executionName, '', "title={$executionName}");?>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
<div class="table-col">
|
||||
<?php if(isset($latestExecutions[$projectID])):?>
|
||||
<div class="c-progress">
|
||||
<?php $hourList[$executionID] = isset($hourList[$executionID]) ? $hourList[$executionID] : $emptyHour; ?>
|
||||
<div class='progress-pie' data-doughnut-size='90' data-color='#3CB371' data-value='<?php echo round($hourList[$executionID]->progress);?>' data-width='24' data-height='24' data-back-color='#e8edf3'>
|
||||
<div class='progress-info'><?php echo round($hourList[$executionID]->progress);?></div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach;?>
|
||||
<?php endif;?>
|
||||
</td>
|
||||
<td class="release">
|
||||
<?php if(isset($releaseList[$productID])):?>
|
||||
<?php foreach($releaseList[$productID] as $releaseID => $release):?>
|
||||
<div class="board-item">
|
||||
<?php echo html::a($this->createLink('release', 'view', "releaseID=$releaseID"), $release->name, '', "title={$release->name} class='text-ellipsis'");?>
|
||||
<?php if($release->marker) echo " <span><i class='icon icon-flag red'></i></span>";?>
|
||||
</div>
|
||||
<?php endforeach;?>
|
||||
<?php endif;?>
|
||||
</td>
|
||||
<?php $i ++;?>
|
||||
</tr>
|
||||
<?php endforeach;?>
|
||||
<?php $colorIndex = $colorIndex == 9 ? 0 : ++ $colorIndex;?>
|
||||
<?php endforeach;?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endforeach;?>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
<script>
|
||||
$(function()
|
||||
{
|
||||
$(document).scroll(function()
|
||||
{
|
||||
if($('.fix-table-copy-wrapper').length > 0)
|
||||
{
|
||||
$('.fix-table-copy-wrapper table thead tr:first th:first').css('background', 'rgba(255,255,255,0)');
|
||||
}
|
||||
})
|
||||
|
||||
$('.emptyBoard').parent().height($('.board-item').parent().height());
|
||||
})
|
||||
</script>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
@@ -837,16 +837,17 @@ class programModel extends model
|
||||
*
|
||||
* @param string $model
|
||||
* @param string $mode
|
||||
* @param bool $isQueryAll
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getTopPairs($model = '', $mode = '')
|
||||
public function getTopPairs($model = '', $mode = '', $isQueryAll = false)
|
||||
{
|
||||
return $this->dao->select('id,name')->from(TABLE_PROGRAM)
|
||||
->where('type')->eq('program')
|
||||
->andWhere('grade')->eq(1)
|
||||
->beginIF(strpos($mode, 'noclosed') !== false)->andWhere('status')->ne('closed')->fi()
|
||||
->andWhere('id')->in($this->app->user->view->programs)
|
||||
->beginIF(!$isQueryAll)->andWhere('id')->in($this->app->user->view->programs)->fi()
|
||||
->andWhere('deleted')->eq(0)
|
||||
->beginIF($model)->andWhere('model')->eq($model)->fi()
|
||||
->orderBy('`order`')
|
||||
|
||||
+47
-32
@@ -1688,40 +1688,9 @@ class projectModel extends model
|
||||
->fetchAll('id');
|
||||
}
|
||||
|
||||
$hours = array();
|
||||
$hours = $this->computerProgress($executions);
|
||||
$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, execution, estimate, consumed, `left`, status, closedReason')
|
||||
->from(TABLE_TASK)
|
||||
->where('execution')->in(array_keys($executions))
|
||||
->andWhere('parent')->lt(1)
|
||||
->andWhere('deleted')->eq(0)
|
||||
->fetchGroup('execution', 'id');
|
||||
|
||||
/* Compute totalEstimate, totalConsumed, totalLeft. */
|
||||
foreach($tasks as $executionID => $executionTasks)
|
||||
{
|
||||
$hour = (object)$emptyHour;
|
||||
foreach($executionTasks as $task)
|
||||
{
|
||||
$hour->totalEstimate += $task->estimate;
|
||||
$hour->totalConsumed += $task->consumed;
|
||||
if($task->status != 'cancel' and $task->status != 'closed') $hour->totalLeft += $task->left;
|
||||
}
|
||||
$hours[$executionID] = $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;
|
||||
}
|
||||
|
||||
/* Get burndown charts datas. */
|
||||
$burns = $this->dao->select('execution, date AS name, `left` AS value')
|
||||
->from(TABLE_BURN)
|
||||
@@ -1838,6 +1807,52 @@ class projectModel extends model
|
||||
return array('kanbanGroup' => array('my' => $myProjects, 'other' => $otherProjects), 'latestExecutions' => $latestExecutions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computer execution progress.
|
||||
*
|
||||
* @param array $executions
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function computerProgress($executions)
|
||||
{
|
||||
$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, execution, estimate, consumed, `left`, status, closedReason')
|
||||
->from(TABLE_TASK)
|
||||
->where('execution')->in(array_keys($executions))
|
||||
->andWhere('parent')->lt(1)
|
||||
->andWhere('deleted')->eq(0)
|
||||
->fetchGroup('execution', 'id');
|
||||
|
||||
/* Compute totalEstimate, totalConsumed, totalLeft. */
|
||||
foreach($tasks as $executionID => $executionTasks)
|
||||
{
|
||||
$hour = (object)$emptyHour;
|
||||
foreach($executionTasks as $task)
|
||||
{
|
||||
$hour->totalEstimate += $task->estimate;
|
||||
$hour->totalConsumed += $task->consumed;
|
||||
if($task->status != 'cancel' and $task->status != 'closed') $hour->totalLeft += $task->left;
|
||||
}
|
||||
$hours[$executionID] = $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;
|
||||
}
|
||||
|
||||
return $hours;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set menu of project module.
|
||||
*
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
body {margin-bottom: 25px;}
|
||||
.w-220px {width: 220px;}
|
||||
.w-170px {width: 170px;}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user