Skip to content

Commit 6daed50

Browse files
committed
feat: 实现日志功能
1 parent 6eeafde commit 6daed50

5 files changed

Lines changed: 221 additions & 11 deletions

File tree

Lines changed: 53 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,60 @@
1-
@namespace BootstrapBlazor.Components
1+
@namespace BootstrapBlazor.Components.Tasks
22
@inherits BootstrapComponentBase
33

44
<div @attributes="AdditionalAttributes" class="@ClassString">
5-
<Table TItem="IScheduler" Items="@_schedulers">
5+
<Table TItem="IScheduler" Items="@_schedulers" IsBordered="true" IsStriped="true">
66
<TableColumns>
7-
<TableTemplateColumn Text="@Localizer["Name"]"></TableTemplateColumn>
8-
<TableTemplateColumn Text="@Localizer["Status"]"></TableTemplateColumn>
9-
<TableTemplateColumn Text="@Localizer["NextRuntime"]"></TableTemplateColumn>
10-
<TableTemplateColumn Text="@Localizer["LastRuntime"]"></TableTemplateColumn>
11-
<TableTemplateColumn Text="@Localizer["LastRunResult"]"></TableTemplateColumn>
12-
<TableTemplateColumn Text="@Localizer["TaskStatus"]"></TableTemplateColumn>
13-
<TableTemplateColumn Text="@Localizer["Exception"]"></TableTemplateColumn>
7+
<TableTemplateColumn Text="@Localizer["Name"]">
8+
<Template Context="v">
9+
@v.Row.Name
10+
</Template>
11+
</TableTemplateColumn>
12+
<TableTemplateColumn Text="@Localizer["Status"]">
13+
<Template Context="v">
14+
<Tag Color="GetStatusColor(v.Row.Status)" Icon="@GetStatusIcon(v.Row.Status)">@FormatStatus(v.Row.Status)</Tag>
15+
</Template>
16+
</TableTemplateColumn>
17+
<TableTemplateColumn Text="@Localizer["NextRuntime"]">
18+
<Template Context="v">
19+
@FormatDateTime(v.Row.NextRuntime)
20+
</Template>
21+
</TableTemplateColumn>
22+
<TableTemplateColumn Text="@Localizer["LastRuntime"]">
23+
<Template Context="v">
24+
@FormatDateTime(v.Row.LastRuntime)
25+
</Template>
26+
</TableTemplateColumn>
27+
<TableTemplateColumn Text="@Localizer["LastRunResult"]">
28+
<Template Context="v">
29+
<Tag Color="GetResultColor(v.Row.LastRunResult)">@FormatResult(v.Row.LastRunResult)</Tag>
30+
</Template>
31+
</TableTemplateColumn>
32+
<TableTemplateColumn Text="@Localizer["TaskStatus"]">
33+
<Template Context="v">
34+
@v.Row.TaskStatus
35+
</Template>
36+
</TableTemplateColumn>
37+
<TableTemplateColumn Text="@Localizer["Exception"]">
38+
<Template Context="v">
39+
@if (v.Row.Exception != null)
40+
{
41+
<Button Color="Color.Danger" Size="Size.ExtraSmall" Icon="fa-solid fa-exclamation-circle"
42+
OnClickWithoutRender="() => OnShowException(v.Row.Exception)"></Button>
43+
}
44+
</Template>
45+
</TableTemplateColumn>
46+
<TableTemplateColumn Text="@Localizer["Operation"]">
47+
<Template Context="v">
48+
<div class="btn-group">
49+
<Button Size="Size.ExtraSmall" Color="Color.Warning" Icon="fa-solid fa-pause-circle"
50+
Text="@Localizer["ButtonPause"]" OnClick="() => OnPause(v.Row)" IsDisabled="OnCheckTaskStatus(v.Row)" />
51+
<Button Size="Size.ExtraSmall" Color="Color.Success" Icon="fa-solid fa-play-circle"
52+
Text="@Localizer["ButtonRun"]" OnClick="() => OnRun(v.Row)" IsDisabled="OnCheckTaskStatus(v.Row)" />
53+
<Button Size="Size.ExtraSmall" Color="Color.Info" Icon="fa-solid fa-info-circle"
54+
Text="@Localizer["ButtonLog"]" OnClick="() => OnLog(v.Row)" IsDisabled="OnCheckTaskStatus(v.Row)" />
55+
</div>
56+
</Template>
57+
</TableTemplateColumn>
1458
</TableColumns>
1559
</Table>
1660
</div>

src/components/BootstrapBlazor.Tasks.Dashboard/TaskDashboard.razor.cs

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
using Microsoft.AspNetCore.Components;
66
using Microsoft.Extensions.Localization;
77

8-
namespace BootstrapBlazor.Components;
8+
namespace BootstrapBlazor.Components.Tasks;
99

1010
/// <summary>
1111
/// Task Dashboard Component
@@ -15,6 +15,9 @@ public partial class TaskDashboard
1515
[Inject, NotNull]
1616
private IStringLocalizer<TaskDashboard>? Localizer { get; set; }
1717

18+
[Inject, NotNull]
19+
private DialogService? DialogService { get; set; }
20+
1821
private string? ClassString => CssBuilder.Default("bb-tasks-dashboard")
1922
.AddClassFromAttributes(AdditionalAttributes)
2023
.Build();
@@ -30,4 +33,79 @@ protected override void OnParametersSet()
3033

3134
_schedulers = TaskServicesManager.ToList();
3235
}
36+
37+
private static Color GetStatusColor(SchedulerStatus status) => status switch
38+
{
39+
SchedulerStatus.Running => Color.Success,
40+
SchedulerStatus.Ready => Color.Primary,
41+
_ => Color.Danger
42+
};
43+
44+
private string FormatStatus(SchedulerStatus status) => status switch
45+
{
46+
SchedulerStatus.Running => Localizer["SchedulerStatus.Running"],
47+
SchedulerStatus.Ready => Localizer["SchedulerStatus.Ready"],
48+
_ => Localizer["SchedulerStatus.Disabled"]
49+
};
50+
51+
private static string GetStatusIcon(SchedulerStatus status) => status switch
52+
{
53+
SchedulerStatus.Running => "fa-solid fa-play-circle",
54+
SchedulerStatus.Ready => "fa-solid fa-stop-circle",
55+
_ => "fa-solid fa-times-circle"
56+
};
57+
58+
private static Color GetResultColor(TriggerResult result) => result switch
59+
{
60+
TriggerResult.Running => Color.Primary,
61+
TriggerResult.Success => Color.Success,
62+
TriggerResult.Cancelled => Color.Dark,
63+
TriggerResult.Timeout => Color.Warning,
64+
_ => Color.Danger,
65+
};
66+
67+
private string FormatResult(TriggerResult result) => result switch
68+
{
69+
TriggerResult.Running => Localizer["TriggerResult.Running"],
70+
TriggerResult.Success => Localizer["TriggerResult.Success"],
71+
TriggerResult.Cancelled => Localizer["TriggerResult.Timeout"],
72+
TriggerResult.Timeout => Localizer["TriggerResult.Timeout"],
73+
_ => Localizer["TriggerResult.Error"],
74+
};
75+
76+
private static Task OnPause(IScheduler scheduler)
77+
{
78+
scheduler.Status = SchedulerStatus.Ready;
79+
return Task.CompletedTask;
80+
}
81+
82+
private static Task OnRun(IScheduler scheduler)
83+
{
84+
scheduler.Status = SchedulerStatus.Running;
85+
return Task.CompletedTask;
86+
}
87+
88+
private async Task OnLog(IScheduler scheduler)
89+
{
90+
var option = new DialogOption()
91+
{
92+
Class = "modal-dialog-task",
93+
Title = Localizer["LogDilaogTitle", scheduler.Name],
94+
Component = BootstrapDynamicComponent.CreateComponent<TaskInfo>(new Dictionary<string, object?>
95+
{
96+
[nameof(TaskInfo.Scheduler)] = scheduler,
97+
[nameof(TaskInfo.HeaderText)] = Localizer["LogDilaogConsoleHeaderText"].Value
98+
})
99+
};
100+
await DialogService.Show(option);
101+
}
102+
103+
private static bool OnCheckTaskStatus(IScheduler model) => model.Status != SchedulerStatus.Running;
104+
105+
private static string? FormatDateTime(DateTimeOffset? dateTime) => dateTime?.ToString("yyyy-MM-dd HH:mm:ss");
106+
107+
private Task OnShowException(Exception ex)
108+
{
109+
return Task.CompletedTask;
110+
}
33111
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
@namespace BootstrapBlazor.Components.Tasks
2+
3+
<BootstrapBlazor.Components.Console Items="@Messages" Height="280" ShowAutoScroll="true" HeaderText="@HeaderText" />
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
2+
// Licensed under the LGPL License, Version 3.0. See License.txt in the project root for license information.
3+
// Website: https://admin.blazor.zone
4+
5+
using Microsoft.AspNetCore.Components;
6+
7+
namespace BootstrapBlazor.Components.Tasks;
8+
9+
/// <summary>
10+
/// TaskInfo 组件
11+
/// </summary>
12+
public partial class TaskInfo : IDisposable
13+
{
14+
/// <summary>
15+
/// 获得/设置 <see cref="IScheduler"/> 实例
16+
/// </summary>
17+
[Parameter]
18+
[NotNull]
19+
[EditorRequired]
20+
public IScheduler? Scheduler { get; set; }
21+
22+
/// <summary>
23+
/// 获得/设置 日志窗口标题文本
24+
/// </summary>
25+
[Parameter]
26+
public string? HeaderText { get; set; }
27+
28+
private List<ConsoleMessageItem> Messages { get; } = new(24);
29+
30+
/// <summary>
31+
/// <inheritdoc/>
32+
/// </summary>
33+
/// <param name="firstRender"></param>
34+
/// <returns></returns>
35+
protected override async Task OnAfterRenderAsync(bool firstRender)
36+
{
37+
await base.OnAfterRenderAsync(firstRender);
38+
39+
if (firstRender)
40+
{
41+
var sche = TaskServicesManager.Get(Scheduler.Name);
42+
if (sche != null)
43+
{
44+
sche.Triggers.First().PulseCallback = async t => await DispatchMessage(t);
45+
await DispatchMessage(sche.Triggers.First());
46+
}
47+
}
48+
}
49+
50+
private async Task DispatchMessage(ITrigger trigger)
51+
{
52+
var message = $"Trigger({trigger.GetType().Name}) LastRuntime: {trigger.LastRuntime} Run({trigger.LastResult}) NextRuntime: {trigger.NextRuntime} Elapsed: {trigger.LastRunElapsedTime.TotalSeconds}";
53+
Messages.Add(new ConsoleMessageItem()
54+
{
55+
Message = message
56+
});
57+
if (Messages.Count > 20)
58+
{
59+
Messages.RemoveAt(0);
60+
}
61+
await InvokeAsync(StateHasChanged);
62+
}
63+
64+
private void Dispose(bool disposing)
65+
{
66+
if (disposing)
67+
{
68+
var sche = TaskServicesManager.Get(Scheduler.Name);
69+
if (sche != null)
70+
{
71+
sche.Triggers.First().PulseCallback = null;
72+
}
73+
}
74+
}
75+
76+
/// <summary>
77+
///
78+
/// </summary>
79+
public void Dispose()
80+
{
81+
Dispose(true);
82+
GC.SuppressFinalize(this);
83+
}
84+
}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1-
@using Microsoft.AspNetCore.Components.Web
1+
@using BootstrapBlazor.Components
2+
@using Microsoft.AspNetCore.Components.Web
23
@using Longbow.Tasks

0 commit comments

Comments
 (0)