Merge branch 'master' of https://gitlab.zcorp.cc/easycorp/zentaopms into sprint/244

This commit is contained in:
曹延义
2022-09-28 15:57:00 +08:00
21 changed files with 89 additions and 107 deletions
+1 -1
View File
@@ -53,7 +53,7 @@ class buildsEntry extends entry
$project = $this->loadModel('project')->getByID($projectID);
if(!$project) return $this->send404();
$fields = 'execution,product,name,builder,date,scmPath,filePath,desc';
$fields = 'execution,product,name,builder,date,scmPath,filePath,desc,branch';
$this->batchSetPost($fields);
$control = $this->loadController('build', 'create');
+7
View File
@@ -34,6 +34,13 @@
35025 需求导入模板增加由谁评审字段
旗舰版:
35042 旗舰版周报3个工作项列表能显示总数
修复的Bug
27875 工时记录页面日期控件展开后显示遮挡
27778 创建项目和编辑项目的所属项目集字段显示不一致
27690 创建项目页面提示信息窗口建议向右展开
27632 复制bug时希望可以同步反馈者和通知邮箱两个字段的信息
27561 提需求页面所属产品右侧边框线缺失
27547 编辑项目集预算,点击保存,提示有未提交表单
2022-09-08 17.6.1
完成的需求
+7 -3
View File
@@ -374,10 +374,10 @@ class actionModel extends model
elseif($actionName == 'linked2execution' or $actionName == 'linked2kanban')
{
$execution = $this->dao->select('name,type')->from(TABLE_PROJECT)->where('id')->eq($action->extra)->fetch();
$name = $execution->name;
$method = $execution->type == 'kanban' ? 'kanban' : 'view';
if($name)
if(!empty($execution))
{
$name = $execution->name;
$method = $execution->type == 'kanban' ? 'kanban' : 'view';
$action->extra = (!common::hasPriv('execution', $method) or ($method == 'kanban' and isonlybody())) ? $name : html::a(helper::createLink('execution', $method, "executionID=$action->execution"), $name);
}
}
@@ -1060,6 +1060,9 @@ class actionModel extends model
$programCondition = empty($this->app->user->view->programs) ? '0' : $this->app->user->view->programs;
$efforts = $this->dao->select('id')->from(TABLE_EFFORT)->where($condition)->fetchPairs();
$efforts = !empty($efforts) ? implode(',', $efforts) : 0;
/* Get actions. */
$actions = $this->dao->select('*')->from(TABLE_ACTION)
->where('objectType')->notIN($this->config->action->ignoreObjectType4Dynamic)
@@ -1087,6 +1090,7 @@ class actionModel extends model
/* Filter out client login/logout actions. */
->andWhere('action')->notin('disconnectxuanxuan,reconnectxuanxuan,loginxuanxuan,logoutxuanxuan')
->andWhere("IF((objectType = 'program'), (objectID in ($programCondition)), '1=1')")
->andWhere("IF((objectType = 'effort'), (objectID in ($efforts)), '1=1')")
->orderBy($orderBy)
->page($pager)
->fetchAll();
+2 -2
View File
@@ -17,7 +17,7 @@ foreach($products as $product)
}
$productsPinYin = common::convert2Pinyin($productNames);
$linkHtml = $this->product->setParamsForLink($module, $link, $projectID, 0);
$productsHtml = count($products) > 1 ? html::a($linkHtml, $this->lang->bug->allProduct, '', "class='text-important' title='{$this->lang->bug->allProduct}' data-key='" . zget($productsPinYin, $this->lang->bug->allProduct, '') . "' data-app='{$this->app->tab}'") : '';
$productsHtml = count($products) > 1 ? html::a($linkHtml, $this->lang->bug->allProduct, '', "class='text-primary' title='{$this->lang->bug->allProduct}' data-key='" . zget($productsPinYin, $this->lang->bug->allProduct, '') . "' data-app='{$this->app->tab}'") : '';
foreach($products as $product)
{
@@ -26,7 +26,7 @@ foreach($products as $product)
$productName .= $product->line ? zget($lines, $product->line, '') . '/' . $product->name : $product->name;
$objectID = ($product->type != 'platform' && $module == 'branch' && $method == 'manage') ? $productID : $product->id;
$linkHtml = $this->product->setParamsForLink($module, $link, $projectID, $product->id);
$productsHtml .= html::a($linkHtml, $productName, '', "class='text-important $selected' title='{$productName}' data-key='" . zget($productsPinYin, $product->name, '') . "' data-app='{$this->app->tab}'");
$productsHtml .= html::a($linkHtml, $productName, '', "class='text-primary $selected' title='{$productName}' data-key='" . zget($productsPinYin, $product->name, '') . "' data-app='{$this->app->tab}'");
}
?>
<div class="table-row">
+3 -2
View File
@@ -20,6 +20,7 @@
#stories .action {display: none;}
#bugs .action {display: none;}
tbody tr td:first-child input {display: none;}
.page-title .dropdown-menu {top: 40px; left: 70px;}
</style>
<?php endif;?>
<div id='mainMenu' class='clearfix'>
@@ -28,8 +29,8 @@ tbody tr td:first-child input {display: none;}
<?php common::printBack($browseLink, 'btn btn-secondary');?>
<div class='divider'></div>
<div class='page-title'>
<span class='text' title='<?php echo $build->name;?>'>
<?php echo html::a('javascript:void(0)', "<span class='label label-id'>{$build->id}</span> " . $build->name . " <span class='caret'></span>", '', "data-toggle='dropdown' class='btn btn-link btn-active-text'");?>
<span title='<?php echo $build->name;?>'>
<?php echo html::a('javascript:void(0)', "<span class='label label-id'>{$build->id}</span> " . $build->name . " <span class='caret'></span>", '', "data-toggle='dropdown' class='text btn btn-link btn-active-text'");?>
<?php
echo "<ul class='dropdown-menu'>";
foreach($buildPairs as $id => $name)
+1 -1
View File
@@ -25,7 +25,7 @@ foreach($products as $product)
$linkHtml = sprintf($link, $product->id);
if($product->status == 'normal' and $product->PO == $this->app->user->account)
{
$myProductsHtml .= html::a($linkHtml, $productName, '', "class='text-important $selected' title='{$productName}' data-key='" . zget($productsPinYin, $product->name, '') . "' data-app='$tab'");
$myProductsHtml .= html::a($linkHtml, $productName, '', "class='text-primary $selected' title='{$productName}' data-key='" . zget($productsPinYin, $product->name, '') . "' data-app='$tab'");
}
else if($product->status == 'normal' and !($product->PO == $this->app->user->account))
{
+1 -1
View File
@@ -2498,7 +2498,7 @@ class execution extends control
$kanbanGroup = $this->kanban->getExecutionKanban($executionID, $browseType, $groupBy, '', $orderBy);
if(empty($kanbanGroup))
{
$this->kanban->createExecutionLane($executionID, $browseType, $groupBy);
$this->kanban->createExecutionLane($executionID, $browseType);
$kanbanGroup = $this->kanban->getExecutionKanban($executionID, $browseType, $groupBy, '', $orderBy);
}
+2 -2
View File
@@ -706,7 +706,7 @@ class executionModel extends model
/* Check unique code for edited executions. */
if($projectModel == 'scrum' and isset($executionCode) and empty($executionCode))
{
dao::$errors['code'][] = 'execution#' . $executionID . sprintf($this->lang->error->notempty, $this->lang->project->code);
dao::$errors['code'][] = 'execution#' . $executionID . sprintf($this->lang->error->notempty, $this->lang->execution->execCode);
return false;
}
elseif(!empty($executionCode))
@@ -714,7 +714,7 @@ class executionModel extends model
/* Check unique code for edited executions. */
if(isset($codeList[$executionCode]))
{
dao::$errors['code'][] = 'execution#' . $executionID . sprintf($this->lang->error->unique, $this->lang->project->code, $executionCode);
dao::$errors['code'][] = 'execution#' . $executionID . sprintf($this->lang->error->unique, $this->lang->execution->execCode, $executionCode);
return false;
}
$codeList[$executionCode] = $executionCode;
+1 -1
View File
@@ -1457,7 +1457,7 @@ $(function()
resetRegionHeight($(this).hasClass('icon-angle-top') ? 'open' : 'close');
});
$('.region-header').on('click', '.action', hideKanbanAction);
$('#regionTabs, .region-header').on('click', '.action', hideKanbanAction);
$('#TRAction').on('click', '.btn', hideKanbanAction);
/* Hide action box when user click document */
+15 -65
View File
@@ -1554,7 +1554,7 @@ class kanbanModel extends model
$teamPairs = array();
foreach($taskTeams[$taskID] as $account => $team) $teamPairs[$account] = $team->realname;
$task->team = $teamPairs;
$task->teamMember = $teamPairs;
}
/* Get objects cards menus. */
@@ -1610,6 +1610,7 @@ class kanbanModel extends model
$laneData['order'] = $lane->order;
$laneData['type'] = $browseType;
$laneData['defaultCardType'] = $browseType;
if(empty($laneID) and !in_array($groupBy, array('module', 'story', 'pri', 'severity'))) $laneID = '';
if($browseType == 'task' and $groupBy == 'story')
{
@@ -1675,8 +1676,9 @@ class kanbanModel extends model
if($groupBy == 'assignedTo')
{
$laneID = (string)$laneID;
if(empty($object->team) and $object->$groupBy !== $laneID) continue;
if(!empty($object->team) and !in_array($laneID, array_keys($object->team), true)) continue;
if(empty($object->$groupBy)) $object->$groupBy = '';
if(empty($object->teamMember) and (string)$object->$groupBy !== $laneID) continue;
if(!empty($object->teamMember) and !in_array($laneID, array_keys($object->teamMember), true)) continue;
if($object->$groupBy !== $laneID) $cardData['assignedTo'] = $laneID;
}
@@ -1745,9 +1747,9 @@ class kanbanModel extends model
{
if(!isset($groupByList[$item->$groupBy])) $groupByList[$item->$groupBy] = $item->$groupBy;
if($groupBy == 'assignedTo' and !empty($item->team))
if($groupBy == 'assignedTo' and !empty($item->teamMember))
{
foreach($item->team as $account => $name)
foreach($item->teamMember as $account => $name)
{
if(!isset($groupByList[$account])) $groupByList[$account] = $account;
}
@@ -1796,6 +1798,7 @@ class kanbanModel extends model
if(in_array($groupBy, array('module', 'story', 'pri', 'severity'))) $objectPairs[0] = $this->lang->$browseType->$groupBy . ': ' . $this->lang->kanban->noGroup;
if(in_array($groupBy, array('assignedTo', 'source'))) $objectPairs[] = $this->lang->$browseType->$groupBy . ': ' . $this->lang->kanban->noGroup;
if($browseType == 'bug' and $groupBy == 'type') $objectPairs[0] = $this->lang->$browseType->$groupBy . ': ' . $this->lang->kanban->noGroup;
$laneColor = 0;
$order = 1;
@@ -2420,72 +2423,19 @@ class kanbanModel extends model
*
* @param int $executionID
* @param string $type all|story|bug|task
* @param string $groupBy default
* @access public
* @return void
*/
public function createExecutionLane($executionID, $type = 'all', $groupBy = 'default')
public function createExecutionLane($executionID, $type = 'all')
{
if($groupBy == 'default' or $type == 'all')
foreach($this->config->kanban->default as $type => $lane)
{
foreach($this->config->kanban->default as $type => $lane)
{
$lane->type = $type;
$lane->execution = $executionID;
$this->dao->insert(TABLE_KANBANLANE)->data($lane)->exec();
$lane->type = $type;
$lane->execution = $executionID;
$this->dao->insert(TABLE_KANBANLANE)->data($lane)->exec();
$laneID = $this->dao->lastInsertId();
$this->createExecutionColumns($laneID, $type, $executionID);
}
}
else
{
$this->loadModel($type);
$groupList = $this->getObjectGroup($executionID, $type, $groupBy);
$objectPairs = array();
if($groupBy == 'module') $objectPairs = $this->dao->select('id,name')->from(TABLE_MODULE)->where('type')->in('story,bug,task')->andWhere('deleted')->eq('0')->fetchPairs();
if($groupBy == 'story') $objectPairs = $this->dao->select('id,title')->from(TABLE_STORY)->where('deleted')->eq(0)->fetchPairs();
if($groupBy == 'assignedTo') $objectPairs = $this->loadModel('user')->getPairs('noletter');
$laneName = '';
$laneOrder = 5;
$colorIndex = 0;
foreach($groupList as $groupKey)
{
if($groupKey)
{
if(strpos('module,story,assignedTo', $groupBy) !== false)
{
$laneName = zget($objectPairs, $groupKey);
}
else
{
$laneName = zget($this->lang->$type->{$groupBy . 'List'}, $groupKey);
}
}
else
{
$laneName = $this->lang->kanban->noGroup;
}
$lane = new stdClass();
$lane->execution = $executionID;
$lane->type = $type;
$lane->groupby = $groupBy;
$lane->extra = $groupKey;
$lane->name = $laneName;
$lane->color = $this->config->kanban->laneColorList[$colorIndex];
$lane->order = $laneOrder;
$laneOrder += 5;
$colorIndex += 1;
if($colorIndex == count($this->config->kanban->laneColorList) + 1) $colorIndex = 0;
$this->dao->insert(TABLE_KANBANLANE)->data($lane)->exec();
$laneID = $this->dao->lastInsertId();
$this->createExecutionColumns($laneID, $type, $executionID, $groupBy, $groupKey);
}
$laneID = $this->dao->lastInsertId();
$this->createExecutionColumns($laneID, $type, $executionID);
}
}
@@ -52,7 +52,7 @@
<ul class='dropdown-menu' style='max-height:240px; max-width: 300px; overflow-y:auto'>
<?php foreach($lang->productplan->orderList as $order => $label):?>
<?php $active = $orderBy == $order ? 'active' : '';?>
<li class='<?php echo $active;?>'><?php echo html::a(inlink('browse', "productID=$productID&branch=$branchID&browseType=$browseType&orderBy=$order"), $label);?></li>
<li class='<?php echo $active;?>'><?php echo html::a(inlink('browse', "productID=$productID&branch=$branchID&browseType=$browseType&queryID=$queryID&orderBy=$order"), $label);?></li>
<?php endforeach;?>
</ul>
</div>
+15 -15
View File
@@ -1125,7 +1125,6 @@ class project extends control
$this->app->loadClass('pager', $static = true);
$pager = new pager($recTotal, $recPerPage, $pageID);
$sort = common::appendOrder($orderBy);
$bugs = $this->bug->getProjectBugs($projectID, $productID, $branchID, $build, $type, $param, $sort, '', $pager);
/* team member pairs. */
$memberPairs = array();
@@ -1154,20 +1153,6 @@ class project extends control
}
}
/* Process the openedBuild and resolvedBuild fields. */
$bugs = $this->bug->processBuildForBugs($bugs);
/* Get story and task id list. */
$storyIdList = $taskIdList = array();
foreach($bugs as $bug)
{
if($bug->story) $storyIdList[$bug->story] = $bug->story;
if($bug->task) $taskIdList[$bug->task] = $bug->task;
if($bug->toTask) $taskIdList[$bug->toTask] = $bug->toTask;
}
$storyList = $storyIdList ? $this->loadModel('story')->getByList($storyIdList) : array();
$taskList = $taskIdList ? $this->loadModel('task')->getByList($taskIdList) : array();
$moduleID = $type != 'bysearch' ? $param : 0;
$modules = $this->tree->getAllModulePairs('bug');
@@ -1188,6 +1173,21 @@ class project extends control
}
$tree = $moduleID ? $this->tree->getByID($moduleID) : '';
/* Process the openedBuild and resolvedBuild fields. */
$bugs = $this->bug->getProjectBugs($projectID, $productID, $branchID, $build, $type, $param, $sort, '', $pager);
$bugs = $this->bug->processBuildForBugs($bugs);
/* Get story and task id list. */
$storyIdList = $taskIdList = array();
foreach($bugs as $bug)
{
if($bug->story) $storyIdList[$bug->story] = $bug->story;
if($bug->task) $taskIdList[$bug->task] = $bug->task;
if($bug->toTask) $taskIdList[$bug->toTask] = $bug->toTask;
}
$storyList = $storyIdList ? $this->loadModel('story')->getByList($storyIdList) : array();
$taskList = $taskIdList ? $this->loadModel('task')->getByList($taskIdList) : array();
$showModule = !empty($this->config->datatable->projectBug->showModule) ? $this->config->datatable->projectBug->showModule : '';
/* Assign. */
+2 -2
View File
@@ -81,7 +81,7 @@ class release extends control
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => inlink('view', "releaseID=$releaseID")));
}
$builds = $this->loadModel('build')->getBuildPairs($productID, $branch, 'notrunk|withbranch', 0, 'execution', false);
$builds = $this->loadModel('build')->getBuildPairs($productID, $branch, 'notrunk|withbranch', 0, 'execution', '', false);
$releasedBuilds = $this->release->getReleasedBuilds($productID, $branch);
foreach($releasedBuilds as $build) unset($builds[$build]);
unset($builds['trunk']);
@@ -140,7 +140,7 @@ class release extends control
$this->commonAction($release->product, $release->branch);
$build = $this->build->getById($release->build);
$builds = $this->loadModel('build')->getBuildPairs($release->product, $release->branch, 'notrunk|withbranch', 0, 'execution', $release->build, false);
$builds = $this->loadModel('build')->getBuildPairs($release->product, $release->branch, 'notrunk|withbranch', $release->project, 'project', $release->build, false);
$releasedBuilds = $this->release->getReleasedBuilds($release->product, $release->branch);
foreach($releasedBuilds as $releasedBuild)
{
+21 -1
View File
@@ -611,6 +611,26 @@ class task extends control
if(!isset($this->view->members[$this->view->task->assignedTo])) $this->view->members[$this->view->task->assignedTo] = $this->view->task->assignedTo;
if(isset($this->view->members['closed']) or $this->view->task->status == 'closed') $this->view->members['closed'] = 'Closed';
$executions = array();
if(!empty($task->project))
{
$executionList = $this->execution->getPairs($task->project);
$project = $this->loadModel('project')->getByID($task->project);
if(isset($project->model) and $project->model == 'waterfall')
{
foreach($executionList as $key=>$val)
{
$values = $project->name . '/' . $val;
$executions[$key] = $values;
}
}
else
{
$executions = $executionList;
}
}
$this->view->title = $this->lang->task->edit . 'TASK' . $this->lang->colon . $this->view->task->name;
$this->view->position[] = $this->lang->task->common;
$this->view->position[] = $this->lang->task->edit;
@@ -619,7 +639,7 @@ class task extends control
$this->view->users = $this->loadModel('user')->getPairs('nodeleted|noclosed', "{$this->view->task->openedBy},{$this->view->task->canceledBy},{$this->view->task->closedBy}");
$this->view->showAllModule = isset($this->config->execution->task->allModule) ? $this->config->execution->task->allModule : '';
$this->view->modules = $this->tree->getTaskOptionMenu($this->view->task->execution, 0, 0, $this->view->showAllModule ? 'allModule' : '');
$this->view->executions = $this->config->systemMode == 'classic' ? $this->execution->getPairs() : $this->execution->getByProject($task->project, 'noclosed', 0, true, false, $task->execution);
$this->view->executions = $this->config->systemMode == 'classic' ? $this->execution->getPairs() : $executions;
$this->display();
}
+1 -1
View File
@@ -12,7 +12,7 @@
#linearefforts .nav li.active a{color: #0c64eb !important}
.input-group-addon {background: #fff}
.icon-calendar {color: rgb(22, 168, 248)}
#recordForm .table>thead>tr>th{ border: none}
#recordForm .table > thead > tr > th {border: none; font-weight: 400;}
.main-header {border-bottom: none !important}
.main-header ul.hours:before{content:"("}
.main-header ul.hours:after{content:")"}
+1 -1
View File
@@ -18,7 +18,7 @@
<div id='mainMenu' class='clearfix'>
<div class='btn-toolbar pull-left'>
<?php if(!isonlybody()):?>
<?php echo html::a($browseLink, '<i class="icon icon-back icon-sm"></i> ' . $lang->goback, '', "class='btn btn-secondary' data-app={$this->app->tab}");?>
<?php echo html::a($browseLink, '<i class="icon icon-back icon-sm"></i> ' . $lang->goback, '', "class='btn btn-secondary'");?>
<div class="divider"></div>
<?php endif;?>
<div class="page-title">
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -26,7 +26,7 @@ $(function()
const mainHeader = document.getElementById('mainHeader');
if(!mainHeader) return;
const style = window.getComputedStyle(mainHeader, null);
const color = window.getComputedStyle(document.querySelector('#navbar .nav>li:not(.active)>a'), null).color;
const color = window.getComputedStyle(document.querySelector('#navbar .nav>li:not(.active)>a, #userMenu .nav>li:not(.active)>a'), null).color;
const clientHeaderStyle = {windowControlBtnColor: color, background: style.background, color: color};
window.parent.appHeaderStyleUpdated = true;
window.open('xxc://setAppHeaderStyle/zentao-integrated/' + encodeURIComponent(JSON.stringify(clientHeaderStyle)), '_blank');
@@ -150,7 +150,7 @@ class xuanxuanMessage extends messageModel
$content = json_encode($contentData);
$avatarUrl = $server . $this->app->getWebRoot() . 'favicon.ico';
if($target) $this->loadModel('im')->messageCreateNotify($target, $title, $subtitle = '', $content, $contentType = 'object', $url, $actions = array(), $sender = array('id' => 'zentao', 'realname' => $this->lang->message->sender, 'name' => $this->lang->message->sender, 'avatar' => $avatarUrl));
if($target && ($objectType == 'bug' || $objectType == 'task' || $objectType == 'story')) $this->loadModel('im')->messageCreateNotify($target, $title, $subtitle = '', $content, $contentType = 'object', $url, $actions = array(), $sender = array('id' => 'zentao', 'realname' => $this->lang->message->sender, 'name' => $this->lang->message->sender, 'avatar' => $avatarUrl));
if($objectType == 'mr' and is_array($this->lang->message->mr->$actionType) and !empty($object->assignee))
{