diff --git a/config/config.php b/config/config.php index cf7f32fe11..5832892fe4 100644 --- a/config/config.php +++ b/config/config.php @@ -32,6 +32,7 @@ $config->methodVar = 'f'; // 请求类型为GET:模块 $config->viewVar = 't'; // 请求类型为GET:视图变量名。 requestType=GET: the view var name. $config->sessionVar = 'zentaosid'; // 请求类型为GET:session变量名。 requestType=GET: the session var name. $config->views = ',html,json,mhtml,xhtml,'; // 支持的视图类型。 Supported view formats. +$config->visions = ',rnd,lite,'; // 支持的界面类型。 Supported vision formats. /* 支持的主题和语言。Supported thems and languages. */ $config->themes['default'] = 'default'; diff --git a/db/update16.4.sql b/db/update16.4.sql index 1868e6b66c..934ce65547 100644 --- a/db/update16.4.sql +++ b/db/update16.4.sql @@ -1,3 +1,4 @@ +======= ALTER TABLE `zt_project` ADD `vision` varchar(10) NOT NULL DEFAULT 'rnd' AFTER `order`; ALTER TABLE `zt_product` ADD `vision` varchar(10) NOT NULL DEFAULT 'rnd' AFTER `order`; ALTER TABLE `zt_task` ADD `vision` varchar(10) NOT NULL DEFAULT 'rnd' AFTER `deleted`; @@ -16,3 +17,6 @@ ALTER TABLE `zt_block` ADD `vision` varchar(10) NOT NULL DEFAULT 'rnd' AFTER `ac ALTER TABLE `zt_block` DROP INDEX `account_module_type_order`, ADD UNIQUE `account_vision_module_type_order` (`account`, `vision`, `module`, `type`, `order`); ALTER TABLE `zt_effort` ADD `vision` varchar(10) NOT NULL DEFAULT 'rnd' AFTER `id`; ALTER TABLE `zt_story` ADD `vision` varchar(10) NOT NULL DEFAULT 'rnd' AFTER `id`; + +ALTER TABLE `zt_user` ADD `visions` varchar(20) NOT NULL AFTER `visits`; +UPDATE `zt_user` SET `visions`='rnd,lite'; diff --git a/extension/lite/action/ext/lang/zh-cn/lite.php b/extension/lite/action/ext/lang/zh-cn/lite.php index 20d56c85f2..8bb9e00e85 100644 --- a/extension/lite/action/ext/lang/zh-cn/lite.php +++ b/extension/lite/action/ext/lang/zh-cn/lite.php @@ -1,8 +1,8 @@ action->label->execution = "看板|execution|task|executionID=%s"; -$lang->action->label->task = '卡片|task|view|taskID=%s'; +$lang->action->label->task = '任务|task|view|taskID=%s'; -$lang->action->objectTypes['task'] = '卡片'; +$lang->action->objectTypes['task'] = '任务'; unset($lang->action->dynamicAction->program); unset($lang->action->dynamicAction->product); diff --git a/extension/lite/block/ext/lang/zh-cn/lite.php b/extension/lite/block/ext/lang/zh-cn/lite.php index 7ce135d69e..4d2c0d93f4 100644 --- a/extension/lite/block/ext/lang/zh-cn/lite.php +++ b/extension/lite/block/ext/lang/zh-cn/lite.php @@ -11,9 +11,9 @@ $lang->block->delayed = '已延期'; $lang->block->titleList['scrumlist'] = '看板列表'; $lang->block->titleList['sprint'] = '看板总览'; -$lang->block->myTask = '我的卡片'; +$lang->block->myTask = '我的任务'; -$lang->block->finishedTasks = '完成的卡片数'; +$lang->block->finishedTasks = '完成的任务数'; $lang->block->story = '目标'; @@ -44,7 +44,7 @@ $lang->block->modules['execution']->availableBlocks = new stdclass(); $lang->block->modules['execution']->availableBlocks->statistic = $lang->execution->common . '统计'; $lang->block->modules['execution']->availableBlocks->overview = $lang->execution->common . '总览'; $lang->block->modules['execution']->availableBlocks->list = $lang->execution->common . '列表'; -$lang->block->modules['execution']->availableBlocks->task = '卡片列表'; +$lang->block->modules['execution']->availableBlocks->task = '任务列表'; unset($lang->block->moduleList['product']); unset($lang->block->moduleList['qa']); diff --git a/extension/lite/common/ext/lang/zh-cn/lite.php b/extension/lite/common/ext/lang/zh-cn/lite.php index cfeb6f2052..a68f6e492f 100644 --- a/extension/lite/common/ext/lang/zh-cn/lite.php +++ b/extension/lite/common/ext/lang/zh-cn/lite.php @@ -1,18 +1,16 @@ execution->common = '看板'; $lang->executionCommon = '看板'; -$lang->task->common = '卡片'; +$lang->task->common = '任务'; $lang->story->common = '目标'; /* Main Navigation. */ $lang->mainNav = new stdclass(); $lang->mainNav->my = "{$lang->navIcons['my']} {$lang->my->shortCommon}|my|index|"; $lang->mainNav->project = "{$lang->navIcons['project']} {$lang->project->common}|$projectModule|$projectMethod|"; -$lang->mainNav->execution = "{$lang->navIcons['execution']} {$lang->execution->common}|$executionModule|$executionMethod|"; +$lang->mainNav->execution = "{$lang->navIcons['execution']} 任务|$executionModule|$executionMethod|"; $lang->mainNav->kanban = "{$lang->navIcons['kanban']} {$lang->kanban->common}|kanban|space|"; $lang->mainNav->doc = "{$lang->navIcons['doc']} {$lang->doc->common}|doc|index|"; -$lang->mainNav->report = "{$lang->navIcons['report']} {$lang->report->common}|report|productSummary|"; -$lang->mainNav->kanban = "{$lang->navIcons['kanban']} {$lang->kanban->common}|kanban|space|"; $lang->mainNav->system = "{$lang->navIcons['system']} {$lang->system->common}|my|team|"; $lang->mainNav->admin = "{$lang->navIcons['admin']} {$lang->admin->common}|admin|index|"; @@ -46,7 +44,7 @@ else $lang->dividerMenu = ',doc,admin,'; } -$lang->task->common = '卡片'; +$lang->task->common = '任务'; /* My menu. */ $lang->my->menu = new stdclass(); @@ -88,13 +86,13 @@ $lang->kanban->menuOrder[20] = 'doc'; $lang->kanban->menuOrder[25] = 'dynamic'; $lang->kanban->menuOrder[30] = 'settings'; -$lang->execution->menu = new stdclass(); -$lang->execution->menu->kanban = array('link' => "看板|execution|kanban|executionID=%s"); -$lang->execution->menu->list = array('link' => "列表|execution|task|executionID=%s"); -if($config->edition != 'open') $lang->execution->menu->calendar = array('link' => "日历|execution|calendar|executionID=%s"); +$lang->execution->menu = new stdclass(); +$lang->execution->menu->kanban = array('link' => "看板视图|execution|kanban|executionID=%s"); +$lang->execution->menu->task = array('link' => "列表视图|execution|task|executionID=%s"); +if($config->edition != 'open') $lang->execution->menu->calendar = array('link' => "日历视图|execution|calendar|executionID=%s"); if($config->edition != 'open') $lang->execution->menu->gantt = array('link' => "甘特图|execution|gantt|executionID=%s"); -$lang->execution->menu->tree = array('link' => "树状图|execution|tree|executionID=%s"); -$lang->execution->menu->group = array('link' => "分组视图|execution|grouptask|executionID=%s"); +$lang->execution->menu->tree = array('link' => "树状图|execution|tree|executionID=%s"); +$lang->execution->menu->grouptask = array('link' => "分组视图|execution|grouptask|executionID=%s"); $lang->kanban->menu->doc['subMenu'] = new stdclass(); @@ -204,7 +202,7 @@ $lang->admin->dividerMenu = ',company,message,system,'; $lang->searchObjects['all'] = '全部'; $lang->searchObjects['todo'] = '待办'; $lang->searchObjects['story'] = '目标'; -$lang->searchObjects['task'] = '卡片'; +$lang->searchObjects['task'] = '任务'; $lang->searchObjects['doc'] = '文档'; $lang->searchObjects['project'] = '项目'; $lang->searchObjects['execution'] = '看板'; @@ -247,7 +245,7 @@ unset($lang->createIcons['kanbanspace']); unset($lang->createIcons['kanban']); $lang->createObjects['story'] = '目标'; -$lang->createObjects['task'] = '卡片'; +$lang->createObjects['task'] = '任务'; $lang->createObjects['execution'] = '看板'; $lang->createIcons['execution'] = 'kanban'; diff --git a/extension/lite/company/ext/lang/zh-cn/lite.php b/extension/lite/company/ext/lang/zh-cn/lite.php new file mode 100644 index 0000000000..f09b1918cf --- /dev/null +++ b/extension/lite/company/ext/lang/zh-cn/lite.php @@ -0,0 +1,3 @@ +company->execution = '看板'; +$lang->company->product = '项目'; diff --git a/extension/lite/custom/ext/config/lite.php b/extension/lite/custom/ext/config/lite.php index 00f7290e18..6ca05649d1 100644 --- a/extension/lite/custom/ext/config/lite.php +++ b/extension/lite/custom/ext/config/lite.php @@ -4,6 +4,7 @@ $config->custom->requiredModules[10] = 'project'; $config->custom->requiredModules[20] = 'story'; $config->custom->requiredModules[35] = 'execution'; $config->custom->requiredModules[40] = 'task'; +$config->custom->requiredModules[80] = 'doc'; $config->custom->requiredModules[85] = 'user'; $config->custom->fieldList['execution']['create'] = 'desc'; diff --git a/extension/lite/custom/ext/lang/zh-cn/lite.php b/extension/lite/custom/ext/lang/zh-cn/lite.php index 0e6d7a8036..9d1feed8cd 100644 --- a/extension/lite/custom/ext/lang/zh-cn/lite.php +++ b/extension/lite/custom/ext/lang/zh-cn/lite.php @@ -1,7 +1,7 @@ custom->execution = '看板'; $lang->custom->closedExecution = '已关闭' . $lang->custom->execution; -$lang->custom->notice->readOnlyOfExecution = "禁止修改后,已关闭{$lang->custom->execution}下的卡片、日志以及关联目标都禁止修改。"; +$lang->custom->notice->readOnlyOfExecution = "禁止修改后,已关闭{$lang->custom->execution}下的任务、日志以及关联目标都禁止修改。"; $lang->custom->moduleName['execution'] = $lang->custom->execution; @@ -9,7 +9,7 @@ $lang->custom->object = array(); $lang->custom->object['project'] = '项目'; $lang->custom->object['execution'] = $lang->custom->execution; $lang->custom->object['story'] = $lang->SRCommon; -$lang->custom->object['task'] = '卡片'; +$lang->custom->object['task'] = '任务'; $lang->custom->object['todo'] = '待办'; $lang->custom->object['user'] = '用户'; $lang->custom->object['block'] = '区块'; diff --git a/extension/lite/dev/ext/lang/zh-cn/lite.php b/extension/lite/dev/ext/lang/zh-cn/lite.php index a640e108fb..9ef59bcb45 100644 --- a/extension/lite/dev/ext/lang/zh-cn/lite.php +++ b/extension/lite/dev/ext/lang/zh-cn/lite.php @@ -22,7 +22,7 @@ $lang->dev->tableList['projectstory'] = '项目' . $lang->SRCommon; $lang->dev->tableList['execution'] = $lang->executionCommon; $lang->dev->tableList['story'] = $lang->SRCommon; $lang->dev->tableList['storyspec'] = "{$lang->SRCommon}描述"; -$lang->dev->tableList['task'] = '卡片'; +$lang->dev->tableList['task'] = '任务'; $lang->dev->tableList['taskestimate'] = '任务预计'; $lang->dev->tableList['team'] = '团队'; $lang->dev->tableList['todo'] = '待办'; diff --git a/extension/lite/execution/ext/control/kanban.php b/extension/lite/execution/ext/control/kanban.php index e45f8e5cfd..478bb47c80 100644 --- a/extension/lite/execution/ext/control/kanban.php +++ b/extension/lite/execution/ext/control/kanban.php @@ -7,11 +7,14 @@ class myExecution extends execution $this->app->loadLang('kanban'); common::setMenuVars('execution', $executionID); - $execution = $this->execution->getById($executionID); + $currentMethod = $this->app->methodName; + $execution = $this->execution->getById($executionID); $this->loadModel('project')->setMenu($execution->project); - $this->lang->kanban->menu->execution['subMenu'] = $this->lang->execution->menu; + $this->lang->kanban->menu->execution['subMenu'] = new stdClass(); + + /* change subMenu to sub select menu */ + $TRActions = $this->execution->getTRActions($currentMethod); - $TRActions = ''; $TRActions .= ""; - if($this->app->rawMethod == 'task') $this->lang->TRActions = ''; + + if(in_array($this->app->rawMethod, array('task', 'calendar', 'gantt', 'tree', 'grouptask'))) $this->lang->TRActions = $this->getTRActions($this->app->rawMethod); $this->lang->modulePageNav = $modulePageNav; } + +public function getTree($executionID) +{ + $fullTrees = $this->loadModel('tree')->getTaskStructure($executionID, 0); + + array_unshift($fullTrees, array('id' => 0, 'name' => '/', 'type' => 'task', 'actions' => false, 'root' => $executionID)); + + foreach($fullTrees as $i => $tree) + { + $tree = (object)$tree; + + if($tree->type == 'product') array_unshift($tree->children, array('id' => 0, 'name' => '/', 'type' => 'story', 'actions' => false, 'root' => $tree->root)); + $fullTree = $this->fillTasksInTree($tree, $executionID); + + if(empty($fullTree->children)) + { + unset($fullTrees[$i]); + } + else + { + $fullTrees[$i] = $fullTree; + } + } + + if(isset($fullTrees[0]) and empty($fullTrees[0]->children)) array_shift($fullTrees); + + $newTrees = array(); + + foreach($fullTrees as $i => $tree) + { + if($tree->type == 'product') + { + foreach($tree->children as $value) + { + $newTrees[] = $value; + } + } + else + { + $newTrees[] = $tree; + } + } + + return array_values($newTrees); +} + +public function getTRActions($currentMethod) +{ + $subMenu = $this->lang->execution->menu; + + foreach($subMenu as $key => $value) + { + $tmpValue = explode('|', $value['link']); + $subMenu->$key['name'] = $tmpValue[0]; + $subMenu->$key['module'] = $tmpValue[1]; + $subMenu->$key['method'] = $tmpValue[2]; + $subMenu->$key['vars'] = $tmpValue[3]; + } + + $TRActions = ''; + $TRActions .= ""; + return $TRActions; +} diff --git a/extension/lite/execution/ext/view/kanban.lite.html.hook.php b/extension/lite/execution/ext/view/kanban.lite.html.hook.php index b4e48e22c1..4e62f06cb1 100644 --- a/extension/lite/execution/ext/view/kanban.lite.html.hook.php +++ b/extension/lite/execution/ext/view/kanban.lite.html.hook.php @@ -1,3 +1,7 @@ + diff --git a/extension/lite/kanban/ext/lang/zh-cn/lite.php b/extension/lite/kanban/ext/lang/zh-cn/lite.php new file mode 100644 index 0000000000..109bc66527 --- /dev/null +++ b/extension/lite/kanban/ext/lang/zh-cn/lite.php @@ -0,0 +1,8 @@ +kanban->taskColumn = array(); +$lang->kanban->taskColumn['wait'] = '未开始'; +$lang->kanban->taskColumn['developing'] = '进行中'; +$lang->kanban->taskColumn['developed'] = '已完成'; +$lang->kanban->taskColumn['pause'] = '已暂停'; +$lang->kanban->taskColumn['canceled'] = '已取消'; +$lang->kanban->taskColumn['closed'] = '已关闭'; diff --git a/extension/lite/kanban/ext/model/lite.php b/extension/lite/kanban/ext/model/lite.php new file mode 100644 index 0000000000..e80d0834e3 --- /dev/null +++ b/extension/lite/kanban/ext/model/lite.php @@ -0,0 +1,174 @@ +lang->kanban->menu = new stdclass(); +} + +public function getKanban4Group($executionID, $browseType, $groupBy) +{ + /* Get card data. */ + $cardList = array(); + if($browseType == 'story') $cardList = $this->loadModel('story')->getExecutionStories($executionID, 0, 0, 't1.`order`_desc', 'allStory'); + if($browseType == 'bug') $cardList = $this->loadModel('bug')->getExecutionBugs($executionID); + if($browseType == 'task') $cardList = $this->loadModel('execution')->getKanbanTasks($executionID, "id"); + + $lanes = $this->getLanes4Group($executionID, $browseType, $groupBy, $cardList); + if(empty($lanes)) return array(); + + $columns = $this->dao->select('t1.*, t2.`type` as columnType')->from(TABLE_KANBANCELL)->alias('t1') + ->leftJoin(TABLE_KANBANCOLUMN)->alias('t2')->on('t1.`column` = t2.id') + ->where('t1.kanban')->eq($executionID) + ->andWhere('t1.`type`')->eq($browseType) + ->fetchAll(); + + $cardGroup = array(); + foreach($columns as $column) + { + if(empty($column->cards)) continue; + foreach($cardList as $card) + { + if(strpos($column->cards, ",$card->id,") !== false) $cardGroup[$column->columnType][$card->id] = $card; + } + } + + /* Build kanban group data. */ + $kanbanGroup = array(); + foreach($lanes as $laneID => $lane) + { + $laneData = array(); + $columnData = array(); + $columnList = $this->lang->kanban->{$browseType . 'Column'}; + + $laneData['id'] = $groupBy . $laneID; + $laneData['laneID'] = $groupBy . $laneID; + $laneData['name'] = (($groupBy == 'pri' or $groupBy == 'severity') and $laneID) ? $this->lang->$browseType->$groupBy . ':' . $lane->name : $lane->name; + $laneData['color'] = $lane->color; + $laneData['order'] = $lane->order; + $laneData['defaultCardType'] = $browseType; + + /* Construct kanban column data. */ + foreach($columnList as $columnID => $columnName) + { + $parentColumn = ''; + if(in_array($columnID, array('testing', 'tested'))) $parentColumn = 'test'; + if(in_array($columnID, array('fixing', 'fixed'))) $parentColumn = 'resolving'; + + $columnData[$columnID]['id'] = $columnID; + $columnData[$columnID]['type'] = $columnID; + $columnData[$columnID]['name'] = $columnName; + $columnData[$columnID]['color'] = '#333'; + $columnData[$columnID]['limit'] = -1; + $columnData[$columnID]['laneType'] = $browseType; + $columnData[$columnID]['asParent'] = in_array($columnID, array('develop', 'test', 'resolving')) ? true : false; + $columnData[$columnID]['parentType'] = $parentColumn; + + $cardOrder = 1; + $objects = zget($cardGroup, $columnID, array()); + foreach($objects as $object) + { + if(empty($object)) continue; + + $cardData = array(); + if(in_array($groupBy, array('module', 'story', 'pri', 'severity')) and (int)$object->$groupBy !== $laneID) continue; + if(in_array($groupBy, array('assignedTo', 'type', 'category', 'source')) and $object->$groupBy != $laneID) continue; + + $cardData['id'] = $object->id; + $cardData['order'] = $cardOrder; + $cardData['pri'] = $object->pri ? $object->pri : ''; + $cardData['estimate'] = $browseType == 'bug' ? '' : $object->estimate; + $cardData['assignedTo'] = $object->assignedTo; + $cardData['deadline'] = $browseType == 'story' ? '' : $object->deadline; + $cardData['severity'] = $browseType == 'bug' ? $object->severity : ''; + + if($browseType == 'task') + { + $cardData['name'] = $object->name; + } + else + { + $cardData['title'] = $object->title; + } + + $laneData['cards'][$columnID][] = $cardData; + $cardOrder ++; + } + if(!isset($laneData['cards'][$columnID])) $laneData['cards'][$columnID] = array(); + } + + $kanbanGroup[$groupBy]['id'] = $groupBy . $laneID; + $kanbanGroup[$groupBy]['columns'] = array_values($columnData); + $kanbanGroup[$groupBy]['lanes'][] = $laneData; + $kanbanGroup[$groupBy]['defaultCardType'] = $browseType; + } + + return $kanbanGroup; +} + +/** + * Get card group by execution id. + * + * @param int $kanbanID + * @param string $browseType all|task|bug|story + * @param string $orderBy + * @access public + * @return array + */ +public function getCardGroupByExecution($executionID, $browseType = 'all', $orderBy = 'id_asc') +{ + $cards = $this->dao->select('t1.*, t2.type as columnType') + ->from(TABLE_KANBANCELL)->alias('t1') + ->leftJoin(TABLE_KANBANCOLUMN)->alias('t2')->on('t1.column=t2.id') + ->where('t1.kanban')->eq($executionID) + ->beginIF($browseType != 'all')->andWhere('t1.type')->eq($browseType)->fi() + ->orderby($orderBy) + ->fetchgroup('lane', 'column'); + + /* Get group objects. */ + if($browseType == 'all' or $browseType == 'story') $objectGroup['story'] = $this->loadModel('story')->getExecutionStories($executionID, 0, 0, 't1.`order`_desc', 'allStory'); + if($browseType == 'all' or $browseType == 'bug') $objectGroup['bug'] = $this->loadModel('bug')->getExecutionBugs($executionID); + if($browseType == 'all' or $browseType == 'task') $objectGroup['task'] = $this->loadModel('execution')->getKanbanTasks($executionID, "id"); + $taskCardMenu = $this->getKanbanCardMenu($executionID, $objectGroup['task'], 'task'); + $cardGroup = array(); + + foreach($cards as $laneID => $cells) + { + foreach($cells as $columnID => $cell) + { + $cardIdList = array_filter(explode(',', $cell->cards)); + $cardOrder = 1; + foreach($cardIdList as $cardID) + { + $cardData = array(); + $objects = zget($objectGroup, $cell->type, array()); + $object = zget($objects, $cardID, array()); + + if(empty($object)) continue; + + $cardData['id'] = $object->id; + $cardData['order'] = $cardOrder++; + $cardData['pri'] = $object->pri ? $object->pri : ''; + $cardData['estimate'] = $cell->type == 'bug' ? '' : $object->estimate; + $cardData['assignedTo'] = $object->assignedTo; + $cardData['deadline'] = $cell->type == 'story' ? '' : $object->deadline; + $cardData['severity'] = $cell->type == 'bug' ? $object->severity : ''; + $cardData['acl'] = 'open'; + $cardData['lane'] = $laneID; + $cardData['column'] = $cell->column; + $cardData['menus'] = $taskCardMenu[$cardID]; + + if($cell->type == 'task') + { + $cardData['name'] = $object->name; + } + else + { + $cardData['title'] = $object->title; + } + $cardGroup[$laneID][$cell->columnType][] = $cardData; + } + } + } + return $cardGroup; +} + diff --git a/extension/lite/product/ext/view/browse.html.php b/extension/lite/product/ext/view/browse.html.php index 3ca43fa507..fcaa1d5269 100644 --- a/extension/lite/product/ext/view/browse.html.php +++ b/extension/lite/product/ext/view/browse.html.php @@ -42,7 +42,6 @@ $projectIDParam = $isProjectStory ? "projectID=$projectID&" : ''; .btn-group button.dropdown-toggle.btn-secondary, .btn-group button.dropdown-toggle.btn-primary {padding:6px;}