add dropdown menu for FK values

This commit is contained in:
Mikhail Chusavitin
2026-01-21 18:32:53 +03:00
parent 44ad6785a8
commit 2f7a180543
2 changed files with 88 additions and 23 deletions

View File

@@ -205,6 +205,28 @@ async function selectTable(schema, tableName) {
console.log('📋 Метаданные получены:', currentMeta);
// ✅ Загружаем значения для всех FK полей
const fkValues = new Map();
for (const col of currentMeta.columns) {
if (col.IS_FOREIGN_KEY && col.FOREIGN_KEY) {
console.log('🔗 Загрузка FK значений для:', col.COLUMN_NAME);
try {
const result = await api(
`/api/fk-values?schema=${encodeURIComponent(col.FOREIGN_KEY.ref_schema)}&` +
`table=${encodeURIComponent(col.FOREIGN_KEY.ref_table)}&` +
`column=${encodeURIComponent(col.FOREIGN_KEY.ref_column)}`
);
fkValues.set(col.COLUMN_NAME, result.values || []);
console.log(' ✅ Загружено значений:', result.values.length);
} catch (err) {
console.error(' ❌ Ошибка загрузки FK:', err);
fkValues.set(col.COLUMN_NAME, []);
}
}
}
// ✅ Формируем колонки с правильными редакторами
const columns = [
{
formatter: "rowSelection",
@@ -217,12 +239,45 @@ async function selectTable(schema, tableName) {
cell.getRow().toggleSelect();
}
},
...currentMeta.columns.map(col => ({
...currentMeta.columns.map(col => {
const colDef = {
title: col.COLUMN_NAME,
field: col.COLUMN_NAME,
editor: "input",
headerFilter: "input"
}))
};
// ✅ Выбираем редактор в зависимости от типа поля
if (col.IS_FOREIGN_KEY && fkValues.has(col.COLUMN_NAME)) {
const values = fkValues.get(col.COLUMN_NAME);
if (values.length > 0) {
// ✅ Выпадающий список для FK
colDef.editor = "list";
colDef.editorParams = {
values: values,
clearable: col.IS_NULLABLE, // Разрешаем очистку для nullable полей
autocomplete: true,
listOnEmpty: true,
freetext: false // Запрещаем ввод произвольного текста
};
console.log(` 📋 ${col.COLUMN_NAME}: select с ${values.length} значениями`);
} else {
// Нет значений - обычный input с предупреждением
colDef.editor = "input";
colDef.editorParams = {
elementAttributes: {
placeholder: `⚠️ Нет значений в ${col.FOREIGN_KEY.ref_table}`
}
};
}
} else {
// Обычный редактор
colDef.editor = "input";
}
return colDef;
})
];
if (table) {
@@ -324,13 +379,21 @@ async function selectTable(schema, tableName) {
} catch (err) {
console.error('❌ ОШИБКА:', err);
// ✅ Красная подсветка + откат значения
if (rowElement && rowElement.getElement) {
rowElement.getElement().style.backgroundColor = '#ffebee';
}
// Подсветка остаётся до перезагрузки данных
setTimeout(() => {
if (confirm('Ошибка сохранения:\n' + err.message + '\n\nОбновить таблицу?')) {
table.replaceData();
}
}, 100);
} else {
alert('Ошибка: ' + err.message);
}
}
}
// События
table.on("rowSelectionChanged", function(data, rows) {
@@ -412,7 +475,10 @@ async function selectTable(schema, tableName) {
document.addEventListener('keydown', enterHandler);
console.log('✅ ВСЕ СОБЫТИЯ ПОДКЛЮЧЕНЫ - ВЕРСИЯ 2.0');
console.log('📋 FK полей с dropdown:', Array.from(fkValues.keys()).join(', '));
}
// functions
document.getElementById('btnSelectAll').addEventListener('click', async () => {

View File

@@ -197,10 +197,7 @@ private function formatPDOError(\PDOException $e, string $schema, string $table,
public function updateRow(string $schema, string $table, array $row, array $columns, array $pk): array
{
error_log("=== UPDATE ROW ===");
error_log("Schema: $schema");
error_log("Table: $table");
error_log("Row data: " . json_encode($row, JSON_UNESCAPED_UNICODE));
error_log("PK: " . json_encode($pk));
error_log("Schema: $schema, Table: $table");
if (empty($pk)) {
throw new \RuntimeException('No primary key — update disabled');
@@ -221,14 +218,12 @@ public function updateRow(string $schema, string $table, array $row, array $colu
}
if (empty($sets)) {
error_log("No changes to update");
return ['updated' => 0, 'message' => 'No changes'];
}
$whereParts = [];
foreach ($pk as $name) {
if (!array_key_exists($name, $row)) {
error_log("ERROR: Missing PK value: $name");
throw new \RuntimeException("Missing PK value: $name");
}
$whereParts[] = "`$name` = :pk_$name";
@@ -242,20 +237,24 @@ public function updateRow(string $schema, string $table, array $row, array $colu
implode(' AND ', $whereParts)
);
error_log("SQL: $sql");
error_log("Params: " . json_encode($params, JSON_UNESCAPED_UNICODE));
$stmt = $this->pdo->prepare($sql);
$stmt->execute($params);
// ✅ Обрабатываем ошибки с красивым сообщением
try {
$stmt->execute($params);
$rowCount = $stmt->rowCount();
error_log("Rows updated: $rowCount");
error_log("=== UPDATE COMPLETE ===");
return ['updated' => $rowCount];
} catch (\PDOException $e) {
error_log("UPDATE FAILED: " . $e->getMessage());
// Форматируем ошибку для пользователя
throw new \RuntimeException($this->formatPDOError($e, $schema, $table, $params));
}
}
public function deleteRow(string $schema, string $table, array $row, array $pk): array
{
if (empty($pk)) {