@wzyjs/uis 0.3.8

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 (55) hide show
  1. package/package.json +49 -0
  2. package/src/antd/form/CheckboxButton/index.module.scss +24 -0
  3. package/src/antd/form/CheckboxButton/index.tsx +31 -0
  4. package/src/antd/form/RadioButton/index.tsx +30 -0
  5. package/src/antd/form/Upload/index.tsx +65 -0
  6. package/src/antd/form/UploadImage/index.tsx +338 -0
  7. package/src/antd/form/index.ts +5 -0
  8. package/src/antd/index.ts +43 -0
  9. package/src/antd/pro/Alert/index.tsx +24 -0
  10. package/src/antd/pro/Button/components/Confirm.tsx +24 -0
  11. package/src/antd/pro/Button/components/Copy.tsx +46 -0
  12. package/src/antd/pro/Button/components/Drawer.tsx +37 -0
  13. package/src/antd/pro/Button/components/Group.tsx +26 -0
  14. package/src/antd/pro/Button/index.tsx +11 -0
  15. package/src/antd/pro/Card/index.tsx +92 -0
  16. package/src/antd/pro/Collapse/components/Item.tsx +30 -0
  17. package/src/antd/pro/Collapse/index.tsx +27 -0
  18. package/src/antd/pro/Image/index.tsx +17 -0
  19. package/src/antd/pro/Input/components/Range.tsx +46 -0
  20. package/src/antd/pro/Input/index.tsx +61 -0
  21. package/src/antd/pro/Popconfirm/index.tsx +16 -0
  22. package/src/antd/pro/Radio/components/Cancel.tsx +30 -0
  23. package/src/antd/pro/Radio/index.tsx +7 -0
  24. package/src/antd/pro/Space/index.tsx +15 -0
  25. package/src/antd/pro/Typography/components/String.tsx +72 -0
  26. package/src/antd/pro/Typography/index.tsx +9 -0
  27. package/src/antd/pro/index.ts +10 -0
  28. package/src/components/BottomBar/index.tsx +28 -0
  29. package/src/components/CodeView/index.tsx +85 -0
  30. package/src/components/Collapse/index.tsx +26 -0
  31. package/src/components/Com2Canvas/index.tsx +60 -0
  32. package/src/components/CompileHtml/index.tsx +26 -0
  33. package/src/components/DateSwitcher/index.module.scss +10 -0
  34. package/src/components/DateSwitcher/index.tsx +75 -0
  35. package/src/components/DownloadLink/index.tsx +36 -0
  36. package/src/components/DragSort/index.tsx +77 -0
  37. package/src/components/DynamicSelect/index.tsx +77 -0
  38. package/src/components/DynamicSelect/utils.ts +47 -0
  39. package/src/components/EnumTag/index.tsx +24 -0
  40. package/src/components/FetchSelect/index.tsx +57 -0
  41. package/src/components/Fold/index.tsx +52 -0
  42. package/src/components/FormPro/index.tsx +28 -0
  43. package/src/components/GroupLayout/index.tsx +45 -0
  44. package/src/components/HtmlPro/index.tsx +18 -0
  45. package/src/components/IframePro/index.tsx +52 -0
  46. package/src/components/JsonRenderer/index.tsx +115 -0
  47. package/src/components/JsonView/index.tsx +21 -0
  48. package/src/components/Markdown/index.tsx +152 -0
  49. package/src/components/Markdown/style.ts +106 -0
  50. package/src/components/MultiImageDisplay/index.tsx +63 -0
  51. package/src/components/SectorButton/index.tsx +247 -0
  52. package/src/components/TextInput/index.tsx +61 -0
  53. package/src/components/Video/index.tsx +37 -0
  54. package/src/components/index.ts +22 -0
  55. package/src/web.ts +2 -0
@@ -0,0 +1,60 @@
1
+ 'use client'
2
+
3
+ import React, { useEffect, useRef, ReactNode } from 'react'
4
+
5
+ import html2canvas from 'html2canvas'
6
+
7
+ import { useDebounceFn } from '@wzyjs/hooks/web'
8
+ import { getRandomColor } from '@wzyjs/utils/web'
9
+
10
+ interface Com2CanvasProps {
11
+ children: ReactNode;
12
+ downloadName?: string;
13
+ onChange?: (url: string) => void;
14
+ }
15
+
16
+ export const Com2Canvas = (props: Com2CanvasProps) => {
17
+ const { children, downloadName, onChange } = props
18
+
19
+ const random = useRef(getRandomColor())
20
+ const htmlId = `h2c_html_${random.current}`
21
+ const canvasId = `htc_canvas_${random.current}`
22
+
23
+ const { run } = useDebounceFn(() => {
24
+ const el = document.querySelector(`#${canvasId}`) as HTMLElement
25
+ if (!el) {
26
+ return
27
+ }
28
+
29
+ html2canvas(el, {
30
+ allowTaint: true, // 允许污染
31
+ useCORS: true, // 使用跨域(当allowTaint为true时这段代码没什么用)
32
+ scale: 2,
33
+ }).then((canvas: any) => {
34
+ el.innerHTML = ''
35
+ el.appendChild(canvas)
36
+
37
+ onChange?.(canvas.toDataURL('image/png'))
38
+
39
+ if (downloadName) {
40
+ el.onclick = () => {
41
+ const a = document.createElement('a')
42
+ a.download = downloadName
43
+ a.href = canvas.toDataURL('image/png')
44
+ document.body.appendChild(a)
45
+ a.click()
46
+ a.remove()
47
+ }
48
+ }
49
+ })
50
+ }, { wait: 500 })
51
+
52
+ useEffect(run, [children])
53
+
54
+ return (
55
+ <span style={{ position: 'relative' }}>
56
+ <span id={htmlId}>{children}</span>
57
+ <span id={canvasId} style={{ position: 'absolute', top: 0 }} />
58
+ </span>
59
+ )
60
+ }
@@ -0,0 +1,26 @@
1
+ 'use client'
2
+
3
+ import React, { useMemo } from 'react'
4
+ import Handlebars from 'handlebars'
5
+
6
+ interface Props {
7
+ template?: string
8
+ data: any
9
+ }
10
+
11
+ export default (props: Props) => {
12
+ const { template, data } = props
13
+
14
+ const html = useMemo(() => {
15
+ const html = Handlebars.compile(template || '')(data)
16
+ return html.replaceAll('\n', '').replaceAll('\t', '')
17
+ }, [template, data])
18
+
19
+ if (!html) {
20
+ return null
21
+ }
22
+
23
+ return (
24
+ <div dangerouslySetInnerHTML={{ __html: html }} />
25
+ )
26
+ }
@@ -0,0 +1,10 @@
1
+ .picker {
2
+ display: flex;
3
+ align-items: center;
4
+ gap: 0.5rem;
5
+
6
+ :global(.ant-picker-input input) {
7
+ text-align: center !important;
8
+ cursor: pointer;
9
+ }
10
+ }
@@ -0,0 +1,75 @@
1
+ 'use client'
2
+
3
+ import React, { useState } from 'react'
4
+
5
+ import { DatePicker, Button } from 'antd'
6
+ import { LeftOutlined, RightOutlined } from '@ant-design/icons'
7
+
8
+ import { dayjs, type Dayjs } from '@wzyjs/utils/web'
9
+
10
+ import styles from './index.module.scss'
11
+
12
+ interface DateSwitcherProps {
13
+ value?: Dayjs
14
+ onChange?: (date: Dayjs) => void
15
+ }
16
+
17
+ export const DateSwitcher = (props: DateSwitcherProps) => {
18
+ const { value = dayjs(), onChange } = props
19
+
20
+ const [selectedDate, setSelectedDate] = useState(value)
21
+
22
+ const handleDateChange = (date: Dayjs | null) => {
23
+ if (date) {
24
+ setSelectedDate(date)
25
+ onChange?.(date)
26
+ }
27
+ }
28
+
29
+ const handlePrevDay = () => {
30
+ const newDate = selectedDate.subtract(1, 'day')
31
+ handleDateChange(newDate)
32
+ }
33
+
34
+ const handleNextDay = () => {
35
+ const newDate = selectedDate.add(1, 'day')
36
+ handleDateChange(newDate)
37
+ }
38
+
39
+ const isToday = selectedDate.isSame(dayjs(), 'day')
40
+
41
+ return (
42
+ <div className={styles.picker}>
43
+ <Button
44
+ type='text'
45
+ icon={<LeftOutlined />}
46
+ onClick={handlePrevDay}
47
+ className='flex items-center justify-center'
48
+ />
49
+ <DatePicker
50
+ value={selectedDate}
51
+ onChange={handleDateChange}
52
+ allowClear={false}
53
+ suffixIcon={null}
54
+ className='w-40 text-center cursor-pointer'
55
+ style={{ border: 'none' }}
56
+ components={{
57
+ input: props => (
58
+ <div {...props} className={isToday ? 'text-green-600' : ''}>
59
+ <span>{selectedDate.format('YYYY-MM-DD')}</span>
60
+ <span style={{ marginLeft: 5 }}>
61
+ (周{['日', '一', '二', '三', '四', '五', '六'][dayjs(selectedDate).day()]})
62
+ </span>
63
+ </div>
64
+ ),
65
+ }}
66
+ />
67
+ <Button
68
+ type='text'
69
+ icon={<RightOutlined />}
70
+ onClick={handleNextDay}
71
+ className='flex items-center justify-center'
72
+ />
73
+ </div>
74
+ )
75
+ }
@@ -0,0 +1,36 @@
1
+ 'use client'
2
+
3
+ import React from 'react'
4
+
5
+ interface DownloadLinkProps {
6
+ url: string
7
+ filename?: string
8
+ }
9
+
10
+ export const DownloadLink = ({ url, filename }: DownloadLinkProps) => {
11
+ const handleDownload = (e: any) => {
12
+ e.preventDefault()
13
+ fetch(url, { method: 'GET' })
14
+ .then(response => response.blob())
15
+ .then(blob => {
16
+ const downloadUrl = window.URL.createObjectURL(blob)
17
+ const a = document.createElement('a')
18
+ a.href = downloadUrl
19
+ a.download = filename || '下载文件'
20
+ document.body.appendChild(a)
21
+ a.click()
22
+ a.remove()
23
+ window.URL.revokeObjectURL(downloadUrl)
24
+ })
25
+ .catch((err) => {
26
+ console.log(666, err)
27
+ alert('下载失败')
28
+ })
29
+ }
30
+
31
+ return (
32
+ <a href={url} onClick={handleDownload}>
33
+ 下载
34
+ </a>
35
+ )
36
+ }
@@ -0,0 +1,77 @@
1
+ 'use client'
2
+
3
+ import React from 'react'
4
+
5
+ import { Space } from 'antd'
6
+ import {
7
+ DragDropContext,
8
+ Draggable,
9
+ Droppable,
10
+ type OnDragEndResponder,
11
+ type DraggableProvided,
12
+ } from 'react-beautiful-dnd'
13
+
14
+ interface DragSortProps<T> {
15
+ direction?: 'vertical' | 'horizontal'
16
+ droppableId?: string
17
+ list?: T[]
18
+ children: (item: T, provided: DraggableProvided) => React.ReactNode
19
+ lastChildren?: React.ReactNode
20
+ onDragEnd?: OnDragEndResponder
21
+ hasContext?: boolean
22
+ dropType?: string
23
+ }
24
+
25
+ export { type DropResult, type DraggableProvided } from 'react-beautiful-dnd'
26
+
27
+ export const DragSort = <T extends { id: string }>(props: DragSortProps<T>) => {
28
+ const {
29
+ dropType,
30
+ direction = 'vertical',
31
+ droppableId = 'list',
32
+ list,
33
+ children,
34
+ hasContext = true,
35
+ lastChildren,
36
+ onDragEnd = () => undefined,
37
+ } = props
38
+
39
+ const content = (
40
+ <Droppable
41
+ type={dropType}
42
+ droppableId={droppableId}
43
+ direction={direction}
44
+ isDropDisabled={false}
45
+ isCombineEnabled={false}
46
+ ignoreContainerClipping
47
+ >
48
+ {provided => (
49
+ <div ref={provided.innerRef} {...provided.droppableProps}>
50
+ <Space orientation={direction} wrap style={{ width: '100%' }}>
51
+ {list?.map((item, index) => (
52
+ <Draggable key={item.id} disableInteractiveElementBlocking draggableId={item.id.toString()} index={index}>
53
+ {provided => (
54
+ <div ref={provided.innerRef} {...provided.draggableProps} >
55
+ {children(item, provided)}
56
+ </div>
57
+ )}
58
+ </Draggable>
59
+ ))}
60
+ {provided.placeholder}
61
+ {lastChildren}
62
+ </Space>
63
+ </div>
64
+ )}
65
+ </Droppable>
66
+ )
67
+
68
+ if (!hasContext) {
69
+ return content
70
+ }
71
+
72
+ return (
73
+ <DragDropContext onDragEnd={onDragEnd}>
74
+ {content}
75
+ </DragDropContext>
76
+ )
77
+ }
@@ -0,0 +1,77 @@
1
+ import React from 'react'
2
+ import { AutoComplete, Button, Space } from 'antd'
3
+ import { type Option } from '@wzyjs/types'
4
+
5
+ export * from './utils'
6
+
7
+ interface DynamicSelectProps {
8
+ value?: string[]
9
+ onChange?: (value: string[]) => void
10
+ options?: Option[]
11
+ }
12
+
13
+ export const DynamicSelect = (props: DynamicSelectProps) => {
14
+ const { value = [''], onChange, options = [] } = props
15
+
16
+ const removeOption = (index: number) => {
17
+ const newOptions = [...value]
18
+ newOptions.splice(index, 1)
19
+ onChange?.(newOptions)
20
+ }
21
+
22
+ const handleChange = (index: number, val: string) => {
23
+ const newValue = [...[...value].slice(0, index), val]
24
+ onChange?.(newValue)
25
+
26
+ if (newValue.every(item => item)) {
27
+ onChange?.([...newValue, ''])
28
+ }
29
+ }
30
+
31
+ const getOptions = (options: Option[], index: number): Option[] => {
32
+ if (index === 0) {
33
+ return options
34
+ }
35
+
36
+ const currentValue = value[value.length - 1 - index]
37
+ if (!currentValue) return []
38
+
39
+ return getOptions(
40
+ options.find(item => item.value === currentValue)?.children || [],
41
+ index - 1,
42
+ )
43
+ }
44
+
45
+ return (
46
+ <Space size={8} align='center'>
47
+ {value.map((val, index) => (
48
+ <Space key={index} size={4} align='center'>
49
+ <AutoComplete
50
+ style={{
51
+ minWidth: '120px',
52
+ maxWidth: '300px',
53
+ width: 'auto',
54
+ }}
55
+ value={val}
56
+ onChange={val => handleChange(index, val)}
57
+ options={getOptions(options, index)}
58
+ placeholder={`请选择第 ${index + 1} 级`}
59
+ />
60
+ {index !== 0 && (
61
+ <Button
62
+ type='text'
63
+ danger
64
+ size='small'
65
+ onClick={() => removeOption(index)}
66
+ >
67
+ 删除
68
+ </Button>
69
+ )}
70
+ {index < value.length - 1 && (
71
+ <span style={{ color: '#999' }}>/</span>
72
+ )}
73
+ </Space>
74
+ ))}
75
+ </Space>
76
+ )
77
+ }
@@ -0,0 +1,47 @@
1
+ import type { Option } from '@wzyjs/types'
2
+
3
+ export const transformOptions = (data: string[][]): Option[] => {
4
+ const result: Option[] = []
5
+
6
+ data.forEach((item = []) => {
7
+ let currentNode: Option | undefined
8
+ let parentNode: Option | undefined
9
+
10
+ for (let i = 0; i < item.length; i++) {
11
+ const currentValue = item[i]
12
+ if (!currentValue) continue
13
+
14
+ if (i === 0) {
15
+ currentNode = result.find(r => r.value === currentValue)
16
+
17
+ if (!currentNode) {
18
+ currentNode = {
19
+ label: currentValue,
20
+ value: currentValue,
21
+ }
22
+ result.push(currentNode)
23
+ }
24
+
25
+ parentNode = currentNode
26
+ } else {
27
+ currentNode = parentNode?.children?.find(c => c.value === currentValue)
28
+
29
+ if (!currentNode) {
30
+ currentNode = {
31
+ label: currentValue,
32
+ value: currentValue,
33
+ }
34
+ if (!parentNode) {
35
+ return
36
+ }
37
+ parentNode.children = parentNode.children || []
38
+ parentNode.children.push(currentNode)
39
+ }
40
+
41
+ parentNode = currentNode
42
+ }
43
+ }
44
+ })
45
+
46
+ return result
47
+ }
@@ -0,0 +1,24 @@
1
+ import React from 'react'
2
+
3
+ import { Tag } from 'antd'
4
+
5
+ type EnumTagProps = {
6
+ value: string
7
+ map: Map<string, { label: string; value: string; extra?: { color?: string } }>
8
+ }
9
+
10
+ export const EnumTag = (props: EnumTagProps) => {
11
+ const { value, map } = props
12
+
13
+ const enumItem = map.get(value)
14
+
15
+ if (!enumItem) {
16
+ return <Tag>{value}</Tag>
17
+ }
18
+
19
+ return (
20
+ <Tag color={enumItem.extra?.color}>
21
+ {enumItem.label}
22
+ </Tag>
23
+ )
24
+ }
@@ -0,0 +1,57 @@
1
+ 'use client'
2
+
3
+ import { useImperativeHandle } from 'react'
4
+ import { Select, SelectProps, Spin } from 'antd'
5
+ import { useRequest } from '@wzyjs/hooks/web'
6
+
7
+ export interface FetchSelectProps<I> extends SelectProps {
8
+ selectRef?: any,
9
+ isDetail?: boolean, // 只返回id 还是返回整个信息
10
+ searchApi: (params: { search: string }) => Promise<any>,
11
+ convertData?: (data: I[]) => any[],
12
+ onChange?: (value: any) => void
13
+ }
14
+
15
+ export interface FetchSelectRef {
16
+ refresh: () => void
17
+ }
18
+
19
+ export const FetchSelect = <I extends { id: string | number }, >(props: FetchSelectProps<I>) => {
20
+ const { searchApi, convertData, onChange, isDetail = false, selectRef, ...other } = props
21
+
22
+ const { data, run, loading, refresh } = useRequest(searchApi, {
23
+ debounceWait: 100,
24
+ })
25
+
26
+ const onSearch = (value: string) => {
27
+ run({ search: value })
28
+ }
29
+
30
+ useImperativeHandle(selectRef, () => ({
31
+ refresh,
32
+ }))
33
+
34
+ return (
35
+ <Select
36
+ showSearch
37
+ defaultActiveFirstOption={false}
38
+ popupMatchSelectWidth={false}
39
+ suffixIcon={null}
40
+ filterOption={false}
41
+ notFoundContent={loading ? <Spin size='small' /> : null}
42
+ loading={loading}
43
+ {...other}
44
+
45
+ options={convertData ? convertData(data?.data || []) : data?.data}
46
+ onSearch={onSearch}
47
+ onChange={value => {
48
+ if (isDetail) {
49
+ const detail = data?.data?.find(item => item.id === value)
50
+ onChange?.(detail)
51
+ } else {
52
+ onChange?.(value)
53
+ }
54
+ }}
55
+ />
56
+ )
57
+ }
@@ -0,0 +1,52 @@
1
+ 'use client'
2
+
3
+ import React, { useState } from 'react'
4
+ import { Button } from 'antd'
5
+ import { DownOutlined, UpOutlined } from '@ant-design/icons'
6
+
7
+ interface FoldProps {
8
+ max: number
9
+ children?: React.ReactNode
10
+ btnStyle?: React.CSSProperties
11
+ }
12
+
13
+ export const Fold = (props: FoldProps) => {
14
+ const { max, children, btnStyle = {} } = props
15
+
16
+ const [collapsed, setCollapsed] = useState<boolean | undefined>(undefined)
17
+
18
+ const divRef = React.useRef<HTMLDivElement>(null)
19
+
20
+ React.useEffect(() => {
21
+ if (divRef.current) {
22
+ const { clientHeight } = divRef.current
23
+ if (clientHeight > max) {
24
+ setCollapsed(true)
25
+ }
26
+ }
27
+ }, [divRef.current])
28
+
29
+ return (
30
+ <div ref={divRef} style={{ overflow: 'hidden' }}>
31
+ <div style={{ maxHeight: collapsed ? max : undefined }}>
32
+ {children}
33
+ </div>
34
+
35
+ <div style={{ textAlign: 'center', ...btnStyle }}>
36
+ {collapsed === undefined ? null : collapsed ? (
37
+ <Button
38
+ size='small'
39
+ icon={<DownOutlined />}
40
+ onClick={() => setCollapsed(false)}
41
+ />
42
+ ) : (
43
+ <Button
44
+ size='small'
45
+ icon={<UpOutlined />}
46
+ onClick={() => setCollapsed(true)}
47
+ />
48
+ )}
49
+ </div>
50
+ </div>
51
+ )
52
+ }
@@ -0,0 +1,28 @@
1
+ 'use client'
2
+
3
+ import React, { useImperativeHandle, useRef } from 'react'
4
+ import { BetaSchemaForm, ProFormInstance } from '@ant-design/pro-components'
5
+ import { FormSchema } from '@ant-design/pro-form/es/components/SchemaForm'
6
+
7
+ export type { ProFormColumnsType, ProFormInstance } from '@ant-design/pro-components'
8
+
9
+ export type FormProProps<T, ValueType> = FormSchema<T, ValueType>
10
+
11
+ export const FormPro = <T, ValueType>(props: FormProProps<T, ValueType>) => {
12
+
13
+ const formRef = useRef<ProFormInstance>(null)
14
+ useImperativeHandle(props.formRef, () => formRef?.current, [formRef])
15
+
16
+ // useEffect(() => {
17
+ // if (props.value) {
18
+ // formRef.current?.setFieldsValue(props.value)
19
+ // }
20
+ // }, [JSON.stringify(props.value)])
21
+
22
+ return (
23
+ <BetaSchemaForm
24
+ {...props}
25
+ formRef={formRef}
26
+ />
27
+ )
28
+ }
@@ -0,0 +1,45 @@
1
+ import { CSSProperties, ReactNode } from 'react'
2
+
3
+ import GridLayout, { Layout } from 'react-grid-layout'
4
+ import 'react-grid-layout/css/styles.css'
5
+
6
+ export type { Layout as GridLayoutItem } from 'react-grid-layout'
7
+
8
+ interface GridLayoutProps<I> {
9
+ layout: I[]
10
+ style?: CSSProperties
11
+ onChange?: (layout: I[]) => void
12
+ renderItem?: (item: I) => ReactNode
13
+ }
14
+
15
+ export const GroupLayout = <I extends Layout>(props: GridLayoutProps<I>) => {
16
+ const { style, layout, onChange, renderItem = item => item.i } = props
17
+
18
+ const onLayoutChange = (items: Layout[]) => {
19
+ onChange?.(items.map(item => ({
20
+ ...layout.find(i => i.i === item.i),
21
+ ...item,
22
+ }) as I))
23
+ }
24
+
25
+ return (
26
+ <GridLayout
27
+ layout={layout}
28
+ cols={24}
29
+ rowHeight={50}
30
+ width={1200}
31
+ useCSSTransforms={false}
32
+ containerPadding={[0, 0]}
33
+ style={{ width: '100%', height: '100%', userSelect: 'none', ...style }}
34
+ draggableHandle='.drag-handle'
35
+ resizeHandles={['se']}
36
+ onLayoutChange={onLayoutChange}
37
+ >
38
+ {layout.map(item => (
39
+ <div key={item.i}>
40
+ {renderItem(item)}
41
+ </div>
42
+ ))}
43
+ </GridLayout>
44
+ )
45
+ }
@@ -0,0 +1,18 @@
1
+ 'use client'
2
+
3
+ import React, { CSSProperties } from 'react'
4
+
5
+ export interface HtmlProProps {
6
+ html: string;
7
+ style?: CSSProperties
8
+ }
9
+
10
+ export const HtmlPro = (props: HtmlProProps) => {
11
+ const { html, style = {} } = props
12
+ return (
13
+ <div
14
+ style={{ minWidth: '100%', ...style }}
15
+ dangerouslySetInnerHTML={{ __html: html }}
16
+ />
17
+ )
18
+ }
@@ -0,0 +1,52 @@
1
+ 'use client'
2
+
3
+ import React, { useEffect, CSSProperties } from 'react'
4
+ import { Spin } from 'antd'
5
+ import { useBoolean } from '@wzyjs/hooks/web'
6
+
7
+ export interface IframeProProps {
8
+ url: string;
9
+ errMessage?: string;
10
+ style?: CSSProperties;
11
+ isShowLoading?: boolean;
12
+ }
13
+
14
+ export const IframePro = (props: IframeProProps) => {
15
+ const { url, style, errMessage = '', isShowLoading = false } = props
16
+
17
+ const [loading, { setTrue, setFalse }] = useBoolean(true)
18
+
19
+ useEffect(() => {
20
+ setTrue()
21
+ }, [url])
22
+
23
+ if (!url) {
24
+ return (
25
+ <span
26
+ style={{
27
+ ...style,
28
+ color: '#ccc',
29
+ fontSize: 14,
30
+ display: 'flex',
31
+ flexDirection: 'column',
32
+ justifyContent: 'center',
33
+ alignItems: 'center',
34
+ }}
35
+ >
36
+ {errMessage || '没有url'}
37
+ </span>
38
+ )
39
+ }
40
+
41
+ return (
42
+ <Spin spinning={loading && isShowLoading}>
43
+ <iframe
44
+ src={url}
45
+ width='100%'
46
+ height='100%'
47
+ style={style}
48
+ onLoad={setFalse}
49
+ />
50
+ </Spin>
51
+ )
52
+ }