feat: translate

This commit is contained in:
2025-10-15 10:34:22 +08:00
parent 32b4a7e624
commit ee96c5feb8
11 changed files with 231 additions and 75 deletions

View File

@@ -6,10 +6,12 @@ import catSvg from "@/assets/translate/cat.svg";
import pigSvg from "@/assets/translate/pig.svg";
import { Message } from "../../../types";
import "./index.less";
import { Refresh } from "@icon-park/react";
interface DefinedProps {
data: Message[];
isRecording: boolean;
onRefresh: (formData: FormData, messageId: number) => void;
}
function Index(props: DefinedProps) {
@@ -26,16 +28,16 @@ function Index(props: DefinedProps) {
const onVoiceChange = () => {
setIsPlating(!isPlaying);
};
const playAudio = (messageId: number, audioUrl: string) => {
const playAudio = (id: number, audioUrl: string) => {
if (isRecording) {
Toast.show("录音中,无法播放音频");
return;
}
if (currentPlayingId === messageId) {
if (audioRefs.current[messageId]) {
audioRefs.current[messageId].pause();
audioRefs.current[messageId].currentTime = 0;
if (currentPlayingId === id && audioRefs.current[id]) {
if (audioRefs.current[id]) {
audioRefs.current[id].pause();
audioRefs.current[id].currentTime = 0;
}
setCurrentPlayingId(undefined);
setIsPlating(false);
@@ -43,11 +45,11 @@ function Index(props: DefinedProps) {
}
stopAllAudio();
if (!audioRefs.current[messageId]) {
audioRefs.current[messageId] = new Audio(audioUrl);
if (!audioRefs.current[id]) {
audioRefs.current[id] = new Audio(audioUrl);
}
const audio = audioRefs.current[messageId];
const audio = audioRefs.current[id];
audio.currentTime = 0;
audio.onended = () => {
@@ -55,8 +57,24 @@ function Index(props: DefinedProps) {
setIsPlating(false);
};
audio.onerror = (error) => {
console.error("音频播放错误:", error);
audio.onerror = () => {
const error = audio.error;
switch (error?.code) {
case MediaError.MEDIA_ERR_ABORTED:
console.warn("音频播放被用户中断");
break;
case MediaError.MEDIA_ERR_NETWORK:
console.warn("网络错误,无法加载音频");
break;
case MediaError.MEDIA_ERR_DECODE:
console.warn("解码失败,可能是格式不支持");
break;
case MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED:
console.warn("浏览器不支持该音频格式");
break;
default:
console.warn("未知错误");
};
Toast.show("音频播放失败");
setIsPlating(false);
};
@@ -64,7 +82,7 @@ function Index(props: DefinedProps) {
audio
.play()
.then(() => {
setCurrentPlayingId(messageId);
setCurrentPlayingId(id);
setIsPlating(true);
})
.catch((error) => {
@@ -87,7 +105,7 @@ function Index(props: DefinedProps) {
}
});
};
const renderAvatar = (type?: "pig" | "cat" | "dog") => {
const renderAvatar = (type?: "pig" | "cat" | "dog" | "") => {
if (type === "pig") {
<Image src={pigSvg} width={40} height={40} fit="cover" style={{ borderRadius: 32 }} />;
}
@@ -97,31 +115,43 @@ function Index(props: DefinedProps) {
return <Image src={dogSvg} width={40} height={40} fit="cover" style={{ borderRadius: 32 }} />;
};
const refreshMessage = async (messageId: number, e: React.MouseEvent) => {
e.stopPropagation();
const formData = new FormData();
formData.append("msgId", messageId.toString());
props.onRefresh(formData, messageId);
};
return (
<div className="message">
{data.map((item, index) => (
<div className="item" key={index} onClick={() => playAudio(item.id, item.audioUrl)}>
{renderAvatar(item.type)}
<div className="item" key={index} onClick={() => playAudio(item.id, item.contentText)}>
{renderAvatar(item.petType)}
<div className="rig">
<div>
<span className="name">{item.name}</span>
<span className="name">{item.petName}</span>
<Divider direction="vertical" style={{ margin: "0px 8px" }} />
<span className="">{item.timestamp}</span>
<span className="">{item.createTime}</span>
</div>
<div className="voice-container">
<VoiceIcon
onChange={onVoiceChange}
isPlaying={isPlaying && currentPlayingId === item.id}
/>
<div className="time">{item.duration}''</div>
<div className="time">{item.contentDuration}''</div>
</div>
{item.isTranslating ? (
<div className="translate">
<SpinLoading color="default" style={{ "--size": "12px" }} />
<span>...</span>
</div>
) : item.transStatus === 1 ? (
<div className="translate">{item.transResult ?? "暂无翻译结果"}</div>
) : (
<div className="translate">{item.translatedText}</div>
<div className="translate">
<span> </span>
<Refresh onClick={(e) => refreshMessage(item.id, e)} size="12" fill="#333" />
</div>
)}
</div>
</div>
@@ -141,6 +171,8 @@ function Index(props: DefinedProps) {
</div>
</div>
</div>
<div style={{ height: "130px", width: "100%" }}></div>
</div>
);
}