| | | 1 | | @using OzonDomains.Models.AccessControl |
| | | 2 | | @model DataScopeSet |
| | | 3 | | |
| | | 4 | | @{ |
| | 0 | 5 | | ViewData["Title"] = Model.Name; |
| | 0 | 6 | | Layout = "_AdminLayout"; |
| | 0 | 7 | | ViewData["Breadcrumb"] = new List<(string, string?)> |
| | 0 | 8 | | { |
| | 0 | 9 | | ("Администрирование", null), |
| | 0 | 10 | | ("Наборы ограничений", Url.Action("Index", "DataScopeSets", new { area = "Studio2" })), |
| | 0 | 11 | | (Model.Name, null) |
| | 0 | 12 | | }; |
| | | 13 | | |
| | 0 | 14 | | var appStatuses = ViewBag.AppStatuses as List<OzonDomains.Models.AppStatus> ?? new(); |
| | 0 | 15 | | var suppliers = ViewBag.Suppliers as List<OzonDomains.Models.Supplier> ?? new(); |
| | 0 | 16 | | var ozonClients = ViewBag.OzonClients as List<OzonDomains.Models.OzonClient> ?? new(); |
| | 0 | 17 | | var warehouses = ViewBag.Warehouses as List<OzonDomains.Models.Warehouse> ?? new(); |
| | 0 | 18 | | var deliveries = ViewBag.DeliveryProviders as List<OzonDomains.Models.DeliveryProvider> ?? new(); |
| | | 19 | | |
| | 0 | 20 | | string GetName(DataScopeSetItem item) => item.ScopeType switch |
| | 0 | 21 | | { |
| | 0 | 22 | | DataScopeType.AppStatus => appStatuses.FirstOrDefault(x => x.Id == item.ReferenceId)?.Name ?? $"ID {item. |
| | 0 | 23 | | DataScopeType.Supplier => suppliers.FirstOrDefault(x => x.Id == item.ReferenceId)?.Name ?? $"ID {item |
| | 0 | 24 | | DataScopeType.OzonClient => ozonClients.FirstOrDefault(x => x.Id == item.ReferenceId)?.Name ?? $"ID {item |
| | 0 | 25 | | DataScopeType.Warehouse => warehouses.FirstOrDefault(x => x.Id == item.ReferenceId)?.Name ?? $"ID {item |
| | 0 | 26 | | DataScopeType.DeliveryProvider => deliveries.FirstOrDefault(x => x.Id == item.ReferenceId)?.Name ?? $"ID {item |
| | 0 | 27 | | _ => $"ID {item.ReferenceId}" |
| | 0 | 28 | | }; |
| | 0 | 29 | | string GetTypeLabel(DataScopeType t) => t switch |
| | 0 | 30 | | { |
| | 0 | 31 | | DataScopeType.AppStatus => "Статус", |
| | 0 | 32 | | DataScopeType.Supplier => "Поставщик", |
| | 0 | 33 | | DataScopeType.OzonClient => "Клиент Ozon", |
| | 0 | 34 | | DataScopeType.Warehouse => "Склад", |
| | 0 | 35 | | DataScopeType.DeliveryProvider => "Служба доставки", |
| | 0 | 36 | | _ => t.ToString() |
| | 0 | 37 | | }; |
| | 0 | 38 | | string GetTypeBadge(DataScopeType t) => t switch |
| | 0 | 39 | | { |
| | 0 | 40 | | DataScopeType.AppStatus => "bg-purple-lt", |
| | 0 | 41 | | DataScopeType.Supplier => "bg-blue-lt", |
| | 0 | 42 | | DataScopeType.OzonClient => "bg-orange-lt", |
| | 0 | 43 | | DataScopeType.Warehouse => "bg-teal-lt", |
| | 0 | 44 | | DataScopeType.DeliveryProvider => "bg-pink-lt", |
| | 0 | 45 | | _ => "bg-secondary-lt" |
| | 0 | 46 | | }; |
| | | 47 | | } |
| | | 48 | | |
| | | 49 | | @section PageActions { |
| | 0 | 50 | | <a asp-action="Edit" asp-route-id="@Model.Id" class="btn btn-outline-secondary me-2"> |
| | | 51 | | <i class="ti ti-edit me-1"></i>Изменить название |
| | | 52 | | </a> |
| | | 53 | | } |
| | | 54 | | |
| | | 55 | | <div class="row"> |
| | | 56 | | <!-- Info card --> |
| | | 57 | | <div class="col-md-4 mb-3"> |
| | | 58 | | <div class="card h-100"> |
| | | 59 | | <div class="card-body"> |
| | 0 | 60 | | <h4 class="mb-1">@Model.Name</h4> |
| | 0 | 61 | | @if (!string.IsNullOrEmpty(Model.Description)) |
| | | 62 | | { |
| | 0 | 63 | | <p class="text-muted">@Model.Description</p> |
| | | 64 | | } |
| | | 65 | | <div class="datagrid mt-3"> |
| | | 66 | | <div class="datagrid-item"> |
| | | 67 | | <div class="datagrid-title">Создан</div> |
| | 0 | 68 | | <div class="datagrid-content">@Model.CreatedAt.ToLocalTime().ToString("dd.MM.yyyy")</div> |
| | | 69 | | </div> |
| | | 70 | | <div class="datagrid-item"> |
| | | 71 | | <div class="datagrid-title">Ограничений</div> |
| | | 72 | | <div class="datagrid-content"> |
| | | 73 | | <span class="badge @(Model.Items.Any() ? "bg-orange" : "bg-green")"> |
| | 0 | 74 | | @(Model.Items.Any() ? Model.Items.Count : "нет") |
| | | 75 | | </span> |
| | | 76 | | </div> |
| | | 77 | | </div> |
| | | 78 | | <div class="datagrid-item"> |
| | | 79 | | <div class="datagrid-title">Используется в профилях</div> |
| | | 80 | | <div class="datagrid-content"> |
| | 0 | 81 | | @if (Model.AccessProfiles.Any()) |
| | | 82 | | { |
| | 0 | 83 | | @foreach (var p in Model.AccessProfiles) |
| | | 84 | | { |
| | 0 | 85 | | <span class="badge bg-blue-lt me-1">@p.Name</span> |
| | | 86 | | } |
| | | 87 | | } |
| | | 88 | | else |
| | | 89 | | { |
| | | 90 | | <span class="text-muted">нигде</span> |
| | | 91 | | } |
| | | 92 | | </div> |
| | | 93 | | </div> |
| | | 94 | | </div> |
| | | 95 | | |
| | 0 | 96 | | @if (!Model.Items.Any()) |
| | | 97 | | { |
| | | 98 | | <div class="alert alert-success mt-3"> |
| | | 99 | | <i class="ti ti-check me-2"></i> |
| | | 100 | | Набор пуст — ограничений нет, пользователи видят <strong>все данные</strong>. |
| | | 101 | | </div> |
| | | 102 | | } |
| | | 103 | | </div> |
| | | 104 | | </div> |
| | | 105 | | </div> |
| | | 106 | | |
| | | 107 | | <!-- Items management --> |
| | | 108 | | <div class="col-md-8 mb-3"> |
| | | 109 | | <!-- Add item --> |
| | | 110 | | <div class="card mb-3"> |
| | | 111 | | <div class="card-header"> |
| | | 112 | | <h3 class="card-title"><i class="ti ti-plus me-2"></i>Добавить ограничение</h3> |
| | | 113 | | </div> |
| | | 114 | | <div class="card-body"> |
| | | 115 | | <form asp-action="AddItem" method="post" class="row g-3 align-items-end"> |
| | | 116 | | <input type="hidden" name="setId" value="@Model.Id"/> |
| | | 117 | | <div class="col-md-5"> |
| | | 118 | | <label class="form-label">Тип</label> |
| | | 119 | | <select name="scopeType" id="scopeTypeSelect" class="form-select" onchange="updateRefList(this.v |
| | 0 | 120 | | <option value="@((int)DataScopeType.AppStatus)">Статус</option> |
| | 0 | 121 | | <option value="@((int)DataScopeType.Supplier)">Поставщик</option> |
| | 0 | 122 | | <option value="@((int)DataScopeType.OzonClient)">Клиент Ozon</option> |
| | 0 | 123 | | <option value="@((int)DataScopeType.Warehouse)">Склад</option> |
| | 0 | 124 | | <option value="@((int)DataScopeType.DeliveryProvider)">Служба доставки</option> |
| | | 125 | | </select> |
| | | 126 | | </div> |
| | | 127 | | <div class="col-md-5"> |
| | | 128 | | <label class="form-label">Значение</label> |
| | | 129 | | <select name="referenceId" id="refSelect" class="form-select"> |
| | | 130 | | <option value="">— выберите —</option> |
| | | 131 | | </select> |
| | | 132 | | </div> |
| | | 133 | | <div class="col-md-2"> |
| | | 134 | | <button type="submit" class="btn btn-primary w-100"> |
| | | 135 | | <i class="ti ti-plus"></i> |
| | | 136 | | </button> |
| | | 137 | | </div> |
| | | 138 | | </form> |
| | | 139 | | </div> |
| | | 140 | | </div> |
| | | 141 | | |
| | | 142 | | <!-- Existing items --> |
| | | 143 | | <div class="card"> |
| | | 144 | | <div class="card-header"> |
| | | 145 | | <h3 class="card-title"><i class="ti ti-filter me-2"></i>Текущие ограничения</h3> |
| | | 146 | | </div> |
| | 0 | 147 | | @if (!Model.Items.Any()) |
| | | 148 | | { |
| | | 149 | | <div class="card-body text-muted text-center py-4"> |
| | | 150 | | <i class="ti ti-inbox mb-2" style="font-size:2rem"></i> |
| | | 151 | | <p>Ограничений нет. Добавьте выше.</p> |
| | | 152 | | </div> |
| | | 153 | | } |
| | | 154 | | else |
| | | 155 | | { |
| | | 156 | | <div class="table-responsive"> |
| | | 157 | | <table class="table table-vcenter card-table"> |
| | | 158 | | <thead> |
| | | 159 | | <tr> |
| | | 160 | | <th>Тип</th> |
| | | 161 | | <th>Значение</th> |
| | | 162 | | <th style="width:60px"></th> |
| | | 163 | | </tr> |
| | | 164 | | </thead> |
| | | 165 | | <tbody> |
| | 0 | 166 | | @foreach (var item in Model.Items.OrderBy(i => i.ScopeType).ThenBy(i => i.ReferenceId)) |
| | | 167 | | { |
| | | 168 | | <tr> |
| | | 169 | | <td> |
| | 0 | 170 | | <span class="badge @GetTypeBadge(item.ScopeType)">@GetTypeLabel(item.ScopeType)</spa |
| | | 171 | | </td> |
| | 0 | 172 | | <td class="fw-semibold">@GetName(item)</td> |
| | | 173 | | <td> |
| | | 174 | | <form asp-action="RemoveItem" method="post"> |
| | | 175 | | <input type="hidden" name="itemId" value="@item.Id"/> |
| | | 176 | | <input type="hidden" name="setId" value="@Model.Id"/> |
| | | 177 | | <button type="submit" class="btn btn-sm btn-ghost-danger" |
| | | 178 | | title="Удалить ограничение" |
| | | 179 | | data-st2-confirm="Удалить это ограничение?" data-st2-confirm-variant="da |
| | | 180 | | <i class="ti ti-trash"></i> |
| | | 181 | | </button> |
| | | 182 | | </form> |
| | | 183 | | </td> |
| | | 184 | | </tr> |
| | | 185 | | } |
| | | 186 | | </tbody> |
| | | 187 | | </table> |
| | | 188 | | </div> |
| | | 189 | | } |
| | | 190 | | </div> |
| | | 191 | | </div> |
| | | 192 | | </div> |
| | | 193 | | |
| | | 194 | | @section Scripts { |
| | | 195 | | <script> |
| | | 196 | | const refs = { |
| | 0 | 197 | | "@((int)DataScopeType.AppStatus)": [ |
| | 0 | 198 | | @Html.Raw(string.Join(",", appStatuses.Select(x => $"{{id:{x.Id},name:{System.Text.Json.JsonSerializer.Serialize |
| | | 199 | | ], |
| | 0 | 200 | | "@((int)DataScopeType.Supplier)": [ |
| | 0 | 201 | | @Html.Raw(string.Join(",", suppliers.Select(x => $"{{id:{x.Id},name:{System.Text.Json.JsonSerializer.Serialize(x |
| | | 202 | | ], |
| | 0 | 203 | | "@((int)DataScopeType.OzonClient)": [ |
| | 0 | 204 | | @Html.Raw(string.Join(",", ozonClients.Select(x => $"{{id:{x.Id},name:{System.Text.Json.JsonSerializer.Serialize |
| | | 205 | | ], |
| | 0 | 206 | | "@((int)DataScopeType.Warehouse)": [ |
| | 0 | 207 | | @Html.Raw(string.Join(",", warehouses.Select(x => $"{{id:{x.Id},name:{System.Text.Json.JsonSerializer.Serialize( |
| | | 208 | | ], |
| | 0 | 209 | | "@((int)DataScopeType.DeliveryProvider)": [ |
| | 0 | 210 | | @Html.Raw(string.Join(",", deliveries.Select(x => $"{{id:{x.Id},name:{System.Text.Json.JsonSerializer.Serialize( |
| | | 211 | | ] |
| | | 212 | | }; |
| | | 213 | | |
| | | 214 | | function updateRefList(type) { |
| | | 215 | | const sel = document.getElementById('refSelect'); |
| | | 216 | | sel.innerHTML = '<option value="">— выберите —</option>'; |
| | | 217 | | (refs[type] || []).forEach(r => { |
| | | 218 | | const opt = document.createElement('option'); |
| | | 219 | | opt.value = r.id; |
| | | 220 | | opt.textContent = r.name || `ID ${r.id}`; |
| | | 221 | | sel.appendChild(opt); |
| | | 222 | | }); |
| | | 223 | | } |
| | | 224 | | // init on load |
| | | 225 | | updateRefList(document.getElementById('scopeTypeSelect').value); |
| | | 226 | | </script> |
| | | 227 | | } |