155 lines
4.0 KiB
TypeScript
155 lines
4.0 KiB
TypeScript
import { useCallback, useEffect, useRef, useState } from "react";
|
|
import FloatingMenu, { FloatMenuItemConfig } from "@/component/floatingMenu";
|
|
import { Image, Toast } from "antd-mobile";
|
|
import MessageCom from "./component/message";
|
|
import VoiceRecord from "./component/voice";
|
|
import XPopup from "@/component/xpopup";
|
|
import type { Message } from "./types";
|
|
|
|
import { mockTranslateAudio } from "@/utils/voice";
|
|
import dogSvg from "@/assets/translate/dog.svg";
|
|
import catSvg from "@/assets/translate/cat.svg";
|
|
import pigSvg from "@/assets/translate/pig.svg";
|
|
import { MoreTwo } from "@icon-park/react";
|
|
interface DefinedProps {}
|
|
const menuItems: FloatMenuItemConfig[] = [
|
|
{ icon: <Image src={dogSvg} />, type: "dog" },
|
|
{ icon: <Image src={catSvg} />, type: "cat" },
|
|
{ icon: <Image src={pigSvg} />, type: "pig" },
|
|
{
|
|
icon: (
|
|
<MoreTwo
|
|
theme="outline"
|
|
size="24"
|
|
fill="#666"
|
|
strokeWidth={3}
|
|
strokeLinecap="butt"
|
|
/>
|
|
),
|
|
type: "add",
|
|
},
|
|
];
|
|
function Index(props: DefinedProps) {
|
|
// const data: Message[] = [
|
|
// {
|
|
// id: 1,
|
|
// audioUrl: "",
|
|
// duration: 0,
|
|
// translatedText: "",
|
|
// isTranslating: true,
|
|
// isPlaying: false,
|
|
// timestamp: 0,
|
|
// },
|
|
// ];
|
|
const [currentPlayingId, setCurrentPlayingId] = useState<string | null>(null); //当前播放id
|
|
const [messages, setMessages] = useState<Message[]>([]);
|
|
const [isRecording, setIsRecording] = useState(false); //是否录音中
|
|
const [currentLanguage, setCurrentLanguage] = useState<FloatMenuItemConfig>();
|
|
const [visible, setVisible] = useState<boolean>(false);
|
|
|
|
useEffect(() => {
|
|
setCurrentLanguage(menuItems[0]);
|
|
}, []);
|
|
|
|
//完成录音
|
|
const onRecordingComplete = useCallback(
|
|
(audioUrl: string, actualDuration: number) => {
|
|
const newMessage: Message = {
|
|
id: Date.now(),
|
|
type: "dog",
|
|
audioUrl,
|
|
name: "生无可恋喵",
|
|
duration: actualDuration,
|
|
timestamp: Date.now(),
|
|
isTranslating: true,
|
|
};
|
|
|
|
setMessages((prev) => [...prev, newMessage]);
|
|
setTimeout(() => {
|
|
onTranslateAudio(newMessage.id);
|
|
}, 1000);
|
|
|
|
Toast.show("语音已发送");
|
|
},
|
|
[messages]
|
|
);
|
|
|
|
//翻译
|
|
const onTranslateAudio = useCallback(
|
|
async (messageId: number) => {
|
|
try {
|
|
const translatedText = await mockTranslateAudio();
|
|
|
|
setMessages((prev) =>
|
|
prev.map((msg) =>
|
|
msg.id === messageId
|
|
? { ...msg, translatedText, isTranslating: false }
|
|
: msg
|
|
)
|
|
);
|
|
} catch (error) {
|
|
console.error("翻译失败:", error);
|
|
Toast.show("翻译失败,请重试");
|
|
|
|
setMessages((prev) =>
|
|
prev.map((msg) =>
|
|
msg.id === messageId
|
|
? {
|
|
...msg,
|
|
isTranslating: false,
|
|
translatedText: "翻译失败,请重试",
|
|
}
|
|
: msg
|
|
)
|
|
);
|
|
}
|
|
},
|
|
[messages]
|
|
);
|
|
|
|
const onSetIsRecording = (flag: boolean) => {
|
|
setIsRecording(flag);
|
|
};
|
|
|
|
const onLanguage = (item: FloatMenuItemConfig) => {
|
|
if (item.type === "add") {
|
|
setVisible(true);
|
|
} else {
|
|
setCurrentLanguage(item);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="translate-container">
|
|
<MessageCom data={messages} isRecording={isRecording}></MessageCom>
|
|
<VoiceRecord
|
|
onRecordingComplete={onRecordingComplete}
|
|
isRecording={isRecording}
|
|
onSetIsRecording={onSetIsRecording}
|
|
/>
|
|
<FloatingMenu
|
|
menuItems={menuItems}
|
|
value={currentLanguage}
|
|
onChange={onLanguage}
|
|
/>
|
|
<XPopup
|
|
title="选择翻译语种"
|
|
visible={visible}
|
|
onClose={() => {
|
|
setVisible(false);
|
|
}}
|
|
>
|
|
<div className="card">
|
|
<span>快捷选项</span>
|
|
<div></div>
|
|
</div>
|
|
<div className="card">
|
|
<span>宠物语种</span>
|
|
</div>
|
|
</XPopup>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default Index;
|