| | | 1 | | @using System.Text |
| | | 2 | | @using OServices.FiltersServices.FilterModels |
| | | 3 | | @using OzonDomains |
| | | 4 | | @using OzonDomains.Models |
| | | 5 | | @using OzonDomains.Models.SupplierStatuses |
| | | 6 | | @using OzonOrdersWeb.Areas.Studio2.ViewHelpers |
| | | 7 | | @using OzonOrdersWeb.ViewModels.OrderViewModels |
| | | 8 | | @using Services.FiltersServices.SortModels |
| | | 9 | | |
| | | 10 | | @model OrderPageViewModel<Order, OrderFilterModel> |
| | | 11 | | |
| | | 12 | | @{ |
| | | 13 | | // Текущий sortOrder для определения активной колонки |
| | 0 | 14 | | var currentSort = ViewBag.CurrentSortOrder as OrderSortState? ?? OrderSortState.StandardState; |
| | | 15 | | |
| | | 16 | | // Хелпер для получения текста с условной стрелкой |
| | 0 | 17 | | Func<string, OrderSortState, OrderSortState, string> getSortText = (text, ascState, descState) => |
| | 0 | 18 | | { |
| | 0 | 19 | | if (currentSort == ascState) return text + "↑"; |
| | 0 | 20 | | if (currentSort == descState) return text + "↓"; |
| | 0 | 21 | | return text; |
| | 0 | 22 | | }; |
| | | 23 | | } |
| | | 24 | | |
| | | 25 | | <link rel="stylesheet" href="~/css/orderIndex.css" asp-append-version="true"/> |
| | | 26 | | <link rel="stylesheet" href="~/css/Studio2/Orders/TransactionsTable.css" asp-append-version="true"/> |
| | | 27 | | <link rel="stylesheet" href="~/css/Studio2/Orders/productImageCell.css" asp-append-version="true"/> |
| | | 28 | | <link rel="stylesheet" href="~/css/Studio2/Orders/ozon-cancellation-info.css" asp-append-version="true"/> |
| | | 29 | | <link rel="stylesheet" href="~/css/Studio2/Orders/orders-index-redesign.css" asp-append-version="true"/> |
| | | 30 | | <link rel="stylesheet" href="~/css/table.css" asp-append-version="true"/> |
| | | 31 | | <!-- Закрепленный счетчик выделенных заказов --> |
| | | 32 | | <div id="selectedOrdersCounterFixed" class="selected-orders-counter"> |
| | | 33 | | <i class="fas fa-check-circle text-primary"></i> |
| | | 34 | | <span id="selectedCountFixed">0</span> |
| | | 35 | | <span class="text-muted">выделено</span> |
| | | 36 | | <button type="button" id="viewSelectedBtnFixed" class="btn btn-sm" |
| | | 37 | | onclick="showSelectedOrdersModal()"> |
| | | 38 | | <i class="fas fa-list me-1"></i>Показать |
| | | 39 | | </button> |
| | | 40 | | <button type="button" id="clearSelectedBtnFixed" class="btn btn-sm" |
| | | 41 | | onclick="clearSelectedIdsSession()" title="Очистить выделение"> |
| | | 42 | | <i class="fas fa-trash-alt"></i> |
| | | 43 | | </button> |
| | | 44 | | </div> |
| | | 45 | | |
| | | 46 | | <script src="~/js/copyArticle.js"></script> |
| | | 47 | | <script src="~/js/clearForm.js"></script> |
| | | 48 | | <!-- JsBarcode CDN --> |
| | | 49 | | <script src="https://cdn.jsdelivr.net/npm/jsbarcode@3.11.6/dist/JsBarcode.all.min.js"></script> |
| | | 50 | | |
| | | 51 | | <meta charset="UTF-8"> |
| | | 52 | | |
| | | 53 | | @{ |
| | 0 | 54 | | ViewData["Title"] = "Список заказов"; |
| | 0 | 55 | | Layout = "~/Views/Shared/_Layout.cshtml"; |
| | | 56 | | } |
| | | 57 | | |
| | | 58 | | @{ |
| | 0 | 59 | | var uploadResult = ViewData["UploadResult"] as int[]; |
| | 0 | 60 | | string uploadResultPeriod = ViewData["UploadResultPeriod"] as string ?? ""; |
| | | 61 | | // Приоритетно берём сообщение из TempData, как в других представлениях, с падением обратно в ViewData |
| | 0 | 62 | | string? transactionResult = TempData["TransactionResult"] as string ?? ViewData["TransactionResult"] as string; |
| | 0 | 63 | | string? erorrResult = TempData["ErorrResult"] as string ?? ViewData["ErorrResult"] as string; |
| | 0 | 64 | | string? ordersNotFoundInOzone = ViewData["OrdersNotFoundInOzone"] as string; |
| | | 65 | | // Транзакция прошла, но часть работы сознательно не выполнена (например, документ 1С не создан |
| | | 66 | | // из-за нехватки остатка). Ни «Успешно», ни «Ошибка операции» тут не подходят. |
| | 0 | 67 | | string? transactionWarning = TempData["TransactionWarning"] as string ?? ViewData["TransactionWarning"] as string; |
| | 0 | 68 | | bool? multipleShipmentNumberSearch = (bool?)TempData["MultipleShipmentNumberSearch"]; |
| | 0 | 69 | | int? foundOrdersCountForShipmentNumbers = (int?)TempData["FoundOrdersCountForShipmentNumbers"]; |
| | 0 | 70 | | int? shipmentNumbersSearchedCount = (int?)TempData["ShipmentNumbersSearchedCount"]; |
| | 0 | 71 | | var shipmentNumbersFoundRaw = TempData["ShipmentNumbersFound"] as string; |
| | 0 | 72 | | var shipmentNumbersNotFoundRaw = TempData["ShipmentNumbersNotFound"] as string; |
| | 0 | 73 | | var shipmentNumbersFound = string.IsNullOrEmpty(shipmentNumbersFoundRaw) ? new List<string>() : shipmentNumbersFound |
| | 0 | 74 | | var shipmentNumbersNotFound = string.IsNullOrEmpty(shipmentNumbersNotFoundRaw) ? new List<string>() : shipmentNumber |
| | | 75 | | } |
| | | 76 | | |
| | 0 | 77 | | @if (uploadResult != null) |
| | | 78 | | { |
| | | 79 | | <div class="alert alert-dismissible alert-success"> |
| | | 80 | | <button type="button" class="btn-close" data-bs-dismiss="alert"></button> |
| | | 81 | | <p>Файл успешно загружен! <br/>Результат: |
| | 0 | 82 | | <br/>Добавлено @uploadResult[0] строк.<br/>Обновлено @uploadResult[1] строк.</p> |
| | 0 | 83 | | @if (uploadResultPeriod != null) |
| | | 84 | | { |
| | 0 | 85 | | <p>Период @Html.Raw(@uploadResultPeriod)</p> |
| | | 86 | | } |
| | | 87 | | </div> |
| | | 88 | | } |
| | | 89 | | |
| | 0 | 90 | | @if (!string.IsNullOrWhiteSpace(ordersNotFoundInOzone)) |
| | | 91 | | { |
| | | 92 | | <script type="application/json" data-app-toast-seed> |
| | 0 | 93 | | @Html.Raw(System.Text.Json.JsonSerializer.Serialize(new[] |
| | 0 | 94 | | { |
| | 0 | 95 | | new { variant = "danger", title = "Нужна проверка", message = ordersNotFoundInOzone, detailsHtml = (string?) |
| | 0 | 96 | | })) |
| | | 97 | | </script> |
| | | 98 | | } |
| | | 99 | | |
| | 0 | 100 | | @if (ViewData["GlobalSearchQuery"] is string globalSearchQuery && !string.IsNullOrWhiteSpace(globalSearchQuery)) |
| | | 101 | | { |
| | | 102 | | <div class="alert alert-dismissible alert-info mb-2 py-2"> |
| | | 103 | | <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Закрыть"></button> |
| | | 104 | | <i class="fas fa-search me-2"></i> |
| | 0 | 105 | | <strong>Быстрый поиск:</strong> «@globalSearchQuery» — номер заказа, артикул или название |
| | | 106 | | </div> |
| | | 107 | | } |
| | | 108 | | |
| | 0 | 109 | | @if (multipleShipmentNumberSearch == true && foundOrdersCountForShipmentNumbers.HasValue) |
| | | 110 | | { |
| | | 111 | | <div class="alert alert-dismissible alert-info mb-2 py-2"> |
| | | 112 | | <button type="button" class="btn-close" data-bs-dismiss="alert"></button> |
| | | 113 | | <i class="fas fa-search me-2"></i> |
| | | 114 | | <strong>Результат поиска по номерам заказов:</strong> |
| | 0 | 115 | | найдено <strong>@foundOrdersCountForShipmentNumbers</strong> из <strong>@(shipmentNumbersSearchedCount ?? foundO |
| | 0 | 116 | | @if (shipmentNumbersNotFound.Count > 0) |
| | | 117 | | { |
| | 0 | 118 | | <span class="text-danger ms-2">не найдено: <strong>@shipmentNumbersNotFound.Count</strong></span> |
| | | 119 | | } |
| | | 120 | | <a class="ms-2" data-bs-toggle="collapse" href="#shipmentSearchDetails" role="button" aria-expanded="false"> |
| | | 121 | | <small>подробнее ▾</small> |
| | | 122 | | </a> |
| | | 123 | | <div class="collapse mt-2" id="shipmentSearchDetails"> |
| | | 124 | | <div class="row g-2"> |
| | 0 | 125 | | @if (shipmentNumbersFound.Count > 0) |
| | | 126 | | { |
| | | 127 | | <div class="col-auto"> |
| | 0 | 128 | | <strong class="text-success">Найдены (@shipmentNumbersFound.Count):</strong><br/> |
| | 0 | 129 | | <small>@string.Join(", ", shipmentNumbersFound)</small> |
| | | 130 | | </div> |
| | | 131 | | } |
| | 0 | 132 | | @if (shipmentNumbersNotFound.Count > 0) |
| | | 133 | | { |
| | | 134 | | <div class="col-auto"> |
| | 0 | 135 | | <strong class="text-danger">Не найдены (@shipmentNumbersNotFound.Count):</strong><br/> |
| | 0 | 136 | | <small>@string.Join(", ", shipmentNumbersNotFound)</small> |
| | | 137 | | </div> |
| | | 138 | | } |
| | | 139 | | </div> |
| | | 140 | | </div> |
| | | 141 | | </div> |
| | | 142 | | } |
| | | 143 | | |
| | | 144 | | @{ |
| | 0 | 145 | | var buttonState = ViewData["ButtonState"] as string ?? ""; |
| | 0 | 146 | | var allowedEndpointsList = ViewBag.AllowedEndpoints as List<string> ?? new List<string>(); |
| | 0 | 147 | | var hasEndpointPermissionsFlag = ViewBag.HasEndpointPermissions != null && (bool)ViewBag.HasEndpointPermissions; |
| | 0 | 148 | | var isAdminFlag = ViewBag.IsAdmin != null && (bool)ViewBag.IsAdmin; |
| | 0 | 149 | | var appPageTxPaths = ViewBag.AppPageTransactionPaths as List<string> ?? new List<string>(); |
| | 0 | 150 | | var useAppPageTx = ViewBag.UseAppPageTransactionMenu != null && (bool)ViewBag.UseAppPageTransactionMenu; |
| | 0 | 151 | | var appPageCtxPaths = ViewBag.AppPageContextMenuPaths as List<string> ?? new List<string>(); |
| | 0 | 152 | | var useAppPageCtx = ViewBag.UseAppPageContextMenu != null && (bool)ViewBag.UseAppPageContextMenu; |
| | 0 | 153 | | var isAppSuperAdmin = ViewBag.IsAppSuperAdmin != null && (bool)ViewBag.IsAppSuperAdmin; |
| | 0 | 154 | | var allAppPageTx = Studio2RolePageMenuCatalog.AllTransactionDropdownMvcPaths; |
| | 0 | 155 | | var allAppPageCtx = Studio2OrderContextMenuCatalog.AllContextMenuMvcPaths; |
| | | 156 | | } |
| | | 157 | | |
| | | 158 | | <script> |
| | | 159 | | // URL для LinkReplacementProduct (index.js — статический файл, Razor не обрабатывается) |
| | 0 | 160 | | window.linkReplacementProductUrl = '@Url.Action("LinkReplacementProduct", "Products", new { area = "Studio2" })'; |
| | | 161 | | // Список разрешённых эндпоинтов для текущего пользователя (делаем глобальными для доступа из других функций) |
| | 0 | 162 | | window.allowedEndpoints = @Html.Raw(Json.Serialize(allowedEndpointsList)); |
| | 0 | 163 | | window.hasEndpointPermissions = @Json.Serialize(hasEndpointPermissionsFlag); |
| | 0 | 164 | | window.isAdmin = @Json.Serialize(isAdminFlag); |
| | 0 | 165 | | window.isAppSuperAdmin = @Json.Serialize(isAppSuperAdmin); |
| | 0 | 166 | | window.appPageTransactionPaths = @Html.Raw(Json.Serialize(appPageTxPaths)); |
| | 0 | 167 | | window.useAppPageTransactionMenu = @Json.Serialize(useAppPageTx); |
| | 0 | 168 | | window.allAppPageTransactionPaths = @Html.Raw(Json.Serialize(allAppPageTx)); |
| | 0 | 169 | | window.appPageContextMenuPaths = @Html.Raw(Json.Serialize(appPageCtxPaths)); |
| | 0 | 170 | | window.useAppPageContextMenu = @Json.Serialize(useAppPageCtx); |
| | 0 | 171 | | window.allAppPageContextMenuPaths = @Html.Raw(Json.Serialize(allAppPageCtx)); |
| | | 172 | | |
| | | 173 | | // Отладочная информация |
| | | 174 | | console.log('Allowed endpoints:', window.allowedEndpoints); |
| | | 175 | | console.log('Allowed endpoints count:', window.allowedEndpoints ? window.allowedEndpoints.length : 0); |
| | | 176 | | console.log('Has endpoint permissions:', window.hasEndpointPermissions); |
| | | 177 | | console.log('Is Admin:', window.isAdmin); |
| | 0 | 178 | | console.log('Raw ViewBag.AllowedEndpoints:', @Html.Raw(Json.Serialize(ViewBag.AllowedEndpoints ?? new List<string>() |
| | | 179 | | |
| | 0 | 180 | | window.ordersIndexAjaxUrl = '@Url.Action("IndexTableAjax", "Orders", new { area = "Studio2" })'; |
| | 0 | 181 | | window.ordersIndexDateCalendarUrl = '@Url.Action("IndexDateCalendarAjax", "Orders", new { area = "Studio2" })'; |
| | | 182 | | window.ordersIndexAjaxEnabled = true; |
| | 0 | 183 | | window.searchCommercialCategoriesUrl = '@Url.Action("SearchCommercialCategories", "OrderLookup", new { area = "Studi |
| | 0 | 184 | | window.statusColors = @Html.Raw(Json.Serialize(ViewBag.StatusColors ?? new Dictionary<string, string>())); |
| | 0 | 185 | | window.clientStatusColors = @Html.Raw(Json.Serialize(ViewBag.ClientStatusColors ?? new Dictionary<string, string>()) |
| | | 186 | | var statusColors = window.statusColors; |
| | | 187 | | |
| | | 188 | | // Подсказки для пунктов меню транзакций (из StatusTransition), ключ = (int)TransactionType |
| | 0 | 189 | | window.transactionTooltipsJs = @Html.Raw(Json.Serialize(ViewBag.TransactionTooltips ?? new Dictionary<int, string>() |
| | | 190 | | // Правила переходов для всплывающей подсказки выделения заказов |
| | 0 | 191 | | window.transactionTransitionRulesJs = @Html.Raw(Json.Serialize(ViewBag.TransactionTransitionRules ?? new List<object |
| | | 192 | | </script> |
| | | 193 | | |
| | | 194 | | <partial name="~/Areas/Studio2/Views/Partials/Orders/_IndexTable.cshtml" model="Model"/> |
| | | 195 | | |
| | | 196 | | <div class="dropdown" id="contextMenu" style="display: none;"> |
| | | 197 | | <ul class="dropdown-menu" aria-labelledby="dropdownMenuButton"> |
| | | 198 | | <li><a class="dropdown-item" id="editAction">Изменить</a></li> |
| | | 199 | | <li><a class="dropdown-item" id="deleteAction">Удалить</a></li> |
| | | 200 | | </ul> |
| | | 201 | | </div> |
| | | 202 | | |
| | | 203 | | <div class="modal fade" id="historyModal" tabindex="-1" aria-labelledby="historyModalLabel" aria-hidden="true"> |
| | | 204 | | <div class="modal-dialog modal-dialog-centered modal-fullscreen"> |
| | | 205 | | <div class="modal-content orders-modal orders-modal--neutral"> |
| | | 206 | | <div class="modal-header"> |
| | | 207 | | <h5 class="modal-title" id="historyModalLabel"> |
| | | 208 | | <i class="fas fa-clock-rotate-left" aria-hidden="true"></i>История заказа |
| | | 209 | | </h5> |
| | | 210 | | <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Закрыть"></button> |
| | | 211 | | </div> |
| | | 212 | | <div class="modal-body"> |
| | | 213 | | <div id="historyContent"></div> |
| | | 214 | | </div> |
| | | 215 | | </div> |
| | | 216 | | </div> |
| | | 217 | | </div> |
| | | 218 | | |
| | | 219 | | |
| | | 220 | | <partial name="~/Areas/Studio2/Views/Partials/Orders/Modals/_OrderShipmentTotalsModal.cshtml"/> |
| | | 221 | | <ul id="infoWindow" class="dropdown-menu"></ul> |
| | | 222 | | |
| | | 223 | | <!-- Скрытое поле для передачи текущего номера страницы в index.js --> |
| | | 224 | | <input type="hidden" id="currentPageNumber" value="@Model.PageNumber" |
| | 0 | 225 | | data-orders-total-pages="@Model.TotalPages" data-orders-page-size="@Model.PageSize"/> |
| | | 226 | | |
| | | 227 | | <!-- Модальное окно подтверждения экспорта в Excel --> |
| | | 228 | | <partial name="~/Areas/Studio2/Views/Partials/Orders/Modals/_ExcelExportConfirm.cshtml"/> |
| | | 229 | | |
| | | 230 | | <!-- Модальное окно фильтров печати для клиента --> |
| | | 231 | | <partial name="~/Areas/Studio2/Views/Partials/Orders/Modals/_ClientPrintFilters.cshtml"/> |
| | | 232 | | |
| | | 233 | | <!-- Оверлей прогресса печати --> |
| | | 234 | | <partial name="~/Areas/Studio2/Views/Partials/Orders/_IndexPrintProgressOverlay.cshtml"/> |
| | | 235 | | |
| | | 236 | | <!-- Модальное окно подтверждения при нескольких товарах в заказе --> |
| | | 237 | | <partial name="~/Areas/Studio2/Views/Partials/Orders/Modals/_MultipleItemsConfirm.cshtml"/> |
| | | 238 | | |
| | | 239 | | <!-- Модальное окно для подтверждения печати этикетки --> |
| | | 240 | | <partial name="~/Areas/Studio2/Views/Partials/Orders/Modals/_LabelPrintConfirm.cshtml"/> |
| | | 241 | | |
| | | 242 | | <!-- Модальное окно печати этикетки Яндекс.Маркет --> |
| | | 243 | | <partial name="~/Areas/Studio2/Views/Partials/Orders/Modals/_YandexMarketLabelPrint.cshtml"/> |
| | | 244 | | |
| | | 245 | | <!-- Модальное окно для подтверждения архивации --> |
| | | 246 | | <partial name="~/Areas/Studio2/Views/Partials/Orders/Modals/_ArchiveConfirm.cshtml"/> |
| | | 247 | | |
| | | 248 | | <!-- Модальное окно для подтверждения разархивации --> |
| | | 249 | | <partial name="~/Areas/Studio2/Views/Partials/Orders/Modals/_UnarchiveConfirm.cshtml"/> |
| | | 250 | | |
| | | 251 | | <!-- Модальное окно для подтверждения удаления --> |
| | | 252 | | <partial name="~/Areas/Studio2/Views/Partials/Orders/Modals/_DeleteConfirm.cshtml"/> |
| | | 253 | | |
| | | 254 | | <br/> |
| | | 255 | | <div id="ordersIndexPaginationBar" class="orders-index-pagination-bar d-flex align-items-center justify-content-between |
| | | 256 | | <!-- Размер страницы --> |
| | | 257 | | <form method="post" |
| | | 258 | | asp-area="Studio2" |
| | | 259 | | asp-controller="Orders" |
| | | 260 | | asp-action="SetPageSizeForV2" |
| | | 261 | | class="orders-page-size-form d-flex align-items-center gap-2" |
| | | 262 | | data-no-loading> |
| | | 263 | | |
| | | 264 | | <label class="orders-page-size-label" for="pageSize">Строк на стр.</label> |
| | | 265 | | <input type="number" |
| | | 266 | | id="pageSize" |
| | | 267 | | name="size" |
| | | 268 | | class="form-control form-control-sm orders-page-size-input" |
| | | 269 | | placeholder="@OzonOrdersWeb.Controllers.OrdersController.MaxOrdersPageSize" |
| | | 270 | | min="1" |
| | | 271 | | max="@OzonOrdersWeb.Controllers.OrdersController.MaxOrdersPageSize" |
| | | 272 | | title="Максимум @(OzonOrdersWeb.Controllers.OrdersController.MaxOrdersPageSize) строк; больше — кнопкой « |
| | | 273 | | required> |
| | | 274 | | |
| | | 275 | | <button class="orders-page-size-btn" type="submit"> |
| | | 276 | | <i class="fas fa-check" aria-hidden="true"></i> |
| | | 277 | | <span>Ввод</span> |
| | | 278 | | </button> |
| | | 279 | | </form> |
| | | 280 | | |
| | | 281 | | <!-- Пагинация по центру --> |
| | | 282 | | @{ |
| | 0 | 283 | | ViewData["UseOrdersIndexAjax"] = true; |
| | | 284 | | } |
| | | 285 | | <partial name="~/Areas/Studio2/Views/Partials/Orders/_IndexPagination.cshtml" model="Model"/> |
| | | 286 | | |
| | | 287 | | <!-- Пустой элемент справа для симметрии --> |
| | | 288 | | <div class="orders-page-size-spacer" aria-hidden="true"></div> |
| | | 289 | | </div> |
| | | 290 | | |
| | | 291 | | @* «Показать ещё» — дозагрузка следующей страницы строк в тот же tbody через AJAX, |
| | | 292 | | без full reload. Скрыта, если текущая страница последняя (управляется orders-index-ajax.js). *@ |
| | | 293 | | <div id="ordersLoadMoreBar" class="orders-load-more-bar d-flex justify-content-center mb-3" |
| | 0 | 294 | | @(Model.PageNumber >= Model.TotalPages ? "hidden" : null)> |
| | | 295 | | <button type="button" id="ordersLoadMoreBtn" class="btn btn-outline-primary btn-sm" data-orders-load-more> |
| | | 296 | | <i class="fas fa-chevron-down me-1" aria-hidden="true"></i> |
| | 0 | 297 | | <span>Показать ещё @Model.PageSize</span> |
| | | 298 | | </button> |
| | | 299 | | </div> |
| | | 300 | | |
| | | 301 | | @* Передача данных поиска по EAN в index.js *@ |
| | 0 | 302 | | @if (ViewData["SearchByBarcode"] is true) |
| | | 303 | | { |
| | | 304 | | <div id="barcodeSearchData" |
| | 0 | 305 | | data-barcode="@ViewData["BarcodeValue"]" |
| | 0 | 306 | | data-found="@ViewData["FoundOrdersCount"]"> |
| | | 307 | | </div> |
| | | 308 | | } |
| | | 309 | | |
| | | 310 | | <!-- Модальное окно для связывания продуктов --> |
| | | 311 | | <partial name="~/Areas/Studio2/Views/Partials/Orders/Modals/_BindProducts.cshtml"/> |
| | | 312 | | |
| | | 313 | | @section Scripts { |
| | | 314 | | <script src="~/js/Studio2/Labels/ozonLabelPrintCore.js"></script> |
| | | 315 | | <script src="~/js/shared/header-page-dropdown.js" asp-append-version="true"></script> |
| | | 316 | | <script src="~/js/Studio2/Orders/orders-index-ajax.js" asp-append-version="true"></script> |
| | | 317 | | <script src="~/js/Studio2/Orders/index.js" asp-append-version="true"></script> |
| | | 318 | | <script src="~/js/Studio2/Orders/orders-filter-dropdowns.js" asp-append-version="true"></script> |
| | | 319 | | <script src="~/js/Studio2/Orders/orders-index-feedback.js" asp-append-version="true"></script> |
| | | 320 | | } |
| | | 321 | | |
| | | 322 | | @section HeaderActions { |
| | | 323 | | @{ |
| | 0 | 324 | | var supplierStatuses = ViewBag.SupplierStatuses as List<SupplierStatus> ?? []; |
| | 0 | 325 | | var selectedSupplierStatus = supplierStatuses.FirstOrDefault(status => status.Id == Model.FilterModel.SupplierStatus |
| | 0 | 326 | | var selectedSupplierStatusLabel = selectedSupplierStatus is null |
| | 0 | 327 | | ? string.Empty |
| | 0 | 328 | | : $"{GetSupplierProviderName(selectedSupplierStatus.ProviderKey)} · {selectedSupplierStatus.Name}"; |
| | | 329 | | |
| | 0 | 330 | | string GetSupplierProviderName(string providerKey) => providerKey switch |
| | 0 | 331 | | { |
| | 0 | 332 | | "Armtek" => "Армтек RU", |
| | 0 | 333 | | "ArmtekBy" => "Армтек РБ", |
| | 0 | 334 | | "Avd" => "АВД", |
| | 0 | 335 | | "MlAuto" => "ML-Auto РБ", |
| | 0 | 336 | | "MlAutoRu" => "ML-Auto RU", |
| | 0 | 337 | | _ => providerKey |
| | 0 | 338 | | }; |
| | | 339 | | |
| | 0 | 340 | | string? GetSupplierProviderLogoUrl(string providerKey) => providerKey switch |
| | 0 | 341 | | { |
| | 0 | 342 | | "Armtek" or "ArmtekBy" => "/images/armtek-logo.svg", |
| | 0 | 343 | | "Avd" => "/images/avd-logo.svg", |
| | 0 | 344 | | "MlAuto" => "https://www.ml-auto.by/media/files/settings/inside-placeholder-logo-mobile.png", |
| | 0 | 345 | | "MlAutoRu" => "https://ml-auto.ru/media/files/settings/inside-placeholder-logo-mobile.png", |
| | 0 | 346 | | _ => null |
| | 0 | 347 | | }; |
| | | 348 | | } |
| | | 349 | | <div class="header-page-actions"> |
| | | 350 | | <span class="header-page-actions-sep"></span> |
| | | 351 | | |
| | | 352 | | <!-- Настройки поиска --> |
| | | 353 | | <div class="btn-group"> |
| | | 354 | | <button id="searchSettingsDropdown" type="button" |
| | | 355 | | class="hpa-btn" aria-expanded="false" aria-haspopup="true"> |
| | | 356 | | <i class="fas fa-sliders-h"></i><span class="hpa-label">Поиск</span> |
| | | 357 | | </button> |
| | | 358 | | <ul id="searchSettingsDropdownMenu" class="dropdown-menu hpa-search-menu hpa-fixed-dropdown p-3" style="display: |
| | | 359 | | <li class="mb-2"> |
| | | 360 | | <div class="form-check form-switch"> |
| | | 361 | | <input class="form-check-input" type="checkbox" id="includeArchivedFilter" |
| | 0 | 362 | | data-initial-checked="@(Model.FilterModel.IncludeArchived.ToString().ToLower())"> |
| | | 363 | | <label class="form-check-label" for="includeArchivedFilter"> |
| | | 364 | | <i class="fas fa-archive me-1 text-primary"></i> Включая архив |
| | | 365 | | </label> |
| | | 366 | | </div> |
| | | 367 | | </li> |
| | | 368 | | <li class="mb-2"> |
| | | 369 | | <div class="form-check form-switch"> |
| | | 370 | | <input class="form-check-input" type="checkbox" id="filterListsByDataFilter" |
| | | 371 | | data-initial-checked="false"> |
| | | 372 | | <label class="form-check-label" for="filterListsByDataFilter"> |
| | | 373 | | <i class="fas fa-filter me-1 text-info"></i> Фильтры по данным |
| | | 374 | | </label> |
| | | 375 | | </div> |
| | | 376 | | </li> |
| | | 377 | | <li class="mb-2"> |
| | | 378 | | <div class="form-check form-switch"> |
| | | 379 | | <input class="form-check-input" type="checkbox" id="groupByShipmentFilter" |
| | 0 | 380 | | data-initial-checked="@(Model.FilterModel.GroupByShipment.ToString().ToLower())"> |
| | | 381 | | <label class="form-check-label" for="groupByShipmentFilter"> |
| | | 382 | | <i class="fas fa-boxes me-1 text-success"></i> Группировать по отправлению |
| | | 383 | | </label> |
| | | 384 | | </div> |
| | | 385 | | </li> |
| | | 386 | | <li class="mb-2"> |
| | | 387 | | <div class="form-check form-switch"> |
| | | 388 | | <input class="form-check-input" type="checkbox" id="syncClientStatusesFilter" |
| | 0 | 389 | | data-initial-checked="@(Model.FilterModel.SyncClientStatusesOnLoad.ToString().ToLower())"> |
| | | 390 | | <label class="form-check-label" for="syncClientStatusesFilter"> |
| | | 391 | | <i class="fas fa-sync-alt me-1 text-primary"></i> Синхр. статусы клиента |
| | | 392 | | </label> |
| | | 393 | | </div> |
| | | 394 | | </li> |
| | | 395 | | <li class="mb-2"> |
| | | 396 | | <div class="form-check form-switch"> |
| | | 397 | | <input class="form-check-input" type="checkbox" id="onlyWithZasylFilter" |
| | 0 | 398 | | data-initial-checked="@(Model.FilterModel.OnlyWithZasyl.ToString().ToLower())"> |
| | | 399 | | <label class="form-check-label" for="onlyWithZasylFilter"> |
| | | 400 | | <i class="fas fa-tag me-1 text-warning"></i> Только засыл |
| | | 401 | | </label> |
| | | 402 | | </div> |
| | | 403 | | </li> |
| | | 404 | | <li class="mb-2"> |
| | | 405 | | <div class="form-check form-switch"> |
| | | 406 | | <input class="form-check-input" type="checkbox" id="onlyWithReturnsFilter" |
| | 0 | 407 | | data-initial-checked="@(Model.FilterModel.OnlyWithReturns.ToString().ToLower())"> |
| | | 408 | | <label class="form-check-label" for="onlyWithReturnsFilter"> |
| | | 409 | | <i class="fas fa-undo me-1 text-info"></i> Только возвраты |
| | | 410 | | </label> |
| | | 411 | | </div> |
| | | 412 | | </li> |
| | | 413 | | <li class="mb-2"> |
| | | 414 | | <div class="form-check form-switch"> |
| | | 415 | | <input class="form-check-input" type="checkbox" id="onlyWithTrackingNumberFilter" |
| | 0 | 416 | | data-initial-checked="@(Model.FilterModel.OnlyWithTrackingNumber.ToString().ToLower())"> |
| | | 417 | | <label class="form-check-label" for="onlyWithTrackingNumberFilter"> |
| | | 418 | | <i class="fas fa-truck me-1 text-secondary"></i> С трек-номером |
| | | 419 | | </label> |
| | | 420 | | </div> |
| | | 421 | | </li> |
| | | 422 | | <li class="mb-2"> |
| | | 423 | | <label for="supplierStatusDropdownFilter" class="hpa-search-label"> |
| | | 424 | | <i class="fas fa-truck-loading me-1 text-success"></i> Статус поставщика |
| | | 425 | | </label> |
| | | 426 | | <div class="hpa-supplier-status-filter"> |
| | | 427 | | <button type="button" id="supplierStatusDropdownFilter" |
| | | 428 | | class="form-control form-control-sm hpa-supplier-status-trigger" |
| | | 429 | | data-placeholder="Все статусы поставщиков" |
| | | 430 | | value="@selectedSupplierStatusLabel" |
| | | 431 | | aria-expanded="false"> |
| | 0 | 432 | | <span class="hpa-supplier-status-trigger-text">@(string.IsNullOrEmpty(selectedSupplierStatusLabe |
| | | 433 | | <i class="fas fa-chevron-down" aria-hidden="true"></i> |
| | | 434 | | </button> |
| | | 435 | | <div id="supplierStatusDropdown" class="hpa-supplier-status-dropdown" hidden> |
| | | 436 | | <div class="hpa-supplier-status-search-wrap"> |
| | | 437 | | <i class="fas fa-search" aria-hidden="true"></i> |
| | | 438 | | <input type="search" id="supplierStatusDropdownSearch" class="form-control form-control-sm" |
| | | 439 | | placeholder="Поиск по статусу или поставщику" autocomplete="off"> |
| | | 440 | | </div> |
| | | 441 | | <div class="hpa-supplier-status-options"> |
| | | 442 | | <button type="button" class="hpa-supplier-status-option hpa-supplier-status-option--all" |
| | | 443 | | data-supplier-status-id="" data-supplier-status-label="Все статусы поставщиков"> |
| | | 444 | | <span>Все статусы поставщиков</span> |
| | | 445 | | </button> |
| | 0 | 446 | | @foreach (var supplierStatus in supplierStatuses) |
| | | 447 | | { |
| | 0 | 448 | | var providerName = GetSupplierProviderName(supplierStatus.ProviderKey); |
| | 0 | 449 | | var logoUrl = GetSupplierProviderLogoUrl(supplierStatus.ProviderKey); |
| | 0 | 450 | | var backgroundColor = supplierStatus.GetStatusColor(); |
| | 0 | 451 | | var foregroundColor = StatusColorContrast.GetTextColor(backgroundColor); |
| | 0 | 452 | | var stageName = supplierStatus.StatusKind == SupplierStatusKind.Cart ? "Корзина" : "Зака |
| | 0 | 453 | | var optionLabel = $"{providerName} · {supplierStatus.Name}"; |
| | | 454 | | |
| | | 455 | | <button type="button" class="hpa-supplier-status-option" |
| | 0 | 456 | | data-supplier-status-id="@supplierStatus.Id" |
| | 0 | 457 | | data-supplier-status-label="@optionLabel" |
| | 0 | 458 | | data-supplier-status-search="@($"{providerName} {supplierStatus.Name} {stageName}")" |
| | | 459 | | style="--supplier-status-bg:@backgroundColor; --supplier-status-fg:@foregroundColor; |
| | | 460 | | <span class="hpa-supplier-status-provider-logo" aria-hidden="true"> |
| | 0 | 461 | | @if (logoUrl is not null) |
| | | 462 | | { |
| | | 463 | | <img src="@logoUrl" alt=""/> |
| | | 464 | | } |
| | 0 | 465 | | @if (supplierStatus.ProviderKey == "ArmtekBy") |
| | | 466 | | { |
| | | 467 | | <b>BY</b> |
| | | 468 | | } |
| | | 469 | | </span> |
| | | 470 | | <span class="hpa-supplier-status-option-main"> |
| | 0 | 471 | | <span class="hpa-supplier-status-badge">@supplierStatus.Name</span> |
| | 0 | 472 | | <span class="hpa-supplier-status-meta">@providerName · @stageName</span> |
| | | 473 | | </span> |
| | | 474 | | </button> |
| | | 475 | | } |
| | | 476 | | </div> |
| | | 477 | | </div> |
| | | 478 | | </div> |
| | | 479 | | </li> |
| | | 480 | | <li><hr class="dropdown-divider my-2"></li> |
| | | 481 | | <li class="mb-2"> |
| | | 482 | | <label for="returnLogisticBarcodeFilter" class="hpa-search-label"> |
| | | 483 | | <i class="fas fa-barcode me-1 text-info"></i> Штрихкод возврата |
| | | 484 | | </label> |
| | | 485 | | <input type="text" class="form-control form-control-sm" id="returnLogisticBarcodeFilter" |
| | | 486 | | placeholder="Введите штрихкод..." autocomplete="off"> |
| | | 487 | | </li> |
| | | 488 | | <li class="mb-2"> |
| | | 489 | | <label for="deliveryNameDropdownFilter" class="hpa-search-label"> |
| | | 490 | | <i class="fas fa-shipping-fast me-1 text-secondary"></i> Тип доставки |
| | | 491 | | </label> |
| | | 492 | | <input type="text" class="form-control form-control-sm" id="deliveryNameDropdownFilter" |
| | | 493 | | placeholder="Тип доставки..." autocomplete="off"> |
| | | 494 | | </li> |
| | | 495 | | <li class="mb-2"> |
| | | 496 | | <label for="hasOzonPromotionFilter" class="hpa-search-label"> |
| | | 497 | | <i class="fas fa-tags me-1 text-warning"></i> Участие в акции |
| | | 498 | | </label> |
| | | 499 | | <select id="hasOzonPromotionFilter" class="form-select form-select-sm" |
| | | 500 | | aria-label="Участие товара в акции Ozon на момент загрузки"> |
| | | 501 | | <option value="" selected="@(Model.FilterModel.HasOzonPromotion == null ? "selected" : null)">Все то |
| | | 502 | | <option value="true" selected="@(Model.FilterModel.HasOzonPromotion == true ? "selected" : null)">В |
| | | 503 | | <option value="false" selected="@(Model.FilterModel.HasOzonPromotion == false ? "selected" : null)"> |
| | | 504 | | </select> |
| | | 505 | | </li> |
| | | 506 | | <li> |
| | | 507 | | <label for="trackingNumberDropdownFilter" class="hpa-search-label"> |
| | | 508 | | <i class="fas fa-hashtag me-1 text-secondary"></i> Трек-номер |
| | | 509 | | </label> |
| | | 510 | | <input type="text" class="form-control form-control-sm" id="trackingNumberDropdownFilter" |
| | | 511 | | placeholder="Трек-номер..." autocomplete="off"> |
| | | 512 | | </li> |
| | | 513 | | </ul> |
| | | 514 | | </div> |
| | | 515 | | |
| | | 516 | | <!-- Провести документ --> |
| | | 517 | | <div class="btn-group"> |
| | | 518 | | <button id="uniqueDropdownToggle" type="button" |
| | | 519 | | class="hpa-btn hpa-btn--conduct" aria-expanded="false" aria-haspopup="true"> |
| | | 520 | | <i class="fas fa-file-invoice"></i><span class="hpa-label">Провести</span> |
| | | 521 | | </button> |
| | | 522 | | <ul id="uniqueDropdownMenu" class="dropdown-menu dropdown-menu-start hpa-fixed-dropdown" aria-labelledby="unique |
| | | 523 | | </div> |
| | | 524 | | |
| | | 525 | | <!-- Действия --> |
| | | 526 | | <div class="btn-group" id="actions-nav-item"> |
| | | 527 | | <button id="headerActionsDropdown" type="button" class="hpa-btn" aria-expanded="false" aria-haspopup="true"> |
| | | 528 | | <i class="fas fa-bolt"></i><span class="hpa-label">Действия</span> |
| | | 529 | | </button> |
| | | 530 | | <ul id="headerActionsDropdownMenu" class="dropdown-menu dropdown-menu-start hpa-fixed-dropdown" style="display:n |
| | | 531 | | <div class="file-action-btn-wrapper" style="display: block;"> |
| | | 532 | | <li><a href="#" onclick="showPrintExcelModal(); return false;" |
| | | 533 | | class="dropdown-item excel-export-btn" data-endpoint="/Studio2/Orders/PrintOrdersExcelV2"> |
| | | 534 | | <i class="fas fa-file-excel text-success me-2"></i>Экспорт в Excel |
| | | 535 | | </a></li> |
| | | 536 | | </div> |
| | | 537 | | <div class="file-action-btn-wrapper" style="display: block;"> |
| | | 538 | | <li><a href="/Studio2/Percentage/UploadFile" class="dropdown-item file-upload-btn" |
| | | 539 | | data-endpoint="/Studio2/Percentage/UploadFile"> |
| | | 540 | | <i class="fas fa-file-import text-secondary me-2"></i>Загрузить данные из файла |
| | | 541 | | </a></li> |
| | | 542 | | </div> |
| | | 543 | | <div class="file-action-btn-wrapper" style="display: block;"> |
| | | 544 | | <li><a href="/Studio2/Orders/UploadFile" class="dropdown-item file-upload-btn" |
| | | 545 | | data-endpoint="/Studio2/Orders/UploadFile"> |
| | | 546 | | <i class="fas fa-file-upload text-primary me-2"></i>Загрузить заказы из файла |
| | | 547 | | </a></li> |
| | | 548 | | </div> |
| | | 549 | | <div class="file-action-btn-wrapper" style="display: block;"> |
| | | 550 | | <li><a href="/Studio2/Orders/Create" class="dropdown-item create-order-btn" |
| | | 551 | | data-endpoint="/Studio2/Orders/Create" data-requires-admin="true"> |
| | | 552 | | <i class="fas fa-plus-circle text-success me-2"></i>Создать заказ |
| | | 553 | | </a></li> |
| | | 554 | | </div> |
| | | 555 | | <div class="file-action-btn-wrapper" style="display: block;"> |
| | | 556 | | <li><a href="/Studio2/AssemblyList" class="dropdown-item"> |
| | | 557 | | <i class="fas fa-list-alt text-primary me-2"></i>Лист подбора |
| | | 558 | | </a></li> |
| | | 559 | | </div> |
| | | 560 | | </ul> |
| | | 561 | | </div> |
| | | 562 | | </div> |
| | | 563 | | } |