* Finish task #45827.

This commit is contained in:
孙广明
2021-12-10 14:00:22 +08:00
parent 1a2b990b6a
commit b9707ddb68
8 changed files with 240 additions and 13 deletions
+1
View File
@@ -5,6 +5,7 @@ $config->kanban = new stdclass();
$config->kanban->require = new stdclass();
$config->kanban->require->createregion = 'name';
$config->kanban->require->createlane = 'name';
$config->kanban->require->createcolumn = 'name';
$config->kanban->setwip = new stdclass();
$config->kanban->setlane = new stdclass();
+26
View File
@@ -218,6 +218,32 @@ class kanban extends control
$this->display();
}
/**
* Create a column for a kanban.
*
* @param int $columnID
* @param string $position left|right
* @access public
* @return void
*/
public function createColumn($columnID, $position = 'left')
{
$column = $this->kanban->getColumnByID($columnID);
if($_POST)
{
$order = $position == 'left' ? $column->order : $column->order + 1;
$this->kanban->createColumn($column->region, null, $order);
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => 'parent', 'callback' => 'closeModalAndUpdateKanban', 'callback_params' => $column->region));
}
$this->view->title = $this->lang->kanban->createColumn;
$this->view->column = $column;
$this->view->position = $position;
$this->display();
}
/**
* Set WIP.
+27
View File
@@ -0,0 +1,27 @@
$(document).ready(function()
{
$.setAjaxForm('#createColumnForm');
initColorPicker();
$(document).on('click', '#noLimit', function()
{
if($(this).prop('checked'))
{
$(this).parents('td').find('input[name^=limit]').val('');
$(this).parents('td').find('input[name^=limit]').attr('readonly', true);
}
else
{
$(this).parents('td').find('input[name^=limit]').removeAttr('readonly');
}
});
});
function setWIPLimit()
{
var count = $('#WIPCount').val();
if($('#noLimit').attr('checked') == 'checked') count = -1;;
$('#limit').val(count);
}
-2
View File
@@ -627,8 +627,6 @@ function createColumnMenu(options)
if(privs.includes('editColumn')) items.push({label: kanbanLang.editColumn, icon: 'edit', url: createLink('kanban', 'setColumn', 'columnID=' + column.id, '', 'true'), className: 'iframe', attrs: {'data-toggle': 'modal'}});
if(privs.includes('setWIP')) items.push({label: kanbanLang.setWIP, icon: 'alert', url: createLink('kanban', 'setWIP', 'columnID=' + column.id), className: 'iframe', attrs: {'data-toggle': 'modal', 'data-width' : '500px'}});
if(privs.includes('splitColumn')) items.push({label: kanbanLang.splitColumn, icon: 'col-split', url: createLink('kanban', 'splitColumn', 'columnID=' + column.id), className: 'iframe', attrs: {'data-toggle': 'modal'}});
if(privs.includes('setWIP')) items.push({label: kanbanLang.setWIP, icon: '', url: createLink('kanban', 'setWIP', 'columnID=' + column.id + '&executionID=0&from=kanban'), className: 'iframe', attrs: {'data-toggle': 'modal', 'data-width': '500px'}});
if(privs.includes('editColumn')) items.push({label: kanbanLang.editColumn, icon: '', url: createLink('kanban', 'setColumn', 'columnID=' + column.id + '&executionID=0&from=kanban', '', 'true'), className: 'iframe', attrs: {'data-toggle': 'modal'}});
if(privs.includes('createColumn'))
{
items.push({label: kanbanLang.createColumnOnLeft, icon: 'col-add-left', url: createLink('kanban', 'createColumn', 'columnID=' + column.id + '&position=left'), className: 'iframe', attrs: {'data-toggle': 'modal'}});
+4
View File
@@ -51,6 +51,9 @@ $lang->kanban->closedDate = '关闭日期';
$lang->kanban->empty = '暂时没有看板';
$lang->kanban->teamSumCount = '共%s人';
$lang->kanban->createColumnOnLeft = '在左侧添加看板列';
$lang->kanban->createColumnOnRight = '在右侧添加看板列';
$lang->kanban->aclList['open'] = '继承空间访问权限(能访问当前空间,即可访问)';
$lang->kanban->aclList['private'] = '私有(看板团队成员、白名单、空间负责人可访问)';
@@ -191,6 +194,7 @@ $lang->kanbanspace->featureBar['closed'] = '已关闭';
$lang->kanbancolumn = new stdclass();
$lang->kanbancolumn->name = $lang->kanban->columnName;
$lang->kanbancolumn->limit = $lang->kanban->WIPCount;
$lang->kanbancolumn->color = '看板列颜色';
$lang->kanbanlane = new stdclass();
$lang->kanbanlane->name = $lang->kanban->laneName;
+119 -7
View File
@@ -180,18 +180,104 @@ class kanbanModel extends model
$column->group = $groupID;
$column->name = $columnName;
$column->type = $index;
$column->order = $index;
$column->limit = -1;
$column->color = '#333';
$this->dao->insert(TABLE_KANBANCOLUMN)->data($column)->exec();
$this->saveOrder($regionID, 'region', $this->dao->lastInsertID(), 'column', '', $index);
$this->createColumn($regionID, $column);
$index ++;
//$this->saveOrder($regionID, 'region', $this->dao->lastInsertID(), 'column', '', $index);
}
return !dao::isError();
}
/**
* Create a column.
*
* @param int $regionID
* @param object $column
* @param int $order
* @access public
* @return int
*/
public function createColumn($regionID, $column = null, $order = 0)
{
if(empty($column))
{
$column = fixer::input('post')
->add('region', $regionID)
->setIF($order, 'order', $order)
->setDefault('color', '#272E33')
->get();
if(!$order)
{
$maxOrder = $this->dao->select('MAX(`order`) AS maxOrder')->from(TABLE_KANBANCOLUMN)
->where('`group`')->eq($column->group)
->fetch('maxOrder');
$column->order = $maxOrder + 1;
}
}
if(!$column->limit && empty($column->noLimit)) dao::$errors['limit'][] = sprintf($this->lang->error->notempty, $this->lang->kanban->WIP);
if(dao::isError()) return false;
$limit = (int)$column->limit;
if(!empty($column->parent))
{
/* Create a child column. */
$parentColumn = $this->getColumnByID($column->parent);
if($parentColumn->limit)
{
/* The WIP of the child column is infinite or greater than the WIP of the parent column. */
if(!$limit || $limit > $parentColumn->limit)
{
dao::$errors['limit'][] = $this->lang->kanban->error->parentLimitNote;
return false;
}
$childColumns = $this->getColumnsByParent($column->parent);
foreach($childColumns as $childColumn)
{
$limit += (int)$childColumn->limit;
if($limit > $parentColumn->limit)
{
/* The total WIP of the child columns is greater than the WIP of the parent column. */
dao::$errors['limit'][] = $this->lang->kanban->error->childLimitNote;
return false;
}
}
}
}
$column->limit = (int)$column->limit;
if($order)
{
/* It means copy a column or insert a column before or after a column. */
$this->dao->update(TABLE_KANBANCOLUMN)
->set('`order` = `order` + 1')
->where('`group`')->eq($column->group)
->andWhere('`order`')->ge($order)
->exec();
}
$this->dao->insert(TABLE_KANBANCOLUMN)->data($column, 'noLimit,position,copyItems')
->batchCheck($this->config->kanban->require->createcolumn, 'notempty')
->autoCheck()
->exec();
if(dao::isError()) return false;
$columnID = $this->dao->lastInsertID();
$maxType = $this->dao->select('type')->from(TABLE_KANBANCOLUMN)->where('`group`')->eq($column->group)->orderBy('type_desc')->limit(1)->fetch('type');
$this->dao->update(TABLE_KANBANCOLUMN)->set('type')->eq($maxType + 1)->where('id')->eq($columnID)->exec();
$this->loadModel('action')->create('kanbanColumn', $columnID, 'Created');
return $columnID;
}
/**
* Save kanban object order.
*
@@ -602,9 +688,17 @@ class kanbanModel extends model
{
if($object->acl == 'private')
{
$aclUsers = $object->owner . $object->team . $object->whitelist;
if($objectType == 'kanban') $aclUsers .= ',' . $spaceOwnerPairs[$object->space];
if(strpos(",$aclUsers,", ",$account,") === false) unset($objects[$objectID]);
$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')
{
$parentOwner = isset($spaceOwnerPairs[$object->space]) ? $spaceOwnerPairs[$object->space] : '';
if(strpos(",$parentOwner,", ",$account,") !== false) $remove = false;
}
if($remove) unset($objects[$objectID]);
}
}
@@ -1517,7 +1611,7 @@ class kanbanModel extends model
* @access public
* @return object
*/
public function getColumnById($columnID)
public function getColumnByID($columnID)
{
$column = $this->dao->select('t1.*, t2.type as laneType')->from(TABLE_KANBANCOLUMN)->alias('t1')
->leftjoin(TABLE_KANBANLANE)->alias('t2')->on('t1.lane=t2.id')
@@ -1547,6 +1641,24 @@ class kanbanModel extends model
->fetch();
}
/**
* Get child columns by parent id.
*
* @param int $parentID
* @param string $archived
* @param string $deleted
* @access public
* @return array
*/
public function getColumnsByParent($parentID, $archived = '0', $deleted = '0')
{
return $this->dao->select('*')->from(TABLE_KANBANCOLUMN)
->where('parent')->eq($parentID)
->andWhere('archived')->eq($archived)
->andWhere('deleted')->eq($deleted)
->orderBy('order')
->fetchAll('id');
}
/**
* Get lane by id.
+59
View File
@@ -0,0 +1,59 @@
<?php
/**
* The create lane view file of kanban module of ZentaoPMS.
*
* @copyright Copyright 2009-2020 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author Guangming Sun<sunguangming@easycorp.ltd>
* @package kanban
* @version $Id$
* @link https://www.zentao.net
*/
?>
<?php include '../../common/view/header.lite.html.php';?>
<div id='mainContent' class='main-content'>
<div class='center-block'>
<div class='main-header'>
<h2><?php echo $lang->kanban->createColumn;?></h2>
</div>
<form id='createColumnForm' method='post' class='form-ajax' action='<?php echo inlink('createColumn', "columnID=$column->id&position=$position");?>' onsubmit='return setWIPLimit();'>
<table class='table table-form'>
<tr>
<th class="w-120px"><?php echo $lang->kanbancolumn->name;?></th>
<td>
<div class='required required-wrapper'></div>
<?php echo html::input('name', '', "class='form-control'");?>
</td>
</tr>
<tr class='child-column'>
<th><?php echo $lang->kanban->WIPCount;?></th>
<td>
<div class='required required-wrapper'></div>
<div class='input-group'>
<?php echo html::number('limit', '', "min='1' class='form-control'" . ($column->limit ? '' : "readonly"));?>
<span class='input-group-addon'>
<label class='checkbox-inline'>
<input type='checkbox' name='noLimit' id='noLimit' value='-1' <?php if(!$column->limit) echo "checked";?>/> <?php echo $this->lang->kanban->noLimit;?>
</label>
</span>
</div>
</td>
</tr>
<tr>
<th><?php echo $lang->kanbancolumn->color;?></th>
<td><div id='color-picker'></div></td>
</tr>
<tr>
<td colspan='2' class='form-actions text-center'>
<?php echo html::hidden('color', '#272E33');?>
<?php echo html::hidden('group', $column->group);?>
<?php echo html::hidden('parent', $column->parent);?>
<?php echo html::submitButton();?>
<?php echo html::commonButton($lang->cancel, "data-dismiss='modal'", 'btn btn-wide');?>
</td>
</tr>
</table>
</form>
</div>
</div>
<?php include '../../common/view/footer.lite.html.php';?>
+4 -4
View File
@@ -29,11 +29,11 @@ $canCreateLane = commonModel::hasPriv('kanban', 'createLane');
<label class="label label-region"><?php echo $this->lang->kanbanlane->common . ' ' . $region->laneCount;?></label>
<i class="icon icon-double-angle-up"></i>
<?php if($canEditRegion || $canCreateLane || $canDeleteRegion):?>
<button class="btn btn-link action" type="button" data-toggle="dropdown"><i class="icon icon-more-v"></i></button>
<button class="btn btn-link action" type="button" data-toggle="dropdown"><i class="icon icon-ellipsis-v"></i></button>
<ul class="dropdown-menu pull-right">
<?php if($canEditRegion) echo '<li>' . html::a(inlink('editRegion', "regionID={$region->id}"), $this->lang->kanban->editRegion, "data-toggle='modal'") . '</li>';?>
<?php if($canCreateLane) echo '<li>' . html::a(inlink('createLane', "kanbanID={$project->id}&regionID={$region->id}"), $this->lang->kanban->createLane, "data-toggle='modal'") . '</li>';?>
<?php if($canDeleteRegion) echo '<li>' . html::a(inlink('deleteRegion', "regionID={$region->id}"), $this->lang->kanban->deleteRegion, "class='confirmer' data-confirmTitle='{$lang->kanbanregion->confirmDelete}' data-confirmDetail='{$lang->kanbanregion->confirmDeleteDetail}'") . '</li>';?>
<?php if($canEditRegion) echo '<li>' . html::a(inlink('editRegion', "regionID={$region->id}", '', 1), $this->lang->kanban->editRegion, '', 'class="iframe"') . '</li>';?>
<?php if($canCreateLane) echo '<li>' . html::a(inlink('createLane', "kanbanID={$kanban->id}&regionID={$region->id}", '', 1), $this->lang->kanban->createLane, '', "class='iframe'") . '</li>';?>
<?php if($canDeleteRegion) echo '<li>' . html::a(inlink('deleteRegion', "regionID={$region->id}"), $this->lang->kanban->deleteRegion, "hiddenwin") . '</li>';?>
</ul>
<?php endif;?>
</div>