From f7107a16250b4c3bb8277e6d8ce1f96c4bdbdc90 Mon Sep 17 00:00:00 2001 From: Syngnat Date: Wed, 1 Apr 2026 15:45:50 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20fix(data-grid):=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E5=8D=95=E5=85=83=E6=A0=BC=E7=BC=96=E8=BE=91=E5=80=BC?= =?UTF-8?q?=E4=B8=A2=E5=A4=B1=E5=8F=8A=E6=97=A5=E6=9C=9F=E9=80=89=E6=8B=A9?= =?UTF-8?q?=E5=99=A8=E6=BB=9A=E5=8A=A8=E5=81=8F=E7=A7=BB=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 移除 Form.Item 的 preserve={false},修复嵌套字段名下编辑后值变为 undefined 的问题 - 将表单值初始化移至 useEffect([editing]),确保每次编辑时从 record 重新读取并覆盖旧值 - 新增 cellRef 绑定单元格 DOM,用于定位滚动容器 - DatePicker/TimePicker 面板打开时在 ant-table-wrapper 上拦截 wheel 事件,阻止表格滚动导致选择器漂移 - 面板关闭时自动移除 wheel 事件监听,恢复正常滚动 - refs #297 --- frontend/src/components/DataGrid.tsx | 45 +++++++++++++++++++++------- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/frontend/src/components/DataGrid.tsx b/frontend/src/components/DataGrid.tsx index 9d168ce..5357f4c 100644 --- a/frontend/src/components/DataGrid.tsx +++ b/frontend/src/components/DataGrid.tsx @@ -571,28 +571,47 @@ const EditableCell: React.FC = React.memo(({ }) => { const [editing, setEditing] = useState(false); const inputRef = useRef(null); + const cellRef = useRef(null); const pickerOpenRef = useRef(false); + const scrollLockRef = useRef<{ el: HTMLElement; handler: (e: WheelEvent) => void } | null>(null); const form = useContext(EditableContext); const cellContextMenuContext = useContext(CellContextMenuContext); + /** DatePicker 面板打开时锁定表格滚动,关闭时恢复 */ + const lockTableScroll = useCallback((lock: boolean) => { + if (lock) { + // 查找虚拟滚动容器或常规滚动容器 + const tableWrapper = cellRef.current?.closest?.('.ant-table-wrapper') as HTMLElement | null; + if (tableWrapper) { + const handler = (e: WheelEvent) => { e.preventDefault(); e.stopPropagation(); }; + tableWrapper.addEventListener('wheel', handler, { capture: true, passive: false }); + scrollLockRef.current = { el: tableWrapper, handler }; + } + } else if (scrollLockRef.current) { + const { el, handler } = scrollLockRef.current; + el.removeEventListener('wheel', handler, { capture: true } as any); + scrollLockRef.current = null; + } + }, []); + useEffect(() => { if (editing) { + // 每次进入编辑时强制设置表单值(覆盖 form store 中可能残留的旧值) + const raw = record[dataIndex]; + const fieldName = getCellFieldName(record, dataIndex); + if (isDateTimeField) { + const dayjsVal = parseToDayjs(raw, pickerType); + setCellFieldValue(form, fieldName, dayjsVal); + } else { + const initialValue = typeof raw === 'string' ? normalizeDateTimeString(raw) : raw; + setCellFieldValue(form, fieldName, initialValue); + } inputRef.current?.focus(); } }, [editing]); const toggleEdit = () => { setEditing(!editing); - const raw = record[dataIndex]; - const fieldName = getCellFieldName(record, dataIndex); - if (isDateTimeField) { - // 日期时间类型: 将字符串值转为 dayjs 对象供 DatePicker 使用 - const dayjsVal = parseToDayjs(raw, pickerType); - setCellFieldValue(form, fieldName, dayjsVal); - } else { - const initialValue = typeof raw === 'string' ? normalizeDateTimeString(raw) : raw; - setCellFieldValue(form, fieldName, initialValue); - } }; const save = async () => { @@ -637,7 +656,7 @@ const EditableCell: React.FC = React.memo(({ if (editable) { childNode = editing ? ( - + {isDateTimeField ? ( pickerType === 'time' ? ( = React.memo(({ style={{ width: '100%' }} format={TEMPORAL_FORMATS[pickerType]} onChange={() => setTimeout(save, 0)} + onOpenChange={lockTableScroll} onBlur={() => setTimeout(save, 0)} needConfirm={false} /> @@ -669,6 +689,7 @@ const EditableCell: React.FC = React.memo(({ onOk={() => setTimeout(save, 0)} onOpenChange={(open) => { pickerOpenRef.current = open; + lockTableScroll(open); // 面板关闭(点击外部)时退出编辑,不保存;仅"确定"按钮(onOk)触发保存 if (!open) setTimeout(() => { if (editing) toggleEdit(); }, 0); }} @@ -686,6 +707,7 @@ const EditableCell: React.FC = React.memo(({ format={TEMPORAL_FORMATS[pickerType]} picker={pickerType as any} onChange={() => setTimeout(save, 0)} + onOpenChange={lockTableScroll} onBlur={() => setTimeout(save, 0)} needConfirm={false} /> @@ -745,6 +767,7 @@ const EditableCell: React.FC = React.memo(({ return (