@zjlab-fe/data-hub-ui 0.32.6 → 0.33.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.
Files changed (73) hide show
  1. package/dist/types/components/FileUploader/UploadStoreProvider/UploadStoreProvider.d.ts +4 -1
  2. package/dist/types/components/SDK-modal/document-link.d.ts +1 -3
  3. package/dist/types/components/SDK-modal/index.d.ts +4 -0
  4. package/dist/types/components/SDK-modal/inner-modal.d.ts +9 -0
  5. package/dist/types/components/SDK-modal/types.d.ts +4 -3
  6. package/dist/types/components/apply-perm-modal/index.d.ts +14 -5
  7. package/dist/types/components/confirm-again/index.d.ts +8 -1
  8. package/dist/types/components/copy/index.d.ts +9 -4
  9. package/dist/types/components/limit-credit-modal/index.d.ts +9 -3
  10. package/dist/types/components/tag-group-filter/dataSizeFilter.d.ts +0 -1
  11. package/dist/types/components/tag-group-filter/index.d.ts +4 -1
  12. package/dist/types/index.d.ts +7 -5
  13. package/dist/types/locale/index.d.ts +18 -0
  14. package/dist/types/locale/modalHolder.d.ts +11 -0
  15. package/dist/types/locale/resolveLocale.d.ts +9 -0
  16. package/dist/types/locale/translations.d.ts +808 -0
  17. package/dist/types/locale/types.d.ts +32 -0
  18. package/es/components/FileUploader/Locale/useTranslate.js +34 -11
  19. package/es/components/FileUploader/UploadStoreProvider/UploadStoreProvider.js +5 -3
  20. package/es/components/FileUploader/hooks/useOnMountedResumeUnfinished.js +6 -3
  21. package/es/components/SDK-modal/document-link.js +5 -2
  22. package/es/components/SDK-modal/index.js +29 -2
  23. package/es/components/SDK-modal/inner-modal.js +23 -12
  24. package/es/components/apply-perm-modal/index.js +20 -8
  25. package/es/components/confirm-again/index.js +12 -2
  26. package/es/components/copy/index.js +21 -7
  27. package/es/components/data-table/index.js +15 -4
  28. package/es/components/dataset-batch-action/index.js +48 -25
  29. package/es/components/file-preview/data-table/index.js +4 -3
  30. package/es/components/file-preview/index.js +5 -4
  31. package/es/components/file-uploader/components/uploader-drop-zone.js +4 -2
  32. package/es/components/file-uploader/components/uploader-file-item.js +12 -9
  33. package/es/components/file-uploader/components/uploader-file-list.js +6 -3
  34. package/es/components/file-uploader/components/uploader.js +4 -2
  35. package/es/components/file-uploader/components/uploading-status.js +18 -12
  36. package/es/components/header/index.js +3 -1
  37. package/es/components/input-tag/index.js +5 -2
  38. package/es/components/limit-credit-modal/index.js +38 -19
  39. package/es/components/menu/index.js +5 -2
  40. package/es/components/notion-editor/code-block/languages.js +1 -1
  41. package/es/components/notion-editor/index.js +23 -13
  42. package/es/components/operator-chain/components/AddButton.js +3 -1
  43. package/es/components/operator-chain/components/IOCard.js +4 -1
  44. package/es/components/operator-chain/components/VirtualDropdown.js +6 -3
  45. package/es/components/permission-editor/index.js +1 -0
  46. package/es/components/permission-editor/permissionEditModal/index.js +7 -4
  47. package/es/components/permission-editor/permissionEditor/index.js +40 -75
  48. package/es/components/permission-editor/permissionViewPopover/index.js +5 -2
  49. package/es/components/tag-group-filter/dataSizeFilter.js +6 -3
  50. package/es/components/tag-group-filter/index.js +2 -2
  51. package/es/components/tip-tap/bubble-menu.js +8 -3
  52. package/es/components/tip-tap/editor.js +5 -2
  53. package/es/components/tip-tap/extensions/index.js +1 -1
  54. package/es/components/tip-tap/toolbar/components/color-picker.js +3 -1
  55. package/es/components/tip-tap/toolbar/components/heading-dropdown.js +8 -5
  56. package/es/components/tip-tap/toolbar/components/link-button.js +4 -1
  57. package/es/components/tip-tap/toolbar/components/table-button.js +5 -2
  58. package/es/components/tip-tap/toolbar/index.js +4 -1
  59. package/es/components/uploadDrawer/fileUploadDrawer.js +6 -2
  60. package/es/components/uploadDrawer/fileUploadDrawerList.js +4 -1
  61. package/es/components/uploadDrawer/fileUploadDrawerListProgressButton.js +4 -2
  62. package/es/components/uploadDrawer/hooks/useCancelUpload.js +3 -1
  63. package/es/components/uploadDrawer/hooks/useFilterFiles.js +7 -4
  64. package/es/components/uploadDrawer/hooks/useFormatFiles.js +3 -1
  65. package/es/components/uploadDrawer/hooks/useResumeUnfinishedUploads.js +7 -6
  66. package/es/components/uploadDrawer/index.js +4 -2
  67. package/es/index.js +6 -5
  68. package/es/locale/index.js +64 -0
  69. package/es/locale/modalHolder.js +21 -0
  70. package/es/locale/resolveLocale.js +73 -0
  71. package/es/locale/translations.js +273 -0
  72. package/lib/index.js +1 -1
  73. package/package.json +7 -3
@@ -0,0 +1,32 @@
1
+ import { translations } from './translations';
2
+ export type DataHubLang = 'zh' | 'en';
3
+ export type DataHubAntdMode = 'inherit' | 'isolated';
4
+ export type DataHubThemeToken = {
5
+ colorPrimary?: string;
6
+ colorSuccess?: string;
7
+ colorWarning?: string;
8
+ colorError?: string;
9
+ colorInfo?: string;
10
+ colorBgBase?: string;
11
+ colorTextBase?: string;
12
+ borderRadius?: number;
13
+ fontFamily?: string;
14
+ fontSize?: number;
15
+ motion?: boolean;
16
+ };
17
+ export type DataHubTheme = {
18
+ token?: DataHubThemeToken;
19
+ darkMode?: boolean;
20
+ };
21
+ type MessageLeaf = {
22
+ zh: string;
23
+ en: string;
24
+ };
25
+ type ProjectedMessages<T> = T extends MessageLeaf ? string : T extends Record<string, unknown> ? {
26
+ [K in keyof T]: ProjectedMessages<T[K]>;
27
+ } : T;
28
+ export type DataHubLocaleMessages = ProjectedMessages<typeof translations>;
29
+ export type DataHubLocale = {
30
+ locale: DataHubLang;
31
+ } & DataHubLocaleMessages;
32
+ export {};
@@ -1,16 +1,39 @@
1
- import { useContext, useCallback } from 'react';
2
- import { FileUploaderLocaleContext } from '../UploadStoreProvider/UploadStoreProvider.js';
1
+ import { useLocale } from '../../../locale/index.js';
3
2
 
3
+ const LEGACY_KEY_MAP = {
4
+ 'FileUploader 必须在 UploadStoreProvider 内使用': 'mustUseProvider',
5
+ 'FileUploadModal 必须在 UploadStoreProvider 内使用': 'modalMustUseProvider',
6
+ 文件上传: 'title',
7
+ 确定: 'confirm',
8
+ 等待上传: 'waiting',
9
+ 已取消: 'cancelled',
10
+ 上传中: 'uploading',
11
+ 上传失败: 'failed',
12
+ 已上传: 'uploaded',
13
+ 分块合并中: 'mergingParts',
14
+ 以下文件大小超过: 'sizeExceededPrefix',
15
+ 已删除: 'deleted',
16
+ 点击或拖拽上传文件: 'dropHint',
17
+ '发现同名文件,是否覆盖?': 'duplicateTitle',
18
+ 覆盖: 'overwrite',
19
+ 取消: 'cancel',
20
+ 正在上传: 'uploadingNow',
21
+ 取消失败: 'cancelFailed',
22
+ 当前上传: 'currentUpload',
23
+ 已暂停: 'paused',
24
+ 上传成功: 'success',
25
+ 校验中: 'calibrating',
26
+ 合并中: 'merging',
27
+ 部分文件获取上传地址失败: 'getUrlFailed',
28
+ };
4
29
  function useTranslate() {
5
- const locale = useContext(FileUploaderLocaleContext);
6
- return useCallback((key) => {
7
- const content = locale[key];
8
- if (!content) {
9
- console.warn(`Translation key not found: ${key}`);
10
- return key;
11
- }
12
- return content;
13
- }, [locale]);
30
+ const { locale } = useLocale();
31
+ return (key) => {
32
+ const mapped = LEGACY_KEY_MAP[key];
33
+ if (mapped)
34
+ return locale.FileUploader[mapped];
35
+ return key;
36
+ };
14
37
  }
15
38
 
16
39
  export { useTranslate };
@@ -1,6 +1,7 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
2
  import { createContext, useReducer, useState } from 'react';
3
3
  import { useSaveUnfinishedUploads } from './useSaveUnfinishedUploads.js';
4
+ import { useLocale } from '../../../locale/index.js';
4
5
  import { localeZh, localeEn } from '../Locale/translations.js';
5
6
  import { useSetupMergingEvent } from './useSetupMergingEvent.js';
6
7
  import { useOnFileAllUploaded } from './useOnFileAllUploaded.js';
@@ -17,15 +18,16 @@ const UploadStoreDispatchContext = createContext(() => null);
17
18
  /**
18
19
  * @deprecated This component is deprecated and will be removed in future releases.
19
20
  */
20
- function UploadStoreProvider({ locale = 'zh', children, }) {
21
- const FileUploaderLocale = locale === 'zh' ? localeZh : localeEn;
21
+ function UploadStoreProvider({ locale: _locale, children, }) {
22
+ const { locale } = useLocale();
23
+ const fileUploaderLocale = locale.locale === 'en' ? localeEn : localeZh;
22
24
  const [uploadStore, setUploadStore] = useReducer(uploadReducer, {});
23
25
  const [allUploaderManagers, setAllUploaderManagers] = useState({});
24
26
  const [allOnUploadSuccesses, setAllOnUploadSuccesses] = useState({});
25
27
  useSaveUnfinishedUploads(uploadStore);
26
28
  useOnFileAllUploaded(uploadStore, setUploadStore);
27
29
  useSetupMergingEvent(uploadStore, allUploaderManagers, allOnUploadSuccesses, setUploadStore);
28
- return (jsx(FileUploaderLocaleContext.Provider, { value: FileUploaderLocale, children: jsx(AllUploaderManagersContext.Provider, { value: allUploaderManagers, children: jsx(AllUploaderManagersDispatchContext.Provider, { value: setAllUploaderManagers, children: jsx(AllOnUploadSuccessesContext.Provider, { value: allOnUploadSuccesses, children: jsx(AllOnUploadSuccessesDispatchContext.Provider, { value: setAllOnUploadSuccesses, children: jsx(UploadStoreContext.Provider, { value: uploadStore, children: jsx(UploadStoreDispatchContext.Provider, { value: setUploadStore, children: children }) }) }) }) }) }) }));
30
+ return (jsx(FileUploaderLocaleContext.Provider, { value: fileUploaderLocale, children: jsx(AllUploaderManagersContext.Provider, { value: allUploaderManagers, children: jsx(AllUploaderManagersDispatchContext.Provider, { value: setAllUploaderManagers, children: jsx(AllOnUploadSuccessesContext.Provider, { value: allOnUploadSuccesses, children: jsx(AllOnUploadSuccessesDispatchContext.Provider, { value: setAllOnUploadSuccesses, children: jsx(UploadStoreContext.Provider, { value: uploadStore, children: jsx(UploadStoreDispatchContext.Provider, { value: setUploadStore, children: children }) }) }) }) }) }) }));
29
31
  }
30
32
 
31
33
  export { AllOnUploadSuccessesContext, AllOnUploadSuccessesDispatchContext, AllUploaderManagersContext, AllUploaderManagersDispatchContext, FileUploaderLocaleContext, TEMP_STORE, UploadStoreContext, UploadStoreDispatchContext, UploadStoreProvider as default };
@@ -7,23 +7,26 @@ import { useContext, useCallback } from 'react';
7
7
  import { useRetryUpload } from './useRetryUpload.js';
8
8
  import { UploadStoreDispatchContext } from '../UploadStoreProvider/UploadStoreProvider.js';
9
9
  import { confirmModalConfig } from '../utils/modalConfig.js';
10
+ import { useLocale } from '../../../locale/index.js';
10
11
 
11
12
  function useOnMountedResumeUnfinished(identifier) {
12
13
  const { message, modal } = App.useApp();
14
+ const { locale } = useLocale();
15
+ const texts = locale.FileUploader;
13
16
  const setUploadStore = useContext(UploadStoreDispatchContext);
14
17
  const retryUpload = useRetryUpload();
15
18
  return useCallback(() => __awaiter(this, void 0, void 0, function* () {
16
19
  const prevUploadableFiles = yield reloadSaveData(identifier);
17
20
  setUploadStore({ type: 'add_files', identifier, files: prevUploadableFiles });
18
21
  if (prevUploadableFiles.length) {
19
- modal.confirm(Object.assign(Object.assign({}, confirmModalConfig), { title: '提示', content: '检测到未完成上传任务,是否继续上传?', onOk() {
22
+ modal.confirm(Object.assign(Object.assign({}, confirmModalConfig), { title: texts.notice, content: texts.unfinishedContent, onOk() {
20
23
  prevUploadableFiles.forEach((file) => retryUpload(file));
21
24
  },
22
25
  onCancel() {
23
- message.info('点击上传按钮手动继续');
26
+ message.info(texts.resumeManually);
24
27
  } }));
25
28
  }
26
- }), [identifier, setUploadStore, retryUpload, modal, message]);
29
+ }), [identifier, setUploadStore, retryUpload, modal, message, texts]);
27
30
  }
28
31
  function reloadSaveData(identifier) {
29
32
  return __awaiter(this, void 0, void 0, function* () {
@@ -1,8 +1,11 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
2
  import { documentLink, documentLinkAnchor } from './index.module.scss.js';
3
+ import { useLocale } from '../../locale/index.js';
3
4
 
4
- function DocumentationLink({ link, locale }) {
5
- return (jsxs("span", { className: documentLink, children: [locale['documentPrefix'], jsx("a", { href: link, target: "_blank", rel: "noopener noreferrer", className: documentLinkAnchor, children: locale['documentLinkText'] })] }));
5
+ function DocumentationLink({ link }) {
6
+ const { locale } = useLocale();
7
+ const texts = locale.SDKModal;
8
+ return (jsxs("span", { className: documentLink, children: [texts.documentPrefix, jsx("a", { href: link, target: "_blank", rel: "noopener noreferrer", className: documentLinkAnchor, children: texts.documentLinkText })] }));
6
9
  }
7
10
 
8
11
  export { DocumentationLink as default };
@@ -1,6 +1,8 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
2
  import { createRoot } from 'react-dom/client';
3
- import InnerModal from './inner-modal.js';
3
+ import InnerModal, { defaultModalConfig, SDKModalContent } from './inner-modal.js';
4
+ import { useLocale } from '../../locale/index.js';
5
+ import { useDataHubModal } from '../../locale/modalHolder.js';
4
6
 
5
7
  function showSDKModal(config) {
6
8
  const container = document.createElement('div');
@@ -16,10 +18,35 @@ function showSDKModal(config) {
16
18
  root.render(jsx(InnerModal, { open: true, onClose: destroy, SDKCode: config.SDKCode, loadSDK: config.loadSDK, title: config.title, subTitle: config.subTitle, modalConfig: config.modalConfig, documentLink: config.documentLink, locale: config.locale }));
17
19
  return { destroy };
18
20
  }
21
+ function useSDKModal() {
22
+ const { locale } = useLocale();
23
+ const modal = useDataHubModal();
24
+ const sdkTexts = locale.SDKModal;
25
+ return (config) => {
26
+ var _a, _b, _c, _d, _e;
27
+ const modalConfig = (_a = config.modalConfig) !== null && _a !== void 0 ? _a : {};
28
+ const widthCandidate = (_b = modalConfig.width) !== null && _b !== void 0 ? _b : defaultModalConfig.width;
29
+ const width = typeof widthCandidate === 'number' || typeof widthCandidate === 'string' ? widthCandidate : 600;
30
+ return modal.confirm({
31
+ title: config.title,
32
+ content: (jsx(SDKModalContent, { SDKCode: config.SDKCode, loadSDK: config.loadSDK, subTitle: config.subTitle, documentLink: config.documentLink })),
33
+ icon: null,
34
+ okCancel: false,
35
+ okText: sdkTexts.confirm,
36
+ width,
37
+ centered: (_c = modalConfig.centered) !== null && _c !== void 0 ? _c : defaultModalConfig.centered,
38
+ closable: (_d = modalConfig.closable) !== null && _d !== void 0 ? _d : defaultModalConfig.closable,
39
+ styles: (_e = modalConfig.styles) !== null && _e !== void 0 ? _e : defaultModalConfig.styles,
40
+ onOk: () => { var _a; return (_a = config.onClose) === null || _a === void 0 ? void 0 : _a.call(config); },
41
+ onCancel: () => { var _a; return (_a = config.onClose) === null || _a === void 0 ? void 0 : _a.call(config); },
42
+ footer: (_originNode, { OkBtn }) => (jsx("div", { style: { textAlign: 'center' }, children: jsx(OkBtn, {}) })),
43
+ });
44
+ };
45
+ }
19
46
  function SDKModalComponent(props) {
20
47
  return jsx(InnerModal, Object.assign({}, props));
21
48
  }
22
49
  const SDKModal = SDKModalComponent;
23
50
  SDKModal.show = showSDKModal;
24
51
 
25
- export { SDKModal as default, showSDKModal };
52
+ export { SDKModal as default, showSDKModal, useSDKModal };
@@ -1,11 +1,11 @@
1
- import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
- import { Modal, Spin, Flex, Button } from 'antd';
1
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
2
+ import { Spin, Flex, Modal, Button } from 'antd';
3
3
  import { memo, useState, useEffect } from 'react';
4
4
  import classNames from 'classnames';
5
5
  import Copy from '../copy/index.js';
6
6
  import DocumentationLink from './document-link.js';
7
- import { getLocale } from './locale/translations.js';
8
7
  import { codeBlock, loading, errorText, codeContent } from './index.module.scss.js';
8
+ import { useLocale } from '../../locale/index.js';
9
9
 
10
10
  const defaultModalConfig = {
11
11
  width: 600,
@@ -19,13 +19,13 @@ const defaultModalConfig = {
19
19
  content: { padding: '20px 20px 16px 20px', borderRadius: '10px' },
20
20
  },
21
21
  };
22
- var InnerModal = memo(function InnerModal({ open, onClose, SDKCode, loadSDK, title, subTitle, modalConfig, documentLink, locale, }) {
22
+ const SDKModalContent = memo(function SDKModalContent({ SDKCode, loadSDK, subTitle, documentLink, active = true, }) {
23
23
  const [code, setCode] = useState('');
24
24
  const [loading$1, setLoading] = useState(false);
25
25
  const [error, setError] = useState('');
26
- const resolvedLocale = getLocale(locale);
27
26
  useEffect(() => {
28
- if (!open) {
27
+ let requestActive = true;
28
+ if (!active) {
29
29
  setCode('');
30
30
  setError('');
31
31
  setLoading(false);
@@ -41,19 +41,30 @@ var InnerModal = memo(function InnerModal({ open, onClose, SDKCode, loadSDK, tit
41
41
  setLoading(true);
42
42
  loadSDK()
43
43
  .then((result) => {
44
- setCode(result);
44
+ if (requestActive)
45
+ setCode(result);
45
46
  })
46
47
  .catch((err) => {
47
48
  var _a;
48
- setError((_a = err === null || err === void 0 ? void 0 : err.message) !== null && _a !== void 0 ? _a : String(err));
49
+ if (requestActive)
50
+ setError((_a = err === null || err === void 0 ? void 0 : err.message) !== null && _a !== void 0 ? _a : String(err));
49
51
  })
50
52
  .finally(() => {
51
- setLoading(false);
53
+ if (requestActive)
54
+ setLoading(false);
52
55
  });
53
56
  }
54
- }, [open, SDKCode, loadSDK]);
57
+ return () => {
58
+ requestActive = false;
59
+ };
60
+ }, [active, SDKCode, loadSDK]);
61
+ return (jsxs(Fragment, { children: [subTitle && jsx("div", { children: subTitle }), jsx(Spin, { spinning: loading$1, className: classNames(codeBlock, loading) }), !loading$1 && (jsx(Flex, { align: "start", justify: "space-between", className: codeBlock, children: error ? (jsx("span", { className: errorText, children: error })) : (jsxs(Fragment, { children: [jsx("div", { className: codeContent, dangerouslySetInnerHTML: { __html: code.replace(/\n/g, '<br>') } }), jsx(Copy, { text: code, showFeedback: true })] })) })), documentLink && jsx(DocumentationLink, { link: documentLink })] }));
62
+ });
63
+ var InnerModal = memo(function InnerModal({ open, onClose, SDKCode, loadSDK, title, subTitle, modalConfig, documentLink, locale: _locale, }) {
64
+ const { locale } = useLocale();
65
+ const texts = locale.SDKModal;
55
66
  const mergedConfig = Object.assign(Object.assign({}, defaultModalConfig), modalConfig);
56
- return (jsxs(Modal, Object.assign({}, mergedConfig, { open: open, title: title, onCancel: onClose, footer: jsx(Button, { type: "primary", onClick: onClose, children: resolvedLocale['confirm'] }), children: [subTitle && jsx("div", { children: subTitle }), jsx(Spin, { spinning: loading$1, className: classNames(codeBlock, loading) }), !loading$1 && (jsx(Flex, { align: "start", justify: "space-between", className: codeBlock, children: error ? (jsx("span", { className: errorText, children: error })) : (jsxs(Fragment, { children: [jsx("div", { className: codeContent, dangerouslySetInnerHTML: { __html: code.replace(/\n/g, '<br>') } }), jsx(Copy, { text: code, showFeedback: true })] })) })), documentLink && jsx(DocumentationLink, { link: documentLink, locale: resolvedLocale })] })));
67
+ return (jsx(Modal, Object.assign({}, mergedConfig, { open: open, title: title, onCancel: onClose, footer: jsx(Button, { type: "primary", onClick: onClose, children: texts.confirm }), children: jsx(SDKModalContent, { active: open, SDKCode: SDKCode, loadSDK: loadSDK, subTitle: subTitle, documentLink: documentLink }) })));
57
68
  });
58
69
 
59
- export { InnerModal as default };
70
+ export { SDKModalContent, InnerModal as default, defaultModalConfig };
@@ -2,6 +2,8 @@ import { jsxs, jsx } from 'react/jsx-runtime';
2
2
  import { Flex, Button, Modal } from 'antd';
3
3
  import { noModalWrap, title, content, footer, permModal, permFunModal } from './index.module.scss.js';
4
4
  import { isPublicNetwork } from '@zjlab-fe/util';
5
+ import { useLocale } from '../../locale/index.js';
6
+ import { useDataHubModal } from '../../locale/modalHolder.js';
5
7
 
6
8
  const okText = {
7
9
  zh: '申请',
@@ -24,30 +26,40 @@ const applyUrl = (isPublic) => isPublic
24
26
  : 'https://alidocs.dingtalk.com/notable/share/form/v01Q35O8510LgZgBl9V_dv19yqvsgs3oebp3pcjys_1qX0QQ0';
25
27
  /**
26
28
  * 申请权限弹窗
27
- * @param locale {string} 语言 'zh' | 'en',默认zh
29
+ * @param locale 已废弃,语言由 DataHubProvider / antd ConfigProvider 决定
28
30
  * @param open {boolean} 是否展示弹窗
29
31
  * @param noModal {boolean} 是否以非弹窗形式展示
30
32
  * @param onCancel {function} 取消回调
31
- * @returns
32
33
  */
33
34
  function ApplyPermModal(props) {
34
- const { locale = 'zh', noModal = false } = props;
35
+ const { noModal = false } = props;
36
+ const { locale } = useLocale();
37
+ const lang = locale.locale;
35
38
  const handleApply = () => window.open(applyUrl(isPublicNetwork()), '_blank');
36
39
  if (noModal) {
37
- return (jsxs(Flex, { vertical: true, align: "center", gap: 8, className: noModalWrap, children: [jsx("div", { className: title, children: titleText[locale] }), jsx("div", { className: content, children: contentText[locale] }), jsx(Flex, { className: footer, children: jsx(Button, { type: "primary", onClick: handleApply, children: okText[locale] }) })] }));
40
+ return (jsxs(Flex, { vertical: true, align: "center", gap: 8, className: noModalWrap, children: [jsx("div", { className: title, children: titleText[lang] }), jsx("div", { className: content, children: contentText[lang] }), jsx(Flex, { className: footer, children: jsx(Button, { type: "primary", onClick: handleApply, children: okText[lang] }) })] }));
38
41
  }
39
- return (jsx(Modal, Object.assign({}, props, { title: titleText[locale], onOk: handleApply, okText: okText[locale], cancelText: cancelText[locale], wrapClassName: permModal, width: 400, children: contentText[locale] })));
42
+ return (jsx(Modal, Object.assign({}, props, { title: titleText[lang], onOk: handleApply, okText: okText[lang], cancelText: cancelText[lang], wrapClassName: permModal, width: 400, children: contentText[lang] })));
40
43
  }
41
44
  ApplyPermModal.confirm = (props) => {
42
- const { locale = 'zh' } = props || {};
43
45
  const handleApply = () => window.open(applyUrl(isPublicNetwork()), '_blank');
44
- const modal = Modal.confirm(Object.assign(Object.assign({}, props), { open: true, title: titleText[locale], content: contentText[locale], onOk: handleApply, okText: okText[locale], cancelText: cancelText[locale] }));
46
+ const modal = Modal.confirm(Object.assign(Object.assign({}, props), { open: true, title: titleText.zh, content: contentText.zh, onOk: handleApply, okText: okText.zh, cancelText: cancelText.zh }));
45
47
  modal.update({
46
48
  icon: null,
47
49
  closable: true,
48
50
  width: 400,
49
51
  wrapClassName: `${permFunModal}`,
50
52
  });
53
+ return modal;
51
54
  };
55
+ function useApplyPermModal() {
56
+ const { locale } = useLocale();
57
+ const modal = useDataHubModal();
58
+ const lang = locale.locale;
59
+ return (props) => {
60
+ const handleApply = () => window.open(applyUrl(isPublicNetwork()), '_blank');
61
+ return modal.confirm(Object.assign(Object.assign({}, props), { open: true, title: titleText[lang], content: contentText[lang], onOk: handleApply, okText: okText[lang], cancelText: cancelText[lang], icon: null, closable: true, width: 400, wrapClassName: permFunModal }));
62
+ };
63
+ }
52
64
 
53
- export { ApplyPermModal as default };
65
+ export { ApplyPermModal as default, useApplyPermModal };
@@ -1,6 +1,8 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
2
  import { Modal } from 'antd';
3
3
  import classNames from 'classnames';
4
+ import { useLocale } from '../../locale/index.js';
5
+ import { useDataHubModal } from '../../locale/modalHolder.js';
4
6
  import useStyle from './index.scss.js';
5
7
 
6
8
  useStyle();
@@ -10,7 +12,15 @@ function ConfirmAgain(props) {
10
12
  }
11
13
  ConfirmAgain.confirm = (props) => {
12
14
  var _a, _b, _c;
13
- Modal.confirm(Object.assign(Object.assign({}, props), { width: (_a = props.width) !== null && _a !== void 0 ? _a : 400, closable: (_b = props.closable) !== null && _b !== void 0 ? _b : true, icon: (_c = props.icon) !== null && _c !== void 0 ? _c : null, wrapClassName: classNames('data-hub-ui-confirm-wrap', props.wrapClassName) }));
15
+ return Modal.confirm(Object.assign(Object.assign({}, props), { width: (_a = props.width) !== null && _a !== void 0 ? _a : 400, closable: (_b = props.closable) !== null && _b !== void 0 ? _b : true, icon: (_c = props.icon) !== null && _c !== void 0 ? _c : null, wrapClassName: classNames('data-hub-ui-confirm-wrap', props.wrapClassName) }));
14
16
  };
17
+ function useConfirmAgain() {
18
+ const { locale } = useLocale();
19
+ const modal = useDataHubModal();
20
+ return (props) => {
21
+ var _a, _b, _c, _d, _e;
22
+ return modal.confirm(Object.assign(Object.assign({}, props), { width: (_a = props.width) !== null && _a !== void 0 ? _a : 400, closable: (_b = props.closable) !== null && _b !== void 0 ? _b : true, icon: (_c = props.icon) !== null && _c !== void 0 ? _c : null, okText: (_d = props.okText) !== null && _d !== void 0 ? _d : locale.Common.confirm, cancelText: (_e = props.cancelText) !== null && _e !== void 0 ? _e : locale.Common.cancel, wrapClassName: classNames('data-hub-ui-confirm-wrap', props.wrapClassName) }));
23
+ };
24
+ }
15
25
 
16
- export { ConfirmAgain as default };
26
+ export { ConfirmAgain as default, useConfirmAgain };
@@ -3,39 +3,53 @@ import { message } from 'antd';
3
3
  import copyToClipboard from 'copy-to-clipboard';
4
4
  import { icon } from './index.module.scss.js';
5
5
  import classNames from 'classnames';
6
+ import { useLocale } from '../../locale/index.js';
6
7
 
7
8
  const successMsg = {
8
9
  zh: '已复制',
9
10
  en: 'Copied',
10
11
  };
11
12
  function Copy(props) {
12
- const { showFeedback = true, text, locale = 'zh' } = props;
13
+ const { showFeedback = true, text } = props;
14
+ const { locale } = useLocale();
13
15
  const onClick = () => {
14
16
  if (text) {
15
17
  copyToClipboard(text);
16
18
  if (showFeedback) {
17
- message.success(successMsg[locale]);
19
+ message.success(successMsg[locale.locale]);
18
20
  }
19
21
  }
20
22
  (props === null || props === void 0 ? void 0 : props.onClick) && props.onClick();
21
23
  };
22
24
  return (jsx("span", { className: classNames(icon, 'data-hub-ui-copy-icon'), onClick: onClick, children: "\uE85C" }));
23
25
  }
26
+ function useCopy() {
27
+ const { locale } = useLocale();
28
+ return (text, options = { showFeedback: true }) => {
29
+ const { showFeedback = true } = options;
30
+ if (text) {
31
+ copyToClipboard(text);
32
+ if (showFeedback) {
33
+ message.success(successMsg[locale.locale]);
34
+ }
35
+ }
36
+ };
37
+ }
24
38
  /**
25
39
  * 复制文本内容到粘贴板
26
40
  * @param text {string} 文本内容
27
41
  * @param options {object} 其它选项
28
42
  * @param options.showFeedback {boolean} 是否展示复制成功的反馈信息,默认展示
29
- * @param options.locale {string} 语言,默认:zh
43
+ * @param options.locale 已废弃,语言由 DataHubProvider / antd ConfigProvider 决定
30
44
  */
31
- function copy(text, options = { showFeedback: true, locale: 'zh' }) {
32
- const { showFeedback = 'true', locale = 'zh' } = options;
45
+ function copy(text, options = { showFeedback: true }) {
46
+ const { showFeedback = true } = options;
33
47
  if (text) {
34
48
  copyToClipboard(text);
35
49
  if (showFeedback) {
36
- message.success(successMsg[locale]);
50
+ message.success(successMsg.zh);
37
51
  }
38
52
  }
39
53
  }
40
54
 
41
- export { copy, Copy as default };
55
+ export { copy, Copy as default, useCopy };
@@ -3,6 +3,7 @@ import React from 'react';
3
3
  import { Table, Empty } from 'antd';
4
4
  import ActionCell from './action-cell.js';
5
5
  import { dataTable, dataTableRowClickable, truncateText, truncateTextExpanded } from './index.module.scss.js';
6
+ import { useLocale } from '../../locale/index.js';
6
7
 
7
8
  const DEFAULT_MIN_WIDTH = 920;
8
9
  const DEFAULT_EXPAND_MAX_HEIGHT = 200;
@@ -47,7 +48,9 @@ function TruncateText({ content, expanded, title, }) {
47
48
  }
48
49
  function DataTable(props) {
49
50
  var _a, _b;
50
- const { rowKey, columns, actions, actionColumnTitle = '操作', actionColumnWidth = 188, dataSource, loading = false, pagination: controlledPagination, onChange, rowSelection, defaultPageSize = 10, showSizeChanger = false, showQuickJumper = true, className, minWidth = DEFAULT_MIN_WIDTH, rowTextExpand, } = props;
51
+ const { rowKey, columns, actions, actionColumnTitle, actionColumnWidth = 188, dataSource, loading = false, pagination: controlledPagination, onChange, rowSelection, defaultPageSize = 10, showSizeChanger = false, showQuickJumper = true, className, minWidth = DEFAULT_MIN_WIDTH, rowTextExpand, } = props;
52
+ const { locale } = useLocale();
53
+ const resolvedActionColumnTitle = actionColumnTitle !== null && actionColumnTitle !== void 0 ? actionColumnTitle : locale.DataTable.action;
51
54
  const expandEnabled = Boolean(rowTextExpand);
52
55
  const expandMultiple = typeof rowTextExpand === 'object' ? ((_a = rowTextExpand.multiple) !== null && _a !== void 0 ? _a : true) : true;
53
56
  const expandMaxHeight = typeof rowTextExpand === 'object'
@@ -106,12 +109,20 @@ function DataTable(props) {
106
109
  ...enhancedColumns,
107
110
  {
108
111
  key: '__actions__',
109
- title: actionColumnTitle,
112
+ title: resolvedActionColumnTitle,
110
113
  width: actionColumnWidth,
111
114
  render: (_, record) => jsx(ActionCell, { record: record, actions: actions }),
112
115
  },
113
116
  ];
114
- }, [actions, actionColumnTitle, actionColumnWidth, columns, expandEnabled, expandedRowKeys, rowKey]);
117
+ }, [
118
+ actions,
119
+ resolvedActionColumnTitle,
120
+ actionColumnWidth,
121
+ columns,
122
+ expandEnabled,
123
+ expandedRowKeys,
124
+ rowKey,
125
+ ]);
115
126
  const resolvedRowSelection = React.useMemo(() => {
116
127
  var _a;
117
128
  if (!rowSelection) {
@@ -159,7 +170,7 @@ function DataTable(props) {
159
170
  },
160
171
  })
161
172
  : undefined, locale: {
162
- emptyText: jsx(Empty, { image: Empty.PRESENTED_IMAGE_SIMPLE, description: "\u6682\u65E0\u6570\u636E" }),
173
+ emptyText: jsx(Empty, { image: Empty.PRESENTED_IMAGE_SIMPLE, description: locale.DataTable.empty }),
163
174
  } }));
164
175
  }
165
176
 
@@ -2,6 +2,7 @@ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
2
  import React from 'react';
3
3
  import { Upload, Input, Modal, Tabs, message, Alert, Button } from 'antd';
4
4
  import { datasetBatchAction, description, manualLabel, uploadContainer, uploadIconWrapper, uploadIcon, uploadText, alertMessage, fieldSelection, fieldHeader, fieldTitleWrapper, fieldTitleIndicator, fieldTitle, fieldActions, selectAllBtn, clearAllBtn, fieldGrid, fieldItem, selected, unselected, fieldItemContent, fieldLabel, fieldCheckbox, checked, unchecked, checkIcon, fieldMeta, listTip, tipContent, tipIcon, tipText } from './index.module.scss.js';
5
+ import { useLocale } from '../../locale/index.js';
5
6
 
6
7
  const { Dragger } = Upload;
7
8
  const { TextArea } = Input;
@@ -12,39 +13,61 @@ var EDatasetBatchType;
12
13
  EDatasetBatchType["tag"] = "tag";
13
14
  EDatasetBatchType["zone"] = "area";
14
15
  })(EDatasetBatchType || (EDatasetBatchType = {}));
15
- const DATASET_FIELDS = [
16
- { id: 'id', label: '数据集ID' },
17
- { id: 'name', label: '数据集名称' },
18
- { id: 'provider', label: '提供方' },
19
- { id: 'creator', label: '发布者' },
20
- { id: 'fileSize', label: '数据量' },
21
- { id: 'authorizationType', label: '开放方式' },
22
- { id: 'subjects', label: '科学领域' },
23
- { id: 'source', label: '来源名称' },
24
- { id: 'keywords', label: '关键词' },
25
- { id: 'label', label: '相关标签' },
26
- { id: 'license', label: '使用许可' },
27
- { id: 'dataSourceUrl', label: '来源链接' },
28
- { id: 'publishTime', label: '发布时间' },
29
- { id: 'storageFilePath', label: '存储路径' },
30
- { id: 'domain', label: '域名标识' },
16
+ const DATASET_FIELD_IDS = [
17
+ 'id',
18
+ 'name',
19
+ 'provider',
20
+ 'creator',
21
+ 'fileSize',
22
+ 'authorizationType',
23
+ 'subjects',
24
+ 'source',
25
+ 'keywords',
26
+ 'label',
27
+ 'license',
28
+ 'dataSourceUrl',
29
+ 'publishTime',
30
+ 'storageFilePath',
31
+ 'domain',
31
32
  ];
33
+ function getDatasetFields(texts) {
34
+ const labels = {
35
+ id: texts.fieldId,
36
+ name: texts.fieldName,
37
+ provider: texts.fieldProvider,
38
+ creator: texts.fieldCreator,
39
+ fileSize: texts.fieldFileSize,
40
+ authorizationType: texts.fieldAuthorizationType,
41
+ subjects: texts.fieldSubjects,
42
+ source: texts.fieldSource,
43
+ keywords: texts.fieldKeywords,
44
+ label: texts.fieldLabel,
45
+ license: texts.fieldLicense,
46
+ dataSourceUrl: texts.fieldDataSourceUrl,
47
+ publishTime: texts.fieldPublishTime,
48
+ storageFilePath: texts.fieldStorageFilePath,
49
+ domain: texts.fieldDomain,
50
+ };
51
+ return DATASET_FIELD_IDS.map((id) => ({ id, label: labels[id] }));
52
+ }
32
53
  function DatasetBatchAction(p) {
33
54
  var _a, _b;
55
+ const { locale } = useLocale();
56
+ const texts = locale.DatasetBatchAction;
34
57
  const [fileList, setFileList] = React.useState([]);
35
58
  const [manualInputValue, setManualInputValue] = React.useState('');
36
59
  const [activeTab, setActiveTab] = React.useState(p.hasZoneManualInput ? 'manual' : 'upload');
37
- const exportFields = (_a = p.fieldOptions) !== null && _a !== void 0 ? _a : (p.type === EDatasetBatchType.list || p.type === EDatasetBatchType.export ? DATASET_FIELDS : []);
60
+ const exportFields = (_a = p.fieldOptions) !== null && _a !== void 0 ? _a : (p.type === EDatasetBatchType.list || p.type === EDatasetBatchType.export ? getDatasetFields(texts) : []);
38
61
  const [selectedFields, setSelectedFields] = React.useState(new Set((exportFields === null || exportFields === void 0 ? void 0 : exportFields.map((f) => f.id)) || []));
39
62
  const hasUpload = (_b = p.hasUpload) !== null && _b !== void 0 ? _b : true;
40
63
  const handleConfirmExport = () => {
41
64
  if (p.type === EDatasetBatchType.zone) {
42
65
  if (activeTab === 'manual' && !manualInputValue.trim()) {
43
- message.warning('请输入数据集ID');
66
+ message.warning(texts.enterDatasetId);
44
67
  return;
45
68
  }
46
69
  if (activeTab === 'upload' && !fileList.length) {
47
- message.warning('请上传CSV文件');
70
+ message.warning(texts.uploadCsv);
48
71
  return;
49
72
  }
50
73
  const inputIds = activeTab === 'manual'
@@ -61,7 +84,7 @@ function DatasetBatchAction(p) {
61
84
  });
62
85
  }
63
86
  else if (p.type !== EDatasetBatchType.list && !fileList.length) {
64
- message.warning('请上传csv或excel文件');
87
+ message.warning(texts.uploadCsvOrExcel);
65
88
  return;
66
89
  }
67
90
  else {
@@ -76,14 +99,14 @@ function DatasetBatchAction(p) {
76
99
  next.add(fieldId);
77
100
  setSelectedFields(next);
78
101
  };
79
- return (jsxs(Modal, { title: p.title, open: true, onOk: handleConfirmExport, onCancel: p.onCancel, className: datasetBatchAction, okText: "\u786E\u5B9A", cancelText: "\u53D6\u6D88", children: [jsx("p", { className: description, children: p.description }), p.type === EDatasetBatchType.zone && p.hasZoneManualInput && (jsxs(Fragment, { children: [hasUpload && (jsx(Tabs, { activeKey: activeTab, onChange: setActiveTab, items: [
102
+ return (jsxs(Modal, { title: p.title, open: true, onOk: handleConfirmExport, onCancel: p.onCancel, className: datasetBatchAction, okText: texts.ok, cancelText: texts.cancel, children: [jsx("p", { className: description, children: p.description }), p.type === EDatasetBatchType.zone && p.hasZoneManualInput && (jsxs(Fragment, { children: [hasUpload && (jsx(Tabs, { activeKey: activeTab, onChange: setActiveTab, items: [
80
103
  {
81
104
  key: 'manual',
82
- label: '手动输入ID',
105
+ label: texts.manualTab,
83
106
  },
84
107
  {
85
108
  key: 'upload',
86
- label: '批量任务文件上传',
109
+ label: texts.uploadTab,
87
110
  },
88
111
  ] })), activeTab === 'manual' && (jsxs("div", { children: [jsx("p", { className: manualLabel, children: p.manualInputTitle }), jsx(TextArea, { value: manualInputValue, onChange: (e) => setManualInputValue(e.target.value), placeholder: p.manualInputPlaceholder, rows: 6 })] }))] })), hasUpload &&
89
112
  (p.type === EDatasetBatchType.export ||
@@ -95,10 +118,10 @@ function DatasetBatchAction(p) {
95
118
  }, className: uploadContainer, multiple: false, accept: ".csv,.xlsx,.xls", fileList: fileList, onChange: (info) => {
96
119
  const newFileList = [...info.fileList];
97
120
  if (newFileList.length > 1) {
98
- message.warning('单次任务只能上传1个文件,不支持第二个文件的上传');
121
+ message.warning(texts.onlyOneFile);
99
122
  }
100
123
  setFileList(newFileList.slice(0, 1));
101
- }, onRemove: () => setFileList([]), children: [jsx("div", { className: uploadIconWrapper, children: jsx("svg", { className: uploadIcon, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2.5, d: "M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" }) }) }), jsx("div", { className: uploadText, children: "\u70B9\u51FB\u6D4F\u89C8\u6587\u4EF6\u6216\u5C06\u6587\u4EF6\u62D6\u62FD\u81F3\u6B64\uFF08\u652F\u6301csv\u6216excel\u6587\u4EF6\uFF09" })] })), p.type === EDatasetBatchType.tag && (jsx(Alert, { message: "\u63D0\u793A\uFF1A\u6587\u4EF6\u7B2C\u4E00\u5217\u5E94\u4E3A dataset_id\uFF0C\u7B2C\u4E8C\u5217\u4E3A tag_ids\uFF08\u591A\u4E2A\u6807\u7B7E ID \u8BF7\u7528\u5206\u53F7\u5206\u9694\uFF09\u3002", type: "info", showIcon: true, className: alertMessage })), p.type === EDatasetBatchType.zone && activeTab === 'upload' && p.hasZoneManualInput && (jsx(Alert, { message: '\u63D0\u793A\uFF1A\u8BF7\u4E0A\u4F20csv\u6216excel\u6587\u4EF6\uFF0C\u63D0\u4F9B\u6570\u636E\u96C6id\uFF0C\u5355\u6B21\u4EFB\u52A1\u53EA\u80FD\u4E0A\u4F201\u4E2A\u6587\u4EF6\u3002\u6587\u4EF6\u91C7\u7528\u5355\u5217\u5E03\u5C40\uFF0C\u9996\u884C\u4E3A"dataset_id"\uFF0C\u4ECE\u7B2C\u4E8C\u884C\u5F00\u59CB\u6BCF\u884C\u4E3A\u4E00\u4E2A\u5177\u4F53id\u3002', type: "info", showIcon: true, className: alertMessage })), exportFields && exportFields.length > 0 && (jsxs("div", { className: fieldSelection, children: [jsxs("div", { className: fieldHeader, children: [jsxs("div", { className: fieldTitleWrapper, children: [jsx("div", { className: fieldTitleIndicator }), jsx("h4", { className: fieldTitle, children: p.fieldTitle })] }), jsxs("div", { className: fieldActions, children: [jsx("span", { onClick: () => setSelectedFields(new Set((exportFields === null || exportFields === void 0 ? void 0 : exportFields.map((f) => f.id)) || [])), className: selectAllBtn, children: "\u5168\u9009" }), jsx("span", { onClick: () => setSelectedFields(new Set()), className: clearAllBtn, children: "\u6E05\u7A7A" })] })] }), jsx("div", { className: fieldGrid, children: exportFields.map((field) => {
124
+ }, onRemove: () => setFileList([]), children: [jsx("div", { className: uploadIconWrapper, children: jsx("svg", { className: uploadIcon, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2.5, d: "M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" }) }) }), jsx("div", { className: uploadText, children: texts.dragUpload })] })), p.type === EDatasetBatchType.tag && (jsx(Alert, { message: texts.tagAlert, type: "info", showIcon: true, className: alertMessage })), p.type === EDatasetBatchType.zone && activeTab === 'upload' && p.hasZoneManualInput && (jsx(Alert, { message: texts.zoneAlert, type: "info", showIcon: true, className: alertMessage })), exportFields && exportFields.length > 0 && (jsxs("div", { className: fieldSelection, children: [jsxs("div", { className: fieldHeader, children: [jsxs("div", { className: fieldTitleWrapper, children: [jsx("div", { className: fieldTitleIndicator }), jsx("h4", { className: fieldTitle, children: p.fieldTitle })] }), jsxs("div", { className: fieldActions, children: [jsx("span", { onClick: () => setSelectedFields(new Set((exportFields === null || exportFields === void 0 ? void 0 : exportFields.map((f) => f.id)) || [])), className: selectAllBtn, children: "\u5168\u9009" }), jsx("span", { onClick: () => setSelectedFields(new Set()), className: clearAllBtn, children: "\u6E05\u7A7A" })] })] }), jsx("div", { className: fieldGrid, children: exportFields.map((field) => {
102
125
  const isSelected = selectedFields.has(field.id);
103
126
  return (jsxs(Button, { onClick: () => toggleExportField(field.id), className: `${fieldItem} ${isSelected ? selected : unselected}`, style: { height: p.type === EDatasetBatchType.zone ? '60px' : '32px' }, children: [jsxs("div", { className: fieldItemContent, children: [jsx("span", { className: fieldLabel, title: field.label, children: field.label }), jsx("div", { className: `${fieldCheckbox} ${isSelected ? checked : unchecked}`, children: isSelected && (jsx("svg", { className: checkIcon, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 4, children: jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 13l4 4L19 7" }) })) })] }), p.type === EDatasetBatchType.zone && (jsxs("div", { className: fieldMeta, children: [jsxs("span", { children: ["ID\uFF1A", field.id] }), jsxs("span", { children: [field.datasetCnt, " \u8D44\u4EA7"] })] }))] }, field.id));
104
127
  }) })] })), p.type === EDatasetBatchType.list && (jsx("div", { className: listTip, children: jsxs("div", { className: tipContent, children: [jsx("svg", { className: tipIcon, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2.5, d: "M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }), jsx("p", { className: tipText, children: "\u8BF7\u524D\u5F80\"\u6279\u91CF\u4EFB\u52A1\"\u4E2D\u67E5\u770B\u5BFC\u51FA\u6587\u4EF6" })] }) }))] }));