Merge branch 'master' into 'sprint/181_zhengrunyu_fixbug'
# Conflicts: # module/productplan/model.php
This commit is contained in:
@@ -707,6 +707,10 @@ class actionModel extends model
|
||||
{
|
||||
$desc = $this->lang->$objectType->action->rejectreviewed;
|
||||
}
|
||||
elseif($action->objectType == 'productplan' and in_array($action->action, array('startedbychild','finishedbychild','closedbychild','activatedbychild')))
|
||||
{
|
||||
$desc = $this->lang->$objectType->action->changebychild;
|
||||
}
|
||||
elseif(isset($this->config->maxVersion) and strpos($this->config->action->assetType, $action->objectType) !== false and $action->action == 'approved')
|
||||
{
|
||||
$desc = empty($this->lang->action->approve->{$action->extra}) ? '' : $this->lang->action->approve->{$action->extra};
|
||||
|
||||
@@ -49,7 +49,7 @@ $sessionString .= session_name() . '=' . session_id();
|
||||
if($canImportToPracticeLib or $canImportToComponentLib)
|
||||
{
|
||||
echo "<div class='btn-group' id='more'>";
|
||||
echo html::a('javascript:;', "<i class='icon icon-ellipsis-v'></i>", '', "data-toggle='dropdown' class='btn btn-link'");
|
||||
echo html::a('javascript:;', "<i class='icon icon-diamond'></i>", '', "data-toggle='dropdown' class='btn btn-link'");
|
||||
echo "<ul class='dropdown-menu pull-right'>";
|
||||
if($canImportToPracticeLib) echo '<li>' . html::a('#importToPracticeLib', $lang->doc->importToPracticeLib, '', 'data-toggle="modal"') . '</li>';
|
||||
if($canImportToComponentLib) echo '<li>' . html::a('#importToComponentLib', $lang->doc->importToComponentLib, '', 'data-toggle="modal"') . '</li>';
|
||||
|
||||
@@ -537,7 +537,7 @@ class kanbanModel extends model
|
||||
$branches = array();
|
||||
$colorIndex = 0;
|
||||
$laneOrder = 1;
|
||||
$cardActions = array('view');
|
||||
$cardActions = array('view', 'createExecution', 'linkStory', 'linkBug', 'edit', 'start', 'finish', 'close', 'activate', 'delete');
|
||||
|
||||
if($product->type == 'normal')
|
||||
{
|
||||
@@ -573,7 +573,12 @@ class kanbanModel extends model
|
||||
$plan->actions = array();
|
||||
foreach($cardActions as $action)
|
||||
{
|
||||
if(common::hasPriv('productplan', $action)) $plan->actions[] = $action;
|
||||
if($action == 'createExecution')
|
||||
{
|
||||
if(common::hasPriv('execution', 'create')) $plan->actions[] = $action;
|
||||
continue;
|
||||
}
|
||||
if($this->productplan->isClickable($plan, $action)) $plan->actions[] = $action;
|
||||
}
|
||||
$planList[$plan->status][] = $plan;
|
||||
}
|
||||
|
||||
@@ -1078,6 +1078,7 @@ class my extends control
|
||||
$this->session->set('opportunityLibList', $uri, 'assetlib');
|
||||
$this->session->set('practiceLibList', $uri, 'assetlib');
|
||||
$this->session->set('componentLibList', $uri, 'assetlib');
|
||||
$this->session->set('opportunityList', $uri, 'project');
|
||||
|
||||
/* Set the pager. */
|
||||
$this->app->loadClass('pager', $static = true);
|
||||
|
||||
@@ -10,5 +10,6 @@ $config->productplan->start->requiredFields = 'begin,end';
|
||||
$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->editor->start = array('id' => 'desc', 'tools' => 'simpleTools');
|
||||
|
||||
$config->productplan->laneColorList = array('#32C5FF', '#006AF1', '#9D28B2', '#FF8F26', '#FFC20E', '#00A78E', '#7FBB00', '#424BAC', '#C0E9FF', '#EC2761');
|
||||
|
||||
@@ -68,7 +68,7 @@ class productplan extends control
|
||||
|
||||
if($this->viewType == 'json') return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'id' => $planID));
|
||||
if(isonlybody()) return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'closeModal' => true, 'callback' => 'parent.refreshPlan()'));
|
||||
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $this->createLink('productplan', 'browse', "productID=$productID&branch=$branchID")));
|
||||
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $this->createLink('productplan', 'browse', "productID=$productID&branch=$branchID&browseType=wait")));
|
||||
}
|
||||
|
||||
$this->commonAction($productID, $branchID);
|
||||
@@ -252,8 +252,12 @@ class productplan extends control
|
||||
$viewType = $this->cookie->viewType ? $this->cookie->viewType : 'list';
|
||||
|
||||
$this->commonAction($productID, $branch);
|
||||
$product = $this->product->getById($productID);
|
||||
$productName = empty($product) ? '' : $product->name;
|
||||
$product = $this->product->getById($productID);
|
||||
$productName = empty($product) ? '' : $product->name;
|
||||
$branchList = $this->branch->getList($productID, 0, 'all');
|
||||
$branchStatusList = array();
|
||||
foreach($branchList as $productBranch) $branchStatusList[$productBranch->id] = $productBranch->status;
|
||||
|
||||
if($viewType == 'kanban')
|
||||
{
|
||||
$branches = array();
|
||||
@@ -285,17 +289,18 @@ class productplan extends control
|
||||
$this->view->kanbanData = $this->loadModel('kanban')->getPlanKanban($product, $branchID, $planGroup);
|
||||
}
|
||||
|
||||
$this->view->title = $productName . $this->lang->colon . $this->lang->productplan->browse;
|
||||
$this->view->position[] = $this->lang->productplan->browse;
|
||||
$this->view->productID = $productID;
|
||||
$this->view->branch = $branch;
|
||||
$this->view->browseType = $browseType;
|
||||
$this->view->viewType = $viewType;
|
||||
$this->view->orderBy = $orderBy;
|
||||
$this->view->plans = $this->productplan->getList($productID, $branch, $browseType, $pager, $sort);
|
||||
$this->view->pager = $pager;
|
||||
$this->view->projects = $this->product->getProjectPairsByProduct($productID, $branch);
|
||||
$this->view->statusList = $this->lang->productplan->featureBar['browse'];
|
||||
$this->view->title = $productName . $this->lang->colon . $this->lang->productplan->browse;
|
||||
$this->view->position[] = $this->lang->productplan->browse;
|
||||
$this->view->productID = $productID;
|
||||
$this->view->branch = $branch;
|
||||
$this->view->branchStatusList = $branchStatusList;
|
||||
$this->view->browseType = $browseType;
|
||||
$this->view->viewType = $viewType;
|
||||
$this->view->orderBy = $orderBy;
|
||||
$this->view->plans = $this->productplan->getList($productID, $branch, $browseType, $pager, $sort);
|
||||
$this->view->pager = $pager;
|
||||
$this->view->projects = $this->product->getProjectPairsByProduct($productID, $branch);
|
||||
$this->view->statusList = $this->lang->productplan->featureBar['browse'];
|
||||
$this->display();
|
||||
}
|
||||
|
||||
@@ -403,9 +408,6 @@ class productplan extends control
|
||||
$changes = $this->productplan->updateStatus($planID, 'doing');
|
||||
if(dao::isError()) die(js::error(dao::getError()));
|
||||
|
||||
$actionID = $this->loadModel('action')->create('productplan', $planID, 'started');
|
||||
$this->action->logHistory($actionID, $changes);
|
||||
|
||||
die(js::reload('parent'));
|
||||
}
|
||||
}
|
||||
@@ -416,11 +418,9 @@ class productplan extends control
|
||||
$changes = $this->productplan->updateStatus($planID, 'doing');
|
||||
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
|
||||
$actionID = $this->loadModel('action')->create('productplan', $planID, 'started');
|
||||
$this->action->logHistory($actionID, $changes);
|
||||
|
||||
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess,'locate' => 'parent'));
|
||||
}
|
||||
|
||||
$this->view->plan = $plan;
|
||||
$this->display();
|
||||
}
|
||||
@@ -445,9 +445,6 @@ class productplan extends control
|
||||
$changes = $this->productplan->updateStatus($planID, 'done');
|
||||
if(dao::isError()) die(js::error(dao::getError()));
|
||||
|
||||
$actionID = $this->loadModel('action')->create('productplan', $planID, 'finished');
|
||||
$this->action->logHistory($actionID, $changes);
|
||||
|
||||
die(js::reload('parent'));
|
||||
}
|
||||
}
|
||||
@@ -471,9 +468,6 @@ class productplan extends control
|
||||
$changes = $this->productplan->updateStatus($planID, 'closed');
|
||||
if(dao::isError()) die(js::error(dao::getError()));
|
||||
|
||||
$actionID = $this->loadModel('action')->create('productplan', $planID, 'closed');
|
||||
$this->action->logHistory($actionID, $changes);
|
||||
|
||||
die(js::reload('parent'));
|
||||
}
|
||||
}
|
||||
@@ -497,9 +491,6 @@ class productplan extends control
|
||||
$changes = $this->productplan->updateStatus($planID, 'doing');
|
||||
if(dao::isError()) die(js::error(dao::getError()));
|
||||
|
||||
$actionID = $this->loadModel('action')->create('productplan', $planID, 'activated');
|
||||
$this->action->logHistory($actionID, $changes);
|
||||
|
||||
die(js::reload('parent'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,16 +17,18 @@ td.c-branch {overflow: hidden; text-align: left !important; text-overflow: ellip
|
||||
|
||||
.c-title {width: 160px;}
|
||||
.c-branch {width: 100px;}
|
||||
.c-story {width: 80px;}
|
||||
.c-execution {width: 120px;}
|
||||
.c-story, .c-status {width: 80px;}
|
||||
.c-execution {width: 50px !important;}
|
||||
.c-bug, .c-hour {width: 60px;}
|
||||
|
||||
.plan-name {position: relative; display: flex; align-items: center;}
|
||||
.plan-name > span {flex: none;}
|
||||
|
||||
.c-title.has-child > .plan-name.has-suffix > a, .c-title.has-child > .plan-name.has-prefix > a {overflow:hidden; max-width: calc(100% - 70px);}
|
||||
.plan-name.has-suffix > a, .plan-name.has-prefix > a {overflow:hidden; max-width: calc(100% - 46px);}
|
||||
#productplanList .plan-name > .label.label-danger {margin-left:3px; }
|
||||
#productplanList .c-title.has-child > .plan-name.expired > a {overflow:hidden; max-width: calc(100% - 62px);}
|
||||
#productplanList .c-title.has-child > .plan-name > a {overflow:hidden; max-width: calc(100% - 16px);}
|
||||
#productplanList .c-title > .plan-name.expired > a {overflow:hidden; max-width: calc(100% - 46px);}
|
||||
#productplanList .plan-name.expired > .label.label-danger {margin-left:3px; }
|
||||
#productplanList .plan-name > .label.label-light {margin-right:3px; }
|
||||
|
||||
.switchButton {background: #fff !important;}
|
||||
.panel-actions {position: relative; padding: 0 0; padding-top: 1px;}
|
||||
|
||||
@@ -75,9 +75,105 @@ $(function()
|
||||
{
|
||||
$.zui.ContextMenu.hide();
|
||||
});
|
||||
|
||||
/* Init contextmenu */
|
||||
$('#kanban').on('click', '[data-contextmenu]', function(event)
|
||||
{
|
||||
var $trigger = $(this);
|
||||
var menuType = $trigger.data('contextmenu');
|
||||
var menuCreator = window.menuCreators[menuType];
|
||||
if(!menuCreator) return;
|
||||
|
||||
var options = $.extend({event: event, $trigger: $trigger}, $trigger.data());
|
||||
var items = menuCreator(options);
|
||||
if(!items || !items.length) return;
|
||||
|
||||
$.zui.ContextMenu.show(items, items.$options || {event: event});
|
||||
});
|
||||
}
|
||||
|
||||
/* Hide contextmenu when page scroll */
|
||||
$(window).on('scroll', function()
|
||||
{
|
||||
$.zui.ContextMenu.hide();
|
||||
});
|
||||
});
|
||||
|
||||
/* Define menu creators */
|
||||
window.menuCreators =
|
||||
{
|
||||
card: createCardMenu
|
||||
};
|
||||
|
||||
/**
|
||||
* Create card menu.
|
||||
*
|
||||
* @param object $options
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
function createCardMenu(options)
|
||||
{
|
||||
var card = options.$trigger.closest('.kanban-item').data('item');
|
||||
var privs = card.actions;
|
||||
if(!privs.length) return [];
|
||||
|
||||
var items = [];
|
||||
if(privs.includes('createExecution'))
|
||||
{
|
||||
var className = '';
|
||||
var executionLink = systemMode == 'new' ? '#projects' : createLink('execution', 'create', "projectID=0&executionID=0©ExecutionID=0&plan=" + card.id + "&confirm=no&productID=" + productID);
|
||||
var today = new Date();
|
||||
var end = $.zui.createDate(card.end);
|
||||
if(end.toLocaleDateString() < today.toLocaleDateString())
|
||||
{
|
||||
className = 'disabled';
|
||||
}
|
||||
else if(card.status == 'done' || card.status == 'closed')
|
||||
{
|
||||
className = 'disabled';
|
||||
}
|
||||
else if(product.type != 'normal')
|
||||
{
|
||||
var branchStatus = branchStatusList[card.branch];
|
||||
if(branchStatus == 'closed') className = 'disabled';
|
||||
}
|
||||
|
||||
if(systemMode == 'new')
|
||||
{
|
||||
items.push({label: productplanLang.createExecution, icon: 'plus', url: executionLink, className: className, attrs: {'data-toggle': 'modal', 'onclick': 'getPlanID(this,' + card.branch + ')', 'data-id': card.id}});
|
||||
}
|
||||
else
|
||||
{
|
||||
items.push({label: productplanLang.createExecution, icon: 'plus', url: executionLink, className: className});
|
||||
}
|
||||
}
|
||||
|
||||
if(privs.includes('linkStory')) items.push({label: productplanLang.linkStory, icon: 'link', url: createLink('productplan', 'view', "planID=" + card.id + "&type=story&orderBy=id_desc&link=true")});
|
||||
if(privs.includes('linkBug')) items.push({label: productplanLang.linkBug, icon: 'bug', url: createLink('productplan', 'view', "planID=" + card.id + "&type=bug&orderBy=id_desc&link=true")});
|
||||
if(privs.includes('edit')) items.push({label: productplanLang.edit, icon: 'edit', url: createLink('productplan', 'edit', "planID=" + card.id)});
|
||||
if(privs.includes('start'))
|
||||
{
|
||||
if(card.begin == '2030-01-01' || card.end == '2030-01-01')
|
||||
{
|
||||
items.push({label: productplanLang.start, icon: 'start', url: createLink('productplan', 'start', "planID=" + card.id, '', true), className: 'iframe', attrs: {'data-toggle': 'modal', 'data-id': card.id, 'data-width': '550px'}});
|
||||
}
|
||||
else
|
||||
{
|
||||
items.push({label: productplanLang.start, icon: 'start', url: createLink('productplan', 'start', "planID=" + card.id), attrs: {'target': 'hiddenwin'}});
|
||||
}
|
||||
}
|
||||
|
||||
if(privs.includes('finish')) items.push({label: productplanLang.finish, icon: 'checked', url: createLink('productplan', 'finish', "planID=" + card.id), attrs: {'target': 'hiddenwin'}});
|
||||
if(privs.includes('close')) items.push({label: productplanLang.close, icon: 'off', url: createLink('productplan', 'close', "planID=" + card.id), attrs: {'target': 'hiddenwin'}});
|
||||
if(privs.includes('activate')) items.push({label: productplanLang.activate, icon: 'magic', url: createLink('productplan', 'activate', "planID=" + card.id), attrs: {'target': 'hiddenwin'}});
|
||||
if(privs.includes('delete')) items.push({label: productplanLang.delete, icon: 'trash', url: createLink('productplan', 'delete', "planID=" + card.id), attrs: {'target': 'hiddenwin'}});
|
||||
|
||||
var bounds = options.$trigger[0].getBoundingClientRect();
|
||||
items.$options = {x: bounds.right, y: bounds.top};
|
||||
return items;
|
||||
}
|
||||
|
||||
$(document).on('click', 'td.content .more', function(e)
|
||||
{
|
||||
var $toggle = $(this);
|
||||
@@ -107,8 +203,7 @@ 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;
|
||||
var kanbanRules = window.kanbanDropRules ? window.kanbanDropRules : null;
|
||||
|
||||
if(!kanbanRules) return $root.find('.kanban-lane[data-id="' + lane.id + '"] .kanban-lane-col:not([data-type="project"],[data-type="' + col.type + '"])');
|
||||
|
||||
@@ -160,6 +255,50 @@ function handleFinishDrop(event)
|
||||
function changeCardColType(card, fromColType, toColType, kanbanID)
|
||||
{
|
||||
if(typeof card == 'undefined') return false;
|
||||
var objectID = card.id;
|
||||
var privs = card.actions;
|
||||
var showIframe = false;
|
||||
var link = '';
|
||||
|
||||
if(toColType == 'doing')
|
||||
{
|
||||
if(fromColType == 'wait' && privs.includes('start'))
|
||||
{
|
||||
var link = createLink('productplan', 'start', 'planID=' + objectID, '', true);
|
||||
showIframe = true;
|
||||
}
|
||||
else if((fromColType == 'done' || fromColType == 'closed') && privs.includes('activate'))
|
||||
{
|
||||
var link = createLink('productplan', 'activate', 'planID=' + objectID, '', true);
|
||||
showIframe = false;
|
||||
}
|
||||
}
|
||||
else if(toColType == 'done')
|
||||
{
|
||||
if(fromColType == 'doing')
|
||||
{
|
||||
var link = createLink('productplan', 'finish', 'planID=' + objectID, '', true);
|
||||
showIframe = false;
|
||||
}
|
||||
}
|
||||
else if(toColType == 'closed')
|
||||
{
|
||||
if(fromColType == 'done')
|
||||
{
|
||||
var link = createLink('productplan', 'close', 'planID=' + objectID);
|
||||
showIframe = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(showIframe)
|
||||
{
|
||||
var modalTrigger = new $.zui.ModalTrigger({type: 'iframe', width: '50%', url: link});
|
||||
modalTrigger.show();
|
||||
}
|
||||
else if(!showIframe && link)
|
||||
{
|
||||
hiddenwin.location.href = link;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -167,22 +306,30 @@ function changeCardColType(card, fromColType, toColType, kanbanID)
|
||||
*/
|
||||
function renderKanbanItem(item, $item)
|
||||
{
|
||||
var privs = item.actions;
|
||||
var $titleBox = $item.children('.titleBox');
|
||||
var privs = item.actions;
|
||||
var printMoreBtn = (privs.includes('createExecution') || privs.includes('linkStory') || privs.includes('linkBug') || privs.includes('edit') || privs.includes('start') || privs.includes('finish') || privs.includes('close') || privs.includes('activate') || privs.includes('delete'));
|
||||
|
||||
/* Output header information. */
|
||||
var $header = $item.children('.header');
|
||||
if(!$header.length) $header = $(
|
||||
[
|
||||
'<div class="header">',
|
||||
'</div>'
|
||||
].join('')).appendTo($item);
|
||||
|
||||
var $titleBox = $item.children('.titleBox');
|
||||
if(!$titleBox.length) $titleBox = $(
|
||||
[
|
||||
'<div class="titleBox">',
|
||||
'</div>'
|
||||
].join('')).appendTo($item);
|
||||
].join('')).appendTo($header);
|
||||
|
||||
/* Print plan name. */
|
||||
var $title = $titleBox.children('.title');
|
||||
if(!$title.length)
|
||||
{
|
||||
if(privs.includes('view')) $title = $('<a class="title"></a>').appendTo($titleBox).attr('href', createLink('productplan', 'view', 'cardID=' + item.id));
|
||||
if(!privs.includes('view')) $title = $('<p class="title"></p>').appendTo($titleBox);
|
||||
if(!privs.includes('view')) $title = $('<a class="title"></a>').appendTo($titleBox);
|
||||
}
|
||||
$title.text(item.title).attr('title', item.title);
|
||||
|
||||
@@ -190,7 +337,7 @@ function renderKanbanItem(item, $item)
|
||||
var today = new Date();
|
||||
var begin = $.zui.createDate(item.begin);
|
||||
var end = $.zui.createDate(item.end);
|
||||
if(end.toLocaleDateString() < today.toLocaleDateString())
|
||||
if(end.toLocaleDateString() < today.toLocaleDateString() && (item.status == 'wait' || item.status == 'doing'))
|
||||
{
|
||||
$expired = $titleBox.children('.expired');
|
||||
if(!$expired.length)
|
||||
@@ -199,6 +346,18 @@ function renderKanbanItem(item, $item)
|
||||
}
|
||||
}
|
||||
|
||||
if(printMoreBtn)
|
||||
{
|
||||
$(
|
||||
[
|
||||
'<div class="actions" title="' + productplanLang.more + '">',
|
||||
'<a data-contextmenu="card" data-id="' + item.id + '">',
|
||||
'<i class="icon icon-ellipsis-v"></i>',
|
||||
'</a>',
|
||||
'</div>'
|
||||
].join('')).appendTo($header);
|
||||
}
|
||||
|
||||
/* Output plan date information. */
|
||||
var $dateBox = $item.children('.dateBox');
|
||||
if(!$dateBox.length) $dateBox = $(
|
||||
@@ -263,3 +422,14 @@ function getPlanID(obj, branch)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if(!window.kanbanDropRules)
|
||||
{
|
||||
window.kanbanDropRules =
|
||||
{
|
||||
wait: ['doing'],
|
||||
doing: ['done'],
|
||||
done: ['doing', 'closed'],
|
||||
closed: ['doing']
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,12 +18,13 @@ $lang->productplan->delete = "Delete Plan";
|
||||
$lang->productplan->start = "Start Plan";
|
||||
$lang->productplan->finish = "Finish Plan";
|
||||
$lang->productplan->close = "Close Plan";
|
||||
$lang->productplan->activate = "Activate Plan";
|
||||
$lang->productplan->startAB = "Start";
|
||||
$lang->productplan->finishAB = "Finish";
|
||||
$lang->productplan->closeAB = "Close";
|
||||
$lang->productplan->activateAB = "Activate";
|
||||
$lang->productplan->view = "Plan Detail";
|
||||
$lang->productplan->activate = "Activate Plan";
|
||||
$lang->productplan->view = "View";
|
||||
$lang->productplan->bugSummary = "Total <strong>%s</strong> Bugs on this page.";
|
||||
$lang->productplan->basicInfo = 'Basic Info';
|
||||
$lang->productplan->batchEdit = 'Batch Edit';
|
||||
@@ -31,6 +32,7 @@ $lang->productplan->project = 'Project';
|
||||
$lang->productplan->plan = 'Plan';
|
||||
$lang->productplan->allAB = 'All';
|
||||
$lang->productplan->to = 'To';
|
||||
$lang->productplan->more = 'More';
|
||||
|
||||
$lang->productplan->batchUnlink = "Batch Unlink";
|
||||
$lang->productplan->unlinkAB = "Unlink";
|
||||
@@ -96,6 +98,11 @@ $lang->productplan->statusList['doing'] = 'Doing';
|
||||
$lang->productplan->statusList['done'] = 'Done';
|
||||
$lang->productplan->statusList['closed'] = 'Closed';
|
||||
|
||||
$lang->productplan->parentActionList['startedbychild'] = '<strong>starting </strong>the productplan sets the plan status as <strong>Doing</strong>.';
|
||||
$lang->productplan->parentActionList['finishedbychild'] = '<strong>finishing </strong>all productplan sets the plan status as <strong>Done</strong>.';
|
||||
$lang->productplan->parentActionList['closedbychild'] = '<strong>closing </strong>all productplan sets the plan status as <strong>Closed</strong>.';
|
||||
$lang->productplan->parentActionList['activatedbychild'] = '<strong>activating </strong>the productplan sets the plan status as <strong>Doing</strong>.';
|
||||
|
||||
$lang->productplan->endList[7] = '1 Week';
|
||||
$lang->productplan->endList[14] = '2 Weeks';
|
||||
$lang->productplan->endList[31] = '1 Month';
|
||||
@@ -120,3 +127,6 @@ $lang->productplan->featureBar['browse']['wait'] = 'Waiting';
|
||||
$lang->productplan->featureBar['browse']['doing'] = 'Doing';
|
||||
$lang->productplan->featureBar['browse']['done'] = 'Done';
|
||||
$lang->productplan->featureBar['browse']['closed'] = 'Closed';
|
||||
|
||||
$lang->productplan->action = new stdclass();
|
||||
$lang->productplan->action->changebychild = array('main' => '$date, $extra', 'extra' => 'parentActionList');
|
||||
|
||||
@@ -31,6 +31,7 @@ $lang->productplan->project = '项目';
|
||||
$lang->productplan->plan = '计划';
|
||||
$lang->productplan->allAB = '所有';
|
||||
$lang->productplan->to = '至';
|
||||
$lang->productplan->more = '更多操作';
|
||||
|
||||
$lang->productplan->batchUnlink = "批量移除";
|
||||
$lang->productplan->unlinkAB = "移除";
|
||||
@@ -96,6 +97,11 @@ $lang->productplan->statusList['doing'] = '进行中';
|
||||
$lang->productplan->statusList['done'] = '已完成';
|
||||
$lang->productplan->statusList['closed'] = '已关闭';
|
||||
|
||||
$lang->productplan->parentActionList['startedbychild'] = '系统判断由于子计划 <strong>开始</strong> ,将计划状态置为 <strong>进行中</strong> 。';
|
||||
$lang->productplan->parentActionList['finishedbychild'] = '系统判断由于子计划 <strong>全部完成</strong> ,将计划状态置为 <strong>已完成</strong> 。';
|
||||
$lang->productplan->parentActionList['closedbychild'] = '系统判断由于子计划 <strong>全部关闭</strong> ,将计划状态置为 <strong>已关闭</strong> 。';
|
||||
$lang->productplan->parentActionList['activatedbychild'] = '系统判断由于子计划 <strong>激活</strong> ,将计划状态置为 <strong>进行中</strong> 。';
|
||||
|
||||
$lang->productplan->endList[7] = '一星期';
|
||||
$lang->productplan->endList[14] = '两星期';
|
||||
$lang->productplan->endList[31] = '一个月';
|
||||
@@ -120,3 +126,6 @@ $lang->productplan->featureBar['browse']['wait'] = '未开始';
|
||||
$lang->productplan->featureBar['browse']['doing'] = '进行中';
|
||||
$lang->productplan->featureBar['browse']['done'] = '已完成';
|
||||
$lang->productplan->featureBar['browse']['closed'] = '已关闭';
|
||||
|
||||
$lang->productplan->action = new stdclass();
|
||||
$lang->productplan->action->changebychild = array('main' => '$date, $extra', 'extra' => 'parentActionList');
|
||||
|
||||
@@ -520,14 +520,23 @@ class productplanModel extends model
|
||||
{
|
||||
$planID = (int)$planID;
|
||||
$oldPlan = $this->getByID($planID);
|
||||
if($oldPlan->parent > 0) $parentPlan = $this->getByID($oldPlan->parent);
|
||||
if($oldPlan->parent > 0)
|
||||
{
|
||||
$parentPlan = $this->getByID($oldPlan->parent);
|
||||
$parentChange = false;
|
||||
}
|
||||
|
||||
if($status == 'doing' and !empty($_POST))
|
||||
{
|
||||
$plan = fixer::input('post')->add('status', $status)->get();
|
||||
$plan = fixer::input('post')
|
||||
->add('status', $status)
|
||||
->stripTags($this->config->productplan->editor->start['id'], $this->config->allowedTags)
|
||||
->remove('uid')
|
||||
->get();
|
||||
|
||||
$this->checkDate4Plan($oldPlan, $plan->begin, $plan->end);
|
||||
if(dao::isError()) return false;
|
||||
$plan = $this->loadModel('file')->processImgURL($plan, $this->config->productplan->editor->start['id'], $this->post->uid);
|
||||
|
||||
$this->dao->update(TABLE_PRODUCTPLAN)
|
||||
->data($plan)
|
||||
@@ -535,8 +544,15 @@ class productplanModel extends model
|
||||
->batchCheck($this->config->productplan->start->requiredFields, 'notempty')
|
||||
->checkIF(!empty($_POST['begin']) && !empty($_POST['end']), 'end', 'ge', $plan->begin)
|
||||
->where('id')->eq($planID)
|
||||
->beginIF(isset($parentPlan))->orWhere('id')->eq($oldPlan->parent)->fi()
|
||||
->exec();
|
||||
|
||||
$this->file->updateObjectID($this->post->uid, $planID, 'productplan');
|
||||
|
||||
if(isset($parentPlan) and $parentPlan->status != 'doing')
|
||||
{
|
||||
$this->dao->update(TABLE_PRODUCTPLAN)->set('status')->eq($status)->where('id')->eq($oldPlan->parent)->exec();
|
||||
$parentChange = true;
|
||||
}
|
||||
}
|
||||
elseif($status == 'doing' and isset($parentPlan) and $parentPlan->status != 'doing')
|
||||
{
|
||||
@@ -545,6 +561,7 @@ class productplanModel extends model
|
||||
->where('id')->eq($planID)
|
||||
->orWhere('id')->eq($oldPlan->parent)
|
||||
->exec();
|
||||
if($parentPlan->status != 'doing') $parentChange = true;
|
||||
}
|
||||
elseif($status == 'done' and isset($parentPlan))
|
||||
{
|
||||
@@ -558,6 +575,7 @@ class productplanModel extends model
|
||||
break;
|
||||
}
|
||||
}
|
||||
if($parentDone) $parentChange = true;
|
||||
$this->dao->update(TABLE_PRODUCTPLAN)
|
||||
->set('`status`')->eq($status)
|
||||
->where('id')->eq($planID)
|
||||
@@ -576,6 +594,7 @@ class productplanModel extends model
|
||||
break;
|
||||
}
|
||||
}
|
||||
if($parentClosed) $parentChange = true;
|
||||
$this->dao->update(TABLE_PRODUCTPLAN)
|
||||
->set('`status`')->eq($status)
|
||||
->where('id')->eq($planID)
|
||||
@@ -593,7 +612,39 @@ class productplanModel extends model
|
||||
if(dao::isError()) return false;
|
||||
|
||||
if(!isset($plan)) $plan = $this->getByID($planID);
|
||||
if(!dao::isError())return common::createChanges($oldPlan, $plan);
|
||||
if(!dao::isError())
|
||||
{
|
||||
$method = $this->app->rawMethod;
|
||||
if($method == 'start')
|
||||
{
|
||||
$action = 'started';
|
||||
if(isset($parentChange) and $parentChange) $parentAction = 'startedbychild';
|
||||
}
|
||||
elseif($method == 'finish')
|
||||
{
|
||||
$action = 'finished';
|
||||
if(isset($parentChange) and $parentChange) $parentAction = 'finishedbychild';
|
||||
}
|
||||
elseif($method == 'close')
|
||||
{
|
||||
$action = 'closed';
|
||||
if(isset($parentChange) and $parentChange) $parentAction = 'closedbychild';
|
||||
}
|
||||
elseif($method == 'activate')
|
||||
{
|
||||
$action = 'activated';
|
||||
if(isset($parentChange) and $parentChange) $parentAction = 'activatedbychild';
|
||||
}
|
||||
|
||||
if(isset($action))
|
||||
{
|
||||
$changes = common::createChanges($oldPlan, $plan);
|
||||
$actionID = $this->loadModel('action')->create('productplan', $planID, $action);
|
||||
$this->action->loghistory($actionID, $changes);
|
||||
|
||||
if(isset($parentChange) and $parentChange) $actionID = $this->action->create('productplan', $oldPlan->parent, $parentAction, '', $parentAction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -612,7 +663,7 @@ class productplanModel extends model
|
||||
$config = HTMLPurifier_Config::createDefault();
|
||||
$config->set('Cache.DefinitionImpl', null);
|
||||
$purifier = new HTMLPurifier($config);
|
||||
|
||||
|
||||
$plans = array();
|
||||
$extendFields = $this->getFlowExtendFields();
|
||||
foreach($data->id as $planID)
|
||||
@@ -689,17 +740,17 @@ class productplanModel extends model
|
||||
$maxEnd = $end;
|
||||
foreach($childPlans as $childPlan)
|
||||
{
|
||||
if($childPlan->begin < $minBegin) $minBegin = $childPlan->begin;
|
||||
if($childPlan->end > $maxEnd) $maxEnd = $childPlan->end;
|
||||
if($childPlan->begin < $minBegin and $minBegin != '2030-01-01') $minBegin = $childPlan->begin;
|
||||
if($childPlan->end > $maxEnd and $maxEnd != '2030-01-01') $maxEnd = $childPlan->end;
|
||||
}
|
||||
if($minBegin < $begin) dao::$errors['begin'] = sprintf($this->lang->beginGreaterChild, $minBegin);
|
||||
if($maxEnd > $end) dao::$errors['end'] = sprintf($this->lang->endLetterChild, $maxEnd);
|
||||
if($minBegin < $begin and $begin != '2030-01-01') dao::$errors['begin'] = sprintf($this->lang->beginGreaterChild, $minBegin);
|
||||
if($maxEnd > $end and $end != '2030-01-01') dao::$errors['end'] = sprintf($this->lang->endLetterChild, $maxEnd);
|
||||
}
|
||||
elseif($plan->parent > 0)
|
||||
{
|
||||
$parentPlan = $this->getByID($plan->parent);
|
||||
if($begin < $parentPlan->begin) dao::$errors['begin'] = sprintf($this->lang->productplan->beginLetterParent, $parentPlan->begin);
|
||||
if($end > $parentPlan->end) dao::$errors['end'] = sprintf($this->lang->productplan->endGreaterParent, $parentPlan->end);
|
||||
if($begin < $parentPlan->begin and $parentPlan->begin != '2030-01-01') dao::$errors['begin'] = sprintf($this->lang->productplan->beginLetterParent, $parentPlan->begin);
|
||||
if($end > $parentPlan->end and $parentPlan->end != '2030-01-01') dao::$errors['end'] = sprintf($this->lang->productplan->endGreaterParent, $parentPlan->end);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -929,7 +980,7 @@ class productplanModel extends model
|
||||
if($plan->status != 'done' or $plan->parent < 0) return false;
|
||||
break;
|
||||
case 'activate' :
|
||||
if($plan->status != 'closed' or $plan->parent < 0) return false;
|
||||
if($plan->status == 'wait' or $plan == 'doing' or $plan->parent < 0) return false;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
<?php js::set('enterProjectList', $lang->productplan->enterProjectList);?>
|
||||
<?php js::set('projectNotEmpty', $lang->productplan->projectNotEmpty)?>
|
||||
<?php js::set('viewType', $viewType);?>
|
||||
<?php js::set('product', $product);?>
|
||||
<?php js::set('systemMode', $config->systemMode);?>
|
||||
<?php js::set('branchStatusList', $branchStatusList);?>
|
||||
<?php
|
||||
if($viewType == 'kanban')
|
||||
{
|
||||
@@ -28,4 +31,32 @@ else
|
||||
include 'browsebylist.html.php';
|
||||
}
|
||||
?>
|
||||
<div class="modal fade" id="projects">
|
||||
<div class="modal-dialog mw-500px">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title"><?php echo $lang->productplan->selectProjects;?></h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<table class='table table-form'>
|
||||
<tr>
|
||||
<th><?php echo $lang->productplan->project?></th>
|
||||
<td><?php echo html::select('project', $projects, '', "class='form-control chosen'");?></td>
|
||||
</tr>
|
||||
<tr class='tips hidden'>
|
||||
<th></th>
|
||||
<td><span class='text-red'><?php echo $lang->productplan->noLinkedProject;?></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan='2' class='text-center'>
|
||||
<?php echo html::hidden('planID', '');?>
|
||||
<?php echo html::commonButton($lang->productplan->nextStep, "id='createExecutionButton'", 'btn btn-primary btn-wide');?>
|
||||
<?php echo html::commonButton($lang->cancel, "data-dismiss='modal'", 'btn btn-default btn-wide');?>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
|
||||
@@ -18,13 +18,19 @@
|
||||
#branchBox {width: 120px;}
|
||||
#branch_chosen .icon-delay {padding-right: 10px; font-size: 15px;}
|
||||
#kanbanContainer {padding-bottom: 0; margin-bottom: 0;}
|
||||
.kanban-item:hover > .header > .actions {opacity: 1;}
|
||||
.kanban-card {height: 80px !important;}
|
||||
.kanban-card .titleBox {width: 100%; display: flex;}
|
||||
.kanban-card .titleBox > span {flex: none;}
|
||||
.kanban-card .header .titleBox {display: flex; width: 90%; float: left;}
|
||||
.kanban-card .header .titleBox > span {flex: none;}
|
||||
.kanban-card .header .actions {float: right; opacity: 0;}
|
||||
.kanban-card .header .actions > a:hover {background-color: rgba(0,0,0,.075); opacity: 1;}
|
||||
.kanban-card:hover > .header > .actions {opacity: 1;}
|
||||
.kanban-card .title {white-space: nowrap; overflow: hidden;}
|
||||
.kanban-card .expired {margin-left: 2px;}
|
||||
.kanban-card .dateBox {padding-top: 5px;}
|
||||
.kanban-card .dateBox {padding-top: 22px;}
|
||||
.kanban-card .desc {overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: #838a9d; padding-top: 5px;}
|
||||
.kanban-card .actions > a {display: block; float: left; width: 20px; height: 20px; line-height: 20px; text-align: center; border-radius: 4px; opacity: .7;}
|
||||
.dropdown-menu > li > .disabled {pointer-events: none; color: #838a9d;}
|
||||
</style>
|
||||
<?php js::set('kanbanData', $kanbanData);?>
|
||||
<?php js::set('productplanLang', $lang->productplan);?>
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
</th>
|
||||
<th class='c-title'><?php common::printOrderLink('title', $orderBy, $vars, $lang->productplan->title);?></th>
|
||||
<?php if($browseType == 'all'):?>
|
||||
<th><?php common::printOrderLink('status', $orderBy, $vars, $lang->productplan->status);?></th>
|
||||
<th class='c-status'><?php common::printOrderLink('status', $orderBy, $vars, $lang->productplan->status);?></th>
|
||||
<?php endif;?>
|
||||
<?php if($this->session->currentProductType != 'normal'):?>
|
||||
<th class='c-branch'><?php common::printOrderLink('branch',$orderBy, $vars, $lang->productplan->branch);?></th>
|
||||
@@ -78,6 +78,7 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php $this->loadModel('file');?>
|
||||
<?php $today = date('Y-m-d');?>
|
||||
<?php foreach($plans as $plan):?>
|
||||
<?php
|
||||
$canBeChanged = common::canBeChanged('plan', $plan);
|
||||
@@ -110,14 +111,22 @@
|
||||
<?php echo sprintf('%03d', $plan->id);?>
|
||||
<?php endif;?>
|
||||
</td>
|
||||
<td class='c-title text-left<?php if($plan->parent == '-1') echo ' has-child';?>' title="<?php echo $plan->title?>">
|
||||
<td class='c-title text-left<?php if(isset($plan->children)) echo ' has-child';?>' title="<?php echo $plan->title?>">
|
||||
<?php
|
||||
$suffix = '';
|
||||
if($plan->end < helper::now()) $suffix = "<span class='label label-danger label-badge'>{$this->lang->productplan->expired}</span>";
|
||||
if($plan->parent == '-1') $suffix .= '<a class="task-toggle" data-id="' . $plan->id . '"><i class="icon icon-angle-double-right"></i></a>';
|
||||
if(!empty($suffix)) echo '<div class="plan-name has-prefix has-suffix">';
|
||||
$class = '';
|
||||
$expired = '';
|
||||
if($plan->end < $today and in_array($plan->status, array('wait', 'doing')))
|
||||
{
|
||||
$class .= ' expired';
|
||||
$expired = "<span class='label label-danger label-badge'>{$this->lang->productplan->expired}</span>";
|
||||
}
|
||||
|
||||
echo "<div class='plan-name has-prefix {$class}'>";
|
||||
if($plan->parent > 0 and !isset($plans[$plan->parent])) echo "<span class='label label-badge label-light' title='{$this->lang->productplan->children}'>{$this->lang->productplan->childrenAB}</span>";
|
||||
echo html::a(inlink('view', "id=$plan->id"), $plan->title);
|
||||
if(!empty($suffix)) echo $suffix . '</div>';
|
||||
if(!empty($expired)) echo $expired;
|
||||
if(isset($plan->children)) echo '<a class="task-toggle" data-id="' . $plan->id . '"><i class="icon icon-angle-double-right"></i></a>';
|
||||
echo '</div>';
|
||||
?>
|
||||
</td>
|
||||
<?php if($browseType == 'all'):?>
|
||||
@@ -147,12 +156,12 @@
|
||||
if($plan->begin == '2030-01-01' or $plan->end == '2030-01-01')
|
||||
{
|
||||
$class = 'iframe';
|
||||
$attr = "data-toggle='modal' data-id='{$plan->id}' data-width='550px'";
|
||||
$attr = "data-id='{$plan->id}' data-width='550px'";
|
||||
$isOnlyBody = true;
|
||||
}
|
||||
common::printIcon('productplan', 'start', "planID=$plan->id", $plan, 'list', 'play', '', $class, $isOnlyBody, $attr, $lang->productplan->start);
|
||||
common::printIcon('productplan', 'finish', "planID=$plan->id", $plan, 'list', 'checked', '', $class, false, $attr, $lang->productplan->finish);
|
||||
common::printIcon('productplan', 'close', "planID=$plan->id", $plan, 'list', 'off', '', $class, false, $attr, $lang->productplan->close);
|
||||
common::printIcon('productplan', 'start', "planID=$plan->id", $plan, 'list', 'play', '', $class, $isOnlyBody);
|
||||
common::printIcon('productplan', 'finish', "planID=$plan->id", $plan, 'list', 'checked', '', $class, false, $attr);
|
||||
common::printIcon('productplan', 'close', "planID=$plan->id", $plan, 'list', 'off', '', $class, false, $attr);
|
||||
}
|
||||
|
||||
$attr = $plan->expired ? "disabled='disabled'" : '';
|
||||
@@ -163,9 +172,10 @@
|
||||
|
||||
if($product->type != 'normal')
|
||||
{
|
||||
$branchStatus = $this->branch->getByID($plan->branch, 0, 'status');
|
||||
$branchStatus = isset($branchStatusList[$plan->branch]) ? $branchStatusList[$plan->branch] : '';
|
||||
if($branchStatus == 'closed') $disabled = 'disabled';
|
||||
}
|
||||
if(in_array($plan->status, array('done', 'closed'))) $disabled = 'disabled';
|
||||
|
||||
if($config->systemMode == 'new')
|
||||
{
|
||||
@@ -181,8 +191,14 @@
|
||||
common::printIcon('productplan', 'edit', "planID=$plan->id", $plan, 'list');
|
||||
if(common::hasPriv('productplan', 'create', $plan))
|
||||
{
|
||||
if($plan->parent > '0') echo "<button type='button' class='disabled btn'><i class='disabled icon-split' title='{$this->lang->productplan->children}'></i></button> ";
|
||||
if($plan->parent <= '0') echo html::a($this->createLink('productplan', 'create', "product=$productID&branch=$branch&parent={$plan->id}"), "<i class='icon-split'></i>", '', "class='btn' title='{$this->lang->productplan->children}'");
|
||||
if($plan->parent > 0 or in_array($plan->status, array('done', 'closed')))
|
||||
{
|
||||
echo "<button type='button' class='disabled btn'><i class='disabled icon-split' title='{$this->lang->productplan->children}'></i></button> ";
|
||||
}
|
||||
else
|
||||
{
|
||||
echo html::a($this->createLink('productplan', 'create', "product=$productID&branch=$branch&parent={$plan->id}"), "<i class='icon-split'></i>", '', "class='btn' title='{$this->lang->productplan->children}'");
|
||||
}
|
||||
}
|
||||
|
||||
if(common::hasPriv('productplan', 'delete', $plan))
|
||||
@@ -214,31 +230,3 @@
|
||||
</form>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
<div class="modal fade" id="projects">
|
||||
<div class="modal-dialog mw-500px">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title"><?php echo $lang->productplan->selectProjects;?></h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<table class='table table-form'>
|
||||
<tr>
|
||||
<th><?php echo $lang->productplan->project?></th>
|
||||
<td><?php echo html::select('project', $projects, '', "class='form-control chosen'");?></td>
|
||||
</tr>
|
||||
<tr class='tips hidden'>
|
||||
<th></th>
|
||||
<td><span class='text-red'><?php echo $lang->productplan->noLinkedProject;?></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan='2' class='text-center'>
|
||||
<?php echo html::hidden('planID', '');?>
|
||||
<?php echo html::commonButton($lang->productplan->nextStep, "id='createExecutionButton'", 'btn btn-primary btn-wide');?>
|
||||
<?php echo html::commonButton($lang->cancel, "data-dismiss='modal'", 'btn btn-default btn-wide');?>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -10,11 +10,8 @@
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
?>
|
||||
<style>
|
||||
.table-form {margin-top: 90px;}
|
||||
.form-actions {height:160px;}
|
||||
</style>
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<?php include '../../common/view/kindeditor.html.php';?>
|
||||
<div id='mainContent' class='main-content'>
|
||||
<div class='center-block'>
|
||||
<div class='main-header'>
|
||||
@@ -31,7 +28,11 @@
|
||||
<td colspan='2'><?php echo html::input('end', $plan->end != '2030-01-01' ? formatTime($plan->end) : '', 'class="form-control form-date"');?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan='4' class='text-center form-actions'>
|
||||
<th><?php echo $lang->productplan->desc;?></th>
|
||||
<td colspan='4'><?php echo html::textarea('desc', $plan->desc, 'class="form-control"');?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan='5' class='text-center form-actions'>
|
||||
<?php echo html::submitButton($lang->productplan->start);?>
|
||||
<?php echo html::commonButton($lang->cancel, "data-dismiss='modal'", 'btn btn-wide');?>
|
||||
</td>
|
||||
|
||||
@@ -59,11 +59,12 @@
|
||||
common::printLink('productplan', 'finish', "planID=$plan->id", "<i class='icon-checked'></i>{$lang->productplan->finishAB}", '', "class='btn btn-link {$class}' target='hiddenwin' title='{$lang->productplan->finish}'", '', false, $plan);
|
||||
$class = $plan->status == 'done' ? '' : 'disabled';
|
||||
common::printLink('productplan', 'close', "planID=$plan->id", "<i class='icon-off'></i>{$lang->productplan->closeAB}", '', "class='btn btn-link {$class}' target='hiddenwin' title='{$lang->productplan->close}'", '', false, $plan);
|
||||
$class = $plan->status == 'closed' ? '' : 'disabled';
|
||||
$class = in_array($plan->status, array('closed', 'done')) ? '' : 'disabled';
|
||||
common::printLink('productplan', 'activate', "planID=$plan->id", "<i class='icon-magic'></i>{$lang->productplan->activateAB}", '', "class='btn btn-link {$class}' target='hiddenwin' title='{$lang->productplan->activate}'", '', false, $plan);
|
||||
}
|
||||
|
||||
if(common::hasPriv('productplan', 'create', $plan) and $plan->parent <= '0') echo html::a($this->createLink('productplan', 'create', "product={$plan->product}&branch={$plan->branch}&parent={$plan->id}"), "<i class='icon-split'></i> " . $this->lang->productplan->children , '', "class='btn btn-link' title='{$this->lang->productplan->children}'");
|
||||
$class = in_array($plan->status, array('done', 'closed')) ? 'disabled' : '';
|
||||
if(common::hasPriv('productplan', 'create', $plan) and $plan->parent <= 0) echo html::a($this->createLink('productplan', 'create', "product={$plan->product}&branch={$plan->branch}&parent={$plan->id}"), "<i class='icon-split'></i> " . $this->lang->productplan->children , '', "class='btn btn-link {$class}' title='{$this->lang->productplan->children}'");
|
||||
if(common::hasPriv('productplan', 'edit', $plan)) echo html::a($this->createLink('productplan', 'edit', "planID=$plan->id"), "<i class='icon-common-edit icon-edit'></i> " . $this->lang->edit, '', "class='btn btn-link' title='{$this->lang->edit}'");
|
||||
if(common::hasPriv('productplan', 'delete', $plan) and $plan->parent >= 0) echo html::a($this->createLink('productplan', 'delete', "planID=$plan->id"), "<i class='icon-common-delete icon-trash'></i> " . $this->lang->delete, '', "class='btn btn-link' title='{$this->lang->delete}' target='hiddenwin'");
|
||||
}
|
||||
|
||||
@@ -145,6 +145,7 @@ class programplan extends control
|
||||
$this->view->plans = $this->programplan->getStage($planID ? $planID : $projectID, $this->productID, 'parent');
|
||||
$this->view->planID = $planID;
|
||||
$this->view->type = 'lists';
|
||||
$this->view->PMUsers = $this->loadModel('user')->getPairs('noclosed|nodeleted|pmfirst', $project->PM);
|
||||
|
||||
$this->display();
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ function addItem(obj)
|
||||
var newItem = $('#names' + i).closest('tr');
|
||||
newItem.find('.form-date').datepicker();
|
||||
$("#output" + i).chosen();
|
||||
$("#PM_i__chosen").remove();
|
||||
$("#PM" + i).chosen();
|
||||
$("#output_i__chosen").remove();
|
||||
i ++;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ $lang->programplan->createSubPlan = 'Create Sub Stage';
|
||||
$lang->programplan->parent = 'Parent Stage';
|
||||
$lang->programplan->emptyParent = 'N/A';
|
||||
$lang->programplan->name = 'Stage Name';
|
||||
$lang->programplan->PM = 'Stage Manager';
|
||||
$lang->programplan->subStageName = 'Sub Stage Name';
|
||||
$lang->programplan->percent = 'Workload Ratio';
|
||||
$lang->programplan->percentAB = 'Ratio';
|
||||
|
||||
@@ -21,6 +21,7 @@ $lang->programplan->createSubPlan = '创建二级阶段';
|
||||
$lang->programplan->parent = '父阶段';
|
||||
$lang->programplan->emptyParent = '无';
|
||||
$lang->programplan->name = '阶段名称';
|
||||
$lang->programplan->PM = '阶段负责人';
|
||||
$lang->programplan->subStageName = '子阶段名称';
|
||||
$lang->programplan->percent = '工作量占比';
|
||||
$lang->programplan->percentAB = '工作量占比';
|
||||
|
||||
@@ -409,8 +409,6 @@ class programplanModel extends model
|
||||
$parentACL = $parentStage->acl;
|
||||
}
|
||||
|
||||
$attributes = array_values($attributes);
|
||||
$milestone = array_values($milestone);
|
||||
$datas = array();
|
||||
foreach($names as $key => $name)
|
||||
{
|
||||
@@ -431,6 +429,7 @@ class programplanModel extends model
|
||||
$plan->realEnd = empty($realEnd[$key]) ? '0000-00-00' : $realEnd[$key];
|
||||
$plan->output = empty($output[$key]) ? '' : implode(',', $output[$key]);
|
||||
$plan->acl = empty($parentID) ? $acl[$key] : $parentACL;
|
||||
$plan->PM = empty($PM[$key]) ? '' : $PM[$key];
|
||||
|
||||
$datas[] = $plan;
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
<thead>
|
||||
<tr class='text-center'>
|
||||
<th class='required'><?php echo $name;?></th>
|
||||
<th class='w-110px'><?php echo $lang->programplan->PM;?></th>
|
||||
<th class='w-110px'>
|
||||
<?php echo $lang->programplan->percent;?>
|
||||
<?php if($planID):?>
|
||||
@@ -69,20 +70,21 @@
|
||||
<?php if(empty($plans) and $planID == 0):?>
|
||||
<?php foreach($stages as $stage):?>
|
||||
<tr>
|
||||
<td><input type='text' name='names[]' id='names<?php echo $i;?>' value='<?php echo $stage->name;?>' class='form-control' /></td>
|
||||
<td><input type='text' name='names[<?php echo $i;?>]' id='names<?php echo $i;?>' value='<?php echo $stage->name;?>' class='form-control' /></td>
|
||||
<td><?php echo html::select("PM[$i]", $PMUsers, '', "class='form-control chosen'");?></td>
|
||||
<td>
|
||||
<div class='input-group'>
|
||||
<input type='text' name='percents[]' id='percent<?php echo $i;?>' value='<?php echo $stage->percent;?>' class='form-control'/>
|
||||
<input type='text' name='percents[<?php echo $i;?>]' id='percent<?php echo $i;?>' value='<?php echo $stage->percent;?>' class='form-control'/>
|
||||
<span class='input-group-addon'>%</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class='<?php echo $hideAttribute?>'><?php echo html::select("attributes[$i]", $lang->stage->typeList, $stage->type, "class='form-control'");?></td>
|
||||
<td><?php echo html::select("acl[]", $lang->project->aclList, 'open', "class='form-control' $class");?></td>
|
||||
<td><?php echo html::select("acl[$i]", $lang->project->aclList, 'open', "class='form-control' $class");?></td>
|
||||
<td><?php echo html::radio("milestone[$i]", $lang->programplan->milestoneList, 0);?></td>
|
||||
<td><input type='text' name='begin[]' id='begin<?php echo $i;?>' value='' class='form-control form-date' /></td>
|
||||
<td><input type='text' name='end[]' id='end<?php echo $i;?>' value='' class='form-control form-date' /></td>
|
||||
<td><input type='text' name='realBegan[]' id='realBegan<?php echo $i;?>' value='' class='form-control form-date' /></td>
|
||||
<td><input type='text' name='realEnd[]' id='realEnd<?php echo $i;?>' value='' class='form-control form-date' /></td>
|
||||
<td><input type='text' name='begin[<?php echo $i;?>]' id='begin<?php echo $i;?>' value='' class='form-control form-date' /></td>
|
||||
<td><input type='text' name='end[<?php echo $i;?>]' id='end<?php echo $i;?>' value='' class='form-control form-date' /></td>
|
||||
<td><input type='text' name='realBegan[<?php echo $i;?>]' id='realBegan<?php echo $i;?>' value='' class='form-control form-date' /></td>
|
||||
<td><input type='text' name='realEnd[<?php echo $i;?>]' id='realEnd<?php echo $i;?>' value='' class='form-control form-date' /></td>
|
||||
<?php if(isset($this->config->qcVersion)):?>
|
||||
<td><?php echo html::select("output[$i][]", $documentList, '', "class='form-control chosen' multiple");?></td>
|
||||
<?php endif;?>
|
||||
@@ -98,22 +100,23 @@
|
||||
<?php if(!empty($plans)):?>
|
||||
<?php foreach($plans as $plan):?>
|
||||
<?php $disabled = $plan->setMilestone ? '' : "disabled='disabled'"?>
|
||||
<?php echo html::hidden('planIDList[]', $plan->id);?>
|
||||
<?php echo html::hidden("planIDList[$i]", $plan->id);?>
|
||||
<tr>
|
||||
<td><input type='text' name="names[]" id='names<?php echo $i;?>' value='<?php echo $plan->name;?>' class='form-control' /></td>
|
||||
<td><input type='text' name="names[<?php echo $i;?>]" id='names<?php echo $i;?>' value='<?php echo $plan->name;?>' class='form-control' /></td>
|
||||
<td><?php echo html::select("PM[$i]", $PMUsers, '', "class='form-control chosen'");?></td>
|
||||
<td>
|
||||
<div class='input-group'>
|
||||
<input type='text' name='percents[]' id='percent<?php echo $i;?>' value='<?php echo $plan->percent;?>' class='form-control' />
|
||||
<input type='text' name='percents[<?php echo $i;?>]' id='percent<?php echo $i;?>' value='<?php echo $plan->percent;?>' class='form-control' />
|
||||
<span class='input-group-addon'>%</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class='<?php echo $hideAttribute?>'><?php echo html::select("attributes[$i]", $lang->stage->typeList, $plan->attribute, "class='form-control'");?></td>
|
||||
<td><?php echo html::select("acl[]", $lang->project->aclList, $plan->acl, "class='form-control' $class");?></td>
|
||||
<td><?php echo html::select("acl[$i]", $lang->project->aclList, $plan->acl, "class='form-control' $class");?></td>
|
||||
<td><?php echo html::radio("milestone[$i]", $lang->programplan->milestoneList, $plan->milestone, $disabled);?></td>
|
||||
<td><input type='text' name='begin[] ' id='begin<?php echo $i;?>' value='<?php echo $plan->begin;?>' class='form-control form-date' /></td>
|
||||
<td><input type='text' name='end[]' id='end<?php echo $i;?>' value='<?php echo $plan->end;?>' class='form-control form-date' /></td>
|
||||
<td><input type='text' name='realBegan[] ' id='realBegan<?php echo $i;?>' value='<?php echo $plan->realBegan;?>' class='form-control form-date' /></td>
|
||||
<td><input type='text' name='realEnd[]' id='realEnd<?php echo $i;?>' value='<?php echo $plan->realEnd;?>' class='form-control form-date' /></td>
|
||||
<td><input type='text' name='begin[<?php echo $i;?>] ' id='begin<?php echo $i;?>' value='<?php echo $plan->begin;?>' class='form-control form-date' /></td>
|
||||
<td><input type='text' name='end[<?php echo $i;?>]' id='end<?php echo $i;?>' value='<?php echo $plan->end;?>' class='form-control form-date' /></td>
|
||||
<td><input type='text' name='realBegan[<?php echo $i;?>] ' id='realBegan<?php echo $i;?>' value='<?php echo $plan->realBegan;?>' class='form-control form-date' /></td>
|
||||
<td><input type='text' name='realEnd[<?php echo $i;?>]' id='realEnd<?php echo $i;?>' value='<?php echo $plan->realEnd;?>' class='form-control form-date' /></td>
|
||||
<?php if(isset($this->config->qcVersion)):?>
|
||||
<?php $option = empty($plan->output) ? 0 : explode(',', $plan->output);?>
|
||||
<td><?php echo html::select("output[$i][]", $documentList, $option, "class='form-control chosen' multiple");?></td>
|
||||
@@ -128,20 +131,21 @@
|
||||
|
||||
<?php for($j = 0; $j < 5; $j ++):?>
|
||||
<tr class='addedItem'>
|
||||
<td><input type='text' name='names[]' id='names<?php echo $i;?>' value='' class='form-control' /></td>
|
||||
<td><input type='text' name='names[<?php echo $i;?>]' id='names<?php echo $i;?>' value='' class='form-control' /></td>
|
||||
<td><?php echo html::select("PM[$i]", $PMUsers, '', "class='form-control chosen'");?></td>
|
||||
<td>
|
||||
<div class='input-group'>
|
||||
<input type='text' name='percents[]' id='percent<?php echo $i;?>' value='' class='form-control' />
|
||||
<input type='text' name='percents[<?php echo $i;?>]' id='percent<?php echo $i;?>' value='' class='form-control' />
|
||||
<span class='input-group-addon'>%</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class='<?php echo $hideAttribute?>'><?php echo html::select("attributes[$i]", $lang->stage->typeList, '', "class='form-control'");?></td>
|
||||
<td><?php echo html::select("acl[]", $lang->project->aclList, 'open', "class='form-control' $class");?></td>
|
||||
<td><?php echo html::select("acl[$i]", $lang->project->aclList, 'open', "class='form-control' $class");?></td>
|
||||
<td><?php echo html::radio("milestone[$i]", $lang->programplan->milestoneList, 0);?></td>
|
||||
<td><input type='text' name='begin[] ' id='begin<?php echo $i;?>' value='' class='form-control form-date' /></td>
|
||||
<td><input type='text' name='end[]' id='end<?php echo $i;?>' value='' class='form-control form-date' /></td>
|
||||
<td><input type='text' name='realBegan[] ' id='realBegan<?php echo $i;?>' value='' class='form-control form-date' /></td>
|
||||
<td><input type='text' name='realEnd[]' id='realEnd<?php echo $i;?>' value='' class='form-control form-date' /></td>
|
||||
<td><input type='text' name='begin[<?php echo $i;?>] ' id='begin<?php echo $i;?>' value='' class='form-control form-date' /></td>
|
||||
<td><input type='text' name='end[<?php echo $i;?>]' id='end<?php echo $i;?>' value='' class='form-control form-date' /></td>
|
||||
<td><input type='text' name='realBegan[<?php echo $i;?>] ' id='realBegan<?php echo $i;?>' value='' class='form-control form-date' /></td>
|
||||
<td><input type='text' name='realEnd[<?php echo $i;?>]' id='realEnd<?php echo $i;?>' value='' class='form-control form-date' /></td>
|
||||
<?php if(isset($this->config->qcVersion)):?>
|
||||
<td><?php echo html::select("output[$i][]", $documentList, '', "class='form-control chosen' multiple");?></td>
|
||||
<?php endif;?>
|
||||
@@ -167,21 +171,22 @@
|
||||
<?php $i = '%i%';?>
|
||||
<table class='hidden'>
|
||||
<tr id='addItem' class='hidden'>
|
||||
<td><input type='text' name='names[]' id='names<?php echo $i;?>' class='form-control' /></td>
|
||||
<?php echo html::hidden('planIDList[]', 0);?>
|
||||
<td><input type='text' name='<?php echo "names[$i]";?>' id='names<?php echo $i;?>' class='form-control' /></td>
|
||||
<td><?php echo html::select("PM[$i]", $PMUsers, '', "class='form-control chosen' id='PM$i'");?></td>
|
||||
<?php echo html::hidden("planIDList[$i]", 0);?>
|
||||
<td>
|
||||
<div class='input-group'>
|
||||
<input type='text' name='percents[]' id='percent<?php echo $i;?>' class='form-control' />
|
||||
<input type='text' name='<?php echo "percents[$i]";?>' id='percent<?php echo $i;?>' class='form-control' />
|
||||
<span class='input-group-addon'>%</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class='<?php echo $hideAttribute?>'><?php echo html::select("attributes[$i]", $lang->stage->typeList, '', "class='form-control'");?></td>
|
||||
<td><?php echo html::select("acl[]", $lang->project->aclList, 'open', "class='form-control' $class");?></td>
|
||||
<td><?php echo html::select("acl[$i]", $lang->project->aclList, 'open', "class='form-control' $class");?></td>
|
||||
<td><?php echo html::radio("milestone[$i]", $lang->programplan->milestoneList, 0);?></td>
|
||||
<td><input type='text' name='begin[] ' id='begin<?php echo $i;?>' class='form-control form-date' /></td>
|
||||
<td><input type='text' name='end[]' id='end<?php echo $i;?>' class='form-control form-date' /></td>
|
||||
<td><input type='text' name='realBegan[] ' id='realBegan<?php echo $i;?>' class='form-control form-date' /></td>
|
||||
<td><input type='text' name='realEnd[]' id='realEnd<?php echo $i;?>' class='form-control form-date' /></td>
|
||||
<td><input type='text' name='<?php echo "begin[$i]";?>' id='begin<?php echo $i;?>' class='form-control form-date' /></td>
|
||||
<td><input type='text' name='<?php echo "end[$i]";?>' id='end<?php echo $i;?>' class='form-control form-date' /></td>
|
||||
<td><input type='text' name='<?php echo "realBegan[$i]";?>' id='realBegan<?php echo $i;?>' class='form-control form-date' /></td>
|
||||
<td><input type='text' name='<?php echo "realEnd[$i]";?>' id='realEnd<?php echo $i;?>' class='form-control form-date' /></td>
|
||||
<?php if(isset($this->config->qcVersion)):?>
|
||||
<td><?php echo html::select("output[$i][]", $documentList, '', "class='form-control chosen ' multiple");?></td>
|
||||
<?php endif;?>
|
||||
|
||||
@@ -129,3 +129,7 @@ $config->project->removePriv['project'] = array('index', 'browse', 'kanban', '
|
||||
$config->project->removePriv['bug'] = array('batchChangePlan');
|
||||
$config->project->removePriv['doc'] = array('catalog', 'index');
|
||||
$config->project->removePriv['auditplan'] = array('delete');
|
||||
|
||||
$config->project->checkList = new stdclass();
|
||||
$config->project->checkList->scrum = array('bug', 'execution', 'meeting', 'release', 'build', 'doc', 'testtask', 'risk', 'issue', 'case');
|
||||
$config->project->checkList->waterfall = array('execution', 'design', 'doc', 'bug', 'case', 'build', 'release', 'testtask', 'review', 'build', 'researchplan', 'issue', 'risk', 'opportunity', 'auditplan', 'gapanalysis', 'meeting');
|
||||
|
||||
@@ -593,6 +593,9 @@ class project extends control
|
||||
}
|
||||
}
|
||||
|
||||
$canChangeModel = $this->project->checkCanChangeModel($projectID, $project->model);
|
||||
$disableModel = $canChangeModel == true ? '' : 'disabled';
|
||||
|
||||
$this->view->title = $this->lang->project->edit;
|
||||
$this->view->position[] = $this->lang->project->edit;
|
||||
|
||||
@@ -617,6 +620,8 @@ class project extends control
|
||||
$this->view->parentProgram = $this->program->getByID($project->parent);
|
||||
$this->view->availableBudget = $this->program->getBudgetLeft($parentProject) + (float)$project->budget;
|
||||
$this->view->budgetUnitList = $this->project->getBudgetUnitList();
|
||||
$this->view->model = $project->model;
|
||||
$this->view->disableModel = $disableModel;
|
||||
|
||||
$this->display();
|
||||
}
|
||||
|
||||
@@ -259,8 +259,8 @@ $lang->project->membersUnit = '%s men';
|
||||
$lang->project->lastIteration = "Recent {$lang->executionCommon}";
|
||||
$lang->project->ongoingStage = 'Ongoing stage';
|
||||
$lang->project->scrum = 'Scrum';
|
||||
$lang->project->waterfall = 'CMMI';
|
||||
$lang->project->waterfallTitle = 'CMMI';
|
||||
$lang->project->waterfall = 'Waterfall';
|
||||
$lang->project->waterfallTitle = 'Waterfall project management';
|
||||
$lang->project->cannotCreateChild = 'It is not empty, so you cannot add a child. You can add a parent for it, and then create a child.';
|
||||
$lang->project->confirmDelete = "Do you want to delete [%s]?";
|
||||
$lang->project->emptyPM = 'No manager';
|
||||
|
||||
@@ -2086,4 +2086,52 @@ class projectModel extends model
|
||||
if(!$this->common->isOpenMethod($moduleName, $methodName) and !commonModel::hasPriv($moduleName, $methodName)) $this->common->deny($moduleName, $methodName, false);
|
||||
common::setMenuVars('project', $objectID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the project model can be changed.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @param string $model
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function checkCanChangeModel($projectID, $model)
|
||||
{
|
||||
$checkList = $this->config->project->checkList->$model;
|
||||
foreach($checkList as $module)
|
||||
{
|
||||
if($module == '') continue;
|
||||
|
||||
$type = '';
|
||||
$table = constant('TABLE_'. strtoupper($module));
|
||||
$object = new stdclass();
|
||||
|
||||
if($table == TABLE_EXECUTION)
|
||||
{
|
||||
$type = $model == 'scrum' ? 'sprint' : 'stage';
|
||||
}
|
||||
|
||||
$object = $this->getDataByProject($table, $projectID, $type);
|
||||
if(!empty($object)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the objects under the project.
|
||||
*
|
||||
* @param constant $table
|
||||
* @param int $projectID
|
||||
* @param string $type
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function getDataByProject($table, $projectID, $type = '')
|
||||
{
|
||||
$result = $this->dao->select('id')->from($table)
|
||||
->where('project')->eq($projectID)
|
||||
->beginIF(!empty($type))->andWhere('type')->eq($type)->fi()
|
||||
->fetch();
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,10 @@
|
||||
</div>
|
||||
<form class='form-indicator main-form form-ajax' method='post' target='hiddenwin' id='dataform'>
|
||||
<table class='table table-form'>
|
||||
<tr>
|
||||
<th><?php echo $lang->project->model;?></th>
|
||||
<td><?php echo html::select('model', $lang->project->modelList, $model, "class='form-control chosen' required $disableModel");?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class='w-120px'><?php echo $lang->program->parent;?></th>
|
||||
<?php
|
||||
@@ -183,7 +187,6 @@
|
||||
<tr>
|
||||
<td colspan='4' class='text-center form-actions'>
|
||||
<?php
|
||||
echo html::hidden('model', $project->model);
|
||||
echo html::submitButton();
|
||||
if(!isonlybody()) echo html::backButton();
|
||||
?>
|
||||
|
||||
@@ -193,7 +193,7 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->execution->totalEstimate;?></th>
|
||||
<td><?php echo (float)$workhour->totalEstimate . $lang->execution->workHour;?></td>
|
||||
<td><?php echo (float)$workhour->totalEstimate . $lang->execution->workHour;?></td>
|
||||
<th><?php echo $lang->execution->totalDays;?></th>
|
||||
<td><?php echo $project->days;?></td>
|
||||
</tr>
|
||||
|
||||
Reference in New Issue
Block a user