+ `;
+
+ // Обязательные поля
+ if (requiredFields.length > 0) {
+ html += `
`;
+ requiredFields.forEach(field => {
+ html += renderFieldInput(field, fkOptions, true);
+ });
+ }
+
+ // Дополнительные поля
+ if (optionalFields.length > 0) {
+ html += `
`;
+ optionalFields.forEach(field => {
+ html += renderFieldInput(field, fkOptions, false);
+ });
+ }
+
+ html += `
+
@@ -403,83 +477,6 @@ async function promptForRequiredFields(requiredFields, optionalFields) {
modal.appendChild(dialog);
document.body.appendChild(modal);
- // Создать Tabulator таблицу
- const tabulatorInstance = new Tabulator('#insertFormTable', {
- data: tableData,
- layout: 'fitColumns',
- height: '100%',
- columns: [
- {
- title: 'Поле',
- field: 'field_name',
- width: 250,
- headerSort: false,
- formatter: function(cell) {
- const data = cell.getRow().getData();
- let html = `
${escapeHtml(data.field_name)}
`;
-
- // FK информация
- if (data._fk_info) {
- html += `
- → ${data._fk_info.ref_table}.${data._fk_info.ref_column}
-
`;
- }
-
- // Комментарий из базы
- if (data._field_comment) {
- html += `
- 💡 ${escapeHtml(data._field_comment)}
-
`;
- }
-
- return html;
- }
- },
- {
- title: 'Значение',
- field: 'field_value',
- headerSort: false,
- editor: function(cell) {
- const meta = cell.getRow().getData()._field_meta;
-
- if (meta.is_fk && fkOptions[meta.name]?.length > 0) {
- return 'list';
- }
-
- return 'input';
- },
- editorParams: function(cell) {
- const meta = cell.getRow().getData()._field_meta;
- const isRequired = cell.getRow().getData()._required;
-
- if (meta.is_fk && fkOptions[meta.name]?.length > 0) {
- return {
- values: fkOptions[meta.name],
- autocomplete: true,
- clearable: !isRequired,
- listOnEmpty: true,
- freetext: false,
- emptyValue: isRequired ? undefined : null,
- filterFunc: function(term, label, value, item) {
- if (!term) return true;
- return String(label).toLowerCase().includes(term.toLowerCase());
- },
- elementAttributes: {
- placeholder: isRequired ? 'Выберите значение' : 'Не выбрано (NULL)'
- }
- };
- }
-
- return {
- elementAttributes: {
- placeholder: meta.type === 'number' ? 'Число' : 'Текст'
- }
- };
- }
- }
- ]
- });
-
return new Promise((resolve) => {
document.getElementById('insertCancel').addEventListener('click', () => {
if (document.body.contains(modal)) {
@@ -501,12 +498,21 @@ async function promptForRequiredFields(requiredFields, optionalFields) {
const values = {};
let allRequiredFilled = true;
- const rows = tabulatorInstance.getData();
- for (const row of rows) {
- const field = row._field_meta;
- const value = row.field_value;
+ const allFields = [...requiredFields, ...optionalFields];
- if (row._required && (value === null || value === '')) {
+ for (const field of allFields) {
+ const inputElement = document.getElementById(`field_${field.name}`);
+ if (!inputElement) continue;
+
+ const value = inputElement.value;
+
+ if (field.type === 'datetime' || field.data_type.includes('date')) {
+ if (allFields.find(f => f.name === field.name).type === 'datetime' || field.data_type.includes('date')) {
+ // Дата остается строкой для отправки на сервер
+ }
+ }
+
+ if (requiredFields.find(f => f.name === field.name) && (value === null || value === '')) {
alert(`Обязательное поле "${field.name}" не заполнено!`);
allRequiredFilled = false;
break;
@@ -514,7 +520,7 @@ async function promptForRequiredFields(requiredFields, optionalFields) {
if (value !== null && value !== '') {
values[field.name] = convertFieldValue(value, field.type, field.data_type);
- } else if (!row._required) {
+ } else {
values[field.name] = null;
}
}
@@ -547,7 +553,7 @@ function convertFieldValue(value, editorType, dataType) {
}
/**
- * Модальное окно редактирования (Tabulator форма)
+ * Модальное окно редактирования (простая HTML форма с datalist)
*/
async function showEditModal(selectedRows) {
const isSingleRow = selectedRows.length === 1;
@@ -603,17 +609,6 @@ async function showEditModal(selectedRows) {
}
}
- // Подготовить данные для Tabulator
- const tableData = editableFields.map(field => ({
- update: isSingleRow,
- field_name: field.name,
- field_value: field.valuesMatch ? field.commonValue : null,
- _has_mixed: !field.valuesMatch,
- _field_meta: field,
- _field_comment: field.comment || '',
- _fk_info: field.is_fk ? field.fk_info : null
- }));
-
// Создать модальное окно
const modal = document.createElement('div');
modal.className = 'edit-modal-overlay';
@@ -626,7 +621,7 @@ async function showEditModal(selectedRows) {
const dialog = document.createElement('div');
dialog.style.cssText = `
background: white; padding: 20px; border-radius: 8px;
- max-width: 700px; width: 90%; max-height: 80vh; overflow: hidden;
+ max-width: 600px; width: 90%; max-height: 80vh; overflow: auto;
display: flex; flex-direction: column;
`;
@@ -637,14 +632,99 @@ async function showEditModal(selectedRows) {
if (!isSingleRow) {
html += `
- ⚠️ Отметьте галочками поля для изменения во всех выбранных записях.
+ ⚠️ Значения применятся к${count === 1 ? '' : ' всем'} выбранной записи.
`;
}
+ // Отобразить поля редактирования
+ editableFields.forEach(field => {
+ const currentValue = field.valuesMatch ? field.commonValue : null;
+ const hasMixedValues = !field.valuesMatch;
+
+ let fieldHtml = `
+
';
+ html += fieldHtml;
+ });
+
html += `
-
-
+
@@ -658,122 +738,6 @@ async function showEditModal(selectedRows) {
modal.appendChild(dialog);
document.body.appendChild(modal);
- // Подготовить колонки для Tabulator
- const columns = [];
-
- // Колонка checkbox (только для batch edit)
- if (!isSingleRow) {
- columns.push({
- title: '',
- field: 'update',
- width: 40,
- hozAlign: 'center',
- headerSort: false,
- formatter: 'tickCross',
- cellClick: function(e, cell) {
- cell.setValue(!cell.getValue());
- }
- });
- }
-
- // Колонка "Поле"
- columns.push({
- title: 'Поле',
- field: 'field_name',
- width: 250,
- headerSort: false,
- formatter: function(cell) {
- const data = cell.getRow().getData();
- let html = '
';
-
- html += `
🔑 ${escapeHtml(data.field_name)}
`;
-
- // FK информация
- if (data._fk_info) {
- html += `
- → ${data._fk_info.ref_table}.${data._fk_info.ref_column}
-
`;
- }
-
- // Комментарий из базы
- if (data._field_comment) {
- html += `
- 💡 ${escapeHtml(data._field_comment)}
-
`;
- }
-
- // "(разные значения)" индикатор
- if (!isSingleRow && data._has_mixed) {
- html += `
- (разные значения)
-
`;
- }
-
- html += '
';
- return html;
- }
- });
-
- // Колонка "Значение"
- columns.push({
- title: 'Значение',
- field: 'field_value',
- headerSort: false,
- editable: function(cell) {
- const data = cell.getRow().getData();
- if (!isSingleRow && !data.update) return false;
- return true;
- },
- editor: function(cell) {
- const meta = cell.getRow().getData()._field_meta;
- if (meta.is_fk && fkOptions[meta.name]?.length > 0) {
- return 'list';
- }
- return 'input';
- },
- editorParams: function(cell) {
- const meta = cell.getRow().getData()._field_meta;
-
- if (meta.is_fk && fkOptions[meta.name]?.length > 0) {
- return {
- values: fkOptions[meta.name],
- autocomplete: true,
- clearable: meta.is_nullable,
- listOnEmpty: true,
- freetext: false,
- emptyValue: meta.is_nullable ? null : undefined,
- filterFunc: function(term, label, value, item) {
- if (!term) return true;
- return String(label).toLowerCase().includes(term.toLowerCase());
- },
- elementAttributes: {
- placeholder: 'Выберите значение'
- }
- };
- }
-
- return {
- elementAttributes: {
- placeholder: meta.type === 'number' ? 'Число' : 'Текст'
- }
- };
- },
- cellEdited: function(cell) {
- if (!isSingleRow) {
- const row = cell.getRow();
- row.update('update', true);
- }
- }
- });
-
- // Создать Tabulator
- const tabulatorInstance = new Tabulator('#editFormTable', {
- data: tableData,
- layout: 'fitColumns',
- height: '100%',
- columns: columns
- });
-
document.getElementById('editCancel').addEventListener('click', () => {
if (document.body.contains(modal)) {
document.body.removeChild(modal);
@@ -792,22 +756,26 @@ async function showEditModal(selectedRows) {
const changes = {};
let hasChanges = false;
- const rows = tabulatorInstance.getData();
- for (const row of rows) {
- const shouldUpdate = isSingleRow || row.update;
- if (!shouldUpdate) continue;
+ for (const field of editableFields) {
+ const inputElement = document.getElementById(`field_${field.name}`);
+ if (!inputElement) continue;
- const field = row._field_meta;
- let value = row.field_value;
+ const value = inputElement.value;
+ const oldValue = field.valuesMatch ? field.commonValue : null;
- if (value === null || value === '') {
- value = null;
- } else {
- value = convertFieldValue(value, field.type, field.data_type);
+ // Проверить изменения
+ const oldValueStr = oldValue !== null && oldValue !== undefined ? String(oldValue) : '';
+ const newValueStr = value !== null && value !== undefined ? String(value) : '';
+
+ if (oldValueStr !== newValueStr) {
+ hasChanges = true;
}
- changes[field.name] = value;
- hasChanges = true;
+ if (value !== null && value !== '') {
+ changes[field.name] = convertFieldValue(value, field.type, field.data_type);
+ } else {
+ changes[field.name] = null;
+ }
}
if (!hasChanges) {