84 lines
1.8 KiB
Vue
84 lines
1.8 KiB
Vue
<script setup lang="ts">
|
||
import { SpeakerWaveIcon } from "@/assets/Icons";
|
||
import { useLayoutStore, useTtsStore } from "@/stores";
|
||
|
||
const { text, messageId } = defineProps<{
|
||
text: string;
|
||
messageId: string;
|
||
}>();
|
||
|
||
const ttsStore = useTtsStore();
|
||
const layoutStore = useLayoutStore();
|
||
const { simpleMode } = storeToRefs(layoutStore);
|
||
|
||
// 获取当前消息的状态
|
||
const isPlaying = computed(() => ttsStore.isPlaying(messageId));
|
||
const isLoading = computed(() => ttsStore.isLoading(messageId));
|
||
const hasAudio = computed(() => ttsStore.hasAudio(messageId));
|
||
|
||
// 处理按钮点击
|
||
const handleClick = () => {
|
||
if (isLoading.value) {
|
||
return; // 合成中不响应点击
|
||
}
|
||
|
||
if (hasAudio.value) {
|
||
// 如果音频已准备好,切换播放/暂停
|
||
if (isPlaying.value) {
|
||
ttsStore.pause(messageId);
|
||
} else {
|
||
ttsStore.play(messageId);
|
||
}
|
||
} else {
|
||
// 如果没有音频,开始TTS转换
|
||
ttsStore.convertText(text, messageId);
|
||
}
|
||
};
|
||
|
||
// 文本改变清理之前的音频
|
||
watch(
|
||
() => text,
|
||
() => {
|
||
ttsStore.clearAudio(messageId);
|
||
}
|
||
);
|
||
|
||
onUnmounted(() => {
|
||
ttsStore.clearAudio(messageId);
|
||
});
|
||
</script>
|
||
|
||
<template>
|
||
<NPopover trigger="hover">
|
||
<template #trigger>
|
||
<NButton
|
||
:loading="isLoading"
|
||
@click="handleClick"
|
||
quaternary
|
||
circle
|
||
:disabled="!text.trim()"
|
||
>
|
||
<SpeakerWaveIcon
|
||
v-if="!isLoading"
|
||
class="!w-4 !h-4"
|
||
:class="{
|
||
'': !simpleMode,
|
||
'animate-pulse': isPlaying
|
||
}"
|
||
/>
|
||
</NButton>
|
||
</template>
|
||
<span>
|
||
{{
|
||
isLoading
|
||
? "合成中..."
|
||
: isPlaying
|
||
? "点击暂停"
|
||
: hasAudio
|
||
? "点击播放"
|
||
: "语音合成"
|
||
}}
|
||
</span>
|
||
</NPopover>
|
||
</template>
|