Fix #5942: set the next execution time correctly.

This commit is contained in:
Ben
2026-01-08 11:39:32 +08:00
parent d4399955ac
commit 43ee682d1f
2 changed files with 228 additions and 151 deletions

View File

@@ -5,8 +5,16 @@
@inject IStringLocalizer<Edit> Localizer @inject IStringLocalizer<Edit> Localizer
@inject IStringLocalizer<SharedResources> SharedLocalizer @inject IStringLocalizer<SharedResources> SharedLocalizer
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate> @if (_initialized)
{
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
<div class="container"> <div class="container">
@if (!_editable)
{
<div class="alert alert-warning alert-dismissible fade show mb-3 custom" role="alert">
@Localizer["JobNotEditable"]
</div>
}
<div class="row mb-1 align-items-center"> <div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="name" HelpText="Enter the job name" ResourceKey="Name">Name: </Label> <Label Class="col-sm-3" For="name" HelpText="Enter the job name" ResourceKey="Name">Name: </Label>
<div class="col-sm-9"> <div class="col-sm-9">
@@ -31,8 +39,8 @@
<div class="row mb-1 align-items-center"> <div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="runs-every" HelpText="Select how often you want the job to run" ResourceKey="RunsEvery">Runs Every: </Label> <Label Class="col-sm-3" For="runs-every" HelpText="Select how often you want the job to run" ResourceKey="RunsEvery">Runs Every: </Label>
<div class="col-sm-9"> <div class="col-sm-9">
<input id="runs-every" class="form-control mb-1" @bind="@_interval" maxlength="4" required /> <input id="runs-every" class="form-control mb-1" @bind="@_interval" maxlength="4" required disabled="@(!_editable)" />
<select id="runs-every" class="form-select" @bind="@_frequency" required> <select id="runs-every" class="form-select" @bind="@_frequency" required disabled="@(!_editable)">
<option value="m">@Localizer["Minute(s)"]</option> <option value="m">@Localizer["Minute(s)"]</option>
<option value="H">@Localizer["Hour(s)"]</option> <option value="H">@Localizer["Hour(s)"]</option>
<option value="d">@Localizer["Day(s)"]</option> <option value="d">@Localizer["Day(s)"]</option>
@@ -45,7 +53,7 @@
<div class="row mb-1 align-items-center"> <div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="retention" HelpText="Number of log entries to retain for this job" ResourceKey="RetentionLog">Retention Log (Items): </Label> <Label Class="col-sm-3" For="retention" HelpText="Number of log entries to retain for this job" ResourceKey="RetentionLog">Retention Log (Items): </Label>
<div class="col-sm-9"> <div class="col-sm-9">
<input id="retention" type="number" min="0" step ="1" class="form-control" @bind="@_retentionHistory" maxlength="3" required /> <input id="retention" type="number" min="0" step="1" class="form-control" @bind="@_retentionHistory" maxlength="3" required disabled="@(!_editable)" />
</div> </div>
</div> </div>
<div class="row mb-1 align-items-center"> <div class="row mb-1 align-items-center">
@@ -53,10 +61,10 @@
<div class="col-sm-9"> <div class="col-sm-9">
<div class="row"> <div class="row">
<div class="col"> <div class="col">
<input id="starting" type="date" class="form-control" @bind="@_startDate" /> <input id="starting" type="date" class="form-control" @bind="@_startDate" disabled="@(!_editable)" />
</div> </div>
<div class="col"> <div class="col">
<input id="starting" type="time" class="form-control" @bind="@_startTime" placeholder="hh:mm" required="@(_startDate.HasValue)" /> <input id="starting" type="time" class="form-control" @bind="@_startTime" placeholder="hh:mm" required="@(_startDate.HasValue)" disabled="@(!_editable)" />
</div> </div>
</div> </div>
</div> </div>
@@ -66,10 +74,10 @@
<div class="col-sm-9"> <div class="col-sm-9">
<div class="row"> <div class="row">
<div class="col"> <div class="col">
<input id="ending" type="date" class="form-control" @bind="@_endDate" /> <input id="ending" type="date" class="form-control" @bind="@_endDate" disabled="@(!_editable)" />
</div> </div>
<div class="col"> <div class="col">
<input id="ending" type="time" class="form-control" placeholder="hh:mm" @bind="@_endTime" required="@(_endDate.HasValue)" /> <input id="ending" type="time" class="form-control" placeholder="hh:mm" @bind="@_endTime" required="@(_endDate.HasValue)" disabled="@(!_editable)" />
</div> </div>
</div> </div>
</div> </div>
@@ -77,28 +85,28 @@
<div class="row mb-1 align-items-center"> <div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="next" HelpText="Optionally modify the date and time when this job should execute next" ResourceKey="NextExecution">Next Execution: </Label> <Label Class="col-sm-3" For="next" HelpText="Optionally modify the date and time when this job should execute next" ResourceKey="NextExecution">Next Execution: </Label>
<div class="col-sm-9"> <div class="col-sm-9">
<div class="row"> <input id="next" class="form-control" @bind="@_nextDate" readonly />
<div class="col">
<input id="next" type="date" class="form-control" @bind="@_nextDate" />
</div>
<div class="col">
<input id="next" type="time" class="form-control" placeholder="hh:mm" @bind="@_nextTime" required="@(_nextDate.HasValue)" />
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
<br /> <br />
<button type="button" class="btn btn-success" @onclick="SaveJob">@SharedLocalizer["Save"]</button> <button type="button" class="btn btn-success" @onclick="SaveJob">@SharedLocalizer["Save"]</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink> @if (!_editable)
{
<button type="button" class="btn btn-danger ms-1" @onclick="ExecuteJob">@SharedLocalizer["Execute"]</button>
}
<NavLink class="btn btn-secondary ms-1" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
<br /> <br />
<br /> <br />
<AuditInfo CreatedBy="@createdby" CreatedOn="@createdon" ModifiedBy="@modifiedby" ModifiedOn="@modifiedon"></AuditInfo> <AuditInfo CreatedBy="@createdby" CreatedOn="@createdon" ModifiedBy="@modifiedby" ModifiedOn="@modifiedon"></AuditInfo>
</form> </form>
}
@code { @code {
private ElementReference form; private ElementReference form;
private bool validated = false; private bool validated = false;
private bool _initialized = false;
private bool _editable = true;
private int _jobId; private int _jobId;
private string _name = string.Empty; private string _name = string.Empty;
private string _jobType = string.Empty; private string _jobType = string.Empty;
@@ -127,6 +135,7 @@
Job job = await JobService.GetJobAsync(_jobId); Job job = await JobService.GetJobAsync(_jobId);
if (job != null) if (job != null)
{ {
_editable = !job.IsEnabled && !job.IsExecuting;
_name = job.Name; _name = job.Name;
_jobType = job.JobType; _jobType = job.JobType;
_isEnabled = job.IsEnabled.ToString(); _isEnabled = job.IsEnabled.ToString();
@@ -144,6 +153,8 @@
modifiedby = job.ModifiedBy; modifiedby = job.ModifiedBy;
modifiedon = job.ModifiedOn; modifiedon = job.ModifiedOn;
} }
_initialized = true;
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -166,7 +177,11 @@
var job = await JobService.GetJobAsync(_jobId); var job = await JobService.GetJobAsync(_jobId);
job.Name = _name; job.Name = _name;
job.JobType = _jobType; job.JobType = _jobType;
var enabledChanged = job.IsEnabled != Boolean.Parse(_isEnabled);
job.IsEnabled = Boolean.Parse(_isEnabled); job.IsEnabled = Boolean.Parse(_isEnabled);
if (_editable)
{
job.Frequency = _frequency; job.Frequency = _frequency;
if (job.Frequency == "O") // once if (job.Frequency == "O") // once
{ {
@@ -184,16 +199,77 @@
? LocalToUtc(_endDate.GetValueOrDefault().Date.Add(_endTime.GetValueOrDefault().TimeOfDay)) ? LocalToUtc(_endDate.GetValueOrDefault().Date.Add(_endTime.GetValueOrDefault().TimeOfDay))
: null; : null;
job.NextExecution = _nextDate.HasValue && _nextTime.HasValue
? LocalToUtc(_nextDate.GetValueOrDefault().Date.Add(_nextTime.GetValueOrDefault().TimeOfDay))
: null;
job.RetentionHistory = int.Parse(_retentionHistory); job.RetentionHistory = int.Parse(_retentionHistory);
}
if (!job.IsEnabled)
{
job.NextExecution = null;
}
else if (enabledChanged)
{
job.NextExecution = null;
if(job.StartDate != null && job.StartDate < DateTime.UtcNow)
{
var startDate = DateTime.UtcNow;
if ((job.Frequency == "d" || job.Frequency == "w" || job.Frequency == "M") && job.StartDate.Value.TimeOfDay.TotalSeconds != 0)
{
// set the start time
startDate = startDate.Date.Add(job.StartDate.Value.TimeOfDay);
if(startDate < DateTime.UtcNow)
{
switch (job.Frequency)
{
case "d":
startDate = startDate.AddDays(job.Interval);
break;
case "w":
startDate = startDate.AddDays(job.Interval * 7);
break;
case "M":
startDate = startDate.AddMonths(job.Interval);
break;
}
}
}
job.StartDate = startDate;
}
}
await PerformSaveJobAction(job);
NavigationManager.NavigateTo(NavigateUrl());
}
else
{
AddModuleMessage(Localizer["Message.Required.JobInfo"], MessageType.Warning);
}
}
private async Task ExecuteJob()
{
var job = await JobService.GetJobAsync(_jobId);
if (job != null)
{
job.NextExecution = null;
await PerformSaveJobAction(job);
if(!job.IsStarted)
{
await JobService.StartJobAsync(_jobId);
}
NavigationManager.NavigateTo(NavigateUrl());
}
}
private async Task PerformSaveJobAction(Job job)
{
try try
{ {
job = await JobService.UpdateJobAsync(job); job = await JobService.UpdateJobAsync(job);
await logger.LogInformation("Job Updated {Job}", job); await logger.LogInformation("Job Updated {Job}", job);
NavigationManager.NavigateTo(NavigateUrl());
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -201,9 +277,4 @@
AddModuleMessage(Localizer["Error.Job.Update"], MessageType.Error); AddModuleMessage(Localizer["Error.Job.Update"], MessageType.Error);
} }
} }
else
{
AddModuleMessage(Localizer["Message.Required.JobInfo"], MessageType.Warning);
}
}
} }

View File

@@ -195,4 +195,10 @@
<data name="Message.StartEndDateError" xml:space="preserve"> <data name="Message.StartEndDateError" xml:space="preserve">
<value>Start Date cannot be after End Date.</value> <value>Start Date cannot be after End Date.</value>
</data> </data>
<data name="JobNotEditable" xml:space="preserve">
<value>The job properties is not able to be modified because it's enabled or running in progress.</value>
</data>
<data name="Execute" xml:space="preserve">
<value>Execute</value>
</data>
</root> </root>