* Finish task #58288.

This commit is contained in:
liumengyi
2022-06-22 15:23:38 +08:00
parent 1e7ec30f10
commit 8f0073050f
11 changed files with 212 additions and 50 deletions
+3 -12
View File
@@ -628,7 +628,6 @@ $lang->resource->kanban->close = 'close';
$lang->resource->kanban->delete = 'delete';
$lang->resource->kanban->createRegion = 'createRegion';
$lang->resource->kanban->editRegion = 'editRegion';
$lang->resource->kanban->performable = 'performable';
$lang->resource->kanban->sortRegion = 'sortRegion';
$lang->resource->kanban->sortGroup = 'sortGroup';
$lang->resource->kanban->deleteRegion = 'deleteRegion';
@@ -659,11 +658,7 @@ $lang->resource->kanban->laneMove = 'laneMove';
$lang->resource->kanban->viewArchivedColumn = 'viewArchivedColumn';
$lang->resource->kanban->viewArchivedCard = 'viewArchivedCard';
$lang->resource->kanban->restoreCard = 'restoreCard';
$lang->resource->kanban->setLaneHeight = 'setLaneHeight';
$lang->resource->kanban->setColumnWidth = 'setColumnWidth';
$lang->resource->kanban->batchCreateCard = 'batchCreateCard';
$lang->resource->kanban->import = 'import';
$lang->resource->kanban->enableArchived = 'enableArchived';
$lang->kanban->methodOrder[5] = 'space';
$lang->kanban->methodOrder[10] = 'createSpace';
@@ -708,13 +703,9 @@ $lang->kanban->methodOrder[195] = 'viewArchivedColumn';
$lang->kanban->methodorder[200] = 'viewArchivedCard';
$lang->kanban->methodorder[205] = 'archiveColumn';
$lang->kanban->methodorder[210] = 'restoreCard';
$lang->kanban->methodorder[215] = 'setLaneHeight';
$lang->kanban->methodorder[220] = 'setColumnWidth';
$lang->kanban->methodOrder[225] = 'batchCreateCard';
$lang->kanban->methodorder[230] = 'import';
$lang->kanban->methodorder[235] = 'enableArchived';
$lang->kanban->methodorder[240] = 'activate';
$lang->kanban->methodorder[245] = 'activateSpace';
$lang->kanban->methodOrder[215] = 'batchCreateCard';
$lang->kanban->methodorder[220] = 'activate';
$lang->kanban->methodorder[225] = 'activateSpace';
/* Execution. */
$lang->resource->execution = new stdclass();
+6
View File
@@ -269,6 +269,12 @@ class kanban extends control
$this->view->kanban = $kanban;
$this->view->type = $space->type;
$this->view->laneCount = $this->kanban->getLaneCount($kanbanID);
$this->view->heightType = $kanban->displayCards > 2 ? 'custom' : 'auto';
$this->view->displayCards = $kanban->displayCards ? $kanban->displayCards : '';
$this->view->enableImport = empty($kanban->object) ? 'off' : 'on';
$this->view->importObjects = empty($kanban->object) ? array() : explode(',', $kanban->object);
$this->display();
}
+5
View File
@@ -1 +1,6 @@
#mainContent {padding-left: 0px;}
#mainContent .laneHeightBox, #mainContent .importBox {display: grid;}
#mainContent .laneHeightBox .radio-inline+.radio-inline, #mainContent .importBox .radio-inline+.radio-inline {margin-left: 0px; padding-top: 5px;}
#mainContent .objectBox {padding-top: 2px;}
#mainContent .objectBox .checkbox-primary {display: inline-block;}
#mainContent .objectBox .checkbox-primary:not(:first-child) {margin-left: 10px;}
+5
View File
@@ -1 +1,6 @@
#mainContent {padding-left: 0px;}
#mainContent .laneHeightBox, #mainContent .importBox {display: grid;}
#mainContent .laneHeightBox .radio-inline+.radio-inline, #mainContent .importBox .radio-inline+.radio-inline {margin-left: 0px; padding-top: 5px;}
#mainContent .objectBox {padding-top: 2px;}
#mainContent .objectBox .checkbox-primary {display: inline-block;}
#mainContent .objectBox .checkbox-primary:not(:first-child) {margin-left: 10px;}
+34 -1
View File
@@ -1,3 +1,37 @@
$(function()
{
if(enableImport == 'off') $("input[name^='importObjectList']").attr('disabled', 'disabled');
$("input[name='import']").change(function()
{
if($(this).val() == 'off')
{
$("input[name^='importObjectList']").attr('disabled', 'disabled');
}
else
{
$("input[name^='importObjectList']").removeAttr('disabled');
}
})
$("input[name^='importObjectList']").change(function()
{
if($("input:checked[name^=importObjectList]").length != 0 && !$('#emptyTip').is('.hidden')) $('#emptyTip').addClass('hidden');
})
$('#submit').click(function()
{
var enableImport = $("input:checked[name='import']").val();
var objectListLength = $("input:checked[name^=importObjectList]").length;
if(enableImport == 'on' && objectListLength == 0 && vision != 'lite')
{
$('#emptyTip').removeClass('hidden');
return false;
}
})
})
/**
* When space type or space value change.
*
@@ -11,4 +45,3 @@ function changeValue(spaceID, type)
if(typeof type === 'undefined') type = spaceType;
location.href = createLink('kanban', 'create', 'spaceID=' + spaceID + '&type=' + type);
}
+48
View File
@@ -0,0 +1,48 @@
$(function()
{
var heightType = $("[name='heightType']:checked").val();
setCardCount(heightType);
if(enableImport == 'off') $("input[name^='importObjectList']").attr('disabled', 'disabled');
$("input[name='import']").change(function()
{
if($(this).val() == 'off')
{
$("input[name^='importObjectList']").attr('disabled', 'disabled');
}
else
{
$("input[name^='importObjectList']").removeAttr('disabled');
}
})
$("input[name^='importObjectList']").change(function()
{
if($("input:checked[name^=importObjectList]").length != 0 && !$('#emptyTip').is('.hidden')) $('#emptyTip').addClass('hidden');
})
$('#submit').click(function()
{
var enableImport = $("input:checked[name='import']").val();
var objectListLength = $("input:checked[name^=importObjectList]").length;
if(enableImport == 'on' && objectListLength == 0 && vision != 'lite')
{
$('#emptyTip').removeClass('hidden');
return false;
}
})
})
/**
* Set card count.
*
* @param string $heightType
* @access public
* @return void
*/
function setCardCount(heightType)
{
heightType != 'custom' ? $('#cardBox').addClass('hidden') : $('#cardBox').removeClass('hidden');
}
+5 -5
View File
@@ -1128,7 +1128,7 @@ function createCardMenu(options)
var items = [];
if(privs.includes('editCard') && card.fromType == '') items.push({label: kanbanLang.editCard, icon: 'edit', url: createLink('kanban', 'editCard', 'cardID=' + card.id, '', 'true'), className: 'iframe', attrs: {'data-toggle': 'modal', 'data-width': '80%'}});
if(privs.includes('deleteCard')) items.push({label: card.fromType == '' ? kanbanLang.deleteCard : kanbanLang.removeCard, icon: card.fromType == '' ? 'trash' : 'unlink', url: createLink('kanban', 'deleteCard', 'cardID=' + card.id), attrs: {'target': 'hiddenwin'}});
if(privs.includes('performable') && kanban.performable == 1)
if(kanban.performable == 1)
{
if(card.status == 'done')
{
@@ -1145,7 +1145,7 @@ function createCardMenu(options)
var deleteCardAction = privs.includes('deleteCard');
var archiveCardAction = (privs.includes('archiveCard') && kanban.archived == '1') ? true : false;
var performable = (privs.includes('performable') && kanban.performable == 1) ? true : false;
var performable = kanban.performable == 1 ? true : false;
var moveCardAction = privs.includes('moveCard');
var setCardColorAction = privs.includes('setCardColor');
@@ -1257,9 +1257,9 @@ function createColumnCreateMenu(options)
if(privs.includes('createCard')) items.push({label: kanbanLang.createCard, url: $.createLink('kanban', 'createCard', 'kanbanID=' + kanbanID + '&regionID=' + regionID + '&groupID=' + groupID + '&columnID=' + columnID, '', true), className: 'iframe', attrs: {'data-toggle': 'modal'}});
if(privs.includes('batchCreateCard')) items.push({label: kanbanLang.batchCreateCard, url: $.createLink('kanban', 'batchCreateCard', 'kanbanID=' + kanbanID + '&regionID=' + regionID + '&groupID=' + groupID + '&laneID=' + laneID + '&columnID=' + columnID), attrs: {'data-width': '80%'}});
if(privs.includes('import') && kanban.object.indexOf('cards') != -1) items.push({label: kanbanLang.importCard, url: $.createLink('kanban', 'importCard', 'kanbanID=' + kanbanID + '&regionID=' + regionID + '&groupID=' + groupID + '&columnID=' + columnID), className: 'iframe', attrs: {'data-toggle': 'modal'}});
if(privs.includes('import') && kanban.object && kanban.object != 'cards' && vision != 'lite') items.push({className: 'parentDivider'});
if(privs.includes('import') && kanban.object && kanban.object != 'cards' && vision != 'lite') items.push({label: kanbanLang.importAB, className: 'import'});
if(kanban.object.indexOf('cards') != -1) items.push({label: kanbanLang.importCard, url: $.createLink('kanban', 'importCard', 'kanbanID=' + kanbanID + '&regionID=' + regionID + '&groupID=' + groupID + '&columnID=' + columnID), className: 'iframe', attrs: {'data-toggle': 'modal'}});
if(kanban.object && kanban.object != 'cards' && vision != 'lite') items.push({className: 'parentDivider'});
if(kanban.object && kanban.object != 'cards' && vision != 'lite') items.push({label: kanbanLang.importAB, className: 'import'});
return items;
}
+1 -1
View File
@@ -8,7 +8,7 @@ $lang->kanban->closeSpace = '关闭空间';
$lang->kanban->deleteSpace = '删除空间';
$lang->kanban->activateSpace = '激活空间';
$lang->kanban->sortSpace = '空间排序';
$lang->kanban->edit = '设置看板';
$lang->kanban->edit = '编辑看板';
$lang->kanban->view = '查看看板';
$lang->kanban->activate = '激活看板';
$lang->kanban->close = '关闭看板';
+45 -31
View File
@@ -1008,7 +1008,7 @@ class kanbanModel extends model
->orderBy($order)
->fetchGroup('group');
$actions = array('createColumn', 'setColumn', 'setWIP', 'archiveColumn', 'restoreColumn', 'deleteColumn', 'createCard', 'batchCreateCard', 'splitColumn', 'import', 'sortColumn');
$actions = array('createColumn', 'setColumn', 'setWIP', 'archiveColumn', 'restoreColumn', 'deleteColumn', 'createCard', 'batchCreateCard', 'splitColumn', 'sortColumn');
/* Group by parent. */
$parentColumnGroup = array();
@@ -1081,7 +1081,7 @@ class kanbanModel extends model
->andWhere('type')->eq('common')
->fetchAll();
$actions = array('editCard', 'performable', 'archiveCard', 'deleteCard', 'moveCard', 'setCardColor', 'viewCard', 'sortCard', 'viewExecution', 'viewPlan', 'viewRelease', 'viewBuild');
$actions = array('editCard', 'archiveCard', 'deleteCard', 'moveCard', 'setCardColor', 'viewCard', 'sortCard', 'viewExecution', 'viewPlan', 'viewRelease', 'viewBuild');
$cardGroup = array();
foreach($cellList as $cell)
{
@@ -2064,15 +2064,19 @@ class kanbanModel extends model
$kanban = fixer::input('post')
->setDefault('createdBy', $account)
->setDefault('createdDate', helper::now())
->setdefault('owner', '')
->setdefault('team', '')
->setdefault('whitelist', '')
->setDefault('owner', '')
->setDefault('team', '')
->setDefault('whitelist', '')
->setDefault('displayCards', 0)
->setIF($this->post->import == 'off', 'object', '')
->join('whitelist', ',')
->join('team', ',')
->trim('name')
->remove('uid,contactListMenu,type')
->remove('uid,contactListMenu,type,import,importObjectList')
->get();
if($this->post->import == 'on') $kanban->object = implode(',', $this->post->importObjectList);
if(strpos(",{$kanban->team},", ",$account,") === false) $kanban->team .= ",$account";
if(strpos(",{$kanban->team},", ",$kanban->owner,") === false) $kanban->team .= ",$kanban->owner";
@@ -2121,12 +2125,25 @@ class kanbanModel extends model
$kanban = fixer::input('post')
->setDefault('lastEditedBy', $account)
->setDefault('lastEditedDate', helper::now())
->setDefault('displayCards', 0)
->setIF($this->post->import == 'off', 'object', '')
->join('whitelist', ',')
->join('team', ',')
->trim('name')
->remove('uid,contactListMenu')
->remove('uid,contactListMenu,import,importObjectList,heightType')
->get();
if($this->post->import == 'on') $kanban->object = implode(',', $this->post->importObjectList);
if(isset($_POST['heightType']) and $this->post->heightType == 'custom')
{
if(!preg_match("/^-?\d+$/", $kanban->displayCards) or $kanban->displayCards < 3)
{
dao::$errors['displayCards'] = $this->lang->kanbanlane->error->mustBeInt;
return false;
}
}
$this->dao->update(TABLE_KANBAN)->data($kanban)
->autoCheck()
->batchCheck($this->config->kanban->edit->requiredFields, 'notempty')
@@ -3053,26 +3070,12 @@ class kanbanModel extends model
$btnColor = '';
if($this->app->cookie->theme == 'blue') $btnColor = 'style="color:#000000"';
$printSetHeightBtn = false;
if(common::hasPriv('kanban', 'setLaneHeight'))
{
$laneCount = $this->dao->select('COUNT(t2.id) as count')->from(TABLE_KANBANREGION)->alias('t1')
->leftJoin(TABLE_KANBANLANE)->alias('t2')->on('t1.id=t2.region')
->where('t1.kanban')->eq($kanban->id)
->andWhere('t1.deleted')->eq(0)
->andWhere('t2.deleted')->eq(0)
->andWhere('t2.type')->eq('common')
->fetch('count');
if($laneCount > 1) $printSetHeightBtn = true;
}
$actions = '';
$actions .= "<div class='btn-group'>";
$actions .= "<a href='javascript:fullScreen();' id='fullScreenBtn' $btnColor class='btn btn-link'><i class='icon icon-fullscreen'></i> {$this->lang->kanban->fullScreen}</a>";
$CRKanban = !(isset($this->config->CRKanban) and $this->config->CRKanban == '0' and $kanban->status == 'closed');
$printRegionBtn = ($CRKanban and (common::hasPriv('kanban', 'createRegion') or $printSetHeightBtn or common::hasPriv('kanban', 'performable') or common::hasPriv('kanban', 'enableArchived') or common::hasPriv('kanban', 'import') or common::hasPriv('kanban', 'setColumnWidth')));
$printRegionBtn = ($CRKanban and (common::hasPriv('kanban', 'createRegion')));
$printKanbanBtn = (common::hasPriv('kanban', 'edit') or ($kanban->status == 'active' and common::hasPriv('kanban', 'close')) or common::hasPriv('kanban', 'delete') or ($kanban->status == 'closed' and common::hasPriv('kanban', 'activate')));
if($printRegionBtn or $printKanbanBtn)
@@ -3081,20 +3084,11 @@ class kanbanModel extends model
$actions .= "<ul id='kanbanActionMenu' class='dropdown-menu text-left'>";
$columnActions = '';
if(common::hasPriv('kanban', 'setColumnWidth') and $CRKanban) $columnActions .= '<li>' . html::a(helper::createLink('kanban', 'setColumnWidth', "kanbanID=$kanban->id", '', true), '<i class="icon icon-size-width"></i>' . $this->lang->kanban->columnWidth, '', "class='iframe btn btn-link' data-width=400") . '</li>';
if($printSetHeightBtn and $CRKanban)
{
$width = $this->app->getClientLang() == 'en' ? '920' : '770';
$columnActions .= '<li>' . html::a(helper::createLink('kanban', 'setLaneHeight', "kanbanID=$kanban->id", '', true), '<i class="icon icon-size-height"></i>' . $this->lang->kanban->laneHeight, '', "class='iframe btn btn-link' data-width='$width'") . '</li>';
}
$actions .= $columnActions;
$commonActions = '';
if(common::hasPriv('kanban', 'createRegion') and $CRKanban) $commonActions .= '<li>' . html::a(helper::createLink('kanban', 'createRegion', "kanbanID=$kanban->id", '', true), '<i class="icon icon-plus"></i>' . $this->lang->kanban->createRegion, '', "class='iframe btn btn-link'") . '</li>';
$importWidth = $this->app->getClientLang() == 'en' ? '700' : '550';
if(common::hasPriv('kanban', 'import') and $CRKanban) $commonActions .= '<li>' . html::a(helper::createLink('kanban', 'import', "kanbanID=$kanban->id", '', true), '<i class="icon icon-import"></i>' . $this->lang->kanban->import, '', "class='iframe btn btn-link' data-width=$importWidth") . '</li>';
if(common::hasPriv('kanban', 'enableArchived') and $CRKanban) $commonActions .= '<li>' . html::a(helper::createLink('kanban', 'enableArchived', "kanbanID=$kanban->id", '', true), '<i class="icon icon-card-archive"></i>' . $this->lang->kanban->archived, '', "class='iframe btn btn-link' data-width=400") . '</li>';
if(common::hasPriv('kanban', 'performable') and $CRKanban) $commonActions .= '<li>' . html::a(helper::createLink('kanban', 'performable', "kanbanID=$kanban->id", '', true), '<i class="icon icon-checked"></i>' . $this->lang->kanban->manageProgress, '', "class='iframe btn btn-link' data-width=40%") . '</li>';
if($columnActions and $commonActions)
{
@@ -3858,4 +3852,24 @@ class kanbanModel extends model
$this->dao->update(TABLE_KANBAN)->set('object')->eq($importObjectList)->where('id')->eq($kanbanID)->exec();
}
/**
* Get kanban lane count.
*
* @param int $kanbanID
* @param string $type
* @access public
* @return int
*/
public function getLaneCount($kanbanID, $type = 'common')
{
return $this->dao->select('COUNT(t2.id) as count')->from(TABLE_KANBANREGION)->alias('t1')
->leftJoin(TABLE_KANBANLANE)->alias('t2')->on('t1.id=t2.region')
->where('t1.kanban')->eq($kanbanID)
->andWhere('t1.deleted')->eq(0)
->andWhere('t2.deleted')->eq(0)
->beginIF($type == 'common')->andWhere('t2.type')->eq('common')->fi()
->beginIF($type != 'common')->andWhere('t2.type')->ne('common')->fi()
->fetch('count');
}
}
+27
View File
@@ -13,6 +13,9 @@
<?php include '../../common/view/header.html.php';?>
<?php include '../../common/view/kindeditor.html.php';?>
<?php js::set('spaceType', $type);?>
<?php js::set('enableImport', 'off');?>
<?php js::set('vision', $this->config->vision);?>
<?php $width = $this->app->getClientLang() == 'en' ? 'w-120px' : 'w-80px';?>
<div id='mainContent' class='main-content'>
<div class='main-header'>
<h2><?php echo $lang->kanban->create;?></h2>
@@ -47,6 +50,30 @@
</td>
</tr>
<?php endif;?>
<tr>
<th class='<?php echo $width;?>'><?php echo $lang->kanban->columnWidth;?></th>
<td><?php echo nl2br(html::radio('fluidBoard', $lang->kanbancolumn->fluidBoardList, 0));?></td>
</tr>
<tr class="hidden" id='cardBox'>
<th class='c-count'><?php echo $lang->kanban->cardCount;?></th>
<td><?php echo html::input('displayCards', '', "class='form-control' required placeholder='{$lang->kanban->cardCountTip}' autocomplete='off'");?></td>
</tr>
<tr>
<th rowspan='2'><?php echo $lang->kanban->import?></th>
<td class='importBox'><?php echo nl2br(html::radio('import', $lang->kanban->importList, 'off'));?></td>
</tr>
<tr>
<td class='objectBox'><?php echo html::checkbox('importObjectList', $lang->kanban->importObjectList, array());?></td>
</tr>
<tr id='emptyTip' class='hidden'><th></th><td colspan='2' style='color: red;'><?php echo $lang->kanban->error->importObjNotEmpty;?></td></tr>
<tr>
<th class='w-90px'><?php echo $lang->kanban->archive;?></th>
<td><?php echo nl2br(html::radio('archived', $lang->kanban->archiveList, '0'));?></td>
</tr>
<tr>
<th id='c-title'><?php echo $lang->kanban->manageProgress;?></th>
<td><?php echo nl2br(html::radio('performable', $lang->kanban->enableList, '0'));?></td>
</tr>
<tr>
<th><?php echo $lang->kanban->desc;?></th>
<td colspan='2'>
+33
View File
@@ -12,6 +12,9 @@
?>
<?php include '../../common/view/header.html.php';?>
<?php include '../../common/view/kindeditor.html.php';?>
<?php js::set('enableImport', $enableImport);?>
<?php js::set('vision', $this->config->vision);?>
<?php $width = $this->app->getClientLang() == 'en' ? 'w-120px' : 'w-80px';?>
<div id='mainContent' class='main-content'>
<div class='main-header'>
<h2><?php echo $lang->kanban->edit;?></h2>
@@ -40,6 +43,36 @@
</td>
</tr>
<?php endif;?>
<tr>
<th class='<?php echo $width;?>'><?php echo $lang->kanban->columnWidth;?></th>
<td><?php echo nl2br(html::radio('fluidBoard', $lang->kanbancolumn->fluidBoardList, $kanban->fluidBoard));?></td>
</tr>
<?php if($laneCount > 1):?>
<tr>
<th id='c-name'><?php echo $lang->kanban->laneHeight;?></th>
<td class='laneHeightBox'><?php echo nl2br(html::radio('heightType', $lang->kanbanlane->heightTypeList, $heightType, "onclick='setCardCount(this.value);'"));?></td>
</tr>
<tr class="hidden" id='cardBox'>
<th class='c-count'><?php echo $lang->kanban->cardCount;?></th>
<td><?php echo html::input('displayCards', $displayCards, "class='form-control' required placeholder='{$lang->kanban->cardCountTip}' autocomplete='off'");?></td>
</tr>
<?php endif;?>
<tr>
<th rowspan='2'><?php echo $lang->kanban->import?></th>
<td class='importBox'><?php echo nl2br(html::radio('import', $lang->kanban->importList, $enableImport));?></td>
</tr>
<tr>
<td class='objectBox'><?php echo html::checkbox('importObjectList', $lang->kanban->importObjectList, $importObjects);?></td>
</tr>
<tr id='emptyTip' class='hidden'><th></th><td colspan='2' style='color: red;'><?php echo $lang->kanban->error->importObjNotEmpty;?></td></tr>
<tr>
<th class='w-90px'><?php echo $lang->kanban->archive;?></th>
<td><?php echo nl2br(html::radio('archived', $lang->kanban->archiveList, $kanban->archived));?></td>
</tr>
<tr>
<th id='c-title'><?php echo $lang->kanban->manageProgress;?></th>
<td><?php echo nl2br(html::radio('performable', $lang->kanban->enableList, $kanban->performable));?></td>
</tr>
<tr>
<th><?php echo $lang->kanban->desc;?></th>
<td colspan='2'>