diff --git a/config/filter.php b/config/filter.php
index c700ab2094..ac0f39bb27 100755
--- a/config/filter.php
+++ b/config/filter.php
@@ -138,6 +138,7 @@ $filter->svn->cat = new stdclass();
$filter->svn->diff = new stdclass();
$filter->task->create = new stdclass();
$filter->task->export = new stdclass();
+$filter->task->recordestimate = new stdclass();
$filter->execution->default = new stdclass();
$filter->execution->story = new stdclass();
$filter->testcase->default = new stdclass();
@@ -298,8 +299,9 @@ $filter->story->track->cookie['preProductID'] = 'int';
$filter->productplan->browse->cookie['viewType'] = 'code';
-$filter->task->create->cookie['lastTaskModule'] = 'int';
-$filter->task->export->cookie['checkedItem'] = 'reg::checked';
+$filter->task->create->cookie['lastTaskModule'] = 'int';
+$filter->task->export->cookie['checkedItem'] = 'reg::checked';
+$filter->task->recordestimate->cookie['taskEffortFold'] = 'reg::checked';
$filter->execution->default->cookie['kanbanview'] = 'code';
$filter->execution->story->cookie['storyPreExecutionID'] = 'int';
diff --git a/db/update17.6.2.sql b/db/update17.6.2.sql
index 210f7b25a6..3217d8b7db 100644
--- a/db/update17.6.2.sql
+++ b/db/update17.6.2.sql
@@ -15,7 +15,6 @@ CREATE TABLE IF NOT EXISTS `zt_ticket` (
`deadline` date NOT NULL,
`pri` tinyint unsigned NOT NULL DEFAULT '0',
`estimate` float unsigned NOT NULL,
- `consumed` float unsigned NOT NULL,
`left` float unsigned NOT NULL,
`status` varchar(30) NOT NULL,
`openedBy` varchar(30) NOT NULL,
diff --git a/db/zentao.sql b/db/zentao.sql
index c8aa8923f8..5e2f79f431 100755
--- a/db/zentao.sql
+++ b/db/zentao.sql
@@ -6333,6 +6333,7 @@ CREATE TABLE IF NOT EXISTS `zt_im_chat` (
`pinnedMessages` text NOT NULL DEFAULT '',
`mergedChats` text NOT NULL DEFAULT '',
`adminInvite` enum('0','1') NOT NULL DEFAULT '0',
+ `avatar` text NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
KEY `gid` (`gid`),
KEY `name` (`name`),
@@ -7141,7 +7142,6 @@ CREATE TABLE IF NOT EXISTS `zt_ticket` (
`deadline` date NOT NULL,
`pri` tinyint unsigned NOT NULL DEFAULT '0',
`estimate` float unsigned NOT NULL,
- `consumed` float unsigned NOT NULL,
`left` float unsigned NOT NULL,
`status` varchar(30) NOT NULL,
`openedBy` varchar(30) NOT NULL,
diff --git a/module/action/lang/de.php b/module/action/lang/de.php
index 861617d835..f11ff708dd 100644
--- a/module/action/lang/de.php
+++ b/module/action/lang/de.php
@@ -380,6 +380,7 @@ $lang->action->label->importedproductplan = 'imported';
$lang->action->label->importedrelease = 'imported';
$lang->action->label->importedexecution = 'imported';
$lang->action->label->importedbuild = 'imported';
+$lang->action->label->importedticket = 'imported';
$lang->action->label->fromsonarqube = 'created a bug from SonarQube Issue named:';
$lang->action->label->bind = 'bound';
$lang->action->label->unbind = 'unbound';
diff --git a/module/action/lang/en.php b/module/action/lang/en.php
index defc55df36..fbdaf2970f 100755
--- a/module/action/lang/en.php
+++ b/module/action/lang/en.php
@@ -380,6 +380,7 @@ $lang->action->label->importedproductplan = 'imported';
$lang->action->label->importedrelease = 'imported';
$lang->action->label->importedexecution = 'imported';
$lang->action->label->importedbuild = 'imported';
+$lang->action->label->importedticket = 'imported';
$lang->action->label->fromsonarqube = 'created a bug from SonarQube Issue named:';
$lang->action->label->bind = 'bound';
$lang->action->label->unbind = 'unbound';
diff --git a/module/action/lang/fr.php b/module/action/lang/fr.php
index 8443df084c..1e033620da 100644
--- a/module/action/lang/fr.php
+++ b/module/action/lang/fr.php
@@ -380,6 +380,7 @@ $lang->action->label->importedproductplan = 'imported';
$lang->action->label->importedrelease = 'imported';
$lang->action->label->importedexecution = 'imported';
$lang->action->label->importedbuild = 'imported';
+$lang->action->label->importedticket = 'imported';
$lang->action->label->fromsonarqube = 'created a bug from SonarQube Issue named:';
$lang->action->label->bind = 'bound';
$lang->action->label->unbind = 'unbound';
diff --git a/module/action/lang/zh-cn.php b/module/action/lang/zh-cn.php
index b7d6217ddb..251a39f9a4 100755
--- a/module/action/lang/zh-cn.php
+++ b/module/action/lang/zh-cn.php
@@ -380,6 +380,7 @@ $lang->action->label->importedproductplan = '导入了';
$lang->action->label->importedrelease = '导入了';
$lang->action->label->importedexecution = '导入了';
$lang->action->label->importedbuild = '导入了';
+$lang->action->label->importedticket = '导入了';
$lang->action->label->fromsonarqube = '由SonarQube问题创建';
$lang->action->label->bind = '绑定了';
$lang->action->label->unbind = '取消绑定了';
diff --git a/module/action/model.php b/module/action/model.php
index df39540510..f80d99301b 100755
--- a/module/action/model.php
+++ b/module/action/model.php
@@ -1264,7 +1264,7 @@ class actionModel extends model
{
$objectType = str_replace('imported', '', $action->action);
$objectTable = zget($this->config->objectTables, $objectType);
- $objectName = $objectType == 'productplan' ? 'title' : 'name';
+ $objectName = ($objectType == 'productplan' or $objectType == 'ticket') ? 'title' : 'name';
$action->objectName = $this->dao->select($objectName)->from($objectTable)->where('id')->eq($action->extra)->fetch($objectName);
}
elseif($action->objectType == 'module' and !empty($action->extra) and $action->action != 'deleted')
diff --git a/module/execution/model.php b/module/execution/model.php
index 53d34b207f..40f754c853 100644
--- a/module/execution/model.php
+++ b/module/execution/model.php
@@ -4630,7 +4630,7 @@ class executionModel extends model
}
else
{
- echo $execution->name;
+ echo "" . $execution->name . '';
if(!helper::isZeroDate($execution->end))
{
if($execution->status != 'closed')
diff --git a/module/execution/view/kanban.html.php b/module/execution/view/kanban.html.php
index ef11cd5ea9..f8acbc9740 100644
--- a/module/execution/view/kanban.html.php
+++ b/module/execution/view/kanban.html.php
@@ -157,7 +157,7 @@ js::set('priv',
" . $lang->searchAB, '', "class='btn btn-link querybox-toggle'");
echo html::a('javascript:fullScreen()', " " . $lang->kanban->fullScreen, '', "class='btn btn-link'");
if(common::hasPriv('execution', 'setKanban')) echo html::a(helper::createLink('execution', 'setKanban', "executionID=$execution->id", '', true), ' ' . $lang->settings, '', "class='iframe btn btn-link text-left' data-width='$width'");
diff --git a/module/kanban/css/setting.css b/module/kanban/css/setting.css
index 13f732de59..eb0d66d2ec 100644
--- a/module/kanban/css/setting.css
+++ b/module/kanban/css/setting.css
@@ -8,3 +8,4 @@
#mainContent .objectBox .checkbox-primary>label:after {width: 14px; height: 14px;}
#mainContent table > tbody th {width: 110px !important;}
[lang^=en] .laneHeightBox > label, [lang^=de] .laneHeightBox > label, [lang^=fr] .laneHeightBox > label, [lang^=en] .importBox > label, [lang^=de] .importBox > label, [lang^=fr] .importBox > label {margin-left: 0px;}
+#dataform tr > th {vertical-align: top;}
diff --git a/module/kanban/view/viewarchivedcard.html.php b/module/kanban/view/viewarchivedcard.html.php
index 2c4c142e36..41efc5d7bc 100644
--- a/module/kanban/view/viewarchivedcard.html.php
+++ b/module/kanban/view/viewarchivedcard.html.php
@@ -62,6 +62,7 @@ $app->loadLang('execution');
$app->loadLang('release');
$app->loadLang('build');
$app->loadLang('productplan');
+if($this->config->edition != 'open') $app->loadLang('ticket');
js::set('systemMode', $this->config->systemMode);
?>
@@ -103,7 +104,12 @@ js::set('systemMode', $this->config->systemMode);
title) ? $card->title : $card->name;
- $delayed = ($card->fromType == 'execution' and !empty($card->delay)) ? "
{$lang->execution->delayed}" : '';
+ $delayed = '';
+ if($card->fromType == 'execution' or $card->fromType == 'ticket')
+ {
+ $delayed = (!empty($card->delay) or (!helper::isZeroDate($card->deadline) and helper::now() > $card->deadline)) ? "
{$lang->execution->delayed}" : '';
+ }
+
if(common::hasPriv($card->fromType, 'view')) echo "
" . html::a($this->createLink($card->fromType, 'view', "id=$card->fromID"), $name, '', " title='$name'") . "$delayed
";
if(!common::hasPriv($card->fromType, 'view')) echo "
";
if($card->fromType == 'productplan' or $card->fromType == 'build')
@@ -128,6 +134,9 @@ js::set('systemMode', $this->config->systemMode);
begin) and !helper::isZeroDate($card->end) and $card->begin != '2030-01-01' and $card->end != '2030-01-01' and $card->fromType != ''):?>
begin)) . ' ' . $lang->{$card->fromType}->to . ' ' . date("m-d", strtotime($card->end));?>
+ fromType == 'ticket' and !helper::isZeroDate($card->deadline) and $card->begin != '2030-01-01' and $card->end != '2030-01-01'):?>
+
deadline)) . ' ' . $lang->kanbancard->deadlineAB;?>
+
begin == '2030-01-01' or $card->end == '2030-01-01') echo '
' . $lang->{$card->fromType}->future . '';
@@ -135,6 +144,7 @@ js::set('systemMode', $this->config->systemMode);
if($card->fromType == 'execution') $assignedToList = $card->PM;
if($card->fromType == 'build') $assignedToList = $card->builder;
if($card->fromType == 'release' or $card->fromType == 'productplan') $assignedToList = $card->createdBy;
+ if($card->fromType == 'ticket') $assignedToList = $card->assignedTo;
$count = 0;
$members = '';
?>
@@ -219,6 +229,7 @@ $(function()
if($item.children('.build').length) icon = '
';
if($item.children('.productplan').length) icon = '';
if($item.children('.release').length) icon = '';
+ if($item.children('.ticket').length) icon = '';
if($item.children('.execution').length && systemMode == 'new') icon = '';
if($item.children('.execution').length && systemMode == 'classic') icon = '';
diff --git a/module/my/view/requirement.html.php b/module/my/view/requirement.html.php
index 449c7ef409..8765bec631 100644
--- a/module/my/view/requirement.html.php
+++ b/module/my/view/requirement.html.php
@@ -32,7 +32,7 @@
echo html::a(inlink($app->rawMethod, "mode=requirement&type=reviewBy¶m=$param&orderBy=$orderBy&recTotal=$recTotal&recPerPage=$recPerPage&pagerID=$pageID"), "{$lang->my->storyMenu->reviewByMe}" . ($type == 'reviewBy' ? $recTotalLabel : ''), '', "class='btn btn-link" . ($type == 'reviewBy' ? ' btn-active-text' : '') . "'");
}
?>
- loadModel('search');echo $lang->search->common;?>
+ search->common;?>
diff --git a/module/my/view/story.html.php b/module/my/view/story.html.php
index 73539fc401..06214c4675 100644
--- a/module/my/view/story.html.php
+++ b/module/my/view/story.html.php
@@ -31,7 +31,7 @@
echo html::a(inlink($app->rawMethod, "mode=story&type=reviewBy¶m=$param&orderBy=$orderBy&recTotal=$recTotal&recPerPage=$recPerPage&pagerID=$pageID"), "
{$lang->my->storyMenu->reviewByMe}" . ($type == 'reviewBy' ? $recTotalLabel : ''), '', "class='btn btn-link" . ($type == 'reviewBy' ? ' btn-active-text' : '') . "'");
}
?>
-
loadModel('search');echo $lang->search->common;?>
+
search->common;?>
diff --git a/module/my/view/testcase.html.php b/module/my/view/testcase.html.php
index 4da01f76ea..8f0f14b6a3 100644
--- a/module/my/view/testcase.html.php
+++ b/module/my/view/testcase.html.php
@@ -28,7 +28,7 @@
echo html::a(inlink($app->rawMethod, "mode=$mode&type=assigntome"), "
{$lang->my->assignedToMe}" . ($type == 'assigntome' ? $recTotalLabel : ''), '', "class='btn btn-link" . ($type == 'assigntome' ? ' btn-active-text' : '') . "'");
}
?>
-
loadModel('search');echo $lang->search->common;?>
+
search->common;?>
diff --git a/module/port/model.php b/module/port/model.php
index a791a5b9f5..207c062800 100644
--- a/module/port/model.php
+++ b/module/port/model.php
@@ -1385,8 +1385,11 @@ class portModel extends model
elseif($control == 'hidden') $html .= html::hidden("$name", $selected);
- elseif($control == 'textarea') $html .= '
' . html::textarea("$name", $selected, "class='form-control' cols='50' rows='1'") . ' | ';
-
+ elseif($control == 'textarea')
+ {
+ if($model == 'bug' and $field == 'steps') $selected = str_replace("\n\n\n\n\n\n", '', $selected);
+ $html .= '
' . html::textarea("$name", $selected, "class='form-control' cols='50' rows='1'") . ' | ';
+ }
elseif($field == 'stepDesc' or $field == 'stepExpect')
{
$stepDesc = $this->process4Testcase($field, $tmpList, $row);
diff --git a/module/product/js/browse.js b/module/product/js/browse.js
index e4e9e68bb2..0a979fd7bb 100644
--- a/module/product/js/browse.js
+++ b/module/product/js/browse.js
@@ -11,7 +11,7 @@ $(function()
var $title = $('#storyList thead th.c-title');
var headerWidth = $('#storyList thead th.c-title a').innerWidth();
var buttonWidth = $('#storyList thead th.c-title button').innerWidth();
- if($title.width() < headerWidth + buttonWidth + 2) $title.width(headerWidth + buttonWidth + 30);
+ if($title.width() < headerWidth + buttonWidth + 16) $title.width(headerWidth + buttonWidth + 30);
});
$('#storyList td.has-child .story-toggle').each(function()
diff --git a/module/project/css/execution.css b/module/project/css/execution.css
index 0dc1148810..71939a8e6b 100644
--- a/module/project/css/execution.css
+++ b/module/project/css/execution.css
@@ -14,4 +14,5 @@ th.table-nest-title .check-all {position: absolute; left: 15px; top: 7px;}
.table-statistic {padding-left: 10px;}
td.flex {display: flex; flex-flow: row nowrap; justify-content: flex-start; align-items: center; margin-bottom: 0px;}
td.c-name > .project-type-label {flex: 0 0 36px; padding-right: 2px;}
-.c-name > a, .table-children .text-left > a { padding-left: 5px; text-overflow: clip;}
+.c-name > a, .table-children .text-left > a, .c-name > span.text-ellipsis { padding-left: 5px; text-overflow: clip;}
+span.table-nest-icon.table-nest-toggle {min-width: 22px; max-width: 22px;}
diff --git a/module/project/view/testtask.html.php b/module/project/view/testtask.html.php
index 00f5400a4f..5e28abe0af 100644
--- a/module/project/view/testtask.html.php
+++ b/module/project/view/testtask.html.php
@@ -60,7 +60,7 @@
testtask->begin);?> |
testtask->end);?> |
statusAB);?> |
-
text-center'>actions;?> |
+
actions;?> |
@@ -102,7 +102,7 @@
{
common::printIcon('testtask', 'cases', "taskID=$task->id", $task, 'list', 'sitemap');
common::printIcon('testtask', 'linkCase', "taskID=$task->id", $task, 'list', 'link');
- if(common::hasPriv('execution', 'testreport') and $project->model == 'scrum')
+ if(common::hasPriv('execution', 'testreport'))
{
echo html::a($this->createLink('execution', 'testreport', "executionID=$task->execution&objectType=execution&extra=$task->id"), '', '', 'class="btn " title="' . $lang->testreport->browse . '" data-app="project"');
}
diff --git a/module/projectstory/control.php b/module/projectstory/control.php
index 651cb073b7..c51eef53ec 100644
--- a/module/projectstory/control.php
+++ b/module/projectstory/control.php
@@ -68,11 +68,13 @@ class projectStory extends control
* View a story.
*
* @param int $storyID
+ * @param int $projectID
* @access public
* @return void
*/
- public function view($storyID)
+ public function view($storyID, $projectID = 0)
{
+ if($projectID) $this->session->set('project', $projectID, 'project');
$this->session->set('productList', $this->app->getURI(true), 'product');
$story = $this->loadModel('story')->getByID($storyID);
diff --git a/module/story/lang/de.php b/module/story/lang/de.php
index b4fd31b40c..8209fbf211 100644
--- a/module/story/lang/de.php
+++ b/module/story/lang/de.php
@@ -118,6 +118,7 @@ $lang->story->pri = 'Priorität';
$lang->story->estimate = 'Schätzung(h)';
$lang->story->estimateAB = 'Schätzung(h)';
$lang->story->hour = 'Stunde';
+$lang->story->consumed = 'Zeitaufwendig';
$lang->story->status = 'Status';
$lang->story->statusAB = 'Status';
$lang->story->subStatus = 'Sub Status';
diff --git a/module/story/lang/en.php b/module/story/lang/en.php
index eaf61f59dd..dbb5d44d16 100644
--- a/module/story/lang/en.php
+++ b/module/story/lang/en.php
@@ -118,6 +118,7 @@ $lang->story->pri = 'Priority';
$lang->story->estimate = "Estimates";
$lang->story->estimateAB = 'Est.';
$lang->story->hour = $lang->hourCommon;
+$lang->story->consumed = 'Consumed';
$lang->story->status = 'Status';
$lang->story->statusAB = 'Status';
$lang->story->subStatus = 'Sub Status';
diff --git a/module/story/lang/fr.php b/module/story/lang/fr.php
index d0bff1b1f6..cf5f0c0ac0 100644
--- a/module/story/lang/fr.php
+++ b/module/story/lang/fr.php
@@ -118,6 +118,7 @@ $lang->story->pri = 'Priorité';
$lang->story->estimate = 'Estimation';
$lang->story->estimateAB = 'Esti.(h)';
$lang->story->hour = 'Heures';
+$lang->story->consumed = 'Long';
$lang->story->status = 'Statut';
$lang->story->statusAB = 'Statut';
$lang->story->subStatus = 'Sous-statut';
diff --git a/module/story/lang/vi.php b/module/story/lang/vi.php
index e92b3a8b0c..c0e7f138b4 100644
--- a/module/story/lang/vi.php
+++ b/module/story/lang/vi.php
@@ -116,6 +116,7 @@ $lang->story->pri = 'Ưu tiên';
$lang->story->estimate = "{$lang->hourCommon} dự tính";
$lang->story->estimateAB = 'DT.' . $lang->hourCommon == 'giờ' ? '(giờ)' : '(SP)';
$lang->story->hour = $lang->hourCommon;
+$lang->story->consumed = 'Mất thời gian';
$lang->story->status = 'Tình trạng';
$lang->story->subStatus = 'Tình trạng con';
$lang->story->stage = 'Giai đoạn';
diff --git a/module/story/lang/zh-cn.php b/module/story/lang/zh-cn.php
index 8f268263e5..0ec66c579d 100644
--- a/module/story/lang/zh-cn.php
+++ b/module/story/lang/zh-cn.php
@@ -118,6 +118,7 @@ $lang->story->pri = '优先级';
$lang->story->estimate = "预计{$lang->hourCommon}";
$lang->story->estimateAB = '预计';
$lang->story->hour = $lang->hourCommon;
+$lang->story->consumed = '耗时';
$lang->story->status = '当前状态';
$lang->story->statusAB = '状态';
$lang->story->subStatus = '子状态';
diff --git a/module/story/lang/zh-tw.php b/module/story/lang/zh-tw.php
index c282e5c83c..75bc90d3e6 100644
--- a/module/story/lang/zh-tw.php
+++ b/module/story/lang/zh-tw.php
@@ -107,6 +107,7 @@ $lang->story->pri = '優先順序';
$lang->story->estimate = "預計{$lang->hourCommon}";
$lang->story->estimateAB = '預計';
$lang->story->hour = $lang->hourCommon;
+$lang->story->consumed = '耗時';
$lang->story->status = '當前狀態';
$lang->story->subStatus = '子狀態';
$lang->story->stage = '所處階段';
diff --git a/module/story/model.php b/module/story/model.php
index 8c2be6c9a4..2abb5e2a5a 100644
--- a/module/story/model.php
+++ b/module/story/model.php
@@ -4641,7 +4641,7 @@ class storyModel extends model
if($tab == 'project')
{
- $storyLink = helper::createLink('projectstory', 'view', "storyID=$story->id");
+ $storyLink = helper::createLink('projectstory', 'view', "storyID=$story->id&project={$this->session->project}");
$canView = common::hasPriv('projectstory', 'view');
}
elseif($tab == 'execution')
diff --git a/module/task/config.php b/module/task/config.php
index 8a6a6a8493..f2202e1f3f 100644
--- a/module/task/config.php
+++ b/module/task/config.php
@@ -105,17 +105,17 @@ $config->task->datatable->fieldList['deadline']['control'] = 'date';
$config->task->datatable->fieldList['estimate']['title'] = 'estimateAB';
$config->task->datatable->fieldList['estimate']['fixed'] = 'no';
-$config->task->datatable->fieldList['estimate']['width'] = '55';
+$config->task->datatable->fieldList['estimate']['width'] = '65';
$config->task->datatable->fieldList['estimate']['required'] = 'no';
$config->task->datatable->fieldList['consumed']['title'] = 'consumedAB';
$config->task->datatable->fieldList['consumed']['fixed'] = 'no';
-$config->task->datatable->fieldList['consumed']['width'] = '55';
+$config->task->datatable->fieldList['consumed']['width'] = '65';
$config->task->datatable->fieldList['consumed']['required'] = 'no';
$config->task->datatable->fieldList['left']['title'] = 'leftAB';
$config->task->datatable->fieldList['left']['fixed'] = 'no';
-$config->task->datatable->fieldList['left']['width'] = '55';
+$config->task->datatable->fieldList['left']['width'] = '65';
$config->task->datatable->fieldList['left']['required'] = 'no';
$config->task->datatable->fieldList['progress']['title'] = 'progressAB';
diff --git a/module/task/control.php b/module/task/control.php
index c3255549d5..697354a001 100755
--- a/module/task/control.php
+++ b/module/task/control.php
@@ -1219,7 +1219,7 @@ class task extends control
{
if(empty($orderBy))
{
- $orderBy = 'order_asc,id';
+ $orderBy = 'id_desc';
}
else
{
@@ -1227,14 +1227,35 @@ class task extends control
$orderBy .= preg_replace('/(order_|date_)/', ',id_', $orderBy);
}
}
- if(!$orderBy) $orderBy = 'date_asc';
- $this->view->title = $this->lang->task->record;
- $this->view->task = $task;
- $this->view->from = $from;
- $this->view->orderBy = $orderBy;
- $this->view->efforts = $this->task->getTaskEstimate($taskID, '', '', $orderBy);
- $this->view->users = $this->loadModel('user')->getPairs('noclosed|noletter');
+ if(!$orderBy) $orderBy = 'id_desc';
+
+ /* Set the fold state of the current task. */
+ $referer = strtolower($_SERVER['HTTP_REFERER']);
+ if(strpos($referer, 'recordestimate') and $this->cookie->taskEffortFold !== false)
+ {
+ $taskEffortFold = $this->cookie->taskEffortFold;
+ }
+ else
+ {
+ $taskEffortFold = 0;
+ $currentAccount = $this->app->user->account;
+ if($task->assignedTo == $currentAccount) $taskEffortFold = 1;
+ if(!empty($task->team))
+ {
+ $teamMember = array_column($task->team, 'account');
+ if(in_array($currentAccount, $teamMember)) $taskEffortFold = 1;
+ }
+ }
+
+ $this->view->title = $this->lang->task->record;
+ $this->view->task = $task;
+ $this->view->from = $from;
+ $this->view->orderBy = $orderBy;
+ $this->view->efforts = $this->task->getTaskEstimate($taskID, '', '', $orderBy);
+ $this->view->users = $this->loadModel('user')->getPairs('noclosed|noletter');
+ $this->view->taskEffortFold = $taskEffortFold;
+
$this->display();
}
@@ -1859,6 +1880,16 @@ class task extends control
if(!isset($this->view->members[$this->view->task->finishedBy])) $this->view->members[$this->view->task->finishedBy] = $this->view->task->finishedBy;
+ if(!empty($this->view->task->team))
+ {
+ $teamAccounts = array_column($this->view->task->team, 'account');
+ $teamMembers = array();
+ foreach($this->view->members as $account => $name)
+ {
+ if(!$account or in_array($account, $teamAccounts)) $teamMembers[$account] = $name;
+ }
+ $this->view->teamMembers = $teamMembers;
+ }
$this->view->title = $this->view->execution->name . $this->lang->colon . $this->lang->task->activate;
$this->view->position[] = $this->lang->task->activate;
$this->view->users = $this->loadModel('user')->getPairs('noletter');
diff --git a/module/task/css/common.css b/module/task/css/common.css
index 9205805f5d..ba1774a931 100644
--- a/module/task/css/common.css
+++ b/module/task/css/common.css
@@ -7,7 +7,6 @@
#modalTeam .modal-header .modal-title {font-size: 13px; line-height: 24px;}
#taskTeamEditor tr {padding: 8px 7px 8px 7px;}
#taskTeamEditor td .chosen-single .chosen-search input,
-#taskTeamEditor tr td .chosen-single {height: 35px; line-height: 24px;}
#taskTeamEditor td .chosen-single .chosen-search::before {top: 10px;}
#taskTeamEditor tr td:first-child {width: 40px; position: relative;}
.team-number {display: inline-block; width: 20px; height: 20px; line-height: 20px; border-radius: 10px; text-align: center; background: #f4f5f7;}
@@ -19,8 +18,10 @@
#modalTeam .modal-content input[type="text"]::-webkit-input-placeholder{color: #c4c4c4;text-align: left;}
#modalTeam .modal-content input[type="text"]::-moz-placeholder{color: #c4c4c4;text-align: left;}
#modalTeam .modal-content input[type="text"]::-ms-input-placeholder{color: #c4c4c4;text-align: left;}
+#modalTeam #team_chosen span {line-height: 24px;}
+#modalTeam #team_chosen a.chosen-default > span {color: #c4c4c4;}
-#modalTeam .input-control input[type="text"]::input-placeholder{text-align: right;}
-#modalTeam .input-control input[type="text"]::-webkit-input-placeholder{text-align: right;}
-#modalTeam .input-control input[type="text"]::-moz-placeholder{text-align: right;}
-#modalTeam .input-control input[type="text"]::-ms-input-placeholder{text-align: right;}
+#modalTeam .input-control input[type="text"]::input-placeholder{text-align: center;}
+#modalTeam .input-control input[type="text"]::-webkit-input-placeholder{text-align: center;}
+#modalTeam .input-control input[type="text"]::-moz-placeholder{text-align: center;}
+#modalTeam .input-control input[type="text"]::-ms-input-placeholder{text-align: center;}
diff --git a/module/task/css/create.css b/module/task/css/create.css
index 0c8b0eb081..f33c85556f 100644
--- a/module/task/css/create.css
+++ b/module/task/css/create.css
@@ -29,5 +29,6 @@
.keep-row-height {height: 32px;}
#modalTeam .modal-dialog {min-height: 120px; width: 520px; color: #3c4353;}
-#taskTeamEditor .chosen-single {width: 200px;}
+#taskTeamEditor .hourBox {padding-bottom: 7px; width: 135px;}
#taskTeamEditor .estimateBox {width: 120px;}
+#modalTeam .modal-content {padding: 0;}
diff --git a/module/task/css/editteam.css b/module/task/css/editteam.css
new file mode 100644
index 0000000000..5d45d0da74
--- /dev/null
+++ b/module/task/css/editteam.css
@@ -0,0 +1 @@
+#mainContent {padding-left: 0;}
diff --git a/module/task/css/recordestimate.css b/module/task/css/recordestimate.css
index 05d5323044..5ead61fb66 100644
--- a/module/task/css/recordestimate.css
+++ b/module/task/css/recordestimate.css
@@ -21,3 +21,8 @@
.table.has-sort-head thead>tr>th>a:after, .table.has-sort-head thead>tr>th>a:before {top: -7px;}
.table.has-sort-head thead>tr>th>a:hover, .table.has-sort-head thead>tr>th>a:hover:after, .table.has-sort-head thead>tr>th>a:hover:before {color: #000;}
+
+#toggleFoldIcon:hover {cursor: pointer;}
+#toggleFoldIcon .icon-border {width: 20px; height: 20px; border-radius: 8px; border: 1px solid #D5E5FF;}
+#toggleFoldIcon .icon-border > .icon {color: #3785FF;}
+#toggleFoldIcon .text {color: #3785FF;}
diff --git a/module/task/js/activate.js b/module/task/js/activate.js
index 654188a1d5..06cb075947 100644
--- a/module/task/js/activate.js
+++ b/module/task/js/activate.js
@@ -1,56 +1,158 @@
-$('#confirmButton').click(function()
+$(function()
{
- var memberCount = '';
- var totalEstimate = 0;
- var totalConsumed = oldConsumed;
- var totalLeft = 0;
- var error = false;
- $('select[name^=team]').each(function()
+ $('#confirmButton').click(function()
{
- if($(this).val() == '') return;
-
- memberCount++;
-
- var $tr = $(this).closest('tr');
- var account = $(this).find('option:selected').text();
-
- var estimate = parseFloat($tr.find('[name^=teamEstimate]').val());
- if(!isNaN(estimate)) totalEstimate += estimate;
- if($tr.hasClass('member-wait') && (isNaN(estimate) || estimate == 0))
+ var memberCount = '';
+ var totalEstimate = 0;
+ var totalConsumed = oldConsumed;
+ var totalLeft = 0;
+ var error = false;
+ $('select[name^=team]').each(function()
{
- bootbox.alert(account + ' ' + estimateNotEmpty);
- error = true;
- return false;
+ if($(this).val() == '') return;
+
+ memberCount++;
+
+ var $tr = $(this).closest('tr');
+ var account = $(this).find('option:selected').text();
+
+ var estimate = parseFloat($tr.find('[name^=teamEstimate]').val());
+ if(!isNaN(estimate)) totalEstimate += estimate;
+ if($tr.hasClass('member-wait') && (isNaN(estimate) || estimate <= 0))
+ {
+ bootbox.alert(account + ' ' + estimateNotEmpty);
+ error = true;
+ return false;
+ }
+
+ var consumed = parseFloat($tr.find('[name^=teamConsumed]').val());
+ if(!isNaN(consumed)) totalConsumed += consumed;
+
+ var $left = $tr.find('[name^=teamLeft]');
+ var left = parseFloat($left.val());
+ if(!isNaN(left)) totalLeft += left;
+ if(!$left.prop('readonly') && $tr.hasClass('member-wait') && (isNaN(left) || left <= 0))
+ {
+ bootbox.alert(account + ' ' + leftNotEmpty);
+ error = true;
+ return false;
+ }
+ })
+
+ if(error) return false;
+
+ if(memberCount < 2)
+ {
+ bootbox.alert(teamMemberError);
+ return false;
}
- var consumed = parseFloat($tr.find('[name^=teamConsumed]').val());
- if(!isNaN(consumed)) totalConsumed += consumed;
+ $('#left').val(totalLeft);
+ updateAssignedTo();
- var $left = $tr.find('[name^=teamLeft]');
- var left = parseFloat($left.val());
- if(!isNaN(left)) totalLeft += left;
- if(!$left.prop('readonly') && $tr.hasClass('member-wait') && (isNaN(left) || left == 0))
- {
- bootbox.alert(account + ' ' + leftNotEmpty);
- error = true;
- return false;
- }
- })
+ $('.close').click();
+ });
- if(error) return false;
-
- if(memberCount < 2)
+ $('#multiple').on('click', function()
{
- bootbox.alert(teamMemberError);
- return false;
- }
+ var showTeam = $(this).is(":checked");
+ $('#assignedTo').val('');
+ $('#left').val('');
+ $('#dataPlanGroup').removeClass('required');
+ $('.multi-append').empty();
+ $('.teamTemplate select, .teamTemplate input').val('');
+ $('.teamTemplate input[name^=teamConsumed]').val('0');
+ $('.teamTemplate select').trigger('chosen:updated');
- $('#left').val(totalLeft);
- updateAssignedTo();
+ /* Reset team modal. */
+ var oldTeamCount = $('#taskTeamEditor select:disabled').length;
+ var removeCount = oldTeamCount > 6 ? 1 : (5 - oldTeamCount);
+ $('#taskTeamEditor tr.teamTemplate').filter(':gt(' + removeCount + ')').remove();
+ $('.member-done').find('input[name^=teamLeft]').val(0);
- $('.close').click();
+ /* Reset assignedTo select.*/
+ $('#assignedTo_chosen').remove();
+ $('#assignedTo').replaceWith(assignedToHtml);
+
+ if(showTeam)
+ {
+ $('#assignedTo').attr('disabled', true);
+ $('#left').attr('readonly', true);
+ $('.team-group').removeClass('hidden');
+ }
+ else
+ {
+ $('.team-group').addClass('hidden');
+ $('#assignedTo').removeAttr('disabled');
+ $('#left').removeAttr('readonly');
+ $('#dataPlanGroup').addClass('required');
+ }
+ $('#assignedTo').chosen();
+ $('#assignedTo').trigger('chosen:updated');
+ });
+
+ $('#assignedTo').on('change', setTeamUser);
+ $('#left').on('input', setTeamUser);
+
+ $('#submit').on('click', function()
+ {
+ if(isMultiple)
+ {
+ var multiple = $('#multiple').is(":checked");
+ if(!multiple)
+ {
+ var assignedTo = $('#assignedTo').val();
+ if(!assignedTo)
+ {
+ bootbox.alert(teamNotEmpty);
+ return false;
+ }
+ }
+
+ var estimate = parseInt($('#left').val());
+ if(isNaN(estimate) || estimate <= 0)
+ {
+ bootbox.alert(multiple ? teamLeftEmpty : leftNotEmpty);
+ return false;
+ }
+
+ $('#assignedTo').val('');
+ }
+ });
});
+/**
+ * Set team user form.
+ *
+ * @access public
+ * @return void
+ */
+function setTeamUser()
+{
+ $('.multi-append').empty();
+
+ var assignedTo = $('#assignedTo').val();
+ var estimate = parseInt($('#left').val());
+ if(!assignedTo || !estimate) return;
+
+ if(taskMode == 'multi')
+ {
+ $('.member-done').each(function()
+ {
+ if($(this).find('select').val() == assignedTo) $(this).find('input[name^=teamLeft]').val(estimate);
+ });
+ }
+ else
+ {
+ var teamLine = '';
+ teamLine += '';
+ teamLine += '';
+ teamLine += '';
+ teamLine += '';
+ $('.multi-append').html(teamLine);
+ }
+}
+
/**
* Update assignedTo.
*
@@ -77,15 +179,7 @@ function updateAssignedTo()
html += "";
});
-
- if(mode == 'multi' && isTeamMember && mode != 'linear')
- {
- $('[name=assignedTo]').removeAttr('disabled').trigger('chosen:updated');
- }
- else
- {
- $('[name=assignedTo]').attr('disabled', 'disabled').trigger('chosen:updated');
- }
+ $('[name=assignedTo]').attr('disabled', 'disabled').trigger('chosen:updated');
}
else
{
diff --git a/module/task/js/editteam.js b/module/task/js/editteam.js
index bc08f7bfbd..fe4836386e 100644
--- a/module/task/js/editteam.js
+++ b/module/task/js/editteam.js
@@ -16,3 +16,8 @@ $(document).ready(function()
}
});
});
+
+$(function()
+{
+ parent.$(' #triggerModal .modal-dialog').css('width', '800px');
+});
diff --git a/module/task/js/recordestimate.js b/module/task/js/recordestimate.js
index e10c2adf66..c539fc9fc5 100644
--- a/module/task/js/recordestimate.js
+++ b/module/task/js/recordestimate.js
@@ -74,4 +74,33 @@ $(function()
{
$(this).prev().datetimepicker('show');
});
+
+ $('#toggleFoldIcon').click(function()
+ {
+ var fold = $(this).find('.icon-angle-down').length > 0;
+ var $icon = $(this).find('.icon-border > i');
+ var $text = $(this).find('.text');
+
+ $.cookie('taskEffortFold', fold ? 0 : 1);
+
+ if(fold)
+ {
+ /* Update icon and text. */
+ $icon.removeClass('icon-angle-down')
+ .addClass('icon-angle-top');
+ $text.text(foldEffort);
+
+ /* Show all efforts. */
+ $('.taskEffort > tbody > tr').removeClass('hidden');
+ }
+ else
+ {
+ $icon.removeClass('icon-angle-top')
+ .addClass('icon-angle-down');
+ $text.text(unfoldEffort);
+
+ /* Efforts whose number is greater than 3 are hidden. */
+ $('.taskEffort > tbody > tr').filter(':gt(2)').addClass('hidden');
+ }
+ });
})
diff --git a/module/task/lang/de.php b/module/task/lang/de.php
index f0a1f3ad84..001b5e5e34 100644
--- a/module/task/lang/de.php
+++ b/module/task/lang/de.php
@@ -60,6 +60,9 @@ $lang->task->replace = 'Replace';
$lang->task->myEffort = 'My Effort';
$lang->task->allEffort = 'Team Effort';
$lang->task->teamOrder = 'Order';
+$lang->task->manageTeam = 'Manage Team';
+$lang->task->unfoldEffort = 'Unfold Effort';
+$lang->task->foldEffort = 'Fold Effort';
$lang->task->common = 'Aufgabe';
$lang->task->id = 'ID';
@@ -277,6 +280,8 @@ $lang->task->error->alreadyConsumed = 'The currently selected parent task has
$lang->task->error->date = 'The date should be <= today.';
$lang->task->error->leftEmptyAB = 'When the task status is %s, "Hours Left" cannot be 0';
$lang->task->error->leftEmpty = 'Task#%sWhen the task status is %s, "Left" cannot be 0';
+$lang->task->error->notempty = '%s must be > 0.';
+$lang->task->error->teamLeftEmpty = 'Please maintain team hours.';
/* Report. */
$lang->task->report = new stdclass();
diff --git a/module/task/lang/en.php b/module/task/lang/en.php
index ec3982d903..fdd5f404e3 100755
--- a/module/task/lang/en.php
+++ b/module/task/lang/en.php
@@ -60,6 +60,9 @@ $lang->task->replace = 'Replace';
$lang->task->myEffort = 'My Effort';
$lang->task->allEffort = 'Team Effort';
$lang->task->teamOrder = 'Order';
+$lang->task->manageTeam = 'Manage Team';
+$lang->task->unfoldEffort = 'Unfold Effort';
+$lang->task->foldEffort = 'Fold Effort';
$lang->task->common = 'Task';
$lang->task->id = 'ID';
@@ -277,6 +280,8 @@ $lang->task->error->alreadyConsumed = 'The currently selected parent task has
$lang->task->error->date = 'The date should be <= today.';
$lang->task->error->leftEmptyAB = 'When the task status is %s, "Hours Left" cannot be 0';
$lang->task->error->leftEmpty = 'Task#%sWhen the task status is %s, "Left" cannot be 0';
+$lang->task->error->notempty = '%s must be > 0.';
+$lang->task->error->teamLeftEmpty = 'Please maintain team hours.';
/* Report. */
$lang->task->report = new stdclass();
diff --git a/module/task/lang/fr.php b/module/task/lang/fr.php
index 0b2b1eb1e2..8c5c49092d 100644
--- a/module/task/lang/fr.php
+++ b/module/task/lang/fr.php
@@ -60,6 +60,9 @@ $lang->task->replace = 'Replace';
$lang->task->myEffort = 'My Effort';
$lang->task->allEffort = 'Team Effort';
$lang->task->teamOrder = 'Order';
+$lang->task->manageTeam = 'Manage Team';
+$lang->task->unfoldEffort = 'Unfold Effort';
+$lang->task->foldEffort = 'Fold Effort';
$lang->task->common = 'Tâche';
$lang->task->id = 'ID';
@@ -277,6 +280,8 @@ $lang->task->error->alreadyConsumed = 'The currently selected parent task has
$lang->task->error->date = 'The date should be <= today.';
$lang->task->error->leftEmptyAB = 'When the task status is %s, "Hours Left" cannot be 0';
$lang->task->error->leftEmpty = 'Task#%sWhen the task status is %s, "Left" cannot be 0';
+$lang->task->error->notempty = '%s must be > 0.';
+$lang->task->error->teamLeftEmpty = 'Please maintain team hours.';
/* Report. */
$lang->task->report = new stdclass();
diff --git a/module/task/lang/zh-cn.php b/module/task/lang/zh-cn.php
index 506c414896..9b456371b7 100755
--- a/module/task/lang/zh-cn.php
+++ b/module/task/lang/zh-cn.php
@@ -60,6 +60,9 @@ $lang->task->replace = '替换';
$lang->task->myEffort = '我的日志';
$lang->task->allEffort = '团队日志';
$lang->task->teamOrder = '工序';
+$lang->task->manageTeam = '维护团队';
+$lang->task->unfoldEffort = '展开日志';
+$lang->task->foldEffort = '收起日志';
$lang->task->common = '任务';
$lang->task->id = '编号';
@@ -277,6 +280,8 @@ $lang->task->error->alreadyConsumed = '当前选中的父任务已有消耗。
$lang->task->error->date = '日期不能大于今天';
$lang->task->error->leftEmptyAB = '任务状态为%s时,预计剩余不能为0';
$lang->task->error->leftEmpty = 'Task#%s任务状态为%s时,剩余不能为0';
+$lang->task->error->notempty = '%s必须大于0。';
+$lang->task->error->teamLeftEmpty = '请维护团队工时。';
/* Report. */
$lang->task->report = new stdclass();
diff --git a/module/task/model.php b/module/task/model.php
index e97f896780..391b13cf33 100755
--- a/module/task/model.php
+++ b/module/task/model.php
@@ -2282,6 +2282,12 @@ class taskModel extends model
return false;
}
+ if(empty($task->left))
+ {
+ dao::$errors[] = sprintf($this->lang->task->error->notempty, $this->lang->task->left);
+ return false;
+ }
+
if(!empty($oldTask->team))
{
$this->manageTaskTeam($oldTask->mode, $oldTask->id, $task->status);
diff --git a/module/task/view/activate.html.php b/module/task/view/activate.html.php
index 302e5e1c66..43bd6f38a1 100644
--- a/module/task/view/activate.html.php
+++ b/module/task/view/activate.html.php
@@ -17,9 +17,15 @@
user->account);?>
task->error->teamMember);?>
+task->error->teamLeftEmpty);?>
lang->task->error->leftEmptyAB, $this->lang->task->statusList[$task->status]));?>
-error->notempty, $lang->task->estimate))?>
-error->notempty, $lang->task->left))?>
+task->error->notempty, $lang->task->estimate))?>
+task->error->notempty, $lang->task->left))?>
+error->notempty, $lang->task->assignedTo))?>
+team);?>
+
+mode);?>
+
diff --git a/module/task/view/editteam.html.php b/module/task/view/editteam.html.php
index c42ae0753b..635ad6da64 100755
--- a/module/task/view/editteam.html.php
+++ b/module/task/view/editteam.html.php
@@ -64,7 +64,6 @@
-
diff --git a/module/task/view/lineareffort.html.php b/module/task/view/lineareffort.html.php
index c6677f2380..9431f43eaf 100644
--- a/module/task/view/lineareffort.html.php
+++ b/module/task/view/lineareffort.html.php
@@ -50,7 +50,7 @@ foreach($efforts as $key => $effort)
-
+
$effort)
+
$count):?>
account != $this->app->user->account) continue;?>
-
+ 3) ? 'hidden' : ''?>
+
|
@@ -93,10 +95,19 @@ foreach($efforts as $key => $effort)
?>
+
+ 4):?>
+
+
+ task->unfoldEffort : $lang->task->foldEffort;?>
+
+
+
+
diff --git a/module/task/view/recordestimate.html.php b/module/task/view/recordestimate.html.php
index 404b281ae2..9302b6c137 100644
--- a/module/task/view/recordestimate.html.php
+++ b/module/task/view/recordestimate.html.php
@@ -12,6 +12,9 @@
?>
+task->foldEffort);?>
+task->unfoldEffort);?>
+id);?>
task->canOperateEffort($task) and empty($myOrders)):?>
@@ -59,7 +62,7 @@ if(!empty($members) && $task->mode == 'linear')
team) and $task->mode == 'linear'):?>
-
+
id&from=$from&orderBy=%s";?>
@@ -72,8 +75,10 @@ if(!empty($members) && $task->mode == 'linear')
+
-
+ 3) ? 'hidden' : ''?>
+
| date;?> |
account);?> |
work;?> |
@@ -87,9 +92,18 @@ if(!empty($members) && $task->mode == 'linear')
?>
+
+ 3):?>
+
+
+ task->unfoldEffort : $lang->task->foldEffort;?>
+
+
+
+
task->canOperateEffort($task) and empty($myOrders)):?>
diff --git a/module/task/view/taskteam.html.php b/module/task/view/taskteam.html.php
index 28ca7dee5f..c088f536c5 100644
--- a/module/task/view/taskteam.html.php
+++ b/module/task/view/taskteam.html.php
@@ -3,7 +3,19 @@
#taskTeamEditor .estimateBox span {background-color: #fff;}
#taskTeamEditor .estimateBox input {background-color: #fff; border-right-width: 0px;}
#taskTeamEditor input, #taskTeamEditor span, #taskTeamEditor .chosen-container > a {border-color: #eee;}
+#taskTeamEditor td.sort-handler {padding-bottom: 12px;}
+rawMethod != 'create'):?>
+
+
+rawMethod == 'assignto'):?>
+
+
mode) or $task->mode == 'linear') ? '' : 'hidden';?>
team)):?>
@@ -31,11 +43,11 @@ if($task->mode == 'multi' and $app->rawMethod == 'activate') $hourDisabled = fal
- account, "class='form-control chosen'" . ($memberDisabled ? ' disabled' : ''))?>
+ account, "class='form-control chosen' data-placeholder='{$lang->task->assignedTo}'" . ($memberDisabled ? ' disabled' : ''))?>
account);?>
account);?>
|
-
+ |
|
-
+ |
mode) and $task->mode == 'linear'):?>
@@ -68,10 +80,10 @@ if($task->mode == 'multi' and $app->rawMethod == 'activate') $hourDisabled = fal
|
-
+ task->assignedTo}'")?>
|
-
+ |
team)):?>
task->estimateAB}'") ?>
diff --git a/www/theme/default/style.css b/www/theme/default/style.css
index 903622c2d1..f588ff7ffe 100644
--- a/www/theme/default/style.css
+++ b/www/theme/default/style.css
@@ -122,8 +122,10 @@ body.xxc-embed.m-productplan-view,body.xxc-embed.m-bug-browse,body.xxc-embed.m-p
.setting-input {width: 64px; height: 20px; margin: 0 4px; text-align: center;}
.setting-input.disabled,.setting-input[disabled="disabled"] {color: #C4C4C4;}
.width-radio-row {display: flex;}
-#dataform .width-radio-row.required:after {top: 1px; left: 360px;}
+#dataform .width-radio-row.required:after {top: 1px; left: 215px;}
+#dataform .width-radio-row.mt10.required:after {top: 1px; left: 355px;}
.mt10 {margin-top: 10px;}
+#dataform tr > th {vertical-align: middle;}
#programTableList > tr:hover {background: #E6F0FFCC;}
|