feat: 添加音频播放组件

This commit is contained in:
2025-09-21 01:45:08 +08:00
parent 74a72961f7
commit 7c34b3ca94
3 changed files with 115 additions and 2 deletions

View File

@@ -59,6 +59,7 @@ import { ref, computed, watch } from 'vue'
import { message } from 'ant-design-vue'
import MarkdownIt from 'markdown-it'
import { Service } from '@/api/services/Service'
import { useAudioPlayer } from '@/composables/useAudioPlayer'
interface Props {
visible: boolean
@@ -81,6 +82,9 @@ const visible = computed({
const confirming = ref(false)
const activeNoticeKey = ref('')
// 音频播放器
const { playSound } = useAudioPlayer()
// 初始化 markdown 解析器
const md = new MarkdownIt({
html: true,
@@ -159,10 +163,12 @@ watch(
{ immediate: true }
)
// 监听弹窗显示状态,重置到第一个公告
watch(visible, newVisible => {
// 监听弹窗显示状态,重置到第一个公告并播放音频
watch(visible, async (newVisible) => {
if (newVisible && notices.value.length > 0) {
activeNoticeKey.value = notices.value[0]
// 当公告模态框显示时播放音频
await playSound('simple/announcement_display')
}
})
</script>

View File

@@ -0,0 +1,99 @@
import { ref } from 'vue'
import { message } from 'ant-design-vue'
import { useSettingsApi } from '@/composables/useSettingsApi'
import { API_ENDPOINTS } from '@/config/mirrors'
export function useAudioPlayer() {
const { getSettings } = useSettingsApi()
const currentAudio = ref<HTMLAudioElement | null>(null)
const isPlaying = ref(false)
const loading = ref(false)
/**
* 停止当前播放的音频
*/
const stopCurrentAudio = () => {
if (currentAudio.value) {
currentAudio.value.pause()
currentAudio.value.currentTime = 0
currentAudio.value = null
isPlaying.value = false
}
}
/**
* 播放音频
* @param soundPath 音频路径,例如: "noisy/welcome" 或 "welcome"
*/
const playSound = async (soundPath: string): Promise<boolean> => {
if (!soundPath) {
console.warn('音频路径不能为空')
return false
}
loading.value = true
try {
// 首先检查语音设置
const settings = await getSettings()
if (!settings?.Voice?.Enabled) {
console.log('语音功能已禁用,跳过音频播放')
return false
}
// 停止当前播放的音频
stopCurrentAudio()
// 构建音频URL
const audioUrl = `${API_ENDPOINTS.local}/api/res/sounds/${soundPath}.wav`
// 创建新的音频对象
const audio = new Audio(audioUrl)
currentAudio.value = audio
// 设置音频事件监听器
audio.addEventListener('loadstart', () => {
isPlaying.value = true
})
audio.addEventListener('ended', () => {
isPlaying.value = false
currentAudio.value = null
})
audio.addEventListener('error', (e) => {
console.error('音频播放失败:', e)
message.error(`音频播放失败: ${soundPath}`)
isPlaying.value = false
currentAudio.value = null
})
// 播放音频
await audio.play()
return true
} catch (error) {
console.error('播放音频时发生错误:', error)
message.error('音频播放失败,请检查网络连接')
isPlaying.value = false
currentAudio.value = null
return false
} finally {
loading.value = false
}
}
/**
* 停止播放
*/
const stopSound = () => {
stopCurrentAudio()
}
return {
isPlaying,
loading,
playSound,
stopSound
}
}

View File

@@ -240,6 +240,7 @@ import { message } from 'ant-design-vue'
import { ClockCircleOutlined, UserOutlined, BellOutlined } from '@ant-design/icons-vue'
import { Service } from '@/api/services/Service'
import NoticeModal from '@/components/NoticeModal.vue'
import { useAudioPlayer } from '@/composables/useAudioPlayer'
import dayjs from 'dayjs'
import { API_ENDPOINTS } from '@/config/mirrors.ts'
@@ -296,6 +297,9 @@ const noticeVisible = ref(false)
const noticeData = ref<Record<string, string>>({})
const noticeLoading = ref(false)
// 音频播放器
const { playSound } = useAudioPlayer()
// 获取当前活动信息
const currentActivity = computed(() => {
if (!activityData.value.length) return null
@@ -435,6 +439,8 @@ const fetchNoticeData = async () => {
if (response.if_need_show && response.data && Object.keys(response.data).length > 0) {
noticeData.value = response.data
noticeVisible.value = true
// 播放公告展示音频
await playSound('simple/announcement_display')
}
} else {
console.warn('获取公告失败:', response.message)
@@ -461,6 +467,8 @@ const showNotice = async () => {
if (response.data && Object.keys(response.data).length > 0) {
noticeData.value = response.data
noticeVisible.value = true
// 手动查看公告时也播放音频
await playSound('simple/announcement_display')
} else {
message.info('暂无公告信息')
}