@fe-free/core 4.0.4 → 5.0.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.
- package/CHANGELOG.md +18 -0
- package/i18next.config.ts +11 -0
- package/package.json +4 -4
- package/src/core_app/index.tsx +20 -15
- package/src/crud/crud.tsx +4 -2
- package/src/crud/crud_delete.tsx +9 -6
- package/src/crud/crud_detail.tsx +32 -21
- package/src/crud/use_operate.tsx +18 -13
- package/src/crud/use_row_selection.tsx +27 -14
- package/src/crud/use_tips.tsx +46 -9
- package/src/crud_of_list/index.tsx +17 -4
- package/src/crud_of_pure/index.tsx +8 -2
- package/src/data_viewer/index.tsx +9 -1
- package/src/form/form_list/form_list.tsx +11 -8
- package/src/form/form_list/form_list_helper.tsx +3 -1
- package/src/form/form_list/form_list_modal_helper.tsx +8 -2
- package/src/i18n.tsx +5 -0
- package/src/infinite_list/index.tsx +12 -2
- package/src/locales/en-US/translation.json +87 -0
- package/src/locales/zh-CN/translation.json +87 -0
- package/src/record/index.tsx +3 -1
- package/src/tree/file_tree.tsx +24 -10
- package/src/upload/index.tsx +31 -12
- package/src/value_type_map/json_modal.tsx +3 -1
|
@@ -2,6 +2,7 @@ import { useDebounce } from 'ahooks';
|
|
|
2
2
|
import { Input } from 'antd';
|
|
3
3
|
import classNames from 'classnames';
|
|
4
4
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
5
|
+
import { useTranslation } from 'react-i18next';
|
|
5
6
|
import type { CRUDProps } from '../crud';
|
|
6
7
|
import { CRUD } from '../crud';
|
|
7
8
|
import './style.scss';
|
|
@@ -15,15 +16,26 @@ interface CRUDOfListProps<
|
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
function useTips(props) {
|
|
19
|
+
const { t } = useTranslation();
|
|
18
20
|
useEffect(() => {
|
|
19
21
|
const count = props.tableProps.columns?.filter((column) => column.search).length;
|
|
20
22
|
if (!count) {
|
|
21
|
-
console.warn(
|
|
23
|
+
console.warn(
|
|
24
|
+
t(
|
|
25
|
+
'core.crudOfList.warnAtLeastOneSearch',
|
|
26
|
+
'CRUDOfList 的 columns 中至少有一个 search 为 true 的列',
|
|
27
|
+
),
|
|
28
|
+
);
|
|
22
29
|
}
|
|
23
30
|
if (count > 1) {
|
|
24
|
-
console.warn(
|
|
31
|
+
console.warn(
|
|
32
|
+
t(
|
|
33
|
+
'core.crudOfList.warnOnlyOneSearch',
|
|
34
|
+
'CRUDOfList 的 columns 中只能有一个 search 为 true 的列',
|
|
35
|
+
),
|
|
36
|
+
);
|
|
25
37
|
}
|
|
26
|
-
}, []);
|
|
38
|
+
}, [t]);
|
|
27
39
|
}
|
|
28
40
|
|
|
29
41
|
function SearchRender(props: {
|
|
@@ -31,9 +43,10 @@ function SearchRender(props: {
|
|
|
31
43
|
value?: string;
|
|
32
44
|
onChange: (value: string) => void;
|
|
33
45
|
}) {
|
|
46
|
+
const { t } = useTranslation();
|
|
34
47
|
return (
|
|
35
48
|
<Input
|
|
36
|
-
placeholder={props.placeholder ?? '输入搜索'}
|
|
49
|
+
placeholder={props.placeholder ?? t('@fe-free/core.crudOfList.searchPlaceholder', '输入搜索')}
|
|
37
50
|
allowClear
|
|
38
51
|
value={props.value}
|
|
39
52
|
onChange={(e) => props.onChange(e.target.value)}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import classNames from 'classnames';
|
|
2
2
|
import { useMemo } from 'react';
|
|
3
|
+
import { useTranslation } from 'react-i18next';
|
|
3
4
|
import type { CRUDProps } from '../crud';
|
|
4
5
|
import { CRUD } from '../crud';
|
|
5
6
|
import './style.scss';
|
|
@@ -17,6 +18,7 @@ function CRUDOfPure<
|
|
|
17
18
|
DataSource extends Record<string, any> = any,
|
|
18
19
|
Key extends string | number = string,
|
|
19
20
|
>(props: CRUDOfPureProps<DataSource, Key>) {
|
|
21
|
+
const { t } = useTranslation();
|
|
20
22
|
const newColumns = props.tableProps.columns?.map((column) => {
|
|
21
23
|
if (column.search) {
|
|
22
24
|
return {
|
|
@@ -30,8 +32,12 @@ function CRUDOfPure<
|
|
|
30
32
|
fieldProps: {
|
|
31
33
|
placeholder:
|
|
32
34
|
column.valueType === 'select' || column.valueEnum
|
|
33
|
-
?
|
|
34
|
-
|
|
35
|
+
? t('@fe-free/core.crudOfPure.selectPlaceholder', '请选择{title}', {
|
|
36
|
+
title: column.title,
|
|
37
|
+
})
|
|
38
|
+
: t('@fe-free/core.crudOfPure.inputPlaceholder', '请输入{title}', {
|
|
39
|
+
title: column.title,
|
|
40
|
+
}),
|
|
35
41
|
...column.fieldProps,
|
|
36
42
|
},
|
|
37
43
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ArrowsAltOutlined } from '@fe-free/icons';
|
|
2
2
|
import { Button, Modal, Select } from 'antd';
|
|
3
3
|
import { useMemo, useState } from 'react';
|
|
4
|
+
import { useTranslation } from 'react-i18next';
|
|
4
5
|
import { Editor } from '../editor';
|
|
5
6
|
import { PageLayout } from '../page_layout';
|
|
6
7
|
|
|
@@ -19,6 +20,7 @@ const options = [
|
|
|
19
20
|
];
|
|
20
21
|
|
|
21
22
|
function DataViewer({ data, title, enableMaximize }: DataViewerProps) {
|
|
23
|
+
const { t } = useTranslation();
|
|
22
24
|
const [maximize, setMaximize] = useState(false);
|
|
23
25
|
const [language, setLanguage] = useState<DataViewerLanguage>(
|
|
24
26
|
options[0].value as DataViewerLanguage,
|
|
@@ -64,7 +66,13 @@ function DataViewer({ data, title, enableMaximize }: DataViewerProps) {
|
|
|
64
66
|
</div>
|
|
65
67
|
</PageLayout>
|
|
66
68
|
{maximize && (
|
|
67
|
-
<Modal
|
|
69
|
+
<Modal
|
|
70
|
+
title={t('@fe-free/core.dataViewer.view', '查看')}
|
|
71
|
+
open
|
|
72
|
+
width={'80vw'}
|
|
73
|
+
onCancel={() => setMaximize(false)}
|
|
74
|
+
footer={null}
|
|
75
|
+
>
|
|
68
76
|
<div className="h-[80vh]">
|
|
69
77
|
<Editor
|
|
70
78
|
value={value}
|
|
@@ -3,6 +3,7 @@ import { ProForm } from '@ant-design/pro-components';
|
|
|
3
3
|
import { Input, InputNumber, Switch } from 'antd';
|
|
4
4
|
|
|
5
5
|
import { uniq, uniqBy } from 'lodash-es';
|
|
6
|
+
import { useTranslation } from 'react-i18next';
|
|
6
7
|
import { ProFormListHelper } from './form_list_helper';
|
|
7
8
|
|
|
8
9
|
interface ListTextProps {
|
|
@@ -108,6 +109,7 @@ function ListBoolean(props: ListBooleanProps) {
|
|
|
108
109
|
|
|
109
110
|
function ProFormListText(props: ProFormItemProps<ListTextProps>) {
|
|
110
111
|
const { fieldProps, ...rest } = props;
|
|
112
|
+
const { t } = useTranslation();
|
|
111
113
|
|
|
112
114
|
return (
|
|
113
115
|
<ProForm.Item
|
|
@@ -121,19 +123,19 @@ function ProFormListText(props: ProFormItemProps<ListTextProps>) {
|
|
|
121
123
|
if (value) {
|
|
122
124
|
if (fieldProps?.isValueLabel) {
|
|
123
125
|
if (value?.some((item) => item.value === undefined || item.value === '')) {
|
|
124
|
-
return Promise.reject('存在空选项');
|
|
126
|
+
return Promise.reject(t('@fe-free/core.formList.emptyOption', '存在空选项'));
|
|
125
127
|
}
|
|
126
128
|
// 不能有重复的 value
|
|
127
129
|
if (uniqBy(value, 'value').length !== value.length) {
|
|
128
|
-
return Promise.reject('不能有重复');
|
|
130
|
+
return Promise.reject(t('@fe-free/core.formList.duplicateValue', '不能有重复'));
|
|
129
131
|
}
|
|
130
132
|
} else {
|
|
131
133
|
if (value?.some((item) => item === undefined || item === '')) {
|
|
132
|
-
return Promise.reject('存在空选项');
|
|
134
|
+
return Promise.reject(t('@fe-free/core.formList.emptyOption', '存在空选项'));
|
|
133
135
|
}
|
|
134
136
|
// 不能有重复的 value
|
|
135
137
|
if (uniq(value).length !== value.length) {
|
|
136
|
-
return Promise.reject('不能有重复');
|
|
138
|
+
return Promise.reject(t('@fe-free/core.formList.duplicateValue', '不能有重复'));
|
|
137
139
|
}
|
|
138
140
|
}
|
|
139
141
|
}
|
|
@@ -150,6 +152,7 @@ function ProFormListText(props: ProFormItemProps<ListTextProps>) {
|
|
|
150
152
|
|
|
151
153
|
function ProFormListNumber(props: ProFormItemProps<ListNumberProps>) {
|
|
152
154
|
const { fieldProps, ...rest } = props;
|
|
155
|
+
const { t } = useTranslation();
|
|
153
156
|
|
|
154
157
|
return (
|
|
155
158
|
<ProForm.Item
|
|
@@ -163,19 +166,19 @@ function ProFormListNumber(props: ProFormItemProps<ListNumberProps>) {
|
|
|
163
166
|
if (value) {
|
|
164
167
|
if (fieldProps?.isValueLabel) {
|
|
165
168
|
if (value?.some((item) => item.value === undefined || item.value === null)) {
|
|
166
|
-
return Promise.reject('存在空选项');
|
|
169
|
+
return Promise.reject(t('@fe-free/core.formList.emptyOption', '存在空选项'));
|
|
167
170
|
}
|
|
168
171
|
// 不能有重复的 value
|
|
169
172
|
if (uniqBy(value, 'value').length !== value.length) {
|
|
170
|
-
return Promise.reject('不能有重复');
|
|
173
|
+
return Promise.reject(t('@fe-free/core.formList.duplicateValue', '不能有重复'));
|
|
171
174
|
}
|
|
172
175
|
} else {
|
|
173
176
|
if (value?.some((item) => item === undefined || item === null)) {
|
|
174
|
-
return Promise.reject('存在空选项');
|
|
177
|
+
return Promise.reject(t('@fe-free/core.formList.emptyOption', '存在空选项'));
|
|
175
178
|
}
|
|
176
179
|
// 不能有重复的 value
|
|
177
180
|
if (uniq(value).length !== value.length) {
|
|
178
|
-
return Promise.reject('不能有重复');
|
|
181
|
+
return Promise.reject(t('@fe-free/core.formList.duplicateValue', '不能有重复'));
|
|
179
182
|
}
|
|
180
183
|
}
|
|
181
184
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { DeleteOutlined, PlusOutlined } from '@fe-free/icons';
|
|
2
2
|
import { Button } from 'antd';
|
|
3
3
|
import classNames from 'classnames';
|
|
4
|
+
import { useTranslation } from 'react-i18next';
|
|
4
5
|
|
|
5
6
|
interface ProFormListHelperProps<T> {
|
|
6
7
|
value?: T[];
|
|
@@ -27,6 +28,7 @@ interface ProFormListHelperProps<T> {
|
|
|
27
28
|
|
|
28
29
|
const emptyArr = [];
|
|
29
30
|
function ProFormListHelper<T = any>(props: ProFormListHelperProps<T>) {
|
|
31
|
+
const { t } = useTranslation();
|
|
30
32
|
const options = props.value || emptyArr;
|
|
31
33
|
|
|
32
34
|
return (
|
|
@@ -85,7 +87,7 @@ function ProFormListHelper<T = any>(props: ProFormListHelperProps<T>) {
|
|
|
85
87
|
props.onChange?.(newOptions);
|
|
86
88
|
}}
|
|
87
89
|
>
|
|
88
|
-
{props.addText || '添加'}
|
|
90
|
+
{props.addText || t('@fe-free/core.formList.add', '添加')}
|
|
89
91
|
</Button>
|
|
90
92
|
</div>
|
|
91
93
|
)}
|
|
@@ -2,6 +2,7 @@ import { ModalForm } from '@ant-design/pro-components';
|
|
|
2
2
|
import { DeleteOutlined, EditOutlined, PlusOutlined } from '@fe-free/icons';
|
|
3
3
|
import { Button } from 'antd';
|
|
4
4
|
import React from 'react';
|
|
5
|
+
import { useTranslation } from 'react-i18next';
|
|
5
6
|
|
|
6
7
|
const emptyArr = [];
|
|
7
8
|
|
|
@@ -34,6 +35,7 @@ function Edit<T>(props: {
|
|
|
34
35
|
editForm?: any;
|
|
35
36
|
disabledSubmitter?: boolean;
|
|
36
37
|
}) {
|
|
38
|
+
const { t } = useTranslation();
|
|
37
39
|
const handleFinish = async (newValues) => {
|
|
38
40
|
props.onChange(newValues as T);
|
|
39
41
|
|
|
@@ -42,7 +44,11 @@ function Edit<T>(props: {
|
|
|
42
44
|
|
|
43
45
|
return (
|
|
44
46
|
<ModalForm
|
|
45
|
-
title={
|
|
47
|
+
title={
|
|
48
|
+
props.values
|
|
49
|
+
? t('@fe-free/core.formList.edit', '编辑')
|
|
50
|
+
: t('@fe-free/core.formList.add', '添加')
|
|
51
|
+
}
|
|
46
52
|
trigger={props.children}
|
|
47
53
|
onFinish={handleFinish}
|
|
48
54
|
formRef={props?.editForm}
|
|
@@ -119,7 +125,7 @@ function ProFormListModalHelper<T = any>(props: ProFormListModalHelperProps<T>)
|
|
|
119
125
|
>
|
|
120
126
|
{props.addTrigger || (
|
|
121
127
|
<Button size="small" icon={<PlusOutlined />}>
|
|
122
|
-
添加
|
|
128
|
+
{t('@fe-free/core.formList.add', '添加')}
|
|
123
129
|
</Button>
|
|
124
130
|
)}
|
|
125
131
|
</Edit>
|
package/src/i18n.tsx
CHANGED
|
@@ -33,6 +33,8 @@ function initI18n({ enTranslation }) {
|
|
|
33
33
|
const cacheLng = localStorage.getItem('i18nextLng') || EnumLanguage.ZH_CN;
|
|
34
34
|
const lng = listLanguage.find((item) => item.value === cacheLng) ? cacheLng : EnumLanguage.ZH_CN;
|
|
35
35
|
|
|
36
|
+
console.log('initI18n', 'cacheLng', cacheLng, 'lng', lng);
|
|
37
|
+
|
|
36
38
|
i18n
|
|
37
39
|
.use(LanguageDetector)
|
|
38
40
|
.use(initReactI18next)
|
|
@@ -60,4 +62,7 @@ function I18nProvider({ children }: { children: React.ReactNode }) {
|
|
|
60
62
|
return <I18nextProvider i18n={i18n}>{children}</I18nextProvider>;
|
|
61
63
|
}
|
|
62
64
|
|
|
65
|
+
// @ts-ignore
|
|
66
|
+
window._i18n = i18n;
|
|
67
|
+
|
|
63
68
|
export { EnumLanguage, I18nProvider, initI18n, listLanguage, valueEnumLanguage };
|
|
@@ -2,6 +2,7 @@ import { Spin } from 'antd';
|
|
|
2
2
|
import classNames from 'classnames';
|
|
3
3
|
import type { ReactNode } from 'react';
|
|
4
4
|
import { useImperativeHandle, useRef, useState } from 'react';
|
|
5
|
+
import { useTranslation } from 'react-i18next';
|
|
5
6
|
import stringify from 'safe-stable-stringify';
|
|
6
7
|
import { useGlobalInfiniteScroll } from '../ahooks/use_global_infinite_scroll';
|
|
7
8
|
|
|
@@ -34,6 +35,7 @@ const InfiniteListBase = <D, P>({
|
|
|
34
35
|
gridClassName,
|
|
35
36
|
className,
|
|
36
37
|
}: InfiniteListProps<D, P>) => {
|
|
38
|
+
const { t } = useTranslation();
|
|
37
39
|
const ref = useRef<HTMLDivElement>(null);
|
|
38
40
|
|
|
39
41
|
const { data, loading, loadingMore, noMore, mutate, reload } = useGlobalInfiniteScroll(
|
|
@@ -103,8 +105,16 @@ const InfiniteListBase = <D, P>({
|
|
|
103
105
|
</div>
|
|
104
106
|
)}
|
|
105
107
|
<div className="flex w-full items-center justify-center">
|
|
106
|
-
{noMore &&
|
|
107
|
-
|
|
108
|
+
{noMore && (
|
|
109
|
+
<div className="my-5 text-center text-03">
|
|
110
|
+
{t('@fe-free/core.infiniteList.noMoreData', '没有更多数据')}
|
|
111
|
+
</div>
|
|
112
|
+
)}
|
|
113
|
+
{loadingMore && (
|
|
114
|
+
<div className="my-5 text-center text-03">
|
|
115
|
+
{t('@fe-free/core.infiniteList.loadingMore', '加载更多数据中...')}
|
|
116
|
+
</div>
|
|
117
|
+
)}
|
|
108
118
|
</div>
|
|
109
119
|
</div>
|
|
110
120
|
);
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
{
|
|
2
|
+
"@fe-free/core": {
|
|
3
|
+
"app": {
|
|
4
|
+
"mainScriptNotFound": "Could not find [data-name=\"mainScript\"], update reminder is disabled",
|
|
5
|
+
"newVersionFound": "New version found",
|
|
6
|
+
"refresh": "Refresh",
|
|
7
|
+
"refreshPrompt": "Please refresh the page in time to update to avoid affecting usage",
|
|
8
|
+
"updateLater": "Update later"
|
|
9
|
+
},
|
|
10
|
+
"crud": {
|
|
11
|
+
"batchActionConfirm": "Are you sure you want to execute {action}?",
|
|
12
|
+
"batchDelete": "Batch delete",
|
|
13
|
+
"cancel": "Cancel",
|
|
14
|
+
"clearSelection": "Clear selection",
|
|
15
|
+
"confirm": "Confirm",
|
|
16
|
+
"create": "Create",
|
|
17
|
+
"createSuccess": "Created successfully",
|
|
18
|
+
"delete": "Delete",
|
|
19
|
+
"deleteConfirm": "Are you sure you want to delete \"{name}\"?",
|
|
20
|
+
"deleteSuccess": "Deleted successfully",
|
|
21
|
+
"deleteWarning": "This action cannot be undone, please proceed with caution",
|
|
22
|
+
"operate": "Actions",
|
|
23
|
+
"read": "View",
|
|
24
|
+
"requestDeleteByRecordRequired": "requestDeleteByRecord is required",
|
|
25
|
+
"selectedItems": "{num} items selected",
|
|
26
|
+
"update": "Edit",
|
|
27
|
+
"updateSuccess": "Updated successfully",
|
|
28
|
+
"warnCreateDetailForm": "detailForm is required when actions include create",
|
|
29
|
+
"warnReadDetailForm": "detailForm is required when actions include read",
|
|
30
|
+
"warnUpdateDetailForm": "detailForm is required when actions include update"
|
|
31
|
+
},
|
|
32
|
+
"crudOfList": {
|
|
33
|
+
"searchPlaceholder": "Enter search"
|
|
34
|
+
},
|
|
35
|
+
"crudOfPure": {
|
|
36
|
+
"inputPlaceholder": "Please enter {title}",
|
|
37
|
+
"selectPlaceholder": "Please select {title}"
|
|
38
|
+
},
|
|
39
|
+
"dataViewer": {
|
|
40
|
+
"view": "View"
|
|
41
|
+
},
|
|
42
|
+
"fileTree": {
|
|
43
|
+
"create": "Create",
|
|
44
|
+
"createSubDirectory": "Create subdirectory",
|
|
45
|
+
"delete": "Delete",
|
|
46
|
+
"directoryName": "Directory name",
|
|
47
|
+
"update": "Edit"
|
|
48
|
+
},
|
|
49
|
+
"formList": {
|
|
50
|
+
"add": "Add",
|
|
51
|
+
"duplicateValue": "Duplicate values are not allowed",
|
|
52
|
+
"edit": "Edit",
|
|
53
|
+
"emptyOption": "Empty option exists"
|
|
54
|
+
},
|
|
55
|
+
"infiniteList": {
|
|
56
|
+
"loadingMore": "Loading more data...",
|
|
57
|
+
"noMoreData": "No more data"
|
|
58
|
+
},
|
|
59
|
+
"record": {
|
|
60
|
+
"inputPlaceholder": "Please enter"
|
|
61
|
+
},
|
|
62
|
+
"upload": {
|
|
63
|
+
"delete": "Delete",
|
|
64
|
+
"dragUpload": "Click or drag files to this area to upload",
|
|
65
|
+
"fileCount": "File count ({success}/{total})",
|
|
66
|
+
"localUpload": "Local upload",
|
|
67
|
+
"maxFilesWarning": "Only {num} files can be uploaded at most, excess files will be ignored.",
|
|
68
|
+
"pleaseSelect": "Please select"
|
|
69
|
+
},
|
|
70
|
+
"valueTypeMap": {
|
|
71
|
+
"view": "View"
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
"core": {
|
|
75
|
+
"crud": {
|
|
76
|
+
"warnBatchDeleteRequestDeleteByRecords": "requestDeleteByRecords is required when actions include batch_delete",
|
|
77
|
+
"warnCreateRequestCreateByValues": "requestCreateByValues is required when actions include create",
|
|
78
|
+
"warnDeleteProps": "deleteProps and requestDeleteByRecord are required when actions include delete",
|
|
79
|
+
"warnReadRequestGetByRecord": "requestGetByRecord is required when actions include read",
|
|
80
|
+
"warnUpdateRequest": "requestGetByRecord and requestUpdateByValues are required when actions include update"
|
|
81
|
+
},
|
|
82
|
+
"crudOfList": {
|
|
83
|
+
"warnAtLeastOneSearch": "At least one column with search set to true is required in CRUDOfList columns",
|
|
84
|
+
"warnOnlyOneSearch": "Only one column with search set to true is allowed in CRUDOfList columns"
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
{
|
|
2
|
+
"@fe-free/core": {
|
|
3
|
+
"app": {
|
|
4
|
+
"mainScriptNotFound": "没找到 [data-name=\"mainScript\"],不启用更新提醒",
|
|
5
|
+
"newVersionFound": "发现新版本",
|
|
6
|
+
"refresh": "刷新",
|
|
7
|
+
"refreshPrompt": "请及时刷新页面更新,以避免影响使用",
|
|
8
|
+
"updateLater": "稍后更新"
|
|
9
|
+
},
|
|
10
|
+
"crud": {
|
|
11
|
+
"batchActionConfirm": "确定要执行 {action} 吗?",
|
|
12
|
+
"batchDelete": "批量删除",
|
|
13
|
+
"cancel": "取消",
|
|
14
|
+
"clearSelection": "取消选择",
|
|
15
|
+
"confirm": "确定",
|
|
16
|
+
"create": "新建",
|
|
17
|
+
"createSuccess": "新建成功",
|
|
18
|
+
"delete": "删除",
|
|
19
|
+
"deleteConfirm": "确认删除 \"{name}\" 吗?",
|
|
20
|
+
"deleteSuccess": "删除成功",
|
|
21
|
+
"deleteWarning": "删除后不可恢复,请谨慎操作",
|
|
22
|
+
"operate": "操作",
|
|
23
|
+
"read": "查看",
|
|
24
|
+
"requestDeleteByRecordRequired": "没有传 requestDeleteByRecord",
|
|
25
|
+
"selectedItems": "已选 {num} 项",
|
|
26
|
+
"update": "编辑",
|
|
27
|
+
"updateSuccess": "更新成功",
|
|
28
|
+
"warnCreateDetailForm": "actions 包含 create 时,需要传递 detailForm",
|
|
29
|
+
"warnReadDetailForm": "actions 包含 read 时,需要传递 detailForm",
|
|
30
|
+
"warnUpdateDetailForm": "actions 包含 update 时,需要传递 detailForm"
|
|
31
|
+
},
|
|
32
|
+
"crudOfList": {
|
|
33
|
+
"searchPlaceholder": "输入搜索"
|
|
34
|
+
},
|
|
35
|
+
"crudOfPure": {
|
|
36
|
+
"inputPlaceholder": "请输入{title}",
|
|
37
|
+
"selectPlaceholder": "请选择{title}"
|
|
38
|
+
},
|
|
39
|
+
"dataViewer": {
|
|
40
|
+
"view": "查看"
|
|
41
|
+
},
|
|
42
|
+
"fileTree": {
|
|
43
|
+
"create": "新建",
|
|
44
|
+
"createSubDirectory": "新建子目录",
|
|
45
|
+
"delete": "删除",
|
|
46
|
+
"directoryName": "目录名称",
|
|
47
|
+
"update": "编辑"
|
|
48
|
+
},
|
|
49
|
+
"formList": {
|
|
50
|
+
"add": "添加",
|
|
51
|
+
"duplicateValue": "不能有重复",
|
|
52
|
+
"edit": "编辑",
|
|
53
|
+
"emptyOption": "存在空选项"
|
|
54
|
+
},
|
|
55
|
+
"infiniteList": {
|
|
56
|
+
"loadingMore": "加载更多数据中...",
|
|
57
|
+
"noMoreData": "没有更多数据"
|
|
58
|
+
},
|
|
59
|
+
"record": {
|
|
60
|
+
"inputPlaceholder": "请输入"
|
|
61
|
+
},
|
|
62
|
+
"upload": {
|
|
63
|
+
"delete": "删除",
|
|
64
|
+
"dragUpload": "点击或拖拽到此区域进行上传",
|
|
65
|
+
"fileCount": "文件数量 ({success}/{total})",
|
|
66
|
+
"localUpload": "本地上传",
|
|
67
|
+
"maxFilesWarning": "最多只能上传 {num} 个文件,超出部分会忽略。",
|
|
68
|
+
"pleaseSelect": "请选择"
|
|
69
|
+
},
|
|
70
|
+
"valueTypeMap": {
|
|
71
|
+
"view": "查看"
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
"core": {
|
|
75
|
+
"crud": {
|
|
76
|
+
"warnBatchDeleteRequestDeleteByRecords": "actions 包含 batch_delete 时,需要传递 requestDeleteByRecords",
|
|
77
|
+
"warnCreateRequestCreateByValues": "actions 包含 create 时,需要传递 requestCreateByValues",
|
|
78
|
+
"warnDeleteProps": "actions 包含 delete 时,需要传递 deleteProps 和 requestDeleteByRecord",
|
|
79
|
+
"warnReadRequestGetByRecord": "actions 包含 read 时,需要传递 requestGetByRecord",
|
|
80
|
+
"warnUpdateRequest": "actions 包含 update 时,需要传递 requestGetByRecord 和 requestUpdateByValues"
|
|
81
|
+
},
|
|
82
|
+
"crudOfList": {
|
|
83
|
+
"warnAtLeastOneSearch": "CRUDOfList 的 columns 中至少有一个 search 为 true 的列",
|
|
84
|
+
"warnOnlyOneSearch": "CRUDOfList 的 columns 中只能有一个 search 为 true 的列"
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
package/src/record/index.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Divider, Input } from 'antd';
|
|
2
2
|
import classNames from 'classnames';
|
|
3
3
|
import { useCallback, useMemo } from 'react';
|
|
4
|
+
import { useTranslation } from 'react-i18next';
|
|
4
5
|
import { ProFormListHelper } from '../form';
|
|
5
6
|
|
|
6
7
|
function Item({
|
|
@@ -12,6 +13,7 @@ function Item({
|
|
|
12
13
|
label?: string;
|
|
13
14
|
onChange: (value: string) => void;
|
|
14
15
|
}) {
|
|
16
|
+
const { t } = useTranslation();
|
|
15
17
|
return (
|
|
16
18
|
<div className="flex flex-col gap-2">
|
|
17
19
|
<div className="flex items-center gap-1">
|
|
@@ -20,7 +22,7 @@ function Item({
|
|
|
20
22
|
</div>
|
|
21
23
|
<Input
|
|
22
24
|
value={value}
|
|
23
|
-
placeholder={'请输入'}
|
|
25
|
+
placeholder={t('@fe-free/core.record.inputPlaceholder', '请输入')}
|
|
24
26
|
onChange={(e) => {
|
|
25
27
|
onChange(e.target.value);
|
|
26
28
|
}}
|
package/src/tree/file_tree.tsx
CHANGED
|
@@ -4,6 +4,7 @@ import { Dropdown } from 'antd';
|
|
|
4
4
|
import type { DataNode } from 'antd/es/tree';
|
|
5
5
|
import classNames from 'classnames';
|
|
6
6
|
import { useCallback, useMemo } from 'react';
|
|
7
|
+
import { useTranslation } from 'react-i18next';
|
|
7
8
|
import { OperateDelete } from '../crud/crud_delete';
|
|
8
9
|
import { FileCard } from '../file';
|
|
9
10
|
import type { TreeProps } from './tree';
|
|
@@ -46,13 +47,14 @@ function Detail<D extends DataNode>({
|
|
|
46
47
|
requestUpdateByValues?: FileTreeProps<D>['requestUpdateByValues'];
|
|
47
48
|
trigger: React.ReactElement;
|
|
48
49
|
}) {
|
|
50
|
+
const { t } = useTranslation();
|
|
49
51
|
const title = useMemo(() => {
|
|
50
52
|
if (action === 'create') {
|
|
51
|
-
return '新建';
|
|
53
|
+
return t('@fe-free/core.fileTree.create', '新建');
|
|
52
54
|
}
|
|
53
55
|
|
|
54
|
-
return '编辑';
|
|
55
|
-
}, [action]);
|
|
56
|
+
return t('@fe-free/core.fileTree.update', '编辑');
|
|
57
|
+
}, [action, t]);
|
|
56
58
|
|
|
57
59
|
return (
|
|
58
60
|
<ModalForm
|
|
@@ -83,7 +85,12 @@ function Detail<D extends DataNode>({
|
|
|
83
85
|
labelCol={{ span: 6 }}
|
|
84
86
|
>
|
|
85
87
|
<ProFormText name="key" hidden />
|
|
86
|
-
<ProFormText
|
|
88
|
+
<ProFormText
|
|
89
|
+
name="title"
|
|
90
|
+
label={t('@fe-free/core.fileTree.directoryName', '目录名称')}
|
|
91
|
+
required
|
|
92
|
+
rules={[{ required: true }]}
|
|
93
|
+
/>
|
|
87
94
|
</ModalForm>
|
|
88
95
|
);
|
|
89
96
|
}
|
|
@@ -98,6 +105,7 @@ function More({
|
|
|
98
105
|
updateProps,
|
|
99
106
|
deleteProps,
|
|
100
107
|
}) {
|
|
108
|
+
const { t } = useTranslation();
|
|
101
109
|
const isCreateDisabled = createProps?.operateIsDisabled?.(nodeData);
|
|
102
110
|
const isCreateHidden = createProps?.operateIsHidden?.(nodeData);
|
|
103
111
|
const isUpdateDisabled = updateProps?.operateIsDisabled?.(nodeData);
|
|
@@ -109,13 +117,15 @@ function More({
|
|
|
109
117
|
actions?.includes('create') &&
|
|
110
118
|
!isCreateHidden && {
|
|
111
119
|
label: isCreateDisabled ? (
|
|
112
|
-
<div className="cursor-not-allowed text-03"
|
|
120
|
+
<div className="cursor-not-allowed text-03">
|
|
121
|
+
{t('@fe-free/core.fileTree.createSubDirectory', '新建子目录')}
|
|
122
|
+
</div>
|
|
113
123
|
) : (
|
|
114
124
|
<Detail
|
|
115
125
|
action="create"
|
|
116
126
|
nodeData={{ key: nodeData.key }}
|
|
117
127
|
requestCreateByValues={(values) => requestCreateByValues?.({ ...values })}
|
|
118
|
-
trigger={<div
|
|
128
|
+
trigger={<div>{t('@fe-free/core.fileTree.createSubDirectory', '新建子目录')}</div>}
|
|
119
129
|
/>
|
|
120
130
|
),
|
|
121
131
|
key: 'create',
|
|
@@ -123,13 +133,15 @@ function More({
|
|
|
123
133
|
actions?.includes('update') &&
|
|
124
134
|
!isUpdateHidden && {
|
|
125
135
|
label: isUpdateDisabled ? (
|
|
126
|
-
<div className="cursor-not-allowed text-03"
|
|
136
|
+
<div className="cursor-not-allowed text-03">
|
|
137
|
+
{t('@fe-free/core.fileTree.update', '编辑')}
|
|
138
|
+
</div>
|
|
127
139
|
) : (
|
|
128
140
|
<Detail
|
|
129
141
|
action="update"
|
|
130
142
|
nodeData={nodeData}
|
|
131
143
|
requestUpdateByValues={(values) => requestUpdateByValues?.({ ...values })}
|
|
132
|
-
trigger={<div
|
|
144
|
+
trigger={<div>{t('@fe-free/core.fileTree.update', '编辑')}</div>}
|
|
133
145
|
/>
|
|
134
146
|
),
|
|
135
147
|
key: 'update',
|
|
@@ -137,11 +149,13 @@ function More({
|
|
|
137
149
|
actions?.includes('delete') &&
|
|
138
150
|
!isDeleteHidden && {
|
|
139
151
|
label: isDeleteDisabled ? (
|
|
140
|
-
<div className="cursor-not-allowed text-03"
|
|
152
|
+
<div className="cursor-not-allowed text-03">
|
|
153
|
+
{t('@fe-free/core.fileTree.delete', '删除')}
|
|
154
|
+
</div>
|
|
141
155
|
) : (
|
|
142
156
|
<OperateDelete
|
|
143
157
|
name={nodeData.title}
|
|
144
|
-
operateText=
|
|
158
|
+
operateText={t('@fe-free/core.fileTree.delete', '删除')}
|
|
145
159
|
onDelete={() => requestDeleteByRecord?.({ key: nodeData.key })}
|
|
146
160
|
/>
|
|
147
161
|
),
|