diff --git a/index.html b/index.html index 3e55f2a..47c51cb 100644 --- a/index.html +++ b/index.html @@ -24,17 +24,325 @@ --radius-sm: 8px; --shadow-md: 0 4px 20px rgba(0,0,0,0.1); --shadow-lg: 0 10px 40px rgba(0,0,0,0.12); - --transition: 0.25s cubic-bezier(0.4, 0, 0.2, 1); + --transition: 0.25s cubic-bezier(0.4,0,0.2,1); } - * { margin: 0; padding: 0; box-sizing: border-box; } - body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; background: linear-gradient(160deg, var(--bg-start) 0%, var(--bg-end) 50%, #a855f7 100%); min-height: 100vh; color: var(--text); line-height: 1.6; } - /* ... все остальные стили и скрипт из оригинального кода ... */ + [data-theme="dark"] { + --bg-start: #111827; + --bg-end: #1e293b; + --surface: #1f2937; + --surface-alt: #111827; + --text: #f9fafb; + --text-secondary: #d1d5db; + --text-muted: #9ca3af; + --border: #374151; + } + * {margin:0;padding:0;box-sizing:border-box;} + body {font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif; + background:linear-gradient(160deg,var(--bg-start) 0%,var(--bg-end) 50%,#a855f7 100%); + min-height:100vh;color:var(--text);line-height:1.6;} + .container {max-width:1100px;margin:0 auto;padding:2rem 1.5rem 4rem;position:relative;z-index:1;} + .hero {text-align:center;padding:2rem 1rem 3rem;color:white;} + .hero-badge {display:inline-flex;align-items:center;gap:0.5rem;background:rgba(255,255,255,0.15);backdrop-filter:blur(10px); + padding:0.4rem 1rem;border-radius:20px;font-size:0.85rem;font-weight:500;margin-bottom:1.25rem;border:1px solid rgba(255,255,255,0.2);} + .hero h1 {font-size:clamp(1.8rem,4vw,2.75rem);font-weight:800;letter-spacing:-0.02em;margin-bottom:0.75rem;text-shadow:0 2px 10px rgba(0,0,0,0.15);} + .hero-subtitle {font-size:1.05rem;opacity:0.9;max-width:650px;margin:0 auto;line-height:1.7;} + .card {background:var(--surface);border-radius:var(--radius);box-shadow:var(--shadow-lg);margin-bottom:1.5rem;overflow:hidden;transition:box-shadow var(--transition);} + .card:hover {box-shadow:0 15px 50px rgba(0,0,0,0.15);} + .card-head {display:flex;align-items:center;gap:1rem;padding:1.25rem 2rem;border-bottom:1px solid var(--border);background:var(--surface-alt);} + .step-badge {width:36px;height:36px;border-radius:10px;background:linear-gradient(135deg,var(--primary),var(--bg-end));color:white;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:1rem;flex-shrink:0;} + .card-head h2 {font-size:1.25rem;font-weight:700;} + .card-body {padding:2rem;} + .dropzone {border:2px dashed var(--border);border-radius:12px;padding:3rem 2rem;text-align:center;cursor:pointer;transition:all var(--transition); + background:var(--surface-alt);} + .dropzone:hover,.dropzone.dragover {border-color:var(--primary);background:#eef2ff;transform:scale(1.01);} + .dropzone.dragover {box-shadow:0 0 0 4px rgba(99,102,241,0.15);} + .dropzone-icon {width:72px;height:72px;margin:0 auto 1.25rem;background:linear-gradient(135deg,#eef2ff,#e0e7ff);border-radius:50%;display:flex;align-items:center;justify-content:center;transition:transform var(--transition);} + .dropzone:hover .dropzone-icon {transform:scale(1.1);} + .dropzone-title {font-size:1.1rem;font-weight:600;margin-bottom:0.5rem;} + .dropzone-hint {font-size:0.9rem;color:var(--text-secondary);max-width:450px;margin:0 auto;} + .file-list {margin-top:1.5rem;} + .file-item {display:flex;align-items:center;gap:0.75rem;padding:0.75rem 1rem;background:var(--surface-alt);border-radius:var(--radius-sm); + margin-bottom:0.5rem;border:1px solid var(--border);animation:slideIn .3s ease;} + @keyframes slideIn{from{opacity:0;transform:translateY(-8px);}to{opacity:1;transform:translateY(0);}} + .file-icon {width:36px;height:36px;border-radius:8px;display:flex;align-items:center;justify-content:center;font-size:1.1rem;flex-shrink:0;} + .file-icon.vedomost{background:#dbeafe;} + .file-icon.transaction{background:#fef3c7;} + .file-info {flex:1;min-width:0;} + .file-name {font-size:0.9rem;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;} + .file-type {font-size:0.8rem;color:var(--text-muted);} + .file-remove {width:28px;height:28px;border:none;background:transparent;border-radius:6px;cursor:pointer;color:var(--text-muted); + font-size:1.1rem;display:flex;align-items:center;justify-content:center;transition:all var(--transition);} + .file-remove:hover {background:#fee2e2;color:var(--danger);} + .actions {display:flex;gap:0.75rem;margin-top:1.5rem;flex-wrap:wrap;} + .btn {padding:0.75rem 1.75rem;border:none;border-radius:10px;font-size:0.95rem;font-weight:600;cursor:pointer;transition:all var(--transition); + display:inline-flex;align-items:center;gap:0.5rem;} + .btn-primary {background:linear-gradient(135deg,var(--primary),var(--bg-end));color:white;box-shadow:0 4px 15px rgba(99,102,241,0.35);} + .btn-primary:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 6px 25px rgba(99,102,241,0.45);} + .btn-primary:disabled{opacity:0.4;cursor:not-allowed;} + .btn-outline {background:transparent;color:var(--text-secondary);border:1.5px solid var(--border);} + .btn-outline:hover:not(:disabled){background:var(--surface-alt);border-color:var(--text-muted);} + .btn-success {background:linear-gradient(135deg,#10b981,#059669);color:white;box-shadow:0 4px 15px rgba(16,185,129,0.3);} + .btn-success:hover{transform:translateY(-2px);box-shadow:0 6px 20px rgba(16,185,129,0.4);} + .btn-export {background:linear-gradient(135deg,#f59e0b,#d97706);color:white;} + .btn-export:hover{transform:translateY(-2px);box-shadow:0 6px 20px rgba(245,158,11,0.4);} + .btn-theme {background:linear-gradient(135deg,#94a3b8,#64748b);color:white;} + .btn-theme:hover{transform:translateY(-2px);} + .progress-bar {width:100%;height:4px;background:var(--border);border-radius:2px;overflow:hidden;margin-top:1rem;display:none;} + .progress-bar.active{display:block;} + .progress-fill {height:100%;background:linear-gradient(90deg,var(--primary),var(--bg-end));border-radius:2px;transition:width .3s ease;width:0%;} + .table-wrap {overflow-x:auto;border-radius:var(--radius-sm);border:1px solid var(--border);} + table {width:100%;border-collapse:collapse;font-size:0.875rem;} + thead{background:var(--surface-alt);} th, td {padding:0.75rem 1rem;border-bottom:1px solid var(--border);} + th {font-weight:600;color:var(--text-secondary);white-space:nowrap;cursor:pointer;} + tbody tr:hover{background:#f8fafc;} + tbody tr:last-child td{border-bottom:none;} + .badge{display:inline-flex;align-items:center;gap:0.3rem;padding:0.2rem 0.65rem;border-radius:6px;font-size:0.8rem;font-weight:600;} + .badge-ok{background:#d1fae5;color:#065f46;} + .badge-warn{background:#fef3c7;color:#92400e;} + .badge-err{background:#fee2e2;color:#991b1b;} + .tabs-wrapper {border-bottom:2px solid var(--border);margin-bottom:1.5rem;display:flex;gap:0.25rem;overflow-x:auto;scrollbar-width:none;} + .tabs-wrapper::-webkit-scrollbar{display:none;} + .tab-btn {padding:0.75rem 1.25rem;background:none;border:none;border-bottom:2.5px solid transparent;cursor:pointer;font-size:0.9rem;font-weight:600;color:var(--text-muted);white-space:nowrap;transition:all var(--transition);margin-bottom:-2px;} + .tab-btn:hover{color:var(--primary);} .tab-btn.active{color:var(--primary);border-bottom-color:var(--primary);} + .tab-btn .count{display:inline-flex;align-items:center;justify-content:center;min-width:20px;height:20px;background:var(--primary-light);color:var(--primary-dark);border-radius:10px;font-size:0.75rem;padding:0 6px;margin-left:0.35rem;} + .tab-panel{display:none;animation:fadeUp .3s ease;} + .tab-panel.active{display:block;} + @keyframes fadeUp{from{opacity:0;transform:translateY(8px);}to{opacity:1;transform:translateY(0);}} + .empty-state{text-align:center;padding:3rem 1rem;} + .empty-state-icon{font-size:4rem;margin-bottom:1rem;opacity:0.3;} + .empty-state p{color:var(--text-muted);} + .info-card{background:var(--surface);border-radius:var(--radius);box-shadow:var(--shadow-md);overflow:hidden;} + .info-head{padding:1.25rem 2rem;border-bottom:1px solid var(--border);background:var(--surface-alt);display:flex;align-items:center;gap:0.75rem;} + .info-head h2{font-size:1.25rem;font-weight:700;} + .info-grid{padding:1.5rem 2rem;display:grid;gap:1.25rem;} + .info-block{display:flex;gap:1rem;padding:1.25rem;background:var(--surface-alt);border-radius:12px;border:1px solid var(--border);transition:border-color var(--transition);} + .info-block:hover{border-color:var(--primary-light);} + .info-block-icon{width:42px;height:42px;border-radius:10px;display:flex;align-items:center;justify-content:center;font-size:1.25rem;flex-shrink:0;} + .info-block-icon.blue{background:#dbeafe;} + .info-block-icon.green{background:#d1fae5;} + .info-block-icon.amber{background:#fef3c7;} + .info-block-icon.purple{background:#ede9fe;} + .info-block-icon.rose{background:#ffe4e6;} + .info-block-title{font-weight:700;font-size:0.95rem;margin-bottom:0.35rem;} + .info-block-text{font-size:0.9rem;color:var(--text-secondary);line-height:1.65;} + .footer{text-align:center;padding:2rem 1rem;color:rgba(255,255,255,0.6);font-size:0.85rem;} + @media (max-width:768px){.container{padding:1rem 0.75rem 3rem;}.hero{padding:1.5rem 0.5rem 2rem;}.card-head{padding:1rem 1.25rem;}.card-body{padding:1.25rem;}.dropzone{padding:2rem 1rem;}.actions{flex-direction:column;}.btn{width:100%;justify-content:center;}.info-grid{padding:1rem;}.info-block{flex-direction:column;}} + +
- -

Тестовый файл для репозитория «Сверка выручки водителей». Добавьте сюда улучшенный код.

+
+
[LOCK] Работает офлайн — файлы не отправляются на сервер
+

Сверка выручки водителей

+

Загрузите ведомости приёма наличных и выгрузку транзакций — получите сводную таблицу, расхождения и готовый Excel-отчёт

+
+ +
+
1

Файлы

+
+
+
+
Перетащите файлы сюда или нажмите для выбора
+
Любое число ведомостей (.xlsx) + одна выгрузка TRANSACTIONS_EXT. Тип определяется автоматически.
+
+ +
+
+ + + + +
+
+
+
+ +
+
2

Результат

+
+
📋

Загрузите файлы и нажмите «Провести сверку»

+ + +
+
+ +
+
💡

Как это работает

+
+
📄
Определение типа файла
Ведомость распознаётся по заголовку «ВЕДОМОСТЬ ПРИЕМА НАЛИЧНЫХ СРЕДСТВ»; из неё берутся номер документа, дата, ФИО кассира, разделы «Город» / «Пригород» и строки водителей. Выгрузка распознаётся по столбцам CONDUCTOR, DATE и TARIF_SUM.
+
📅
Период
Из транзакций берутся только даты, указанные в загруженных ведомостях. Остальные даты показываются справочно и в сверку не входят.
+
🔍
Ключ сопоставления
ФИО водителя + гос. номер ТС. Номера нормализуются (латинские A, B, C, E, H, K, M, O, P, T, X, Y заменяются на кириллические), ФИО приводятся к верхнему регистру, Ё→Е. Опечатки в ФИО сводятся нечётким сравнением при схожести ≥ 88%.
+
💰
Суммы
«Сдано» — графа «Итого на сумму» ведомости. «Собрано» — TARIF_SUM ÷ 100 (копейки → рубли) по всем транзакциям водителя за выбранные даты.
+
🔒
Приватность
Файлы никуда не отправляются — весь расчёт выполняется в браузере на вашем компьютере. Приложение работает без интернета.
+
+
+
+ - \ No newline at end of file +