diff --git a/packages/core/client/package.json b/packages/core/client/package.json
index fb7a6ee25..c35d91df9 100644
--- a/packages/core/client/package.json
+++ b/packages/core/client/package.json
@@ -34,6 +34,7 @@
"mathjs": "^10.6.0",
"react-beautiful-dnd": "^13.1.0",
"react-big-calendar": "^0.38.7",
+ "react-iframe": "~1.8.5",
"react-contenteditable": "^3.3.6",
"react-drag-listview": "^0.1.9",
"react-helmet": "^6.1.0",
diff --git a/packages/core/client/src/locale/en_US.ts b/packages/core/client/src/locale/en_US.ts
index 7c3454bd8..528c6bcd9 100644
--- a/packages/core/client/src/locale/en_US.ts
+++ b/packages/core/client/src/locale/en_US.ts
@@ -510,4 +510,5 @@ export default {
"Selector": "Selector",
"Inner": "Inner",
"Search and select collection": "Search and select collection",
+ 'Please fill in the iframe URL': 'Please fill in the iframe URL',
}
diff --git a/packages/core/client/src/locale/zh_CN.ts b/packages/core/client/src/locale/zh_CN.ts
index d42d84565..7a5169cad 100644
--- a/packages/core/client/src/locale/zh_CN.ts
+++ b/packages/core/client/src/locale/zh_CN.ts
@@ -626,4 +626,5 @@ export default {
"Selector": "选择器",
"Inner": "里面",
"Search and select collection": "搜索并选择数据表",
+ 'Please fill in the iframe URL': '请填写嵌入的地址',
}
diff --git a/packages/core/client/src/schema-component/common/iframe/Iframe.Designer.tsx b/packages/core/client/src/schema-component/common/iframe/Iframe.Designer.tsx
new file mode 100644
index 000000000..0b4505cea
--- /dev/null
+++ b/packages/core/client/src/schema-component/common/iframe/Iframe.Designer.tsx
@@ -0,0 +1,66 @@
+import { ISchema, useField, useFieldSchema } from '@formily/react';
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import { GeneralSchemaDesigner, SchemaSettings } from '../../../schema-settings';
+import { useDesignable } from '../../hooks';
+
+export const IframeDesigner = () => {
+ const field = useField();
+ const fieldSchema = useFieldSchema();
+ const { t } = useTranslation();
+ const { dn } = useDesignable();
+
+ return (
+
+ {
+ field.componentProps.url = url;
+ field.componentProps.height = height;
+ const componentProps = fieldSchema['x-component-props'] || {};
+ componentProps['url'] = url;
+ componentProps['height'] = height;
+ fieldSchema['x-component-props'] = componentProps;
+ dn.emit('patch', {
+ schema: {
+ 'x-uid': fieldSchema['x-uid'],
+ 'x-component-props': componentProps,
+ },
+ });
+ }}
+ />
+
+
+
+ );
+};
diff --git a/packages/core/client/src/schema-component/common/iframe/index.tsx b/packages/core/client/src/schema-component/common/iframe/index.tsx
new file mode 100644
index 000000000..b434d123f
--- /dev/null
+++ b/packages/core/client/src/schema-component/common/iframe/index.tsx
@@ -0,0 +1,39 @@
+import { observer } from '@formily/react';
+import { Card } from 'antd';
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import RIframe from 'react-iframe';
+import type { IIframe } from 'react-iframe/types';
+import { IframeDesigner } from './Iframe.Designer';
+
+function isNumeric(str: string) {
+ if (typeof str !== 'string') return false; // we only process strings!
+ return (
+ !isNaN(str as any) && // use type coercion to parse the _entirety_ of the string (`parseFloat` alone does not do this)...
+ !isNaN(parseFloat(str))
+ ); // ...and ensure strings of whitespace fail
+}
+
+export const Iframe: any = observer((props: IIframe) => {
+ const { url, height, ...others } = props;
+ const { t } = useTranslation();
+ if (!url) {
+ return {t('Please fill in the iframe URL')};
+ }
+ return (
+
+ );
+});
+
+Iframe.Designer = IframeDesigner;
diff --git a/packages/core/client/src/schema-component/common/index.ts b/packages/core/client/src/schema-component/common/index.ts
index e1b472059..ba61b9f1c 100644
--- a/packages/core/client/src/schema-component/common/index.ts
+++ b/packages/core/client/src/schema-component/common/index.ts
@@ -1,3 +1,4 @@
export * from './dnd-context';
+export * from './iframe';
export * from './sortable-item';
diff --git a/packages/core/client/src/schema-initializer/buttons/BlockInitializers.tsx b/packages/core/client/src/schema-initializer/buttons/BlockInitializers.tsx
index c7f3b0b46..d00f42fea 100644
--- a/packages/core/client/src/schema-initializer/buttons/BlockInitializers.tsx
+++ b/packages/core/client/src/schema-initializer/buttons/BlockInitializers.tsx
@@ -164,6 +164,12 @@ export const BlockInitializers = {
title: '{{t("Markdown")}}',
component: 'MarkdownBlockInitializer',
},
+ {
+ key: 'iframe',
+ type: 'item',
+ title: '{{t("Iframe")}}',
+ component: 'IframeBlockInitializer',
+ },
{
key: 'auditLogs',
type: 'item',
diff --git a/packages/core/client/src/schema-initializer/items/IframeBlockInitializer.tsx b/packages/core/client/src/schema-initializer/items/IframeBlockInitializer.tsx
new file mode 100644
index 000000000..7994a3c9f
--- /dev/null
+++ b/packages/core/client/src/schema-initializer/items/IframeBlockInitializer.tsx
@@ -0,0 +1,25 @@
+import { FormOutlined } from '@ant-design/icons';
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+
+import { SchemaInitializer } from '../SchemaInitializer';
+
+export const IframeBlockInitializer = (props) => {
+ const { insert } = props;
+ const { t } = useTranslation();
+ return (
+ }
+ onClick={() => {
+ insert({
+ type: 'void',
+ 'x-designer': 'Iframe.Designer',
+ 'x-decorator': 'BlockItem',
+ 'x-component': 'Iframe',
+ 'x-component-props': {},
+ });
+ }}
+ />
+ );
+};
diff --git a/packages/core/client/src/schema-initializer/items/index.tsx b/packages/core/client/src/schema-initializer/items/index.tsx
index 64d99cef7..ecef69bc1 100644
--- a/packages/core/client/src/schema-initializer/items/index.tsx
+++ b/packages/core/client/src/schema-initializer/items/index.tsx
@@ -11,12 +11,13 @@ export * from './CreateSubmitActionInitializer';
export * from './CustomizeActionInitializer';
export * from './CustomizeBulkEditActionInitializer';
export * from './DataBlockInitializer';
-export * from './DestroyActionInitializer';
export * from './DeleteEventActionInitializer';
+export * from './DestroyActionInitializer';
export * from './DetailsBlockInitializer';
export * from './FilterActionInitializer';
export * from './FormBlockInitializer';
export * from './G2PlotInitializer';
+export * from './IframeBlockInitializer';
export * from './InitializerWithSwitch';
export * from './KanbanBlockInitializer';
export * from './MarkdownBlockInitializer';
@@ -37,3 +38,4 @@ export * from './TableSelectorInitializer';
export * from './UpdateActionInitializer';
export * from './UpdateSubmitActionInitializer';
export * from './ViewActionInitializer';
+