| | | 1 | | @page |
| | | 2 | | @model LoginModel |
| | | 3 | | |
| | | 4 | | @{ |
| | 0 | 5 | | ViewData["Title"] = "Войти"; |
| | 0 | 6 | | Layout = null; |
| | | 7 | | } |
| | | 8 | | |
| | | 9 | | <!DOCTYPE html> |
| | | 10 | | <html lang="ru"> |
| | | 11 | | <head> |
| | | 12 | | <meta charset="utf-8"/> |
| | | 13 | | <meta name="viewport" content="width=device-width, initial-scale=1.0"/> |
| | 0 | 14 | | <title>@ViewData["Title"] — Studio2</title> |
| | | 15 | | <link rel="icon" type="image/svg+xml" href="~/favicon.svg" asp-append-version="true"/> |
| | | 16 | | <link rel="apple-touch-icon" href="~/favicon.svg" asp-append-version="true"/> |
| | | 17 | | <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css"/> |
| | | 18 | | <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.css"/> |
| | | 19 | | <link rel="stylesheet" href="~/css/design-tokens.css" asp-append-version="true"/> |
| | | 20 | | <link rel="stylesheet" href="~/css/base.css" asp-append-version="true"/> |
| | | 21 | | <link rel="stylesheet" href="~/css/auth.css" asp-append-version="true"/> |
| | | 22 | | <link rel="stylesheet" href="~/css/system-notification-modal.css" asp-append-version="true"/> |
| | | 23 | | <link rel="stylesheet" href="~/css/server-availability.css" asp-append-version="true"/> |
| | | 24 | | @* Страница входа — Layout = null, поэтому наблюдатель доступности подключается отдельно: |
| | | 25 | | во время деплоя форма входа так же «молча» не отправляется. *@ |
| | | 26 | | <meta name="studio2-instance" content="@OzonOrdersWeb.Observability.AppInstanceInfo.InstanceId"/> |
| | | 27 | | <script src="~/js/layout/server-availability.js" asp-append-version="true"></script> |
| | | 28 | | </head> |
| | | 29 | | <body class="auth-page"> |
| | | 30 | | <div class="auth-layout"> |
| | | 31 | | <aside class="auth-aside" aria-hidden="true"> |
| | | 32 | | <div class="auth-aside-inner"> |
| | | 33 | | <a class="auth-logo" href="/"> |
| | | 34 | | <span class="auth-logo-icon" aria-hidden="true"> |
| | | 35 | | <img class="auth-logo-image" src="~/images/branding/studio2-auth-icon-v1.png" asp-append-version="tr |
| | | 36 | | </span> |
| | | 37 | | <span class="auth-logo-text">Studio2</span> |
| | | 38 | | </a> |
| | | 39 | | <h1 class="auth-aside-title">Управление заказами и складом</h1> |
| | | 40 | | <p class="auth-aside-lead"> |
| | | 41 | | Единая платформа для обработки заказов, транзакций, остатков и интеграций с Ozon, 1С и Bitrix. |
| | | 42 | | </p> |
| | | 43 | | <ul class="auth-aside-features"> |
| | | 44 | | <li><i class="bi bi-box-seam"></i> Заказы и транзакции в одном интерфейсе</li> |
| | | 45 | | <li><i class="bi bi-arrow-left-right"></i> Синхронизация со складами и маркетплейсами</li> |
| | | 46 | | <li><i class="bi bi-shield-check"></i> Разграничение доступа по ролям</li> |
| | | 47 | | </ul> |
| | | 48 | | </div> |
| | | 49 | | </aside> |
| | | 50 | | |
| | | 51 | | <section class="auth-panel"> |
| | | 52 | | <div class="auth-form-wrap"> |
| | | 53 | | <div class="auth-mobile-brand"> |
| | | 54 | | <span class="auth-logo-icon" aria-hidden="true"> |
| | | 55 | | <img class="auth-logo-image" src="~/images/branding/studio2-auth-icon-v1.png" asp-append-version="tr |
| | | 56 | | </span> |
| | | 57 | | <span class="auth-logo-text">Studio2</span> |
| | | 58 | | </div> |
| | | 59 | | |
| | | 60 | | <div class="auth-card"> |
| | 0 | 61 | | <h2 class="auth-card-title">@ViewData["Title"]</h2> |
| | | 62 | | <p class="auth-card-subtitle">Используйте учётную запись для входа в систему</p> |
| | | 63 | | |
| | | 64 | | <form id="account" method="post"> |
| | 0 | 65 | | @if (!ViewData.ModelState.IsValid) |
| | | 66 | | { |
| | | 67 | | <div asp-validation-summary="All" class="alert alert-danger auth-alert" role="alert"></div> |
| | | 68 | | } |
| | | 69 | | |
| | | 70 | | <div class="auth-field"> |
| | | 71 | | <label asp-for="Input.Username">Логин или Email</label> |
| | | 72 | | <div class="auth-input-wrap"> |
| | | 73 | | <i class="bi bi-person" aria-hidden="true"></i> |
| | | 74 | | <input asp-for="Input.Username" class="form-control" |
| | | 75 | | autocomplete="username" aria-required="true" |
| | | 76 | | placeholder="Введите логин или email"/> |
| | | 77 | | </div> |
| | | 78 | | <span asp-validation-for="Input.Username" class="text-danger"></span> |
| | | 79 | | </div> |
| | | 80 | | |
| | | 81 | | <div class="auth-field"> |
| | | 82 | | <label asp-for="Input.Password">Пароль</label> |
| | | 83 | | <div class="auth-input-wrap"> |
| | | 84 | | <i class="bi bi-lock" aria-hidden="true"></i> |
| | | 85 | | <input asp-for="Input.Password" class="form-control" |
| | | 86 | | autocomplete="current-password" aria-required="true" |
| | | 87 | | placeholder="Введите пароль"/> |
| | | 88 | | </div> |
| | | 89 | | <span asp-validation-for="Input.Password" class="text-danger"></span> |
| | | 90 | | </div> |
| | | 91 | | |
| | | 92 | | <div class="form-check auth-remember"> |
| | | 93 | | <input class="form-check-input" asp-for="Input.RememberMe"/> |
| | | 94 | | <label class="form-check-label" asp-for="Input.RememberMe"> |
| | | 95 | | Запомнить меня |
| | | 96 | | </label> |
| | | 97 | | </div> |
| | | 98 | | |
| | | 99 | | <button id="login-submit" type="submit" class="btn btn-primary auth-submit"> |
| | | 100 | | <i class="bi bi-box-arrow-in-right" aria-hidden="true"></i> |
| | | 101 | | Войти |
| | | 102 | | </button> |
| | | 103 | | </form> |
| | | 104 | | |
| | | 105 | | <div class="text-center my-3 text-muted small">или</div> |
| | 0 | 106 | | <form id="external-account" asp-page="./ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" method="po |
| | | 107 | | <button type="submit" class="btn btn-outline-dark auth-submit" name="provider" value="Google"> |
| | | 108 | | <i class="bi bi-google" aria-hidden="true"></i> |
| | | 109 | | Войти через Google |
| | | 110 | | </button> |
| | | 111 | | </form> |
| | | 112 | | |
| | | 113 | | <p class="auth-footer">Interparts · Studio2</p> |
| | | 114 | | </div> |
| | | 115 | | </div> |
| | | 116 | | </section> |
| | | 117 | | </div> |
| | | 118 | | <script> |
| | | 119 | | (function () { |
| | | 120 | | var pageLoadedAt = Date.now(); |
| | | 121 | | var STALE_PAGE_MS = 60 * 60 * 1000; // 1 час |
| | | 122 | | |
| | | 123 | | // Регрессия #1218: если страница входа оставалась открытой в фоновой вкладке более часа |
| | | 124 | | // (или сервис был перезапущен/обновлён), токен CSRF устаревает. При возвращении на вкладку |
| | | 125 | | // мягко обновляем страницу для получения свежего токена, если пароль ещё не введён. |
| | | 126 | | document.addEventListener('visibilitychange', function () { |
| | | 127 | | if (!document.hidden && Date.now() - pageLoadedAt > STALE_PAGE_MS) { |
| | | 128 | | var passwordInput = document.getElementById('Input_Password'); |
| | | 129 | | if (!passwordInput || !passwordInput.value) { |
| | | 130 | | window.location.reload(); |
| | | 131 | | } |
| | | 132 | | } |
| | | 133 | | }); |
| | | 134 | | })(); |
| | | 135 | | </script> |
| | | 136 | | </body> |
| | | 137 | | </html> |