🐛 fix(datagrid-mysql): 修复MySQL行编辑时datetime空值提交失败

- 前端按列类型归一化 temporal 字段,INSERT 空值跳过字段、UPDATE 空值转 NULL
- 后端 ApplyChanges 增加 temporal 字段兜底,避免空字符串写入 datetime/timestamp
- 新增全默认值插入路径,兼容 CURRENT_TIMESTAMP 等默认值场景
- refs #113
This commit is contained in:
Syngnat
2026-02-26 14:13:27 +08:00
parent a435d62d3b
commit 66a3113fa8
2 changed files with 139 additions and 7 deletions

View File

@@ -90,6 +90,14 @@ const normalizeDateTimeString = (val: string) => {
return `${match[1]} ${match[2]}`;
};
const isTemporalColumnType = (columnType?: string): boolean => {
const raw = String(columnType || '').trim().toLowerCase();
if (!raw) return false;
if (raw.includes('datetime') || raw.includes('timestamp')) return true;
const base = raw.split(/[ (]/)[0];
return base === 'date' || base === 'time' || base === 'year';
};
// --- Helper: Format Value ---
const formatCellValue = (val: any) => {
try {
@@ -764,6 +772,35 @@ const DataGrid: React.FC<DataGridProps> = ({
return next;
}, [columnMetaMap]);
const normalizeCommitCellValue = useCallback(
(columnName: string, value: any, mode: 'insert' | 'update') => {
if (value === undefined) return undefined;
const normalizedName = String(columnName || '').trim();
const meta = columnMetaMap[normalizedName] || columnMetaMapByLowerName[normalizedName.toLowerCase()];
const temporal = isTemporalColumnType(meta?.type);
if (!temporal) {
return value;
}
if (value === null) {
return null;
}
if (typeof value === 'string') {
const raw = value.trim();
if (raw === '') {
// INSERT 空时间值直接忽略字段让数据库默认值生效UPDATE 空时间值转 NULL。
return mode === 'insert' ? undefined : null;
}
return normalizeDateTimeString(value);
}
return value;
},
[columnMetaMap, columnMetaMapByLowerName]
);
const renderColumnTitle = useCallback((name: string): React.ReactNode => {
const normalizedName = String(name || '');
const meta = columnMetaMap[normalizedName] || columnMetaMapByLowerName[normalizedName.toLowerCase()];
@@ -1814,7 +1851,17 @@ const DataGrid: React.FC<DataGridProps> = ({
const updates: any[] = [];
const deletes: any[] = [];
addedRows.forEach(row => { const { [GONAVI_ROW_KEY]: _rowKey, ...vals } = row; inserts.push(vals); });
addedRows.forEach(row => {
const { [GONAVI_ROW_KEY]: _rowKey, ...vals } = row;
const normalizedValues: Record<string, any> = {};
Object.entries(vals).forEach(([col, val]) => {
const normalizedVal = normalizeCommitCellValue(col, val, 'insert');
if (normalizedVal !== undefined) {
normalizedValues[col] = normalizedVal;
}
});
inserts.push(normalizedValues);
});
deletedRowKeys.forEach(keyStr => {
// Find original data
const originalRow = data.find(d => rowKeyStr(d?.[GONAVI_ROW_KEY]) === keyStr) || addedRows.find(d => rowKeyStr(d?.[GONAVI_ROW_KEY]) === keyStr);
@@ -1847,8 +1894,16 @@ const DataGrid: React.FC<DataGridProps> = ({
});
}
if (Object.keys(values).length === 0) return;
updates.push({ keys: pkData, values });
const normalizedValues: Record<string, any> = {};
Object.entries(values).forEach(([col, val]) => {
const normalizedVal = normalizeCommitCellValue(col, val, 'update');
if (normalizedVal !== undefined) {
normalizedValues[col] = normalizedVal;
}
});
if (Object.keys(normalizedValues).length === 0) return;
updates.push({ keys: pkData, values: normalizedValues });
});
if (inserts.length === 0 && updates.length === 0 && deletes.length === 0) {