Files
turborfq/public/index.html
Mikhail Chusavitin 1ecd0d28fa Replace dropdown selects with Tabulator autocomplete forms
- Replace native HTML <select> elements with Tabulator-based vertical forms
- Implement autocomplete functionality for FK fields in Insert modal
- Implement autocomplete functionality for FK fields in Edit modal (single and batch)
- Add comprehensive CSS styling for vertical form-tables
- Show field descriptions, FK references, and comments inline
- Support NULL values for optional fields with clear button
- Auto-enable checkboxes on field edit in batch mode
- Consistent UX with autocomplete in main table grid

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-02-10 13:34:42 +03:00

600 lines
15 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Turbo RFQ</title>
<!-- Tabulator CSS/JS (CDN) -->
<link href="https://unpkg.com/tabulator-tables@6.3.0/dist/css/tabulator.min.css" rel="stylesheet">
<script src="https://unpkg.com/tabulator-tables@6.3.0/dist/js/tabulator.min.js"></script>
<style>
body {
margin: 0;
font-family: sans-serif;
display: flex;
height: 100vh;
overflow: hidden;
}
#sidebar {
width: 250px;
border-right: 1px solid #ccc;
padding: 8px;
box-sizing: border-box;
overflow-y: auto;
flex-shrink: 0;
}
#main {
flex: 1;
display: flex;
flex-direction: column;
min-width: 0;
overflow: hidden;
}
#table {
flex: 1;
position: relative;
overflow: auto; /* ✅ Разрешаем прокрутку */
min-height: 0;
margin-bottom: 14px;
}
/* ✅ Стили для меню столбцов */
.columns-menu {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 4px 20px rgba(0,0,0,0.3);
z-index: 10000;
max-width: 500px;
max-height: 80vh;
overflow-y: auto;
}
.columns-menu-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.5);
z-index: 9999;
}
.column-checkbox {
display: flex;
align-items: center;
padding: 8px;
margin: 4px 0;
border-radius: 4px;
cursor: pointer;
}
.column-checkbox:hover {
background: #f5f5f5;
}
.column-checkbox input[type="checkbox"] {
margin-right: 10px;
cursor: pointer;
}
.column-checkbox label {
cursor: pointer;
flex: 1;
user-select: none;
}
/* ✅ Минимальная ширина столбцов */
.tabulator-col {
min-width: 100px !important;
}
#toolbar {
padding: 8px;
border-bottom: 1px solid #ccc;
flex-shrink: 0;
display: flex;
align-items: center;
gap: 4px;
flex-wrap: wrap;
}
#loginPanel {
padding: 8px;
border-bottom: 1px solid #ccc;
background: #f7f7f7;
flex-shrink: 0;
}
#csvFileInput { display: none; }
/* Размер шрифта при редактировании ячеек */
.tabulator-cell input,
.tabulator-cell select,
.tabulator-cell textarea {
font-size: 14px !important;
font-family: sans-serif !important;
padding: 4px !important;
border: 1px solid #4CAF50 !important;
box-sizing: border-box !important;
width: 100% !important;
min-height: 24px !important;
}
.tabulator-cell input:focus,
.tabulator-cell select:focus,
.tabulator-cell textarea:focus {
outline: none !important;
border-color: #45a049 !important;
box-shadow: 0 0 0 2px rgba(76, 175, 80, 0.2) !important;
}
/* Стили для выделенных строк */
.tabulator-row.tabulator-selected {
background-color: #e3f2fd !important;
}
.tabulator-row.tabulator-selected:hover {
background-color: #bbdefb !important;
}
/* Стили для модальных окон FK */
.fk-modal {
font-family: sans-serif;
}
.fk-modal select,
.fk-modal input {
border: 1px solid #ccc;
border-radius: 4px;
}
.fk-modal select:focus,
.fk-modal input:focus {
outline: none;
border-color: #4CAF50;
box-shadow: 0 0 0 2px rgba(76, 175, 80, 0.2);
}
.fk-modal button:hover {
opacity: 0.9;
}
/* Кнопки toolbar */
#toolbar button {
padding: 6px 12px;
cursor: pointer;
border: 1px solid #ccc;
background: #fff;
border-radius: 3px;
font-size: 13px;
}
#toolbar button:hover {
background: #f0f0f0;
}
#toolbar button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
/* Счетчик выделенных */
#selectionCounter {
padding: 6px 12px;
background: #e3f2fd;
border-radius: 3px;
font-size: 13px;
color: #1976d2;
font-weight: bold;
margin-left: auto;
}
.toolbar-divider {
width: 1px;
height: 24px;
background: #ccc;
margin: 0 4px;
}
/* Стили для тултипов */
.tabulator-tooltip {
max-width: 400px;
padding: 8px 12px;
background: #333;
color: white;
border-radius: 4px;
font-size: 13px;
line-height: 1.5;
box-shadow: 0 2px 8px rgba(0,0,0,0.3);
}
.tabulator-tooltip strong {
color: #4CAF50;
}
.tabulator-tooltip em {
color: #b3e5fc;
font-style: normal;
}
/* ✅ Стили для Tabulator - консолидированные */
.tabulator {
border: none;
background-color: white;
overflow: auto !important;
}
.tabulator .tabulator-header {
background-color: #f5f5f5;
border-bottom: 2px solid #ddd;
}
.tabulator .tabulator-tableholder {
overflow-x: auto !important;
}
.tabulator .tabulator-table {
width: auto !important;
}
/* ✅ Минимальная ширина столбцов (кроме служебных) */
.tabulator-col {
min-width: 100px !important;
}
/* ✅ ИСКЛЮЧЕНИЕ: столбец с чекбоксами - фиксированная ширина */
/* Таргетируем столбец rowSelection по всем возможным селекторам */
.tabulator-col.tabulator-row-handle,
.tabulator-col[tabulator-field=""],
.tabulator-col:first-child {
width: 40px !important;
min-width: 40px !important;
max-width: 40px !important;
}
/* ✅ Заголовок столбца с чекбоксами - убираем лишний padding */
.tabulator-header .tabulator-col.tabulator-row-handle,
.tabulator-header .tabulator-col[tabulator-field=""],
.tabulator-header .tabulator-col:first-child {
width: 40px !important;
min-width: 40px !important;
max-width: 40px !important;
flex: 0 0 40px !important;
padding: 0 !important;
}
/* ✅ Ячейки заголовка столбца с чекбоксами - одинаковый padding с ячейками */
.tabulator-header .tabulator-cell.tabulator-row-handle,
.tabulator-header .tabulator-cell[tabulator-field=""],
.tabulator-header .tabulator-cell:first-child {
width: 40px !important;
min-width: 40px !important;
max-width: 40px !important;
padding: 4px !important;
box-sizing: border-box !important;
}
/* ✅ Ячейки столбца с чекбоксами */
.tabulator-cell[tabulator-field=""],
.tabulator-row .tabulator-cell:first-child {
width: 40px !important;
min-width: 40px !important;
max-width: 40px !important;
padding: 4px !important;
box-sizing: border-box !important;
}
/* ✅ Чекбокс внутри ячейки */
.tabulator-row-handle {
width: 40px !important;
}
/* Header */
#header {
display: none; /* Скрыт до авторизации */
padding: 8px 15px;
background: #2196F3;
color: white;
align-items: center;
justify-content: space-between;
}
#headerTitle {
font-weight: bold;
font-size: 16px;
}
#userMenu {
position: relative;
}
#userIcon {
display: flex;
align-items: center;
gap: 8px;
cursor: pointer;
padding: 5px 10px;
border-radius: 4px;
transition: background 0.2s;
}
#userIcon:hover {
background: rgba(255,255,255,0.2);
}
#userName {
font-size: 14px;
}
#userDropdown {
position: absolute;
top: 100%;
right: 0;
background: white;
border-radius: 4px;
box-shadow: 0 2px 10px rgba(0,0,0,0.2);
min-width: 180px;
z-index: 1000;
overflow: hidden;
}
#userDropdown.dropdown-hidden {
display: none;
}
.dropdown-item {
padding: 12px 15px;
cursor: pointer;
color: #333;
transition: background 0.2s;
}
.dropdown-item:hover {
background: #f5f5f5;
}
.dropdown-divider {
height: 1px;
background: #e0e0e0;
}
/* Login Screen */
#loginScreen {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
#loginBox {
background: white;
padding: 40px;
border-radius: 12px;
box-shadow: 0 10px 40px rgba(0,0,0,0.2);
width: 100%;
max-width: 360px;
}
#loginBox h2 {
margin: 0 0 25px 0;
text-align: center;
color: #333;
font-weight: 500;
}
.login-field {
margin-bottom: 20px;
}
.login-field label {
display: block;
margin-bottom: 6px;
color: #555;
font-size: 14px;
}
.login-field input {
width: 100%;
padding: 12px;
border: 1px solid #ddd;
border-radius: 6px;
font-size: 14px;
box-sizing: border-box;
transition: border-color 0.2s;
}
.login-field input:focus {
outline: none;
border-color: #667eea;
}
#loginBox button {
width: 100%;
padding: 14px;
background: #667eea;
color: white;
border: none;
border-radius: 6px;
font-size: 16px;
cursor: pointer;
transition: background 0.2s;
}
#loginBox button:hover {
background: #5a6fd6;
}
#loginBox button:disabled {
background: #ccc;
cursor: not-allowed;
}
#loginStatus {
margin-top: 15px;
text-align: center;
font-size: 14px;
min-height: 20px;
}
#loginStatus.error {
color: #d32f2f;
}
#loginStatus.success {
color: #388e3c;
}
/* App Content */
#appContent {
flex: 1;
display: flex;
flex-direction: column;
min-height: 0;
}
/* Стили для вертикальных форм-таблиц в модальных окнах */
#insertFormTable.tabulator,
#editFormTable.tabulator {
border: 1px solid #ddd;
font-size: 14px;
}
#insertFormTable .tabulator-cell,
#editFormTable .tabulator-cell {
padding: 12px 14px;
vertical-align: middle;
}
#insertFormTable .tabulator-header,
#editFormTable .tabulator-header {
background: #f8f9fa;
font-weight: 600;
border-bottom: 2px solid #ddd;
}
#insertFormTable .tabulator-row,
#editFormTable .tabulator-row {
border-bottom: 1px solid #eee;
}
#insertFormTable .tabulator-row:hover,
#editFormTable .tabulator-row:hover {
background: #f9f9f9;
}
/* Первая колонка (названия полей) - фиксированный фон */
#insertFormTable .tabulator-col:first-child,
#editFormTable .tabulator-col:nth-child(2),
#insertFormTable .tabulator-cell:first-child,
#editFormTable .tabulator-cell:nth-child(2) {
background: #f5f5f5;
font-weight: 500;
}
/* Стили для редакторов в формах */
#insertFormTable .tabulator-cell input,
#editFormTable .tabulator-cell input,
#insertFormTable .tabulator-cell .tabulator-editor-list,
#editFormTable .tabulator-cell .tabulator-editor-list {
font-size: 14px;
padding: 6px 8px;
border: 1px solid #ddd;
border-radius: 3px;
}
#insertFormTable .tabulator-cell input:focus,
#editFormTable .tabulator-cell input:focus,
#insertFormTable .tabulator-cell .tabulator-editor-list:focus,
#editFormTable .tabulator-cell .tabulator-editor-list:focus {
border-color: #4CAF50;
box-shadow: 0 0 0 2px rgba(76, 175, 80, 0.2);
outline: none;
}
/* Улучшенные стили для Tabulator list editor в формах */
#insertFormTable .tabulator-cell .tabulator-editing,
#editFormTable .tabulator-cell .tabulator-editing {
padding: 2px 0;
}
</style>
</head>
<body>
<div id="sidebar">
<h3>Базы / таблицы</h3>
<div id="tree"></div>
</div>
<div id="main">
<!-- Header с пользователем -->
<div id="header">
<div id="headerTitle">Turbo RFQ</div>
<div id="userMenu">
<div id="userIcon" title="Меню пользователя">
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
<path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/>
</svg>
<span id="userName"></span>
</div>
<div id="userDropdown" class="dropdown-hidden">
<div class="dropdown-item" id="menuResetSettings">Сбросить настройки</div>
<div class="dropdown-divider"></div>
<div class="dropdown-item" id="menuLogout">Выйти</div>
</div>
</div>
</div>
<!-- Экран авторизации -->
<div id="loginScreen">
<div id="loginBox">
<h2>Вход в систему</h2>
<div class="login-field">
<label for="loginUser">Пользователь</label>
<input id="loginUser" type="text" placeholder="Имя пользователя MariaDB" autocomplete="username">
</div>
<div class="login-field">
<label for="loginPass">Пароль</label>
<input id="loginPass" type="password" placeholder="Пароль" autocomplete="current-password">
</div>
<button id="loginBtn">Войти</button>
<div id="loginStatus"></div>
</div>
</div>
<!-- Основной интерфейс (скрыт до авторизации) -->
<div id="appContent" style="display: none;">
<div id="toolbar">
<button id="btnInsert"> Вставить</button>
<button id="btnCopy">📄 Копировать строку</button>
<button id="btnEdit">✏️ Изменить</button>
<button id="btnDelete">🗑️ Удалить</button>
<div class="toolbar-divider"></div>
<button id="btnSelectAll">☑️ Выделить все</button>
<button id="btnDeselectAll">⬜ Снять выделение</button>
<div class="toolbar-divider"></div>
<button id="btnImportCSV">📥 Импорт CSV</button>
<input type="file" id="csvFileInput" accept=".csv">
<button id="btnExport">📤 Экспорт</button>
<button id="btnAnalyzeCSV">🔍 Анализ CSV</button>
<button id="btnManageColumns">⚙️ Столбцы</button>
<span id="selectionCounter" style="display: none;">Выбрано: 0</span>
</div>
<div id="table"></div>
</div>
</div>
<!-- Модули приложения -->
<script src="js/core.js"></script>
<script src="js/user.js"></script>
<script src="js/table.js"></script>
<script src="js/operations.js"></script>
<script src="js/io.js"></script>
<script src="js/app.js"></script>
</body>
</html>