* adjust for project kanban.

This commit is contained in:
王怡栋
2022-01-17 17:25:20 +08:00
parent 5dad24d03a
commit d8577f7d28
21 changed files with 410 additions and 351 deletions

View File

@@ -1,4 +1,4 @@
ALTER TABLE `zt_project` ADD `vision` varchar(10) NOT NULL DEFAULT 'common' AFTER `order`;
ALTER TABLE `zt_product` ADD `vision` varchar(10) NOT NULL DEFAULT 'common' AFTER `order`;
ALTER TABLE `zt_doclib` ADD `vision` varchar(10) NOT NULL DEFAULT 'common' AFTER `order`;
ALTER TABLE `zt_task` ADD `vision` varchar(10) NOT NULL DEFAULT 'common' AFTER `v2`;
ALTER TABLE `zt_kanban` ADD `project` mediumint(8) unsigned NOT NULL AFTER `space`;

View File

@@ -30,7 +30,7 @@ $lang->project->target = '目标';
/* Scrum menu. */
$lang->scrum->menu = new stdclass();
$lang->scrum->menu->index = array('link' => "{$lang->dashboard}|project|index|project=%s");
$lang->scrum->menu->execution = array('link' => "$lang->executionKanban|project|execution|status=all&projectID=%s", 'subModule' => 'execution', 'exclude' => 'execution-testreport');
$lang->scrum->menu->execution = array('link' => "$lang->executionKanban|project|execution|status=all&projectID=%s", 'subModule' => 'kanban');
$lang->scrum->menu->story = array('link' => "{$lang->project->target}|projectstory|story|projectID=%s", 'subModule' => 'projectstory,tree', 'alias' => 'story,track');
$lang->scrum->menu->doc = array('link' => "{$lang->doc->common}|doc|tableContents|type=project&objectID=%s", 'subModule' => 'doc');
$lang->scrum->menu->dynamic = array('link' => "$lang->dynamic|project|dynamic|project=%s");
@@ -47,6 +47,14 @@ $lang->scrum->menuOrder[20] = 'doc';
$lang->scrum->menuOrder[25] = 'dynamic';
$lang->scrum->menuOrder[30] = 'settings';
$lang->execution->menu = new stdclass();
$lang->execution->menu->kanban = array('link' => "看板|execution|kanban|executionID=%s");
$lang->execution->menu->list = array('link' => "列表|execution|task|executionID=%s");
$lang->execution->menu->calendar = array('link' => "日历|execution|calendar|executionID=%s");
$lang->execution->menu->gantt = array('link' => "甘特图|execution|gantt|executionID=%s");
$lang->execution->menu->tree = array('link' => "树状图|execution|tree|executionID=%s");
$lang->execution->menu->group = array('link' => "分组视图|execution|groupTask|executionID=%s");
$lang->scrum->menu->doc['subMenu'] = new stdclass();
$lang->scrum->menu->settings['subMenu'] = new stdclass();

View File

@@ -0,0 +1,4 @@
<script>
$('#userNav li:first ul.dropdown-menu li a[href*="tutorial"]').parent().remove();
$('#userNav li:first ul.dropdown-menu li a[href*="preference"]').parent().remove();
</script>

View File

@@ -1,66 +0,0 @@
<?php
include '../../../../../module/execution/control.php';
class myExecution extends execution
{
public function all($status = 'all', $projectID = 0, $orderBy = 'order_asc', $productID = 0, $recTotal = 0, $recPerPage = 10, $pageID = 1)
{
$this->app->loadLang('my');
$this->app->loadLang('product');
$this->app->loadLang('stage');
$this->app->loadLang('programplan');
$from = $this->app->tab;
if($from == 'execution') $this->session->set('executionList', $this->app->getURI(true), 'execution');
if($from == 'project')
{
$projects = $this->project->getPairsByProgram();
$projectID = $this->project->saveState($projectID, $projects);
$project = $this->loadModel('project')->getByID($projectID);
$this->view->project = $project;
$this->project->setMenu($projectID);
}
if($this->app->viewType == 'mhtml')
{
if($this->app->rawModule == 'project' and $this->app->rawMethod == 'execution')
{
$projects = $this->project->getPairsByProgram();
$projectID = $this->project->saveState($projectID, $projects);
$this->project->setMenu($projectID);
}
else
{
$executionID = $this->execution->saveState(0, $this->executions);
$this->execution->setMenu($executionID);
}
}
/* Load pager and get tasks. */
$this->app->loadClass('pager', $static = true);
$pager = new pager($recTotal, $recPerPage, $pageID);
$this->view->title = $this->lang->execution->allExecutions;
$this->view->position[] = $this->lang->execution->allExecutions;
$executionStats = $this->project->getStats($projectID, $status, $productID, 0, 30, $orderBy, $pager);
$executionTeams = array();
foreach($executionStats as $execution) $executionTeams[$execution->id] = $this->execution->getTeamMembers($execution->id);
$this->view->executionStats = $executionStats;
$this->view->executionTeams = $executionTeams;
$this->view->productList = $this->loadModel('product')->getProductPairsByProject($projectID);
$this->view->productID = $productID;
$this->view->projectID = $projectID;
$this->view->projects = array('') + $this->project->getPairsByProgram();
$this->view->pager = $pager;
$this->view->orderBy = $orderBy;
$this->view->users = $this->loadModel('user')->getPairs('noletter');
$this->view->status = $status;
$this->view->from = $from;
$this->view->isStage = (isset($project->model) and $project->model == 'waterfall') ? true : false;
$this->view->users = $this->loadModel('user')->getPairs('noletter|nodeleted');
$this->view->usersAvatar = $this->user->getAvatarPairs();
$this->display();
}
}

View File

@@ -1,11 +1,7 @@
<?php
unset($lang->execution->featureBar['all']['undone']);
unset($lang->execution->featureBar['all']['wait']);
unset($lang->execution->featureBar['all']['suspended']);
$lang->execution->createKanban = '创建看板';
$lang->execution->noExecution = "暂时没有看板。";
$lang->execution->create = "添加看板";
$lang->execution->name = "看板名称";
$lang->execution->code = "看板代号";
$lang->execution->desc = "看板描述";

View File

@@ -1,131 +0,0 @@
<?php
/**
* The html template file of all method of execution module for lite vision 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 Wenrui LI <liwenrui@easycorp.ltd>
* @package execution
* @version $Id: index.html.php 5094 2013-07-10 08:46:15Z chencongzhi520@gmail.com $
*/
?>
<?php include $this->app->getModuleRoot() . '/common/view/header.html.php';?>
<?php include $this->app->getModuleRoot() . '/common/view/sortable.html.php';?>
<div id='mainMenu' class='clearfix'>
<div class='btn-toolbar pull-left'>
<?php foreach($lang->execution->featureBar['all'] as $key => $label):?>
<?php echo html::a($this->createLink($this->app->rawModule, $this->app->rawMethod, "status=$key&projectID=$projectID&orderBy=$orderBy&productID=$productID"), "<span class='text'>{$label}</span>" . ($status == $key ? ' <span class="label label-light label-badge">' . count($executionStats) . '</span>' : ''), '', "class='btn btn-link" . ($status == $key ? ' btn-active-text' : '') . "' id='{$key}Tab' data-app='$from'");?>
<?php endforeach;?>
</div>
<div class='btn-toolbar pull-right'>
<?php if(common::hasPriv('execution', 'create')) echo html::a($this->createLink('execution', 'create', "projectID=$projectID"), "<i class='icon icon-sm icon-plus'></i> " . $lang->execution->createKanban, '', "class='btn btn-primary create-execution-btn' data-app='$from'");?>
</div>
</div>
<div id='mainContent' class="main-row fade cell">
<?php if(empty($executionStats)):?>
<div class="table-empty-tip">
<p>
<span class="text-muted"><?php echo $from == 'execution' ? $lang->execution->noExecutions : $lang->execution->noExecution;?></span>
<?php if(common::hasPriv('execution', 'create')):?>
<?php echo html::a($this->createLink('execution', 'create', "projectID=$projectID"), "<i class='icon icon-plus'></i> " . $lang->execution->createKanban, '', "class='btn btn-info' data-app='$from'");?>
<?php endif;?>
</p>
</div>
<?php else:?>
<div class='kanban-cards'>
<?php foreach($executionStats as $index => $execution):?>
<?php $executionStatus = $this->processStatus('execution', $execution);?>
<div id="execution-<?php echo $execution->id;?>" class='kanban-card col' data-url='<?php echo $this->createLink('execution', 'kanban', "executionID=$execution->id");?>'>
<div class="panel">
<div class="panel-heading">
<span class="label execution-status-<?php echo $execution->status;?>"><?php echo $executionStatus;?></span>
<strong class="kanban-name" title='<?php echo $execution->name;?>'><?php echo $execution->name;?></strong>
<div class='kanban-actions' id='kanban-actions-<?php echo $execution->id;?>'>
<div class='dropdown'>
<?php echo html::a('javascript:;', "<i class='icon icon-ellipsis-v'></i>", '', "data-toggle='dropdown' class='btn btn-link'");?>
<ul class='dropdown-menu <?php echo ($index + 1) % 4 == 0 ? 'pull-left' : 'pull-right';?>'>
<?php
if(common::hasPriv('execution','edit'))
{
echo '<li>';
common::printLink('execution', 'edit', "executionID={$execution->id}", '<i class="icon icon-edit"></i> ' . $lang->execution->edit, '', "class='iframe' data-width='75%'", '', true);
echo '</li>';
}
if(common::hasPriv('execution','close'))
{
$class = $execution->status == 'closed' ? 'disabled' : '';
echo "<li class='{$class}'>";
common::printLink('execution', 'close', "executionID={$execution->id}", '<i class="icon icon-off"></i> ' . $lang->execution->close, '', "class='iframe {$class}' data-width='75%'", '', true);
echo '</li>';
}
if(common::hasPriv('execution','delete'))
{
echo '<li>';
common::printLink('execution', 'delete', "executionID={$execution->id}", '<i class="icon icon-trash"></i> ' . $lang->execution->delete, 'hiddenwin');
echo '</li>';
}
?>
</ul>
</div>
</div>
</div>
<div class="panel-body">
<div class="kanban-desc">
<?php echo $execution->desc;?>
</div>
<div class="kanban-footer">
<div class='execution-members pull-left'>
<?php foreach($executionTeams[$execution->id] as $member):?>
<div title="<?php echo $users[$member->account];?>">
<?php echo html::smallAvatar(array('avatar' => $usersAvatar[$member->account], 'account' => $member->account)); ?>
</div>
<?php endforeach;?>
</div>
<div class='execution-members-count pull-left'><?php echo sprintf($lang->project->teamSumCount, count($executionTeams[$execution->id]));?></div>
<div class='execution-acl pull-right'>
<span><i class="icon icon-<?php echo $execution->acl == 'private' ? 'lock' : 'unlock-alt';?>"></i> <?php echo zget($lang->project->acls, $execution->acl, '');?></span>
</div>
</div>
</div>
</div>
</div>
<?php endforeach;?>
</div>
<?php endif;?>
</div>
<style>
.kanban-cards {padding-top: 12px; width: 100%;}
.kanban-card {width: 25%;}
.kanban-card .panel {margin: 0 0; border: 1px solid #DCDCDC; border-radius: 4px; box-shadow: none; cursor: pointer; height: 160px; margin-bottom: 5px;}
.kanban-card .panel:hover {border-color: #006AF1; box-shadow: 0 0 10px 0 rgba(0,0,100,.25);}
.kanban-card .panel:hover .kanban-actions {visibility: unset;}
.kanban-card .kanban-actions {position: absolute; top: 2px; right: 2px; float: right; visibility: hidden;}
.kanban-card .kanban-actions .dropdown-menu.pull-right {top:31px; right: -84px; left: auto;}
.kanban-card .kanban-actions .dropdown-menu.pull-left {top:31px; right:-1px; left: auto;}
.kanban-card .kanban-desc {color: #838a9d; word-break:break-all; height: 70px; overflow: hidden; display: -webkit-box; float:left;}
.kanban-card .kanban-footer {position: absolute; bottom: 10px; right: 10px; left: 15px;}
.kanban-card .execution-members {float: left; height: 24px; line-height: 24px;}
.kanban-card .execution-members > div {display: inline-block; height: 24px;}
.kanban-card .execution-members > div + div {margin-left: -5px;}
.kanban-card .execution-members > div > .avatar {display: inline-block; width: 24px; height: 24px; line-height: 24px; margin-right: 1px;}
.kanban-card .execution-members > span {display: inline-block; color: transparent; width: 2px; height: 2px; background-color: #8990a2; position: relative; border-radius: 50%; top: 3px; margin: 0 3px;}
.kanban-card .execution-members > span:before,
.kanban-card .execution-members > span:after {content: ''; display: block; position: absolute; width: 2px; height: 2px; background-color: #8990a2; top: 0; border-radius: 50%}
.kanban-card .execution-members > span:before {left: -4px;}
.kanban-card .execution-members > span:after {right: -4px;}
.kanban-card .execution-members-count {display: inline-block; margin-left: 6px; position: relative; top: 3px}
.kanban-card .execution-acl {position: absolute; right: 0px; bottom: 2px; color: #838a9d;}
</style>
<script>
/* Make cards clickable. */
$('.kanban-cards').on('click', '.kanban-card', function(e)
{
if(!$(e.target).closest('.kanban-actions').length)
{
window.location.href = $(this).data('url');
}
});
$('execution-status-doing').addClass('label-success');
$('execution-status-suspended').addClass('label-warning');
</script>
<?php include $this->app->getModuleRoot() . '/common/view/footer.html.php';?>

View File

@@ -1,112 +0,0 @@
<?php
/**
* The create view of execution 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 execution
* @version $Id: create.html.php 4728 2013-05-03 06:14:34Z chencongzhi520@gmail.com $
* @link http://www.zentao.net
*/
?>
<?php if(isset($tips)):?>
<?php $defaultURL = $this->createLink('execution', 'kanban', 'executionID=' . $executionID);?>
<?php die(js::locate($defaultURL));?>
<?php endif;?>
<?php include $app->getModuleRoot() . 'common/view/header.html.php';?>
<?php include $app->getModuleRoot() . 'common/view/kindeditor.html.php';?>
<?php js::import($jsRoot . 'misc/date.js');?>
<?php js::set('weekend', $config->execution->weekend);?>
<?php js::set('holders', $lang->execution->placeholder);?>
<?php js::set('errorSameProducts', $lang->execution->errorSameProducts);?>
<?php js::set('errorSameBranches', $lang->execution->errorSameBranches);?>
<?php js::set('productID', empty($productID) ? 0 : $productID);?>
<?php js::set('isStage', $isStage);?>
<?php js::set('copyExecutionID', $copyExecutionID);?>
<?php js::set('systemMode', $config->systemMode);?>
<?php js::set('projectCommon', $lang->project->common);?>
<?php js::set('multiBranchProducts', $multiBranchProducts);?>
<?php js::set('systemMode', $config->systemMode);?>
<div id='mainContent' class='main-content'>
<div class='center-block'>
<div class='main-header'>
<h2><?php echo $lang->execution->create;?></h2>
</div>
<form class='form-indicator main-form form-ajax' method='post' target='hiddenwin' id='dataform'>
<table class='table table-form'>
<?php if($config->systemMode == 'new'):?>
<tr>
<th class='w-120px'><?php echo $lang->execution->projectName;?></th>
<td class="col-main"><?php echo html::select("project", $allProjects, $projectID, "class='form-control chosen' required onchange='refreshPage(this.value)'");?></td>
<td colspan='2'></td>
</tr>
<?php endif;?>
<tr>
<th class='w-120px'><?php echo $lang->execution->name;?></th>
<td class="col-main">
<?php echo html::input('name', $name, "class='form-control' required");?>
<?php echo html::hidden('begin', date('Y-m-d'));?>
<?php echo html::hidden('end', date('Y-m-d'));?>
<?php echo html::hidden('days', '1');?>
</td>
<td colspan='2'></td>
</tr>
<tr>
<th><?php echo $lang->execution->code;?></th>
<td><?php echo html::input('code', $code, "class='form-control' required");?></td><td></td><td></td>
</tr>
<tr class='hide'>
<th><?php echo $lang->execution->status;?></th>
<td><?php echo html::hidden('status', 'wait');?></td>
<td></td>
<td></td>
</tr>
<?php $this->printExtendFields('', 'table', 'columns=3');?>
<tr>
<th><?php echo $lang->execution->owner;?></th>
<td><?php echo html::select('PM', $pmUsers, empty($copyExecution) ? '' : $copyExecution->PM, "class='form-control chosen'");?></td>
</tr>
<tr>
<th><?php echo $lang->execution->team;?></th>
<td colspan='3'><?php echo html::select('teamMembers[]', $users, '', "class='form-control chosen' multiple"); ?></td>
</tr>
<tr>
<th><?php echo $lang->execution->desc;?></th>
<td colspan='3'>
<?php echo $this->fetch('user', 'ajaxPrintTemplates', 'type=execution&link=desc');?>
<?php echo html::textarea('desc', '', "rows='6' class='form-control kindeditor' hidefocus='true'");?>
</td>
</tr>
<tr>
<th><?php echo $lang->execution->acl;?></th>
<td colspan='3'><?php echo nl2br(html::radio('acl', $lang->execution->aclList, $acl, "onclick='setWhite(this.value);'", 'block'));?></td>
</tr>
<tr class="hidden" id="whitelistBox">
<th><?php echo $lang->whitelist;?></th>
<td colspan='2'>
<div class='input-group'>
<?php echo html::select('whitelist[]', $users, $whitelist, 'class="form-control chosen" multiple');?>
<?php echo $this->fetch('my', 'buildContactLists', "dropdownName=whitelist");?>
</div>
</td>
</tr>
<tr>
<td colspan='4' class='text-center form-actions'>
<?php echo html::submitButton();?>
<?php echo $gobackLink ? html::a($gobackLink, $lang->goback, '', 'class="btn btn-wide"') : html::backButton();?>
<?php echo html::hidden('lifetime', key($lang->execution->lifeTimeList));?>
<?php echo html::hidden("products[]", key($allProducts));?>
<?php echo html::hidden("PO", '');?>
<?php echo html::hidden("QD", '');?>
<?php echo html::hidden("RD", '');?>
<?php echo html::hidden("type", 'kanban');?>
<?php echo html::hidden("vision", 'lite');?>
</td>
</tr>
</table>
</form>
</div>
</div>
<?php include $app->getModuleRoot() . 'common/view/footer.html.php';?>

View File

@@ -0,0 +1,3 @@
<?php
$config->kanban->create->requiredFields = 'project,name';
$config->kanban->edit->requiredFields = 'project,name';

View File

@@ -0,0 +1,5 @@
<?php
$lang->kanban->project = '所属项目';
$lang->kanban->aclList['extend'] = '继承项目访问权限(能访问当前项目,即可访问)';
$lang->kanban->aclList['private'] = '私有(看板团队成员、白名单、项目负责人可访问)';

View File

@@ -0,0 +1,22 @@
<?php
public function getKanbanByProject($projectID, $status = 'all')
{
$project = $this->loadModel('project')->getById($projectID);
$teams = $this->project->getTeamMembers($projectID);
$project->team = join(',', array_keys($teams));
$project->owner = zget($project, 'PO', 'openedBy');
$kanbans = $this->dao->select('*')->from(TABLE_KANBAN)
->where('project')->eq($projectID)
->andWhere('deleted')->eq(0)
->beginIF($status != 'all')->andWhere('status')->eq($status)->fi()
->fetchAll('id');
foreach($kanbans as $kanban)
{
if(!$this->checkKanbanPriv($kanban, 'kanban', array($project->id => $project))) unset($kanbans[$kanban->id]);
}
return array_values($kanbans);
}

View File

@@ -0,0 +1,76 @@
<?php
/**
* The create file of kanban module of ZenTaoPMS.
*
* @copyright Copyright 2009-2021 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author Shujie Tian <tianshujie@easycorp.ltd>
* @package kanban
* @version $Id: create.html.php 935 2021-12-09 13:48:24Z $
* @link https://www.zentao.net
*/
?>
<?php include $app->getModuleRoot() . 'common/view/header.html.php';?>
<?php include $app->getModuleRoot() . 'common/view/kindeditor.html.php';?>
<div id='mainContent' class='main-content'>
<div class='main-header'>
<h2><?php echo $lang->kanban->create;?></h2>
</div>
<form class='form-indicator main-form form-ajax' method='post' enctype='multipart/form-data' id='dataform'>
<table class='table table-form'>
<tr>
<th><?php echo $lang->kanban->project;?></th>
<td>
<?php
$projects = array(0 => '') + $this->loadModel('project')->getPairsByModel('all', 0, 'noclosed');
echo html::select('project', $projects, $spaceID, "class='form-control chosen'");
echo html::hidden('space', 0);
?>
</td>
<td></td>
</tr>
<tr>
<th><?php echo $lang->kanban->name;?></th>
<td><?php echo html::input('name', '', "class='form-control'");?></td>
</tr>
<tr>
<th><?php echo $lang->kanban->archived;?></th>
<td><?php echo html::radio('archived', $lang->kanban->enableArchived, '0');?></td>
</tr>
<tr>
<th><?php echo $lang->kanban->owner;?></th>
<td><?php echo html::select('owner', $users, '', "class='form-control chosen'");?></td>
</tr>
<tr>
<th><?php echo $lang->kanban->team;?></th>
<td colspan='2'>
<div class="input-group">
<?php echo html::select('team[]', $users, '', "class='form-control chosen' multiple data-drop_direction='down'");?>
<?php echo $this->fetch('my', 'buildContactLists');?>
</div>
</td>
</tr>
<tr>
<th><?php echo $lang->kanban->desc;?></th>
<td colspan='2'>
<?php echo $this->fetch('user', 'ajaxPrintTemplates', 'type=kanban&link=desc');?>
<?php echo html::textarea('desc', '', "rows='10' class='form-control'");?>
</td>
</tr>
<tr>
<th><?php echo $lang->kanban->acl;?></th>
<td colspan='2'><?php echo nl2br(html::radio('acl', $lang->kanban->aclList, 'private', "onclick='setWhite(this.value);'", 'block'));?></td>
</tr>
<tr id="whitelistBox">
<th><?php echo $lang->whitelist;?></th>
<td><?php echo html::select('whitelist[]', $users, '', 'class="form-control chosen" multiple');?></td>
</tr>
<tr>
<td colspan='3' class='text-center form-actions'>
<?php echo html::submitButton();?>
</td>
</tr>
</table>
</form>
</div>
<?php include $app->getModuleRoot() . 'common/view/footer.html.php';?>

View File

@@ -0,0 +1,76 @@
<?php
/**
* The edit file of kanban module of ZenTaoPMS.
*
* @copyright Copyright 2009-2021 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author Mengyi Liu <liumengyi@easycorp.ltd>
* @package kanban
* @version $Id: edit.html.php 935 2021-12-09 16:15:24Z $
* @link https://www.zentao.net
*/
?>
<?php include $app->getModuleRoot() . 'common/view/header.html.php';?>
<?php include $app->getModuleRoot() . 'common/view/kindeditor.html.php';?>
<div id='mainContent' class='main-content'>
<div class='main-header'>
<h2><?php echo $lang->kanban->edit;?></h2>
</div>
<form class='form-indicator main-form form-ajax' method='post' enctype='multipart/form-data' id='dataform'>
<table class='table table-form'>
<tr>
<th><?php echo $lang->kanban->project;?></th>
<td>
<?php
$projects = array(0 => '') + $this->loadModel('project')->getPairsByModel('all', 0, 'noclosed');
echo html::select('project', $projects, $kanban->project, "class='form-control chosen'");
echo html::hidden('space', 0);
?>
</td>
<td></td>
</tr>
<tr>
<th><?php echo $lang->kanban->name;?></th>
<td><?php echo html::input('name', $kanban->name, "class='form-control'");?></td>
</tr>
<tr>
<th><?php echo $lang->kanban->archived;?></th>
<td><?php echo html::radio('archived', $lang->kanban->enableArchived, $kanban->archived);?></td>
</tr>
<tr>
<th><?php echo $lang->kanban->owner;?></th>
<td><?php echo html::select('owner', $users, $kanban->owner, "class='form-control chosen'");?></td>
</tr>
<tr>
<th><?php echo $lang->kanban->team;?></th>
<td colspan='2'>
<div class="input-group">
<?php echo html::select('team[]', $users, $kanban->team, "class='form-control chosen' multiple data-drop_direction='down'");?>
<?php echo $this->fetch('my', 'buildContactLists');?>
</div>
</td>
</tr>
<tr>
<th><?php echo $lang->kanban->desc;?></th>
<td colspan='2'>
<?php echo $this->fetch('user', 'ajaxPrintTemplates', 'type=kanban&link=desc');?>
<?php echo html::textarea('desc', $kanban->desc, "rows='10' class='form-control'");?>
</td>
</tr>
<tr>
<th><?php echo $lang->kanban->acl;?></th>
<td colspan='2'><?php echo nl2br(html::radio('acl', $lang->kanban->aclList, $kanban->acl == 'open' ? 'extend' : $kanban->acl, "onclick='setWhite(this.value);'", 'block'));?></td>
</tr>
<tr id="whitelistBox">
<th><?php echo $lang->whitelist;?></th>
<td><?php echo html::select('whitelist[]', $users, $kanban->whitelist, 'class="form-control chosen" multiple');?></td>
</tr>
<tr>
<td colspan='3' class='text-center form-actions'>
<?php echo html::submitButton();?>
</td>
</tr>
</table>
</form>
</div>
<?php include $app->getModuleRoot() . 'common/view/footer.html.php';?>

View File

@@ -0,0 +1,15 @@
<?php
class project extends control
{
public function execution($status = 'all', $projectID = 0, $orderBy = 'order_asc', $productID = 0, $recTotal = 0, $recPerPage = 10, $pageID = 1)
{
$this->project->setMenu($projectID);
$this->app->loadLang('execution');
$this->view->projectID = $projectID;
$this->view->status = $status;
$this->view->kanbans = $this->loadModel('kanban')->getKanbanByProject($projectID, $status == 'doing' ? 'active' : $status);
$this->view->usersAvatar = $this->loadModel('user')->getAvatarPairs();
$this->display();
}
}

View File

@@ -0,0 +1,129 @@
<?php
/**
* The html template file of all method of execution module for lite vision 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 Wenrui LI <liwenrui@easycorp.ltd>
* @package execution
* @version $Id: index.html.php 5094 2013-07-10 08:46:15Z chencongzhi520@gmail.com $
*/
?>
<?php include $this->app->getModuleRoot() . '/common/view/header.html.php';?>
<?php include $this->app->getModuleRoot() . '/common/view/sortable.html.php';?>
<div id='mainMenu' class='clearfix'>
<div class='btn-toolbar pull-left'>
<?php foreach($lang->execution->featureBar['all'] as $key => $label):?>
<?php echo html::a($this->createLink('project', 'execution', "status=$key&projectID=$projectID"), "<span class='text'>{$label}</span>" . ($status == $key ? ' <span class="label label-light label-badge">' . count($kanbans) . '</span>' : ''), '', "class='btn btn-link" . ($status == $key ? ' btn-active-text' : '') . "' id='{$key}Tab' data-app='project'");?>
<?php endforeach;?>
</div>
<div class='btn-toolbar pull-right'>
<?php if(common::hasPriv('kanban', 'create')) echo html::a($this->createLink('kanban', 'create', "projectID=$projectID", 'html', true), "<i class='icon icon-sm icon-plus'></i> " . $lang->execution->createKanban, '', "class='btn btn-primary create-execution-btn iframe' data-app='project'");?>
</div>
</div>
<div id='mainContent' class="main-row fade cell">
<?php if(empty($kanbans)):?>
<div class="table-empty-tip">
<p>
<span class="text-muted"><?php echo $lang->execution->noExecution;?></span>
<?php if(common::hasPriv('kanban', 'create')):?>
<?php echo html::a($this->createLink('kanban', 'create', "projectID=$projectID", 'html', true), "<i class='icon icon-plus'></i> " . $lang->execution->createKanban, '', "class='btn btn-info iframe' data-app='project'");?>
<?php endif;?>
</p>
</div>
<?php else:?>
<div class='kanban-cards'>
<?php foreach($kanbans as $index => $kanban):?>
<div id="kanban-<?php echo $kanban->id;?>" class='kanban-card col' data-url='<?php echo $this->createLink('kanban', 'view', "kanbanID=$kanban->id");?>'>
<div class="panel">
<div class="panel-heading">
<span class="label kanban-status-<?php echo $kanban->status;?>"><?php echo zget($lang->execution->statusList, $kanban->status);?></span>
<strong class="kanban-name" title='<?php echo $kanban->name;?>'><?php echo $kanban->name;?></strong>
<div class='kanban-actions' id='kanban-actions-<?php echo $kanban->id;?>'>
<div class='dropdown'>
<?php echo html::a('javascript:;', "<i class='icon icon-ellipsis-v'></i>", '', "data-toggle='dropdown' class='btn btn-link'");?>
<ul class='dropdown-menu <?php echo ($index + 1) % 4 == 0 ? 'pull-left' : 'pull-right';?>'>
<?php
if(common::hasPriv('kanban','edit'))
{
echo '<li>';
common::printLink('kanban', 'edit', "kanbanID={$kanban->id}", '<i class="icon icon-edit"></i> ' . $lang->kanban->edit, '', "class='iframe' data-width='75%'", '', true);
echo '</li>';
}
if(common::hasPriv('kanban','close'))
{
$class = $kanban->status == 'closed' ? 'disabled' : '';
echo "<li class='{$class}'>";
common::printLink('kanban', 'close', "kanbanID={$kanban->id}", '<i class="icon icon-off"></i> ' . $lang->kanban->close, '', "class='iframe {$class}' data-width='75%'", '', true);
echo '</li>';
}
if(common::hasPriv('kanban','delete'))
{
echo '<li>';
common::printLink('kanban', 'delete', "kanbanID={$kanban->id}", '<i class="icon icon-trash"></i> ' . $lang->kanban->delete, 'hiddenwin');
echo '</li>';
}
?>
</ul>
</div>
</div>
</div>
<div class="panel-body">
<div class="kanban-desc">
<?php echo $kanban->desc;?>
</div>
<div class="kanban-footer">
<div class='kanban-members pull-left'>
<?php $teams = explode(',', trim($kanban->team, ','));?>
<?php foreach($teams as $account):?>
<div title="<?php echo zget($users, $account);?>">
<?php echo html::smallAvatar(array('avatar' => zget($usersAvatar, $account), 'account' => $account)); ?>
</div>
<?php endforeach;?>
</div>
<div class='kanban-members-count pull-left'><?php echo sprintf($lang->project->teamSumCount, count($teams));?></div>
<div class='kanban-acl pull-right'>
<span><i class="icon icon-<?php echo $kanban->acl == 'private' ? 'lock' : 'unlock-alt';?>"></i> <?php echo zget($lang->project->acls, $kanban->acl, '');?></span>
</div>
</div>
</div>
</div>
</div>
<?php endforeach;?>
</div>
<?php endif;?>
</div>
<style>
.kanban-cards {padding-top: 12px; width: 100%;}
.kanban-card {width: 25%;}
.kanban-card .panel {margin: 0 0; border: 1px solid #DCDCDC; border-radius: 4px; box-shadow: none; cursor: pointer; height: 160px; margin-bottom: 5px;}
.kanban-card .panel:hover {border-color: #006AF1; box-shadow: 0 0 10px 0 rgba(0,0,100,.25);}
.kanban-card .panel:hover .kanban-actions {visibility: unset;}
.kanban-card .kanban-actions {position: absolute; top: 2px; right: 2px; float: right; visibility: hidden;}
.kanban-card .kanban-actions .dropdown-menu.pull-right {top:31px; right: -84px; left: auto;}
.kanban-card .kanban-actions .dropdown-menu.pull-left {top:31px; right:-1px; left: auto;}
.kanban-card .kanban-desc {color: #838a9d; word-break:break-all; height: 70px; overflow: hidden; display: -webkit-box; float:left;}
.kanban-card .kanban-footer {position: absolute; bottom: 10px; right: 10px; left: 15px;}
.kanban-card .kanban-members {float: left; height: 24px; line-height: 24px;}
.kanban-card .kanban-members > div {display: inline-block; height: 24px;}
.kanban-card .kanban-members > div + div {margin-left: -5px;}
.kanban-card .kanban-members > div > .avatar {display: inline-block; width: 24px; height: 24px; line-height: 24px; margin-right: 1px;}
.kanban-card .kanban-members > span {display: inline-block; color: transparent; width: 2px; height: 2px; background-color: #8990a2; position: relative; border-radius: 50%; top: 3px; margin: 0 3px;}
.kanban-card .kanban-members > span:before,
.kanban-card .kanban-members > span:after {content: ''; display: block; position: absolute; width: 2px; height: 2px; background-color: #8990a2; top: 0; border-radius: 50%}
.kanban-card .kanban-members > span:before {left: -4px;}
.kanban-card .kanban-members > span:after {right: -4px;}
.kanban-card .kanban-members-count {display: inline-block; margin-left: 6px; position: relative; top: 3px}
.kanban-card .kanban-acl {position: absolute; right: 0px; bottom: 2px; color: #838a9d;}
</style>
<script>
/* Make cards clickable. */
$('.kanban-cards').on('click', '.kanban-card', function(e)
{
if(!$(e.target).closest('.kanban-actions').length)
{
window.location.href = $(this).data('url');
}
});
</script>
<?php include $this->app->getModuleRoot() . '/common/view/footer.html.php';?>

View File

@@ -315,10 +315,11 @@ class router extends baseRouter
if($config->framework->extensionLevel >= 1)
{
if(!empty($extConfigPath['common'])) $commonExtConfigFiles = helper::ls($extConfigPath['common'], '.php');
if(!empty($extConfigPath['vision'])) $visionExtConfigFiles = array_merge($commonExtConfigFiles, helper::ls($extConfigPath['common'], '.php'));
if(!empty($extConfigPath['vision'])) $commonExtConfigFiles = array_merge($commonExtConfigFiles, helper::ls($extConfigPath['vision'], '.php'));
if(!empty($extConfigPath['custom'])) $commonExtConfigFiles = array_merge($commonExtConfigFiles, helper::ls($extConfigPath['custom'], '.php'));
}
if($config->framework->extensionLevel == 2 and !empty($extConfigPath['site'])) $siteExtConfigFiles = helper::ls($extConfigPath['site'], '.php');
$extConfigFiles = array_merge($commonExtConfigFiles, $visionExtConfigFiles, $siteExtConfigFiles);
$extConfigFiles = array_merge($commonExtConfigFiles, $siteExtConfigFiles);
/* 将主配置文件和扩展配置文件合并在一起。Put the main config file and extension config files together. */
$configFiles = array_merge(array($mainConfigFile), $extConfigFiles);

View File

@@ -60,10 +60,19 @@ if($this->loadModel('cron')->runable()) js::execute('startCron()');
if(isset($pageJS)) js::execute($pageJS); // load the js for current page.
/* Load hook files for current page. */
$extPath = $this->app->getModuleRoot() . '/common/ext/view/';
$extHookRule = $extPath . 'footer.*.hook.php';
$extHookFiles = glob($extHookRule);
if($extHookFiles) foreach($extHookFiles as $extHookFile) include $extHookFile;
$extensionRoot = $this->app->getExtensionRoot();
if($this->config->vision != 'open')
{
$extHookRule = $extensionRoot . $this->config->edition . '/common/ext/view/footer.*.hook.php';
$extHookFiles = glob($extHookRule);
if($extHookFiles) foreach($extHookFiles as $extHookFile) include $extHookFile;
}
if($this->config->vision == 'lite')
{
$extHookRule = $extensionRoot . $this->config->vision . '/common/ext/view/footer.*.hook.php';
$extHookFiles = glob($extHookRule);
if($extHookFiles) foreach($extHookFiles as $extHookFile) include $extHookFile;
}
?>
</body>
</html>

View File

@@ -64,10 +64,19 @@ $onlybody = zget($_GET, 'onlybody', 'no');
<![endif]-->
<?php
/* Load hook files for current page. */
$extPath = $this->app->getModuleRoot() . '/common/ext/view/';
$extHookRule = $extPath . 'header.*.hook.php';
$extHookFiles = glob($extHookRule);
if($extHookFiles) foreach($extHookFiles as $extHookFile) include $extHookFile;
$extensionRoot = $this->app->getExtensionRoot();
if($this->config->vision != 'open')
{
$extHookRule = $extensionRoot . $this->config->edition . '/common/ext/view/header.*.hook.php';
$extHookFiles = glob($extHookRule);
if($extHookFiles) foreach($extHookFiles as $extHookFile) include $extHookFile;
}
if($this->config->vision == 'lite')
{
$extHookRule = $extensionRoot . $this->config->vision . '/common/ext/view/header.*.hook.php';
$extHookFiles = glob($extHookRule);
if($extHookFiles) foreach($extHookFiles as $extHookFile) include $extHookFile;
}
?>
</head>
<?php $singleClass = $this->app->getViewType() == 'xhtml' ? 'allow-self-open' : '';?>

View File

@@ -971,38 +971,51 @@ class kanbanModel extends model
*/
public function getCanViewObjects($objectType = 'kanban')
{
$table = $this->config->objectTables[$objectType];
$objects = $this->dao->select('*')->from($table)->fetchAll('id');
$spaceList = $objectType == 'kanban' ? $this->dao->select('id,owner,team,whitelist')->from(TABLE_KANBANSPACE)->fetchAll('id') : array();
$table = $this->config->objectTables[$objectType];
$objects = $this->dao->select('*')->from($table)->fetchAll('id');
if($this->app->user->admin) return array_keys($objects);
$account = $this->app->user->account;
$spaceList = $objectType == 'kanban' ? $this->dao->select('id,owner,team,whitelist')->from(TABLE_KANBANSPACE)->fetchAll('id') : array();
$account = $this->app->user->account;
foreach($objects as $objectID => $object)
{
if($object->acl == 'private' or $object->acl == 'extend')
{
$remove = true;
if($object->owner == $account) $remove = false;
if(strpos(",{$object->team},", ",$account,") !== false) $remove = false;
if(strpos(",{$object->whitelist},", ",$account,") !== false) $remove = false;
if($objectType == 'kanban')
{
$spaceOwner = isset($spaceList[$object->space]->owner) ? $spaceList[$object->space]->owner : '';
$spaceTeam = isset($spaceList[$object->space]->team) ? trim($spaceList[$object->space]->team, ',') : '';
$spaceWhiteList = isset($spaceList[$object->space]->whitelist) ? trim($spaceList[$object->space]->whitelist, ',') : '';
if(strpos(",$spaceOwner,", ",$account,") !== false) $remove = false;
if(strpos(",$spaceTeam,", ",$account,") !== false and $object->acl == 'extend') $remove = false;
if(strpos(",$spaceWhiteList,", ",$account,") !== false and $object->acl == 'extend') $remove = false;
}
if($remove) unset($objects[$objectID]);
}
if(!$this->checkKanbanPriv($object, $objectType, $spaceList)) unset($objects[$objectID]);
}
return array_keys($objects);
}
/**
* Check kanban priv.
*
* @param object $object
* @param string $objectType
* @param array $spaceList
* @access public
* @return bool
*/
public function checkKanbanPriv($object, $objectType, $spaceList)
{
$account = $this->app->user->account;
if($object->acl == 'private' or $object->acl == 'extend')
{
if($object->owner == $account) return true;
if(strpos(",{$object->team},", ",$account,") !== false) return true;
if(strpos(",{$object->whitelist},", ",$account,") !== false) return true;
if($objectType == 'kanban')
{
$spaceOwner = isset($spaceList[$object->space]->owner) ? $spaceList[$object->space]->owner : '';
$spaceTeam = isset($spaceList[$object->space]->team) ? trim($spaceList[$object->space]->team, ',') : '';
$spaceWhiteList = isset($spaceList[$object->space]->whitelist) ? trim($spaceList[$object->space]->whitelist, ',') : '';
if(strpos(",$spaceOwner,", ",$account,") !== false) return true;
if(strpos(",$spaceTeam,", ",$account,") !== false and $object->acl == 'extend') return true;
if(strpos(",$spaceWhiteList,", ",$account,") !== false and $object->acl == 'extend') return true;
}
return false;
}
return true;
}
/**
* Create a space.
*
@@ -1211,7 +1224,6 @@ class kanbanModel extends model
}
}
$this->dao->insert(TABLE_KANBAN)->data($kanban)
->autoCheck()
->batchCheck($this->config->kanban->create->requiredFields, 'notempty')

View File

@@ -111,6 +111,7 @@ class project extends control
$projects = $this->dao->select('*')->from(TABLE_PROJECT)
->where('type')->eq('project')
->andWhere('deleted')->eq(0)
->andWhere('vision')->eq($this->config->vision)
->beginIF(!$this->app->user->admin)->andWhere('id')->in($this->app->user->view->projects)->fi()
->orderBy('order_asc')
->fetchAll('id');

View File

@@ -1845,6 +1845,7 @@ class projectModel extends model
->beginIF($status == 'undone')->andWhere('t1.status')->notIN('done,closed')->fi()
->beginIF($status != 'all' and $status != 'undone' and $status != 'involved')->andWhere('t1.status')->eq($status)->fi()
->beginIF(!$this->app->user->admin)->andWhere('t1.id')->in($this->app->user->view->sprints)->fi()
->andWhere('t1.vision')->eq($this->config->vision)
->andWhere('t1.deleted')->eq('0')
->orderBy($orderBy)
->page($pager)
@@ -1861,6 +1862,7 @@ class projectModel extends model
->beginIF($status != 'all' and $status != 'undone')->andWhere('t2.status')->eq($status)->fi()
->beginIF(!$this->app->user->admin)->andWhere('t2.id')->in($this->app->user->view->sprints)->fi()
->andWhere('t2.deleted')->eq('0')
->andWhere('t1.vision')->eq($this->config->vision)
->orderBy($orderBy)
->page($pager)
->fetchAll('id');

View File

@@ -92,7 +92,7 @@
$setting = $this->datatable->getSetting('project');
$fixedFieldsWidth = $this->datatable->setFixedFieldWidth($setting);
if($useDatatable) include '../../common/view/datatable.html.php';
if($useDatatable) include dirname(dirname(dirname(__FILE__))) . '/common/view/datatable.html.php';
?>
<?php if(!$useDatatable) echo '<div class="table-responsive">';?>
<table class='table has-sort-head <?php if($useDatatable) echo 'datatable';?>' data-fixed-left-width='<?php echo $fixedFieldsWidth['leftWidth']?>' data-fixed-right-width='<?php echo $fixedFieldsWidth['rightWidth']?>'>