< Summary

Information
Class: AspNetCoreGeneratedDocument.Areas_Studio2_Views_OzonChat_ClientChats
Assembly: OzonOrdersWeb
File(s): /home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Areas/Studio2/Views/OzonChat/ClientChats.cshtml
Line coverage
0%
Covered lines: 0
Uncovered lines: 44
Coverable lines: 44
Total lines: 419
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 68
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%2352480%
<ExecuteAsync()0%420200%
<ExecuteAsync()100%210%
<ExecuteAsync()100%210%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Areas/Studio2/Views/OzonChat/ClientChats.cshtml

#LineLine coverage
 1@model OzonOrdersWeb.Areas.Studio2.ViewModels.OzonChatViewModels.OzonChatListViewModel
 2@{
 03    ViewData["Title"] = $"Чаты Ozon - {Model.ClientName}";
 04    Layout = "~/Views/Shared/_Layout.cshtml";
 5}
 6
 7<div class="container-fluid">
 8    <div class="row">
 9        <div class="col-12">
 10            <div class="card">
 11                <div class="card-header">
 12                    <div class="row align-items-center">
 13                        <div class="col-md-6">
 14                            <nav aria-label="breadcrumb">
 15                                <ol class="breadcrumb mb-0">
 16                                    <li class="breadcrumb-item">
 17                                        <a href="@Url.Action("Index")">
 18                                            <i class="fas fa-comments me-1"></i>Чаты Ozon
 19                                        </a>
 20                                    </li>
 021                                    <li class="breadcrumb-item active">@Model.ClientName</li>
 22                                </ol>
 23                            </nav>
 24                        </div>
 25                        <div class="col-md-6 text-end">
 026                            @if (Model.TotalUnreadCount > 0)
 27                            {
 28                                <span class="badge bg-danger fs-6 me-2">
 29                                    <i class="fas fa-envelope me-1"></i>
 030                                    Непрочитанных: @Model.TotalUnreadCount
 31                                </span>
 32                            }
 33                            <span class="badge bg-info fs-6">
 34                                <i class="fas fa-comments me-1"></i>
 035                                Всего чатов: @Model.TotalChatsCount
 36                            </span>
 37                        </div>
 38                    </div>
 39                </div>
 40
 41                <div class="card-body">
 042                    @if (TempData["ErrorMessage"] != null)
 43                    {
 44                        <div class="alert alert-danger alert-dismissible fade show" role="alert">
 45                            <i class="fas fa-exclamation-triangle me-2"></i>
 046                            @TempData["ErrorMessage"]
 47                            <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
 48                        </div>
 49                    }
 50
 51                    <!-- Фильтры -->
 52                    <form method="get" class="row g-3 mb-4 p-3 bg-light rounded">
 53                        <div class="col-md-2">
 54                            <label class="form-label fw-semibold">Статус чата</label>
 55                            <select name="status" class="form-select" onchange="this.form.submit()">
 056                                @foreach (var status in Model.AvailableStatuses)
 57                                {
 058                                    <option value="@status.Value" selected="@(Model.CurrentStatus == status.Value)">
 059                                        @status.Text
 60                                    </option>
 61                                }
 62                            </select>
 63                        </div>
 64                        <div class="col-md-2">
 65                            <label class="form-label fw-semibold">Тип чата</label>
 66                            <select name="chatType" class="form-select" onchange="this.form.submit()">
 067                                @foreach (var chatType in Model.AvailableChatTypes)
 68                                {
 069                                    <option value="@chatType.Value" selected="@(Model.CurrentChatType == chatType.Value)
 070                                        @chatType.Text
 71                                    </option>
 72                                }
 73                            </select>
 74                        </div>
 75                        <div class="col-md-2">
 76                            <label class="form-label fw-semibold">Сообщения</label>
 77                            <div class="form-check mt-2">
 78                                <input class="form-check-input" type="checkbox" name="unreadOnly" value="true"
 079                                       @(Model.UnreadOnly ? "checked" : "") onchange="this.form.submit()">
 80                                <label class="form-check-label">
 81                                    Только непрочитанные
 82                                </label>
 83                            </div>
 84                        </div>
 85                        <div class="col-md-2">
 86                            <label class="form-label fw-semibold">На странице</label>
 87                            <select name="pageSize" class="form-select" onchange="this.form.submit()">
 88                                <option value="10" selected="@(Model.PageSize == 10)">10</option>
 89                                <option value="30" selected="@(Model.PageSize == 30)">30</option>
 90                                <option value="50" selected="@(Model.PageSize == 50)">50</option>
 91                                <option value="100" selected="@(Model.PageSize == 100)">100</option>
 92                            </select>
 93                        </div>
 94                        <div class="col-md-4 d-flex align-items-end gap-2">
 95                            <button type="button" class="btn btn-primary" onclick="refreshChats()">
 96                                <i class="fas fa-sync-alt me-1"></i> Обновить
 97                            </button>
 98                            <form method="post" action="@Url.Action("ExportToExcel")" class="d-inline">
 99                                <input type="hidden" name="clientId" value="@Model.ClientId"/>
 100                                <input type="hidden" name="status" value="@Model.CurrentStatus"/>
 101                                <input type="hidden" name="unreadOnly" value="@Model.UnreadOnly"/>
 102                                <button type="submit" class="btn btn-success">
 103                                    <i class="fas fa-file-excel me-1"></i> Excel
 104                                </button>
 105                            </form>
 106                        </div>
 107                        <input type="hidden" name="clientId" value="@Model.ClientId"/>
 108                    </form>
 109
 110                    <!-- Статистика -->
 111                    <div class="row mb-3">
 112                        <div class="col-md-4">
 113                            <div class="card border-0 bg-light">
 114                                <div class="card-body py-2 px-3 d-flex align-items-center">
 115                                    <i class="fas fa-comments text-primary fs-4 me-3"></i>
 116                                    <div>
 117                                        <div class="text-muted small">Всего чатов</div>
 0118                                        <div class="fw-bold fs-5">@Model.TotalChatsCount</div>
 119                                    </div>
 120                                </div>
 121                            </div>
 122                        </div>
 123                        <div class="col-md-4">
 124                            <div class="card border-0 bg-light">
 125                                <div class="card-body py-2 px-3 d-flex align-items-center">
 126                                    <i class="fas fa-envelope-open text-danger fs-4 me-3"></i>
 127                                    <div>
 128                                        <div class="text-muted small">Непрочитанных сообщений</div>
 0129                                        <div class="fw-bold fs-5">@Model.TotalUnreadCount</div>
 130                                    </div>
 131                                </div>
 132                            </div>
 133                        </div>
 134                        <div class="col-md-4">
 135                            <div class="card border-0 bg-light">
 136                                <div class="card-body py-2 px-3 d-flex align-items-center">
 137                                    <i class="fas fa-list text-info fs-4 me-3"></i>
 138                                    <div>
 139                                        <div class="text-muted small">На странице</div>
 0140                                        <div class="fw-bold fs-5">@Model.Chats.Count</div>
 141                                    </div>
 142                                </div>
 143                            </div>
 144                        </div>
 145                    </div>
 146
 147                    <!-- Список чатов -->
 0148                    @if (Model.Chats.Any())
 149                    {
 150                        <div class="table-responsive">
 151                            <table class="table table-hover">
 152                                <thead class="table-light">
 153                                <tr>
 154                                    <th>ID чата</th>
 155                                    <th>Статус</th>
 156                                    <th>Тип</th>
 157                                    <th>Дата создания</th>
 158                                    <th class="text-center">Непрочитанных</th>
 159                                    <th>Последнее сообщение</th>
 160                                    <th style="width: 200px;">Действия</th>
 161                                </tr>
 162                                </thead>
 163                                <tbody id="chats-table-body">
 0164                                @foreach (var chat in Model.Chats)
 165                                {
 0166                                    <tr data-chat-id="@chat.Chat.ChatId"
 167                                        class="@(chat.UnreadCount > 0 ? "table-warning" : "")">
 168                                        <td>
 0169                                            <code class="text-primary">@chat.Chat.ChatId</code>
 170                                        </td>
 171                                        <td>
 172                                                <span class="@Model.GetStatusCssClass(chat.Chat.ChatStatus ?? "")">
 0173                                                    @Model.GetStatusDescription(chat.Chat.ChatStatus ?? "")
 174                                                </span>
 175                                        </td>
 176                                        <td>
 177                                                <span class="@Model.GetTypeCssClass(chat.Chat.ChatType ?? "")">
 0178                                                    @Model.GetTypeDescription(chat.Chat.ChatType ?? "")
 179                                                </span>
 180                                        </td>
 181                                        <td>
 182                                                <span title="@chat.Chat.CreatedAt.ToString("yyyy-MM-dd HH:mm:ss")">
 0183                                                    @chat.Chat.CreatedAt.ToString("dd.MM.yyyy HH:mm")
 184                                                </span>
 185                                        </td>
 186                                        <td class="text-center">
 0187                                            @if (chat.UnreadCount > 0)
 188                                            {
 0189                                                <span class="badge bg-danger">@chat.UnreadCount</span>
 190                                            }
 191                                            else
 192                                            {
 193                                                <span class="text-muted">—</span>
 194                                            }
 195                                        </td>
 196                                        <td>
 0197                                            @if (chat.LastMessageId != 0)
 198                                            {
 0199                                                <code class="text-muted small">@chat.LastMessageId</code>
 200                                            }
 201                                            else
 202                                            {
 203                                                <span class="text-muted">—</span>
 204                                            }
 205                                        </td>
 206                                        <td>
 207                                            <button type="button" class="btn btn-sm btn-outline-primary me-1"
 208                                                    onclick="viewChatDetails('@chat.Chat.ChatId')"
 209                                                    title="Подробности чата">
 210                                                <i class="fas fa-eye me-1"></i>Детали
 211                                            </button>
 212                                            <button type="button" class="btn btn-sm btn-outline-secondary"
 213                                                    onclick="copyChatId('@chat.Chat.ChatId')"
 214                                                    title="Скопировать ID чата">
 215                                                <i class="fas fa-copy me-1"></i>ID
 216                                            </button>
 217                                        </td>
 218                                    </tr>
 219                                }
 220                                </tbody>
 221                            </table>
 222                        </div>
 223
 224                        <!-- Пагинация -->
 0225                        @if (Model.TotalPages > 1)
 226                        {
 227                            <nav aria-label="Навигация по страницам" class="mt-3">
 228                                <div class="d-flex justify-content-between align-items-center">
 229                                    <div class="text-muted small">
 0230                                        Страница @Model.CurrentPage из @Model.TotalPages
 0231                                        (всего чатов: @Model.TotalChatsCount)
 232                                    </div>
 233                                    <ul class="pagination mb-0">
 234                                        @{
 0235                                            var baseUrl = $"{Url.Action("ClientChats")}?clientId={Model.ClientId}&status
 236                                        }
 237
 238                                        @* Первая страница *@
 239                                        <li class="page-item @(Model.CurrentPage == 1 ? "disabled" : "")">
 240                                            <a class="page-link" href="@(baseUrl)&page=1" title="Первая страница">
 241                                                <i class="fas fa-angle-double-left"></i>
 242                                            </a>
 243                                        </li>
 244
 245                                        @* Предыдущая *@
 246                                        <li class="page-item @(Model.CurrentPage == 1 ? "disabled" : "")">
 247                                            <a class="page-link" href="@(baseUrl)&page=@(Model.CurrentPage - 1)" title="
 248                                                <i class="fas fa-angle-left"></i>
 249                                            </a>
 250                                        </li>
 251
 252                                        @* Номера страниц *@
 253                                        @{
 0254                                            int startPage = Math.Max(1, Model.CurrentPage - 3);
 0255                                            int endPage = Math.Min(Model.TotalPages, Model.CurrentPage + 3);
 256
 0257                                            if (startPage > 1)
 258                                            {
 259                                                <li class="page-item">
 260                                                    <a class="page-link" href="@(baseUrl)&page=1">1</a>
 261                                                </li>
 0262                                                if (startPage > 2)
 263                                                {
 264                                                    <li class="page-item disabled"><span class="page-link">...</span></l
 265                                                }
 266                                            }
 267
 0268                                            for (int i = startPage; i <= endPage; i++)
 269                                            {
 270                                                <li class="page-item @(i == Model.CurrentPage ? "active" : "")">
 0271                                                    <a class="page-link" href="@(baseUrl)&page=@i">@i</a>
 272                                                </li>
 273                                            }
 274
 0275                                            if (endPage < Model.TotalPages)
 276                                            {
 0277                                                if (endPage < Model.TotalPages - 1)
 278                                                {
 279                                                    <li class="page-item disabled"><span class="page-link">...</span></l
 280                                                }
 281                                                <li class="page-item">
 0282                                                    <a class="page-link" href="@(baseUrl)&page=@Model.TotalPages">@Model
 283                                                </li>
 284                                            }
 285                                        }
 286
 287                                        @* Следующая *@
 288                                        <li class="page-item @(Model.CurrentPage >= Model.TotalPages ? "disabled" : "")"
 289                                            <a class="page-link" href="@(baseUrl)&page=@(Model.CurrentPage + 1)" title="
 290                                                <i class="fas fa-angle-right"></i>
 291                                            </a>
 292                                        </li>
 293
 294                                        @* Последняя страница *@
 295                                        <li class="page-item @(Model.CurrentPage >= Model.TotalPages ? "disabled" : "")"
 296                                            <a class="page-link" href="@(baseUrl)&page=@Model.TotalPages" title="Последн
 297                                                <i class="fas fa-angle-double-right"></i>
 298                                            </a>
 299                                        </li>
 300                                    </ul>
 301                                </div>
 302                            </nav>
 303                        }
 304                    }
 305                    else
 306                    {
 307                        <div class="text-center py-5">
 308                            <div class="mb-4">
 309                                <i class="fas fa-comments fa-4x text-muted"></i>
 310                            </div>
 311                            <h5 class="text-muted mb-3">Нет чатов</h5>
 312                            <p class="text-muted">
 0313                                @if (Model.UnreadOnly)
 314                                {
 315                                    <span>Нет чатов с непрочитанными сообщениями для выбранных фильтров.</span>
 316                                }
 317                                else
 318                                {
 319                                    <span>Нет чатов для выбранных фильтров.</span>
 320                                }
 321                            </p>
 322                        </div>
 323                    }
 324                </div>
 325            </div>
 326        </div>
 327    </div>
 328</div>
 329
 330<!-- Модальное окно для подробностей чата -->
 331<div class="modal fade" id="chatDetailsModal" tabindex="-1">
 332    <div class="modal-dialog modal-lg">
 333        <div class="modal-content">
 334            <div class="modal-header">
 335                <h5 class="modal-title">Подробности чата</h5>
 336                <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
 337            </div>
 338            <div class="modal-body">
 339                <div id="chat-details-content">
 340                    <div class="text-center">
 341                        <div class="spinner-border text-primary" role="status">
 342                            <span class="visually-hidden">Загрузка...</span>
 343                        </div>
 344                    </div>
 345                </div>
 346            </div>
 347        </div>
 348    </div>
 349</div>
 350
 351<script>
 352    // Обновление списка чатов
 353    function refreshChats() {
 354        window.location.reload();
 355    }
 356
 357    // Просмотр подробностей чата
 358    function viewChatDetails(chatId) {
 359        const modal = new bootstrap.Modal(document.getElementById('chatDetailsModal'));
 360        document.getElementById('chat-details-content').innerHTML = `
 361        <div class="row">
 362            <div class="col-md-6"><strong>ID чата:</strong></div>
 363            <div class="col-md-6"><code>${chatId}</code></div>
 364        </div>
 365        <hr>
 366        <div class="alert alert-info">
 367            <i class="fas fa-info-circle me-2"></i>
 368            Для полного просмотра сообщений чата используйте административную панель Ozon или соответствующие API методы
 369        </div>
 370    `;
 371        modal.show();
 372    }
 373
 374    // Копирование ID чата
 375    function copyChatId(chatId) {
 376        navigator.clipboard.writeText(chatId).then(() => {
 377            // Показать уведомление
 378            const toast = document.createElement('div');
 379            toast.className = 'toast align-items-center text-white bg-success border-0 position-fixed top-50 start-50 tr
 380            toast.style.zIndex = '9999';
 381            toast.innerHTML = `
 382            <div class="d-flex">
 383                <div class="toast-body">
 384                    <i class="fas fa-check-circle me-2"></i>
 385                    ID чата скопирован в буфер обмена
 386                </div>
 387                <button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast"></button>
 388            </div>
 389        `;
 390
 391            document.body.appendChild(toast);
 392            const bsToast = new bootstrap.Toast(toast);
 393            bsToast.show();
 394
 395            toast.addEventListener('hidden.bs.toast', () => {
 396                document.body.removeChild(toast);
 397            });
 398        });
 399    }
 400
 401    // Автообновление счётчика непрочитанных сообщений каждые 30 секунд
 402    setInterval(() => {
 0403        fetch(`@Url.Action("GetUnreadCount")?clientId=@Model.ClientId`)
 404            .then(response => response.json())
 405            .then(data => {
 406                if (data.success) {
 407                    const badge = document.querySelector('.badge.bg-danger');
 408                    if (data.unreadCount > 0) {
 409                        if (badge) {
 410                            badge.textContent = `Непрочитанных: ${data.unreadCount}`;
 411                        }
 412                    } else if (badge) {
 413                        badge.style.display = 'none';
 414                    }
 415                }
 416            })
 417            .catch(error => console.error('Ошибка при получении счётчика:', error));
 418    }, 30000);
 419</script>