< Summary

Information
Class: AspNetCoreGeneratedDocument.Areas_Studio2_Views_TransactionJobs_Executions
Assembly: OzonOrdersWeb
File(s): /home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Areas/Studio2/Views/TransactionJobs/Executions.cshtml
Line coverage
0%
Covered lines: 0
Uncovered lines: 94
Coverable lines: 94
Total lines: 332
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 164
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
ExecuteAsync()0%1190340%
.cctor()100%210%
ToUtcSafe(...)0%2040%
FormatMsk(...)0%620%
TranslateExecutionStatus(...)0%110100%
GetExecutionStatusBadge(...)0%7280%
TranslateTriggerType(...)0%7280%
TranslateJobType(...)0%7280%
GetJobTypeBadgeClass(...)0%4260%
GetJobTypeIcon(...)0%4260%
<ExecuteAsync()0%6162780%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Areas/Studio2/Views/TransactionJobs/Executions.cshtml

#LineLine coverage
 1@model OzonOrdersWeb.Areas.Studio2.ViewModels.TransactionJobs.BackgroundJobsExecutionsPageViewModel
 2@{
 03    ViewData["Title"] = "Журнал фоновых задач";
 4}
 5@functions
 6{
 07    private static readonly TimeZoneInfo RussianTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Russian Standard Time");
 8
 9    private static DateTime ToUtcSafe(DateTime value)
 10    {
 011        return value.Kind switch
 012        {
 013            DateTimeKind.Utc => value,
 014            DateTimeKind.Local => value.ToUniversalTime(),
 015            _ => DateTime.SpecifyKind(value, DateTimeKind.Utc)
 016        };
 17    }
 18
 19    private static string FormatMsk(DateTime? value, string format = "dd.MM.yyyy HH:mm:ss")
 20    {
 021        if (!value.HasValue)
 022            return "-";
 23
 024        var msk = TimeZoneInfo.ConvertTimeFromUtc(ToUtcSafe(value.Value), RussianTimeZone);
 025        return msk.ToString(format);
 26    }
 27
 028    private static string TranslateExecutionStatus(string? status) => status switch
 029    {
 030        "Running" => "Выполняется",
 031        "Completed" => "Завершено",
 032        "PartialSuccess" => "Частично успешно",
 033        "Failed" => "Ошибка",
 034        _ => status ?? "-"
 035    };
 36
 037    private static string GetExecutionStatusBadge(string? status) => status switch
 038    {
 039        "Completed" => "bg-success",
 040        "Failed" => "bg-danger",
 041        "Running" => "bg-warning text-dark",
 042        "PartialSuccess" => "bg-warning text-dark",
 043        _ => "bg-secondary"
 044    };
 45
 046    private static string TranslateTriggerType(string? triggerType) => triggerType switch
 047    {
 048        "Scheduled" => "По расписанию",
 049        "Manual" => "Вручную",
 050        "Retry" => "Повтор",
 051        _ => triggerType ?? "-"
 052    };
 53
 054    private static string TranslateJobType(string? jobType) => jobType switch
 055    {
 056        "ShippedToCommissioner" => "Отгрузка комиссионеру",
 057        "CustomerReturn" => "Возврат покупателя",
 058        "ShippedToClient" => "Отгрузка клиенту",
 059        _ => jobType ?? "-"
 060    };
 61
 062    private static string GetJobTypeBadgeClass(string? jobType) => jobType switch
 063    {
 064        "ShippedToCommissioner" => "bg-primary",
 065        "CustomerReturn" => "bg-warning text-dark",
 066        "ShippedToClient" => "bg-success",
 067        _ => "bg-secondary"
 068    };
 69
 070    private static string GetJobTypeIcon(string? jobType) => jobType switch
 071    {
 072        "ShippedToCommissioner" => "fa-truck-loading",
 073        "CustomerReturn" => "fa-undo-alt",
 074        "ShippedToClient" => "fa-truck",
 075        _ => "fa-cog"
 076    };
 77}
 78
 79<div class="container-fluid mt-4">
 80    <div class="row mb-3">
 81        <div class="col">
 82            <h2><i class="fas fa-history me-2"></i>Журнал фоновых задач</h2>
 83            <p class="text-muted mb-0">Расписания, запуски, этапы, загрузки отчётов, сопоставления и результаты транзакц
 84        </div>
 85        <div class="col-auto">
 86            <a href="@Url.Action("Index", "TransactionJobs", new { area = "Studio2" })" class="btn btn-outline-secondary
 87                <i class="fas fa-arrow-left me-2"></i>Назад
 88            </a>
 89        </div>
 90    </div>
 91
 92    <div class="card mb-3">
 93        <div class="card-header"><strong>Фильтры запусков</strong></div>
 94        <div class="card-body">
 95            <form method="get" class="row g-3">
 96                <div class="col-md-3">
 97                    <label class="form-label">Расписание</label>
 98                    <select name="scheduleId" class="form-select">
 99                        <option value="">Все</option>
 0100                        @foreach (var schedule in Model.Schedules)
 101                        {
 0102                            if (Model.ScheduleId == schedule.Id)
 103                            {
 0104                                <option value="@schedule.Id" selected="selected">@schedule.Name</option>
 105                            }
 106                            else
 107                            {
 0108                                <option value="@schedule.Id">@schedule.Name</option>
 109                            }
 110                        }
 111                    </select>
 112                </div>
 113                <div class="col-md-2">
 114                    <label class="form-label">Статус</label>
 115                    <select name="status" class="form-select">
 116                        <option value="">Все</option>
 0117                        @if (Model.Status == "Running")
 118                        {
 119                            <option value="Running" selected="selected">Выполняется</option>
 120                        }
 121                        else
 122                        {
 123                            <option value="Running">Выполняется</option>
 124                        }
 0125                        @if (Model.Status == "Completed")
 126                        {
 127                            <option value="Completed" selected="selected">Завершено</option>
 128                        }
 129                        else
 130                        {
 131                            <option value="Completed">Завершено</option>
 132                        }
 0133                        @if (Model.Status == "PartialSuccess")
 134                        {
 135                            <option value="PartialSuccess" selected="selected">Частично успешно</option>
 136                        }
 137                        else
 138                        {
 139                            <option value="PartialSuccess">Частично успешно</option>
 140                        }
 0141                        @if (Model.Status == "Failed")
 142                        {
 143                            <option value="Failed" selected="selected">Ошибка</option>
 144                        }
 145                        else
 146                        {
 147                            <option value="Failed">Ошибка</option>
 148                        }
 149                    </select>
 150                </div>
 151                <div class="col-md-2">
 152                    <label class="form-label">Тип запуска</label>
 153                    <select name="triggerType" class="form-select">
 154                        <option value="">Все</option>
 0155                        @if (Model.TriggerType == "Scheduled")
 156                        {
 157                            <option value="Scheduled" selected="selected">По расписанию</option>
 158                        }
 159                        else
 160                        {
 161                            <option value="Scheduled">По расписанию</option>
 162                        }
 0163                        @if (Model.TriggerType == "Manual")
 164                        {
 165                            <option value="Manual" selected="selected">Вручную</option>
 166                        }
 167                        else
 168                        {
 169                            <option value="Manual">Вручную</option>
 170                        }
 0171                        @if (Model.TriggerType == "Retry")
 172                        {
 173                            <option value="Retry" selected="selected">Повтор</option>
 174                        }
 175                        else
 176                        {
 177                            <option value="Retry">Повтор</option>
 178                        }
 179                    </select>
 180                </div>
 181                <div class="col-md-2">
 182                    <label class="form-label">С</label>
 183                    <input type="date" name="from" class="form-control" value="@(Model.From?.ToString("yyyy-MM-dd"))" />
 184                </div>
 185                <div class="col-md-2">
 186                    <label class="form-label">По</label>
 187                    <input type="date" name="to" class="form-control" value="@(Model.To?.ToString("yyyy-MM-dd"))" />
 188                </div>
 189                <div class="col-md-1">
 190                    <label class="form-label">Размер</label>
 191                    <select name="pageSize" class="form-select">
 0192                        @if (Model.PageSize == 20)
 193                        {
 194                            <option value="20" selected="selected">20</option>
 195                        }
 196                        else
 197                        {
 198                            <option value="20">20</option>
 199                        }
 0200                        @if (Model.PageSize == 50)
 201                        {
 202                            <option value="50" selected="selected">50</option>
 203                        }
 204                        else
 205                        {
 206                            <option value="50">50</option>
 207                        }
 0208                        @if (Model.PageSize == 100)
 209                        {
 210                            <option value="100" selected="selected">100</option>
 211                        }
 212                        else
 213                        {
 214                            <option value="100">100</option>
 215                        }
 216                    </select>
 217                </div>
 218                <div class="col-12">
 219                    <button type="submit" class="btn btn-primary">Применить</button>
 220                    <a href="@Url.Action("Executions")" class="btn btn-outline-secondary ms-2">Сбросить</a>
 221                </div>
 222            </form>
 223        </div>
 224    </div>
 225
 226    <div class="card mb-3">
 227        <div class="card-header d-flex justify-content-between align-items-center">
 228            <strong>Расписания</strong>
 0229            <span class="badge bg-secondary">Всего: @Model.Schedules.Count</span>
 230        </div>
 231        <div class="table-responsive">
 232            <table class="table table-sm table-hover mb-0">
 233                <thead class="table-light">
 234                    <tr>
 235                        <th>ID</th>
 236                        <th>Название</th>
 237                        <th>Клиент</th>
 238                        <th>Тип</th>
 239                        <th>Cron</th>
 240                        <th>Активно</th>
 241                        <th>Последний запуск</th>
 242                        <th>Следующий запуск</th>
 243                    </tr>
 244                </thead>
 245                <tbody>
 0246                @foreach (var schedule in Model.Schedules)
 247                {
 248                    <tr>
 0249                        <td>@schedule.Id</td>
 0250                        <td>@schedule.Name</td>
 0251                        <td>@(schedule.OzonClient?.Name ?? "-")</td>
 252                        <td>
 253                            <span class="badge @GetJobTypeBadgeClass(schedule.JobType)">
 0254                                <i class="fas @GetJobTypeIcon(schedule.JobType) me-1"></i>@TranslateJobType(schedule.Job
 255                            </span>
 256                        </td>
 0257                        <td><code>@schedule.CronExpression</code></td>
 0258                        <td>@(schedule.IsActive ? "Да" : "Нет")</td>
 0259                        <td>@FormatMsk(schedule.LastRunTime, "dd.MM.yyyy HH:mm")</td>
 0260                        <td>@FormatMsk(schedule.NextRunTime, "dd.MM.yyyy HH:mm")</td>
 261                    </tr>
 262                }
 263                </tbody>
 264            </table>
 265        </div>
 266    </div>
 267
 268    <div class="card mb-3">
 269        <div class="card-header d-flex justify-content-between align-items-center">
 270            <strong>Запуски</strong>
 0271            <span class="badge bg-secondary">@Model.TotalCount</span>
 272        </div>
 273        <div class="table-responsive">
 274            <table class="table table-hover mb-0">
 275                <thead class="table-light">
 276                    <tr>
 277                        <th>ID</th>
 278                        <th>Расписание</th>
 279                        <th>Тип</th>
 280                        <th>Запуск</th>
 281                        <th>Статус</th>
 282                        <th>Старт</th>
 283                        <th>Завершение</th>
 284                        <th>Длительность</th>
 285                        <th>Заказы</th>
 286                        <th>Детали</th>
 287                    </tr>
 288                </thead>
 289                <tbody>
 0290                @foreach (var execution in Model.Executions)
 291                {
 292                    <tr>
 0293                        <td>@execution.Id</td>
 0294                        <td>@(execution.Schedule?.Name ?? execution.ScheduleId?.ToString() ?? "-")</td>
 295                        <td>
 296                            <span class="badge @GetJobTypeBadgeClass(execution.JobType)">
 0297                                <i class="fas @GetJobTypeIcon(execution.JobType) me-1"></i>@TranslateJobType(execution.J
 298                            </span>
 299                        </td>
 0300                        <td>@TranslateTriggerType(execution.TriggerType)</td>
 301                        <td>
 302                            <span class="badge @GetExecutionStatusBadge(execution.Status)">
 0303                                @TranslateExecutionStatus(execution.Status)
 304                            </span>
 305                        </td>
 0306                        <td>@FormatMsk(execution.StartedAt)</td>
 0307                        <td>@FormatMsk(execution.CompletedAt)</td>
 0308                        <td>@(execution.DurationMs.HasValue ? $"{execution.DurationMs} мс" : "-")</td>
 0309                        <td>@execution.TotalOrders / @execution.SuccessfulOrders / @execution.FailedOrders</td>
 310                        <td>
 311                            <a class="btn btn-sm btn-outline-primary" href="@Url.Action("ExecutionDetails", new { id = e
 312                        </td>
 313                    </tr>
 314                }
 315                </tbody>
 316            </table>
 317        </div>
 318        <div class="card-footer d-flex justify-content-between align-items-center">
 0319            <span>Страница @Model.Page из @Math.Max(Model.TotalPages, 1)</span>
 320            <div class="btn-group">
 321                @{
 0322                    var prevPage = Math.Max(1, Model.Page - 1);
 0323                    var nextPage = Math.Min(Math.Max(Model.TotalPages, 1), Model.Page + 1);
 324                }
 325                <a class="btn btn-outline-secondary @(Model.Page <= 1 ? "disabled" : "")"
 326                   href="@Url.Action("Executions", new { scheduleId = Model.ScheduleId, status = Model.Status, triggerTy
 327                <a class="btn btn-outline-secondary @(Model.Page >= Model.TotalPages ? "disabled" : "")"
 328                   href="@Url.Action("Executions", new { scheduleId = Model.ScheduleId, status = Model.Status, triggerTy
 329            </div>
 330        </div>
 331    </div>
 332</div>