feat: 添加音频播放组件
This commit is contained in:
@@ -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>
|
||||
|
||||
99
frontend/src/composables/useAudioPlayer.ts
Normal file
99
frontend/src/composables/useAudioPlayer.ts
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -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('暂无公告信息')
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user