@@ -17,26 +17,132 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
1717For commercial licensing, please contact support@quantumnous.com
1818*/
1919
20- import React from 'react' ;
21- import { Modal } from '@douyinfe/semi-ui' ;
20+ import React , { useState , useEffect } from 'react' ;
21+ import { Modal , Button , Typography , Spin } from '@douyinfe/semi-ui' ;
22+ import { IconExternalOpen , IconCopy } from '@douyinfe/semi-icons' ;
23+
24+ const { Text } = Typography ;
2225
2326const ContentModal = ( {
2427 isModalOpen,
2528 setIsModalOpen,
2629 modalContent,
2730 isVideo,
2831} ) => {
32+ const [ videoError , setVideoError ] = useState ( false ) ;
33+ const [ isLoading , setIsLoading ] = useState ( false ) ;
34+
35+ useEffect ( ( ) => {
36+ if ( isModalOpen && isVideo ) {
37+ setVideoError ( false ) ;
38+ setIsLoading ( true ) ;
39+ }
40+ } , [ isModalOpen , isVideo ] ) ;
41+
42+ const handleVideoError = ( ) => {
43+ setVideoError ( true ) ;
44+ setIsLoading ( false ) ;
45+ } ;
46+
47+ const handleVideoLoaded = ( ) => {
48+ setIsLoading ( false ) ;
49+ } ;
50+
51+ const handleCopyUrl = ( ) => {
52+ navigator . clipboard . writeText ( modalContent ) ;
53+ } ;
54+
55+ const handleOpenInNewTab = ( ) => {
56+ window . open ( modalContent , '_blank' ) ;
57+ } ;
58+
59+ const renderVideoContent = ( ) => {
60+ if ( videoError ) {
61+ return (
62+ < div style = { { textAlign : 'center' , padding : '40px' } } >
63+ < Text type = "tertiary" style = { { display : 'block' , marginBottom : '16px' } } >
64+ 视频无法在当前浏览器中播放,这可能是由于:
65+ </ Text >
66+ < Text type = "tertiary" style = { { display : 'block' , marginBottom : '8px' , fontSize : '12px' } } >
67+ • 视频服务商的跨域限制
68+ </ Text >
69+ < Text type = "tertiary" style = { { display : 'block' , marginBottom : '8px' , fontSize : '12px' } } >
70+ • 需要特定的请求头或认证
71+ </ Text >
72+ < Text type = "tertiary" style = { { display : 'block' , marginBottom : '16px' , fontSize : '12px' } } >
73+ • 防盗链保护机制
74+ </ Text >
75+
76+ < div style = { { marginTop : '20px' } } >
77+ < Button
78+ icon = { < IconExternalOpen /> }
79+ onClick = { handleOpenInNewTab }
80+ style = { { marginRight : '8px' } }
81+ >
82+ 在新标签页中打开
83+ </ Button >
84+ < Button
85+ icon = { < IconCopy /> }
86+ onClick = { handleCopyUrl }
87+ >
88+ 复制链接
89+ </ Button >
90+ </ div >
91+
92+ < div style = { { marginTop : '16px' , padding : '8px' , backgroundColor : '#f8f9fa' , borderRadius : '4px' } } >
93+ < Text
94+ type = "tertiary"
95+ style = { { fontSize : '10px' , wordBreak : 'break-all' } }
96+ >
97+ { modalContent }
98+ </ Text >
99+ </ div >
100+ </ div >
101+ ) ;
102+ }
103+
104+ return (
105+ < div style = { { position : 'relative' } } >
106+ { isLoading && (
107+ < div style = { {
108+ position : 'absolute' ,
109+ top : '50%' ,
110+ left : '50%' ,
111+ transform : 'translate(-50%, -50%)' ,
112+ zIndex : 10
113+ } } >
114+ < Spin size = "large" />
115+ </ div >
116+ ) }
117+ < video
118+ src = { modalContent }
119+ controls
120+ style = { { width : '100%' } }
121+ autoPlay
122+ crossOrigin = "anonymous"
123+ onError = { handleVideoError }
124+ onLoadedData = { handleVideoLoaded }
125+ onLoadStart = { ( ) => setIsLoading ( true ) }
126+ />
127+ </ div >
128+ ) ;
129+ } ;
130+
29131 return (
30132 < Modal
31133 visible = { isModalOpen }
32134 onOk = { ( ) => setIsModalOpen ( false ) }
33135 onCancel = { ( ) => setIsModalOpen ( false ) }
34136 closable = { null }
35- bodyStyle = { { height : '400px' , overflow : 'auto' } }
137+ bodyStyle = { {
138+ height : isVideo ? '450px' : '400px' ,
139+ overflow : 'auto' ,
140+ padding : isVideo && videoError ? '0' : '24px'
141+ } }
36142 width = { 800 }
37143 >
38144 { isVideo ? (
39- < video src = { modalContent } controls style = { { width : '100%' } } autoPlay />
145+ renderVideoContent ( )
40146 ) : (
41147 < p style = { { whiteSpace : 'pre-line' } } > { modalContent } </ p >
42148 ) }
0 commit comments