* Finish task#58772,58774,58775

This commit is contained in:
zenggang
2022-06-28 05:39:31 +00:00
parent c0336de284
commit 15feb917ce
6 changed files with 392 additions and 11 deletions
+2
View File
@@ -284,6 +284,8 @@ class execution extends control
$allCount = 0;
foreach($tasks as $task)
{
if($task->mode == 'multi') $task->assignedToRealName = $this->lang->task->team;
$groupTasks[] = $task;
$allCount++;
if(isset($task->children))
@@ -85,10 +85,4 @@
</form>
</div>
</div>
<script>
$(function()
{
$(".form-date").datetimepicker('setEndDate', '<?php echo date(DT_DATE1)?>');
});
</script>
<?php include '../../common/view/footer.html.php';?>
+63 -1
View File
@@ -715,6 +715,12 @@ class task extends control
public function assignTo($executionID, $taskID, $kanbanGroup = '')
{
$this->commonAction($taskID);
$task = $this->task->getByID($taskID);
if(!empty($task->team) and $task->mode == 'multi')
{
return $this->editTeam($executionID, $task, $kanbanGroup);
}
if(!empty($_POST))
{
@@ -754,7 +760,6 @@ class task extends control
}
$members = $this->loadModel('user')->getTeamMemberPairs($executionID, 'execution', 'nodeleted');
$task = $this->task->getByID($taskID);
/* Compute next assignedTo. */
if(!empty($task->team))
@@ -2094,4 +2099,61 @@ class task extends control
}
echo json_encode($task);
}
/**
* Update assign of multi task.
*
* @param int $requestID
* @param object $task
* @param string $kanbanGroup
* @access public
* @return void
*/
public function editTeam($executionID, $task, $kanbanGroup = '')
{
$taskID = $task->id;
$this->commonAction($taskID);
if(!empty($_POST))
{
$this->loadModel('action');
$changes = $this->task->updateTeam($taskID);
if(dao::isError())
{
if($this->viewType == 'json' or (defined('RUN_MODE') && RUN_MODE == 'api')) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
return print(js::error(dao::getError()));
}
$actionID = $this->action->create('task', $taskID, 'Edited');
$this->action->logHistory($actionID, $changes);
$this->executeHooks($taskID);
if($this->viewType == 'json' or (defined('RUN_MODE') && RUN_MODE == 'api')) return $this->send(array('result' => 'success'));
if(isonlybody())
{
$task = $this->task->getById($taskID);
$execution = $this->execution->getByID($task->execution);
if($execution->type == 'kanban' and $this->app->tab == 'execution')
{
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getRDKanban($task->execution, $this->session->execLaneType ? $this->session->execLaneType : 'all', 'id_desc', 0, $kanbanGroup, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData)"));
}
else
{
return print(js::closeModal('parent.parent', 'this'));
}
}
return print(js::locate($this->createLink('task', 'view', "taskID=$taskID"), 'parent'));
}
$this->view->task = $task;
$this->view->members = $this->loadModel('user')->getTeamMemberPairs($executionID, 'execution', 'nodeleted');
$this->view->users = $this->loadModel('user')->getPairs();
$this->display('', 'editTeam');
}
}
+124
View File
@@ -0,0 +1,124 @@
$(document).ready(function()
{
/* show team menu. */
$('[name=multiple]').change(function()
{
var checked = $(this).prop('checked');
if(checked)
{
$('#teamTr').removeClass('hidden');
$('.modeBox').removeClass('hidden');
$('#mode').removeAttr('disabled').trigger('chosen:updated');
$('#parent').val('');
$('#parent').trigger('chosen:updated');
$('#parent').closest('tr').addClass('hidden');
$('#estimate').attr('disabled', 'disabled');
$('#left').attr('disabled', 'disabled');
var mode = $('#mode').val();
if((mode == 'linear' && currentUser != oldAssignedTo) || !team[currentUser]) $('[name=assignedTo]').attr('disabled', 'disabled').trigger('chosen:updated');
}
else
{
$('#teamTr').addClass('hidden');
$('.modeBox').addClass('hidden');
$('#mode').attr('disabled', 'disabled').trigger('chosen:updated');
$('#parent').closest('tr').removeClass('hidden');
$('#estimate').removeAttr('disabled');
$('#left').removeAttr('disabled');
$('[name=assignedTo]').removeAttr('disabled').trigger('chosen:updated');
}
updateAssignedTo();
});
/* Init task team manage dialog */
var $taskTeamEditor = $('#taskTeamEditor').batchActionForm(
{
idStart: 0,
idEnd: newRowCount - 1,
chosen: true,
datetimepicker: false,
colorPicker: false,
});
var taskTeamEditor = $taskTeamEditor.data('zui.batchActionForm');
var adjustButtons = function()
{
var $deleteBtn = $taskTeamEditor.find('.btn-delete');
if ($deleteBtn.length == 1) $deleteBtn.addClass('disabled').attr('disabled', 'disabled');
};
$taskTeamEditor.on('click', '.btn-add', function()
{
var $newRow = taskTeamEditor.createRow(null, $(this).closest('tr'));
$newRow.addClass('highlight');
setTimeout(function()
{
$newRow.removeClass('highlight');
}, 1600);
adjustButtons();
}).on('click', '.btn-delete', function()
{
var $row = $(this).closest('tr');
$row.addClass('highlight').fadeOut(700, function()
{
$row.remove();
adjustButtons();
});
});
adjustButtons();
});
$('#confirmButton').click(function()
{
/* Unique team. */
$('select[name^=team]').each(function(i)
{
value = $(this).val();
if(value == '') return;
$('select[name^=team]').each(function(j)
{
if(i <= j) return;
if(value == $(this).val()) $(this).closest('tr').addClass('hidden');
})
});
$('select[name^=team]').closest('tr.hidden').remove();
var memberCount = '';
var totalEstimate = 0;
var totalConsumed = oldConsumed;
var totalLeft = 0;
$('select[name^=team]').each(function()
{
if($(this).find('option:selected').text() == '') return;
memberCount++;
estimate = parseFloat($(this).parents('td').next('td').find('[name^=teamEstimate]').val());
if(!isNaN(estimate)) totalEstimate += estimate;
consumed = parseFloat($(this).parents('td').next('td').find('[name^=teamConsumed]').val());
if(!isNaN(consumed)) totalConsumed += consumed;
left = parseFloat($(this).parents('td').next('td').find('[name^=teamLeft]').val());
if(!isNaN(left)) totalLeft += left;
})
$('#estimate').val(totalEstimate);
$('#consumedSpan').html(totalConsumed);
$('#left').val(totalLeft);
if(memberCount < 2)
{
alert(teamMemberError);
return false;
}
if(totalLeft == 0 && (taskStatus == 'doing' || taskStatus == 'pause'))
{
alert(totalLeftError);
return false;
}
$('.close').click();
});
+97 -4
View File
@@ -1509,6 +1509,97 @@ class taskModel extends model
if(!dao::isError()) return common::createChanges($oldTask, $task);
}
/**
* Update a task team.
*
* @param int $taskID
* @access public
* @return void
*/
public function updateTeam($taskID)
{
$oldTask = $this->getById($taskID);
if($this->post->estimate < 0 or $this->post->left < 0 or $this->post->consumed < 0)
{
dao::$errors[] = $this->lang->task->error->recordMinus;
return false;
}
$now = helper::now();
$task = fixer::input('post')
->add('id', $taskID)
->setDefault('estimate, left, consumed', 0)
->setIF(is_numeric($this->post->estimate), 'estimate', (float)$this->post->estimate)
->setIF(is_numeric($this->post->consumed), 'consumed', (float)$this->post->consumed)
->setIF(is_numeric($this->post->left), 'left', (float)$this->post->left)
->setDefault('lastEditedBy', $this->app->user->account)
->setDefault('lastEditedDate', $now)
->setDefault('assignedDate', $now)
->stripTags($this->config->task->editor->assignto['id'], $this->config->allowedTags)
->remove('comment,showModule,team,teamEstimate,teamConsumed,teamLeft')
->get();
if($task->consumed < $oldTask->consumed) return print(js::error($this->lang->task->error->consumedSmall));
$teams = array();
if(count(array_unique(array_filter($this->post->team))) > 1)
{
foreach($this->post->team as $row => $account)
{
if(empty($account) or isset($team[$account])) continue;
$member = new stdClass();
$member->account = $account;
$member->join = helper::today();
$member->root = $taskID;
$member->type = 'task';
$member->estimate = $this->post->teamEstimate[$row] ? $this->post->teamEstimate[$row] : 0;
$member->consumed = $this->post->teamConsumed[$row] ? $this->post->teamConsumed[$row] : 0;
$member->left = $this->post->teamLeft[$row] === '' ? 0 : $this->post->teamLeft[$row];
$member->order = $row;
$teams[$account] = $member;
if($oldTask->status == 'done') $member->left = 0;
}
}
/* Save team. */
$this->dao->delete()->from(TABLE_TEAM)->where('root')->eq($taskID)->andWhere('type')->eq('task')->exec();
if(!empty($teams))
{
foreach($teams as $member) $this->dao->insert(TABLE_TEAM)->data($member)->autoCheck()->exec();
/* Assign the left hours to zero who will be skipped. */
$skipMembers = $this->loadModel('execution')->getTeamSkip($oldTask->team, $oldTask->assignedTo, isset($task->assignedTo) ? $task->assignedTo : $oldTask->assignedTo);
foreach($skipMembers as $account => $team) $this->dao->update(TABLE_TEAM)->set('left')->eq(0)->where('root')->eq($taskID)->andWhere('type')->eq('task')->andWhere('account')->eq($account)->exec();
$task = $this->computeHours4Multiple($oldTask, $task, array(), $autoStatus = false);
if($task->status == 'wait')
{
reset($teams);
$task->assignedTo = key($teams);
}
}
else
{
$task->mode = '';
}
if($oldTask->parent > 0) $this->updateParentStatus($taskID);
$task = $this->loadModel('file')->processImgURL($task, $this->config->task->editor->assignto['id'], $this->post->uid);
$this->dao->update(TABLE_TASK)
->data($task)
->autoCheck()
->checkIF($task->estimate != false, 'estimate', 'float')
->checkIF($task->left != false, 'left', 'float')
->checkIF($task->consumed != false, 'consumed', 'float')
->checkFlow()
->where('id')->eq($taskID)
->exec();
if(!dao::isError()) return common::createChanges($oldTask, $task);
}
/**
* Start a task.
*
@@ -2253,7 +2344,7 @@ class taskModel extends model
->beginIF($productID)->andWhere("((t5.root=" . (int)$productID . " and t5.type='story') OR t2.product=" . (int)$productID . ")")->fi()
->beginIF($type == 'undone')->andWhere('t1.status')->notIN('done,closed')->fi()
->beginIF($type == 'needconfirm')->andWhere('t2.version > t1.storyVersion')->andWhere("t2.status = 'active'")->fi()
->beginIF($type == 'assignedtome')->andWhere('t1.assignedTo')->eq($this->app->user->account)->fi()
->beginIF($type == 'assignedtome')->andWhere("(t1.assignedTo = '{$this->app->user->account}' or (t1.mode = 'multi' and t4.`account` = '{$this->app->user->account}') )")->fi()
->beginIF($type == 'finishedbyme')
->andWhere('t1.finishedby', 1)->eq($this->app->user->account)
->orWhere('t1.finishedList')->like("%,{$this->app->user->account},%")
@@ -2268,7 +2359,7 @@ class taskModel extends model
->page($pager, 't1.id')
->fetchAll('id');
$this->loadModel('common')->saveQueryCondition($this->dao->get(), 'task', ($productID or in_array($type, array('myinvolved', 'needconfirm'))) ? false : true);
$this->loadModel('common')->saveQueryCondition($this->dao->get(), 'task', ($productID or in_array($type, array('myinvolved', 'needconfirm', 'assignedtome'))) ? false : true);
if(empty($tasks)) return array();
@@ -2377,6 +2468,7 @@ class taskModel extends model
->leftJoin(TABLE_EXECUTION)->alias('t2')->on("t1.execution = t2.id")
->leftJoin(TABLE_STORY)->alias('t3')->on('t1.story = t3.id')
->leftJoin(TABLE_PROJECT)->alias('t4')->on("t1.project = t4.id")
->leftJoin(TABLE_TEAM)->alias('t5')->on("t5.root = t1.id and t5.type = 'task' and t5.account = '{$account}'")
->where('t1.deleted')->eq(0)
->andWhere('t2.deleted')->eq(0)
->beginIF($this->config->vision)->andWhere('t1.vision')->eq($this->config->vision)->fi()
@@ -2390,7 +2482,8 @@ class taskModel extends model
->markRight(1)
->fi()
->beginIF($this->app->rawModule == 'my' or $this->app->rawModule == 'block')->andWhere('(t2.status')->ne('suspended')->orWhere('t4.status')->ne('suspended')->markRight(1)->fi()
->beginIF($type != 'all' and $type != 'finishedBy')->andWhere("t1.`$type`")->eq($account)->fi()
->beginIF($type != 'all' and $type != 'finishedBy' and $type != 'assignedTo')->andWhere("t1.`$type`")->eq($account)->fi()
->beginIF($type == 'assignedTo')->andWhere("(t1.assignedTo = '{$account}' or (t1.mode = 'multi' and t5.`account` = '{$account}') )")->fi()
->orderBy($orderBy)
->beginIF($limit > 0)->limit($limit)->fi()
->page($pager)
@@ -3478,7 +3571,7 @@ class taskModel extends model
public function printAssignedHtml($task, $users)
{
$btnTextClass = '';
$assignedToText = zget($users, $task->assignedTo);
$assignedToText = (!empty($task->team) and $task->mode == 'multi') ? $this->lang->task->team : zget($users, $task->assignedTo);
if(empty($task->assignedTo))
{
+106
View File
@@ -0,0 +1,106 @@
<?php
/**
* The complete file of task module of ZenTaoPMS.
*
* @copyright Copyright 2009-2015 青岛易软天创网络科技有限公司(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 Jia Fu <fujia@cnezsoft.com>
* @package task
* @version $Id: complete.html.php 935 2010-07-06 07:49:24Z jajacn@126.com $
* @link http://www.zentao.net
*/
?>
<?php include '../../common/view/header.html.php';?>
<?php include '../../common/view/kindeditor.html.php';?>
<?php include '../../common/view/sortable.html.php';?>
<?php js::set('oldConsumed', $task->consumed);?>
<?php js::set('team', $task->team);?>
<?php js::set('members', $members);?>
<?php js::set('newRowCount', count($task->team) < 6 ? 6 - count($task->team) : 1);?>
<?php js::set('teamMemberError', $lang->task->error->teamMember);?>
<?php js::set('totalLeftError', sprintf($this->lang->task->error->leftEmptyAB, $this->lang->task->statusList[$task->status]));?>
<div id='mainContent' class='main-content'>
<div class='center-block' id='taskTeamEditor'>
<?php if(empty($task->team) and !isset($task->team[$app->user->account])):?>
<div class="alert with-icon">
<i class="icon-exclamation-sign"></i>
<div class="content">
<p><?php echo sprintf($lang->task->deniedNotice, '<strong>' . $lang->task->teamMember . '</strong>', $lang->task->transfer);?></p>
</div>
</div>
<?php else:?>
<div class='main-header'>
<h2>
<?php $name = $lang->task->team . ' > ' . $task->name;?>
<?php echo isonlybody() ? ("<span title='$name'>" . $name . '</span>') : html::a($this->createLink('task', 'view', 'task=' . $task->id), $name);?>
<?php if(!isonlybody()):?>
<small> <?php echo $lang->arrow . (empty($task->team) ? $lang->task->assign : $lang->task->transfer);?></small>
<?php endif;?>
</h2>
</div>
<form method='post' target='hiddenwin'>
<table class='table table-form'>
<tbody class="sortable">
<tr class='hidden'>
<th><?php echo $lang->task->estimate;?></th>
<td>
<?php $disabled = (!empty($task->team) or $task->parent < 0) ? "disabled='disabled'" : '';?>
<?php echo html::input('estimate', $task->estimate, "class='form-control' {$disabled}");?>
</td>
</tr>
<tr class='hidden'>
<th><?php echo $lang->task->left;?></th>
<td>
<?php $disabled = (!empty($task->team) or $task->parent < 0) ? "disabled='disabled'" : '';?>
<?php echo html::input('left', $task->left, "class='form-control' {$disabled}");?>
</td>
</tr>
<?php foreach($task->team as $member):?>
<tr>
<td class='w-250px'><?php echo html::select("team[]", $members, $member->account, "class='form-control chosen'")?></td>
<td>
<div class='input-group'>
<span class='input-group-addon'><?php echo $lang->task->estimate?></span>
<?php echo html::input("teamEstimate[]", (float)$member->estimate, "class='form-control text-center' placeholder='{$lang->task->hour}'")?>
<span class='input-group-addon fix-border'><?php echo $lang->task->consumed?></span>
<?php echo html::input("teamConsumed[]", (float)$member->consumed, "class='form-control text-center' readonly placeholder='{$lang->task->hour}'")?>
<span class='input-group-addon fix-border'><?php echo $lang->task->left?></span>
<?php echo html::input("teamLeft[]", (float)$member->left, "class='form-control text-center' placeholder='{$lang->task->hour}'")?>
</div>
</td>
<td class='w-130px sort-handler'>
<button type="button" class="btn btn-link btn-sm btn-icon btn-add"><i class="icon icon-plus"></i></button>
<button type='button' class='btn btn-link btn-sm btn-icon btn-move'><i class='icon-move'></i></button>
<button type="button" class="btn btn-link btn-sm btn-icon btn-delete"><i class="icon icon-close"></i></button>
</td>
</tr>
<?php endforeach;?>
<tr class='template'>
<td class='w-250px'><?php echo html::select("team[]", $members, '', "class='form-control chosen'")?></td>
<td>
<div class='input-group'>
<span class='input-group-addon'><?php echo $lang->task->estimate?></span>
<?php echo html::input("teamEstimate[]", '', "class='form-control text-center' placeholder='{$lang->task->hour}'")?>
<span class='input-group-addon fix-border'><?php echo $lang->task->consumed?></span>
<?php echo html::input("teamConsumed[]", '', "class='form-control text-center' placeholder='{$lang->task->hour}'")?>
<span class='input-group-addon fix-border'><?php echo $lang->task->left?></span>
<?php echo html::input("teamLeft[]", '', "class='form-control text-center' placeholder='{$lang->task->hour}'")?>
</div>
</td>
<td class='w-130px sort-handler'>
<button type="button" class="btn btn-link btn-sm btn-icon btn-add"><i class="icon icon-plus"></i></button>
<button type='button' class='btn btn-link btn-sm btn-icon btn-move'><i class='icon-move'></i></button>
<button type="button" class="btn btn-link btn-sm btn-icon btn-delete"><i class="icon icon-close"></i></button>
</td>
</tr>
</tbody>
<tfoot>
<tr><td colspan='3' class='text-center form-actions'><?php echo html::submitButton();?></td></tr>
</tfoot>
</table>
</form>
<hr class='small' />
<?php endif;?>
</div>
</div>
<?php include '../../common/view/footer.html.php';?>