type == 'normal'):?>
- productplan->all . ' ' . $pager->recTotal;?>
+ productplan->all . ' ' . $planCount;?>
-
-
+
+
@@ -39,3 +43,8 @@
+
+
+
+diff --git a/module/kanban/lang/en.php b/module/kanban/lang/en.php index 6285c4fd03..7ba2b2d2c4 100644 --- a/module/kanban/lang/en.php +++ b/module/kanban/lang/en.php @@ -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; diff --git a/module/kanban/lang/zh-cn.php b/module/kanban/lang/zh-cn.php index bc6ee4b541..62a58dec97 100644 --- a/module/kanban/lang/zh-cn.php +++ b/module/kanban/lang/zh-cn.php @@ -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; diff --git a/module/kanban/model.php b/module/kanban/model.php index 82bd9d5bb8..1aa3ed408a 100644 --- a/module/kanban/model.php +++ b/module/kanban/model.php @@ -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. * diff --git a/module/productplan/config.php b/module/productplan/config.php index 534647eb7c..95793d300b 100644 --- a/module/productplan/config.php +++ b/module/productplan/config.php @@ -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'); diff --git a/module/productplan/control.php b/module/productplan/control.php index cfb3c5cdf7..94d6363a00 100644 --- a/module/productplan/control.php +++ b/module/productplan/control.php @@ -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; diff --git a/module/productplan/js/browse.js b/module/productplan/js/browse.js index 6314c2087e..5a4cc7a73a 100644 --- a/module/productplan/js/browse.js +++ b/module/productplan/js/browse.js @@ -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(''); + $('#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 * diff --git a/module/productplan/model.php b/module/productplan/model.php index 6b785c3e2a..f6cf6ef2fc 100644 --- a/module/productplan/model.php +++ b/module/productplan/model.php @@ -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; } diff --git a/module/productplan/view/browse.html.php b/module/productplan/view/browse.html.php index 1e64745b5d..30ed8d250b 100644 --- a/module/productplan/view/browse.html.php +++ b/module/productplan/view/browse.html.php @@ -17,6 +17,7 @@ productplan->noLinkedProject);?> productplan->enterProjectList);?> productplan->projectNotEmpty)?> + + +