This commit is contained in:
wangyidong
2022-06-28 15:29:41 +08:00
38 changed files with 4021 additions and 3081 deletions
+3 -1
View File
@@ -54,9 +54,11 @@ class feedbacksEntry extends entry
*/
public function post()
{
$fields = 'module,product,type,title,public,desc,status,feedbackBy,notifyEmail,notify,uid';
$fields = 'module,product,type,title,public,desc,status,feedbackBy,notify,uid';
$this->batchSetPost($fields);
$this->setPost('notifyEmail', $this->request('notifyEmail', ''));
$control = $this->loadController('feedback', 'create');
$this->requireFields('title,product');
$control->create();
+3260 -2967
View File
File diff suppressed because one or more lines are too long
+376 -2
View File
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
+1 -1
View File
File diff suppressed because one or more lines are too long
+35 -26
View File
@@ -950,35 +950,46 @@ class actionModel extends model
extract($beginAndEnd);
/* Build has priv condition. */
$condition = 1;
if($productID == 'all') $products = $this->app->user->view->products;
if($projectID == 'all') $projects = $this->app->user->view->projects;
if($executionID == 'all') $executions = $this->app->user->view->sprints;
if($productID == 'all' or $projectID == 'all')
$condition = 1;
$executions = array();
if(!$this->app->user->admin)
{
$productCondition = $productID == 'all' ? "product " . helper::dbIN($products) : '';
$projectCondition = $projectID == 'all' ? "project " . helper::dbIN($projects) : '';
$executionCondition = $executionID == 'all' ? "execution " . helper::dbIN($executions) : '';
if(is_numeric($productID)) $productCondition = "product like '%,$productID,%' or product = '$productID'";
if(is_numeric($projectID)) $projectCondition = "project = '$projectID'";
if(is_numeric($executionID)) $executionCondition = "execution = '$executionID'";
if($productID == 'all') $products = $this->app->user->view->products;
if($projectID == 'all') $projects = $this->app->user->view->projects;
if($executionID == 'all') $executions = $this->app->user->view->sprints;
if($productID == 'all' and $projectID == 'all')
{
$productCondition = "product " . helper::dbIN($products);
$projectCondition = "project " . helper::dbIN($projects);
$executionCondition = "execution " . helper::dbIN($executions);
}
elseif($productID == 'all' and is_numeric($projectID))
{
$products = $this->loadModel('product')->getProductPairsByProject($projectID);
$executions = $this->loadModel('execution')->getPairs($projectID) + array(0 => 0);
$productCondition = "product " . helper::dbIN(array_keys($products));
$projectCondition = "project = $projectID";
$executionCondition = "execution " . helper::dbIN(array_keys($executions));
}
elseif(is_numeric($productID) and $projectID == 'all')
{
$this->loadModel('product');
$projects = $this->product->getProjectPairsByProduct($productID);
$executions = $this->product->getExecutionPairsByProduct($productID);
$productCondition = "product = $productID";
$projectCondition = "project " . helper::dbIN(array_keys($projects));
$executionCondition = "execution " . helper::dbIN(array_keys($executions));
}
$condition = "((product =',0,' or product=0) AND project = '0' AND execution = 0)";
if($productCondition) $condition .= ' OR ' . $productCondition;
if($projectCondition) $condition .= ' OR ' . $projectCondition;
if($executionCondition) $condition .= ' OR ' . $executionCondition;
if($this->app->user->admin) $condition = 1;
if(isset($productCondition)) $condition .= ' OR ' . $productCondition;
if(isset($projectCondition)) $condition .= ' OR ' . $projectCondition;
if(isset($executionCondition)) $condition .= ' OR ' . $executionCondition;
}
/* If is project, select its related. */
$executions = array();
if(is_numeric($projectID) and $executionID == 'all') $executions = $this->loadModel('execution')->getPairs($projectID) + array(0 => 0);
$this->loadModel('doc');
$libs = $this->doc->getLibs('includeDeleted') + array('' => '');
$docs = $this->doc->getPrivDocs(array_keys($libs), 0, 'all');
$actionCondition = $this->getActionCondition();
if(!$actionCondition and !$this->app->user->admin and isset($this->app->user->rights['acls']['actions'])) return array();
@@ -1016,8 +1027,6 @@ class actionModel extends model
->beginIF($projectID == 'notzero')->andWhere('project')->gt(0)->fi()
->beginIF($executionID == 'notzero')->andWhere('execution')->gt(0)->fi()
->beginIF($productID == 'all' or $projectID == 'all' or $executionID == 'all')->andWhere("IF((objectType!= 'doc' && objectType!= 'doclib'), ($condition), '1=1')")->fi()
->beginIF($docs and !$this->app->user->admin)->andWhere("IF(objectType != 'doc' || (objectType = 'doc' && (action = 'approved' || action = 'removed')), '1=1', objectID " . helper::dbIN($docs) . ")")->fi()
->beginIF($libs and !$this->app->user->admin)->andWhere("IF(objectType != 'doclib', '1=1', objectID " . helper::dbIN(array_keys($libs)) . ') ')->fi()
->beginIF($actionCondition)->andWhere("($actionCondition)")->fi()
/* Filter out client login/logout actions. */
->andWhere('action')->notin('disconnectxuanxuan,reconnectxuanxuan,loginxuanxuan,logoutxuanxuan')
+2
View File
@@ -39,6 +39,8 @@ $lang->block->lblNum = 'Nummer';
$lang->block->lblHtml = 'HTML';
$lang->block->dynamic = 'Verlauf';
$lang->block->assignToMe = 'Todo';
$lang->block->wait = 'Wait';
$lang->block->doing = 'Doing';
$lang->block->done = 'Done';
$lang->block->lblFlowchart = 'Workflow';
$lang->block->welcome = 'Willkommen';
+2
View File
@@ -39,6 +39,8 @@ $lang->block->lblNum = 'Number';
$lang->block->lblHtml = 'HTML';
$lang->block->dynamic = 'Dynamics';
$lang->block->assignToMe = 'Todo';
$lang->block->wait = 'Wait';
$lang->block->doing = 'Doing';
$lang->block->done = 'Done';
$lang->block->lblFlowchart = 'Flowchart';
$lang->block->welcome = 'Welcome';
+3 -1
View File
@@ -39,7 +39,9 @@ $lang->block->lblNum = 'Numéro';
$lang->block->lblHtml = 'HTML';
$lang->block->dynamic = 'Historique';
$lang->block->assignToMe = 'Todo';
$lang->block->done = 'Done';
$lang->block->wait = 'En Attente';
$lang->block->doing = 'En Cours';
$lang->block->done = 'Terminées';
$lang->block->lblFlowchart = 'Organigramme';
$lang->block->welcome = 'Bienvenue';
$lang->block->lblTesttask = 'Détail Recette';
+2
View File
@@ -39,6 +39,8 @@ $lang->block->lblNum = '条数';
$lang->block->lblHtml = 'HTML内容';
$lang->block->dynamic = '最新动态';
$lang->block->assignToMe = '待处理';
$lang->block->wait = '未开始';
$lang->block->doing = '进行中';
$lang->block->done = '已完成';
$lang->block->lblFlowchart = '流程图';
$lang->block->welcome = '欢迎总览';
@@ -137,7 +137,7 @@ $(function()
<?php if($project->model == 'scrum' or $project->model == 'kanban'):?>
<div class='table-row'>
<div class="col-4 text-center">
<div><h4><?php echo $lang->block->story;?></h4></div>
<div><h4><?php echo $lang->block->storyCount;?></h4></div>
<div>
<div class="col dataTitle"><?php echo $lang->project->allStories . ":";?></div>
<div class="col data"><?php echo $project->allStories;?></div>
@@ -159,15 +159,30 @@ $(function()
</div>
<div>
<div class="col dataTitle"><?php echo $lang->block->estimate . ":";?></div>
<div class="col data"><?php echo $project->estimate;?></div>
<div class="col data"><?php echo $project->estimate . $lang->execution->workHourUnit;?></div>
</div>
<div>
<div class="col dataTitle"><?php echo $lang->block->consumedHours . ":";?></div>
<div class="col data"><?php echo $project->consumed;?></div>
<div class="col data"><?php echo $project->consumed . $lang->execution->workHourUnit;?></div>
</div>
</div>
<div class="col-4 text-center">
<div><h4><?php echo $lang->bug->common;?></h4></div>
<div><h4><?php echo $lang->block->taskCount;?></h4></div>
<div>
<div class="col dataTitle"><?php echo $lang->block->wait . ":";?></div>
<div class="col data"><?php echo $project->waitTasks;?></div>
</div>
<div>
<div class="col dataTitle"><?php echo $lang->block->doing . ":";?></div>
<div class="col data"><?php echo $project->doingTasks;?></div>
</div>
<div>
<div class="col dataTitle"><?php echo $lang->block->done . ":";?></div>
<div class="col data"><?php echo $project->rndDoneTasks;?></div>
</div>
</div>
<div class="col-4 text-center">
<div><h4><?php echo $lang->block->bugCount;?></h4></div>
<div>
<div class="col dataTitle"><?php echo $lang->block->totalBug . ":";?></div>
<div class="col data"><?php echo $project->allBugs;?></div>
+25 -21
View File
@@ -19,13 +19,11 @@
<tr>
<th><?php echo $lang->block->storyCount;?></th>
<th></th>
<th><?php echo $lang->personnel->invest;?></th>
<th><?php echo $lang->block->investment;?></th>
<th></th>
<th><?php echo $lang->workingHour;?></th>
<th></th>
<?php if($vision == 'lite'): ?>
<th><?php echo $lang->block->taskCount;?></th>
<?php else:?>
<th></th>
<?php if($vision == 'rnd'):?>
<th><?php echo $lang->block->bugCount;?></th>
<?php endif;?>
<th></th>
@@ -37,30 +35,36 @@
<td><?php echo $totalData[$projectID]->allStories;?></td>
<th><?php echo $lang->block->totalPeople . ':';?></th>
<td><?php echo $totalData[$projectID]->teamCount ? html::a($this->createLink('project', 'team', 'projectID=' . $projectID), $totalData[$projectID]->teamCount) : 0;?></td>
<th><?php echo $lang->block->estimatedHours . ':';?></th>
<td><?php echo $totalData[$projectID]->estimate . $lang->execution->workHour;?></td>
<th><?php echo ($vision == 'lite' ? $lang->block->totalTask : $lang->block->totalBug) . ':';?></th>
<td><?php echo $vision == 'lite' ? $totalData[$projectID]->allTasks : $totalData[$projectID]->allBugs;?></td>
<th><?php echo ($vision == 'rnd' ? $lang->block->wait : $lang->block->totalTask) . ':';?></th>
<td><?php echo $vision == 'rnd' ? $totalData[$projectID]->waitTasks : $totalData[$projectID]->allTasks;?></td>
<?php if($vision == 'rnd'):?>
<th><?php echo $lang->block->totalBug . ':';?></th>
<td><?php echo $totalData[$projectID]->allBugs;?></td>
<?php endif;?>
</tr>
<tr>
<th><?php echo $lang->block->done . ':';?></th>
<td><?php echo $totalData[$projectID]->doneStories;?></td>
<th></th>
<td></td>
<th><?php echo $lang->block->consumedHours . ':';?></th>
<td><?php echo $totalData[$projectID]->consumed . $lang->execution->workHour;?></td>
<th><?php echo ($vision == 'lite' ? $lang->block->done : $lang->bug->statusList['resolved']) . ':';?></th>
<td><?php echo $vision == 'lite' ? $totalData[$projectID]->doneTasks : $totalData[$projectID]->doneBugs;?></td>
<th><?php echo $lang->block->estimate . ':';?></th>
<td><?php echo $totalData[$projectID]->estimate . $lang->execution->workHourUnit;?></td>
<th><?php echo ($vision == 'rnd' ? $lang->block->doing : $lang->block->done) . ':';?></th>
<td><?php echo $vision == 'rnd' ? $totalData[$projectID]->doingTasks: $totalData[$projectID]->liteDoneTasks;?></td>
<?php if($vision == 'rnd'):?>
<th><?php echo $lang->bug->statusList['resolved'] . ':';?></th>
<td><?php echo $totalData[$projectID]->doneBugs;?></td>
<?php endif;?>
</tr>
<tr>
<th><?php echo $lang->block->left . ':';?></th>
<td><?php echo $totalData[$projectID]->leftStories;?></td>
<th></th>
<td></td>
<th></th>
<td></td>
<th><?php echo ($vision == 'lite' ? $lang->block->undone : $lang->bug->unResolved) . ':';?></th>
<td><?php echo $vision == 'lite' ? $totalData[$projectID]->leftTasks : $totalData[$projectID]->leftBugs;?></td>
<th><?php echo $lang->block->consumedHours . ':';?></th>
<td><?php echo $totalData[$projectID]->consumed . $lang->execution->workHourUnit;?></td>
<th><?php echo $vision == 'rnd' ? $lang->block->done . ':' : $lang->block->undone;?></th>
<td><?php echo $vision == 'rnd' ? $totalData[$projectID]->rndDoneTasks : $totalData[$projectID]->leftTasks;?></td>
<?php if($vision == 'rnd'):?>
<th><?php echo $lang->bug->unResolved . ':';?></th>
<td><?php echo $totalData[$projectID]->leftBugs;?></td>
<?php endif;?>
</tr>
</tbody>
+1 -1
View File
@@ -1807,7 +1807,7 @@ EOD;
if(empty($class)) $class = 'btn';
$title = $lang->goback . $lang->backShortcutKey;
echo html::a($backLink, '<i class="icon-goback icon-back"></i> ' . $lang->goback, '', "id='back' class='{$class}' title={$title}");
echo html::a($backLink, '<i class="icon-goback icon-back"></i> ' . $lang->goback, '', "id='back' class='{$class}' title={$title} data-app='{$app->tab}'");
}
/**
+2 -2
View File
@@ -165,9 +165,9 @@ $lang->custom->testcase->fields['statusList'] = 'Status';
$lang->custom->testcase->fields['review'] = 'Review Required';
$lang->custom->testtask = new stdClass();
$lang->custom->testtask->fields['priList'] = 'Priority';
$lang->custom->testtask->fields['typeList'] = 'Type';
$lang->custom->testtask->fields['statusList'] = 'Status';
$lang->custom->testtask->fields['typeList'] = 'Type';
$lang->custom->testtask->fields['priList'] = 'Priority';
$lang->custom->todo = new stdClass();
$lang->custom->todo->fields['priList'] = 'Priority';
+2 -2
View File
@@ -165,9 +165,9 @@ $lang->custom->testcase->fields['statusList'] = 'Status';
$lang->custom->testcase->fields['review'] = 'Need Review';
$lang->custom->testtask = new stdClass();
$lang->custom->testtask->fields['priList'] = 'Priority';
$lang->custom->testtask->fields['typeList'] = 'Type';
$lang->custom->testtask->fields['statusList'] = 'Status';
$lang->custom->testtask->fields['typeList'] = 'Type';
$lang->custom->testtask->fields['priList'] = 'Priority';
$lang->custom->todo = new stdClass();
$lang->custom->todo->fields['priList'] = 'Priority';
+2 -2
View File
@@ -165,9 +165,9 @@ $lang->custom->testcase->fields['statusList'] = 'Statut';
$lang->custom->testcase->fields['review'] = 'Validation Requise';
$lang->custom->testtask = new stdClass();
$lang->custom->testtask->fields['priList'] = 'Priorité';
$lang->custom->testtask->fields['typeList'] = 'Type';
$lang->custom->testtask->fields['statusList'] = 'Statut';
$lang->custom->testtask->fields['typeList'] = 'Type';
$lang->custom->testtask->fields['priList'] = 'Priorité';
$lang->custom->todo = new stdClass();
$lang->custom->todo->fields['priList'] = 'Priorité';
+2 -2
View File
@@ -165,9 +165,9 @@ $lang->custom->testcase->fields['statusList'] = '状态';
$lang->custom->testcase->fields['review'] = '评审流程';
$lang->custom->testtask = new stdClass();
$lang->custom->testtask->fields['priList'] = '优先级';
$lang->custom->testtask->fields['typeList'] = '测试类型';
$lang->custom->testtask->fields['statusList'] = '状态';
$lang->custom->testtask->fields['typeList'] = '测试类型';
$lang->custom->testtask->fields['priList'] = '优先级';
$lang->custom->todo = new stdClass();
$lang->custom->todo->fields['priList'] = '优先级';
+1
View File
@@ -1,5 +1,6 @@
.user {display: block; width: 80px; float: left; overflow: hidden;}
.c-name {width: 130px;}
.c-desc {width: 300px;}
.btn-admin {margin-left: 0px !important}
#groupList tbody tr.even td {word-wrap: break-word;}
+10 -7
View File
@@ -42,25 +42,28 @@
<td title='<?php echo $group->desc?>'><?php echo $group->desc;?></td>
<td title='<?php echo $users;?>' class="text-ellipsis"><?php echo $users;?></td>
<td class='c-actions'>
<?php $isProjectAdmin = $group->role == 'projectAdmin';?>
<?php $disabled = $isProjectAdmin ? 'disabled' : '';?>
<?php $lang->group->managepriv = $lang->group->managePrivByGroup;?>
<?php common::printIcon('group', 'manageView', "groupID=$group->id", $group, 'list', 'eye', '', $disabled);?>
<?php common::printIcon('group', 'managepriv', "type=byGroup&param=$group->id", $group, 'list', 'lock', '', $disabled);?>
<?php $lang->group->managemember = $lang->group->manageMember;?>
<?php $isProjectAdmin = $group->role == 'projectAdmin';?>
<?php if($isProjectAdmin):?>
<?php echo "<button class='btn disabled'><i class='icon icon-eye disabled' title='{$lang->group->manageView}'></i></button>";?>
<?php echo "<button class='btn disabled'><i class='icon icon-lock disabled' title='{$lang->group->managepriv}'></i></button>";?>
<?php common::printIcon('group', 'manageProjectAdmin', "groupID=$group->id", $group, 'list', 'persons');?>
<?php echo "<button class='btn disabled'><i class='icon icon-edit disabled' title='{$lang->group->edit}'></i></button>";?>
<?php echo "<button class='btn disabled'><i class='icon icon-copy disabled' title='{$lang->group->copy}'></i></button>";?>
<?php else:?>
<?php common::printIcon('group', 'manageView', "groupID=$group->id", $group, 'list', 'eye');?>
<?php common::printIcon('group', 'managepriv', "type=byGroup&param=$group->id", $group, 'list', 'lock');?>
<?php common::printIcon('group', 'manageMember', "groupID=$group->id", $group, 'list', 'persons', '', "iframe", true, "data-width='90%'");?>
<?php common::printIcon('group', 'edit', "groupID=$group->id", $group, 'list', '', '', "iframe", true, "data-width='550'");?>
<?php common::printIcon('group', 'copy', "groupID=$group->id", $group, 'list', '', '', "iframe", true, "data-width='550'");?>
<?php endif;?>
<?php common::printIcon('group', 'edit', "groupID=$group->id", $group, 'list', '', '', "iframe $disabled", true, "data-width='550'");?>
<?php common::printIcon('group', 'copy', "groupID=$group->id", $group, 'list', '', '', "iframe $disabled", true, "data-width='550'");?>
<?php
if(common::hasPriv('group', 'delete'))
{
if($isProjectAdmin)
{
echo "<button class='btn disabled'><i class='icon icon-trash disabled' title='{$lang->group->delete}'></i></button>";
echo "<a class='btn btn-admin disabled'><i class='icon icon-trash disabled' title='{$lang->group->delete}'></i></a>";
}
else
{
+1 -1
View File
@@ -17,4 +17,4 @@ td.delayed {background: #e84e0f !important; color: white;}
.c-hours {width: 50px;}
.c-status, .c-date, .c-user-short {width: 70px;}
.c-project {width: 130px;}
#taskTable .c-user{width: 110px; padding-left: 29px;}
#taskTable .assigned-title{width: 110px; padding-left: 29px;}
+1 -1
View File
@@ -73,7 +73,7 @@
<?php endif;?>
<th class='c-date text-center'><?php common::printOrderLink('deadline', $orderBy, $vars, $lang->task->deadlineAB);?></th>
<?php if($type != 'assignedTo'): ?>
<th class='c-user'><?php common::printOrderLink('assignedTo', $orderBy, $vars, $lang->task->assignedTo);?></th>
<th class='c-user assigned-title'><?php common::printOrderLink('assignedTo', $orderBy, $vars, $lang->task->assignedTo);?></th>
<?php endif;?>
<?php if($type != 'finishedBy'): ?>
<th class='c-user'><?php common::printOrderLink('finishedBy', $orderBy, $vars, $lang->task->finishedBy);?></th>
+2
View File
@@ -88,3 +88,5 @@ th.c-actions {width: 50px;}
#productTableList > tr.row-line.is-nest-child > td.text-left.table-nest-title > span.table-nest-icon.icon:before{content: '\e6f2'; background-color: white; display: inline;}
#productTableList > tr.row-line.no-nest > td.text-left.table-nest-title > span.table-nest-icon.icon:before{content: '\e6f2'; background-color: white; display: inline;}
.statistic {margin-left: 10px; color: #838a9d; float: left; position: relative; line-height: 28px;}
.table-footer.fixed-footer .statistic {color: #fff;}
+37
View File
@@ -60,6 +60,23 @@ $(function()
});
}
/* Add a statistics prompt statement after the Edit button */
function addStatistic()
{
var checkedLength = $(":checkbox[name^='productIDList']:checked").length;
var summary = checkedProducts.replace('%s', checkedLength);
var statistic = "<div id='productsSummary' class='statistic'>" + summary + "</div>";
if(checkedLength > 0)
{
$('#productsSummary').remove();
$('#editBtn').after(statistic);
}
else
{
$('#productsSummary').addClass('hidden');
}
}
$('#productTableList').on('click', '.row-program,.row-line', function(e)
{
if($(e.target).closest('.table-nest-toggle,a').length) return;
@@ -79,7 +96,27 @@ $(function()
{
updatePrarentCheckbox($('#productTableList>tr[data-id="' + parentID + '"]'));
}
addStatistic()
});
$('#productListForm').on('checkChange', updateCheckboxes);
updateCheckboxes();
$(":checkbox[name^='productIDList']").on('click', function()
{
addStatistic()
});
$(".check-all").on('click', function()
{
if($(":checkbox[name^='productIDList']:not(:checked)").length == 0)
{
$(":checkbox[name^='productIDList']").prop('checked', false);
}
else
{
$(":checkbox[name^='productIDList']").prop('checked', true);
}
addStatistic()
});
});
+1
View File
@@ -34,6 +34,7 @@ $lang->product->changeProgram = "{$lang->productCommon} confirmation of the s
$lang->product->changeProgramTip = "%s > Change Program";
$lang->product->addWhitelist = 'Add Whitelist';
$lang->product->unbindWhitelist = 'Remove Whitelist';
$lang->product->checkedProducts = '%s products selected';
$lang->product->indexAction = "All {$lang->productCommon}";
$lang->product->closeAction = "Close {$lang->productCommon}";
+1
View File
@@ -34,6 +34,7 @@ $lang->product->changeProgram = "{$lang->productCommon} confirmation of the s
$lang->product->changeProgramTip = "%s > Change Program";
$lang->product->addWhitelist = 'Add Whitelist';
$lang->product->unbindWhitelist = 'Unbind Whitelist';
$lang->product->checkedProducts = '%s products selected';
$lang->product->indexAction = "All {$lang->productCommon}";
$lang->product->closeAction = "Close {$lang->productCommon}";
+1
View File
@@ -34,6 +34,7 @@ $lang->product->changeProgram = "{$lang->productCommon} confirmation of the s
$lang->product->changeProgramTip = "%s > Change Program";
$lang->product->addWhitelist = 'Add Whitelist';
$lang->product->unbindWhitelist = 'Remove Whitelist';
$lang->product->checkedProducts = '%s produits s électionnés'
$lang->product->indexAction = "All {$lang->productCommon}";
$lang->product->closeAction = "Fermer {$lang->productCommon}";
+1
View File
@@ -34,6 +34,7 @@ $lang->product->changeProgram = "{$lang->productCommon}调整所属项目集
$lang->product->changeProgramTip = "%s > 修改项目集";
$lang->product->addWhitelist = '添加白名单';
$lang->product->unbindWhitelist = '移除白名单';
$lang->product->checkedProducts = '已选择%s项产品';
$lang->product->indexAction = "所有{$lang->productCommon}仪表盘";
$lang->product->closeAction = "关闭{$lang->productCommon}";
+5 -4
View File
@@ -242,10 +242,10 @@
<?php if(!empty($product) and $canBatchEdit):?>
<div class="checkbox-primary check-all"><label><?php echo $lang->selectAll?></label></div>
<div class="table-actions btn-toolbar">
<?php
$actionLink = $this->createLink('product', 'batchEdit');
echo html::commonButton($lang->edit, "data-form-action='$actionLink'");
?>
<?php
$actionLink = $this->createLink('product', 'batchEdit');
echo html::commonButton($lang->edit, "id='editBtn' data-form-action='$actionLink'");
?>
<?php endif;?>
</div>
</div>
@@ -255,6 +255,7 @@
</div>
<?php js::set('orderBy', $orderBy)?>
<?php js::set('browseType', $browseType)?>
<?php js::set('checkedProducts', $lang->product->checkedProducts);?>
<?php if(commonModel::isTutorialMode()): ?>
<style>
#productListForm {overflow: hidden;}
+1
View File
@@ -880,6 +880,7 @@ class project extends control
*/
public function dynamic($projectID = 0, $type = 'today', $param = '', $recTotal = 0, $date = '', $direction = 'next')
{
$this->loadModel('execution');
$this->project->setMenu($projectID);
/* Save session. */
+31 -22
View File
@@ -333,25 +333,31 @@ class projectModel extends model
$allBugs = $this->getTotalBugByProject($projectIdList, 'all');
$doneBugs = $this->getTotalBugByProject($projectIdList, 'resolved');
$leftTasks = $this->getTotalTaskByProject($projectIdList, 'undone');
$allTasks = $this->getTotalTaskByProject($projectIdList, 'all');
$doneTasks = $this->getTotalTaskByProject($projectIdList, 'done');
$leftTasks = $this->getTotalTaskByProject($projectIdList, 'undone');
$allTasks = $this->getTotalTaskByProject($projectIdList, 'all');
$waitTasks = $this->getTotalTaskByProject($projectIdList, 'wait');
$doingTasks = $this->getTotalTaskByProject($projectIdList, 'doing');
$rndDoneTasks = $this->getTotalTaskByProject($projectIdList, 'done');
$liteDoneTasks = $this->getTotalTaskByProject($projectIdList, 'donelite');
foreach($projects as $projectID => $project)
{
$project->consumed = isset($hours[$projectID]) ? (float)$hours[$projectID]->consumed : 0;
$project->estimate = isset($hours[$projectID]) ? (float)$hours[$projectID]->estimate : 0;
$project->teamCount = isset($teams[$projectID]) ? $teams[$projectID] : 0;
$project->leftTasks = isset($leftTasks[$projectID]) ? $leftTasks[$projectID] : 0;
$project->leftBugs = isset($leftBugs[$projectID]) ? $leftBugs[$projectID] : 0;
$project->allBugs = isset($allBugs[$projectID]) ? $allBugs[$projectID] : 0;
$project->doneBugs = isset($doneBugs[$projectID]) ? $doneBugs[$projectID] : 0;
$project->allStories = $allStories[$projectID];
$project->doneStories = $doneStories[$projectID];
$project->leftStories = $leftStories[$projectID];
$project->leftTasks = isset($leftTasks[$projectID]) ? $leftTasks[$projectID] : 0;
$project->allTasks = isset($allTasks[$projectID]) ? $allTasks[$projectID] : 0;
$project->doneTasks = isset($doneTasks[$projectID]) ? $doneTasks[$projectID] : 0;
$project->consumed = isset($hours[$projectID]) ? (float)$hours[$projectID]->consumed : 0;
$project->estimate = isset($hours[$projectID]) ? (float)$hours[$projectID]->estimate : 0;
$project->teamCount = isset($teams[$projectID]) ? $teams[$projectID] : 0;
$project->leftTasks = isset($leftTasks[$projectID]) ? $leftTasks[$projectID] : 0;
$project->leftBugs = isset($leftBugs[$projectID]) ? $leftBugs[$projectID] : 0;
$project->allBugs = isset($allBugs[$projectID]) ? $allBugs[$projectID] : 0;
$project->doneBugs = isset($doneBugs[$projectID]) ? $doneBugs[$projectID] : 0;
$project->allStories = $allStories[$projectID];
$project->doneStories = $doneStories[$projectID];
$project->leftStories = $leftStories[$projectID];
$project->leftTasks = isset($leftTasks[$projectID]) ? $leftTasks[$projectID] : 0;
$project->allTasks = isset($allTasks[$projectID]) ? $allTasks[$projectID] : 0;
$project->waitTasks = isset($waitTasks[$projectID]) ? $waitTasks[$projectID] : 0;
$project->doingTasks = isset($doingTasks[$projectID]) ? $doingTasks[$projectID] : 0;
$project->rndDoneTasks = isset($rndDoneTasks[$projectID]) ? $rndDoneTasks[$projectID] : 0;
$project->liteDoneTasks = isset($liteDoneTasks[$projectID]) ? $liteDoneTasks[$projectID] : 0;
if(is_float($project->consumed)) $project->consumed = round($project->consumed, 1);
if(is_float($project->estimate)) $project->estimate = round($project->estimate, 1);
@@ -795,12 +801,15 @@ class projectModel extends model
*/
public function getTotalTaskByProject($projectIdList, $status)
{
return $this->dao->select('project, count(*) as tasks')->from(TABLE_TASK)
->where('project')->in($projectIdList)
->andWhere('deleted')->eq(0)
->beginIF($status == 'done')->andWhere('status')->in('done,closed')->fi()
->beginIF($status == 'undone')->andWhere('status')->in('wait,pause,cancel')->fi()
->groupBy('project')
return $this->dao->select('t1.project, count(t1.id) as tasks')->from(TABLE_TASK)->alias('t1')
->leftJoin(TABLE_EXECUTION)->alias('t2')->on('t1.execution=t2.id')
->where('t1.project')->in($projectIdList)
->andWhere('t1.deleted')->eq(0)
->andWhere('t2.deleted')->eq(0)
->beginIF($status == 'donelite')->andWhere('t1.status')->in('done,closed')->fi()
->beginIF($status == 'undone')->andWhere('t1.status')->in('wait,pause,cancel')->fi()
->beginIF(strpos(',wait,doing,done,', ",$status,") !== false)->andWhere('t1.status')->eq($status)->fi()
->groupBy('t1.project')
->fetchPairs('project');
}
+7 -5
View File
@@ -27,7 +27,9 @@
#cards .project-infos > span > .icon {font-size: 12px; display: inline-block; position: relative; top: -1px}
#cards .project-infos > span + span {margin-left: 15px;}
#cards .project-infos > .budget {max-width: 75px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;}
#cards .project-infos > .budget, #cards .project-infos > .date {background: #F8F8F8; border: unset;}
#cards .project-detail {position: absolute; top: 75px; left: 16px; right: 16px; font-size: 12px;}
#cards .project-detail .statistics-title {color: #5B606E;}
#cards .project-footer {position: absolute; bottom: 10px; right: 10px; left: 15px;}
#cardsFooter .pager {margin: 0; float: right;}
#cardsFooter .pager .btn {border: none; padding-top: 4px;}
@@ -37,7 +39,7 @@
#cards .panel .label-closed {background: #D4F7F9 !important; color: #00A78E;}
#cards .panel .label-delay {background: #F85A40 !important; color: #FFF;}
#cards .project-infos .text-red {color: #F85A40 !important;}
#cards .project-detail .leftTasks, .totalLeft {display:block; margin-top: 8px;}
#cards .project-detail .leftTasks, .totalLeft {display:block; font-size: 18px; font-weight: bold; color: #3C4353;}
#cards .project-members {float: left; height: 24px; line-height: 24px;}
#cards .project-members > a {display: inline-block; height: 24px;}
#cards .project-members > a + a {margin-left: -5px;}
@@ -120,20 +122,20 @@
$canActions = (common::hasPriv('project','edit') or common::hasPriv('project','start') or common::hasPriv('project','activate') or common::hasPriv('project','suspend') or common::hasPriv('project','close'));
?>
<span title="<?php echo $budgetTitle;?>" class='label label-outline budget'><?php echo $budgetTitle;?></span>
<span title="<?php echo $project->date;?>" class="label label-outline <?php echo $status == 'delay' ? 'text-red' : '';?>"><?php echo $project->date;?></span>
<span title="<?php echo $project->date;?>" class="label label-outline date <?php echo $status == 'delay' ? 'text-red' : '';?>"><?php echo $project->date;?></span>
</div>
<div class='project-detail'>
<div class='row'>
<div class='col-xs-4'>
<div><?php echo $lang->project->progress;?></div>
<div><span class='statistics-title'><?php echo $lang->project->progress;?></span></div>
<?php echo html::ring($project->hours->progress); ?>
</div>
<div class='col-xs-4'>
<span><?php echo $lang->project->leftTasks;?></span>
<span class='statistics-title'><?php echo $lang->project->leftTasks;?></span>
<span class='leftTasks' title="<?php echo $project->leftTasks;?>"><?php echo $project->leftTasks;?></span>
</div>
<div class='col-xs-4'>
<span><?php echo $lang->project->leftHours;?></span>
<span class='statistics-title'><?php echo $lang->project->leftHours;?></span>
<span class='totalLeft' title="<?php echo empty($project->hours->totalLeft) ? '—' : $project->hours->totalLeft . $lang->execution->workHour;?>"><?php echo empty($project->hours->totalLeft) ? '—' : $project->hours->totalLeft . $lang->execution->workHourUnit;?></span>
</div>
</div>
+1 -1
View File
@@ -176,7 +176,7 @@
<th><?php echo $lang->task->mailto;?></th>
<td>
<div class='input-group'>
<?php echo html::select('mailto[]', $users, str_replace(' ' , '', $task->mailto), 'class="form-control picker-select" multiple');?>
<?php echo html::select('mailto[]', $users, str_replace(' ' , '', $task->mailto), 'class="form-control picker-select" multiple data-drop-direction="bottom"');?>
<?php echo $this->fetch('my', 'buildContactLists');?>
</div>
</td>
+47 -5
View File
@@ -318,14 +318,16 @@ class testtask extends control
if($this->app->tab == 'project')
{
$this->loadModel('project')->setMenu($task->project);
$this->lang->modulePageNav = $this->testtask->select($productID, $taskID, 'project', $task->project);
}
elseif($this->app->tab == 'execution')
{
$this->loadModel('execution')->setMenu($task->execution);
$this->lang->modulePageNav = $this->testtask->select($productID, $taskID, 'execution', $task->execution);
}
elseif($this->app->tab == 'qa')
{
$this->loadModel('qa')->setMenu($this->products, $productID, $task->branch, $taskID);
$this->testtask->setMenu($this->products, $productID, $task->branch, $taskID);
}
$this->executeHooks($taskID);
@@ -481,14 +483,16 @@ class testtask extends control
if($this->app->tab == 'project')
{
$this->loadModel('project')->setMenu($task->project);
$this->lang->modulePageNav = $this->testtask->select($productID, $taskID, 'project', $task->project);
}
elseif($this->app->tab == 'execution')
{
$this->loadModel('execution')->setMenu($task->execution);
$this->lang->modulePageNav = $this->testtask->select($productID, $taskID, 'execution', $task->execution);
}
else
{
$this->loadModel('qa')->setMenu($this->products, $productID, $task->branch, $taskID);
$this->testtask->setMenu($this->products, $productID, $task->branch, $taskID);
}
setcookie('preTaskID', $taskID, $this->config->cookieLife, $this->config->webRoot, '', $this->config->cookieSecure, true);
@@ -612,14 +616,16 @@ class testtask extends control
if($this->app->tab == 'project')
{
$this->loadModel('project')->setMenu($task->project);
$this->lang->modulePageNav = $this->testtask->select($productID, $taskID, 'project', $task->project);
}
elseif($this->app->tab == 'execution')
{
$this->loadModel('execution')->setMenu($task->execution);
$this->lang->modulePageNav = $this->testtask->select($productID, $taskID, 'execution', $task->execution);
}
else
{
$this->loadModel('qa')->setMenu($this->products, $productID, $branchID, $taskID);
$this->testtask->setMenu($this->products, $productID, $branchID, $taskID);
}
unset($this->lang->testtask->report->charts['bugStageGroups']);
unset($this->lang->testtask->report->charts['bugHandleGroups']);
@@ -676,14 +682,16 @@ class testtask extends control
if($this->app->tab == 'project')
{
$this->loadModel('project')->setMenu($this->session->project);
$this->lang->modulePageNav = $this->testtask->select($productID, $taskID, 'project', $task->project);
}
elseif($this->app->tab == 'execution')
{
$this->loadModel('execution')->setMenu($task->execution);
$this->lang->modulePageNav = $this->testtask->select($productID, $taskID, 'execution', $task->execution);
}
else
{
$this->loadModel('qa')->setMenu($this->products, $productID, $task->branch, $taskID);
$this->testtask->setMenu($this->products, $productID, $task->branch, $taskID);
}
/* Determines whether an object is editable. */
@@ -1062,14 +1070,16 @@ class testtask extends control
if($this->app->tab == 'project')
{
$this->loadModel('project')->setMenu($task->project);
$this->lang->modulePageNav = $this->testtask->select($productID, $taskID, 'project', $task->project);
}
elseif($this->app->tab == 'execution')
{
$this->loadModel('execution')->setMenu($task->execution);
$this->lang->modulePageNav = $this->testtask->select($productID, $taskID, 'execution', $task->execution);
}
else
{
$this->loadModel('qa')->setMenu($this->products, $productID, $task->branch, $taskID);
$this->testtask->setMenu($this->products, $productID, $task->branch, $taskID);
}
/* Load pager. */
@@ -1527,4 +1537,36 @@ class testtask extends control
$pairs = $this->loadModel('testreport')->getPairs($productID);
return print(html::select('testreport', array('') + $pairs, '', "class='form-control chosen'"));
}
/**
* Drop menu page.
*
* @param int $productID
* @param int $branch
* @param int $taskID
* @param string $module
* @param string $method
* @param string $objectType
* @param int $objectID
* @access public
* @return void
*/
public function ajaxGetDropMenu($productID, $branch, $taskID, $module, $method, $objectType = '', $objectID = 0)
{
$status = empty($objectType) ? 'local' : 'totalStatus';
$testtasks = $this->testtask->getProductTasks($productID, $branch, 'id_desc', null, array($status, 'totalStatus'));
$namePairs = array_column($testtasks, 'name');
$this->view->currentTaskID = $taskID;
$this->view->testtasks = $testtasks;
$this->view->module = $module;
$this->view->method = $method;
$this->view->productID = $productID;
$this->view->branch = $branch;
$this->view->objectType = $objectType;
$this->view->objectID = $objectID;
$this->view->testtasksPinyin = common::convert2Pinyin($namePairs);
$this->display();
}
}
+69
View File
@@ -2287,4 +2287,73 @@ class testtaskModel extends model
}
return $menu;
}
/**
* Set menu.
*
* @param array $products
* @param int $productID
* @param int|string $branch
* @param int $taskID
* @access public
* @return void
*/
public function setMenu($products, $productID, $branch = '', $taskID = 0)
{
if(!$this->app->user->admin and strpos(",{$this->app->user->view->products},", ",$productID,") === false and $productID != 0 and !defined('TUTORIAL'))
{
$this->app->loadLang('product');
return print(js::error($this->lang->product->accessDenied) . js::locate('back'));
}
$branch = ($this->cookie->preBranch !== '' and $branch === '') ? $this->cookie->preBranch : $branch;
setcookie('preBranch', $branch, $this->config->cookieLife, $this->config->webRoot, '', $this->config->cookieSecure, true);
$product = $this->loadModel('product')->getById($productID);
if($product and $product->type != 'normal') $this->lang->product->branch = sprintf($this->lang->product->branch, $this->lang->product->branchName[$product->type]);
$selectHtml = $this->product->getSwitcher($productID, $taskID, $branch);
if($taskID and $this->app->viewType != 'mhtml')
{
$testtask = $this->getById($taskID);
$module = $this->app->rawModule;
$method = $this->app->rawMethod;
$dropMenuLink = helper::createLink('testtask', 'ajaxGetDropMenu', "productID=$productID&branch=$branch&taskID=$taskID&module=$module&method=$method");
$selectHtml .= "<div class='btn-group header-btn' id='swapper'><button data-toggle='dropdown' type='button' class='btn' id='currentTesttask' title='{$testtask->name}'><span class='text'>{$testtask->name}</span> <span class='caret' style='margin-bottom: -1px'></span></button><div id='dropMenu' class='dropdown-menu search-list' data-ride='searchList' data-url='$dropMenuLink'>";
$selectHtml .= '<div class="input-control search-box has-icon-left has-icon-right search-example"><input type="search" class="form-control search-input" /><label class="input-control-icon-left search-icon"><i class="icon icon-search"></i></label><a class="input-control-icon-right search-clear-btn"><i class="icon icon-close icon-sm"></i></a></div>';
$selectHtml .= "</div></div>";
}
$this->lang->switcherMenu = $selectHtml;
common::setMenuVars('qa', $productID);
}
/**
* Create the select code of testtasks.
*
* @param int $productID
* @param int $testtaskID
* @param string $objectType execution|project
* @param int $objectID
* @access public
* @return string
*/
public function select($productID, $testtaskID, $objectType = '', $objectID = 0)
{
$output = '';
$currentModule = $this->app->rawModule;
$currentMethod = $this->app->rawMethod;
if($testtaskID and $this->app->viewType != 'mhtml')
{
$dropMenuLink = helper::createLink('testtask', 'ajaxGetDropMenu', "productID=$productID&branch=&taskID=$testtaskID&module=$currentModule&method=$currentMethod&objectType=$objectType&objectID=$objectID");
$testtask = $this->getById($testtaskID);
$output .= "<div class='btn-group angle-btn'><div class='btn-group'><button data-toggle='dropdown' type='button' class='btn btn-limit' id='currentTesttask' title='{$testtask->name}'><span class='text'>{$testtask->name}</span> <span class='caret'></span></button><div id='dropMenu' class='dropdown-menu search-list' data-ride='searchList' data-url='$dropMenuLink'>";
$output .= '<div class="input-control search-box has-icon-left has-icon-right search-example"><input type="search" class="form-control search-input" /><label class="input-control-icon-left search-icon"><i class="icon icon-search"></i></label><a class="input-control-icon-right search-clear-btn"><i class="icon icon-close icon-sm"></i></a></div>';
$output .= "</div></div>";
}
$output .= '</div>';
return $output;
}
}
@@ -0,0 +1,43 @@
<?php
/**
* The ajaxgetdropmenu file of testtask module of ZenTaoPMS.
*
* @copyright Copyright 2009-2022 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL(http://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @author Shujie Tian<tianshujie@easycorp.ltd>
* @package testtask
* @version $Id: ajaxgetdropmenu.html.php 935 2022-06-27 16:44:24Z $
* @link https://www.zentao.net
*/
?>
<style>
#currentTesttask + #dropMenu {max-width: 250px;}
#currentTesttask + #dropMenu > .list-group {overflow-x: hidden;}
#currentTesttask + #dropMenu .table-row > .table-col > .list-group {max-width: 248px;}
</style>
<?php
$selectHtml = '';
foreach($testtasks as $testtaskID => $testtask)
{
if($objectType == 'project' and $testtask->project != $objectID) continue;
if($objectType == 'execution' and $testtask->execution != $objectID) continue;
$selected = (string)$testtaskID == $currentTaskID ? 'selected' : '';
$param = $method == 'report' ? "productID=$productID&taskID=$testtaskID&browseType=all&branch=$branch" : "taskID=$testtaskID";
$selectHtml .= html::a($this->createLink($module, $method, $param), $testtask->name, '', "class='$selected' data-key='{$testtasksPinyin[$testtask->name]}' data-app='{$this->app->tab}' title='{$testtask->name}'");
}
?>
<div class="table-row">
<div class="table-col">
<div class='list-group'><?php echo $selectHtml;?></div>
</div>
</div>
<script>
$(function()
{
$('#currentTesttask + #dropMenu .list-group .table-row .table-col a').mouseout(function()
{
$(this).removeClass('active');
})
})
</script>
+1 -1
View File
@@ -1292,7 +1292,7 @@ class user extends control
public function ajaxGetContactUsers($contactListID, $dropdownName = 'mailto', $oldUsers = '')
{
$list = $contactListID ? $this->user->getContactListByID($contactListID) : '';
$attr = $dropdownName == 'mailto' ? "data-placeholder='{$this->lang->chooseUsersToMail}'" : '';
$attr = $dropdownName == 'mailto' ? "data-placeholder='{$this->lang->chooseUsersToMail}' data-drop-direction='bottom'" : '';
$users = $this->user->getPairs('devfirst|nodeleted|noclosed', $list ? $list->userList : '', $this->config->maxCount);
if(isset($this->config->user->moreLink)) $this->config->moreLinks[$dropdownName . "[]"] = $this->config->user->moreLink;
+21
View File
@@ -142,6 +142,16 @@ $(function()
}
}
ztreeObj.expandNode(treeNode, true, false, false);
if(treeNode.checked && !treeNode.nocheck)
{
var childs = getChildNodes(treeNode);
for(i = 0; i < childs.length; i++)
{
var node = ztreeObj.getNodeByParam("id", childs[i]);
ztreeObj.checkNode(node, true, true);
}
}
}
},
error: function()
@@ -151,6 +161,17 @@ $(function()
});
}
function getChildNodes(treeNode)
{
var childNodes = ztreeObj.transformToArray(treeNode);
var nodes = new Array();
for(i = 0; i < childNodes.length; i++)
{
nodes[i] = childNodes[i].id;
}
return nodes;
}
function zTreeOnAsyncSuccess()
{
$("#loadPrompt").remove();