| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 |
- /*
- Copyright (C) 2025 QuantumNous
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as
- published by the Free Software Foundation, either version 3 of the
- License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>.
- For commercial licensing, please contact support@quantumnous.com
- */
- import React, { useState, useEffect } from 'react';
- import { Modal, Button, Typography, Spin } from '@douyinfe/semi-ui';
- import { IconExternalOpen, IconCopy } from '@douyinfe/semi-icons';
- import { useTranslation } from 'react-i18next';
- const { Text } = Typography;
- const ContentModal = ({
- isModalOpen,
- setIsModalOpen,
- modalContent,
- isVideo,
- }) => {
- const { t } = useTranslation();
- const [videoError, setVideoError] = useState(false);
- const [isLoading, setIsLoading] = useState(false);
- useEffect(() => {
- if (isModalOpen && isVideo) {
- setVideoError(false);
- setIsLoading(true);
- }
- }, [isModalOpen, isVideo]);
- const handleVideoError = () => {
- setVideoError(true);
- setIsLoading(false);
- };
- const handleVideoLoaded = () => {
- setIsLoading(false);
- };
- const handleCopyUrl = () => {
- navigator.clipboard.writeText(modalContent);
- };
- const handleOpenInNewTab = () => {
- window.open(modalContent, '_blank');
- };
- const renderVideoContent = () => {
- if (videoError) {
- return (
- <div style={{ textAlign: 'center', padding: '40px' }}>
- <Text
- type='tertiary'
- style={{ display: 'block', marginBottom: '16px' }}
- >
- {t('视频无法在当前浏览器中播放,这可能是由于:')}
- </Text>
- <Text
- type='tertiary'
- style={{ display: 'block', marginBottom: '8px', fontSize: '12px' }}
- >
- {t('• 视频服务商的跨域限制')}
- </Text>
- <Text
- type='tertiary'
- style={{ display: 'block', marginBottom: '8px', fontSize: '12px' }}
- >
- {t('• 需要特定的请求头或认证')}
- </Text>
- <Text
- type='tertiary'
- style={{ display: 'block', marginBottom: '16px', fontSize: '12px' }}
- >
- {t('• 防盗链保护机制')}
- </Text>
- <div style={{ marginTop: '20px' }}>
- <Button
- icon={<IconExternalOpen />}
- onClick={handleOpenInNewTab}
- style={{ marginRight: '8px' }}
- >
- {t('在新标签页中打开')}
- </Button>
- <Button icon={<IconCopy />} onClick={handleCopyUrl}>
- {t('复制链接')}
- </Button>
- </div>
- <div
- style={{
- marginTop: '16px',
- padding: '8px',
- backgroundColor: '#f8f9fa',
- borderRadius: '4px',
- }}
- >
- <Text
- type='tertiary'
- style={{ fontSize: '10px', wordBreak: 'break-all' }}
- >
- {modalContent}
- </Text>
- </div>
- </div>
- );
- }
- return (
- <div style={{ position: 'relative', height: '100%' }}>
- {isLoading && (
- <div
- style={{
- position: 'absolute',
- top: '50%',
- left: '50%',
- transform: 'translate(-50%, -50%)',
- zIndex: 10,
- }}
- >
- <Spin size='large' />
- </div>
- )}
- <video
- src={modalContent}
- controls
- style={{
- width: '100%',
- height: '100%',
- maxWidth: '100%',
- maxHeight: '100%',
- objectFit: 'contain',
- }}
- onError={handleVideoError}
- onLoadedData={handleVideoLoaded}
- onLoadStart={() => setIsLoading(true)}
- />
- </div>
- );
- };
- return (
- <Modal
- visible={isModalOpen}
- onOk={() => setIsModalOpen(false)}
- onCancel={() => setIsModalOpen(false)}
- closable={null}
- bodyStyle={{
- height: isVideo ? '70vh' : '400px',
- maxHeight: '80vh',
- overflow: 'auto',
- padding: isVideo && videoError ? '0' : '24px',
- }}
- width={isVideo ? '90vw' : 800}
- style={isVideo ? { maxWidth: 960 } : undefined}
- >
- {isVideo ? (
- renderVideoContent()
- ) : (
- <p style={{ whiteSpace: 'pre-line' }}>{modalContent}</p>
- )}
- </Modal>
- );
- };
- export default ContentModal;
|