Merge branch 'feature/projecttpl2.0' into release/21.7.3
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE `zt_project` ADD `tplAcl` char(30) NOT NULL DEFAULT 'open' AFTER `whitelist`;
|
||||
ALTER TABLE `zt_project` ADD `tplWhiteList` text NULL AFTER `tplAcl`;
|
||||
@@ -1615,6 +1615,8 @@ CREATE TABLE IF NOT EXISTS `zt_project` (
|
||||
`team` varchar(90) NOT NULL DEFAULT '',
|
||||
`acl` char(30) NOT NULL DEFAULT 'open',
|
||||
`whitelist` text NULL,
|
||||
`tplAcl` char(30) NOT NULL DEFAULT 'open',
|
||||
`tplWhiteList` text NULL,
|
||||
`order` mediumint(8) unsigned NOT NULL DEFAULT '0',
|
||||
`vision` varchar(10) NOT NULL DEFAULT 'rnd',
|
||||
`stageBy` enum('project','product') NOT NULL DEFAULT 'product',
|
||||
|
||||
@@ -534,6 +534,16 @@ class control extends baseControl
|
||||
|
||||
$uiID = $this->loadModel('workflowlayout')->getUIByData($flow->module, $action->action, $object);
|
||||
$fieldList = $this->workflowaction->getPageFields($flow->module, $action->action, true, null, $uiID, $groupID);
|
||||
|
||||
/* 复制项目时显示被复制项目的工作流字段值。*/
|
||||
if($moduleName == 'project' && $methodName == 'create')
|
||||
{
|
||||
foreach($fieldList as $field)
|
||||
{
|
||||
$objectValue = zget($object, $field->field, '');
|
||||
if($objectValue) $field->default = $objectValue;
|
||||
}
|
||||
}
|
||||
return $this->loadModel('flow')->buildFormFields($fields, $fieldList, array(), $object);
|
||||
}
|
||||
|
||||
|
||||
@@ -225,6 +225,7 @@ class dao extends baseDAO
|
||||
$method = $this->app->getMethodName();
|
||||
if($module == 'story' && $this->app->rawModule == 'requirement') $module = 'requirement';
|
||||
if($module == 'story' && $this->app->rawModule == 'epic') $module = 'epic';
|
||||
if($module == 'project' && $method == 'createtemplate') $method = 'create';
|
||||
|
||||
$flowAction = $this->dbh->query("SELECT * FROM " . TABLE_WORKFLOWACTION . " WHERE `module` = '{$module}' AND `action` = '{$method}' AND `buildin` = '1' AND `extensionType` = 'extend' AND `vision` = '{$this->config->vision}'")->fetch(PDO::FETCH_OBJ);
|
||||
if(!$flowAction) return $this;
|
||||
|
||||
@@ -119,6 +119,10 @@ class form extends fixer
|
||||
if($moduleName == 'projectrelease') $moduleName = 'release';
|
||||
if($moduleName == 'projectbuild') $moduleName = 'build';
|
||||
|
||||
/* 项目复制用项目创建的工作流。 */
|
||||
if($moduleName == 'project' && $methodName == 'copyconfirm') $methodName = 'create';
|
||||
if($moduleName == 'project' && $methodName == 'edittemplate') $methodName = 'edit';
|
||||
|
||||
/* 用户需求和业务需求用自己的工作流。*/
|
||||
if($moduleName == 'story' && $app->rawModule == 'requirement') $moduleName = 'requirement';
|
||||
if($moduleName == 'story' && $app->rawModule == 'epic') $moduleName = 'epic';
|
||||
|
||||
@@ -3,3 +3,4 @@
|
||||
#pick-pop-admin-menu .dropmenu-item + .dropmenu-item {margin-top: 4px}
|
||||
#pick-pop-admin-menu .dropmenu-item.active {background-color: unset;}
|
||||
#pick-pop-admin-menu .dropmenu-item:hover {color: rgba(var(--color-primary-500-rgb),var(--tw-text-opacity)); background-color: rgba(var(--color-primary-50-rgb),var(--tw-bg-opacity));}
|
||||
.dropmenu-item .item-content .label {flex-shrink: 0;}
|
||||
@@ -77,12 +77,13 @@ class formPanel extends panel
|
||||
{
|
||||
global $app;
|
||||
$moduleName = $app->getModuleName();
|
||||
$methodName = $app->getMethodName();
|
||||
if($moduleName == 'caselib') return data('lib');
|
||||
if($moduleName == 'flow') return data('data');
|
||||
if($moduleName == 'productplan') return data('plan');
|
||||
if($moduleName == 'projectrelease') return data('release');
|
||||
if($moduleName == 'projectbuild') return data('build');
|
||||
if($moduleName == 'project' && $app->getMethodName() == 'create') return data('copyProject');
|
||||
if($moduleName == 'project' && ($methodName == 'create' or $methodName == 'createtemplate')) return data('copyProject') ? data('copyProject') : null;
|
||||
return data($moduleName);
|
||||
}
|
||||
|
||||
@@ -105,6 +106,9 @@ class formPanel extends panel
|
||||
}
|
||||
}
|
||||
|
||||
if($moduleName == 'project' && $methodName == 'createtemplate') $methodName = 'create';
|
||||
if($moduleName == 'project' && $methodName == 'edittemplate') $methodName = 'edit';
|
||||
|
||||
/* 反馈转化。 */
|
||||
if($moduleName == 'feedback')
|
||||
{
|
||||
|
||||
@@ -211,6 +211,12 @@ class datatable extends control
|
||||
if(!$execution->hasProduct) unset($cols['branch']);
|
||||
}
|
||||
|
||||
if($module == 'project' && $method == 'execution')
|
||||
{
|
||||
$project = $this->datatable->fetchByID($this->session->project, 'project');
|
||||
if(!empty($project->isTpl)) unset($cols['deliverable']);
|
||||
}
|
||||
|
||||
if($extra == 'unsetStory' && isset($cols['story'])) unset($cols['story']);
|
||||
|
||||
if($this->config->edition == 'ipd' && $module == 'product' && $method == 'browse' && $extra == 'story') unset($cols['roadmap']);
|
||||
|
||||
+11
-5
@@ -367,6 +367,7 @@ class doc extends control
|
||||
public function createLib(string $type = '', int $objectID = 0, int $libID = 0)
|
||||
{
|
||||
$this->app->loadLang('api');
|
||||
$this->doc->setMenuByType($type, (int)$objectID, (int)$libID);
|
||||
|
||||
if(!empty($_POST))
|
||||
{
|
||||
@@ -386,10 +387,10 @@ class doc extends control
|
||||
}
|
||||
|
||||
$objects = array();
|
||||
if($type == 'project' && $this->app->tab == 'doc')
|
||||
if($type == 'project')
|
||||
{
|
||||
$this->view->executionPairs = $this->execution->getPairs($objectID, 'all', 'multiple,leaf,noprefix');
|
||||
$this->view->project = $this->project->getById($objectID);
|
||||
$this->view->project = $this->project->getById($objectID);
|
||||
if($this->app->tab == 'doc') $this->view->executionPairs = $this->execution->getPairs($objectID, 'all', 'multiple,leaf,noprefix');
|
||||
}
|
||||
|
||||
if($type == 'execution')
|
||||
@@ -397,6 +398,7 @@ class doc extends control
|
||||
$objects = $this->execution->getPairs(0, 'all', 'multiple,leaf,noprefix,withobject');
|
||||
$execution = $this->execution->getByID($objectID);
|
||||
if($execution->type == 'stage') $this->lang->doc->execution = str_replace($this->lang->executionCommon, $this->lang->project->stage, $this->lang->doc->execution);
|
||||
$this->view->execution = $this->doc->fetchByID($objectID, 'execution');
|
||||
}
|
||||
|
||||
if($type == 'custom' || $type == 'mine' || $type == 'doctemplate')
|
||||
@@ -456,6 +458,11 @@ class doc extends control
|
||||
{
|
||||
if(!common::hasPriv('doc', 'editSpace') && !common::hasPriv('doc', 'editLib')) return;
|
||||
$lib = $this->doc->getLibByID($libID);
|
||||
|
||||
if($lib->type != 'project') $this->docZen->setAclForEditLib($lib);
|
||||
$this->doc->setMenuByType($lib->type, (int)zget($lib, $lib->type, 0), (int)$libID);
|
||||
if($lib->type == 'project') $this->docZen->setAclForEditLib($lib);
|
||||
|
||||
if(!empty($_POST))
|
||||
{
|
||||
$this->lang->doc->name = $this->lang->nameAB;
|
||||
@@ -499,8 +506,6 @@ class doc extends control
|
||||
$this->view->object = $execution;
|
||||
}
|
||||
|
||||
$this->docZen->setAclForEditLib($lib);
|
||||
|
||||
$this->view->lib = $lib;
|
||||
$this->view->groups = $this->loadModel('group')->getPairs();
|
||||
$this->view->users = $this->user->getPairs('noletter|noclosed', $lib->users);
|
||||
@@ -2208,6 +2213,7 @@ class doc extends control
|
||||
$this->doc->setMenuByType($type, $spaceID, $libID);
|
||||
$objectKey = $type . 'ID';
|
||||
$this->view->$objectKey = $spaceID;
|
||||
$this->view->$type = $this->doc->fetchByID($spaceID, $type);
|
||||
}
|
||||
|
||||
if($type == 'mine') $menuType = 'my';
|
||||
|
||||
@@ -25,26 +25,27 @@ if($type === 'project')
|
||||
* 定义文档界面上的权限。
|
||||
* Define the privs of doc app.
|
||||
*/
|
||||
$hasCustomSpace = $type == 'mine' || $type == 'custom';
|
||||
$hasCustomSpace = $type == 'mine' || $type == 'custom';
|
||||
$projectTemplate = ($type === 'project' && !empty($project->isTpl)) || ($type == 'execution' && !empty($execution->isTpl));
|
||||
$privs = array();
|
||||
$privs['create'] = hasPriv('doc', 'create');
|
||||
$privs['edit'] = hasPriv('doc', 'edit');
|
||||
$privs['delete'] = hasPriv('doc', 'delete');
|
||||
$privs['create'] = hasPriv('doc', 'create') && !$projectTemplate;
|
||||
$privs['edit'] = hasPriv('doc', 'edit') && !$projectTemplate;
|
||||
$privs['delete'] = hasPriv('doc', 'delete') && !$projectTemplate;
|
||||
$privs['view'] = hasPriv('doc', 'view');
|
||||
$privs['effort'] = $this->config->edition != 'open' && hasPriv('effort', 'createForObject');
|
||||
$privs['exportDoc'] = $this->config->edition != 'open' && hasPriv('doc', $type . '2export');
|
||||
$privs['exportDoc'] = $this->config->edition != 'open' && hasPriv('doc', $type . '2export') && !$projectTemplate;
|
||||
$privs['exportApi'] = $this->config->edition != 'open' && hasPriv('api', 'export');
|
||||
$privs['moveDoc'] = hasPriv('doc', 'moveDoc');
|
||||
$privs['moveDoc'] = hasPriv('doc', 'moveDoc') && !$projectTemplate;
|
||||
$privs['collect'] = hasPriv('doc', 'collect');
|
||||
$privs['createLib'] = hasPriv('doc', 'createLib');
|
||||
$privs['editLib'] = hasPriv('doc', 'editLib');
|
||||
$privs['moveLib'] = hasPriv('doc', 'moveLib');
|
||||
$privs['moveLib'] = hasPriv('doc', 'moveLib') && !$projectTemplate;
|
||||
$privs['deleteLib'] = hasPriv('doc', 'deleteLib');
|
||||
$privs['sortDocLib'] = hasPriv('doc', 'sortDocLib');
|
||||
$privs['uploadFile'] = hasPriv('doc', 'create');
|
||||
$privs['uploadFile'] = hasPriv('doc', 'create') && !$projectTemplate;
|
||||
$privs['editFile'] = hasPriv('file', 'edit');
|
||||
$privs['deleteFile'] = hasPriv('doc', 'deleteFile');
|
||||
$privs['exportFiles'] = hasPriv('doc', 'exportFiles');
|
||||
$privs['exportFiles'] = hasPriv('doc', 'exportFiles') && !$projectTemplate;
|
||||
$privs['createSpace'] = $hasCustomSpace && hasPriv('doc', 'createSpace');
|
||||
$privs['deleteSpace'] = $hasCustomSpace && hasPriv('doc', 'deleteSpace');
|
||||
$privs['editSpace'] = $hasCustomSpace && hasPriv('doc', 'editSpace');
|
||||
|
||||
@@ -26,6 +26,7 @@ $renderObjectBox = function(string $type) use ($lang, $objects, $objectID)
|
||||
return formRow(
|
||||
setClass('objectBox'),
|
||||
formGroup(
|
||||
set::id('object'),
|
||||
set::width('5/6'),
|
||||
set::label($lang->doc->{$type}),
|
||||
set::name($type),
|
||||
|
||||
@@ -2738,7 +2738,7 @@ class execution extends control
|
||||
$executionGroups = $this->dao->select('*')->from(TABLE_EXECUTION) /* 按照项目分组,获取有权限访问的执行列表。*/
|
||||
->where('deleted')->eq('0')
|
||||
->andWhere('multiple')->eq('1')
|
||||
->andWhere('type')->in('sprint,stage,kanban')
|
||||
->andWhere('type')->in(!empty($execution->isTpl) ? 'sprint,stage' : 'sprint,stage,kanban')
|
||||
->beginIF(!$this->app->user->admin)->andWhere('id')->in($this->app->user->view->sprints)->fi()
|
||||
->beginIF(!empty($execution->isTpl))->andWhere('isTpl')->eq('1')->fi()
|
||||
->andWhere('project')->in(array_keys($projects))
|
||||
|
||||
@@ -153,7 +153,6 @@ class executionModel extends model
|
||||
|
||||
unset($this->lang->execution->menu->burn);
|
||||
unset($this->lang->execution->menu->kanban);
|
||||
unset($this->lang->execution->menu->view);
|
||||
unset($this->lang->execution->menu->story);
|
||||
unset($this->lang->execution->menu->qa);
|
||||
unset($this->lang->execution->menu->devops);
|
||||
@@ -162,6 +161,22 @@ class executionModel extends model
|
||||
unset($this->lang->execution->menu->effort);
|
||||
unset($this->lang->execution->menu->more);
|
||||
|
||||
if(!empty($this->lang->execution->menu->view['subMenu']->gantt))
|
||||
{
|
||||
$this->lang->execution->menu->gantt = $this->lang->execution->menu->view['subMenu']->gantt;
|
||||
|
||||
$taskOrder = 0;
|
||||
foreach($this->lang->execution->menuOrder as $order => $menu) if($menu == 'task') $taskOrder = $order;
|
||||
$this->lang->execution->menuOrder[$taskOrder + 1] = 'gantt';
|
||||
|
||||
if(!empty($this->lang->project->menuOrder))
|
||||
{
|
||||
$taskOrder = 0;
|
||||
foreach($this->lang->project->menuOrder as $order => $menu) if($menu == 'task') $taskOrder = $order;
|
||||
$this->lang->project->menuOrder[$taskOrder + 1] = 'gantt';
|
||||
}
|
||||
}
|
||||
|
||||
if(!empty($this->lang->execution->menu->other['dropMenu']->pssp))
|
||||
{
|
||||
$this->lang->execution->menu->pssp = $this->lang->execution->menu->other['dropMenu']->pssp;
|
||||
@@ -181,6 +196,7 @@ class executionModel extends model
|
||||
}
|
||||
}
|
||||
|
||||
unset($this->lang->execution->menu->view);
|
||||
unset($this->lang->execution->menu->other);
|
||||
if(isset($this->lang->execution->menu->settings['subMenu']->products)) unset($this->lang->execution->menu->settings['subMenu']->products); // 模板下隐藏产品
|
||||
if(isset($this->lang->execution->menu->settings['subMenu']->whitelist)) unset($this->lang->execution->menu->settings['subMenu']->whitelist); // 模板下隐藏白名单
|
||||
|
||||
@@ -1074,9 +1074,13 @@ $config->group->package->projectTemplate = new stdclass();
|
||||
$config->group->package->projectTemplate->order = 5;
|
||||
$config->group->package->projectTemplate->subset = 'projectTemplate';
|
||||
$config->group->package->projectTemplate->privs = array();
|
||||
$config->group->package->projectTemplate->privs['project-template'] = array('edition' => 'max,ipd', 'vision' => 'rnd', 'order' => 5, 'depend' => array('project-index'));
|
||||
$config->group->package->projectTemplate->privs['project-createTemplate'] = array('edition' => 'max,ipd', 'vision' => 'rnd', 'order' => 10, 'depend' => array('project-index', 'project-template'));
|
||||
$config->group->package->projectTemplate->privs['project-deleteTemplate'] = array('edition' => 'max,ipd', 'vision' => 'rnd', 'order' => 15, 'depend' => array('project-index', 'project-template'));
|
||||
$config->group->package->projectTemplate->privs['project-template'] = array('edition' => 'max,ipd', 'vision' => 'rnd', 'order' => 5, 'depend' => array('project-index'));
|
||||
$config->group->package->projectTemplate->privs['project-createTemplate'] = array('edition' => 'max,ipd', 'vision' => 'rnd', 'order' => 10, 'depend' => array('project-index', 'project-template'));
|
||||
$config->group->package->projectTemplate->privs['project-editTemplate'] = array('edition' => 'max,ipd', 'vision' => 'rnd', 'order' => 15, 'depend' => array('project-index', 'project-template'));
|
||||
$config->group->package->projectTemplate->privs['project-publishTemplate'] = array('edition' => 'max,ipd', 'vision' => 'rnd', 'order' => 20, 'depend' => array('project-index', 'project-template'));
|
||||
$config->group->package->projectTemplate->privs['project-disableTemplate'] = array('edition' => 'max,ipd', 'vision' => 'rnd', 'order' => 25, 'depend' => array('project-index', 'project-template'));
|
||||
$config->group->package->projectTemplate->privs['project-templatePriv'] = array('edition' => 'max,ipd', 'vision' => 'rnd', 'order' => 30, 'depend' => array('project-index', 'project-template'));
|
||||
$config->group->package->projectTemplate->privs['project-deleteTemplate'] = array('edition' => 'max,ipd', 'vision' => 'rnd', 'order' => 35, 'depend' => array('project-index', 'project-template'));
|
||||
|
||||
$config->group->package->browseExecution = new stdclass();
|
||||
$config->group->package->browseExecution->order = 5;
|
||||
|
||||
@@ -189,6 +189,9 @@ class projectModel extends model
|
||||
|
||||
$action = strtolower($action);
|
||||
|
||||
if($action == 'publishtemplate') return $project->status == 'wait' || $project->status == 'closed';
|
||||
if($action == 'disabletemplate') return $project->status == 'doing';
|
||||
|
||||
if($action == 'close') return $project->status != 'closed';
|
||||
if($action == 'group') return $project->model != 'kanban';
|
||||
if($action == 'start') return $project->status == 'wait' || $project->status == 'suspended';
|
||||
|
||||
@@ -9,7 +9,7 @@ $fields = defineFieldList('project');
|
||||
$model = data('model');
|
||||
$hasCode = !empty($config->setCode);
|
||||
$currency = data('parentProgram') ? data('parentProgram.budgetUnit') : $config->project->defaultCurrency;
|
||||
$disableStageBy = !empty(data('executions')) || data('app.rawMethod') == 'edit' ? true : false;
|
||||
$disableStageBy = !empty(data('executions')) || data('app.rawMethod') == 'edit' || !empty(data('copyProject'));
|
||||
|
||||
$fields->field('parent')
|
||||
->control('picker', array('required' => true))
|
||||
@@ -46,6 +46,18 @@ $fields->field('PM')->control('picker')->items(data('PMUsers'));
|
||||
|
||||
unset($lang->project->endList[999]);
|
||||
$isLongTime = data('project.end') == LONG_TIME;
|
||||
$copyProject = data('copyProject');
|
||||
if($copyProject)
|
||||
{
|
||||
$beginValue = $copyProject->begin;
|
||||
$endValue = $copyProject->end == LONG_TIME ? '' : $copyProject->end;
|
||||
}
|
||||
else
|
||||
{
|
||||
$beginValue = data('project.begin') ? data('project.begin') : date('Y-m-d');
|
||||
$endValue = data('project.end') == LONG_TIME ? '' : data('project.end');
|
||||
}
|
||||
|
||||
$fields->field('begin')
|
||||
->label($lang->project->planDate)
|
||||
->required()
|
||||
@@ -54,10 +66,10 @@ $fields->field('begin')
|
||||
->control('dateRangePicker')
|
||||
->beginName('begin')
|
||||
->beginPlaceholder($lang->project->begin)
|
||||
->beginValue(data('project.begin') ? data('project.begin') : date('Y-m-d'))
|
||||
->beginValue($beginValue)
|
||||
->endName('end')
|
||||
->endPlaceholder($lang->project->end)
|
||||
->endValue(data('project.end') == LONG_TIME ? '' : data('project.end'))
|
||||
->endValue($endValue)
|
||||
->endDisabled($isLongTime)
|
||||
->endList($lang->project->endList)
|
||||
->itemEnd()
|
||||
|
||||
@@ -47,10 +47,13 @@ $fields->field('days')
|
||||
->control('input', array('className' => $copyProject ? 'has-warning' : ''))
|
||||
->className($copyProject ? 'has-warning' : '')
|
||||
->tip($copyProject ? $lang->project->copyProject->daysTips : null)
|
||||
->value($copyProject ? data('copyProject.days') : '')
|
||||
->tipClass($copyProject ? 'text-warning' : null);
|
||||
|
||||
$fields->field('productsBox')->hidden(data('copyProject') && data('copyProject.hasProduct') == 0);
|
||||
|
||||
$fields->field('PM')->value(data('copyProject.PM'));
|
||||
$fields->field('budget')->value(data('copyProject.budget'));
|
||||
|
||||
$fields->field('budget')->foldable();
|
||||
|
||||
|
||||
@@ -60,6 +60,8 @@ if($canBatchAction)
|
||||
$fieldList = $config->project->execution->dtable->fieldList;
|
||||
$fieldList['status']['statusMap']['changed'] = $lang->task->storyChange;
|
||||
|
||||
if(!empty($project->isTpl)) unset($fieldList['deliverable']);
|
||||
|
||||
/* waterfall & waterfallplus & ipd model with different edit link. */
|
||||
if(in_array($project->model, array('waterfall', 'waterfallplus', 'ipd')))
|
||||
{
|
||||
|
||||
@@ -110,6 +110,10 @@ foreach($projects as $programID => $programProjects)
|
||||
{
|
||||
$link = $indexLink;
|
||||
}
|
||||
elseif(!empty($project->isTpl))
|
||||
{
|
||||
$link = helper::createLink('project', 'execution', "status=undone&projectID={$project->id}");
|
||||
}
|
||||
else
|
||||
{
|
||||
$link = $defaultLink;
|
||||
|
||||
Reference in New Issue
Block a user