< Summary

Information
Class: AspNetCoreGeneratedDocument.Areas_Studio2_Views_Shared__OneCOrgSelector
Assembly: OzonOrdersWeb
File(s): /home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Areas/Studio2/Views/Shared/_OneCOrgSelector.cshtml
Line coverage
0%
Covered lines: 0
Uncovered lines: 1
Coverable lines: 1
Total lines: 182
Line coverage: 0%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
ExecuteAsync()100%210%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Areas/Studio2/Views/Shared/_OneCOrgSelector.cshtml

#LineLine coverage
 1@using OzonOrdersWeb.ViewModels.OrderViewModels
 2@model MultiplayEditOrderViewModel
 3
 4@{
 5    // Дефолтная организация всегда Interparts (0000000000)
 6    const string DefaultInn  = "0000000000";
 7    const string DefaultName = "Interparts";
 8}
 9
 10<input type="hidden" id="oneCOrganizationInn" name="oneCOrganizationInn" value="@DefaultInn" />
 11
 12<span class="text-muted small ms-1">
 13    Организация:
 14    <a href="#" id="oneCOrgSelectorLink" class="text-decoration-none fw-semibold"
 15       data-bs-toggle="modal" data-bs-target="#oneCOrgModal">
 016        @DefaultName (ИНН: @DefaultInn)
 17    </a>
 18</span>
 19
 20<!-- Модалка выбора организации 1С -->
 21<div class="modal fade" id="oneCOrgModal" tabindex="-1" aria-labelledby="oneCOrgModalLabel" aria-hidden="true">
 22    <div class="modal-dialog modal-dialog-centered">
 23        <div class="modal-content">
 24            <div class="modal-header">
 25                <h5 class="modal-title" id="oneCOrgModalLabel">
 26                    <i class="fas fa-building me-2"></i>Организация для проведения в 1С
 27                </h5>
 28                <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
 29            </div>
 30            <div class="modal-body">
 31                <p class="text-muted small mb-3">
 32                    По умолчанию используется <strong>Interparts (0000000000)</strong>. Измените только если нужна друга
 33                </p>
 34                <div class="mb-1 position-relative">
 35                    <label class="form-label fw-semibold">Поиск организации</label>
 36                    <input type="text"  id="oneCOrgSearch"  class="form-control" placeholder="Введите ИНН или название…"
 37                    <input type="hidden" id="oneCOrgTempInn"  value="" />
 38                    <input type="hidden" id="oneCOrgTempName" value="" />
 39                    <div id="oneCOrgResults"
 40                         class="position-absolute w-100 border rounded shadow-sm bg-white"
 41                         style="display:none; z-index:9999; max-height:220px; overflow-y:auto; top:100%;">
 42                    </div>
 43                </div>
 44                <div id="oneCOrgSelectedRow" class="mt-2 text-success small" style="display:none">
 45                    <i class="fas fa-check-circle me-1"></i><span id="oneCOrgSelectedText"></span>
 46                </div>
 47            </div>
 48            <div class="modal-footer d-flex justify-content-between align-items-center">
 49                <button type="button" class="btn btn-outline-secondary btn-sm" id="oneCOrgResetBtn">
 50                    Сбросить (Interparts)
 51                </button>
 52                <div>
 53                    <button type="button" class="btn btn-secondary me-1" data-bs-dismiss="modal">Отмена</button>
 54                    <button type="button" class="btn btn-primary" id="oneCOrgConfirmBtn" data-bs-dismiss="modal" disable
 55                        Применить
 56                    </button>
 57                </div>
 58            </div>
 59        </div>
 60    </div>
 61</div>
 62
 63<script>
 64(function () {
 65    const ENDPOINT  = '/Studio2/OzonClients/SearchOrganizations';
 66    const realInn   = document.getElementById('oneCOrganizationInn');
 67    const linkEl    = document.getElementById('oneCOrgSelectorLink');
 68    const searchEl  = document.getElementById('oneCOrgSearch');
 69    const tempInn   = document.getElementById('oneCOrgTempInn');
 70    const tempName  = document.getElementById('oneCOrgTempName');
 71    const resultsEl = document.getElementById('oneCOrgResults');
 72    const selectedRow  = document.getElementById('oneCOrgSelectedRow');
 73    const selectedText = document.getElementById('oneCOrgSelectedText');
 74    const confirmBtn   = document.getElementById('oneCOrgConfirmBtn');
 75    const resetBtn     = document.getElementById('oneCOrgResetBtn');
 76
 77    let timer = null;
 78
 79    // ── Утилиты ──────────────────────────────────────────────────────────────
 80    const esc = s => (s || '').replace(/[&<>"']/g, c =>
 81        ({ '&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;' }[c]));
 82
 83    function hideResults() { resultsEl.style.display = 'none'; }
 84
 85    function markPending(inn, name) {
 86        tempInn.value  = inn;
 87        tempName.value = name;
 88        selectedText.textContent = name + (inn ? ' (ИНН: ' + inn + ')' : '');
 89        selectedRow.style.display  = '';
 90        confirmBtn.disabled = false;
 91    }
 92
 93    // ── Рендер выпадающего списка ─────────────────────────────────────────────
 94    function renderItems(items, q) {
 95        if (!items.length) {
 96            resultsEl.innerHTML = '<div class="px-3 py-2 text-muted small fst-italic">Не найдено</div>';
 97            resultsEl.style.display = 'block';
 98            return;
 99        }
 100        const hi = t => !q ? esc(t) : esc(t).replace(
 101            new RegExp('(' + q.replace(/[.*+?^${}()|[\]\\]/g,'\\$&') + ')', 'gi'),
 102            '<mark class="bg-warning-subtle rounded px-0">$1</mark>');
 103        resultsEl.innerHTML = items.map((it, i) => `
 104            <div class="one-c-org-item d-flex flex-column px-3 py-2 border-bottom" tabindex="0" data-i="${i}"
 105                 data-inn="${esc(it.inn)}" data-name="${esc(it.name)}">
 106                <span class="fw-semibold small font-monospace">${hi(it.inn || '')}</span>
 107                <span class="text-muted small">${hi(it.name || '')}</span>
 108            </div>`).join('');
 109        resultsEl.querySelectorAll('.one-c-org-item').forEach(el => {
 110            el.addEventListener('mousedown', e => {
 111                e.preventDefault();
 112                markPending(el.dataset.inn, el.dataset.name);
 113                searchEl.value = el.dataset.inn ? `${el.dataset.inn} — ${el.dataset.name}` : el.dataset.name;
 114                hideResults();
 115            });
 116            el.addEventListener('keydown', e => {
 117                if (e.key === 'Enter')   { e.preventDefault(); el.dispatchEvent(new MouseEvent('mousedown')); }
 118                if (e.key === 'ArrowDown') (el.nextElementSibling || el).focus();
 119                if (e.key === 'ArrowUp')   (el.previousElementSibling || el).focus();
 120                if (e.key === 'Escape')  { hideResults(); searchEl.focus(); }
 121            });
 122        });
 123        resultsEl.style.display = 'block';
 124    }
 125
 126    // ── Поиск ─────────────────────────────────────────────────────────────────
 127    async function doSearch(q) {
 128        resultsEl.innerHTML = '<div class="px-3 py-2 text-muted small"><i class="fas fa-circle-notch fa-spin me-1"></i>П
 129        resultsEl.style.display = 'block';
 130        try {
 131            const r = await fetch(`${ENDPOINT}?q=${encodeURIComponent(q)}&limit=15`);
 132            if (!r.ok) throw new Error(r.statusText);
 133            renderItems(await r.json(), q);
 134        } catch (err) {
 135            resultsEl.innerHTML = `<div class="px-3 py-2 text-danger small">Ошибка: ${esc(err.message)}</div>`;
 136        }
 137    }
 138
 139    searchEl.addEventListener('input', function () {
 140        const q = this.value.trim();
 141        clearTimeout(timer);
 142        if (q.length < 2) { hideResults(); return; }
 143        timer = setTimeout(() => doSearch(q), 280);
 144    });
 145    searchEl.addEventListener('keydown', e => {
 146        if (e.key === 'ArrowDown') resultsEl.querySelector('.one-c-org-item')?.focus();
 147        if (e.key === 'Escape')    hideResults();
 148    });
 149    document.addEventListener('click', e => {
 150        if (!resultsEl.contains(e.target) && e.target !== searchEl) hideResults();
 151    });
 152
 153    // ── Применить ─────────────────────────────────────────────────────────────
 154    confirmBtn.addEventListener('click', function () {
 155        if (!tempInn.value) return;
 156        realInn.value = tempInn.value;
 157        linkEl.textContent = tempName.value + ' (ИНН: ' + tempInn.value + ')';
 158    });
 159
 160    // ── Сброс ─────────────────────────────────────────────────────────────────
 161    resetBtn.addEventListener('click', function () {
 162        realInn.value      = '0000000000';
 163        linkEl.textContent = 'Interparts (ИНН: 0000000000)';
 164        searchEl.value     = '';
 165        tempInn.value      = '';
 166        tempName.value     = '';
 167        selectedRow.style.display = 'none';
 168        confirmBtn.disabled = true;
 169        hideResults();
 170    });
 171
 172    // ── Открытие модалки — сбрасываем «pending» ───────────────────────────────
 173    document.getElementById('oneCOrgModal').addEventListener('show.bs.modal', function () {
 174        searchEl.value    = '';
 175        tempInn.value     = '';
 176        tempName.value    = '';
 177        selectedRow.style.display = 'none';
 178        confirmBtn.disabled = true;
 179        hideResults();
 180    });
 181})();
 182</script>

Methods/Properties

ExecuteAsync()