@zat-design/sisyphus-react 4.5.0-beta.2 → 4.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -22,7 +22,7 @@ const Validator = ({
|
|
|
22
22
|
const {
|
|
23
23
|
hasError,
|
|
24
24
|
firstErrorIndex,
|
|
25
|
-
|
|
25
|
+
firstErrorColumnKey
|
|
26
26
|
} = await runUnifiedValidation({
|
|
27
27
|
form: config.form,
|
|
28
28
|
name: config.name,
|
|
@@ -38,9 +38,9 @@ const Validator = ({
|
|
|
38
38
|
config?.tableRef?.current?.scrollTo?.({
|
|
39
39
|
index: firstErrorIndex
|
|
40
40
|
});
|
|
41
|
-
//
|
|
41
|
+
// 横向:把报错列滚入视口(虚拟表格列被虚拟化,按表头列宽算 scrollLeft,与行渲染无关)
|
|
42
42
|
requestAnimationFrame(() => {
|
|
43
|
-
scrollVirtualToErrorColumn(config?.tableRef,
|
|
43
|
+
scrollVirtualToErrorColumn(config?.tableRef, columns || [], firstErrorColumnKey);
|
|
44
44
|
});
|
|
45
45
|
});
|
|
46
46
|
}
|
|
@@ -90,16 +90,22 @@ export declare const getDisabled: ({ globalControl, formDisabled, column, tabled
|
|
|
90
90
|
*/
|
|
91
91
|
export declare const handleScrollToError: () => void;
|
|
92
92
|
/**
|
|
93
|
-
*
|
|
93
|
+
* 把「首个报错列的 cellKey」映射成它在表头 th 中的可见列索引。
|
|
94
|
+
* 列序 = [选择列?(hasSelection 时占位 1), ...用户列];names 列的 cellKey 用 splitNames 结果。
|
|
95
|
+
* @returns 表头 th 下标;未命中返回 -1
|
|
96
|
+
*/
|
|
97
|
+
export declare const resolveErrorColumnIndex: (columns: any[], cellKey: string, hasSelection: boolean) => number;
|
|
98
|
+
/**
|
|
99
|
+
* 虚拟表格:横向滚动定位到「首个报错列」。
|
|
94
100
|
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
101
|
+
* 背景:rc-table 虚拟表格对「列」也做了虚拟化(BodyGrid 仅渲染横向视口内的列),
|
|
102
|
+
* 保存校验失败时报错列可能根本未渲染进 body DOM,无法用单元格测量定位(旧实现据此失效)。
|
|
103
|
+
* 而表头(thead)不被列虚拟化——渲染全部列且为真实测量宽度,故改以表头为列宽来源:
|
|
104
|
+
* 累加报错列之前各列宽、减去 fixed-left 列宽(固定列悬浮,不占滚动偏移)得目标 scrollLeft。
|
|
99
105
|
*
|
|
100
|
-
*
|
|
106
|
+
* 注意:ref.nativeElement 仅为 body 滚动容器,表头在其外层 table-container 内,需向上查找。
|
|
101
107
|
*/
|
|
102
|
-
export declare const scrollVirtualToErrorColumn: (tableRef: React.MutableRefObject<any>,
|
|
108
|
+
export declare const scrollVirtualToErrorColumn: (tableRef: React.MutableRefObject<any>, columns: any[], cellKey?: string | null) => void;
|
|
103
109
|
/**
|
|
104
110
|
* 深copy一个对象,并过滤掉其中的React节点
|
|
105
111
|
* @param value 需要深拷贝的对象
|
|
@@ -333,41 +333,62 @@ export const handleScrollToError = () => {
|
|
|
333
333
|
};
|
|
334
334
|
|
|
335
335
|
/**
|
|
336
|
-
*
|
|
336
|
+
* 把「首个报错列的 cellKey」映射成它在表头 th 中的可见列索引。
|
|
337
|
+
* 列序 = [选择列?(hasSelection 时占位 1), ...用户列];names 列的 cellKey 用 splitNames 结果。
|
|
338
|
+
* @returns 表头 th 下标;未命中返回 -1
|
|
339
|
+
*/
|
|
340
|
+
export const resolveErrorColumnIndex = (columns = [], cellKey, hasSelection) => {
|
|
341
|
+
const idx = (columns || []).findIndex(col => {
|
|
342
|
+
if (Array.isArray(col?.names)) {
|
|
343
|
+
return splitNames(col.names) === cellKey;
|
|
344
|
+
}
|
|
345
|
+
return String(col?.name ?? col?.dataIndex ?? col?.key) === cellKey;
|
|
346
|
+
});
|
|
347
|
+
if (idx < 0) {
|
|
348
|
+
return -1;
|
|
349
|
+
}
|
|
350
|
+
return hasSelection ? idx + 1 : idx;
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* 虚拟表格:横向滚动定位到「首个报错列」。
|
|
337
355
|
*
|
|
338
|
-
*
|
|
339
|
-
*
|
|
340
|
-
*
|
|
341
|
-
*
|
|
356
|
+
* 背景:rc-table 虚拟表格对「列」也做了虚拟化(BodyGrid 仅渲染横向视口内的列),
|
|
357
|
+
* 保存校验失败时报错列可能根本未渲染进 body DOM,无法用单元格测量定位(旧实现据此失效)。
|
|
358
|
+
* 而表头(thead)不被列虚拟化——渲染全部列且为真实测量宽度,故改以表头为列宽来源:
|
|
359
|
+
* 累加报错列之前各列宽、减去 fixed-left 列宽(固定列悬浮,不占滚动偏移)得目标 scrollLeft。
|
|
342
360
|
*
|
|
343
|
-
*
|
|
361
|
+
* 注意:ref.nativeElement 仅为 body 滚动容器,表头在其外层 table-container 内,需向上查找。
|
|
344
362
|
*/
|
|
345
|
-
export const scrollVirtualToErrorColumn = (tableRef,
|
|
363
|
+
export const scrollVirtualToErrorColumn = (tableRef, columns, cellKey) => {
|
|
346
364
|
const ref = tableRef?.current;
|
|
347
365
|
const root = ref?.nativeElement;
|
|
348
|
-
if (!ref?.scrollTo || !root ||
|
|
366
|
+
if (!ref?.scrollTo || !root || !cellKey) {
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
// body 容器在外层 table-container 内,表头与其同级,需从 container 取表头
|
|
370
|
+
const container = root.closest('[class*="table-container"]') || root.parentElement;
|
|
371
|
+
const headerCells = container?.querySelectorAll('thead [class*="table-cell"]');
|
|
372
|
+
if (!headerCells?.length) {
|
|
349
373
|
return;
|
|
350
374
|
}
|
|
351
|
-
const
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
if (
|
|
375
|
+
const hasSelection = !!container?.querySelector('thead [class*="selection-column"]');
|
|
376
|
+
const targetIndex = resolveErrorColumnIndex(columns, cellKey, hasSelection);
|
|
377
|
+
// -1 未命中 / 0 为首列(含 fixed-left),无需横向滚动
|
|
378
|
+
if (targetIndex <= 0 || targetIndex >= headerCells.length) {
|
|
355
379
|
return;
|
|
356
380
|
}
|
|
357
381
|
let offsetLeft = 0;
|
|
358
382
|
let fixedLeft = 0;
|
|
359
|
-
let
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
fixedLeft += width;
|
|
368
|
-
}
|
|
383
|
+
for (let i = 0; i < targetIndex; i += 1) {
|
|
384
|
+
const cell = headerCells[i];
|
|
385
|
+
const {
|
|
386
|
+
width = 0
|
|
387
|
+
} = cell.getBoundingClientRect() || {};
|
|
388
|
+
offsetLeft += width;
|
|
389
|
+
if (isFixStartCell(cell)) {
|
|
390
|
+
fixedLeft += width;
|
|
369
391
|
}
|
|
370
|
-
previousSibling = previousSibling.previousElementSibling;
|
|
371
392
|
}
|
|
372
393
|
ref.scrollTo({
|
|
373
394
|
left: Math.max(0, offsetLeft - fixedLeft)
|
|
@@ -46,6 +46,8 @@ export interface ValidateAllResult {
|
|
|
46
46
|
firstErrorPath: (string | number)[] | null;
|
|
47
47
|
/** 首个错误行的 rowKey(用于横向滚动时定位错误行 DOM),无错误为 null */
|
|
48
48
|
firstErrorRowKey: string | null;
|
|
49
|
+
/** 首个错误列的 cellKey(names 列为 splitNames,普通列为列名),用于横向滚动定位列,无错误为 null */
|
|
50
|
+
firstErrorColumnKey: string | null;
|
|
49
51
|
}
|
|
50
52
|
/**
|
|
51
53
|
* 对 form store 中 name 路径下的全量数组数据,逐行逐列用真实规则校验(脱离 DOM)。
|
|
@@ -82,5 +84,6 @@ export declare const runUnifiedValidation: ({ form, name, columns, config, error
|
|
|
82
84
|
hasError: boolean;
|
|
83
85
|
firstErrorIndex: number | null;
|
|
84
86
|
firstErrorRowKey: string | null;
|
|
87
|
+
firstErrorColumnKey: string | null;
|
|
85
88
|
}>;
|
|
86
89
|
export {};
|
|
@@ -199,6 +199,7 @@ export const validateAllRows = async ({
|
|
|
199
199
|
const errorMap = {};
|
|
200
200
|
let firstErrorPath = null;
|
|
201
201
|
let firstErrorRowKey = null;
|
|
202
|
+
let firstErrorColumnKey = null;
|
|
202
203
|
for (let index = 0; index < list.length; index += 1) {
|
|
203
204
|
const rowData = list[index];
|
|
204
205
|
// 行可能为空位(单行编辑增删残留),跳过
|
|
@@ -244,6 +245,7 @@ export const validateAllRows = async ({
|
|
|
244
245
|
if (!firstErrorPath) {
|
|
245
246
|
firstErrorPath = built.namePath;
|
|
246
247
|
firstErrorRowKey = rowKey;
|
|
248
|
+
firstErrorColumnKey = built.cellKey;
|
|
247
249
|
}
|
|
248
250
|
}
|
|
249
251
|
}
|
|
@@ -252,7 +254,8 @@ export const validateAllRows = async ({
|
|
|
252
254
|
hasError: !!firstErrorPath,
|
|
253
255
|
errorMap,
|
|
254
256
|
firstErrorPath,
|
|
255
|
-
firstErrorRowKey
|
|
257
|
+
firstErrorRowKey,
|
|
258
|
+
firstErrorColumnKey
|
|
256
259
|
};
|
|
257
260
|
};
|
|
258
261
|
|
|
@@ -301,7 +304,8 @@ export const runUnifiedValidation = async ({
|
|
|
301
304
|
hasError,
|
|
302
305
|
errorMap,
|
|
303
306
|
firstErrorPath,
|
|
304
|
-
firstErrorRowKey
|
|
307
|
+
firstErrorRowKey,
|
|
308
|
+
firstErrorColumnKey
|
|
305
309
|
} = await validateAllRows({
|
|
306
310
|
form,
|
|
307
311
|
name,
|
|
@@ -314,6 +318,7 @@ export const runUnifiedValidation = async ({
|
|
|
314
318
|
return {
|
|
315
319
|
hasError,
|
|
316
320
|
firstErrorIndex,
|
|
317
|
-
firstErrorRowKey
|
|
321
|
+
firstErrorRowKey,
|
|
322
|
+
firstErrorColumnKey
|
|
318
323
|
};
|
|
319
324
|
};
|