[sync story #73251] Sync code to this branch from feature/deliverable.
This commit is contained in:
@@ -156,37 +156,46 @@ $(document).off('change', '#formSettingBtn input[value=story]').on('change', '#f
|
||||
|
||||
function checkBatchEstStartedAndDeadline(event)
|
||||
{
|
||||
if(taskDateLimit != 'limit') return;
|
||||
|
||||
const $currentRow = $(event.target).closest('tr');
|
||||
const field = $(event.target).closest('.form-batch-control').data('name');
|
||||
const estStarted = $currentRow.find('[name^=estStarted]').val();
|
||||
const deadline = $currentRow.find('[name^=deadline]').val();
|
||||
const level = $currentRow.attr('data-level');
|
||||
|
||||
if(field == 'estStarted' && estStarted.length > 0 && parentEstStarted.length > 0 && estStarted < parentEstStarted)
|
||||
let $nextRow = $currentRow.next();
|
||||
while($nextRow.length)
|
||||
{
|
||||
const $estStartedTd = $currentRow.find('td[data-name=estStarted]');
|
||||
if($estStartedTd.find('.date-tip').length == 0 || $estStartedTd.find('.date-tip .form-tip').length > 0)
|
||||
{
|
||||
$estStartedTd.find('.date-tip').remove();
|
||||
let nextLevel = $nextRow.attr('data-level');
|
||||
if(nextLevel <= level) break;
|
||||
|
||||
let $datetip = $('<div class="date-tip"></div>');
|
||||
$datetip.append('<div class="form-tip text-warning">' + overParentEstStartedLang + '<span class="ignore-date underline">' + ignoreLang + '</div>');
|
||||
$datetip.off('click', '.ignore-date').on('click', '.ignore-date', function(e){ignoreTip(e)});
|
||||
$estStartedTd.append($datetip);
|
||||
}
|
||||
if(field == 'estStarted') $nextRow.find('td[data-name=estStarted]').find('[id^=estStarted]').zui('datepicker').render({disabled: estStarted == ''});
|
||||
if(field == 'deadline') $nextRow.find('td[data-name=deadline]').find('[id^=deadline]').zui('datepicker').render({disabled: deadline == ''});
|
||||
|
||||
$nextRow = $nextRow.next();
|
||||
}
|
||||
|
||||
if($currentRow.find('td[data-name=name]').find('input[name^=name]').val() == '') return;
|
||||
|
||||
const $estStartedTd = $currentRow.find('td[data-name=estStarted]');
|
||||
$estStartedTd.find('.date-tip').remove();
|
||||
if(field == 'estStarted' && estStarted.length > 0 && parentEstStarted.length > 0 && estStarted < parentEstStarted)
|
||||
{
|
||||
let $datetip = $('<div class="date-tip"></div>');
|
||||
$datetip.append('<div class="form-tip text-danger">' + overParentEstStartedLang + '</div>');
|
||||
$datetip.off('click', '.ignore-date').on('click', '.ignore-date', function(e){ignoreTip(e)});
|
||||
$estStartedTd.append($datetip);
|
||||
}
|
||||
|
||||
const $deadlineTd = $currentRow.find('td[data-name=deadline]');
|
||||
$deadlineTd.find('.date-tip').remove();
|
||||
if(field == 'deadline' && deadline.length > 0 && parentDeadline.length > 0 && deadline > parentDeadline)
|
||||
{
|
||||
const $deadlineTd = $currentRow.find('td[data-name=deadline]');
|
||||
if($deadlineTd.find('.date-tip').length == 0 || $deadlineTd.find('.date-tip .form-tip').length > 0)
|
||||
{
|
||||
$deadlineTd.find('.date-tip').remove();
|
||||
|
||||
let $datetip = $('<div class="date-tip"></div>');
|
||||
$datetip.append('<div class="form-tip text-warning">' + overParentDeadlineLang + '<span class="ignore-date underline">' + ignoreLang + '</div>');
|
||||
$datetip.off('click', '.ignore-date').on('click', '.ignore-date', function(e){ignoreTip(e)});
|
||||
$deadlineTd.append($datetip);
|
||||
}
|
||||
let $datetip = $('<div class="date-tip"></div>');
|
||||
$datetip.append('<div class="form-tip text-danger">' + overParentDeadlineLang + '</div>');
|
||||
$datetip.off('click', '.ignore-date').on('click', '.ignore-date', function(e){ignoreTip(e)});
|
||||
$deadlineTd.append($datetip);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,6 +290,27 @@ window.handleRenderRow = function($row, index)
|
||||
const $preAssignedTo = $prevRow.find('input[name^=assignedTo]').zui('picker');
|
||||
if($preAssignedTo != undefined) $assignedTo.render({items: $preAssignedTo.options.items});
|
||||
})
|
||||
|
||||
if(taskDateLimit == 'limit')
|
||||
{
|
||||
let disabledStarted = false;
|
||||
let disabledDeadline = false;
|
||||
if(parentID)
|
||||
{
|
||||
disabledStarted = parentEstStarted == '';
|
||||
disabledDeadline = parentDeadline == '';
|
||||
}
|
||||
else if(parentID == 0 && level > 0)
|
||||
{
|
||||
const $prevLevelRow = $row.prev('tr[data-level="' + (level - 1) + '"]');
|
||||
const $prevLevelStarted = $prevLevelRow.find('td[data-name=estStarted]').find('[id^=estStarted]');
|
||||
const $prevLevelDeadline = $prevLevelRow.find('td[data-name=deadline]').find('[id^=deadline]');
|
||||
disabledStarted = $prevLevelStarted.val() == '' || $prevLevelStarted.prop('disabled');
|
||||
disabledDeadline = $prevLevelDeadline.val() == '' || $prevLevelDeadline.prop('disabled');
|
||||
}
|
||||
$row.find('td[data-name=estStarted]').find('[id^=estStarted]').on('inited', function(e, info) { info[0].render({disabled: disabledStarted}); })
|
||||
$row.find('td[data-name=deadline]').find('[id^=deadline]').on('inited', function(e, info) { info[0].render({disabled: disabledDeadline}); })
|
||||
}
|
||||
};
|
||||
|
||||
$(function()
|
||||
|
||||
@@ -8,6 +8,8 @@ window.renderRowData = function($row, index, row)
|
||||
members[teamAccount] = users[teamAccount];
|
||||
});
|
||||
|
||||
$row.attr('data-parent', row.parent);
|
||||
|
||||
let taskMembers = [];
|
||||
if(row.mode != '' && teams[row.id] != undefined)
|
||||
{
|
||||
@@ -26,15 +28,25 @@ window.renderRowData = function($row, index, row)
|
||||
const taskUsers = [];
|
||||
let disabled = false;
|
||||
$row.find('.form-batch-input[data-name="assignedTo"]').empty();
|
||||
if(teams[row.id] != undefined && ((row.mode == 'linear' && row.status != 'done') || taskMembers[currentUser] == undefined))
|
||||
{
|
||||
disabled = true;
|
||||
}
|
||||
if(teams[row.id] != undefined && ((row.mode == 'linear' && row.status != 'done') || taskMembers[currentUser] == undefined)) disabled = true;
|
||||
if(row.status == 'closed') disabled = true;
|
||||
|
||||
if(row.assignedTo && taskMembers[row.assignedTo] == undefined) taskMembers[row.assignedTo] = users[row.assignedTo];
|
||||
for(let account in taskMembers) taskUsers.push({value: account, text: taskMembers[account]});
|
||||
|
||||
if(parentTasks[row.parent] != undefined && taskDateLimit == 'limit')
|
||||
{
|
||||
const parentTask = parentTasks[row.parent];
|
||||
$row.find('[id^="estStarted"]').on('inited', function(e, info)
|
||||
{
|
||||
if(parentTask.estStarted == '') info[0].render({disabled: true});
|
||||
});
|
||||
$row.find('[id^="deadline"]').on('inited', function(e, info)
|
||||
{
|
||||
if(parentTask.deadline == '') info[0].render({disabled: true});
|
||||
});
|
||||
}
|
||||
|
||||
$row.find('[data-name="assignedTo"]').find('.picker-box').on('inited', function(e, info)
|
||||
{
|
||||
const $assignedTo = info[0];
|
||||
@@ -46,13 +58,7 @@ window.renderRowData = function($row, index, row)
|
||||
$assignedTo.render({items: taskUsers, disabled: disabled, toolbar: pickerToolbar});
|
||||
});
|
||||
|
||||
if(row.status == 'wait')
|
||||
{
|
||||
$row.find('[data-name="status"]').find('.picker-box').on('inited', function(e, info)
|
||||
{
|
||||
info[0].render({items: noPauseStatusList});
|
||||
});
|
||||
}
|
||||
if(row.status == 'wait') $row.find('[data-name="status"]').find('.picker-box').on('inited', function(e, info) { info[0].render({items: noPauseStatusList}); });
|
||||
|
||||
if(teams[row.id] != undefined || row.isParent > 0)
|
||||
{
|
||||
@@ -173,51 +179,69 @@ window.statusChange = function(event)
|
||||
|
||||
function checkBatchEstStartedAndDeadline(event)
|
||||
{
|
||||
if(parentTasks.length == 0) return true;
|
||||
if(taskDateLimit != 'limit') return;
|
||||
|
||||
const $currentRow = $(event.target).closest('tr');
|
||||
const taskID = $currentRow.find('[name^=id]').val();
|
||||
const parentID = tasks[taskID].parent;
|
||||
if(typeof parentTasks[parentID] == 'undefined' || !parentTasks[parentID]) return true;
|
||||
|
||||
const parentTask = parentTasks[parentID];
|
||||
const field = $(event.target).closest('.form-batch-control').data('name');
|
||||
const estStarted = $currentRow.find('[name^=estStarted]').val();
|
||||
const deadline = $currentRow.find('[name^=deadline]').val();
|
||||
const parentTask = parentTasks[parentID] ? parentTasks[parentID] : {estStarted: '', deadline: ''};
|
||||
|
||||
if(field == 'estStarted')
|
||||
{
|
||||
let parentEstStarted = typeof tasks[parentID] == 'undefined' || $(event.target).closest('tbody').find('[name="estStarted[' + parentID + ']"]').length == 0 ? parentTask.estStarted : $(event.target).closest('tbody').find('[name="estStarted[' + parentID + ']"]').val();
|
||||
if(estStarted.length > 0 && parentEstStarted.length > 0 && estStarted < parentEstStarted)
|
||||
{
|
||||
const $estStartedTd = $currentRow.find('td[data-name=estStarted]');
|
||||
if($estStartedTd.find('.date-tip').length == 0 || $estStartedTd.find('.date-tip .form-tip').length > 0)
|
||||
{
|
||||
$estStartedTd.find('.date-tip').remove();
|
||||
const $estStartedTd = $currentRow.find('td[data-name=estStarted]');
|
||||
$estStartedTd.find('.date-tip').remove();
|
||||
|
||||
let $datetip = $('<div class="date-tip"></div>');
|
||||
$datetip.append('<div class="form-tip text-warning">' + overParentEstStartedLang.replace('%s', parentEstStarted) + '<span class="ignore-date underline">' + ignoreLang + '</div>');
|
||||
$datetip.off('click', '.ignore-date').on('click', '.ignore-date', function(e){ignoreTip(e)});
|
||||
$estStartedTd.append($datetip);
|
||||
const $childrenEstStarted = $(event.target).closest('tbody').find('tr[data-parent="' + taskID + '"]').find('[name^=estStarted]');
|
||||
$childrenEstStarted.each(function(){$(this).zui('datePicker').render({disabled: estStarted.length == 0});});
|
||||
if(estStarted.length > 0)
|
||||
{
|
||||
let $datetip = $('<div class="date-tip"></div>');
|
||||
let parentEstStarted = typeof tasks[parentID] == 'undefined' || $(event.target).closest('tbody').find('[name="estStarted[' + parentID + ']"]').length == 0 ? parentTask.estStarted : $(event.target).closest('tbody').find('[name="estStarted[' + parentID + ']"]').val();
|
||||
if(parentEstStarted.length > 0 && estStarted < parentEstStarted) $datetip.append('<div class="form-tip text-danger">' + overParentEstStartedLang.replace('%s', parentEstStarted) + '</div>');
|
||||
|
||||
let childEstStarted = childrenDateLimit[taskID] ? childrenDateLimit[taskID].estStarted : '';
|
||||
$childrenEstStarted.each(function()
|
||||
{
|
||||
if(childEstStarted.length == 0 || ($(this).val().length > 0 && $(this).val() < childEstStarted)) childEstStarted = $(this).val();
|
||||
});
|
||||
if(childEstStarted.length > 0 && estStarted > childEstStarted)
|
||||
{
|
||||
$datetip.append('<div class="form-tip text-warning">' + overChildEstStartedLang.replace('%s', childEstStarted) + '<span class="ignore-date ignore-child underline">' + ignoreLang + '</span></div>');
|
||||
$datetip.off('click', '.ignore-child').on('click', '.ignore-child', function(e){ignoreTip(e)});
|
||||
}
|
||||
$estStartedTd.append($datetip);
|
||||
}
|
||||
}
|
||||
|
||||
if(field == 'deadline')
|
||||
{
|
||||
let parentDeadline = typeof tasks[parentID] == 'undefined' || $(event.target).closest('tbody').find('[name="deadline[' + parentID + ']"]').length == 0 ? parentTask.deadline : $(event.target).closest('tbody').find('[name="deadline[' + parentID + ']"]').val();
|
||||
if(deadline.length > 0 && parentDeadline.length > 0 && deadline > parentDeadline)
|
||||
{
|
||||
const $deadlineTd = $currentRow.find('td[data-name=deadline]');
|
||||
if($deadlineTd.find('.date-tip').length == 0 || $deadlineTd.find('.date-tip .form-tip').length > 0)
|
||||
{
|
||||
$deadlineTd.find('.date-tip').remove();
|
||||
const $deadlineTd = $currentRow.find('td[data-name=deadline]');
|
||||
$deadlineTd.find('.date-tip').remove();
|
||||
|
||||
let $datetip = $('<div class="date-tip"></div>');
|
||||
$datetip.append('<div class="form-tip text-warning">' + overParentDeadlineLang.replace('%s', parentDeadline) + '<span class="ignore-date underline">' + ignoreLang + '</div>');
|
||||
$datetip.off('click', '.ignore-date').on('click', '.ignore-date', function(e){ignoreTip(e)});
|
||||
$deadlineTd.append($datetip);
|
||||
const $childrenDeadline = $(event.target).closest('tbody').find('tr[data-parent="' + taskID + '"]').find('[name^=deadline]');
|
||||
$childrenDeadline.each(function(){$(this).zui('datePicker').render({disabled: deadline.length == 0});});
|
||||
if(deadline.length > 0)
|
||||
{
|
||||
let $datetip = $('<div class="date-tip"></div>');
|
||||
|
||||
let parentDeadline = typeof tasks[parentID] == 'undefined' || $(event.target).closest('tbody').find('[name="deadline[' + parentID + ']"]').length == 0 ? parentTask.deadline : $(event.target).closest('tbody').find('[name="deadline[' + parentID + ']"]').val();
|
||||
if(parentDeadline.length > 0 && deadline > parentDeadline) $datetip.append('<div class="form-tip text-danger">' + overParentDeadlineLang.replace('%s', parentDeadline) + '</div>');
|
||||
|
||||
let childDeadline = childrenDateLimit[taskID] ? childrenDateLimit[taskID].deadline : '';
|
||||
$childrenDeadline.each(function()
|
||||
{
|
||||
if(childDeadline.length == 0 || ($(this).val().length > 0 && $(this).val() > childDeadline)) childDeadline = $(this).val();
|
||||
});
|
||||
if(childDeadline.length > 0 && deadline < childDeadline)
|
||||
{
|
||||
$datetip.append('<div class="form-tip text-warning">' + overChildDeadlineLang.replace('%s', childDeadline) + '<span class="ignore-date ignore-child underline">' + ignoreLang + '</span></div>');
|
||||
$datetip.off('click', '.ignore-child').on('click', '.ignore-child', function(e){ignoreTip(e)});
|
||||
}
|
||||
$deadlineTd.append($datetip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+30
-22
@@ -644,8 +644,17 @@ overParentEstStartedLang = '';
|
||||
overParentDeadlineLang = '';
|
||||
window.getParentEstStartedAndDeadline = function()
|
||||
{
|
||||
const parent = $('[name=parent]').val();
|
||||
if(!parent) return;
|
||||
const $parent = $('[name=parent]');
|
||||
const parent = $parent.val();
|
||||
if(!parent)
|
||||
{
|
||||
if(taskDateLimit != 'limit') return;
|
||||
|
||||
const $form = $parent.closest('form');
|
||||
$form.find('[name=estStarted]').zui('datePicker').render({disabled: false});
|
||||
$form.find('[name=deadline]').zui('datePicker').render({disabled: false});
|
||||
return;
|
||||
}
|
||||
|
||||
const link = $.createLink('task', 'ajaxGetTaskEstStartedAndDeadline', 'taskID=' + parent);
|
||||
$.getJSON(link, function(data)
|
||||
@@ -662,6 +671,8 @@ window.getParentEstStartedAndDeadline = function()
|
||||
|
||||
window.checkEstStartedAndDeadline = function(event)
|
||||
{
|
||||
if(taskDateLimit != 'limit') return;
|
||||
|
||||
const parent = $('[name=parent]').val();
|
||||
if(!parent) return;
|
||||
|
||||
@@ -672,31 +683,28 @@ window.checkEstStartedAndDeadline = function(event)
|
||||
const $deadline = $form.find('[name=deadline]');
|
||||
const deadline = $deadline.val();
|
||||
|
||||
const $estStartedDiv = $estStarted.closest('.form-group-wrapper');
|
||||
if(field == 'estStarted') $estStartedDiv.find('.date-tip').remove();
|
||||
if(field == 'estStarted' && estStarted.length > 0 && parentEstStarted.length > 0 && estStarted < parentEstStarted)
|
||||
{
|
||||
const $estStartedDiv = $estStarted.closest('.form-group');
|
||||
if($estStartedDiv.find('.date-tip').length == 0 || $estStartedDiv.find('.date-tip .form-tip').length > 0)
|
||||
{
|
||||
$estStartedDiv.find('.date-tip').remove();
|
||||
|
||||
let $datetip = $('<div class="date-tip"></div>');
|
||||
$datetip.append('<div class="form-tip text-warning">' + overParentEstStartedLang + '<span class="ignore-date underline">' + ignoreLang + '</div>');
|
||||
$datetip.off('click', '.ignore-date').on('click', '.ignore-date', function(e){ignoreTip(e)});
|
||||
$estStartedDiv.append($datetip);
|
||||
}
|
||||
let $datetip = $('<div class="date-tip"></div>');
|
||||
$datetip.append('<div class="form-tip text-danger">' + overParentEstStartedLang + '</div>');
|
||||
$estStartedDiv.append($datetip);
|
||||
}
|
||||
|
||||
const $deadlineDiv = $deadline.closest('.form-group-wrapper');
|
||||
if(field == 'deadline') $deadlineDiv.find('.date-tip').remove();
|
||||
if(field == 'deadline' && deadline.length > 0 && parentDeadline.length > 0 && deadline > parentDeadline)
|
||||
{
|
||||
const $deadlineDiv = $deadline.closest('.form-group');
|
||||
if($deadlineDiv.find('.date-tip').length == 0 || $deadlineDiv.find('.date-tip .form-tip').length > 0)
|
||||
{
|
||||
$deadlineDiv.find('.date-tip').remove();
|
||||
|
||||
let $datetip = $('<div class="date-tip"></div>');
|
||||
$datetip.append('<div class="form-tip text-warning">' + overParentDeadlineLang + '<span class="ignore-date underline">' + ignoreLang + '</div>');
|
||||
$datetip.off('click', '.ignore-date').on('click', '.ignore-date', function(e){ignoreTip(e)});
|
||||
$deadlineDiv.append($datetip);
|
||||
}
|
||||
let $datetip = $('<div class="date-tip"></div>');
|
||||
$datetip.append('<div class="form-tip text-danger">' + overParentDeadlineLang + '</div>');
|
||||
$deadlineDiv.append($datetip);
|
||||
}
|
||||
|
||||
let $estStartedPicker = $estStarted.zui('datePicker');
|
||||
let $deadlinePicker = $deadline.zui('datePicker');
|
||||
$estStartedPicker.render({disabled: parentEstStarted == ''});
|
||||
$deadlinePicker.render({disabled: parentDeadline == ''});
|
||||
if(parentEstStarted == '') $estStartedPicker.$.setValue('');
|
||||
if(parentDeadline == '') $deadlinePicker.$.setValue('');
|
||||
}
|
||||
|
||||
+43
-20
@@ -413,8 +413,17 @@ window.setStoryModule = function()
|
||||
|
||||
getParentEstStartedAndDeadline = function()
|
||||
{
|
||||
const parent = $('[name=parent]').val();
|
||||
if(!parent) return;
|
||||
const $parent = $('[name=parent]');
|
||||
const parent = $parent.val();
|
||||
if(!parent)
|
||||
{
|
||||
if(taskDateLimit != 'limit') return;
|
||||
|
||||
const $form = $parent.closest('form');
|
||||
$form.find('[name=estStarted]').zui('datePicker').render({disabled: false});
|
||||
$form.find('[name=deadline]').zui('datePicker').render({disabled: false});
|
||||
return;
|
||||
}
|
||||
|
||||
const link = $.createLink('task', 'ajaxGetTaskEstStartedAndDeadline', 'taskID=' + parent);
|
||||
$.getJSON(link, function(data)
|
||||
@@ -431,6 +440,11 @@ getParentEstStartedAndDeadline = function()
|
||||
|
||||
function checkEstStartedAndDeadline(event)
|
||||
{
|
||||
if(taskDateLimit != 'limit') return;
|
||||
|
||||
const parent = $('[name=parent]').val();
|
||||
if(!parent) return;
|
||||
|
||||
const $form = $(event.target).closest('form');
|
||||
const field = $(event.target).attr('name')
|
||||
const $estStarted = $form.find('[name=estStarted]');
|
||||
@@ -438,31 +452,40 @@ function checkEstStartedAndDeadline(event)
|
||||
const $deadline = $form.find('[name=deadline]');
|
||||
const deadline = $deadline.val();
|
||||
|
||||
if(field == 'estStarted' && estStarted.length > 0 && parentEstStarted.length > 0 && estStarted < parentEstStarted)
|
||||
const $estStartedDiv = $estStarted.closest('.form-group');
|
||||
if(field == 'estStarted' && estStarted.length > 0)
|
||||
{
|
||||
const $estStartedDiv = $estStarted.closest('.form-group');
|
||||
if($estStartedDiv.find('.date-tip').length == 0 || $estStartedDiv.find('.date-tip .form-tip').length > 0)
|
||||
{
|
||||
$estStartedDiv.find('.date-tip').remove();
|
||||
$estStartedDiv.find('.date-tip').remove();
|
||||
let $datetip = $('<div class="date-tip"></div>');
|
||||
if(parentEstStarted.length > 0 && estStarted < parentEstStarted) $datetip.append('<div class="form-tip text-danger">' + overParentEstStartedLang + '</div>');
|
||||
|
||||
let $datetip = $('<div class="date-tip"></div>');
|
||||
$datetip.append('<div class="form-tip text-warning">' + overParentEstStartedLang + '<span class="ignore-date underline">' + ignoreLang + '</div>');
|
||||
$datetip.off('click', '.ignore-date').on('click', '.ignore-date', function(e){ignoreTip(e)});
|
||||
$estStartedDiv.append($datetip);
|
||||
if(childDateLimit['estStarted'].length > 0 && estStarted > childDateLimit['estStarted'])
|
||||
{
|
||||
$datetip.append('<div class="form-tip text-warning">' + overChildEstStartedLang + '<span class="ignore-date ignore-child underline">' + ignoreLang + '</span></div>');
|
||||
$datetip.off('click', '.ignore-child').on('click', '.ignore-child', function (e) { ignoreTip(e) });
|
||||
}
|
||||
$estStartedDiv.append($datetip);
|
||||
}
|
||||
|
||||
if(field == 'deadline' && deadline.length > 0 && parentDeadline.length > 0 && deadline > parentDeadline)
|
||||
const $deadlineDiv = $deadline.closest('.form-group');
|
||||
if(field == 'deadline' && deadline.length > 0)
|
||||
{
|
||||
const $deadlineDiv = $deadline.closest('.form-group');
|
||||
if($deadlineDiv.find('.date-tip').length == 0 || $deadlineDiv.find('.date-tip .form-tip').length > 0)
|
||||
{
|
||||
$deadlineDiv.find('.date-tip').remove();
|
||||
$deadlineDiv.find('.date-tip').remove();
|
||||
let $datetip = $('<div class="date-tip"></div>');
|
||||
if(parentDeadline.length > 0 && deadline > parentDeadline) $datetip.append('<div class="form-tip text-danger">' + overParentDeadlineLang + '</div>');
|
||||
|
||||
let $datetip = $('<div class="date-tip"></div>');
|
||||
$datetip.append('<div class="form-tip text-warning">' + overParentDeadlineLang + '<span class="ignore-date underline">' + ignoreLang + '</div>');
|
||||
$datetip.off('click', '.ignore-date').on('click', '.ignore-date', function(e){ignoreTip(e)});
|
||||
$deadlineDiv.append($datetip);
|
||||
if(childDateLimit['deadline'].length > 0 && deadline < childDateLimit['deadline'])
|
||||
{
|
||||
$datetip.append('<div class="form-tip text-warning">' + overChildDeadlineLang + '<span class="ignore-date ignore-child underline">' + ignoreLang + '</span></div>');
|
||||
$datetip.off('click', '.ignore-child').on('click', '.ignore-child', function (e) { ignoreTip(e) });
|
||||
}
|
||||
$deadlineDiv.append($datetip);
|
||||
}
|
||||
|
||||
let $estStartedPicker = $estStarted.zui('datePicker');
|
||||
let $deadlinePicker = $deadline.zui('datePicker');
|
||||
$estStartedPicker.render({disabled: parentEstStarted == ''});
|
||||
$deadlinePicker.render({disabled: parentDeadline == ''});
|
||||
if(parentEstStarted == '') $estStartedPicker.$.setValue('');
|
||||
if(parentDeadline == '') $deadlinePicker.$.setValue('');
|
||||
}
|
||||
|
||||
@@ -437,6 +437,8 @@ $lang->task->overEsEndDate = 'The %s schedule end time has exceeded, please mo
|
||||
|
||||
$lang->task->overParentEsStarted = 'StartDate is less than the parent task\'s startDate: %s';
|
||||
$lang->task->overParentDeadline = 'Deadline is greater than the parent task\'s deadline: %s';
|
||||
$lang->task->overChildEstStarted = "Existed child task's startDate is less than the task's startDate: %s";
|
||||
$lang->task->overChildDeadline = "Existed child task's deadline is greater than the task's deadline: %s";
|
||||
|
||||
$lang->task->disabledHint = new stdclass();
|
||||
$lang->task->disabledHint->assignedConfirmStoryChange = 'Changes can only be confirmed by the assignee.';
|
||||
|
||||
@@ -437,6 +437,8 @@ $lang->task->overEsEndDate = 'The %s schedule end time has exceeded, please mo
|
||||
|
||||
$lang->task->overParentEsStarted = 'StartDate is less than the parent task\'s startDate: %s';
|
||||
$lang->task->overParentDeadline = 'Deadline is greater than the parent task\'s deadline: %s';
|
||||
$lang->task->overChildEstStarted = "Existed child task's startDate is less than the task's startDate: %s";
|
||||
$lang->task->overChildDeadline = "Existed child task's deadline is greater than the task's deadline: %s";
|
||||
|
||||
$lang->task->disabledHint = new stdclass();
|
||||
$lang->task->disabledHint->assignedConfirmStoryChange = 'Changes can only be confirmed by the assignee.';
|
||||
|
||||
@@ -437,6 +437,8 @@ $lang->task->overEsEndDate = 'The %s schedule end time has exceeded, please mo
|
||||
|
||||
$lang->task->overParentEsStarted = 'StartDate is less than the parent task\'s startDate: %s';
|
||||
$lang->task->overParentDeadline = 'Deadline is greater than the parent task\'s deadline: %s';
|
||||
$lang->task->overChildEstStarted = "Existed child task's startDate is less than the task's startDate: %s";
|
||||
$lang->task->overChildDeadline = "Existed child task's deadline is greater than the task's deadline: %s";
|
||||
|
||||
$lang->task->disabledHint = new stdclass();
|
||||
$lang->task->disabledHint->assignedConfirmStoryChange = 'Changes can only be confirmed by the assignee.';
|
||||
|
||||
@@ -437,6 +437,8 @@ $lang->task->overEsEndDate = '已超出%s计划结束时间,请先修改%s
|
||||
|
||||
$lang->task->overParentEsStarted = '任务的预计开始日期小于了父任务的预计开始日期:%s';
|
||||
$lang->task->overParentDeadline = '任务的截止日期大于了父任务的截止日期:%s';
|
||||
$lang->task->overChildEstStarted = '存在子任务的预计开始日期小于了该任务的预计开始日期:%s';
|
||||
$lang->task->overChildDeadline = '存在子任务的截止日期超出了该任务的截止日期:%s';
|
||||
|
||||
$lang->task->disabledHint = new stdclass();
|
||||
$lang->task->disabledHint->assignedConfirmStoryChange = '只有指派人才能确认变更';
|
||||
|
||||
+30
-10
@@ -749,26 +749,29 @@ class taskModel extends model
|
||||
* @param int $executionID
|
||||
* @param string $estStarted
|
||||
* @param string $deadline
|
||||
* @param string $prefix
|
||||
* @param int|null $rowID
|
||||
* @access public
|
||||
* @return false|void
|
||||
*/
|
||||
public function checkEstStartedAndDeadline(int $executionID, string $estStarted, string $deadline, string $prefix = '')
|
||||
public function checkEstStartedAndDeadline(int $executionID, string $estStarted, string $deadline, int|null $rowID = null)
|
||||
{
|
||||
$beginIndex = $rowID === null ? 'estStarted' : "estStarted[$rowID]";
|
||||
$endIndex = $rowID === null ? 'deadline' : "deadline[$rowID]";
|
||||
|
||||
$execution = $this->loadModel('execution')->getByID($executionID);
|
||||
if(empty($execution) || empty($this->config->limitTaskDate)) return false;
|
||||
if(empty($execution->multiple)) $this->lang->execution->common = $this->lang->project->common;
|
||||
|
||||
if(!empty($estStarted) && !helper::isZeroDate($estStarted))
|
||||
{
|
||||
if($estStarted < $execution->begin) dao::$errors['estStarted'] = $prefix . sprintf($this->lang->task->error->beginLtExecution, $this->lang->execution->common, $execution->begin);
|
||||
if($estStarted > $execution->end) dao::$errors['estStarted'] = $prefix . sprintf($this->lang->task->error->beginGtExecution, $this->lang->execution->common, $execution->end);
|
||||
if($estStarted < $execution->begin) dao::$errors[$beginIndex] = sprintf($this->lang->task->error->beginLtExecution, $this->lang->execution->common, $execution->begin);
|
||||
if($estStarted > $execution->end) dao::$errors[$beginIndex] = sprintf($this->lang->task->error->beginGtExecution, $this->lang->execution->common, $execution->end);
|
||||
}
|
||||
|
||||
if(!empty($deadline) && !helper::isZeroDate($deadline))
|
||||
{
|
||||
if($deadline > $execution->end) dao::$errors['deadline'] = $prefix . sprintf($this->lang->task->error->endGtExecution, $this->lang->execution->common, $execution->end);
|
||||
if($deadline < $execution->begin) dao::$errors['deadline'] = $prefix . sprintf($this->lang->task->error->endLtExecution, $this->lang->execution->common, $execution->begin);
|
||||
if($deadline > $execution->end) dao::$errors[$endIndex] = sprintf($this->lang->task->error->endGtExecution, $this->lang->execution->common, $execution->end);
|
||||
if($deadline < $execution->begin) dao::$errors[$endIndex] = sprintf($this->lang->task->error->endLtExecution, $this->lang->execution->common, $execution->begin);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -821,6 +824,11 @@ class taskModel extends model
|
||||
$tasks = $this->dao->select('estStarted, realStarted, deadline')->from(TABLE_TASK)->where('parent')->eq($taskID)->andWhere('status')->ne('cancel')->andWhere('deleted')->eq(0)->fetchAll();
|
||||
if(empty($tasks)) return !dao::isError();
|
||||
|
||||
/* Initialize task data and update it. */
|
||||
$parent = $this->fetchById($taskID);
|
||||
$taskDateLimit = $this->dao->select('taskDateLimit')->from(TABLE_PROJECT)->where('id')->eq($parent->project)->fetch('taskDateLimit');
|
||||
if($taskDateLimit == 'limit') return !dao::isError();
|
||||
|
||||
/* Compute the earliest estStarted, the earliest realStarted and the latest deadline. */
|
||||
$earliestEstStarted = '';
|
||||
$earliestRealStarted = '';
|
||||
@@ -832,9 +840,6 @@ class taskModel extends model
|
||||
if(!helper::isZeroDate($task->deadline) && (empty($latestDeadline) || $latestDeadline < $task->deadline)) $latestDeadline = $task->deadline;
|
||||
}
|
||||
|
||||
/* Initialize task data and update it. */
|
||||
$parent = $this->fetchById($taskID);
|
||||
|
||||
$newTask = array();
|
||||
if(!empty($earliestEstStarted) && !helper::isZeroDate($parent->estStarted) && $parent->estStarted > $earliestEstStarted) $newTask['estStarted'] = $earliestEstStarted;
|
||||
if(!empty($earliestRealStarted) && !helper::isZeroDate($parent->realStarted) && $parent->realStarted > $earliestRealStarted) $newTask['realStarted'] = $earliestRealStarted;
|
||||
@@ -3251,6 +3256,21 @@ class taskModel extends model
|
||||
|
||||
if($postData->type == 'task')
|
||||
{
|
||||
$project = $this->dao->select('id,taskDateLimit')->from(TABLE_PROJECT)->where('id')->eq($oldObject->project)->fetch();
|
||||
if($project->taskDateLimit == 'limit')
|
||||
{
|
||||
$parentTasks = $this->dao->select('id,estStarted,deadline')->from(TABLE_TASK)->where('id')->in($oldObject->path)->andWhere('id')->ne($oldObject->id)->fetchAll('id');
|
||||
foreach(array_reverse(array_filter(explode(',', $oldObject->path))) as $taskID)
|
||||
{
|
||||
if(!isset($parentTasks[$taskID])) continue;
|
||||
|
||||
$parentTask = $parentTasks[$taskID];
|
||||
if(!helper::isZeroDate($parentTask->estStarted) && $parentTask->estStarted > $postData->startDate) dao::$errors[] = sprintf($this->lang->task->overParentEsStarted, $parentTask->estStarted);
|
||||
if(!helper::isZeroDate($parentTask->deadline) && $parentTask->deadline < $postData->endDate) dao::$errors[] = sprintf($this->lang->task->overParentDeadline, $parentTask->deadline);
|
||||
}
|
||||
if(dao::isError()) return false;
|
||||
}
|
||||
|
||||
$oldObject->estStarted = $postData->startDate;
|
||||
$oldObject->deadline = $postData->endDate;
|
||||
unset($oldObject->openedDate);
|
||||
@@ -3728,7 +3748,7 @@ class taskModel extends model
|
||||
*/
|
||||
public function getChildTasksByList(array $taskIdList): array|false
|
||||
{
|
||||
$childTasks = $this->dao->select('id,parent')->from(TABLE_TASK)->where('parent')->in($taskIdList)->andWhere('deleted')->eq('0')->fetchGroup('parent', 'id');
|
||||
$childTasks = $this->dao->select('id,parent,path,estStarted,deadline')->from(TABLE_TASK)->where('parent')->in($taskIdList)->andWhere('deleted')->eq('0')->fetchGroup('parent', 'id');
|
||||
$nonStoryChildTasks = $this->dao->select('id,parent')->from(TABLE_TASK)->where('parent')->in($taskIdList)->andWhere('story')->eq('0')->andWhere('deleted')->eq('0')->fetchGroup('parent', 'id');
|
||||
return array($childTasks, $nonStoryChildTasks);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ jsVar('overParentEstStartedLang', isset($parentTask) ? sprintf($lang->task->over
|
||||
jsVar('overParentDeadlineLang', isset($parentTask) ? sprintf($lang->task->overParentDeadline, $parentTask->deadline) : '');
|
||||
jsVar('taskHasConsumed', $taskConsumed > 0);
|
||||
jsVar('langAddChildTask', $lang->task->addChildTask);
|
||||
jsVar('taskDateLimit', $project->taskDateLimit);
|
||||
|
||||
/* zin: Set variables to define picker options for form. */
|
||||
$storyItem = '';
|
||||
|
||||
@@ -27,6 +27,7 @@ jsVar('moduleGroup', $moduleGroup);
|
||||
jsVar('executionID', $executionID);
|
||||
jsVar('childTasks', $childTasks);
|
||||
jsVar('nonStoryChildTasks', $nonStoryChildTasks);
|
||||
jsVar('childrenDateLimit', $childrenDateLimit);
|
||||
jsVar('tasks', $tasks);
|
||||
jsVar('noPauseStatusList', $noPauseStatusList);
|
||||
jsVar('stories', $stories);
|
||||
@@ -37,7 +38,10 @@ jsVar('noSprintPairs', $noSprintPairs);
|
||||
jsVar('ignoreLang', $lang->project->ignore);
|
||||
jsVar('overParentEstStartedLang', $lang->task->overParentEsStarted);
|
||||
jsVar('overParentDeadlineLang', $lang->task->overParentDeadline);
|
||||
jsVar('overChildEstStartedLang', $lang->task->overChildEstStarted);
|
||||
jsVar('overChildDeadlineLang', $lang->task->overChildDeadline);
|
||||
jsVar('manageTeamMemberText', $lang->execution->manageTeamMember);
|
||||
jsVar('taskDateLimit', empty($project) ? '' : $project->taskDateLimit);
|
||||
|
||||
/* ====== Define the page structure with zin widgets ====== */
|
||||
formBatchPanel
|
||||
|
||||
@@ -29,6 +29,7 @@ jsVar('showFields', $showFields);
|
||||
jsVar('canViewStory', common::hasPriv('execution', 'storyView'));
|
||||
jsVar('ignoreLang', $lang->project->ignore);
|
||||
jsVar('assignedToOptions', $assignedToOptions);
|
||||
jsVar('taskDateLimit', $project->taskDateLimit);
|
||||
|
||||
if(!empty($task->team))
|
||||
{
|
||||
|
||||
@@ -34,9 +34,13 @@ jsVar('leftNotEmpty', sprintf($lang->error->gt, $lang->task->left, '0'));
|
||||
jsVar('requiredFields', $config->task->edit->requiredFields);
|
||||
jsVar('+parentEstStarted', !empty($parentTask) ? $parentTask->estStarted : '');
|
||||
jsVar('+parentDeadline', !empty($parentTask) ? $parentTask->deadline : '');
|
||||
jsVar('childDateLimit', $childDateLimit);
|
||||
jsVar('ignoreLang', $lang->project->ignore);
|
||||
jsVar('+overParentEstStartedLang', !empty($parentTask) ? sprintf($lang->task->overParentEsStarted, $parentTask->estStarted) : '');
|
||||
jsVar('+overParentDeadlineLang', !empty($parentTask) ? sprintf($lang->task->overParentDeadline, $parentTask->deadline) : '');
|
||||
jsVar('+overChildEstStartedLang', sprintf($lang->task->overChildEstStarted, $childDateLimit['estStarted']));
|
||||
jsVar('+overChildDeadlineLang', sprintf($lang->task->overChildDeadline, $childDateLimit['deadline']));
|
||||
jsVar('taskDateLimit', empty($project) ? '' : $project->taskDateLimit);
|
||||
|
||||
$confirmSyncTip = '';
|
||||
if(!empty($syncChildren) && !empty($task->children)) $confirmSyncTip = sprintf($lang->task->syncStoryToChildrenTip, 'ID' . implode(', ID', $syncChildren));
|
||||
@@ -463,6 +467,7 @@ detailBody
|
||||
datePicker
|
||||
(
|
||||
set::name('estStarted'),
|
||||
set::disabled(!empty($parentTask) && helper::isZeroDate($parentTask->estStarted) ? true : false),
|
||||
on::change('checkEstStartedAndDeadline'),
|
||||
helper::isZeroDate($task->estStarted) ? null : set::value($task->estStarted)
|
||||
)
|
||||
@@ -477,6 +482,7 @@ detailBody
|
||||
datePicker
|
||||
(
|
||||
set::name('deadline'),
|
||||
set::disabled(!empty($parentTask) && helper::isZeroDate($parentTask->deadline) ? true : false),
|
||||
on::change('checkEstStartedAndDeadline'),
|
||||
helper::isZeroDate($task->deadline) ? null : set::value($task->deadline)
|
||||
)
|
||||
|
||||
+131
-62
@@ -70,6 +70,7 @@ class taskZen extends task
|
||||
$this->view->showFields = $this->config->task->custom->createFields;
|
||||
$this->view->gobackLink = (isset($output['from']) && $output['from'] == 'global') ? $this->createLink('execution', 'task', "executionID={$executionID}") : '';
|
||||
$this->view->execution = $execution;
|
||||
$this->view->project = $this->loadModel('project')->fetchById($execution->project);
|
||||
$this->view->storyID = $storyID;
|
||||
$this->view->blockID = helper::isAjaxRequest('modal') ? $this->loadModel('block')->getSpecifiedBlockID('my', 'assigntome', 'assigntome') : 0;
|
||||
$this->view->hideStory = $this->task->isNoStoryExecution($execution);
|
||||
@@ -195,6 +196,7 @@ class taskZen extends task
|
||||
|
||||
$this->view->title = $execution->name . $this->lang->hyphen . $this->lang->task->batchEdit;
|
||||
$this->view->execution = $execution;
|
||||
$this->view->project = $this->loadModel('project')->fetchById($execution->project);
|
||||
$this->view->modules = $this->tree->getTaskOptionMenu($executionID, 0, !empty($this->config->task->allModule) ? 'allModule' : '');
|
||||
}
|
||||
else
|
||||
@@ -247,6 +249,18 @@ class taskZen extends task
|
||||
}
|
||||
|
||||
list($childTasks, $nonStoryChildTasks) = $this->task->getChildTasksByList(array_keys($tasks));
|
||||
$childrenDateLimit = array();
|
||||
foreach($childTasks as $parent => $children)
|
||||
{
|
||||
$childDateLimit = array('estStarted' => '', 'deadline' => '');
|
||||
foreach($children as $child)
|
||||
{
|
||||
if(!helper::isZeroDate($child->estStarted) && (empty($childDateLimit['estStarted']) || $childDateLimit['estStarted'] > $child->estStarted)) $childDateLimit['estStarted'] = $child->estStarted;
|
||||
if(!helper::isZeroDate($child->deadline) && (empty($childDateLimit['deadline']) || $childDateLimit['deadline'] < $child->deadline)) $childDateLimit['deadline'] = $child->deadline;
|
||||
}
|
||||
$childrenDateLimit[$parent] = $childDateLimit;
|
||||
}
|
||||
|
||||
$storyPairs = $this->story->getExecutionStoryPairs($executionID, 0, 'all', '', 'full', 'active', 'story', false);;
|
||||
$storyList = $this->story->getByList(array_keys($storyPairs));
|
||||
$stories = array();
|
||||
@@ -268,6 +282,7 @@ class taskZen extends task
|
||||
$this->view->moduleGroup = $moduleGroup;
|
||||
$this->view->childTasks = $childTasks;
|
||||
$this->view->nonStoryChildTasks = $nonStoryChildTasks;
|
||||
$this->view->childrenDateLimit = $childrenDateLimit;
|
||||
$this->view->stories = $stories;
|
||||
$this->view->parentTasks = $this->task->getByIdList($parentTaskIdList);
|
||||
$this->view->noSprintPairs = $this->loadModel('project')->getProjectExecutionPairs();
|
||||
@@ -301,7 +316,7 @@ class taskZen extends task
|
||||
$executions = !empty($task->project) ? $this->execution->getByProject($task->project, 'all', 0, true) : array();
|
||||
|
||||
/* Get task members. */
|
||||
$taskMembers = array();
|
||||
$taskMembers = $this->view->members;
|
||||
if(!empty($task->team))
|
||||
{
|
||||
foreach($task->members as $teamAccount)
|
||||
@@ -310,10 +325,6 @@ class taskZen extends task
|
||||
$taskMembers[$teamAccount] = $this->view->members[$teamAccount];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$taskMembers = $this->view->members;
|
||||
}
|
||||
|
||||
/* Get execution stories. */
|
||||
$moduleID = $task->module;
|
||||
@@ -324,29 +335,34 @@ class taskZen extends task
|
||||
}
|
||||
$stories = $this->story->getExecutionStoryPairs($this->view->execution->id, 0, 'all', $moduleID, 'full', 'active', 'story', false);
|
||||
|
||||
$syncChildren = array();
|
||||
$syncChildren = array();
|
||||
$childDateLimit = array('estStarted' => '', 'deadline' => '');
|
||||
if(!empty($task->children))
|
||||
{
|
||||
foreach($task->children as $child)
|
||||
{
|
||||
if(empty($child->story)) $syncChildren[] = $child->id;
|
||||
if(!helper::isZeroDate($child->estStarted) && (empty($childDateLimit['estStarted']) || $childDateLimit['estStarted'] > $child->estStarted)) $childDateLimit['estStarted'] = $child->estStarted;
|
||||
if(!helper::isZeroDate($child->deadline) && (empty($childDateLimit['deadline']) || $childDateLimit['deadline'] < $child->deadline)) $childDateLimit['deadline'] = $child->deadline;
|
||||
}
|
||||
}
|
||||
|
||||
if($this->view->execution->multiple) $manageLink = common::hasPriv('execution', 'manageMembers') ? $this->createLink('execution', 'manageMembers', "execution={$this->view->execution->id}") : '';
|
||||
if(!$this->view->execution->multiple) $manageLink = common::hasPriv('project', 'manageMembers') ? $this->createLink('project', 'manageMembers', "projectID={$this->view->execution->project}") : '';
|
||||
|
||||
$this->view->title = $this->lang->task->edit . 'TASK' . $this->lang->hyphen . $this->view->task->name;
|
||||
$this->view->stories = $this->story->addGradeLabel($stories);
|
||||
$this->view->tasks = $tasks;
|
||||
$this->view->taskMembers = $taskMembers;
|
||||
$this->view->users = $this->loadModel('user')->getPairs('nodeleted|noclosed', "{$task->openedBy},{$task->canceledBy},{$task->closedBy}");
|
||||
$this->view->showAllModule = isset($this->config->execution->task->allModule) ? $this->config->execution->task->allModule : '';
|
||||
$this->view->modules = $this->tree->getTaskOptionMenu($task->execution, 0, $this->view->showAllModule ? 'allModule' : '');
|
||||
$this->view->executions = $executions;
|
||||
$this->view->syncChildren = $syncChildren;
|
||||
$this->view->parentTask = !empty($task->parent) ? $this->task->getById($task->parent) : null;
|
||||
$this->view->manageLink = $manageLink;
|
||||
$this->view->title = $this->lang->task->edit . 'TASK' . $this->lang->hyphen . $this->view->task->name;
|
||||
$this->view->stories = $this->story->addGradeLabel($stories);
|
||||
$this->view->tasks = $tasks;
|
||||
$this->view->taskMembers = $taskMembers;
|
||||
$this->view->users = $this->loadModel('user')->getPairs('nodeleted|noclosed', "{$task->openedBy},{$task->canceledBy},{$task->closedBy}");
|
||||
$this->view->showAllModule = isset($this->config->execution->task->allModule) ? $this->config->execution->task->allModule : '';
|
||||
$this->view->modules = $this->tree->getTaskOptionMenu($task->execution, 0, $this->view->showAllModule ? 'allModule' : '');
|
||||
$this->view->executions = $executions;
|
||||
$this->view->syncChildren = $syncChildren;
|
||||
$this->view->childDateLimit = $childDateLimit;
|
||||
$this->view->parentTask = !empty($task->parent) ? $this->task->getById($task->parent) : null;
|
||||
$this->view->manageLink = $manageLink;
|
||||
$this->view->project = $task->project ? $this->loadModel('project')->fetchById($task->project) : null;
|
||||
$this->display();
|
||||
}
|
||||
|
||||
@@ -437,6 +453,7 @@ class taskZen extends task
|
||||
|
||||
$this->view->title = $this->lang->task->batchCreate;
|
||||
$this->view->execution = $execution;
|
||||
$this->view->project = $this->loadModel('project')->fetchById($execution->project);
|
||||
$this->view->modules = $modules;
|
||||
$this->view->parent = $taskID;
|
||||
$this->view->storyID = $storyID;
|
||||
@@ -558,12 +575,13 @@ class taskZen extends task
|
||||
->stripTags($this->config->task->editor->edit['id'], $this->config->allowedTags)
|
||||
->get();
|
||||
|
||||
$project = $this->loadModel('project')->fetchById($oldTask->project);
|
||||
$parents = $this->getParentEstStartedAndDeadline(array($task->parent));
|
||||
$this->checkLegallyDate($task, $project->taskDateLimit == 'limit', isset($parents[$task->parent]) ? $parents[$task->parent] : null);
|
||||
|
||||
$team = $this->post->team ? array_filter($this->post->team) : array();
|
||||
if($task->mode && empty($team))
|
||||
{
|
||||
dao::$errors['assignedTo'] = $this->lang->task->teamNotEmpty;
|
||||
return false;
|
||||
}
|
||||
if($task->mode && empty($team)) dao::$errors['assignedTo'] = $this->lang->task->teamNotEmpty;
|
||||
if(dao::isError()) return false;
|
||||
|
||||
return $this->loadModel('file')->processImgURL($task, $this->config->task->editor->edit['id'], (string)$this->post->uid);
|
||||
}
|
||||
@@ -1006,6 +1024,31 @@ class taskZen extends task
|
||||
$this->setMenu($this->view->execution->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查任务的开始时间和截止时间是否合法。
|
||||
* Check if the start and end time of the task is legal.
|
||||
*
|
||||
* @param object $task
|
||||
* @param bool $isDateLimit
|
||||
* @param object $parent
|
||||
* @param int|null $rowID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function checkLegallyDate(object $task, bool $isDateLimit, object|null $parent, int|null $rowID = null): void
|
||||
{
|
||||
$beginIndex = $rowID === null ? 'estStarted' : "estStarted[$rowID]";
|
||||
$endIndex = $rowID === null ? 'deadline' : "deadline[$rowID]";
|
||||
|
||||
$beginIsZeroDate = helper::isZeroDate($task->estStarted);
|
||||
$endIsZeroDate = helper::isZeroDate($task->deadline);
|
||||
if(!$beginIsZeroDate and !$endIsZeroDate and $task->deadline < $task->estStarted) dao::$errors[$endIndex] = $this->lang->task->error->deadlineSmall;
|
||||
|
||||
if(!$isDateLimit || empty($parent)) return;
|
||||
if(!$beginIsZeroDate && !helper::isZeroDate($parent->estStarted) && $task->estStarted < $parent->estStarted) dao::$errors[$beginIndex] = sprintf($this->lang->task->overParentEsStarted, $parent->estStarted);
|
||||
if(!$endIsZeroDate && !helper::isZeroDate($parent->deadline) && $task->deadline > $parent->deadline) dao::$errors[$endIndex] = sprintf($this->lang->task->overParentDeadline, $parent->deadline);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查传入的创建数据是否符合要求。
|
||||
* Check if the input post meets the requirements.
|
||||
@@ -1018,17 +1061,9 @@ class taskZen extends task
|
||||
protected function checkCreateTask(object $task, array $team): bool
|
||||
{
|
||||
/* Check if the estimate is positive. */
|
||||
if($task->estimate < 0)
|
||||
{
|
||||
dao::$errors['estimate'] = $this->lang->task->error->recordMinus;
|
||||
return false;
|
||||
}
|
||||
|
||||
if($this->post->multiple && empty($team))
|
||||
{
|
||||
dao::$errors['assignedTo'] = $this->lang->task->teamNotEmpty;
|
||||
return false;
|
||||
}
|
||||
if($task->estimate < 0) dao::$errors['estimate'] = $this->lang->task->error->recordMinus;
|
||||
if($this->post->multiple && empty($team)) dao::$errors['assignedTo'] = $this->lang->task->teamNotEmpty;
|
||||
if(dao::isError()) return false;
|
||||
|
||||
/* If the task start and end date must be between the execution start and end date, check if the task start and end date accord with the conditions. */
|
||||
if(!empty($this->config->limitTaskDate))
|
||||
@@ -1037,12 +1072,9 @@ class taskZen extends task
|
||||
if(dao::isError()) return false;
|
||||
}
|
||||
|
||||
/* Check start and end date. */
|
||||
if(!helper::isZeroDate($task->deadline) && $task->estStarted > $task->deadline)
|
||||
{
|
||||
dao::$errors['deadline'] = $this->lang->task->error->deadlineSmall;
|
||||
return false;
|
||||
}
|
||||
$project = $this->dao->findById($task->project)->from(TABLE_PROJECT)->fetch();
|
||||
$parents = $this->getParentEstStartedAndDeadline(array($task->parent));
|
||||
$this->checkLegallyDate($task, $project->taskDateLimit == 'limit', isset($parents[$task->parent]) ? $parents[$task->parent] : null);
|
||||
|
||||
return !dao::isError();
|
||||
}
|
||||
@@ -1060,26 +1092,26 @@ class taskZen extends task
|
||||
{
|
||||
/* Set required fields. */
|
||||
$requiredFields = $this->config->task->create->requiredFields;
|
||||
$execution = $this->loadModel('execution')->getById($executionID);
|
||||
$execution = $this->loadModel('execution')->fetchById($executionID);
|
||||
if($this->task->isNoStoryExecution($execution)) $requiredFields = str_replace(',story,', ',', ',' . $requiredFields . ',');
|
||||
$requiredFields = array_filter(explode(',', $requiredFields));
|
||||
|
||||
$levels = array();
|
||||
$project = $this->loadModel('project')->fetchById($execution->project);
|
||||
$parentIdList = array_filter(array_column($tasks, 'parent', 'parent'));
|
||||
$parents = $this->getParentEstStartedAndDeadline($parentIdList);
|
||||
foreach($tasks as $rowIndex => $task)
|
||||
{
|
||||
if(mb_strlen($task->name) > 255)
|
||||
{
|
||||
dao::$errors["name[$rowIndex]"] = sprintf($this->lang->task->error->length, 255);
|
||||
}
|
||||
$levels[$task->level] = $rowIndex;
|
||||
|
||||
if(mb_strlen($task->name) > 255) dao::$errors["name[$rowIndex]"] = sprintf($this->lang->task->error->length, 255);
|
||||
if(!empty($this->post->estimate[$rowIndex]) and !preg_match("/^[0-9]+(.[0-9]+)?$/", (string)$this->post->estimate[$rowIndex]))
|
||||
{
|
||||
dao::$errors["estimate[$rowIndex]"] = $this->lang->task->error->estimateNumber;
|
||||
}
|
||||
|
||||
/* If the task start and end date must be between the execution start and end date, check if the task start and end date accord with the conditions. */
|
||||
if(!empty($this->config->limitTaskDate))
|
||||
{
|
||||
$this->task->checkEstStartedAndDeadline($executionID, (string)$task->estStarted, (string)$task->deadline);
|
||||
}
|
||||
if(!empty($this->config->limitTaskDate)) $this->task->checkEstStartedAndDeadline($executionID, (string)$task->estStarted, (string)$task->deadline);
|
||||
|
||||
/* Check start and end date. */
|
||||
if(!helper::isZeroDate($task->deadline) && $task->deadline < $task->estStarted)
|
||||
@@ -1087,24 +1119,21 @@ class taskZen extends task
|
||||
dao::$errors["deadline[$rowIndex]"] = $this->lang->task->error->deadlineSmall;
|
||||
}
|
||||
|
||||
$parentTask = isset($parents[$task->parent]) ? $parents[$task->parent] : null;
|
||||
if($task->level > 0 && isset($levels[$task->level - 1])) $parentTask = zget($tasks, $levels[$task->level - 1], null);
|
||||
$this->checkLegallyDate($task, $project->taskDateLimit == 'limit', $parentTask, $rowIndex);
|
||||
|
||||
/* Check if the estimate is positive. */
|
||||
if($task->estimate < 0)
|
||||
{
|
||||
dao::$errors["estimate[$rowIndex]"] = $this->lang->task->error->recordMinus;
|
||||
}
|
||||
if($task->estimate < 0) dao::$errors["estimate[$rowIndex]"] = $this->lang->task->error->recordMinus;
|
||||
|
||||
/* Check if the required fields are empty. */
|
||||
foreach($requiredFields as $field)
|
||||
{
|
||||
if(empty($task->$field))
|
||||
{
|
||||
dao::$errors[$field . "[$rowIndex]"] = sprintf($this->lang->error->notempty, $this->lang->task->$field);
|
||||
}
|
||||
if(empty($task->$field)) dao::$errors[$field . "[$rowIndex]"] = sprintf($this->lang->error->notempty, $this->lang->task->$field);
|
||||
}
|
||||
}
|
||||
|
||||
if(dao::isError()) return false;
|
||||
return true;
|
||||
return !dao::isError();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1118,6 +1147,10 @@ class taskZen extends task
|
||||
*/
|
||||
protected function checkBatchEditTask(array $tasks, array $oldTasks): bool
|
||||
{
|
||||
$oldTask = reset($oldTasks);
|
||||
$project = $this->loadModel('project')->fetchById($oldTask->project);
|
||||
$parentIdList = array_filter(array_column($tasks, 'parent', 'parent'));
|
||||
$parents = $this->getParentEstStartedAndDeadline($parentIdList);
|
||||
foreach($tasks as $taskID => $task)
|
||||
{
|
||||
$oldTask = $oldTasks[$taskID];
|
||||
@@ -1131,11 +1164,12 @@ class taskZen extends task
|
||||
if($task->consumed < 0 ) dao::$errors["consumed[{$taskID}]"] = (array)sprintf($this->lang->task->error->recordMinus, $this->lang->task->consumedThisTime);
|
||||
if($task->left < 0) dao::$errors["left[$taskID]"] = (array)sprintf($this->lang->task->error->recordMinus, $this->lang->task->leftAB);
|
||||
|
||||
if(!empty($this->config->limitTaskDate)) $this->task->checkEstStartedAndDeadline($oldTask->execution, (string)$task->estStarted, (string)$task->deadline, "task:{$taskID} ");
|
||||
if(!empty($this->config->limitTaskDate)) $this->task->checkEstStartedAndDeadline($oldTask->execution, (string)$task->estStarted, (string)$task->deadline, $taskID);
|
||||
|
||||
if($task->status == 'cancel') continue;
|
||||
if($task->status == 'done' && !$task->consumed) dao::$errors["consumed[{$taskID}]"] = (array)sprintf($this->lang->error->notempty, $this->lang->task->consumedThisTime);
|
||||
if(!empty($task->deadline) && $task->estStarted > $task->deadline) dao::$errors["deadline[{$taskID}]"] = (array)$this->lang->task->error->deadlineSmall;
|
||||
|
||||
$this->checkLegallyDate($task, $project->taskDateLimit == 'limit', isset($parents[$task->parent]) ? $parents[$task->parent] : null, $taskID);
|
||||
}
|
||||
return !dao::isError();
|
||||
}
|
||||
@@ -1485,11 +1519,11 @@ class taskZen extends task
|
||||
unset($task->team);
|
||||
}
|
||||
|
||||
if($task->isParent)
|
||||
if($task->isParent && strpos($task->name, "[{$this->lang->task->parentAB}]") === false)
|
||||
{
|
||||
$task->name = '[' . $this->lang->task->parentAB . '] ' . $task->name;
|
||||
}
|
||||
elseif($task->parent > 0)
|
||||
elseif($task->parent > 0 && strpos($task->name, "[{$this->lang->task->childrenAB}]") === false)
|
||||
{
|
||||
$task->name = '[' . $this->lang->task->childrenAB . '] ' . $task->name;
|
||||
}
|
||||
@@ -2047,4 +2081,39 @@ class taskZen extends task
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取父任务的开始时间和截止时间。
|
||||
* Get the start and end time of the parent task.
|
||||
*
|
||||
* @param array $parentIdList
|
||||
* @access protected
|
||||
* @return array
|
||||
*/
|
||||
protected function getParentEstStartedAndDeadline(array $parentIdList): array
|
||||
{
|
||||
$pathPairs = $this->dao->select('id,path')->from(TABLE_TASK)->where('id')->in($parentIdList)->fetchPairs();
|
||||
if(empty($pathPairs)) return array();
|
||||
|
||||
$allParentIdList = array_filter(array_unique(explode(',', implode(',', $pathPairs))));
|
||||
$allParents = $this->dao->select('id,estStarted,deadline')->from(TABLE_TASK)->where('id')->in($allParentIdList)->fetchAll('id');
|
||||
$parents = array();
|
||||
foreach($pathPairs as $parentID => $path)
|
||||
{
|
||||
$parent = new stdClass();
|
||||
$parent->estStarted = null;
|
||||
$parent->deadline = null;
|
||||
foreach(array_reverse(array_filter(explode(',', $path))) as $taskID)
|
||||
{
|
||||
if(!isset($allParents[$taskID])) continue;
|
||||
|
||||
$task = $allParents[$taskID];
|
||||
if(empty($parent->estStarted) && !helper::isZeroDate($task->estStarted)) $parent->estStarted = $task->estStarted;
|
||||
if(empty($parent->deadline) && !helper::isZeroDate($task->deadline)) $parent->deadline = $task->deadline;
|
||||
if(!empty($parent->estStarted) && !empty($parent->deadline)) break;
|
||||
}
|
||||
$parents[$parentID] = $parent;
|
||||
}
|
||||
return $parents;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user