|
|
@@ -2,6 +2,7 @@
|
|
|
<view class="notice-board">
|
|
|
<view class="board-header">
|
|
|
<view class="card_logo" @click="linkSet">
|
|
|
+ <!-- <view class="card_logo"> -->
|
|
|
<image class="logo_image" src="/static/logo.png" mode=""></image>
|
|
|
<view class="logo_title">观山湖区疾控中心</view>
|
|
|
</view>
|
|
|
@@ -34,7 +35,7 @@
|
|
|
</view>
|
|
|
<view class="table-cell time">{{ formatTime(item.createTime) }}</view>
|
|
|
<view class="table-cell time">{{ formatTime(item.outTime) }}</view>
|
|
|
- <view class="table-cell status">
|
|
|
+ <view class="table-cell status" style="padding: 0rpx;">
|
|
|
<view class="status-tag" :class="`status-${getClass(item.status)}`">
|
|
|
{{ getStatusText(item) }}
|
|
|
</view>
|
|
|
@@ -52,7 +53,7 @@
|
|
|
</view>
|
|
|
<view class="table-cell time">{{ formatTime(item.createTime) }}</view>
|
|
|
<view class="table-cell time">{{ formatTime(item.outTime) }}</view>
|
|
|
- <view class="table-cell status">
|
|
|
+ <view class="table-cell status" style="padding: 0rpx;">
|
|
|
<view class="status-tag" :class="`status-${getClass(item.status)}`">
|
|
|
{{ getStatusText(item) }}
|
|
|
</view>
|
|
|
@@ -157,6 +158,9 @@
|
|
|
heartbeatRate: 0,
|
|
|
isSend: true,
|
|
|
reconnectionNum: 0,
|
|
|
+ TTSSpeech: null,
|
|
|
+ speechQueue: [], // 语音队列
|
|
|
+ isSpeaking: false, // 是否正在播放语音
|
|
|
}
|
|
|
},
|
|
|
computed: {
|
|
|
@@ -221,6 +225,22 @@
|
|
|
})
|
|
|
}
|
|
|
},
|
|
|
+ onLoad() {
|
|
|
+ //#ifdef APP
|
|
|
+ // 引入插件
|
|
|
+ this.TTSSpeech = uni.requireNativePlugin('MT-TTS-Speech');
|
|
|
+ // 初始化TTS引擎
|
|
|
+ this.TTSSpeech.init((status) => { // 👈 同样移除 : number
|
|
|
+ if (status === 0) {
|
|
|
+ console.log('TTS引擎初始化成功');
|
|
|
+ } else {
|
|
|
+ console.error('TTS引擎初始化失败,状态码:', status)
|
|
|
+ }
|
|
|
+ }, 'com.iflytek.speechcloud')
|
|
|
+ this.TTSSpeech.setPitch(50)
|
|
|
+ this.TTSSpeech.setSpeed(50)
|
|
|
+ //#endif
|
|
|
+ },
|
|
|
mounted() {
|
|
|
this.reconnectionNum = 0
|
|
|
// 每秒更新当前时间
|
|
|
@@ -269,6 +289,54 @@
|
|
|
}
|
|
|
},
|
|
|
methods: {
|
|
|
+ // 将文本添加到队列
|
|
|
+ addToSpeechQueue(textValue) {
|
|
|
+ if (textValue && typeof textValue === 'string') {
|
|
|
+ this.speechQueue.push(textValue);
|
|
|
+ // 如果没有正在播放,则开始播放
|
|
|
+ if (!this.isSpeaking) {
|
|
|
+ this.processSpeechQueue();
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ console.warn('Invalid text value for speech:', textValue);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 处理语音队列
|
|
|
+ async processSpeechQueue() {
|
|
|
+ if (this.speechQueue.length === 0) {
|
|
|
+ this.isSpeaking = false;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.isSpeaking = true;
|
|
|
+ const textToSpeak = this.speechQueue.shift(); // 取出队列第一个元素
|
|
|
+ try {
|
|
|
+ // 等待当前语音播放完成 (通过 onDone 回调)
|
|
|
+ await this.speak(textToSpeak);
|
|
|
+ } catch (error) {
|
|
|
+ console.error('TTS speak error for text:', textToSpeak, error);
|
|
|
+ // 即使当前项播放失败,也继续处理队列中的下一个
|
|
|
+ } finally {
|
|
|
+ this.processSpeechQueue();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 执行实际的语音播放 (返回 Promise)
|
|
|
+ speak(textValue) {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ if (!this.TTSSpeech) {
|
|
|
+ reject(new Error('TTS engine not initialized.'));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 监听 TTS 播放结束事件
|
|
|
+ this.TTSSpeech.onDone(() => {
|
|
|
+ resolve(); // 播放完成,Promise 成功
|
|
|
+ });
|
|
|
+ // 尝试启动语音播放
|
|
|
+ const speakOptions = {
|
|
|
+ text: textValue,
|
|
|
+ };
|
|
|
+ this.TTSSpeech.speak(speakOptions);
|
|
|
+ });
|
|
|
+ },
|
|
|
keyboardheightchange() {
|
|
|
uni.onKeyboardHeightChange(res => {
|
|
|
this.keyboardHeight = res.height
|
|
|
@@ -350,7 +418,6 @@
|
|
|
}
|
|
|
try {
|
|
|
const data = JSON.parse(res.data);
|
|
|
- // console.log('收到消息:', data);
|
|
|
this.handleMessage(data);
|
|
|
} catch (e) {
|
|
|
console.warn('非 JSON 消息,已忽略', res.data);
|
|
|
@@ -617,6 +684,10 @@
|
|
|
case 'delete':
|
|
|
this.batchRemove(data.data);
|
|
|
break;
|
|
|
+ case 'msg':
|
|
|
+ // 使用队列播放语音
|
|
|
+ this.addToSpeechQueue(data.msg)
|
|
|
+ break;
|
|
|
default:
|
|
|
console.warn('未知操作类型:', action);
|
|
|
}
|
|
|
@@ -1128,7 +1199,9 @@
|
|
|
|
|
|
.table-cell {
|
|
|
padding: 24rpx 16rpx;
|
|
|
- font-size: 50rpx;
|
|
|
+ /* font-size: 50rpx; */
|
|
|
+ font-size: 66rpx;
|
|
|
+ font-weight: bold;
|
|
|
text-align: center;
|
|
|
color: #333;
|
|
|
display: flex;
|
|
|
@@ -1139,7 +1212,8 @@
|
|
|
|
|
|
.cell {
|
|
|
padding: 24rpx 16rpx;
|
|
|
- font-size: 50rpx;
|
|
|
+ /* font-size: 50rpx; */
|
|
|
+ font-size: 60rpx;
|
|
|
text-align: center;
|
|
|
color: #333;
|
|
|
}
|
|
|
@@ -1215,25 +1289,25 @@
|
|
|
.status-observing {
|
|
|
background-color: #9dd6ff;
|
|
|
color: #007bff;
|
|
|
- border: 2rpx solid #48a0ff;
|
|
|
+ border: 6rpx solid #007bff;
|
|
|
}
|
|
|
|
|
|
.status-completed {
|
|
|
background-color: #e8f5e8;
|
|
|
color: #28a745;
|
|
|
- border: 2rpx solid #8bc34a;
|
|
|
+ border: 6rpx solid #28a745;
|
|
|
}
|
|
|
|
|
|
.status-warning {
|
|
|
background-color: #ffebee;
|
|
|
color: #ff0000;
|
|
|
- border: 2rpx solid #ef9a9a;
|
|
|
+ border: 6rpx solid #ff0000;
|
|
|
}
|
|
|
|
|
|
.status-hasleft {
|
|
|
background-color: #fff2e8;
|
|
|
color: #fa8c16;
|
|
|
- border: 2rpx solid #ffbb96;
|
|
|
+ border: 6rpx solid #fa8c16;
|
|
|
}
|
|
|
|
|
|
.item-observing {
|
|
|
@@ -1258,11 +1332,10 @@
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
- padding: 8rpx 20rpx;
|
|
|
- border-radius: 32rpx;
|
|
|
- font-size: 48rpx;
|
|
|
- font-weight: 500;
|
|
|
- width: calc(100% - 20rpx);
|
|
|
+ border-radius: 50rpx;
|
|
|
+ font-size: 60rpx;
|
|
|
+ font-weight: bold;
|
|
|
+ width: 80%;
|
|
|
}
|
|
|
|
|
|
.empty-tip {
|