< Summary

Information
Class: AspNetCoreGeneratedDocument.Areas_Studio2_Views_Orders_UploadFile
Assembly: OzonOrdersWeb
File(s): /home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Areas/Studio2/Views/Orders/UploadFile.cshtml
Line coverage
0%
Covered lines: 0
Uncovered lines: 8
Coverable lines: 8
Total lines: 294
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 32
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%1056320%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Areas/Studio2/Views/Orders/UploadFile.cshtml

#LineLine coverage
 1@{
 02    ViewData["Title"] = "Загрузка файла заказов";
 03    string erorrResult = ViewData["ErorrResult"] as string ?? "";
 4}
 5
 6<link rel="stylesheet" href="~/css/Studio2/Orders/orders-upload-shared.css" asp-append-version="true"/>
 7<link rel="stylesheet" href="~/css/Studio2/Orders/orders-upload.css" asp-append-version="true"/>
 8<link rel="stylesheet" href="~/css/Studio2/Orders/orders-upload-file.css" asp-append-version="true"/>
 9<link rel="stylesheet" href="~/css/Studio2/Orders/orders-upload-redesign.css" asp-append-version="true"/>
 10
 11<div class="container py-3 ou-page">
 12    <div class="ou-hero app-section-hero app-section-hero--import">
 13        <h1><i class="fas fa-file-excel me-2 text-primary"></i>Загрузка файла заказов</h1>
 14        <div class="subtitle">Импорт заказов из Excel или CSV (без API)</div>
 15        <div class="subtitle-help">
 16            Упрощённый вход с главной страницы заказов: только файл поставщика или выгрузки.
 17            Копия сохраняется в Dropbox, строки разбираются по заголовкам и создают/обновляют заказы.
 18            Для загрузки через API Ozon/Yandex используйте <a asp-action="Upload">полную страницу загрузки</a>.
 19        </div>
 20        <div class="ou-quick-links app-section-hero__quick-links">
 21            <a asp-action="Index"><i class="fas fa-list"></i>Список заказов</a>
 22            <a asp-action="Upload"><i class="fas fa-cloud-download-alt"></i>API + файл</a>
 23            <a asp-area="Studio2" asp-controller="Percentage" asp-action="UploadFile"><i class="fas fa-percent"></i>Проц
 24        </div>
 25    </div>
 26
 27    <div class="ou-intro">
 28        <i class="fas fa-circle-info"></i>
 29        <div class="ou-intro-text">
 30            После выбора файла появятся настройки CSV (разделитель) и смещение строки/столбца заголовков.
 31            Предпросмотр показывает до 10 строк — убедитесь, что колонки читаются корректно, затем нажмите «Загрузить».
 32        </div>
 33    </div>
 34
 35    <div class="ou-workflow">
 36        <div class="ou-workflow-step"><span class="num">1</span>Выберите файл</div>
 37        <div class="ou-workflow-step"><span class="num">2</span>Проверьте предпросмотр</div>
 38        <div class="ou-workflow-step"><span class="num">3</span>Загрузите на сервер</div>
 39        <div class="ou-workflow-step"><span class="num">4</span>Заказы в списке</div>
 40    </div>
 41
 42    <div class="ou-card">
 43        <div class="ou-card-body">
 044            @if (!string.IsNullOrEmpty(erorrResult))
 45            {
 46                <div class="alert alert-dismissible alert-danger mb-3">
 47                    <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Закрыть"></button>
 48                    <img src="~/images/status/upload-error.svg" asp-append-version="true" alt="" width="28" height="28" 
 049                    <p class="mb-0 small">@Html.Raw(erorrResult)</p>
 50                </div>
 51            }
 52
 053            @if (!string.IsNullOrEmpty(ViewBag.Message as string))
 54            {
 55                <div class="alert alert-info alert-dismissible mb-3">
 56                    <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Закрыть"></button>
 057                    <img src="~/images/status/info.svg" asp-append-version="true" alt="" width="24" height="24" class="m
 58                </div>
 59            }
 60
 61            <div class="ou-file-section">
 062                @using (Html.BeginForm("UploadExcelFile", "Orders", FormMethod.Post, new { enctype = "multipart/form-dat
 63                {
 64                    <div class="ou-drop-zone" id="dropZone">
 65                        <input type="file" id="fileInput" name="file" accept=".xlsx,.xls,.csv" required>
 66                        <i class="fas fa-cloud-upload-alt ou-drop-zone-icon"></i>
 67                        <div class="ou-drop-zone-text" id="dropZoneText">Перетащите файл или нажмите для выбора</div>
 68                        <div class="ou-drop-zone-hint">.xlsx · .xls · .csv</div>
 69                        <div class="invalid-feedback d-block mt-2">Выберите файл для загрузки</div>
 70                    </div>
 71
 72                    <div id="delimiterInput" style="display: none;" class="ou-input-row">
 73                        <div>
 74                            <label for="delimiter" class="ou-form-label">Разделитель CSV</label>
 75                            <input type="text" class="form-control form-control-sm" id="delimiter" name="delimiter" valu
 76                            <div class="ou-field-hint">По умолчанию точка с запятой</div>
 77                        </div>
 78                    </div>
 79
 80                    <div id="startInputs" style="display: none;" class="ou-input-row">
 81                        <div>
 82                            <label for="startRowInput" class="ou-form-label">Начальная строка</label>
 83                            <input type="number" class="form-control form-control-sm" id="startRowInput" name="startRow"
 84                                   value="1" min="1" onchange="updatePreviewIfFileSelected()">
 85                            <div class="ou-field-hint">Номер строки с заголовками</div>
 86                        </div>
 87                        <div>
 88                            <label for="startColumnInput" class="ou-form-label">Начальный столбец</label>
 89                            <input type="number" class="form-control form-control-sm" id="startColumnInput" name="startC
 90                                   value="1" min="1" onchange="updatePreviewIfFileSelected()">
 91                        </div>
 92                    </div>
 93
 94                    <button type="submit" class="btn btn-primary btn-sm" id="submitBtn" disabled>
 95                        <i class="fas fa-upload me-1"></i>Загрузить файл
 96                    </button>
 097                }
 98
 99                <div id="filePreview" style="display: none;">
 100                    <div class="small fw-semibold text-secondary mt-3 mb-2">
 101                        <i class="fas fa-eye me-1"></i>Предпросмотр
 102                    </div>
 103                    <div class="ou-preview-wrap">
 104                        <table class="table table-sm table-bordered table-striped mb-0" id="previewTable">
 105                            <thead id="previewTableHead" style="position: sticky; top: 0; background: #f8f9fa; z-index: 
 106                            <tbody id="previewTableBody"></tbody>
 107                        </table>
 108                    </div>
 109                    <div class="ou-preview-info" id="previewInfo"></div>
 110                </div>
 111            </div>
 112
 113            <div class="ou-requirements">
 114                <h6>Требования</h6>
 115                <ul class="mb-0 ps-3">
 116                    <li>Форматы: <code>.xlsx</code>, <code>.xls</code>, <code>.csv</code> (UTF-8)</li>
 117                    <li>Заголовки — в указанной строке; данные ниже</li>
 118                    <li>Исходник архивируется в Dropbox <code>/ExcelFiles/дата</code></li>
 119                </ul>
 120            </div>
 121        </div>
 122    </div>
 123</div>
 124
 125<script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script>
 126
 127<script>
 128    document.addEventListener('DOMContentLoaded', function () {
 129        const fileInput = document.getElementById('fileInput');
 130        const dropZone = document.getElementById('dropZone');
 131        const dropZoneText = document.getElementById('dropZoneText');
 132        const startInputs = document.getElementById('startInputs');
 133        const delimiterInput = document.getElementById('delimiterInput');
 134        const submitBtn = document.getElementById('submitBtn');
 135
 136        if (!fileInput || !dropZone) return;
 137
 138        ['dragenter', 'dragover'].forEach(evt => {
 139            dropZone.addEventListener(evt, function (e) {
 140                e.preventDefault();
 141                dropZone.classList.add('drag-over');
 142            });
 143        });
 144        ['dragleave', 'drop'].forEach(evt => {
 145            dropZone.addEventListener(evt, function (e) {
 146                e.preventDefault();
 147                dropZone.classList.remove('drag-over');
 148            });
 149        });
 150        dropZone.addEventListener('drop', function (e) {
 151            const file = e.dataTransfer.files[0];
 152            if (file) {
 153                const dt = new DataTransfer();
 154                dt.items.add(file);
 155                fileInput.files = dt.files;
 156                handleFileSelected(file);
 157            }
 158        });
 159
 160        fileInput.addEventListener('change', function () {
 161            if (this.files[0]) {
 162                handleFileSelected(this.files[0]);
 163            } else {
 164                resetFileState();
 165            }
 166        });
 167
 168        function handleFileSelected(file) {
 169            const extension = file.name.split('.').pop().toLowerCase();
 170            dropZoneText.textContent = file.name;
 171            dropZone.classList.add('has-file');
 172            startInputs.style.display = 'grid';
 173            delimiterInput.style.display = extension === 'csv' ? 'grid' : 'none';
 174            submitBtn.disabled = false;
 175            previewFile(file, extension);
 176        }
 177
 178        function resetFileState() {
 179            dropZoneText.textContent = 'Перетащите файл или нажмите для выбора';
 180            dropZone.classList.remove('has-file');
 181            startInputs.style.display = 'none';
 182            delimiterInput.style.display = 'none';
 183            submitBtn.disabled = true;
 184            hidePreview();
 185        }
 186
 187        function previewFile(file, extension) {
 188            const previewDiv = document.getElementById('filePreview');
 189            const previewTableHead = document.getElementById('previewTableHead');
 190            const previewTableBody = document.getElementById('previewTableBody');
 191            const previewInfo = document.getElementById('previewInfo');
 192            const startRow = parseInt(document.getElementById('startRowInput')?.value || 1);
 193            const startColumn = parseInt(document.getElementById('startColumnInput')?.value || 1);
 194
 195            previewDiv.style.display = 'block';
 196            previewTableHead.innerHTML = '';
 197            previewTableBody.innerHTML = '';
 198            previewInfo.textContent = 'Загрузка...';
 199
 200            const reader = new FileReader();
 201
 202            reader.onload = function (e) {
 203                try {
 204                    let data = [];
 205                    let headers = [];
 206
 207                    if (extension === 'csv') {
 208                        const delimiter = document.getElementById('delimiter')?.value || ';';
 209                        const lines = e.target.result.split('\n').filter(line => line.trim());
 210                        if (lines.length > 0) {
 211                            headers = lines[0].split(delimiter).map(h => h.trim().replace(/"/g, ''));
 212                            for (let i = Math.max(1, startRow); i < Math.min(lines.length, startRow + 10); i++) {
 213                                data.push(lines[i].split(delimiter).map(v => v.trim().replace(/"/g, '')));
 214                            }
 215                        }
 216                    } else {
 217                        const workbook = XLSX.read(e.target.result, { type: 'binary' });
 218                        const worksheet = workbook.Sheets[workbook.SheetNames[0]];
 219                        const jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1, defval: '' });
 220                        if (jsonData.length > 0) {
 221                            const headerRowIndex = Math.max(0, startRow - 1);
 222                            if (jsonData[headerRowIndex]) {
 223                                headers = jsonData[headerRowIndex].slice(startColumn - 1);
 224                            }
 225                            for (let i = Math.max(startRow, headerRowIndex + 1); i < Math.min(jsonData.length, startRow 
 226                                if (jsonData[i]) {
 227                                    data.push(jsonData[i].slice(startColumn - 1));
 228                                }
 229                            }
 230                        }
 231                    }
 232
 233                    if (headers.length > 0) {
 234                        const headerRow = document.createElement('tr');
 235                        headers.forEach(header => {
 236                            const th = document.createElement('th');
 237                            th.textContent = header || '';
 238                            headerRow.appendChild(th);
 239                        });
 240                        previewTableHead.appendChild(headerRow);
 241                    }
 242
 243                    data.forEach(row => {
 244                        const tr = document.createElement('tr');
 245                        headers.forEach((_, index) => {
 246                            const td = document.createElement('td');
 247                            td.textContent = row[index] || '';
 248                            tr.appendChild(td);
 249                        });
 250                        previewTableBody.appendChild(tr);
 251                    });
 252
 253                    previewInfo.textContent = `Показано ${data.length} строк из «${file.name}». Предпросмотр ограничен 1
 254                } catch (error) {
 255                    previewInfo.textContent = 'Ошибка при чтении файла: ' + error.message;
 256                }
 257            };
 258
 259            reader.onerror = function () {
 260                previewInfo.textContent = 'Ошибка при чтении файла';
 261            };
 262
 263            extension === 'csv' ? reader.readAsText(file, 'UTF-8') : reader.readAsBinaryString(file);
 264        }
 265
 266        function hidePreview() {
 267            const previewDiv = document.getElementById('filePreview');
 268            if (previewDiv) previewDiv.style.display = 'none';
 269        }
 270
 271        window.updatePreviewIfFileSelected = function () {
 272            if (fileInput.files && fileInput.files[0]) {
 273                const extension = fileInput.files[0].name.split('.').pop().toLowerCase();
 274                previewFile(fileInput.files[0], extension);
 275            }
 276        };
 277
 278        const fileUploadForm = document.querySelector('form[enctype="multipart/form-data"]');
 279        if (fileUploadForm) {
 280            fileUploadForm.addEventListener('submit', function (event) {
 281                if (!fileUploadForm.checkValidity()) {
 282                    event.preventDefault();
 283                    event.stopPropagation();
 284                    return;
 285                }
 286                fileUploadForm.classList.add('was-validated');
 287                if (submitBtn.disabled) return;
 288                submitBtn.disabled = true;
 289                submitBtn.setAttribute('aria-busy', 'true');
 290                submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin me-1" aria-hidden="true"></i>Загружаем…';
 291            });
 292        }
 293    });
 294</script>

Methods/Properties

ExecuteAsync()