360fans_43883305 发表于 2026-5-14 08:53

政府单位系统 需要这个语音播报的功能,为什么一直弹出请求授权,

点了开启播报 下次语音消息来了 又弹窗,不能一次性全部允许吗

360fans_43883305 发表于 2026-5-14 09:08

有没有和谷歌浏览器这样chrome://settings/content/sound 一下设置所有的免授权的网址

jiang_in 发表于 2026-5-14 10:05

那个网址这边能打开不,这边看下

360fans_43883305 发表于 2026-5-14 11:10

# 语音播报功能文档

## 功能概述

语音播报功能用于实时播报系统告警消息和催报通知,通过 WebSocket 接收后端推送的消息,并使用浏览器原生语音合成 API 进行播报。

---

## 技术实现

### 1. 语音合成 API

项目使用浏览器原生的 `Web Speech API` 进行语音播报:

```javascript
const synth = window.speechSynthesis
```

#### 核心播报方法

```javascript
voiceBroadcast(text) {
const msg = new SpeechSynthesisUtterance(text)
msg.lang = 'zh-CN'    // 中文语音
msg.volume = 1      // 音量 (0-1)
msg.rate = 1          // 语速
msg.pitch = 1         // 音调
synth.speak(msg)
}
```

### 2. 授权机制

由于浏览器安全策略,首次使用语音播报需要用户手动授权。

#### 授权流程

1. 收到消息时检测是否已授权 (`voiceAuthorized`)
2. 未授权则将消息加入待播报队列 (`pendingVoiceTexts`)
3. 弹出确认框请求用户授权
4. 用户点击"开启播报"后:
   - 标记已授权
   - 调用 `unlockVoiceBroadcast()` 解锁语音引擎
   - 调用 `flushPendingVoiceBroadcasts()` 播报队列中的消息

#### 关键代码

```javascript
// 解锁语音播报(静音播报空字符串激活引擎)
unlockVoiceBroadcast() {
const unlockMsg = new SpeechSynthesisUtterance(' ')
unlockMsg.lang = 'zh-CN'
unlockMsg.volume = 0// 静音
synth.cancel()
synth.speak(unlockMsg)
}

// 刷新页面后需重新授权
// 用户拒绝授权后,后续消息继续存入队列(最多20条)
```

### 3. 消息队列机制

```javascript
queueVoiceBroadcast(text) {
if (!text) return

if (this.voiceAuthorized) {
    this.voiceBroadcast(text)// 已授权直接播报
    return
}

// 未授权时存入队列,最多保留20条
if (this.pendingVoiceTexts.length >= 20) {
    this.pendingVoiceTexts.shift()
}
this.pendingVoiceTexts.push(text)
this.promptVoiceAuthorization()// 弹出授权确认框
}
```

---

## WebSocket 消息接收

### 一期 WebSocket

**连接地址**: `window._CONFIG['websocket1']`

**消息格式**:
```javascript
{
message: {
    sendManageName: '发送方名称',
    secondTypeName: '消息类型',
    content: '消息内容',
    sendTime: '发送时间'
}
}
```

**播报内容生成**:
```javascript
let speakStr = `${data.message.sendManageName}的${data.message.secondTypeName}${content}`
```

### 二期 WebSocket

**连接地址**: `window._CONFIG['websocket2']`

**消息格式** (催报消息):
```javascript
{
cmd: 'DDFA_MSG',
sendManageName: '发送方名称',
bussName: '业务名称',
content: '消息内容'
}
```

**播报内容生成**:
```javascript
this.queueVoiceBroadcast(
`来自${data.sendManageName + '的' + data.bussName + '消息,' + content}`
)
```

---

## 文本预处理

播报前会对文本进行字符替换,确保语音正确朗读:

```javascript
content = content.replace(/m³/g, '立方米')
content = content.replace(/\/s/g, '每秒')
```

---

## 消息存储

播报内容会同步存储到 `sessionStorage`,用于历史记录查看:

```javascript
const time = moment().format('YYYY/MM/DD HH:mm')
const newMsgStr = time + speakStr + '\n'
sessionStorage.setItem('一期speakStr语音', voiceStr)
```

---

## 心跳机制

WebSocket 通过心跳保持连接:

```javascript
// 每5秒发送心跳
heartCheckFun() {
this.heartCheck = {
    timeout: 5000,
    start: function() {
      this.timeoutObj = setTimeout(() => {
      that.websocketSend('HeartBeat')
      }, this.timeout)
    }
}
}
```

---

## 错误重连

连接错误时自动重连,最多尝试5次:

```javascript
websocketOnerror() {
this.wsConnectErrorTime += 1
if (this.wsConnectErrorTime > 5) {
    this.lockReconnect = true// 锁定不再重连
    return
}
this.reconnect()// 5秒后重连
}
```

---

## 相关文件

| 文件路径 | 功能描述 |
|---------|---------|
| `src/components/page/GlobalHeader.vue` | 主要语音播报实现(Web Speech API) |
| `src/components/tools/HeaderNotice.vue` | 旧版通知组件(百度 TTS,已弃用) |

---

## 注意事项

1. **浏览器兼容性**: Web Speech API 支持现代浏览器(Chrome、Edge、Firefox、Safari)
2. **授权状态**: 刷新页面后需要重新授权
3. **队列上限**: 未授权时最多缓存20条消息
4. **连接管理**: 页面离开时自动关闭 WebSocket 连接 (`beforeDestroy`)
5. **门户用户**: `manageId === '10001'` 的用户有特殊的 WebSocket 初始化逻辑
页: [1]
查看完整版本: 政府单位系统 需要这个语音播报的功能,为什么一直弹出请求授权,