* Finisht task #46666,#46668,#46659,#46658.
This commit is contained in:
@@ -155,7 +155,11 @@ $lang->kanban->error->mustBeInt = 'The WIPs must be positive integer.';
|
||||
$lang->kanban->error->parentLimitNote = 'The WIPs in the parent column cannot be < the sum of the WIPs in the child column.';
|
||||
$lang->kanban->error->childLimitNote = 'The sum of products in the child column cannot be > the number of products in the parent column.';
|
||||
|
||||
$lang->kanban->defaultColumn = array('wait', 'doing', 'done', 'close');
|
||||
$lang->kanban->defaultColumn = array();
|
||||
$lang->kanban->defaultColumn['wait'] = 'wait';
|
||||
$lang->kanban->defaultColumn['doing'] = 'doing';
|
||||
$lang->kanban->defaultColumn['done'] = 'done';
|
||||
$lang->kanban->defaultColumn['closed'] = 'close';
|
||||
|
||||
$this->lang->kanban->laneTypeList = array();
|
||||
$this->lang->kanban->laneTypeList['story'] = $lang->SRCommon;
|
||||
|
||||
@@ -155,7 +155,11 @@ $lang->kanban->error->mustBeInt = '在制品数量必须是正整数。';
|
||||
$lang->kanban->error->parentLimitNote = '父列的在制品数量不能小于子列在制品数量之和';
|
||||
$lang->kanban->error->childLimitNote = '子列在制品数量之和不能大于父列的在制品数量';
|
||||
|
||||
$lang->kanban->defaultColumn = array('未开始', '进行中', '已完成', '已关闭');
|
||||
$lang->kanban->defaultColumn = array();
|
||||
$lang->kanban->defaultColumn['wait'] = '未开始';
|
||||
$lang->kanban->defaultColumn['doing'] = '进行中';
|
||||
$lang->kanban->defaultColumn['done'] = '已完成';
|
||||
$lang->kanban->defaultColumn['closed'] = '已关闭';
|
||||
|
||||
$this->lang->kanban->laneTypeList = array();
|
||||
$this->lang->kanban->laneTypeList['story'] = $lang->SRCommon;
|
||||
|
||||
@@ -517,6 +517,85 @@ class kanbanModel extends model
|
||||
return $kanbanData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get plan kanban.
|
||||
*
|
||||
* @param object $product
|
||||
* @param int $branchID
|
||||
* @param string $orderBy
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getPlanKanban($product, $branchID = 0, $orderBy = 'id_desc')
|
||||
{
|
||||
$this->loadModel('branch');
|
||||
$this->loadModel('productplan');
|
||||
|
||||
$kanbanData = new stdclass();
|
||||
$lanes = array();
|
||||
$columns = array();
|
||||
$branches = array();
|
||||
$colorIndex = 0;
|
||||
$laneOrder = 1;
|
||||
$planGroup = $this->productplan->getGroupByProduct($product->id, 'skipParent', 'object');
|
||||
|
||||
if($product->type == 'normal' or $branchID == BRANCH_MAIN)
|
||||
{
|
||||
$branches = array(BRANCH_MAIN => $this->lang->branch->main);
|
||||
}
|
||||
elseif($branchID == 'all')
|
||||
{
|
||||
$branches = $this->branch->getPairs($product->id);
|
||||
}
|
||||
elseif($branchID)
|
||||
{
|
||||
$branchName = $this->branch->getById($branchID);
|
||||
$branches = array($branchID => $branchName);
|
||||
}
|
||||
|
||||
foreach($branches as $branchID => $branchName)
|
||||
{
|
||||
$plans = isset($planGroup[$product->id][$branchID]) ? array_filter($planGroup[$product->id][$branchID]) : array();
|
||||
$planList = array();
|
||||
|
||||
foreach($plans as $planID => $plan)
|
||||
{
|
||||
if(empty($plan)) continue;
|
||||
if(!isset($planList[$plan->status])) $planList[$plan->status] = array();
|
||||
$planList[$plan->status][] = $plan;
|
||||
}
|
||||
|
||||
$lane = new stdclass();
|
||||
$lane->id = $branchID;
|
||||
$lane->type = 'branch';
|
||||
$lane->name = $branchName;
|
||||
$lane->color = $this->config->productplan->laneColorList[$colorIndex];
|
||||
$lane->order = $laneOrder;
|
||||
$lane->items = $planList;
|
||||
|
||||
$lanes[] = $lane;
|
||||
$laneOrder += 1;
|
||||
$colorIndex += 1;
|
||||
if($colorIndex == count($this->config->productplan->laneColorList) + 1) $colorIndex = 0;
|
||||
}
|
||||
|
||||
foreach($this->lang->kanban->defaultColumn as $columnType => $columnName)
|
||||
{
|
||||
$column = new stdclass();
|
||||
$column->id = $columnType;
|
||||
$column->type = $columnType;
|
||||
$column->name = $columnName;
|
||||
|
||||
$columns[] = $column;
|
||||
}
|
||||
|
||||
$kanbanData->id = 'plans';
|
||||
$kanbanData->lanes = $lanes;
|
||||
$kanbanData->columns = $columns;
|
||||
|
||||
return $kanbanData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get region by id.
|
||||
*
|
||||
|
||||
@@ -8,3 +8,5 @@ $config->productplan->edit->requiredFields = 'title';
|
||||
$config->productplan->editor = new stdclass();
|
||||
$config->productplan->editor->create = array('id' => 'desc', 'tools' => 'simpleTools');
|
||||
$config->productplan->editor->edit = array('id' => 'desc', 'tools' => 'simpleTools');
|
||||
|
||||
$config->productplan->laneColorList = array('#32C5FF', '#006AF1', '#9D28B2', '#FF8F26', '#FFC20E', '#00A78E', '#7FBB00', '#424BAC', '#C0E9FF', '#EC2761');
|
||||
|
||||
@@ -236,8 +236,11 @@ class productplan extends control
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function browse($productID = 0, $branch = 0, $browseType = 'all', $orderBy = 'begin_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1 )
|
||||
public function browse($productID = 0, $branch = '', $browseType = 'all', $orderBy = 'begin_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1 )
|
||||
{
|
||||
$branchID = $branch === '' ? 'all' : $branch;
|
||||
if(!$branch) $branch = 0;
|
||||
|
||||
/* Load pager. */
|
||||
$this->app->loadClass('pager', $static = true);
|
||||
$pager = new pager($recTotal, $recPerPage, $pageID);
|
||||
@@ -251,9 +254,32 @@ class productplan extends control
|
||||
$this->commonAction($productID, $branch);
|
||||
$product = $this->product->getById($productID);
|
||||
$productName = empty($product) ? '' : $product->name;
|
||||
if($product->type != 'normal' and $viewType == 'bykanban')
|
||||
if($viewType == 'bykanban')
|
||||
{
|
||||
$this->view->branches = array('all' => $this->lang->productplan->allAB) + $this->loadModel('branch')->getPairs($productID);
|
||||
$branches = array();
|
||||
$branchPairs = array();
|
||||
$planCount = 0;
|
||||
if($product->type == 'normal')
|
||||
{
|
||||
$branches = array(BRANCH_MAIN => $this->lang->branch->main);
|
||||
}
|
||||
else
|
||||
{
|
||||
$branches = $this->branch->getPairs($product->id);
|
||||
}
|
||||
|
||||
$planGroup = $this->productplan->getGroupByProduct($product->id, 'skipParent', 'object');
|
||||
foreach($branches as $id => $name)
|
||||
{
|
||||
$plans = isset($planGroup[$product->id][$id]) ? array_filter($planGroup[$product->id][$id]) : array();
|
||||
$branchPairs[$id] = $name . ' ' . count($plans);
|
||||
$planCount += count($plans);
|
||||
}
|
||||
|
||||
$this->view->branches = array('all' => $this->lang->productplan->allAB . ' ' . $planCount) + $branchPairs;
|
||||
$this->view->branchID = $branchID;
|
||||
$this->view->planCount = $planCount;
|
||||
$this->view->kanbanData = $this->loadModel('kanban')->getPlanKanban($product, $branchID, $orderBy);
|
||||
}
|
||||
|
||||
$this->view->title = $productName . $this->lang->colon . $this->lang->productplan->browse;
|
||||
|
||||
@@ -43,6 +43,37 @@ $(function()
|
||||
$.cookie('viewType', viewType, {expires:config.cookieLife, path:config.webRoot});
|
||||
window.location.reload();
|
||||
});
|
||||
|
||||
$('#branch').change(function()
|
||||
{
|
||||
var branchID = $(this).val();
|
||||
var link = createLink('productplan', 'browse', "productID=" + productID + '&branch=' + branchID);
|
||||
location.href = link;
|
||||
});
|
||||
|
||||
if(viewType == 'bykanban')
|
||||
{
|
||||
$('#branch_chosen .chosen-single span').prepend('<i class="icon-delay"></i>');
|
||||
$('#kanban').kanban(
|
||||
{
|
||||
data: kanbanData,
|
||||
minColWidth: 290,
|
||||
maxColWidth: 290,
|
||||
itemRender: renderKanbanItem,
|
||||
virtualize: true,
|
||||
droppable:
|
||||
{
|
||||
target: findDropColumns,
|
||||
finish: handleFinishDrop,
|
||||
mouseButton: 'left'
|
||||
}
|
||||
});
|
||||
|
||||
$('#kanban').on('scroll', function()
|
||||
{
|
||||
$.zui.ContextMenu.hide();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on('click', 'td.content .more', function(e)
|
||||
@@ -64,6 +95,79 @@ $(document).on('click', 'td.content .more', function(e)
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* Find drop columns
|
||||
* @param {JQuery} $element Drag element
|
||||
* @param {JQuery} $root Dnd root element
|
||||
*/
|
||||
function findDropColumns($element, $root)
|
||||
{
|
||||
var $col = $element.closest('.kanban-col');
|
||||
var col = $col.data();
|
||||
var lane = $col.closest('.kanban-lane').data();
|
||||
var kanbanID = $root.data('id');
|
||||
var kanbanRules = window.kanbanDropRules ? window.kanbanDropRules[kanbanID] : null;
|
||||
|
||||
if(!kanbanRules) return $root.find('.kanban-lane[data-id="' + lane.id + '"] .kanban-lane-col:not([data-type="project"],[data-type="' + col.type + '"])');
|
||||
|
||||
var colRules = kanbanRules[col.type];
|
||||
var lane = $col.closest('.kanban-lane').data('lane');
|
||||
return $root.find('.kanban-lane-col').filter(function()
|
||||
{
|
||||
if(!colRules) return false;
|
||||
if(colRules === true) return true;
|
||||
|
||||
var $newCol = $(this);
|
||||
var newCol = $newCol.data();
|
||||
if(newCol.id === col.id) return false;
|
||||
|
||||
var $newLane = $newCol.closest('.kanban-lane');
|
||||
var newLane = $newLane.data('lane');
|
||||
return colRules.indexOf(newCol.type) > -1 && newLane.id === lane.id;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle finish drop task
|
||||
* @param {Object} event Event object
|
||||
* @returns {void}
|
||||
*/
|
||||
function handleFinishDrop(event)
|
||||
{
|
||||
var $card = $(event.element); // The drag card
|
||||
var $dragCol = $card.closest('.kanban-lane-col');
|
||||
var $dropCol = $(event.target);
|
||||
|
||||
/* Get d-n-d(drag and drop) infos 获取拖放操作相关信息 */
|
||||
var card = $card.data('item');
|
||||
var fromColType = $dragCol.data('type');
|
||||
var toColType = $dropCol.data('type');
|
||||
var kanbanID = $card.closest('.kanban').data('id');
|
||||
|
||||
changeCardColType(card, fromColType, toColType, kanbanID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change column type for a card
|
||||
|
||||
* @param {Object} card Card object
|
||||
* @param {String} fromColType The column type before change
|
||||
* @param {String} toColType The column type after change
|
||||
* @param {String} kanbanID Kanban ID
|
||||
*/
|
||||
function changeCardColType(card, fromColType, toColType, kanbanID)
|
||||
{
|
||||
if(typeof card == 'undefined') return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* The function for rendering kanban item
|
||||
*/
|
||||
function renderKanbanItem(item, $item)
|
||||
{
|
||||
var $title = $item.children('.title');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get planID
|
||||
*
|
||||
|
||||
@@ -283,14 +283,15 @@ class productplanModel extends model
|
||||
*
|
||||
* @param string|array $products
|
||||
* @param string $param skipParent|unexpired
|
||||
* @param string $returnType pairs|object
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getGroupByProduct($products = '', $param = '')
|
||||
public function getGroupByProduct($products = '', $param = '', $returnType = 'pairs')
|
||||
{
|
||||
$date = date('Y-m-d');
|
||||
$param = strtolower($param);
|
||||
$plans = $this->dao->select('id,title,parent,begin,end,product,branch')->from(TABLE_PRODUCTPLAN)
|
||||
$plans = $this->dao->select('*')->from(TABLE_PRODUCTPLAN)
|
||||
->where('deleted')->eq(0)
|
||||
->beginIF($products)->andWhere('product')->in($products)->fi()
|
||||
->beginIF(strpos($param, 'skipparent') !== false)->andWhere('parent')->ne(-1)->fi()
|
||||
@@ -298,7 +299,7 @@ class productplanModel extends model
|
||||
->orderBy('id_desc')
|
||||
->fetchAll('id');
|
||||
|
||||
if(!empty($plans)) $plans = $this->reorder4Children($plans);
|
||||
if(!empty($plans) and $returnType != 'object') $plans = $this->reorder4Children($plans);
|
||||
|
||||
$parentTitle = array();
|
||||
$planGroup = array();
|
||||
@@ -306,10 +307,17 @@ class productplanModel extends model
|
||||
{
|
||||
if(!isset($planGroup[$plan->product][$plan->branch])) $planGroup[$plan->product][$plan->branch] = array('' => '');
|
||||
|
||||
if($plan->parent == '-1') $parentTitle[$plan->id] = $plan->title;
|
||||
if($plan->parent > 0 and isset($parentTitle[$plan->parent])) $plan->title = $parentTitle[$plan->parent] . ' /' . $plan->title;
|
||||
$planGroup[$plan->product][$plan->branch][$plan->id] = $plan->title . " [{$plan->begin} ~ {$plan->end}]";
|
||||
if($plan->begin == '2030-01-01' and $plan->end == '2030-01-01') $planGroup[$plan->product][$plan->branch][$plan->id] = $plan->title . ' ' . $this->lang->productplan->future;
|
||||
if($returnType == 'object')
|
||||
{
|
||||
$planGroup[$plan->product][$plan->branch][$plan->id] = $plan;
|
||||
}
|
||||
else
|
||||
{
|
||||
if($plan->parent == '-1') $parentTitle[$plan->id] = $plan->title;
|
||||
if($plan->parent > 0 and isset($parentTitle[$plan->parent])) $plan->title = $parentTitle[$plan->parent] . ' /' . $plan->title;
|
||||
$planGroup[$plan->product][$plan->branch][$plan->id] = $plan->title . " [{$plan->begin} ~ {$plan->end}]";
|
||||
if($plan->begin == '2030-01-01' and $plan->end == '2030-01-01') $planGroup[$plan->product][$plan->branch][$plan->id] = $plan->title . ' ' . $this->lang->productplan->future;
|
||||
}
|
||||
}
|
||||
return $planGroup;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
<?php js::set('noLinkedProject', $lang->productplan->noLinkedProject);?>
|
||||
<?php js::set('enterProjectList', $lang->productplan->enterProjectList);?>
|
||||
<?php js::set('projectNotEmpty', $lang->productplan->projectNotEmpty)?>
|
||||
<?php js::set('viewType', $viewType);?>
|
||||
<?php
|
||||
if($viewType == 'bykanban')
|
||||
{
|
||||
|
||||
@@ -10,24 +10,28 @@
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
?>
|
||||
<?php include '../../common/view/kanban.html.php';?>
|
||||
<style>
|
||||
#allPlans {display: block; height: 25px; margin: 0 auto; text-align: center;}
|
||||
#allPlans > i, #allPlans > span {display: inline-block; vertical-align: middle; line-height: 25px;}
|
||||
#allPlans > i {color: #999;}
|
||||
#branchBox {width: 100px; border-radius: 4px;}
|
||||
#branchBox {width: 120px;}
|
||||
#branch_chosen .icon-delay {padding-right: 10px; font-size: 15px;}
|
||||
#kanbanContainer {padding-bottom: 0; margin-bottom: 0;}
|
||||
</style>
|
||||
<?php js::set('kanbanData', $kanbanData);?>
|
||||
<div id="mainMenu" class="clearfix">
|
||||
<div class="btn-toolbar pull-left">
|
||||
<?php if($product->type == 'normal'):?>
|
||||
<div id='allPlans'>
|
||||
<i class='icon icon-delay'></i>
|
||||
<span><?php echo $lang->productplan->all . ' ' . $pager->recTotal;?></span>
|
||||
<span><?php echo $lang->productplan->all . ' ' . $planCount;?></span>
|
||||
</div>
|
||||
<?php else:?>
|
||||
<div id='branchBox'>
|
||||
<?php echo html::select('branch', $branches, $branch, "class='form-control chosen control-branch'");?>
|
||||
<?php endif;?>
|
||||
<?php echo html::select('branch', $branches, $branchID, "class='form-control chosen control-branch'");?>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
<div class="btn-toolbar pull-right">
|
||||
<div class="btn-group panel-actions">
|
||||
@@ -39,3 +43,8 @@
|
||||
<?php endif;?>
|
||||
</div>
|
||||
</div>
|
||||
<div class='panel' id='kanbanContainer'>
|
||||
<div class='panel-body'>
|
||||
<div id='kanban'></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user