@wordrhyme/auto-crud 1.0.0 → 1.0.2
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.
- package/README.md +76 -7
- package/dist/index.cjs +841 -213
- package/dist/index.d.cts +188 -36
- package/dist/index.d.ts +188 -36
- package/dist/index.js +833 -213
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1408,7 +1408,12 @@ function DataTableFilterList({ table, debounceMs = DEBOUNCE_MS$2, throttleMs = T
|
|
|
1408
1408
|
const [open, setOpen] = React.useState(false);
|
|
1409
1409
|
const addButtonRef = React.useRef(null);
|
|
1410
1410
|
const columns = React.useMemo(() => {
|
|
1411
|
-
return table.getAllColumns().filter((column) =>
|
|
1411
|
+
return table.getAllColumns().filter((column) => {
|
|
1412
|
+
if (!column.getCanFilter()) return false;
|
|
1413
|
+
const modes = column.columnDef.meta?.modes;
|
|
1414
|
+
if (modes && !modes.includes("advanced")) return false;
|
|
1415
|
+
return true;
|
|
1416
|
+
});
|
|
1412
1417
|
}, [table]);
|
|
1413
1418
|
const [filters, setFilters] = useReadableFilters(columns, { debounceMs });
|
|
1414
1419
|
const debouncedSetFilters = useDebouncedCallback(setFilters, debounceMs);
|
|
@@ -1890,7 +1895,12 @@ const REMOVE_FILTER_SHORTCUTS = ["backspace", "delete"];
|
|
|
1890
1895
|
function DataTableFilterMenu({ table, debounceMs = DEBOUNCE_MS$1, throttleMs = THROTTLE_MS$1, shallow = true, disabled,...props }) {
|
|
1891
1896
|
const id = React.useId();
|
|
1892
1897
|
const columns = React.useMemo(() => {
|
|
1893
|
-
return table.getAllColumns().filter((column) =>
|
|
1898
|
+
return table.getAllColumns().filter((column) => {
|
|
1899
|
+
if (!column.columnDef.enableColumnFilter) return false;
|
|
1900
|
+
const modes = column.columnDef.meta?.modes;
|
|
1901
|
+
if (modes && !modes.includes("command")) return false;
|
|
1902
|
+
return true;
|
|
1903
|
+
});
|
|
1894
1904
|
}, [table]);
|
|
1895
1905
|
const [open, setOpen] = React.useState(false);
|
|
1896
1906
|
const [selectedColumn, setSelectedColumn] = React.useState(null);
|
|
@@ -2647,7 +2657,7 @@ function DataTableViewOptions({ table, disabled,...props }) {
|
|
|
2647
2657
|
//#endregion
|
|
2648
2658
|
//#region src/components/auto-crud/auto-table-simple-filters.tsx
|
|
2649
2659
|
function AutoTableSimpleFilters({ table, shallow = false, filters: externalFilters, onFiltersChange }) {
|
|
2650
|
-
const columns = React.useMemo(() => table.getAllColumns().filter((col) => col.
|
|
2660
|
+
const columns = React.useMemo(() => table.getAllColumns().filter((col) => col.getCanFilter()), [table]);
|
|
2651
2661
|
const queryStateOptions = table.options.meta?.queryStateOptions;
|
|
2652
2662
|
const [queryFilters, setQueryFilters] = useReadableFilters(columns, {
|
|
2653
2663
|
...queryStateOptions,
|
|
@@ -2667,9 +2677,10 @@ function AutoTableSimpleFilters({ table, shallow = false, filters: externalFilte
|
|
|
2667
2677
|
React.useEffect(() => {
|
|
2668
2678
|
setMounted(true);
|
|
2669
2679
|
}, []);
|
|
2670
|
-
const
|
|
2671
|
-
|
|
2672
|
-
|
|
2680
|
+
const filterMap = React.useMemo(() => new Map(filters.map((f) => [f.id, f])), [filters]);
|
|
2681
|
+
const getFilterValue = React.useCallback((columnId) => {
|
|
2682
|
+
return filterMap.get(columnId)?.value;
|
|
2683
|
+
}, [filterMap]);
|
|
2673
2684
|
const updateFilter = React.useCallback((columnId, value) => {
|
|
2674
2685
|
const column = columns.find((c) => c.id === columnId);
|
|
2675
2686
|
if (!column) return;
|
|
@@ -2692,7 +2703,14 @@ function AutoTableSimpleFilters({ table, shallow = false, filters: externalFilte
|
|
|
2692
2703
|
setFilters
|
|
2693
2704
|
]);
|
|
2694
2705
|
const hasFilters = filters.length > 0;
|
|
2695
|
-
const filterColumns = React.useMemo(() => columns.filter((col) =>
|
|
2706
|
+
const filterColumns = React.useMemo(() => columns.filter((col) => {
|
|
2707
|
+
const meta = col.columnDef.meta;
|
|
2708
|
+
const enableFilter = col.columnDef.enableColumnFilter !== false;
|
|
2709
|
+
if (!meta?.variant || !enableFilter) return false;
|
|
2710
|
+
const modes = meta.modes;
|
|
2711
|
+
if (modes && !modes.includes("simple")) return false;
|
|
2712
|
+
return true;
|
|
2713
|
+
}), [columns]);
|
|
2696
2714
|
const [expanded, setExpanded] = React.useState(false);
|
|
2697
2715
|
const [visibleCount, setVisibleCount] = React.useState(null);
|
|
2698
2716
|
const containerRef = React.useRef(null);
|
|
@@ -2832,7 +2850,7 @@ function AutoTableSimpleFilters({ table, shallow = false, filters: externalFilte
|
|
|
2832
2850
|
}
|
|
2833
2851
|
function SimpleFacetedFilter({ title, options, multiple, value, onChange }) {
|
|
2834
2852
|
const [open, setOpen] = React.useState(false);
|
|
2835
|
-
const selectedValues = new Set(value);
|
|
2853
|
+
const selectedValues = React.useMemo(() => new Set(value), [value]);
|
|
2836
2854
|
const onItemSelect = (option, isSelected) => {
|
|
2837
2855
|
if (multiple) {
|
|
2838
2856
|
const newValues = new Set(selectedValues);
|
|
@@ -2863,6 +2881,12 @@ function SimpleFacetedFilter({ title, options, multiple, value, onChange }) {
|
|
|
2863
2881
|
tabIndex: 0,
|
|
2864
2882
|
className: "rounded-sm opacity-70 hover:opacity-100",
|
|
2865
2883
|
onClick: onReset,
|
|
2884
|
+
onKeyDown: (e) => {
|
|
2885
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
2886
|
+
e.preventDefault();
|
|
2887
|
+
onReset(e);
|
|
2888
|
+
}
|
|
2889
|
+
},
|
|
2866
2890
|
children: /* @__PURE__ */ jsx(XCircle, {})
|
|
2867
2891
|
}) : /* @__PURE__ */ jsx(PlusCircle, {}),
|
|
2868
2892
|
title,
|
|
@@ -2970,6 +2994,12 @@ function SimpleSliderFilter({ title, range, unit, value, onChange }) {
|
|
|
2970
2994
|
tabIndex: 0,
|
|
2971
2995
|
className: "rounded-sm opacity-70 hover:opacity-100",
|
|
2972
2996
|
onClick: onReset,
|
|
2997
|
+
onKeyDown: (e) => {
|
|
2998
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
2999
|
+
e.preventDefault();
|
|
3000
|
+
onReset(e);
|
|
3001
|
+
}
|
|
3002
|
+
},
|
|
2973
3003
|
children: /* @__PURE__ */ jsx(XCircle, {})
|
|
2974
3004
|
}) : /* @__PURE__ */ jsx(PlusCircle, {}),
|
|
2975
3005
|
/* @__PURE__ */ jsx("span", { children: title }),
|
|
@@ -3093,6 +3123,12 @@ function SimpleDateFilter({ title, multiple, value, onChange }) {
|
|
|
3093
3123
|
tabIndex: 0,
|
|
3094
3124
|
className: "rounded-sm opacity-70 hover:opacity-100",
|
|
3095
3125
|
onClick: onReset,
|
|
3126
|
+
onKeyDown: (e) => {
|
|
3127
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
3128
|
+
e.preventDefault();
|
|
3129
|
+
onReset(e);
|
|
3130
|
+
}
|
|
3131
|
+
},
|
|
3096
3132
|
children: /* @__PURE__ */ jsx(XCircle, {})
|
|
3097
3133
|
}) : /* @__PURE__ */ jsx(CalendarIcon, {}),
|
|
3098
3134
|
/* @__PURE__ */ jsx("span", { children: title }),
|
|
@@ -3705,33 +3741,47 @@ function inferFilterVariantByFieldName(fieldName) {
|
|
|
3705
3741
|
|
|
3706
3742
|
//#endregion
|
|
3707
3743
|
//#region src/lib/schema-bridge/zod-to-columns.tsx
|
|
3744
|
+
const parsedFieldCache = /* @__PURE__ */ new WeakMap();
|
|
3745
|
+
const baseTableSchemaCache = /* @__PURE__ */ new WeakMap();
|
|
3708
3746
|
/**
|
|
3709
3747
|
* 解析 Zod 字段类型
|
|
3710
3748
|
*/
|
|
3711
3749
|
function parseZodField(schema) {
|
|
3750
|
+
const cached = parsedFieldCache.get(schema);
|
|
3751
|
+
if (cached) return cached;
|
|
3752
|
+
const finalize = (result) => {
|
|
3753
|
+
parsedFieldCache.set(schema, result);
|
|
3754
|
+
return result;
|
|
3755
|
+
};
|
|
3712
3756
|
const def = schema._zod?.def ?? schema._def;
|
|
3713
|
-
const testNull = schema.safeParse(null);
|
|
3714
|
-
const required = !schema.safeParse(void 0).success && !testNull.success;
|
|
3715
3757
|
const typeName = def?.typeName;
|
|
3716
|
-
|
|
3758
|
+
const isOptional = def?.type === "optional" || typeName === "ZodOptional";
|
|
3759
|
+
const isNullable = def?.type === "nullable" || typeName === "ZodNullable";
|
|
3760
|
+
if (isOptional || isNullable) {
|
|
3717
3761
|
const innerType = def?.innerType;
|
|
3718
|
-
if (innerType) return {
|
|
3762
|
+
if (innerType) return finalize({
|
|
3719
3763
|
...parseZodField(innerType),
|
|
3720
3764
|
required: false
|
|
3721
|
-
};
|
|
3765
|
+
});
|
|
3722
3766
|
}
|
|
3723
|
-
|
|
3767
|
+
let required;
|
|
3768
|
+
if (isOptional || isNullable) required = false;
|
|
3769
|
+
else {
|
|
3770
|
+
const testNull = schema.safeParse(null);
|
|
3771
|
+
required = !schema.safeParse(void 0).success && !testNull.success;
|
|
3772
|
+
}
|
|
3773
|
+
if (def?.type === "boolean") return finalize({
|
|
3724
3774
|
type: "boolean",
|
|
3725
3775
|
required
|
|
3726
|
-
};
|
|
3727
|
-
if (def?.type === "number") return {
|
|
3776
|
+
});
|
|
3777
|
+
if (def?.type === "number") return finalize({
|
|
3728
3778
|
type: "number",
|
|
3729
3779
|
required
|
|
3730
|
-
};
|
|
3731
|
-
if (def?.type === "date") return {
|
|
3780
|
+
});
|
|
3781
|
+
if (def?.type === "date") return finalize({
|
|
3732
3782
|
type: "date",
|
|
3733
3783
|
required
|
|
3734
|
-
};
|
|
3784
|
+
});
|
|
3735
3785
|
if (def?.type === "enum") {
|
|
3736
3786
|
let enumValues$1;
|
|
3737
3787
|
if (def?.entries) {
|
|
@@ -3742,20 +3792,20 @@ function parseZodField(schema) {
|
|
|
3742
3792
|
const values = def.values;
|
|
3743
3793
|
if (Array.isArray(values)) enumValues$1 = values.map(String);
|
|
3744
3794
|
}
|
|
3745
|
-
if (enumValues$1 && enumValues$1.length > 0) return {
|
|
3795
|
+
if (enumValues$1 && enumValues$1.length > 0) return finalize({
|
|
3746
3796
|
type: "enum",
|
|
3747
3797
|
required,
|
|
3748
3798
|
enumValues: enumValues$1
|
|
3749
|
-
};
|
|
3799
|
+
});
|
|
3750
3800
|
}
|
|
3751
|
-
if (def?.type === "string") return {
|
|
3801
|
+
if (def?.type === "string") return finalize({
|
|
3752
3802
|
type: "string",
|
|
3753
3803
|
required
|
|
3754
|
-
};
|
|
3755
|
-
if (typeName === "ZodBoolean") return {
|
|
3804
|
+
});
|
|
3805
|
+
if (typeName === "ZodBoolean") return finalize({
|
|
3756
3806
|
type: "boolean",
|
|
3757
3807
|
required
|
|
3758
|
-
};
|
|
3808
|
+
});
|
|
3759
3809
|
let enumValues;
|
|
3760
3810
|
if (def?.entries) {
|
|
3761
3811
|
const entries = def.entries;
|
|
@@ -3765,51 +3815,51 @@ function parseZodField(schema) {
|
|
|
3765
3815
|
const values = def.values;
|
|
3766
3816
|
if (Array.isArray(values)) enumValues = values.map(String);
|
|
3767
3817
|
}
|
|
3768
|
-
if (enumValues && Array.isArray(enumValues) && enumValues.length > 0) return {
|
|
3818
|
+
if (enumValues && Array.isArray(enumValues) && enumValues.length > 0) return finalize({
|
|
3769
3819
|
type: "enum",
|
|
3770
3820
|
required,
|
|
3771
3821
|
enumValues
|
|
3772
|
-
};
|
|
3773
|
-
if (typeName === "ZodNumber") return {
|
|
3822
|
+
});
|
|
3823
|
+
if (typeName === "ZodNumber") return finalize({
|
|
3774
3824
|
type: "number",
|
|
3775
3825
|
required
|
|
3776
|
-
};
|
|
3777
|
-
if (typeName === "ZodDate") return {
|
|
3826
|
+
});
|
|
3827
|
+
if (typeName === "ZodDate") return finalize({
|
|
3778
3828
|
type: "date",
|
|
3779
3829
|
required
|
|
3780
|
-
};
|
|
3781
|
-
if (typeName === "ZodArray") return {
|
|
3830
|
+
});
|
|
3831
|
+
if (typeName === "ZodArray") return finalize({
|
|
3782
3832
|
type: "array",
|
|
3783
3833
|
required
|
|
3784
|
-
};
|
|
3785
|
-
if (typeName === "ZodObject") return {
|
|
3834
|
+
});
|
|
3835
|
+
if (typeName === "ZodObject") return finalize({
|
|
3786
3836
|
type: "object",
|
|
3787
3837
|
required
|
|
3788
|
-
};
|
|
3838
|
+
});
|
|
3789
3839
|
const testString = schema.safeParse("test");
|
|
3790
3840
|
const testNumber = schema.safeParse(123);
|
|
3791
3841
|
const testBoolean = schema.safeParse(true);
|
|
3792
3842
|
const testDate = schema.safeParse(17040672e5);
|
|
3793
|
-
if (testBoolean.success && !testString.success && !testNumber.success) return {
|
|
3843
|
+
if (testBoolean.success && !testString.success && !testNumber.success) return finalize({
|
|
3794
3844
|
type: "boolean",
|
|
3795
3845
|
required
|
|
3796
|
-
};
|
|
3797
|
-
if (testDate.success && !testString.success) return {
|
|
3846
|
+
});
|
|
3847
|
+
if (testDate.success && !testString.success) return finalize({
|
|
3798
3848
|
type: "date",
|
|
3799
3849
|
required
|
|
3800
|
-
};
|
|
3801
|
-
if (testNumber.success && !testString.success) return {
|
|
3850
|
+
});
|
|
3851
|
+
if (testNumber.success && !testString.success) return finalize({
|
|
3802
3852
|
type: "number",
|
|
3803
3853
|
required
|
|
3804
|
-
};
|
|
3805
|
-
if (schema.safeParse([]).success && !testString.success) return {
|
|
3854
|
+
});
|
|
3855
|
+
if (schema.safeParse([]).success && !testString.success) return finalize({
|
|
3806
3856
|
type: "array",
|
|
3807
3857
|
required
|
|
3808
|
-
};
|
|
3809
|
-
return {
|
|
3858
|
+
});
|
|
3859
|
+
return finalize({
|
|
3810
3860
|
type: "string",
|
|
3811
3861
|
required
|
|
3812
|
-
};
|
|
3862
|
+
});
|
|
3813
3863
|
}
|
|
3814
3864
|
/**
|
|
3815
3865
|
* 渲染单元格内容
|
|
@@ -3851,9 +3901,14 @@ function renderCell(value, type) {
|
|
|
3851
3901
|
* 从 Zod Schema 创建 Table Schema (ColumnDef 数组)
|
|
3852
3902
|
*/
|
|
3853
3903
|
function createTableSchema(schema, options) {
|
|
3904
|
+
const { overrides, exclude = [] } = options ?? {};
|
|
3905
|
+
const canCache = !(!!overrides && Object.keys(overrides).length > 0) && exclude.length === 0;
|
|
3906
|
+
if (canCache) {
|
|
3907
|
+
const cached = baseTableSchemaCache.get(schema);
|
|
3908
|
+
if (cached) return [...cached];
|
|
3909
|
+
}
|
|
3854
3910
|
const shape = schema.shape;
|
|
3855
3911
|
const columns = [];
|
|
3856
|
-
const { overrides, exclude = [] } = options ?? {};
|
|
3857
3912
|
for (const [key, fieldSchema] of Object.entries(shape)) {
|
|
3858
3913
|
if (exclude.includes(key)) continue;
|
|
3859
3914
|
const override = overrides?.[key];
|
|
@@ -3888,6 +3943,7 @@ function createTableSchema(schema, options) {
|
|
|
3888
3943
|
...restOverride
|
|
3889
3944
|
});
|
|
3890
3945
|
}
|
|
3946
|
+
if (canCache) baseTableSchemaCache.set(schema, columns);
|
|
3891
3947
|
return columns;
|
|
3892
3948
|
}
|
|
3893
3949
|
/**
|
|
@@ -3916,8 +3972,7 @@ function createSelectColumn() {
|
|
|
3916
3972
|
/**
|
|
3917
3973
|
* 创建操作列
|
|
3918
3974
|
*/
|
|
3919
|
-
function createActionsColumn(
|
|
3920
|
-
const { onEdit, onDelete, onView, onCopy } = config;
|
|
3975
|
+
function createActionsColumn(items) {
|
|
3921
3976
|
return {
|
|
3922
3977
|
id: "actions",
|
|
3923
3978
|
cell: ({ row }) => /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, {
|
|
@@ -3928,29 +3983,14 @@ function createActionsColumn(config) {
|
|
|
3928
3983
|
className: "flex size-8 p-0 data-[state=open]:bg-muted",
|
|
3929
3984
|
children: /* @__PURE__ */ jsx(Ellipsis, { className: "size-4" })
|
|
3930
3985
|
})
|
|
3931
|
-
}), /* @__PURE__ */
|
|
3986
|
+
}), /* @__PURE__ */ jsx(DropdownMenuContent, {
|
|
3932
3987
|
align: "end",
|
|
3933
3988
|
className: "w-40",
|
|
3934
|
-
children: [
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
onEdit && /* @__PURE__ */ jsx(DropdownMenuItem, {
|
|
3940
|
-
onClick: () => onEdit(row.original),
|
|
3941
|
-
children: "编辑"
|
|
3942
|
-
}),
|
|
3943
|
-
onCopy && /* @__PURE__ */ jsx(DropdownMenuItem, {
|
|
3944
|
-
onClick: () => onCopy(row.original),
|
|
3945
|
-
children: "复制"
|
|
3946
|
-
}),
|
|
3947
|
-
(onView || onEdit || onCopy) && onDelete && /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
|
|
3948
|
-
onDelete && /* @__PURE__ */ jsx(DropdownMenuItem, {
|
|
3949
|
-
className: "text-destructive",
|
|
3950
|
-
onClick: () => onDelete(row.original),
|
|
3951
|
-
children: "删除"
|
|
3952
|
-
})
|
|
3953
|
-
]
|
|
3989
|
+
children: items.map((item, i) => /* @__PURE__ */ jsxs(React.Fragment, { children: [item.separator && /* @__PURE__ */ jsx(DropdownMenuSeparator, {}), /* @__PURE__ */ jsx(DropdownMenuItem, {
|
|
3990
|
+
className: item.variant === "destructive" ? "text-destructive" : "",
|
|
3991
|
+
onClick: () => item.onClick(row.original),
|
|
3992
|
+
children: item.label
|
|
3993
|
+
})] }, i))
|
|
3954
3994
|
})] }),
|
|
3955
3995
|
size: 40
|
|
3956
3996
|
};
|
|
@@ -4404,6 +4444,13 @@ function useDataTable(props) {
|
|
|
4404
4444
|
filterableColumns,
|
|
4405
4445
|
enableAdvancedFilter
|
|
4406
4446
|
]);
|
|
4447
|
+
const getCoreRowModelFn = React.useMemo(() => getCoreRowModel(), []);
|
|
4448
|
+
const getFilteredRowModelFn = React.useMemo(() => getFilteredRowModel(), []);
|
|
4449
|
+
const getPaginationRowModelFn = React.useMemo(() => getPaginationRowModel(), []);
|
|
4450
|
+
const getSortedRowModelFn = React.useMemo(() => getSortedRowModel(), []);
|
|
4451
|
+
const getFacetedRowModelFn = React.useMemo(() => getFacetedRowModel(), []);
|
|
4452
|
+
const getFacetedUniqueValuesFn = React.useMemo(() => getFacetedUniqueValues(), []);
|
|
4453
|
+
const getFacetedMinMaxValuesFn = React.useMemo(() => getFacetedMinMaxValues(), []);
|
|
4407
4454
|
const table = useReactTable({
|
|
4408
4455
|
...tableProps,
|
|
4409
4456
|
columns,
|
|
@@ -4426,13 +4473,13 @@ function useDataTable(props) {
|
|
|
4426
4473
|
onSortingChange,
|
|
4427
4474
|
onColumnFiltersChange,
|
|
4428
4475
|
onColumnVisibilityChange: setColumnVisibility,
|
|
4429
|
-
getCoreRowModel:
|
|
4430
|
-
getFilteredRowModel:
|
|
4431
|
-
getPaginationRowModel:
|
|
4432
|
-
getSortedRowModel:
|
|
4433
|
-
getFacetedRowModel:
|
|
4434
|
-
getFacetedUniqueValues:
|
|
4435
|
-
getFacetedMinMaxValues:
|
|
4476
|
+
getCoreRowModel: getCoreRowModelFn,
|
|
4477
|
+
getFilteredRowModel: getFilteredRowModelFn,
|
|
4478
|
+
getPaginationRowModel: getPaginationRowModelFn,
|
|
4479
|
+
getSortedRowModel: getSortedRowModelFn,
|
|
4480
|
+
getFacetedRowModel: getFacetedRowModelFn,
|
|
4481
|
+
getFacetedUniqueValues: getFacetedUniqueValuesFn,
|
|
4482
|
+
getFacetedMinMaxValues: getFacetedMinMaxValuesFn,
|
|
4436
4483
|
manualPagination: true,
|
|
4437
4484
|
manualSorting: true,
|
|
4438
4485
|
manualFiltering: true,
|
|
@@ -4463,6 +4510,11 @@ function useDataTable(props) {
|
|
|
4463
4510
|
|
|
4464
4511
|
//#endregion
|
|
4465
4512
|
//#region src/components/auto-crud/auto-table.tsx
|
|
4513
|
+
const DEFAULT_MODES = [
|
|
4514
|
+
"simple",
|
|
4515
|
+
"advanced",
|
|
4516
|
+
"command"
|
|
4517
|
+
];
|
|
4466
4518
|
/** 过滤模式配置 */
|
|
4467
4519
|
const filterModeConfig = {
|
|
4468
4520
|
simple: {
|
|
@@ -4482,11 +4534,7 @@ const filterModeConfig = {
|
|
|
4482
4534
|
}
|
|
4483
4535
|
};
|
|
4484
4536
|
function AutoTable({ schema, data, pageCount = 1, overrides, enableRowSelection = true, exclude, actions, pinnedColumns, filterMode = "simple", onDeleteSelected, onUpdateSelected, batchUpdateFields, actionBarExtra, initialSorting, enableExport = true, onSelectedCountChange, getSelectedRows }) {
|
|
4485
|
-
const modes = filterMode ? Array.isArray(filterMode) ? filterMode : [filterMode] :
|
|
4486
|
-
"simple",
|
|
4487
|
-
"advanced",
|
|
4488
|
-
"command"
|
|
4489
|
-
];
|
|
4537
|
+
const modes = filterMode ? Array.isArray(filterMode) ? filterMode : [filterMode] : DEFAULT_MODES;
|
|
4490
4538
|
const [currentMode, setCurrentMode] = useQueryState("filterMode", parseAsStringEnum(modes).withDefault(modes[0] ?? "simple"));
|
|
4491
4539
|
const showToggle = modes.length > 1;
|
|
4492
4540
|
const { table, shallow, debounceMs, throttleMs } = useDataTable({
|
|
@@ -4508,13 +4556,18 @@ function AutoTable({ schema, data, pageCount = 1, overrides, enableRowSelection
|
|
|
4508
4556
|
]),
|
|
4509
4557
|
pageCount,
|
|
4510
4558
|
enableAdvancedFilter: true,
|
|
4511
|
-
initialState: {
|
|
4559
|
+
initialState: useMemo(() => ({
|
|
4512
4560
|
sorting: initialSorting,
|
|
4513
4561
|
columnPinning: pinnedColumns ?? {
|
|
4514
4562
|
left: enableRowSelection ? ["select"] : [],
|
|
4515
4563
|
right: actions ? ["actions"] : []
|
|
4516
4564
|
}
|
|
4517
|
-
},
|
|
4565
|
+
}), [
|
|
4566
|
+
initialSorting,
|
|
4567
|
+
pinnedColumns,
|
|
4568
|
+
enableRowSelection,
|
|
4569
|
+
actions
|
|
4570
|
+
]),
|
|
4518
4571
|
shallow: false,
|
|
4519
4572
|
clearOnDefault: true
|
|
4520
4573
|
});
|
|
@@ -4555,7 +4608,7 @@ function AutoTable({ schema, data, pageCount = 1, overrides, enableRowSelection
|
|
|
4555
4608
|
})
|
|
4556
4609
|
})
|
|
4557
4610
|
})] }) : null;
|
|
4558
|
-
const
|
|
4611
|
+
const filtersContent = useMemo(() => {
|
|
4559
4612
|
switch (currentMode) {
|
|
4560
4613
|
case "simple": return /* @__PURE__ */ jsx(AutoTableSimpleFilters, {
|
|
4561
4614
|
table,
|
|
@@ -4575,7 +4628,13 @@ function AutoTable({ schema, data, pageCount = 1, overrides, enableRowSelection
|
|
|
4575
4628
|
align: "start"
|
|
4576
4629
|
});
|
|
4577
4630
|
}
|
|
4578
|
-
}
|
|
4631
|
+
}, [
|
|
4632
|
+
currentMode,
|
|
4633
|
+
table,
|
|
4634
|
+
shallow,
|
|
4635
|
+
debounceMs,
|
|
4636
|
+
throttleMs
|
|
4637
|
+
]);
|
|
4579
4638
|
return /* @__PURE__ */ jsxs("div", {
|
|
4580
4639
|
className: "space-y-4",
|
|
4581
4640
|
children: [
|
|
@@ -4587,7 +4646,7 @@ function AutoTable({ schema, data, pageCount = 1, overrides, enableRowSelection
|
|
|
4587
4646
|
children: [currentMode !== "simple" && /* @__PURE__ */ jsx(DataTableSortList, {
|
|
4588
4647
|
table,
|
|
4589
4648
|
align: "start"
|
|
4590
|
-
}),
|
|
4649
|
+
}), filtersContent]
|
|
4591
4650
|
}), /* @__PURE__ */ jsxs("div", {
|
|
4592
4651
|
className: "flex items-center gap-2",
|
|
4593
4652
|
children: [
|
|
@@ -4819,10 +4878,462 @@ function AutoFormInner({ schema: zodSchema, initialValues, onSubmit, overrides,
|
|
|
4819
4878
|
}
|
|
4820
4879
|
const AutoForm = forwardRef(AutoFormInner);
|
|
4821
4880
|
|
|
4881
|
+
//#endregion
|
|
4882
|
+
//#region src/i18n/locale.ts
|
|
4883
|
+
const zhCN = {
|
|
4884
|
+
toolbar: {
|
|
4885
|
+
create: "新建",
|
|
4886
|
+
import: "导入",
|
|
4887
|
+
export: "导出",
|
|
4888
|
+
exportSelected: (count) => `导出(${count})`
|
|
4889
|
+
},
|
|
4890
|
+
rowActions: {
|
|
4891
|
+
view: "查看",
|
|
4892
|
+
edit: "编辑",
|
|
4893
|
+
copy: "复制",
|
|
4894
|
+
delete: "删除"
|
|
4895
|
+
},
|
|
4896
|
+
viewModal: { title: "详情" },
|
|
4897
|
+
boolean: {
|
|
4898
|
+
true: "是",
|
|
4899
|
+
false: "否"
|
|
4900
|
+
},
|
|
4901
|
+
formModal: {
|
|
4902
|
+
createTitle: "新建",
|
|
4903
|
+
editTitle: "编辑",
|
|
4904
|
+
cancel: "取消",
|
|
4905
|
+
create: "创建",
|
|
4906
|
+
save: "保存",
|
|
4907
|
+
submitting: "处理中..."
|
|
4908
|
+
},
|
|
4909
|
+
deleteModal: {
|
|
4910
|
+
title: "确认删除",
|
|
4911
|
+
description: "此操作无法撤销。确定要删除这条记录吗?",
|
|
4912
|
+
cancel: "取消",
|
|
4913
|
+
confirm: "确认删除",
|
|
4914
|
+
confirming: "删除中..."
|
|
4915
|
+
},
|
|
4916
|
+
importDialog: {
|
|
4917
|
+
title: "导入数据",
|
|
4918
|
+
uploadDescription: "上传 CSV 或 JSON 文件以批量导入数据",
|
|
4919
|
+
previewDescription: (count) => `已解析 ${count} 条数据,确认后开始导入`,
|
|
4920
|
+
importingDescription: "正在导入数据...",
|
|
4921
|
+
doneDescription: "导入完成",
|
|
4922
|
+
dragHint: "拖拽文件到此处,或点击选择文件",
|
|
4923
|
+
formatHint: "支持 CSV、JSON 格式",
|
|
4924
|
+
downloadTemplate: "下载 CSV 模板",
|
|
4925
|
+
moreColumns: (count) => `+${count} 列`,
|
|
4926
|
+
previewSummary: (rows, fields, format, previewLimit) => `共 ${rows} 条数据${previewLimit ? `(预览前 ${previewLimit} 条)` : ""},${fields} 个字段,格式: ${format.toUpperCase()}`,
|
|
4927
|
+
reselect: "重新选择",
|
|
4928
|
+
confirmImport: "确认导入",
|
|
4929
|
+
importingRows: (count) => `正在导入 ${count} 条数据...`,
|
|
4930
|
+
resultCreated: "新建",
|
|
4931
|
+
resultUpdated: "更新",
|
|
4932
|
+
resultSkipped: "跳过",
|
|
4933
|
+
resultFailed: "验证失败",
|
|
4934
|
+
failedRowHeader: "行号",
|
|
4935
|
+
failedErrorHeader: "错误",
|
|
4936
|
+
close: "关闭",
|
|
4937
|
+
continueImport: "继续导入",
|
|
4938
|
+
errorNoData: "文件中没有数据行",
|
|
4939
|
+
errorParseFailed: "文件解析失败",
|
|
4940
|
+
errorImportFailed: "导入失败"
|
|
4941
|
+
}
|
|
4942
|
+
};
|
|
4943
|
+
const enUS = {
|
|
4944
|
+
toolbar: {
|
|
4945
|
+
create: "New",
|
|
4946
|
+
import: "Import",
|
|
4947
|
+
export: "Export",
|
|
4948
|
+
exportSelected: (count) => `Export (${count})`
|
|
4949
|
+
},
|
|
4950
|
+
rowActions: {
|
|
4951
|
+
view: "View",
|
|
4952
|
+
edit: "Edit",
|
|
4953
|
+
copy: "Copy",
|
|
4954
|
+
delete: "Delete"
|
|
4955
|
+
},
|
|
4956
|
+
viewModal: { title: "Details" },
|
|
4957
|
+
boolean: {
|
|
4958
|
+
true: "Yes",
|
|
4959
|
+
false: "No"
|
|
4960
|
+
},
|
|
4961
|
+
formModal: {
|
|
4962
|
+
createTitle: "New",
|
|
4963
|
+
editTitle: "Edit",
|
|
4964
|
+
cancel: "Cancel",
|
|
4965
|
+
create: "Create",
|
|
4966
|
+
save: "Save",
|
|
4967
|
+
submitting: "Processing..."
|
|
4968
|
+
},
|
|
4969
|
+
deleteModal: {
|
|
4970
|
+
title: "Confirm Delete",
|
|
4971
|
+
description: "This action cannot be undone. Are you sure you want to delete this record?",
|
|
4972
|
+
cancel: "Cancel",
|
|
4973
|
+
confirm: "Delete",
|
|
4974
|
+
confirming: "Deleting..."
|
|
4975
|
+
},
|
|
4976
|
+
importDialog: {
|
|
4977
|
+
title: "Import Data",
|
|
4978
|
+
uploadDescription: "Upload a CSV or JSON file to bulk import data",
|
|
4979
|
+
previewDescription: (count) => `Parsed ${count} records, confirm to start importing`,
|
|
4980
|
+
importingDescription: "Importing data...",
|
|
4981
|
+
doneDescription: "Import complete",
|
|
4982
|
+
dragHint: "Drag file here, or click to select",
|
|
4983
|
+
formatHint: "Supports CSV, JSON formats",
|
|
4984
|
+
downloadTemplate: "Download CSV Template",
|
|
4985
|
+
moreColumns: (count) => `+${count} more`,
|
|
4986
|
+
previewSummary: (rows, fields, format, previewLimit) => `${rows} records${previewLimit ? ` (preview first ${previewLimit})` : ""}, ${fields} fields, format: ${format.toUpperCase()}`,
|
|
4987
|
+
reselect: "Reselect",
|
|
4988
|
+
confirmImport: "Confirm Import",
|
|
4989
|
+
importingRows: (count) => `Importing ${count} records...`,
|
|
4990
|
+
resultCreated: "Created",
|
|
4991
|
+
resultUpdated: "Updated",
|
|
4992
|
+
resultSkipped: "Skipped",
|
|
4993
|
+
resultFailed: "Failed",
|
|
4994
|
+
failedRowHeader: "Row",
|
|
4995
|
+
failedErrorHeader: "Error",
|
|
4996
|
+
close: "Close",
|
|
4997
|
+
continueImport: "Import More",
|
|
4998
|
+
errorNoData: "No data rows found in file",
|
|
4999
|
+
errorParseFailed: "Failed to parse file",
|
|
5000
|
+
errorImportFailed: "Import failed"
|
|
5001
|
+
}
|
|
5002
|
+
};
|
|
5003
|
+
const jaJP = {
|
|
5004
|
+
toolbar: {
|
|
5005
|
+
create: "新規作成",
|
|
5006
|
+
import: "インポート",
|
|
5007
|
+
export: "エクスポート",
|
|
5008
|
+
exportSelected: (count) => `エクスポート(${count})`
|
|
5009
|
+
},
|
|
5010
|
+
rowActions: {
|
|
5011
|
+
view: "詳細",
|
|
5012
|
+
edit: "編集",
|
|
5013
|
+
copy: "コピー",
|
|
5014
|
+
delete: "削除"
|
|
5015
|
+
},
|
|
5016
|
+
viewModal: { title: "詳細" },
|
|
5017
|
+
boolean: {
|
|
5018
|
+
true: "はい",
|
|
5019
|
+
false: "いいえ"
|
|
5020
|
+
},
|
|
5021
|
+
formModal: {
|
|
5022
|
+
createTitle: "新規作成",
|
|
5023
|
+
editTitle: "編集",
|
|
5024
|
+
cancel: "キャンセル",
|
|
5025
|
+
create: "作成",
|
|
5026
|
+
save: "保存",
|
|
5027
|
+
submitting: "処理中..."
|
|
5028
|
+
},
|
|
5029
|
+
deleteModal: {
|
|
5030
|
+
title: "削除の確認",
|
|
5031
|
+
description: "この操作は元に戻せません。このレコードを削除してもよろしいですか?",
|
|
5032
|
+
cancel: "キャンセル",
|
|
5033
|
+
confirm: "削除する",
|
|
5034
|
+
confirming: "削除中..."
|
|
5035
|
+
},
|
|
5036
|
+
importDialog: {
|
|
5037
|
+
title: "データのインポート",
|
|
5038
|
+
uploadDescription: "CSVまたはJSONファイルをアップロードして一括インポート",
|
|
5039
|
+
previewDescription: (count) => `${count}件のデータを解析しました。確認してインポートを開始します`,
|
|
5040
|
+
importingDescription: "データをインポート中...",
|
|
5041
|
+
doneDescription: "インポート完了",
|
|
5042
|
+
dragHint: "ファイルをここにドラッグするか、クリックして選択",
|
|
5043
|
+
formatHint: "CSV・JSON形式に対応",
|
|
5044
|
+
downloadTemplate: "CSVテンプレートをダウンロード",
|
|
5045
|
+
moreColumns: (count) => `+${count}列`,
|
|
5046
|
+
previewSummary: (rows, fields, format, previewLimit) => `${rows}件${previewLimit ? `(上位${previewLimit}件プレビュー)` : ""}、${fields}フィールド、形式: ${format.toUpperCase()}`,
|
|
5047
|
+
reselect: "再選択",
|
|
5048
|
+
confirmImport: "インポートを確認",
|
|
5049
|
+
importingRows: (count) => `${count}件をインポート中...`,
|
|
5050
|
+
resultCreated: "新規作成",
|
|
5051
|
+
resultUpdated: "更新",
|
|
5052
|
+
resultSkipped: "スキップ",
|
|
5053
|
+
resultFailed: "失敗",
|
|
5054
|
+
failedRowHeader: "行番号",
|
|
5055
|
+
failedErrorHeader: "エラー",
|
|
5056
|
+
close: "閉じる",
|
|
5057
|
+
continueImport: "続けてインポート",
|
|
5058
|
+
errorNoData: "ファイルにデータ行がありません",
|
|
5059
|
+
errorParseFailed: "ファイルの解析に失敗しました",
|
|
5060
|
+
errorImportFailed: "インポートに失敗しました"
|
|
5061
|
+
}
|
|
5062
|
+
};
|
|
5063
|
+
const koKR = {
|
|
5064
|
+
toolbar: {
|
|
5065
|
+
create: "새로 만들기",
|
|
5066
|
+
import: "가져오기",
|
|
5067
|
+
export: "내보내기",
|
|
5068
|
+
exportSelected: (count) => `내보내기(${count})`
|
|
5069
|
+
},
|
|
5070
|
+
rowActions: {
|
|
5071
|
+
view: "보기",
|
|
5072
|
+
edit: "편집",
|
|
5073
|
+
copy: "복사",
|
|
5074
|
+
delete: "삭제"
|
|
5075
|
+
},
|
|
5076
|
+
viewModal: { title: "상세 정보" },
|
|
5077
|
+
boolean: {
|
|
5078
|
+
true: "예",
|
|
5079
|
+
false: "아니요"
|
|
5080
|
+
},
|
|
5081
|
+
formModal: {
|
|
5082
|
+
createTitle: "새로 만들기",
|
|
5083
|
+
editTitle: "편집",
|
|
5084
|
+
cancel: "취소",
|
|
5085
|
+
create: "만들기",
|
|
5086
|
+
save: "저장",
|
|
5087
|
+
submitting: "처리 중..."
|
|
5088
|
+
},
|
|
5089
|
+
deleteModal: {
|
|
5090
|
+
title: "삭제 확인",
|
|
5091
|
+
description: "이 작업은 취소할 수 없습니다. 이 레코드를 삭제하시겠습니까?",
|
|
5092
|
+
cancel: "취소",
|
|
5093
|
+
confirm: "삭제",
|
|
5094
|
+
confirming: "삭제 중..."
|
|
5095
|
+
},
|
|
5096
|
+
importDialog: {
|
|
5097
|
+
title: "데이터 가져오기",
|
|
5098
|
+
uploadDescription: "CSV 또는 JSON 파일을 업로드하여 일괄 가져오기",
|
|
5099
|
+
previewDescription: (count) => `${count}개의 데이터를 분석했습니다. 확인 후 가져오기를 시작합니다`,
|
|
5100
|
+
importingDescription: "데이터를 가져오는 중...",
|
|
5101
|
+
doneDescription: "가져오기 완료",
|
|
5102
|
+
dragHint: "파일을 여기에 드래그하거나 클릭하여 선택",
|
|
5103
|
+
formatHint: "CSV, JSON 형식 지원",
|
|
5104
|
+
downloadTemplate: "CSV 템플릿 다운로드",
|
|
5105
|
+
moreColumns: (count) => `+${count}열 더`,
|
|
5106
|
+
previewSummary: (rows, fields, format, previewLimit) => `${rows}개 레코드${previewLimit ? ` (상위 ${previewLimit}개 미리보기)` : ""}, ${fields}개 필드, 형식: ${format.toUpperCase()}`,
|
|
5107
|
+
reselect: "다시 선택",
|
|
5108
|
+
confirmImport: "가져오기 확인",
|
|
5109
|
+
importingRows: (count) => `${count}개의 레코드를 가져오는 중...`,
|
|
5110
|
+
resultCreated: "생성됨",
|
|
5111
|
+
resultUpdated: "업데이트됨",
|
|
5112
|
+
resultSkipped: "건너뜀",
|
|
5113
|
+
resultFailed: "실패",
|
|
5114
|
+
failedRowHeader: "행 번호",
|
|
5115
|
+
failedErrorHeader: "오류",
|
|
5116
|
+
close: "닫기",
|
|
5117
|
+
continueImport: "계속 가져오기",
|
|
5118
|
+
errorNoData: "파일에 데이터 행이 없습니다",
|
|
5119
|
+
errorParseFailed: "파일 파싱에 실패했습니다",
|
|
5120
|
+
errorImportFailed: "가져오기에 실패했습니다"
|
|
5121
|
+
}
|
|
5122
|
+
};
|
|
5123
|
+
const frFR = {
|
|
5124
|
+
toolbar: {
|
|
5125
|
+
create: "Nouveau",
|
|
5126
|
+
import: "Importer",
|
|
5127
|
+
export: "Exporter",
|
|
5128
|
+
exportSelected: (count) => `Exporter (${count})`
|
|
5129
|
+
},
|
|
5130
|
+
rowActions: {
|
|
5131
|
+
view: "Voir",
|
|
5132
|
+
edit: "Modifier",
|
|
5133
|
+
copy: "Copier",
|
|
5134
|
+
delete: "Supprimer"
|
|
5135
|
+
},
|
|
5136
|
+
viewModal: { title: "Détails" },
|
|
5137
|
+
boolean: {
|
|
5138
|
+
true: "Oui",
|
|
5139
|
+
false: "Non"
|
|
5140
|
+
},
|
|
5141
|
+
formModal: {
|
|
5142
|
+
createTitle: "Nouveau",
|
|
5143
|
+
editTitle: "Modifier",
|
|
5144
|
+
cancel: "Annuler",
|
|
5145
|
+
create: "Créer",
|
|
5146
|
+
save: "Enregistrer",
|
|
5147
|
+
submitting: "En cours..."
|
|
5148
|
+
},
|
|
5149
|
+
deleteModal: {
|
|
5150
|
+
title: "Confirmer la suppression",
|
|
5151
|
+
description: "Cette action est irréversible. Voulez-vous vraiment supprimer cet enregistrement ?",
|
|
5152
|
+
cancel: "Annuler",
|
|
5153
|
+
confirm: "Supprimer",
|
|
5154
|
+
confirming: "Suppression..."
|
|
5155
|
+
},
|
|
5156
|
+
importDialog: {
|
|
5157
|
+
title: "Importer des données",
|
|
5158
|
+
uploadDescription: "Téléchargez un fichier CSV ou JSON pour importer en masse",
|
|
5159
|
+
previewDescription: (count) => `${count} enregistrements analysés, confirmez pour démarrer l'import`,
|
|
5160
|
+
importingDescription: "Importation en cours...",
|
|
5161
|
+
doneDescription: "Import terminé",
|
|
5162
|
+
dragHint: "Glissez un fichier ici ou cliquez pour sélectionner",
|
|
5163
|
+
formatHint: "Formats CSV et JSON acceptés",
|
|
5164
|
+
downloadTemplate: "Télécharger le modèle CSV",
|
|
5165
|
+
moreColumns: (count) => `+${count} colonnes`,
|
|
5166
|
+
previewSummary: (rows, fields, format, previewLimit) => `${rows} enregistrements${previewLimit ? ` (aperçu des ${previewLimit} premiers)` : ""}, ${fields} champs, format : ${format.toUpperCase()}`,
|
|
5167
|
+
reselect: "Resélectionner",
|
|
5168
|
+
confirmImport: "Confirmer l'import",
|
|
5169
|
+
importingRows: (count) => `Importation de ${count} enregistrements...`,
|
|
5170
|
+
resultCreated: "Créés",
|
|
5171
|
+
resultUpdated: "Mis à jour",
|
|
5172
|
+
resultSkipped: "Ignorés",
|
|
5173
|
+
resultFailed: "Échoués",
|
|
5174
|
+
failedRowHeader: "Ligne",
|
|
5175
|
+
failedErrorHeader: "Erreur",
|
|
5176
|
+
close: "Fermer",
|
|
5177
|
+
continueImport: "Continuer l'import",
|
|
5178
|
+
errorNoData: "Aucune ligne de données dans le fichier",
|
|
5179
|
+
errorParseFailed: "Échec de l'analyse du fichier",
|
|
5180
|
+
errorImportFailed: "Échec de l'importation"
|
|
5181
|
+
}
|
|
5182
|
+
};
|
|
5183
|
+
const deDE = {
|
|
5184
|
+
toolbar: {
|
|
5185
|
+
create: "Neu",
|
|
5186
|
+
import: "Importieren",
|
|
5187
|
+
export: "Exportieren",
|
|
5188
|
+
exportSelected: (count) => `Exportieren (${count})`
|
|
5189
|
+
},
|
|
5190
|
+
rowActions: {
|
|
5191
|
+
view: "Anzeigen",
|
|
5192
|
+
edit: "Bearbeiten",
|
|
5193
|
+
copy: "Kopieren",
|
|
5194
|
+
delete: "Löschen"
|
|
5195
|
+
},
|
|
5196
|
+
viewModal: { title: "Details" },
|
|
5197
|
+
boolean: {
|
|
5198
|
+
true: "Ja",
|
|
5199
|
+
false: "Nein"
|
|
5200
|
+
},
|
|
5201
|
+
formModal: {
|
|
5202
|
+
createTitle: "Neu",
|
|
5203
|
+
editTitle: "Bearbeiten",
|
|
5204
|
+
cancel: "Abbrechen",
|
|
5205
|
+
create: "Erstellen",
|
|
5206
|
+
save: "Speichern",
|
|
5207
|
+
submitting: "Wird verarbeitet..."
|
|
5208
|
+
},
|
|
5209
|
+
deleteModal: {
|
|
5210
|
+
title: "Löschen bestätigen",
|
|
5211
|
+
description: "Diese Aktion kann nicht rückgängig gemacht werden. Möchten Sie diesen Datensatz wirklich löschen?",
|
|
5212
|
+
cancel: "Abbrechen",
|
|
5213
|
+
confirm: "Löschen",
|
|
5214
|
+
confirming: "Wird gelöscht..."
|
|
5215
|
+
},
|
|
5216
|
+
importDialog: {
|
|
5217
|
+
title: "Daten importieren",
|
|
5218
|
+
uploadDescription: "CSV- oder JSON-Datei hochladen, um Daten massenweise zu importieren",
|
|
5219
|
+
previewDescription: (count) => `${count} Datensätze analysiert, bestätigen Sie den Import`,
|
|
5220
|
+
importingDescription: "Daten werden importiert...",
|
|
5221
|
+
doneDescription: "Import abgeschlossen",
|
|
5222
|
+
dragHint: "Datei hierher ziehen oder klicken zum Auswählen",
|
|
5223
|
+
formatHint: "CSV- und JSON-Formate werden unterstützt",
|
|
5224
|
+
downloadTemplate: "CSV-Vorlage herunterladen",
|
|
5225
|
+
moreColumns: (count) => `+${count} Spalten`,
|
|
5226
|
+
previewSummary: (rows, fields, format, previewLimit) => `${rows} Datensätze${previewLimit ? ` (Vorschau der ersten ${previewLimit})` : ""}, ${fields} Felder, Format: ${format.toUpperCase()}`,
|
|
5227
|
+
reselect: "Neu auswählen",
|
|
5228
|
+
confirmImport: "Import bestätigen",
|
|
5229
|
+
importingRows: (count) => `${count} Datensätze werden importiert...`,
|
|
5230
|
+
resultCreated: "Erstellt",
|
|
5231
|
+
resultUpdated: "Aktualisiert",
|
|
5232
|
+
resultSkipped: "Übersprungen",
|
|
5233
|
+
resultFailed: "Fehlgeschlagen",
|
|
5234
|
+
failedRowHeader: "Zeile",
|
|
5235
|
+
failedErrorHeader: "Fehler",
|
|
5236
|
+
close: "Schließen",
|
|
5237
|
+
continueImport: "Weiteren Import starten",
|
|
5238
|
+
errorNoData: "Keine Datenzeilen in der Datei",
|
|
5239
|
+
errorParseFailed: "Datei konnte nicht analysiert werden",
|
|
5240
|
+
errorImportFailed: "Import fehlgeschlagen"
|
|
5241
|
+
}
|
|
5242
|
+
};
|
|
5243
|
+
const esES = {
|
|
5244
|
+
toolbar: {
|
|
5245
|
+
create: "Nuevo",
|
|
5246
|
+
import: "Importar",
|
|
5247
|
+
export: "Exportar",
|
|
5248
|
+
exportSelected: (count) => `Exportar (${count})`
|
|
5249
|
+
},
|
|
5250
|
+
rowActions: {
|
|
5251
|
+
view: "Ver",
|
|
5252
|
+
edit: "Editar",
|
|
5253
|
+
copy: "Copiar",
|
|
5254
|
+
delete: "Eliminar"
|
|
5255
|
+
},
|
|
5256
|
+
viewModal: { title: "Detalles" },
|
|
5257
|
+
boolean: {
|
|
5258
|
+
true: "Sí",
|
|
5259
|
+
false: "No"
|
|
5260
|
+
},
|
|
5261
|
+
formModal: {
|
|
5262
|
+
createTitle: "Nuevo",
|
|
5263
|
+
editTitle: "Editar",
|
|
5264
|
+
cancel: "Cancelar",
|
|
5265
|
+
create: "Crear",
|
|
5266
|
+
save: "Guardar",
|
|
5267
|
+
submitting: "Procesando..."
|
|
5268
|
+
},
|
|
5269
|
+
deleteModal: {
|
|
5270
|
+
title: "Confirmar eliminación",
|
|
5271
|
+
description: "Esta acción no se puede deshacer. ¿Está seguro de que desea eliminar este registro?",
|
|
5272
|
+
cancel: "Cancelar",
|
|
5273
|
+
confirm: "Eliminar",
|
|
5274
|
+
confirming: "Eliminando..."
|
|
5275
|
+
},
|
|
5276
|
+
importDialog: {
|
|
5277
|
+
title: "Importar datos",
|
|
5278
|
+
uploadDescription: "Suba un archivo CSV o JSON para importar datos de forma masiva",
|
|
5279
|
+
previewDescription: (count) => `Se analizaron ${count} registros, confirme para iniciar la importación`,
|
|
5280
|
+
importingDescription: "Importando datos...",
|
|
5281
|
+
doneDescription: "Importación completada",
|
|
5282
|
+
dragHint: "Arrastre el archivo aquí o haga clic para seleccionar",
|
|
5283
|
+
formatHint: "Formatos CSV y JSON compatibles",
|
|
5284
|
+
downloadTemplate: "Descargar plantilla CSV",
|
|
5285
|
+
moreColumns: (count) => `+${count} columnas`,
|
|
5286
|
+
previewSummary: (rows, fields, format, previewLimit) => `${rows} registros${previewLimit ? ` (vista previa de los primeros ${previewLimit})` : ""}, ${fields} campos, formato: ${format.toUpperCase()}`,
|
|
5287
|
+
reselect: "Volver a seleccionar",
|
|
5288
|
+
confirmImport: "Confirmar importación",
|
|
5289
|
+
importingRows: (count) => `Importando ${count} registros...`,
|
|
5290
|
+
resultCreated: "Creados",
|
|
5291
|
+
resultUpdated: "Actualizados",
|
|
5292
|
+
resultSkipped: "Omitidos",
|
|
5293
|
+
resultFailed: "Fallidos",
|
|
5294
|
+
failedRowHeader: "Fila",
|
|
5295
|
+
failedErrorHeader: "Error",
|
|
5296
|
+
close: "Cerrar",
|
|
5297
|
+
continueImport: "Continuar importando",
|
|
5298
|
+
errorNoData: "No se encontraron filas de datos en el archivo",
|
|
5299
|
+
errorParseFailed: "Error al analizar el archivo",
|
|
5300
|
+
errorImportFailed: "Error en la importación"
|
|
5301
|
+
}
|
|
5302
|
+
};
|
|
5303
|
+
const BUILTIN_LOCALES = {
|
|
5304
|
+
"zh-CN": zhCN,
|
|
5305
|
+
"en-US": enUS,
|
|
5306
|
+
"ja-JP": jaJP,
|
|
5307
|
+
"ko-KR": koKR,
|
|
5308
|
+
"fr-FR": frFR,
|
|
5309
|
+
"de-DE": deDE,
|
|
5310
|
+
"es-ES": esES
|
|
5311
|
+
};
|
|
5312
|
+
function deepMerge(target, source) {
|
|
5313
|
+
const result = { ...target };
|
|
5314
|
+
for (const key of Object.keys(source)) {
|
|
5315
|
+
const sv = source[key];
|
|
5316
|
+
const tv = target[key];
|
|
5317
|
+
if (sv !== void 0 && sv !== null && typeof sv === "object" && !Array.isArray(sv) && typeof tv === "object" && tv !== null && !Array.isArray(tv)) result[key] = deepMerge(tv, sv);
|
|
5318
|
+
else if (sv !== void 0) result[key] = sv;
|
|
5319
|
+
}
|
|
5320
|
+
return result;
|
|
5321
|
+
}
|
|
5322
|
+
/**
|
|
5323
|
+
* 解析 locale prop 为完整的 AutoCrudLocale
|
|
5324
|
+
* - string → 内置语言(fallback: zh-CN)
|
|
5325
|
+
* - object → 以 zh-CN 为基础深合并
|
|
5326
|
+
*/
|
|
5327
|
+
function resolveLocale(localeProp) {
|
|
5328
|
+
if (!localeProp) return zhCN;
|
|
5329
|
+
if (typeof localeProp === "string") return BUILTIN_LOCALES[localeProp] ?? zhCN;
|
|
5330
|
+
return deepMerge(zhCN, localeProp);
|
|
5331
|
+
}
|
|
5332
|
+
|
|
4822
5333
|
//#endregion
|
|
4823
5334
|
//#region src/components/auto-crud/crud-form-modal.tsx
|
|
4824
|
-
function CrudFormModal({ open, onOpenChange, mode, schema, initialValues, onSubmit, loading = false, variant = "dialog", overrides, title, labelAlign, labelWidth }) {
|
|
4825
|
-
const defaultTitle = mode === "create" ?
|
|
5335
|
+
function CrudFormModal({ open, onOpenChange, mode, schema, initialValues, onSubmit, loading = false, variant = "dialog", overrides, title, locale = zhCN.formModal, labelAlign, labelWidth }) {
|
|
5336
|
+
const defaultTitle = mode === "create" ? locale.createTitle : locale.editTitle;
|
|
4826
5337
|
const formRef = useRef(null);
|
|
4827
5338
|
const handleSubmit = async () => {
|
|
4828
5339
|
await formRef.current?.submit();
|
|
@@ -4838,12 +5349,12 @@ function CrudFormModal({ open, onOpenChange, mode, schema, initialValues, onSubm
|
|
|
4838
5349
|
type: "button",
|
|
4839
5350
|
variant: "outline",
|
|
4840
5351
|
onClick: () => onOpenChange(false),
|
|
4841
|
-
children:
|
|
5352
|
+
children: locale.cancel
|
|
4842
5353
|
}), /* @__PURE__ */ jsx(Button, {
|
|
4843
5354
|
type: "button",
|
|
4844
5355
|
onClick: handleSubmit,
|
|
4845
5356
|
disabled: loading,
|
|
4846
|
-
children: loading ?
|
|
5357
|
+
children: loading ? locale.submitting : mode === "create" ? locale.create : locale.save
|
|
4847
5358
|
})]
|
|
4848
5359
|
}),
|
|
4849
5360
|
children: /* @__PURE__ */ jsx(AutoForm, {
|
|
@@ -4863,7 +5374,7 @@ function CrudFormModal({ open, onOpenChange, mode, schema, initialValues, onSubm
|
|
|
4863
5374
|
|
|
4864
5375
|
//#endregion
|
|
4865
5376
|
//#region src/components/auto-crud/import-dialog.tsx
|
|
4866
|
-
function ImportDialog({ open, onOpenChange, onImport, columns = [], title =
|
|
5377
|
+
function ImportDialog({ open, onOpenChange, onImport, columns = [], title, locale = zhCN.importDialog }) {
|
|
4867
5378
|
const [step, setStep] = React.useState("upload");
|
|
4868
5379
|
const [parsedData, setParsedData] = React.useState(null);
|
|
4869
5380
|
const [error, setError] = React.useState(null);
|
|
@@ -4886,13 +5397,13 @@ function ImportDialog({ open, onOpenChange, onImport, columns = [], title = "导
|
|
|
4886
5397
|
try {
|
|
4887
5398
|
const data = await parseImportFile(file);
|
|
4888
5399
|
if (data.rows.length === 0) {
|
|
4889
|
-
setError(
|
|
5400
|
+
setError(locale.errorNoData);
|
|
4890
5401
|
return;
|
|
4891
5402
|
}
|
|
4892
5403
|
setParsedData(data);
|
|
4893
5404
|
setStep("preview");
|
|
4894
5405
|
} catch (e) {
|
|
4895
|
-
setError(e instanceof Error ? e.message :
|
|
5406
|
+
setError(e instanceof Error ? e.message : locale.errorParseFailed);
|
|
4896
5407
|
}
|
|
4897
5408
|
}, []);
|
|
4898
5409
|
const handleDrop = React.useCallback((e) => {
|
|
@@ -4912,7 +5423,7 @@ function ImportDialog({ open, onOpenChange, onImport, columns = [], title = "导
|
|
|
4912
5423
|
setResult(await onImport(parsedData.rows));
|
|
4913
5424
|
setStep("result");
|
|
4914
5425
|
} catch (e) {
|
|
4915
|
-
setError(e instanceof Error ? e.message :
|
|
5426
|
+
setError(e instanceof Error ? e.message : locale.errorImportFailed);
|
|
4916
5427
|
setStep("preview");
|
|
4917
5428
|
}
|
|
4918
5429
|
}, [parsedData, onImport]);
|
|
@@ -4932,11 +5443,11 @@ function ImportDialog({ open, onOpenChange, onImport, columns = [], title = "导
|
|
|
4932
5443
|
onOpenChange: handleOpenChange,
|
|
4933
5444
|
children: /* @__PURE__ */ jsxs(DialogContent, {
|
|
4934
5445
|
className: "sm:max-w-[600px]",
|
|
4935
|
-
children: [/* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsx(DialogTitle, { children: title }), /* @__PURE__ */ jsxs(DialogDescription, { children: [
|
|
4936
|
-
step === "upload" &&
|
|
4937
|
-
step === "preview" &&
|
|
4938
|
-
step === "importing" &&
|
|
4939
|
-
step === "result" &&
|
|
5446
|
+
children: [/* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsx(DialogTitle, { children: title ?? locale.title }), /* @__PURE__ */ jsxs(DialogDescription, { children: [
|
|
5447
|
+
step === "upload" && locale.uploadDescription,
|
|
5448
|
+
step === "preview" && locale.previewDescription(parsedData?.rows.length ?? 0),
|
|
5449
|
+
step === "importing" && locale.importingDescription,
|
|
5450
|
+
step === "result" && locale.doneDescription
|
|
4940
5451
|
] })] }), /* @__PURE__ */ jsxs("div", {
|
|
4941
5452
|
className: "space-y-4",
|
|
4942
5453
|
children: [
|
|
@@ -4967,11 +5478,11 @@ function ImportDialog({ open, onOpenChange, onImport, columns = [], title = "导
|
|
|
4967
5478
|
}),
|
|
4968
5479
|
/* @__PURE__ */ jsx("p", {
|
|
4969
5480
|
className: "text-sm text-muted-foreground",
|
|
4970
|
-
children:
|
|
5481
|
+
children: locale.dragHint
|
|
4971
5482
|
}),
|
|
4972
5483
|
/* @__PURE__ */ jsx("p", {
|
|
4973
5484
|
className: "text-xs text-muted-foreground/60",
|
|
4974
|
-
children:
|
|
5485
|
+
children: locale.formatHint
|
|
4975
5486
|
})
|
|
4976
5487
|
]
|
|
4977
5488
|
}), /* @__PURE__ */ jsx("input", {
|
|
@@ -4986,7 +5497,7 @@ function ImportDialog({ open, onOpenChange, onImport, columns = [], title = "导
|
|
|
4986
5497
|
size: "sm",
|
|
4987
5498
|
className: "w-full",
|
|
4988
5499
|
onClick: handleDownloadTemplate,
|
|
4989
|
-
children:
|
|
5500
|
+
children: locale.downloadTemplate
|
|
4990
5501
|
})] }),
|
|
4991
5502
|
step === "preview" && parsedData && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4992
5503
|
/* @__PURE__ */ jsx("div", {
|
|
@@ -5006,13 +5517,9 @@ function ImportDialog({ open, onOpenChange, onImport, columns = [], title = "导
|
|
|
5006
5517
|
className: "px-3 py-2 text-left font-medium text-muted-foreground",
|
|
5007
5518
|
children: h
|
|
5008
5519
|
}, h)),
|
|
5009
|
-
parsedData.headers.length > 6 && /* @__PURE__ */
|
|
5520
|
+
parsedData.headers.length > 6 && /* @__PURE__ */ jsx("th", {
|
|
5010
5521
|
className: "px-3 py-2 text-left font-medium text-muted-foreground",
|
|
5011
|
-
children:
|
|
5012
|
-
"+",
|
|
5013
|
-
parsedData.headers.length - 6,
|
|
5014
|
-
" 列"
|
|
5015
|
-
]
|
|
5522
|
+
children: locale.moreColumns(parsedData.headers.length - 6)
|
|
5016
5523
|
})
|
|
5017
5524
|
] })
|
|
5018
5525
|
}), /* @__PURE__ */ jsx("tbody", { children: parsedData.rows.slice(0, 10).map((row, i) => /* @__PURE__ */ jsxs("tr", {
|
|
@@ -5035,40 +5542,27 @@ function ImportDialog({ open, onOpenChange, onImport, columns = [], title = "导
|
|
|
5035
5542
|
})
|
|
5036
5543
|
})
|
|
5037
5544
|
}),
|
|
5038
|
-
/* @__PURE__ */
|
|
5545
|
+
/* @__PURE__ */ jsx("p", {
|
|
5039
5546
|
className: "text-sm text-muted-foreground",
|
|
5040
|
-
children:
|
|
5041
|
-
"共 ",
|
|
5042
|
-
parsedData.rows.length,
|
|
5043
|
-
" 条数据",
|
|
5044
|
-
parsedData.rows.length > 10 && "(预览前 10 条)",
|
|
5045
|
-
",",
|
|
5046
|
-
parsedData.headers.length,
|
|
5047
|
-
" 个字段 ,格式: ",
|
|
5048
|
-
parsedData.format.toUpperCase()
|
|
5049
|
-
]
|
|
5547
|
+
children: locale.previewSummary(parsedData.rows.length, parsedData.headers.length, parsedData.format, parsedData.rows.length > 10 ? 10 : void 0)
|
|
5050
5548
|
}),
|
|
5051
5549
|
/* @__PURE__ */ jsxs("div", {
|
|
5052
5550
|
className: "flex gap-2 justify-end",
|
|
5053
5551
|
children: [/* @__PURE__ */ jsx(Button, {
|
|
5054
5552
|
variant: "outline",
|
|
5055
5553
|
onClick: reset,
|
|
5056
|
-
children:
|
|
5554
|
+
children: locale.reselect
|
|
5057
5555
|
}), /* @__PURE__ */ jsx(Button, {
|
|
5058
5556
|
onClick: handleImport,
|
|
5059
|
-
children:
|
|
5557
|
+
children: locale.confirmImport
|
|
5060
5558
|
})]
|
|
5061
5559
|
})
|
|
5062
5560
|
] }),
|
|
5063
5561
|
step === "importing" && /* @__PURE__ */ jsxs("div", {
|
|
5064
5562
|
className: "flex flex-col items-center gap-4 py-8",
|
|
5065
|
-
children: [/* @__PURE__ */ jsx("div", { className: "h-8 w-8 animate-spin rounded-full border-4 border-primary border-t-transparent" }), /* @__PURE__ */
|
|
5563
|
+
children: [/* @__PURE__ */ jsx("div", { className: "h-8 w-8 animate-spin rounded-full border-4 border-primary border-t-transparent" }), /* @__PURE__ */ jsx("p", {
|
|
5066
5564
|
className: "text-sm text-muted-foreground",
|
|
5067
|
-
children:
|
|
5068
|
-
"正在导入 ",
|
|
5069
|
-
parsedData?.rows.length ?? 0,
|
|
5070
|
-
" 条数据..."
|
|
5071
|
-
]
|
|
5565
|
+
children: locale.importingRows(parsedData?.rows.length ?? 0)
|
|
5072
5566
|
})]
|
|
5073
5567
|
}),
|
|
5074
5568
|
step === "result" && result && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("div", {
|
|
@@ -5083,7 +5577,7 @@ function ImportDialog({ open, onOpenChange, onImport, columns = [], title = "导
|
|
|
5083
5577
|
children: result.success
|
|
5084
5578
|
}), /* @__PURE__ */ jsx("p", {
|
|
5085
5579
|
className: "text-xs text-green-600/80",
|
|
5086
|
-
children:
|
|
5580
|
+
children: locale.resultCreated
|
|
5087
5581
|
})]
|
|
5088
5582
|
}),
|
|
5089
5583
|
(result.updated ?? 0) > 0 && /* @__PURE__ */ jsxs("div", {
|
|
@@ -5093,7 +5587,7 @@ function ImportDialog({ open, onOpenChange, onImport, columns = [], title = "导
|
|
|
5093
5587
|
children: result.updated
|
|
5094
5588
|
}), /* @__PURE__ */ jsx("p", {
|
|
5095
5589
|
className: "text-xs text-blue-600/80",
|
|
5096
|
-
children:
|
|
5590
|
+
children: locale.resultUpdated
|
|
5097
5591
|
})]
|
|
5098
5592
|
}),
|
|
5099
5593
|
result.skipped > 0 && /* @__PURE__ */ jsxs("div", {
|
|
@@ -5103,7 +5597,7 @@ function ImportDialog({ open, onOpenChange, onImport, columns = [], title = "导
|
|
|
5103
5597
|
children: result.skipped
|
|
5104
5598
|
}), /* @__PURE__ */ jsx("p", {
|
|
5105
5599
|
className: "text-xs text-yellow-600/80",
|
|
5106
|
-
children:
|
|
5600
|
+
children: locale.resultSkipped
|
|
5107
5601
|
})]
|
|
5108
5602
|
}),
|
|
5109
5603
|
result.failed.length > 0 && /* @__PURE__ */ jsxs("div", {
|
|
@@ -5113,7 +5607,7 @@ function ImportDialog({ open, onOpenChange, onImport, columns = [], title = "导
|
|
|
5113
5607
|
children: result.failed.length
|
|
5114
5608
|
}), /* @__PURE__ */ jsx("p", {
|
|
5115
5609
|
className: "text-xs text-red-600/80",
|
|
5116
|
-
children:
|
|
5610
|
+
children: locale.resultFailed
|
|
5117
5611
|
})]
|
|
5118
5612
|
})
|
|
5119
5613
|
]
|
|
@@ -5127,10 +5621,10 @@ function ImportDialog({ open, onOpenChange, onImport, columns = [], title = "导
|
|
|
5127
5621
|
className: "sticky top-0 bg-red-50 dark:bg-red-950/30",
|
|
5128
5622
|
children: /* @__PURE__ */ jsxs("tr", { children: [/* @__PURE__ */ jsx("th", {
|
|
5129
5623
|
className: "px-3 py-2 text-left font-medium text-red-600",
|
|
5130
|
-
children:
|
|
5624
|
+
children: locale.failedRowHeader
|
|
5131
5625
|
}), /* @__PURE__ */ jsx("th", {
|
|
5132
5626
|
className: "px-3 py-2 text-left font-medium text-red-600",
|
|
5133
|
-
children:
|
|
5627
|
+
children: locale.failedErrorHeader
|
|
5134
5628
|
})] })
|
|
5135
5629
|
}), /* @__PURE__ */ jsx("tbody", { children: result.failed.map((f) => /* @__PURE__ */ jsxs("tr", {
|
|
5136
5630
|
className: "border-t border-red-100 dark:border-red-900",
|
|
@@ -5150,11 +5644,11 @@ function ImportDialog({ open, onOpenChange, onImport, columns = [], title = "导
|
|
|
5150
5644
|
children: [/* @__PURE__ */ jsx(Button, {
|
|
5151
5645
|
variant: "outline",
|
|
5152
5646
|
onClick: () => handleOpenChange(false),
|
|
5153
|
-
children:
|
|
5647
|
+
children: locale.close
|
|
5154
5648
|
}), /* @__PURE__ */ jsx(Button, {
|
|
5155
5649
|
variant: "outline",
|
|
5156
5650
|
onClick: reset,
|
|
5157
|
-
children:
|
|
5651
|
+
children: locale.continueImport
|
|
5158
5652
|
})]
|
|
5159
5653
|
})] }),
|
|
5160
5654
|
error && /* @__PURE__ */ jsx("div", {
|
|
@@ -5176,26 +5670,51 @@ function ImportDialog({ open, onOpenChange, onImport, columns = [], title = "导
|
|
|
5176
5670
|
function buildTableOverrides(fields, legacyOverrides) {
|
|
5177
5671
|
const result = { ...legacyOverrides };
|
|
5178
5672
|
if (fields) for (const [key, config] of Object.entries(fields)) {
|
|
5673
|
+
const tableMeta = config.table !== false && typeof config.table === "object" ? config.table.meta : void 0;
|
|
5179
5674
|
let filterMeta;
|
|
5180
|
-
if (config.filter && config.filter
|
|
5181
|
-
|
|
5182
|
-
|
|
5675
|
+
if (config.filter && typeof config.filter === "object") {
|
|
5676
|
+
if (config.filter.enabled !== false && config.filter.hidden !== true) {
|
|
5677
|
+
const { enabled: _, hidden: __,...filterProps } = config.filter;
|
|
5678
|
+
if (Object.keys(filterProps).length > 0) filterMeta = filterProps;
|
|
5679
|
+
}
|
|
5680
|
+
}
|
|
5681
|
+
if (config.filter === false) result[key] = {
|
|
5682
|
+
...result[key],
|
|
5683
|
+
enableColumnFilter: false
|
|
5684
|
+
};
|
|
5685
|
+
else if (config.filter && typeof config.filter === "object") {
|
|
5686
|
+
if (config.filter.enabled === false || config.filter.hidden === true) result[key] = {
|
|
5687
|
+
...result[key],
|
|
5688
|
+
enableColumnFilter: false
|
|
5689
|
+
};
|
|
5183
5690
|
}
|
|
5184
|
-
result[key] = {
|
|
5691
|
+
if (tableMeta || filterMeta) result[key] = {
|
|
5185
5692
|
...result[key],
|
|
5186
|
-
|
|
5187
|
-
...config.hidden && { hidden: true },
|
|
5188
|
-
...config.table,
|
|
5189
|
-
...filterMeta && { meta: {
|
|
5693
|
+
meta: {
|
|
5190
5694
|
...result[key]?.meta ?? {},
|
|
5191
|
-
...
|
|
5192
|
-
...filterMeta
|
|
5193
|
-
}
|
|
5695
|
+
...tableMeta ?? {},
|
|
5696
|
+
...filterMeta ?? {}
|
|
5697
|
+
}
|
|
5194
5698
|
};
|
|
5195
|
-
if (config.
|
|
5699
|
+
if (config.label) result[key] = {
|
|
5196
5700
|
...result[key],
|
|
5197
|
-
|
|
5701
|
+
label: config.label
|
|
5198
5702
|
};
|
|
5703
|
+
if (config.hidden) result[key] = {
|
|
5704
|
+
...result[key],
|
|
5705
|
+
hidden: true
|
|
5706
|
+
};
|
|
5707
|
+
if (config.table === false) result[key] = {
|
|
5708
|
+
...result[key],
|
|
5709
|
+
hidden: true
|
|
5710
|
+
};
|
|
5711
|
+
else if (config.table && typeof config.table === "object") {
|
|
5712
|
+
const { meta,...tableProps } = config.table;
|
|
5713
|
+
result[key] = {
|
|
5714
|
+
...result[key],
|
|
5715
|
+
...tableProps
|
|
5716
|
+
};
|
|
5717
|
+
}
|
|
5199
5718
|
}
|
|
5200
5719
|
return result;
|
|
5201
5720
|
}
|
|
@@ -5209,12 +5728,24 @@ function buildFormOverrides(fields, legacyOverrides, denyFields) {
|
|
|
5209
5728
|
...result[field],
|
|
5210
5729
|
"x-hidden": true
|
|
5211
5730
|
};
|
|
5212
|
-
if (fields) for (const [key, config] of Object.entries(fields))
|
|
5213
|
-
|
|
5214
|
-
|
|
5215
|
-
|
|
5216
|
-
|
|
5217
|
-
|
|
5731
|
+
if (fields) for (const [key, config] of Object.entries(fields)) {
|
|
5732
|
+
if (config.label) result[key] = {
|
|
5733
|
+
...result[key],
|
|
5734
|
+
title: config.label
|
|
5735
|
+
};
|
|
5736
|
+
if (config.hidden) result[key] = {
|
|
5737
|
+
...result[key],
|
|
5738
|
+
"x-hidden": true
|
|
5739
|
+
};
|
|
5740
|
+
if (config.form === false) result[key] = {
|
|
5741
|
+
...result[key],
|
|
5742
|
+
"x-hidden": true
|
|
5743
|
+
};
|
|
5744
|
+
else if (config.form && typeof config.form === "object") result[key] = {
|
|
5745
|
+
...result[key],
|
|
5746
|
+
...config.form
|
|
5747
|
+
};
|
|
5748
|
+
}
|
|
5218
5749
|
return result;
|
|
5219
5750
|
}
|
|
5220
5751
|
/**
|
|
@@ -5223,7 +5754,9 @@ function buildFormOverrides(fields, legacyOverrides, denyFields) {
|
|
|
5223
5754
|
function buildHiddenColumns(fields, legacyHidden, denyFields) {
|
|
5224
5755
|
const hidden = new Set([...legacyHidden ?? [], ...denyFields ?? []]);
|
|
5225
5756
|
if (fields) {
|
|
5226
|
-
for (const [key, config] of Object.entries(fields)) if (config.hidden
|
|
5757
|
+
for (const [key, config] of Object.entries(fields)) if (config.hidden) hidden.add(key);
|
|
5758
|
+
else if (config.table === false) hidden.add(key);
|
|
5759
|
+
else if (config.table && typeof config.table === "object" && config.table.hidden) hidden.add(key);
|
|
5227
5760
|
}
|
|
5228
5761
|
return Array.from(hidden);
|
|
5229
5762
|
}
|
|
@@ -5265,13 +5798,13 @@ function buildBatchUpdateFields(schema, batchFields, fields) {
|
|
|
5265
5798
|
/**
|
|
5266
5799
|
* 渲染字段值
|
|
5267
5800
|
*/
|
|
5268
|
-
function renderFieldValue(value, type) {
|
|
5801
|
+
function renderFieldValue(value, type, booleanLocale) {
|
|
5269
5802
|
if (value === null || value === void 0) return /* @__PURE__ */ jsx("span", {
|
|
5270
5803
|
className: "text-muted-foreground",
|
|
5271
5804
|
children: "-"
|
|
5272
5805
|
});
|
|
5273
5806
|
switch (type) {
|
|
5274
|
-
case "boolean": return value ?
|
|
5807
|
+
case "boolean": return value ? booleanLocale.true : booleanLocale.false;
|
|
5275
5808
|
case "date": return formatDate(value);
|
|
5276
5809
|
case "enum": return /* @__PURE__ */ jsx(Badge, {
|
|
5277
5810
|
variant: "outline",
|
|
@@ -5294,7 +5827,7 @@ function renderFieldValue(value, type) {
|
|
|
5294
5827
|
/**
|
|
5295
5828
|
* ViewModal 组件 - 详情查看弹窗
|
|
5296
5829
|
*/
|
|
5297
|
-
function ViewModal({ open, onOpenChange, variant, data, schema, fields: fieldConfig, denyFields }) {
|
|
5830
|
+
function ViewModal({ open, onOpenChange, variant, data, schema, fields: fieldConfig, denyFields, locale }) {
|
|
5298
5831
|
if (!data) return null;
|
|
5299
5832
|
const shape = schema.shape;
|
|
5300
5833
|
const denySet = new Set(denyFields ?? []);
|
|
@@ -5314,7 +5847,7 @@ function ViewModal({ open, onOpenChange, variant, data, schema, fields: fieldCon
|
|
|
5314
5847
|
children: label
|
|
5315
5848
|
}), /* @__PURE__ */ jsx("dd", {
|
|
5316
5849
|
className: "col-span-2 text-sm",
|
|
5317
|
-
children: renderFieldValue(value, parsed.type)
|
|
5850
|
+
children: renderFieldValue(value, parsed.type, locale.boolean)
|
|
5318
5851
|
})]
|
|
5319
5852
|
}, key);
|
|
5320
5853
|
})
|
|
@@ -5322,23 +5855,89 @@ function ViewModal({ open, onOpenChange, variant, data, schema, fields: fieldCon
|
|
|
5322
5855
|
if (variant === "sheet") return /* @__PURE__ */ jsx(Sheet, {
|
|
5323
5856
|
open,
|
|
5324
5857
|
onOpenChange,
|
|
5325
|
-
children: /* @__PURE__ */ jsxs(SheetContent, { children: [/* @__PURE__ */ jsx(SheetHeader, { children: /* @__PURE__ */ jsx(SheetTitle, { children:
|
|
5858
|
+
children: /* @__PURE__ */ jsxs(SheetContent, { children: [/* @__PURE__ */ jsx(SheetHeader, { children: /* @__PURE__ */ jsx(SheetTitle, { children: locale.viewModal.title }) }), content] })
|
|
5326
5859
|
});
|
|
5327
5860
|
return /* @__PURE__ */ jsx(Dialog, {
|
|
5328
5861
|
open,
|
|
5329
5862
|
onOpenChange,
|
|
5330
5863
|
children: /* @__PURE__ */ jsxs(DialogContent, {
|
|
5331
5864
|
className: "max-w-2xl max-h-[80vh] overflow-y-auto",
|
|
5332
|
-
children: [/* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children:
|
|
5865
|
+
children: [/* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: locale.viewModal.title }) }), content]
|
|
5333
5866
|
})
|
|
5334
5867
|
});
|
|
5335
5868
|
}
|
|
5869
|
+
function resolveActions(items, defaults, rowActionsLocale) {
|
|
5870
|
+
const defaultItems = [
|
|
5871
|
+
{
|
|
5872
|
+
label: rowActionsLocale.view,
|
|
5873
|
+
onClick: defaults.openView
|
|
5874
|
+
},
|
|
5875
|
+
...defaults.openEdit ? [{
|
|
5876
|
+
label: rowActionsLocale.edit,
|
|
5877
|
+
onClick: defaults.openEdit
|
|
5878
|
+
}] : [],
|
|
5879
|
+
...defaults.copyRow ? [{
|
|
5880
|
+
label: rowActionsLocale.copy,
|
|
5881
|
+
onClick: defaults.copyRow
|
|
5882
|
+
}] : [],
|
|
5883
|
+
...defaults.openDelete ? [{
|
|
5884
|
+
label: rowActionsLocale.delete,
|
|
5885
|
+
onClick: defaults.openDelete,
|
|
5886
|
+
separator: true,
|
|
5887
|
+
variant: "destructive"
|
|
5888
|
+
}] : []
|
|
5889
|
+
];
|
|
5890
|
+
if (!items || items.length === 0) return defaultItems;
|
|
5891
|
+
if (!items.some((i) => i.type !== "custom")) {
|
|
5892
|
+
const startItems = items.filter((i) => i.type === "custom" && i.position === "start").map(({ label, onClick, separator, variant }) => ({
|
|
5893
|
+
label,
|
|
5894
|
+
onClick,
|
|
5895
|
+
separator,
|
|
5896
|
+
variant
|
|
5897
|
+
}));
|
|
5898
|
+
const endItems = items.filter((i) => i.type === "custom" && i.position !== "start").map(({ label, onClick, separator, variant }) => ({
|
|
5899
|
+
label,
|
|
5900
|
+
onClick,
|
|
5901
|
+
separator,
|
|
5902
|
+
variant
|
|
5903
|
+
}));
|
|
5904
|
+
return [
|
|
5905
|
+
...startItems,
|
|
5906
|
+
...defaultItems,
|
|
5907
|
+
...endItems
|
|
5908
|
+
];
|
|
5909
|
+
}
|
|
5910
|
+
const handlerMap = {
|
|
5911
|
+
view: defaults.openView,
|
|
5912
|
+
edit: defaults.openEdit,
|
|
5913
|
+
copy: defaults.copyRow,
|
|
5914
|
+
delete: defaults.openDelete
|
|
5915
|
+
};
|
|
5916
|
+
const variantMap = { delete: "destructive" };
|
|
5917
|
+
return items.flatMap((item) => {
|
|
5918
|
+
if (item.type === "custom") return [{
|
|
5919
|
+
label: item.label,
|
|
5920
|
+
onClick: item.onClick,
|
|
5921
|
+
separator: item.separator,
|
|
5922
|
+
variant: item.variant
|
|
5923
|
+
}];
|
|
5924
|
+
const handler = item.onClick ?? handlerMap[item.type];
|
|
5925
|
+
if (!handler) return [];
|
|
5926
|
+
return [{
|
|
5927
|
+
label: item.label ?? rowActionsLocale[item.type],
|
|
5928
|
+
onClick: handler,
|
|
5929
|
+
separator: item.separator,
|
|
5930
|
+
variant: variantMap[item.type]
|
|
5931
|
+
}];
|
|
5932
|
+
});
|
|
5933
|
+
}
|
|
5336
5934
|
/**
|
|
5337
5935
|
* AutoCrudTable 组件
|
|
5338
5936
|
*
|
|
5339
5937
|
* 高级 CRUD 表格组件,封装了完整的增删改查流程
|
|
5340
5938
|
*/
|
|
5341
|
-
function AutoCrudTable({ title, description, schema, resource, fields, table: tableConfig, form: formConfig, slots, permissions }) {
|
|
5939
|
+
function AutoCrudTable({ title, description, schema, resource, fields, table: tableConfig, form: formConfig, slots, permissions, actions: actionItems, locale: localeProp }) {
|
|
5940
|
+
const locale = resolveLocale(localeProp);
|
|
5342
5941
|
const can = {
|
|
5343
5942
|
create: permissions?.can?.create ?? true,
|
|
5344
5943
|
update: permissions?.can?.update ?? true,
|
|
@@ -5389,10 +5988,22 @@ function AutoCrudTable({ title, description, schema, resource, fields, table: ta
|
|
|
5389
5988
|
setExporting(false);
|
|
5390
5989
|
}
|
|
5391
5990
|
}, [selectedCount, handleExport]);
|
|
5392
|
-
const tableOverrides = buildTableOverrides(fields, tableConfig?.overrides);
|
|
5393
|
-
const formOverrides = buildFormOverrides(fields, formConfig?.overrides, denyFields)
|
|
5394
|
-
|
|
5395
|
-
|
|
5991
|
+
const tableOverrides = React.useMemo(() => buildTableOverrides(fields, tableConfig?.overrides), [fields, tableConfig?.overrides]);
|
|
5992
|
+
const formOverrides = React.useMemo(() => buildFormOverrides(fields, formConfig?.overrides, denyFields), [
|
|
5993
|
+
fields,
|
|
5994
|
+
formConfig?.overrides,
|
|
5995
|
+
denyFields
|
|
5996
|
+
]);
|
|
5997
|
+
const hiddenColumns = React.useMemo(() => buildHiddenColumns(fields, tableConfig?.hidden, denyFields), [
|
|
5998
|
+
fields,
|
|
5999
|
+
tableConfig?.hidden,
|
|
6000
|
+
denyFields
|
|
6001
|
+
]);
|
|
6002
|
+
const batchFields = React.useMemo(() => buildBatchUpdateFields(schema, tableConfig?.batchFields, fields), [
|
|
6003
|
+
schema,
|
|
6004
|
+
tableConfig?.batchFields,
|
|
6005
|
+
fields
|
|
6006
|
+
]);
|
|
5396
6007
|
return /* @__PURE__ */ jsxs("div", {
|
|
5397
6008
|
className: "space-y-4",
|
|
5398
6009
|
children: [
|
|
@@ -5419,18 +6030,18 @@ function AutoCrudTable({ title, description, schema, resource, fields, table: ta
|
|
|
5419
6030
|
variant: "outline",
|
|
5420
6031
|
size: "sm",
|
|
5421
6032
|
onClick: () => setImportOpen(true),
|
|
5422
|
-
children: [/* @__PURE__ */ jsx(Download, { className: "mr-2 h-4 w-4" }),
|
|
6033
|
+
children: [/* @__PURE__ */ jsx(Download, { className: "mr-2 h-4 w-4" }), locale.toolbar.import]
|
|
5423
6034
|
}),
|
|
5424
6035
|
canExport && /* @__PURE__ */ jsxs(Button, {
|
|
5425
6036
|
variant: "outline",
|
|
5426
6037
|
size: "sm",
|
|
5427
6038
|
onClick: handleExportClick,
|
|
5428
6039
|
disabled: exporting || selectedCount === 0 && !resource.handlers.export,
|
|
5429
|
-
children: [exporting ? /* @__PURE__ */ jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : /* @__PURE__ */ jsx(Upload, { className: "mr-2 h-4 w-4" }), selectedCount > 0 ?
|
|
6040
|
+
children: [exporting ? /* @__PURE__ */ jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : /* @__PURE__ */ jsx(Upload, { className: "mr-2 h-4 w-4" }), selectedCount > 0 ? locale.toolbar.exportSelected(selectedCount) : locale.toolbar.export]
|
|
5430
6041
|
}),
|
|
5431
6042
|
can.create && /* @__PURE__ */ jsx(Button, {
|
|
5432
6043
|
onClick: resource.handlers.openCreate,
|
|
5433
|
-
children:
|
|
6044
|
+
children: locale.toolbar.create
|
|
5434
6045
|
})
|
|
5435
6046
|
]
|
|
5436
6047
|
})]
|
|
@@ -5442,12 +6053,12 @@ function AutoCrudTable({ title, description, schema, resource, fields, table: ta
|
|
|
5442
6053
|
overrides: tableOverrides,
|
|
5443
6054
|
exclude: hiddenColumns,
|
|
5444
6055
|
filterMode: tableConfig?.filterModes,
|
|
5445
|
-
actions: {
|
|
5446
|
-
|
|
5447
|
-
|
|
5448
|
-
|
|
5449
|
-
|
|
5450
|
-
},
|
|
6056
|
+
actions: resolveActions(actionItems, {
|
|
6057
|
+
openView: resource.handlers.openView,
|
|
6058
|
+
openEdit: can.update ? resource.handlers.openEdit : void 0,
|
|
6059
|
+
copyRow: can.create ? resource.handlers.copyRow : void 0,
|
|
6060
|
+
openDelete: can.delete ? resource.handlers.openDelete : void 0
|
|
6061
|
+
}, locale.rowActions),
|
|
5451
6062
|
onDeleteSelected: can.delete ? resource.handlers.deleteMany : void 0,
|
|
5452
6063
|
onUpdateSelected: can.update ? resource.handlers.updateMany : void 0,
|
|
5453
6064
|
batchUpdateFields: can.update ? batchFields : void 0,
|
|
@@ -5468,7 +6079,8 @@ function AutoCrudTable({ title, description, schema, resource, fields, table: ta
|
|
|
5468
6079
|
},
|
|
5469
6080
|
loading: resource.mutations.isCreating || resource.mutations.isUpdating,
|
|
5470
6081
|
variant: resource.modal.variant,
|
|
5471
|
-
overrides: formOverrides
|
|
6082
|
+
overrides: formOverrides,
|
|
6083
|
+
locale: locale.formModal
|
|
5472
6084
|
}),
|
|
5473
6085
|
/* @__PURE__ */ jsx(ViewModal, {
|
|
5474
6086
|
open: resource.modal.viewOpen,
|
|
@@ -5477,22 +6089,24 @@ function AutoCrudTable({ title, description, schema, resource, fields, table: ta
|
|
|
5477
6089
|
data: resource.modal.selected,
|
|
5478
6090
|
schema,
|
|
5479
6091
|
fields,
|
|
5480
|
-
denyFields
|
|
6092
|
+
denyFields,
|
|
6093
|
+
locale
|
|
5481
6094
|
}),
|
|
5482
6095
|
/* @__PURE__ */ jsx(AlertDialog, {
|
|
5483
6096
|
open: resource.modal.deleteOpen,
|
|
5484
6097
|
onOpenChange: (open) => !open && resource.handlers.closeModals(),
|
|
5485
|
-
children: /* @__PURE__ */ jsxs(AlertDialogContent, { children: [/* @__PURE__ */ jsxs(AlertDialogHeader, { children: [/* @__PURE__ */ jsx(AlertDialogTitle, { children:
|
|
6098
|
+
children: /* @__PURE__ */ jsxs(AlertDialogContent, { children: [/* @__PURE__ */ jsxs(AlertDialogHeader, { children: [/* @__PURE__ */ jsx(AlertDialogTitle, { children: locale.deleteModal.title }), /* @__PURE__ */ jsx(AlertDialogDescription, { children: locale.deleteModal.description })] }), /* @__PURE__ */ jsxs(AlertDialogFooter, { children: [/* @__PURE__ */ jsx(AlertDialogCancel, { children: locale.deleteModal.cancel }), /* @__PURE__ */ jsx(AlertDialogAction, {
|
|
5486
6099
|
onClick: resource.handlers.confirmDelete,
|
|
5487
6100
|
disabled: resource.mutations.isDeleting,
|
|
5488
|
-
children: resource.mutations.isDeleting ?
|
|
6101
|
+
children: resource.mutations.isDeleting ? locale.deleteModal.confirming : locale.deleteModal.confirm
|
|
5489
6102
|
})] })] })
|
|
5490
6103
|
}),
|
|
5491
6104
|
canImport && resource.handlers.import && /* @__PURE__ */ jsx(ImportDialog, {
|
|
5492
6105
|
open: importOpen,
|
|
5493
6106
|
onOpenChange: setImportOpen,
|
|
5494
6107
|
onImport: resource.handlers.import,
|
|
5495
|
-
columns: importColumns
|
|
6108
|
+
columns: importColumns,
|
|
6109
|
+
locale: locale.importDialog
|
|
5496
6110
|
})
|
|
5497
6111
|
]
|
|
5498
6112
|
});
|
|
@@ -6124,6 +6738,8 @@ function DataTableToolbarFilter({ column }) {
|
|
|
6124
6738
|
const columnMeta = column.columnDef.meta;
|
|
6125
6739
|
return React.useCallback(() => {
|
|
6126
6740
|
if (!columnMeta?.variant) return null;
|
|
6741
|
+
const modes = columnMeta.modes;
|
|
6742
|
+
if (modes && !modes.includes("advanced")) return null;
|
|
6127
6743
|
switch (columnMeta.variant) {
|
|
6128
6744
|
case "text": return /* @__PURE__ */ jsx(Input, {
|
|
6129
6745
|
placeholder: columnMeta.placeholder ?? columnMeta.label,
|
|
@@ -6245,6 +6861,10 @@ function modalReducer(state, action) {
|
|
|
6245
6861
|
function useAutoCrudResource({ router, schema, query: queryTransform, options = {} }) {
|
|
6246
6862
|
const { idKey = "id", defaultVariant = "dialog", hooks, toast: toastAdapter, exportFetcher } = options;
|
|
6247
6863
|
const toast$1 = useMemo(() => toastAdapter === false ? noopToastAdapter : toastAdapter ?? defaultToastAdapter, [toastAdapter]);
|
|
6864
|
+
const hooksRef = useRef(hooks);
|
|
6865
|
+
useEffect(() => {
|
|
6866
|
+
hooksRef.current = hooks;
|
|
6867
|
+
}, [hooks]);
|
|
6248
6868
|
const columns = useMemo(() => createTableSchema(schema), [schema]);
|
|
6249
6869
|
const [urlParams] = useQueryStates({
|
|
6250
6870
|
page: parseAsInteger.withDefault(1),
|
|
@@ -6308,15 +6928,16 @@ function useAutoCrudResource({ router, schema, query: queryTransform, options =
|
|
|
6308
6928
|
payload: variant
|
|
6309
6929
|
}), []);
|
|
6310
6930
|
const submitCreate = useCallback(async (values) => {
|
|
6931
|
+
const currentHooks = hooksRef.current;
|
|
6311
6932
|
try {
|
|
6312
|
-
if (
|
|
6313
|
-
const result = await
|
|
6933
|
+
if (currentHooks?.beforeCreate) {
|
|
6934
|
+
const result = await currentHooks.beforeCreate(values);
|
|
6314
6935
|
if (typeof result === "boolean") {
|
|
6315
6936
|
if (result) {
|
|
6316
6937
|
toast$1.success("创建成功");
|
|
6317
6938
|
closeModals();
|
|
6318
6939
|
listQuery.refetch();
|
|
6319
|
-
|
|
6940
|
+
currentHooks?.onSuccess?.("create", values);
|
|
6320
6941
|
}
|
|
6321
6942
|
return;
|
|
6322
6943
|
}
|
|
@@ -6327,36 +6948,36 @@ function useAutoCrudResource({ router, schema, query: queryTransform, options =
|
|
|
6327
6948
|
toast$1.success("创建成功");
|
|
6328
6949
|
closeModals();
|
|
6329
6950
|
listQuery.refetch();
|
|
6330
|
-
|
|
6951
|
+
currentHooks?.onSuccess?.("create", data);
|
|
6331
6952
|
},
|
|
6332
6953
|
onError: (error) => {
|
|
6333
6954
|
const err = error;
|
|
6334
6955
|
toast$1.error(`创建失败: ${err.message}`);
|
|
6335
|
-
|
|
6956
|
+
currentHooks?.onError?.("create", err);
|
|
6336
6957
|
}
|
|
6337
6958
|
});
|
|
6338
6959
|
} catch (error) {
|
|
6339
6960
|
const err = error;
|
|
6340
6961
|
toast$1.error(`创建失败: ${err.message}`);
|
|
6341
|
-
|
|
6962
|
+
currentHooks?.onError?.("create", err);
|
|
6342
6963
|
}
|
|
6343
6964
|
}, [
|
|
6344
6965
|
createMutation,
|
|
6345
6966
|
closeModals,
|
|
6346
|
-
listQuery
|
|
6347
|
-
hooks
|
|
6967
|
+
listQuery
|
|
6348
6968
|
]);
|
|
6349
6969
|
const submitUpdate = useCallback(async (values) => {
|
|
6970
|
+
const currentHooks = hooksRef.current;
|
|
6350
6971
|
if (!modal.selected) return;
|
|
6351
6972
|
try {
|
|
6352
|
-
if (
|
|
6353
|
-
const result = await
|
|
6973
|
+
if (currentHooks?.beforeUpdate) {
|
|
6974
|
+
const result = await currentHooks.beforeUpdate(values, modal.selected);
|
|
6354
6975
|
if (typeof result === "boolean") {
|
|
6355
6976
|
if (result) {
|
|
6356
6977
|
toast$1.success("更新成功");
|
|
6357
6978
|
closeModals();
|
|
6358
6979
|
listQuery.refetch();
|
|
6359
|
-
|
|
6980
|
+
currentHooks?.onSuccess?.("update", values);
|
|
6360
6981
|
}
|
|
6361
6982
|
return;
|
|
6362
6983
|
}
|
|
@@ -6371,38 +6992,38 @@ function useAutoCrudResource({ router, schema, query: queryTransform, options =
|
|
|
6371
6992
|
toast$1.success("更新成功");
|
|
6372
6993
|
closeModals();
|
|
6373
6994
|
listQuery.refetch();
|
|
6374
|
-
|
|
6995
|
+
currentHooks?.onSuccess?.("update", data);
|
|
6375
6996
|
},
|
|
6376
6997
|
onError: (error) => {
|
|
6377
6998
|
const err = error;
|
|
6378
6999
|
toast$1.error(`更新失败: ${err.message}`);
|
|
6379
|
-
|
|
7000
|
+
currentHooks?.onError?.("update", err);
|
|
6380
7001
|
}
|
|
6381
7002
|
});
|
|
6382
7003
|
} catch (error) {
|
|
6383
7004
|
const err = error;
|
|
6384
7005
|
toast$1.error(`更新失败: ${err.message}`);
|
|
6385
|
-
|
|
7006
|
+
currentHooks?.onError?.("update", err);
|
|
6386
7007
|
}
|
|
6387
7008
|
}, [
|
|
6388
7009
|
modal.selected,
|
|
6389
7010
|
idKey,
|
|
6390
7011
|
updateMutation,
|
|
6391
7012
|
closeModals,
|
|
6392
|
-
listQuery
|
|
6393
|
-
hooks
|
|
7013
|
+
listQuery
|
|
6394
7014
|
]);
|
|
6395
7015
|
const confirmDelete = useCallback(async () => {
|
|
7016
|
+
const currentHooks = hooksRef.current;
|
|
6396
7017
|
if (!modal.selected) return;
|
|
6397
7018
|
try {
|
|
6398
|
-
if (
|
|
6399
|
-
const result = await
|
|
7019
|
+
if (currentHooks?.beforeDelete) {
|
|
7020
|
+
const result = await currentHooks.beforeDelete(modal.selected);
|
|
6400
7021
|
if (typeof result === "boolean") {
|
|
6401
7022
|
if (result) {
|
|
6402
7023
|
toast$1.success("删除成功");
|
|
6403
7024
|
closeModals();
|
|
6404
7025
|
listQuery.refetch();
|
|
6405
|
-
|
|
7026
|
+
currentHooks?.onSuccess?.("delete", modal.selected);
|
|
6406
7027
|
}
|
|
6407
7028
|
return;
|
|
6408
7029
|
}
|
|
@@ -6413,28 +7034,28 @@ function useAutoCrudResource({ router, schema, query: queryTransform, options =
|
|
|
6413
7034
|
toast$1.success("删除成功");
|
|
6414
7035
|
closeModals();
|
|
6415
7036
|
listQuery.refetch();
|
|
6416
|
-
|
|
7037
|
+
currentHooks?.onSuccess?.("delete", data);
|
|
6417
7038
|
},
|
|
6418
7039
|
onError: (error) => {
|
|
6419
7040
|
const err = error;
|
|
6420
7041
|
toast$1.error(`删除失败: ${err.message}`);
|
|
6421
|
-
|
|
7042
|
+
currentHooks?.onError?.("delete", err);
|
|
6422
7043
|
}
|
|
6423
7044
|
});
|
|
6424
7045
|
} catch (error) {
|
|
6425
7046
|
const err = error;
|
|
6426
7047
|
toast$1.error(`删除失败: ${err.message}`);
|
|
6427
|
-
|
|
7048
|
+
currentHooks?.onError?.("delete", err);
|
|
6428
7049
|
}
|
|
6429
7050
|
}, [
|
|
6430
7051
|
modal.selected,
|
|
6431
7052
|
idKey,
|
|
6432
7053
|
deleteMutation,
|
|
6433
7054
|
closeModals,
|
|
6434
|
-
listQuery
|
|
6435
|
-
hooks
|
|
7055
|
+
listQuery
|
|
6436
7056
|
]);
|
|
6437
7057
|
const deleteMany = useCallback((rows) => {
|
|
7058
|
+
const currentHooks = hooksRef.current;
|
|
6438
7059
|
if (!deleteManyMutation) {
|
|
6439
7060
|
toast$1.error("批量删除功能未启用");
|
|
6440
7061
|
return;
|
|
@@ -6444,21 +7065,21 @@ function useAutoCrudResource({ router, schema, query: queryTransform, options =
|
|
|
6444
7065
|
onSuccess: (data) => {
|
|
6445
7066
|
toast$1.success(`成功删除 ${ids.length} 条记录`);
|
|
6446
7067
|
listQuery.refetch();
|
|
6447
|
-
|
|
7068
|
+
currentHooks?.onSuccess?.("delete", data);
|
|
6448
7069
|
},
|
|
6449
7070
|
onError: (error) => {
|
|
6450
7071
|
const err = error;
|
|
6451
7072
|
toast$1.error(`批量删除失败: ${err.message}`);
|
|
6452
|
-
|
|
7073
|
+
currentHooks?.onError?.("delete", err);
|
|
6453
7074
|
}
|
|
6454
7075
|
});
|
|
6455
7076
|
}, [
|
|
6456
7077
|
deleteManyMutation,
|
|
6457
7078
|
idKey,
|
|
6458
|
-
listQuery
|
|
6459
|
-
hooks
|
|
7079
|
+
listQuery
|
|
6460
7080
|
]);
|
|
6461
7081
|
const updateMany = useCallback((rows, data) => {
|
|
7082
|
+
const currentHooks = hooksRef.current;
|
|
6462
7083
|
if (!updateManyMutation) {
|
|
6463
7084
|
toast$1.error("批量更新功能未启用");
|
|
6464
7085
|
return;
|
|
@@ -6471,19 +7092,18 @@ function useAutoCrudResource({ router, schema, query: queryTransform, options =
|
|
|
6471
7092
|
onSuccess: (result) => {
|
|
6472
7093
|
toast$1.success(`成功更新 ${ids.length} 条记录`);
|
|
6473
7094
|
listQuery.refetch();
|
|
6474
|
-
|
|
7095
|
+
currentHooks?.onSuccess?.("update", result);
|
|
6475
7096
|
},
|
|
6476
7097
|
onError: (error) => {
|
|
6477
7098
|
const err = error;
|
|
6478
7099
|
toast$1.error(`批量更新失败: ${err.message}`);
|
|
6479
|
-
|
|
7100
|
+
currentHooks?.onError?.("update", err);
|
|
6480
7101
|
}
|
|
6481
7102
|
});
|
|
6482
7103
|
}, [
|
|
6483
7104
|
updateManyMutation,
|
|
6484
7105
|
idKey,
|
|
6485
|
-
listQuery
|
|
6486
|
-
hooks
|
|
7106
|
+
listQuery
|
|
6487
7107
|
]);
|
|
6488
7108
|
const copyRow = useCallback((row) => {
|
|
6489
7109
|
dispatch({
|
|
@@ -6856,4 +7476,4 @@ function createMemoryDataSource(initialData = []) {
|
|
|
6856
7476
|
}
|
|
6857
7477
|
|
|
6858
7478
|
//#endregion
|
|
6859
|
-
export { AutoCrudTable, AutoForm, AutoTable, AutoTableActionBar, AutoTableSimpleFilters, CrudFormModal, DataTable, DataTableAdvancedToolbar, DataTableColumnHeader, DataTableFacetedFilter, DataTablePagination, DataTableToolbar, DataTableViewOptions, ExportDialog, ImportDialog, SchemaAdapter, cn, coerceRowValues, createActionsColumn, createEditFormSchema, createFormSchema, createMemoryDataSource, createSelectColumn, createTRPCDataSource, createTableSchema, dataToCSV, downloadCSVTemplate, exportAllToCSV, exportTableToCSV, formatDate, generateCSVTemplate, getUrlParams, humanize, noopToastAdapter, parseAsArrayOf, parseAsInteger, parseAsString, parseAsStringEnum, parseCSV, parseImportFile, parseJSON, parseZodField, setSearchParams, useAutoCrudResource, useDataTable, useQueryState, useQueryStates, useReadableFilters, useUrlState, useUrlStates };
|
|
7479
|
+
export { AutoCrudTable, AutoForm, AutoTable, AutoTableActionBar, AutoTableSimpleFilters, CrudFormModal, DataTable, DataTableAdvancedToolbar, DataTableColumnHeader, DataTableFacetedFilter, DataTablePagination, DataTableToolbar, DataTableViewOptions, ExportDialog, ImportDialog, SchemaAdapter, cn, coerceRowValues, createActionsColumn, createEditFormSchema, createFormSchema, createMemoryDataSource, createSelectColumn, createTRPCDataSource, createTableSchema, dataToCSV, deDE, downloadCSVTemplate, enUS, esES, exportAllToCSV, exportTableToCSV, formatDate, frFR, generateCSVTemplate, getUrlParams, humanize, jaJP, koKR, noopToastAdapter, parseAsArrayOf, parseAsInteger, parseAsString, parseAsStringEnum, parseCSV, parseImportFile, parseJSON, parseZodField, resolveLocale, setSearchParams, useAutoCrudResource, useDataTable, useQueryState, useQueryStates, useReadableFilters, useUrlState, useUrlStates, zhCN };
|