Merge branch 'zentaopms_239'

This commit is contained in:
wangyidong
2022-11-08 08:41:28 +08:00
458 changed files with 9419 additions and 4940 deletions
+1
View File
@@ -1,5 +1,6 @@
<?php
$config->program = new stdclass();
$config->program->showAllProjects = 0;
$config->program->editor = new stdclass();
$config->program->editor->create = array('id' => 'desc', 'tools' => 'simpleTools');
+20
View File
@@ -10,6 +10,14 @@
*/
class program extends control
{
/**
* Construct
*
* @param string $moduleName
* @param string $methodName
* @access public
* @return void
*/
public function __construct($moduleName = '', $methodName = '')
{
parent::__construct($moduleName, $methodName);
@@ -757,4 +765,16 @@ class program extends control
echo $this->fetch('program', 'product', "programID=$programID");
}
/**
* Ajax set show setting.
*
* @access public
* @return void
*/
public function ajaxSetShowSetting()
{
$data = fixer::input('post')->get();
$this->loadModel('setting')->updateItem("{$this->app->user->account}.program.showAllProjects", $data->showAllProjects);
}
}
+3
View File
@@ -26,3 +26,6 @@
.scroll {overflow-x: hidden; overflow-y: auto;}
.fix-table-copy-wrapper thead > tr > th:first-child {background: none!important;}
#showSettingsBox {text-align:right; margin-top:-15px; margin-right:4px;}
#showSettingsBox .checkbox-primary {display:inline-block;}
+26 -2
View File
@@ -131,9 +131,14 @@ function calcColHeight(col, lane, colCards, colHeight)
return colCards.length * 62;
}
$(function()
/**
* Init kanban.
*
* @access public
* @return void
*/
function initKanban()
{
/* Init all kanbans */
$.each(kanbanGroup, function(key, programsData)
{
var $kanban = $('#kanban-' + key);
@@ -146,4 +151,23 @@ $(function()
calcColHeight: calcColHeight
});
});
}
$(function()
{
/* Init all kanbans */
initKanban();
$('#showAllProjects').click(function()
{
var showAllProjects = $(this).prop('checked') ? 1 : 0;
$.post(createLink('program', 'ajaxSetShowSetting'), {"showAllProjects": showAllProjects}, function()
{
$.get(createLink('program', 'kanban'), function(data)
{
$('#kanbanList').html($(data).find('#kanbanList').html());
initKanban();
});
})
})
});
+3
View File
@@ -82,6 +82,7 @@ $lang->program->manageMembers = 'Program Team';
$lang->program->confirmChangePRJUint = 'Synchronize the budget unit of the subprograms and the projects of the program? If yes, please the current exchange rate.';
$lang->program->exRateNotNegative = 'The『exchange rate』should not be negative.';
$lang->program->changePRJUnit = 'Update the budget unit of the project';
$lang->program->showNotCurrentProjects = 'Display project information of non current program';
$lang->program->progress = 'Progress';
$lang->program->children = 'Child';
@@ -163,3 +164,5 @@ $lang->program->kanban->doingExecutions = 'Ongoing Executions';
$lang->program->kanban->normalReleases = 'Normal Releases';
$lang->program->kanban->laneColorList = array('#32C5FF', '#006AF1', '#9D28B2', '#FF8F26', '#FFC20E', '#00A78E', '#7FBB00', '#424BAC', '#C0E9FF', '#EC2761');
$lang->program->defaultProgram = 'Default program';
+3
View File
@@ -82,6 +82,7 @@ $lang->program->manageMembers = 'Program Team';
$lang->program->confirmChangePRJUint = 'Synchronize the budget unit of the subprograms and the projects of the program? If yes, please the current exchange rate.';
$lang->program->exRateNotNegative = 'The『exchange rate』should not be negative.';
$lang->program->changePRJUnit = 'Update the budget unit of the project';
$lang->program->showNotCurrentProjects = 'Display project information of non current program';
$lang->program->progress = 'Progress';
$lang->program->children = 'Add Child';
@@ -163,3 +164,5 @@ $lang->program->kanban->doingExecutions = 'Ongoing Executions';
$lang->program->kanban->normalReleases = 'Normal Releases';
$lang->program->kanban->laneColorList = array('#32C5FF', '#006AF1', '#9D28B2', '#FF8F26', '#FFC20E', '#00A78E', '#7FBB00', '#424BAC', '#C0E9FF', '#EC2761');
$lang->program->defaultProgram = 'Default program';
+3
View File
@@ -82,6 +82,7 @@ $lang->program->manageMembers = 'Program Team';
$lang->program->confirmChangePRJUint = 'Synchronize the budget unit of the subprograms and the projects of the program? If yes, please the current exchange rate.';
$lang->program->exRateNotNegative = 'The『exchange rate』should not be negative.';
$lang->program->changePRJUnit = 'Update the budget unit of the project';
$lang->program->showNotCurrentProjects = 'Display project information of non current program';
$lang->program->progress = 'Progress';
$lang->program->children = 'Child';
@@ -163,3 +164,5 @@ $lang->program->kanban->doingExecutions = 'Ongoing Executions';
$lang->program->kanban->normalReleases = 'Normal Releases';
$lang->program->kanban->laneColorList = array('#32C5FF', '#006AF1', '#9D28B2', '#FF8F26', '#FFC20E', '#00A78E', '#7FBB00', '#424BAC', '#C0E9FF', '#EC2761');
$lang->program->defaultProgram = 'Default program';
+3
View File
@@ -82,6 +82,7 @@ $lang->program->manageMembers = '项目集团队';
$lang->program->confirmChangePRJUint = '是否同步更新该项目集下子项目集和项目的预算的单位?若确认更新,请填写今日汇率。';
$lang->program->exRateNotNegative = '『汇率』不能是负数。';
$lang->program->changePRJUnit = '更新项目预算单位';
$lang->program->showNotCurrentProjects = '显示非当前项目集的项目信息';
$lang->program->progress = '项目进度';
$lang->program->children = '添加子项目集';
@@ -163,3 +164,5 @@ $lang->program->kanban->doingExecutions = '进行中的执行';
$lang->program->kanban->normalReleases = '正常的发布';
$lang->program->kanban->laneColorList = array('#32C5FF', '#006AF1', '#9D28B2', '#FF8F26', '#FFC20E', '#00A78E', '#7FBB00', '#424BAC', '#C0E9FF', '#EC2761');
$lang->program->defaultProgram = '默认项目集';
+122 -15
View File
@@ -66,34 +66,90 @@ class programModel extends model
* @param string $mode all|assign
* @param string $status all|noclosed
* @param string|array $append
* @param string|int $shadow all | 0 | 1
* @access public
* @return array
*/
public function getProductPairs($programID = 0, $mode = 'assign', $status = 'all', $append = '')
public function getProductPairs($programID = 0, $mode = 'assign', $status = 'all', $append = '', $shadow = 0)
{
/* Get the top programID. */
if($programID)
{
$program = $this->getByID($programID);
$path = explode(',', $program->path);
$path = array_filter($path);
$path = array_filter(explode(',', $program->path));
$programID = current($path);
}
/* When mode equals assign and programID equals 0, you can query the standalone product. */
if(!empty($append) and is_array($append)) $append = implode(',', $append);
$views = empty($append) ? $this->app->user->view->products : $this->app->user->view->products . ",$append";
$views = empty($append) ? $this->app->user->view->products : $this->app->user->view->products . ",$append";
$products = $this->dao->select('*')->from(TABLE_PRODUCT)
return $this->dao->select('*')->from(TABLE_PRODUCT)
->where('deleted')->eq(0)
->andWhere('vision')->eq($this->config->vision)
->beginIF($shadow !== 'all')->andWhere('shadow')->eq((int)$shadow)->fi()
->beginIF($mode == 'assign')->andWhere('program')->eq($programID)->fi()
->beginIF(strpos($status, 'noclosed') !== false)->andWhere('status')->ne('closed')->fi()
->beginIF(!$this->app->user->admin)->andWhere('id')->in($views)->fi()
->fetchPairs('id', 'name');
return $products;
}
/**
* Get product pairs which name with program.
*
* @param int $programID
* @param string $mode
* @param string $status
* @param string $append
* @param int $shadow
* @access public
* @return array
*/
public function getProductPairsWithProgram($programID = 0, $mode = 'assign', $status = 'all', $append = '', $shadow = 0)
{
/* Get the top programID. */
if($programID)
{
$program = $this->getByID($programID);
$path = array_filter(explode(',', $program->path));
$programID = current($path);
}
/* When mode equals assign and programID equals 0, you can query the standalone product. */
if(!empty($append) and is_array($append)) $append = implode(',', $append);
$views = empty($append) ? $this->app->user->view->products : $this->app->user->view->products . ",$append";
$products = $this->dao->select("t1.id, t1.program, CONCAT(IF(t2.name IS NOT NULL, t2.name, ''), '/', t1.name) AS name")->from(TABLE_PRODUCT)->alias('t1')
->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.program = t2.id')
->where('t1.deleted')->eq('0')
->andWhere('t1.vision')->eq($this->config->vision)
->beginIF($shadow !== 'all')->andWhere('t1.shadow')->eq((int)$shadow)->fi()
->beginIF($mode == 'assign')->andWhere('t1.program')->eq($programID)->fi()
->beginIF(strpos($status, 'noclosed') !== false)->andWhere('t1.status')->ne('closed')->fi()
->beginIF(!$this->app->user->admin)->andWhere('t1.id')->in($views)->fi()
->orderBy('t1.program, t1.order_asc')
->fetchGroup('program');
/* Put products of current program first.*/
if($mode != 'assign' && $programID)
{
$currentProgramProducts = $products[$programID];
unset($products[$programID]);
array_unshift($products, $currentProgramProducts);
}
$productPairs = array();
foreach($products as $programProducts)
{
foreach($programProducts as $product) $productPairs[$product->id] = $product->name;
}
return $productPairs;
}
/**
* Get program by id.
*
@@ -271,9 +327,8 @@ class programModel extends model
->fetchGroup('product');
/* Get all products linked projects. */
$projectGroup = $this->dao->select('DISTINCT t1.product, t2.id, t2.name, t2.status, t2.end')->from(TABLE_PROJECTPRODUCT)->alias('t1')
->leftJoin(TABLE_PROJECT)->alias('t2')
->on('t1.project = t2.id')
$projectGroup = $this->dao->select('t1.product,t2.id,t2.name,t2.status,t2.end,t2.parent,t2.path')->from(TABLE_PROJECTPRODUCT)->alias('t1')
->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id')
->where('t2.deleted')->eq(0)
->andWhere('t1.product')->in($productPairs)
->andWhere('t2.type')->eq('project')
@@ -296,6 +351,7 @@ class programModel extends model
->where('type')->in('sprint,stage,kanban')
->andWhere('status')->eq('doing')
->andWhere('deleted')->eq(0)
->andWhere('multiple')->ne(0)
->beginIF(!$this->app->user->admin)->andWhere('id')->in($this->app->user->view->sprints)->fi()
->orderBy('id_asc')
->fetchAll('project');
@@ -336,6 +392,7 @@ class programModel extends model
foreach($projects as $project)
{
if(helper::diffDate(helper::today(), $project->end) > 0) $project->delay = 1;
if($this->config->systemMode == 'ALM' and !$this->config->program->showAllProjects and $project->parent != $product->program and strpos($project->path, ",{$product->program},") !== 0) continue;
$status = $project->status == 'wait' ? 'wait' : 'doing';
$execution = zget($doingExecutions, $project->id, array());
@@ -569,9 +626,9 @@ class programModel extends model
->leftJoin(TABLE_STAKEHOLDER)->alias('t3')->on('t1.id=t3.objectID')
->where('t1.deleted')->eq('0')
->andWhere('t1.vision')->eq($this->config->vision)
->beginIF($browseType == 'bysearch')->andWhere($query)->fi()
->beginIF($this->config->systemMode == 'new')->andWhere('t1.type')->eq('project')->fi()
->beginIF($this->config->systemMode == 'new' and ($this->cookie->involved or $involved))->andWhere('t2.type')->eq('project')->fi()
->beginIF($browseType == 'bysearch' and $query)->andWhere($query)->fi()
->andWhere('t1.type')->eq('project')
->beginIF($this->cookie->involved or $involved)->andWhere('t2.type')->eq('project')->fi()
->beginIF(!in_array($browseType, array('all', 'undone', 'bysearch', 'review', 'unclosed'), true))->andWhere('t1.status')->eq($browseType)->fi()
->beginIF($browseType == 'undone' or $browseType == 'unclosed')->andWhere('t1.status')->in('wait,doing')->fi()
->beginIF($browseType == 'review')
@@ -579,8 +636,7 @@ class programModel extends model
->andWhere('t1.reviewStatus')->eq('doing')
->fi()
->beginIF($path)->andWhere('t1.path')->like($path . '%')->fi()
->beginIF(!$queryAll and !$this->app->user->admin and $this->config->systemMode == 'new')->andWhere('t1.id')->in($this->app->user->view->projects)->fi()
->beginIF(!$queryAll and !$this->app->user->admin and $this->config->systemMode == 'classic')->andWhere('t1.id')->in($this->app->user->view->sprints)->fi()
->beginIF(!$queryAll and !$this->app->user->admin)->andWhere('t1.id')->in($this->app->user->view->projects)->fi()
->beginIF($this->cookie->involved or $involved)
->andWhere('t1.openedBy', true)->eq($this->app->user->account)
->orWhere('t1.PM')->eq($this->app->user->account)
@@ -594,7 +650,7 @@ class programModel extends model
->fetchAll('id');
/* Determine how to display the name of the program. */
if($programTitle and $this->config->systemMode == 'new')
if($programTitle and $this->config->systemMode == 'ALM')
{
$programList = $this->getPairs();
foreach($projectList as $id => $project)
@@ -1593,4 +1649,55 @@ class programModel extends model
}
return $menu;
}
/**
* Create default program.
*
* @access public
* @return int
*/
public function createDefaultProgram()
{
$defaultProgram = $this->loadModel('setting')->getItem('owner=system&module=common&section=global&key=defaultProgram');
if($defaultProgram)
{
$program = $this->dao->select('id')->from(TABLE_PROGRAM)->where('id')->eq($defaultProgram)->andWhere('deleted')->eq(0)->fetch();
if($program) return $defaultProgram;
}
$program = $this->dao->select('id')->from(TABLE_PROGRAM)->where('name')->eq($this->lang->program->defaultProgram)->andWhere('deleted')->eq(0)->fetch();
if($program) return $program->id;
$account = isset($this->app->user->account) ? $this->app->user->account : '';
$minBegin = $this->dao->select('min(begin) as min')->from(TABLE_PROJECT)->where('deleted')->eq(0)->fetch('min');
$program = new stdclass();
$program->name = $this->lang->program->defaultProgram;
$program->type = 'program';
$program->budgetUnit = 'CNY';
$program->status = 'doing';
$program->auth = 'extend';
$program->begin = !empty($minBegin) ? $minBegin : helper::today();
$program->end = LONG_TIME;
$program->openedBy = $account;
$program->openedDate = helper::now();
$program->openedVersion = $this->config->version;
$program->acl = 'open';
$program->grade = 1;
$program->vision = 'rnd';
$this->app->loadLang('program');
$this->app->loadLang('project');
$this->lang->project->name = $this->lang->program->name;
$this->dao->insert(TABLE_PROGRAM)->data($program)->exec();
if(dao::isError()) return false;
$programID = $this->dao->lastInsertId();
$this->dao->update(TABLE_PROGRAM)->set('path')->eq(",{$programID},")->set('`order`')->eq($programID * 5)->where('id')->eq($programID)->exec();
$this->loadModel('action')->create('program', $programID, 'openedbysystem');
return $programID;
}
}
+31 -25
View File
@@ -11,12 +11,18 @@
?>
<?php include '../../common/view/header.html.php';?>
<?php include '../../common/view/kanban.html.php';?>
<?php if(empty($kanbanGroup)):?>
<div class="table-empty-tip cell">
<p class="text-muted"><?php echo $lang->program->noProgram;?></p>
<div id='showSettingsBox'>
<div class="checkbox-primary checkbox">
<input type="checkbox" value="1" id="showAllProjects" title="<?php echo $lang->program->showNotCurrentProjects;?>" <?php echo $config->program->showAllProjects ? 'checked' : '';?>>
<label for="showAllProjects"><?php echo $lang->program->showNotCurrentProjects;?></label>
</div>
</div>
<?php else:?>
<div id='kanbanList'>
<?php if(empty($kanbanGroup)):?>
<div class="table-empty-tip cell">
<p class="text-muted"><?php echo $lang->program->noProgram;?></p>
</div>
<?php else:?>
<?php foreach($kanbanGroup as $type => $programs):?>
<?php if(empty($programs)) continue;?>
<div class='panel kanban-panel'>
@@ -27,26 +33,26 @@
<div id='kanban-<?php echo $type;?>' class='kanban'></div>
</div>
</div>
<?php endforeach; ?>
<?php endforeach;?>
<?php
$kanbanColumns = array();
$kanbanColumns['unclosedProduct'] = array('name' => $lang->program->kanban->openProducts, 'type' => 'unclosedProduct');
$kanbanColumns['unexpiredPlan'] = array('name' => $lang->program->kanban->unexpiredPlans, 'type' => 'unexpiredPlan');
$kanbanColumns['waitProject'] = array('name' => $lang->program->kanban->waitingProjects, 'type' => 'waitProject');
$kanbanColumns['doingProject'] = array('name' => $lang->program->kanban->doingProjects, 'type' => 'doingProject');
$kanbanColumns['doingExecution'] = array('name' => $lang->program->kanban->doingExecutions, 'type' => 'doingExecution');
$kanbanColumns['normalRelease'] = array('name' => $lang->program->kanban->normalReleases, 'type' => 'normalRelease');
$userPrivs = array();
$userPrivs['product'] = common::hasPriv('product', 'browse');
$userPrivs['productplan'] = common::hasPriv('productplan', 'view');
$userPrivs['project'] = common::hasPriv('project', 'index');
$userPrivs['execution'] = common::hasPriv('execution', 'task');
$userPrivs['release'] = common::hasPriv('release', 'view');
js::set('kanbanColumns', array_values($kanbanColumns));
js::set('userPrivs', $userPrivs);
js::set('kanbanGroup', $kanbanGroup);
js::set('doingText', $lang->program->statusList['doing']);
?>
<?php endif;?>
</div>
<?php
$kanbanColumns = array();
$kanbanColumns['unclosedProduct'] = array('name' => $lang->program->kanban->openProducts, 'type' => 'unclosedProduct');
$kanbanColumns['unexpiredPlan'] = array('name' => $lang->program->kanban->unexpiredPlans, 'type' => 'unexpiredPlan');
$kanbanColumns['waitProject'] = array('name' => $lang->program->kanban->waitingProjects, 'type' => 'waitProject');
$kanbanColumns['doingProject'] = array('name' => $lang->program->kanban->doingProjects, 'type' => 'doingProject');
$kanbanColumns['doingExecution'] = array('name' => $lang->program->kanban->doingExecutions, 'type' => 'doingExecution');
$kanbanColumns['normalRelease'] = array('name' => $lang->program->kanban->normalReleases, 'type' => 'normalRelease');
$userPrivs = array();
$userPrivs['product'] = common::hasPriv('product', 'browse');
$userPrivs['productplan'] = common::hasPriv('productplan', 'view');
$userPrivs['project'] = common::hasPriv('project', 'index');
$userPrivs['execution'] = common::hasPriv('execution', 'task');
$userPrivs['release'] = common::hasPriv('release', 'view');
js::set('kanbanColumns', array_values($kanbanColumns));
js::set('userPrivs', $userPrivs);
js::set('kanbanGroup', $kanbanGroup);
js::set('doingText', $lang->program->statusList['doing']);
?>
<?php endif; ?>
<?php include '../../common/view/footer.html.php';?>