mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-05-17 06:07:38 +08:00
@@ -142,10 +142,19 @@ const formatCellValue = (val: any) => {
|
||||
try {
|
||||
if (val === null) return <span style={{ color: '#ccc' }}>NULL</span>;
|
||||
if (typeof val === 'object') {
|
||||
if (!Array.isArray(val) && !isPlainObject(val)) {
|
||||
return String(val);
|
||||
}
|
||||
const cached = objectCellPreviewCache.get(val);
|
||||
if (cached !== undefined) {
|
||||
return cached;
|
||||
}
|
||||
const topLevelSize = Array.isArray(val) ? val.length : Object.keys(val || {}).length;
|
||||
if (topLevelSize > 80) {
|
||||
const summary = Array.isArray(val) ? `[Array(${topLevelSize})]` : `{Object(${topLevelSize})}`;
|
||||
objectCellPreviewCache.set(val, summary);
|
||||
return summary;
|
||||
}
|
||||
try {
|
||||
const nextText = JSON.stringify(val);
|
||||
const previewText = nextText.length > TABLE_CELL_PREVIEW_MAX_CHARS ? `${nextText.slice(0, TABLE_CELL_PREVIEW_MAX_CHARS)}…` : nextText;
|
||||
@@ -191,6 +200,26 @@ const isCellValueEqualForDiff = (left: any, right: any): boolean => {
|
||||
return toFormText(left) === toFormText(right);
|
||||
};
|
||||
|
||||
// 渲染阶段轻量比较:避免对象值在 shouldCellUpdate 中反复深度序列化导致卡顿。
|
||||
const isCellValueEqualForRender = (left: any, right: any): boolean => {
|
||||
if (left === right) return true;
|
||||
const leftNullish = left === null || left === undefined;
|
||||
const rightNullish = right === null || right === undefined;
|
||||
if (leftNullish || rightNullish) return leftNullish && rightNullish;
|
||||
|
||||
const leftType = typeof left;
|
||||
const rightType = typeof right;
|
||||
if (leftType === 'object' || rightType === 'object') {
|
||||
// 对象仅按引用比较;真正的值差异在提交保存时再做严格比对。
|
||||
return false;
|
||||
}
|
||||
|
||||
if (leftType === 'string' || rightType === 'string') {
|
||||
return normalizeDateTimeString(String(left)) === normalizeDateTimeString(String(right));
|
||||
}
|
||||
return left === right;
|
||||
};
|
||||
|
||||
const INLINE_EDIT_MAX_CHARS = 2000;
|
||||
|
||||
const shouldOpenModalEditor = (val: any): boolean => {
|
||||
@@ -2067,7 +2096,7 @@ const DataGrid: React.FC<DataGridProps> = ({
|
||||
shouldCellUpdate: (record: Item, prevRecord: Item) => {
|
||||
const rowKeyChanged = record?.[GONAVI_ROW_KEY] !== prevRecord?.[GONAVI_ROW_KEY];
|
||||
if (rowKeyChanged) return true;
|
||||
return !isCellValueEqualForDiff(record?.[key], prevRecord?.[key]);
|
||||
return !isCellValueEqualForRender(record?.[key], prevRecord?.[key]);
|
||||
},
|
||||
onHeaderCell: (column: any) => ({
|
||||
width: column.width,
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
@@ -86,6 +87,16 @@ func normalizeCompositeQueryValue(v interface{}) interface{} {
|
||||
items[i] = normalizeQueryValue(rv.Index(i).Interface())
|
||||
}
|
||||
return items
|
||||
case reflect.Struct:
|
||||
// 部分驱动(如 Kingbase)会返回复杂结构体值,直接透传会导致前端渲染和比较开销激增。
|
||||
// 统一降级为可读字符串,避免对象深层序列化触发 UI 卡顿。
|
||||
if tm, ok := v.(time.Time); ok {
|
||||
return tm.Format(time.RFC3339Nano)
|
||||
}
|
||||
if stringer, ok := v.(fmt.Stringer); ok {
|
||||
return stringer.String()
|
||||
}
|
||||
return fmt.Sprintf("%v", v)
|
||||
default:
|
||||
return normalizeUnsafeIntegerForJS(rv, v)
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@ package db
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type duckMapLike map[any]any
|
||||
@@ -165,3 +167,31 @@ func TestNormalizeQueryValueWithDBType_JSONNumber(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type customStructValue struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
func (v customStructValue) String() string {
|
||||
return fmt.Sprintf("%s-%d", v.Name, v.Age)
|
||||
}
|
||||
|
||||
func TestNormalizeQueryValueWithDBType_StructToString(t *testing.T) {
|
||||
got := normalizeQueryValueWithDBType(customStructValue{Name: "alice", Age: 18}, "")
|
||||
if got != "alice-18" {
|
||||
t.Fatalf("结构体应降级为可读字符串,实际=%v(%T)", got, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizeQueryValueWithDBType_TimeStructToRFC3339(t *testing.T) {
|
||||
input := time.Date(2026, 3, 5, 18, 30, 15, 123456789, time.UTC)
|
||||
got := normalizeQueryValueWithDBType(input, "")
|
||||
text, ok := got.(string)
|
||||
if !ok {
|
||||
t.Fatalf("time.Time 应转为字符串,实际=%v(%T)", got, got)
|
||||
}
|
||||
if text != "2026-03-05T18:30:15.123456789Z" {
|
||||
t.Fatalf("time.Time 规整值异常,实际=%s", text)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user