fix(style): playground image incomplete
This commit is contained in:
@@ -49,5 +49,11 @@
|
||||
|
||||
.speaker {
|
||||
margin-left: 10px;
|
||||
position: relative;
|
||||
|
||||
.volume-slider {
|
||||
position: absolute;
|
||||
bottom: 30px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import { formatTime } from '@/utils/index';
|
||||
import { PauseCircleFilled, PlayCircleFilled } from '@ant-design/icons';
|
||||
import { Button, Slider } from 'antd';
|
||||
import { Button, Slider, Tooltip } from 'antd';
|
||||
import { round } from 'lodash';
|
||||
import React, {
|
||||
forwardRef,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useImperativeHandle
|
||||
} from 'react';
|
||||
import CheckButtons from '../check-buttons';
|
||||
import IconFont from '../icon-font';
|
||||
import './index.less';
|
||||
|
||||
@@ -21,6 +23,13 @@ interface AudioPlayerProps {
|
||||
duration?: number;
|
||||
}
|
||||
|
||||
const speedOptions = [
|
||||
{ label: '1x', value: 1 },
|
||||
{ label: '2x', value: 2 },
|
||||
{ label: '3x', value: 3 },
|
||||
{ label: '4x', value: 4 }
|
||||
];
|
||||
|
||||
const AudioPlayer: React.FC<AudioPlayerProps> = forwardRef((props, ref) => {
|
||||
const { autoplay = false, speed: defaultSpeed = 1 } = props;
|
||||
const audioRef = React.useRef<HTMLAudioElement>(null);
|
||||
@@ -45,6 +54,14 @@ const AudioPlayer: React.FC<AudioPlayerProps> = forwardRef((props, ref) => {
|
||||
audioRef.current?.pause();
|
||||
}
|
||||
}));
|
||||
const handleShowVolume = useCallback(() => {
|
||||
setSpeakerOn(!speakerOn);
|
||||
}, [speakerOn]);
|
||||
|
||||
const handleSeepdChange = useCallback((value: number | string) => {
|
||||
setSpeed(value as number);
|
||||
audioRef.current!.playbackRate = value as number;
|
||||
}, []);
|
||||
|
||||
const handleAudioOnPlay = useCallback(() => {
|
||||
timer.current = setInterval(() => {
|
||||
@@ -78,16 +95,22 @@ const AudioPlayer: React.FC<AudioPlayerProps> = forwardRef((props, ref) => {
|
||||
setPlayOn(!playOn);
|
||||
}, [playOn]);
|
||||
|
||||
const handleFormatVolume = (val: number) => {
|
||||
return `${round(val * 100)}%`;
|
||||
};
|
||||
|
||||
const handleVolumeChange = useCallback((value: number) => {
|
||||
audioRef.current!.volume = round(value, 2);
|
||||
setVolume(round(value, 2));
|
||||
}, []);
|
||||
|
||||
const initPlayerConfig = useCallback(() => {
|
||||
// set volume
|
||||
audioRef.current!.volume = volume;
|
||||
// set playback rate
|
||||
audioRef.current!.playbackRate = speed;
|
||||
}, []);
|
||||
|
||||
const handleLoadedMetadata = useCallback(
|
||||
(data: any) => {
|
||||
console.log('loadmetadata++++++++');
|
||||
const duration = Math.ceil(audioRef.current?.duration || 0);
|
||||
setAudioState({
|
||||
currentTime: 0,
|
||||
@@ -158,7 +181,23 @@ const AudioPlayer: React.FC<AudioPlayerProps> = forwardRef((props, ref) => {
|
||||
onChange={handleCurrentChange}
|
||||
/>
|
||||
</div>
|
||||
<span>{props.speed ? `${props.speed}x` : '1x'}</span>
|
||||
<Tooltip
|
||||
overlayInnerStyle={{
|
||||
backgroundColor: 'var(--color-white-1)'
|
||||
}}
|
||||
arrow={false}
|
||||
title={
|
||||
<CheckButtons
|
||||
options={speedOptions}
|
||||
onChange={handleSeepdChange}
|
||||
size="small"
|
||||
></CheckButtons>
|
||||
}
|
||||
>
|
||||
<span style={{ cursor: 'pointer' }}>
|
||||
{speed ? `${speed}x` : '1x'}
|
||||
</span>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<span className="time">{formatTime(audioState.duration)}</span>
|
||||
</div>
|
||||
@@ -173,6 +212,19 @@ const AudioPlayer: React.FC<AudioPlayerProps> = forwardRef((props, ref) => {
|
||||
></IconFont>
|
||||
}
|
||||
></Button>
|
||||
{speakerOn && (
|
||||
<Slider
|
||||
tooltip={{ formatter: handleFormatVolume }}
|
||||
style={{ height: '100px' }}
|
||||
className="volume-slider"
|
||||
min={0}
|
||||
max={1}
|
||||
step={0.01}
|
||||
value={volume}
|
||||
vertical
|
||||
onChange={handleVolumeChange}
|
||||
/>
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
<audio
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import { Button } from 'antd';
|
||||
import React from 'react';
|
||||
|
||||
interface CheckButtonsProps {
|
||||
options: Global.BaseOption<string | number>[];
|
||||
onChange: (value: string | number) => void;
|
||||
cancelable?: boolean;
|
||||
size?: 'small' | 'middle' | 'large';
|
||||
type?: 'text' | 'primary' | 'default' | 'dashed' | 'link' | undefined;
|
||||
}
|
||||
|
||||
const CheckButtons: React.FC<CheckButtonsProps> = (props) => {
|
||||
const [type, setType] = React.useState(props.type || 'text');
|
||||
const [active, setActive] = React.useState<string | number | null>(null);
|
||||
const handleChange = (value: string | number) => {
|
||||
props.onChange(value);
|
||||
if (props.cancelable && active === value) {
|
||||
setActive(null);
|
||||
} else {
|
||||
setActive(value);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<div className="flex-center gap-6">
|
||||
{props.options?.map?.((option, index) => {
|
||||
return (
|
||||
<Button
|
||||
size={props.size}
|
||||
key={option.value}
|
||||
onClick={() => handleChange(option.value)}
|
||||
variant="filled"
|
||||
color={active === option.value ? 'default' : undefined}
|
||||
type={type}
|
||||
>
|
||||
{option.label}
|
||||
</Button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(CheckButtons);
|
||||
@@ -7,7 +7,6 @@ interface SpeechContentProps {
|
||||
}
|
||||
|
||||
const SpeechContent: React.FC<SpeechContentProps> = (props) => {
|
||||
console.log('SpeechContent', props);
|
||||
return (
|
||||
<>
|
||||
{props.dataList.map((item) => (
|
||||
|
||||
@@ -1,11 +1,29 @@
|
||||
import IconFont from '@/components/icon-font';
|
||||
import { DownloadOutlined, PlayCircleOutlined } from '@ant-design/icons';
|
||||
import {
|
||||
DownloadOutlined,
|
||||
PauseCircleOutlined,
|
||||
PlayCircleOutlined
|
||||
} from '@ant-design/icons';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Button, Tooltip } from 'antd';
|
||||
import dayjs from 'dayjs';
|
||||
import React, { useRef, useState } from 'react';
|
||||
import AudioPlayer from './audio-player';
|
||||
import './styles/index.less';
|
||||
|
||||
// const audioUrl = require('./ih.mp4');
|
||||
const audioFormat = {
|
||||
'audio/mpeg': 'mp3',
|
||||
'audio/wav': 'wav',
|
||||
'audio/ogg': 'ogg',
|
||||
'audio/webm': 'webm',
|
||||
'audio/aac': 'aac',
|
||||
'audio/x-flac': 'flac',
|
||||
'audio/pcm': 'pcm',
|
||||
'audio/flac': 'flac',
|
||||
'audio/x-wav': 'wav',
|
||||
'audio/L16': 'pcm',
|
||||
'audio/opus': 'opus'
|
||||
};
|
||||
|
||||
interface SpeechContentProps {
|
||||
prompt: string;
|
||||
@@ -16,12 +34,19 @@ interface SpeechContentProps {
|
||||
audioUrl: string;
|
||||
}
|
||||
const SpeechItem: React.FC<SpeechContentProps> = (props) => {
|
||||
console.log('porps=======', props);
|
||||
const intl = useIntl();
|
||||
const [collapsed, setCollapsed] = useState(false);
|
||||
const [isPlay, setIsPlay] = useState(false);
|
||||
const ref = useRef<HTMLAudioElement>(null);
|
||||
|
||||
const handlePlay = () => {
|
||||
if (isPlay) {
|
||||
ref.current?.pause();
|
||||
setIsPlay(false);
|
||||
return;
|
||||
}
|
||||
ref.current?.play();
|
||||
setIsPlay(true);
|
||||
};
|
||||
|
||||
const handleCollapse = () => {
|
||||
@@ -30,7 +55,7 @@ const SpeechItem: React.FC<SpeechContentProps> = (props) => {
|
||||
|
||||
const onDownload = () => {
|
||||
const url = props.audioUrl || '';
|
||||
const filename = Date.now() + '';
|
||||
const filename = `audio-${dayjs().format('YYYYMMDDHHmmss')}.${props.format}`;
|
||||
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
@@ -45,7 +70,6 @@ const SpeechItem: React.FC<SpeechContentProps> = (props) => {
|
||||
<div className="speech-item">
|
||||
<div className="voice">
|
||||
<IconFont type="icon-user_voice" className="font-size-16" />
|
||||
{/* <span className="text">{props.voice}</span> */}
|
||||
</div>
|
||||
<div className="wrapper">
|
||||
<AudioPlayer
|
||||
@@ -62,15 +86,25 @@ const SpeechItem: React.FC<SpeechContentProps> = (props) => {
|
||||
<span className="item">{props.speed}x</span>
|
||||
</span>
|
||||
<div className="actions">
|
||||
<Tooltip title="Play">
|
||||
<Tooltip
|
||||
title={
|
||||
isPlay
|
||||
? intl.formatMessage({ id: 'playground.audio.button.stop' })
|
||||
: intl.formatMessage({ id: 'playground.audio.button.play' })
|
||||
}
|
||||
>
|
||||
<Button
|
||||
onClick={handlePlay}
|
||||
icon={<PlayCircleOutlined />}
|
||||
icon={isPlay ? <PauseCircleOutlined /> : <PlayCircleOutlined />}
|
||||
type="text"
|
||||
size="small"
|
||||
></Button>
|
||||
</Tooltip>
|
||||
<Tooltip title="Download">
|
||||
<Tooltip
|
||||
title={intl.formatMessage({
|
||||
id: 'playground.audio.button.download'
|
||||
})}
|
||||
>
|
||||
<Button
|
||||
onClick={onDownload}
|
||||
icon={<DownloadOutlined />}
|
||||
@@ -78,21 +112,8 @@ const SpeechItem: React.FC<SpeechContentProps> = (props) => {
|
||||
size="small"
|
||||
></Button>
|
||||
</Tooltip>
|
||||
{/* <Tooltip title="Show Prompt">
|
||||
<Button
|
||||
icon={<FileTextOutlined />}
|
||||
type="text"
|
||||
size="small"
|
||||
onClick={handleCollapse}
|
||||
></Button>
|
||||
</Tooltip> */}
|
||||
</div>
|
||||
</div>
|
||||
{/* {collapsed && (
|
||||
<div className="prompt-box">
|
||||
<div className="prompt">{props.prompt}</div>
|
||||
</div>
|
||||
)} */}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -13,12 +13,11 @@ interface UploadAudioProps {
|
||||
const UploadAudio: React.FC<UploadAudioProps> = (props) => {
|
||||
const intl = useIntl();
|
||||
const beforeUpload = (file: any) => {
|
||||
return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
const handleOnChange = React.useCallback(
|
||||
(data: { file: any; fileList: any }) => {
|
||||
console.log('handleOnChange', data);
|
||||
props.onChange?.(data);
|
||||
},
|
||||
[]
|
||||
|
||||
Reference in New Issue
Block a user