xaznapp声卡
This commit is contained in:
parent
a875eeba11
commit
179dce665a
@ -18,7 +18,7 @@
|
|||||||
</u--form>
|
</u--form>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<button @click="print()">测试打印</button>
|
<!-- <button @click="print()">测试打印</button -->
|
||||||
<!-- 基础信息 -->
|
<!-- 基础信息 -->
|
||||||
<view class="card basic-info">
|
<view class="card basic-info">
|
||||||
<view class="section-title">基础信息</view>
|
<view class="section-title">基础信息</view>
|
||||||
@ -80,7 +80,7 @@
|
|||||||
<!-- 默认音频列表 -->
|
<!-- 默认音频列表 -->
|
||||||
<view class="card default-list">
|
<view class="card default-list">
|
||||||
<view class="section-title">
|
<view class="section-title">
|
||||||
<text>默认列表</text>
|
<text>播放列表</text>
|
||||||
<image src="https://iot-xcwl.cn/doc/photo/add.svg" mode="aspectFit" class="add-icon"
|
<image src="https://iot-xcwl.cn/doc/photo/add.svg" mode="aspectFit" class="add-icon"
|
||||||
@click="showAddDefaultModal"></image>
|
@click="showAddDefaultModal"></image>
|
||||||
</view>
|
</view>
|
||||||
@ -91,11 +91,20 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="audio-item" v-for="(item, index) in defaultList" :key="index">
|
<view class="audio-item" v-for="(item, index) in defaultList" :key="index">
|
||||||
<view class="audio-info">
|
<view class="audio-info">
|
||||||
<u-icon name="star-fill" size="18" color="#ff9900"></u-icon>
|
<u-icon :name="item.status === '启用' ? 'star-fill' : 'star'" size="18"
|
||||||
|
:color="item.status === '启用' ? '#ff9900' : '#c0c4cc'"></u-icon>
|
||||||
|
<view class="audio-details">
|
||||||
<text class="audio-name">{{ item.name }}</text>
|
<text class="audio-name">{{ item.name }}</text>
|
||||||
|
<view class="audio-meta">
|
||||||
|
<text class="time-info">{{ item.playTime }}</text>
|
||||||
|
<text class="week-info">{{ item.weekdays }}</text>
|
||||||
|
<text v-if="item.radarEnabled" class="radar-info">{{ item.radarSpeed }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="audio-actions">
|
<view class="audio-actions">
|
||||||
<text class="audio-duration">{{ item.duration }}</text>
|
<u-switch v-model="item.status" :active-value="'启用'" :inactive-value="'禁用'"
|
||||||
|
@change="(value) => handleStatusChange(index, value)" size="22"></u-switch>
|
||||||
<u-icon name="trash" size="18" color="#ff4d4f" @click="deleteDefault(index)"></u-icon>
|
<u-icon name="trash" size="18" color="#ff4d4f" @click="deleteDefault(index)"></u-icon>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@ -104,7 +113,6 @@
|
|||||||
|
|
||||||
<!-- 远程喊话 -->
|
<!-- 远程喊话 -->
|
||||||
<view class="card remote-talk">
|
<view class="card remote-talk">
|
||||||
<view class="section-title">远程喊话</view>
|
|
||||||
<view class="talk-container">
|
<view class="talk-container">
|
||||||
<view class="talk-tip">按住按钮开始录音,松开结束录音</view>
|
<view class="talk-tip">按住按钮开始录音,松开结束录音</view>
|
||||||
<view class="talk-button" :class="{ recording: isRecording }" @touchstart="startRecording"
|
<view class="talk-button" :class="{ recording: isRecording }" @touchstart="startRecording"
|
||||||
@ -135,21 +143,25 @@
|
|||||||
</u-form-item>
|
</u-form-item>
|
||||||
<u-form-item label="合成语速" prop="spd" borderBottom>
|
<u-form-item label="合成语速" prop="spd" borderBottom>
|
||||||
<view class="slider-with-value">
|
<view class="slider-with-value">
|
||||||
<u-slider v-model="newAudio.spd" :min="0" :max="15" :step="1" :showValue="true" class="custom-slider"></u-slider>
|
<u-slider v-model="newAudio.spd" :min="0" :max="15" :step="1" :showValue="true"
|
||||||
|
class="custom-slider"></u-slider>
|
||||||
</view>
|
</view>
|
||||||
</u-form-item>
|
</u-form-item>
|
||||||
<u-form-item label="合成音调" prop="pit" borderBottom>
|
<u-form-item label="合成音调" prop="pit" borderBottom>
|
||||||
<view class="slider-with-value">
|
<view class="slider-with-value">
|
||||||
<u-slider v-model="newAudio.pit" :min="0" :max="15" :step="1" :showValue="true" class="custom-slider"></u-slider>
|
<u-slider v-model="newAudio.pit" :min="0" :max="15" :step="1" :showValue="true"
|
||||||
|
class="custom-slider"></u-slider>
|
||||||
</view>
|
</view>
|
||||||
</u-form-item>
|
</u-form-item>
|
||||||
<u-form-item label="合成音量" prop="vol" borderBottom>
|
<u-form-item label="合成音量" prop="vol" borderBottom>
|
||||||
<view class="slider-with-value">
|
<view class="slider-with-value">
|
||||||
<u-slider v-model="newAudio.vol" :min="0" :max="15" :step="1" :showValue="true" class="custom-slider"></u-slider>
|
<u-slider v-model="newAudio.vol" :min="0" :max="15" :step="1" :showValue="true"
|
||||||
|
class="custom-slider"></u-slider>
|
||||||
</view>
|
</view>
|
||||||
</u-form-item>
|
</u-form-item>
|
||||||
<u-form-item label="合成文本" prop="text" borderBottom>
|
<u-form-item label="合成文本" prop="text" borderBottom>
|
||||||
<u-input v-model="newAudio.text" type="textarea" placeholder="请输入合成文本" height="100"></u-input>
|
<u-input v-model="newAudio.text" type="textarea" placeholder="请输入合成文本"
|
||||||
|
height="100"></u-input>
|
||||||
</u-form-item>
|
</u-form-item>
|
||||||
</u-form>
|
</u-form>
|
||||||
</view>
|
</view>
|
||||||
@ -163,7 +175,7 @@
|
|||||||
<!-- 添加默认音频弹窗 -->
|
<!-- 添加默认音频弹窗 -->
|
||||||
<u-popup :show="showAddDefault" mode="center" @close="showAddDefault = false" round="8">
|
<u-popup :show="showAddDefault" mode="center" @close="showAddDefault = false" round="8">
|
||||||
<view class="add-audio-modal">
|
<view class="add-audio-modal">
|
||||||
<view class="modal-title">添加默认音频</view>
|
<view class="modal-title">添加播放列表</view>
|
||||||
<view class="modal-content">
|
<view class="modal-content">
|
||||||
<u-form :model="newDefault" ref="defaultForm">
|
<u-form :model="newDefault" ref="defaultForm">
|
||||||
<u-form-item label="开始时间" prop="startTime" borderBottom>
|
<u-form-item label="开始时间" prop="startTime" borderBottom>
|
||||||
@ -757,13 +769,127 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
confirmAddDefault() {
|
async confirmAddDefault() {
|
||||||
if (!this.checkOnline()) return;
|
if (!this.checkOnline()) return;
|
||||||
|
|
||||||
|
// 验证必填项
|
||||||
|
if (!this.newDefault.startTime || !this.newDefault.endTime || !this.newDefault.audioFile) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '默认音频添加成功',
|
title: '请填写完整信息',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证雷达速度范围
|
||||||
|
if (this.newDefault.radarEnabled) {
|
||||||
|
if (!this.newDefault.minSpeed || !this.newDefault.maxSpeed) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '请填写速度范围',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (parseInt(this.newDefault.minSpeed) >= parseInt(this.newDefault.maxSpeed)) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '最小速度必须小于最大速度',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const playListModel = this.deviceInfo.thingsModels.find(model => model.id === 'play_list');
|
||||||
|
if (playListModel) {
|
||||||
|
try {
|
||||||
|
const jsonStr = playListModel.shadow.replace('JSON=', '');
|
||||||
|
const data = JSON.parse(jsonStr);
|
||||||
|
|
||||||
|
// 确保 sound_card 和 play_list 存在
|
||||||
|
if (!data.sound_card) {
|
||||||
|
data.sound_card = {};
|
||||||
|
}
|
||||||
|
if (!data.sound_card.play_list) {
|
||||||
|
data.sound_card.play_list = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前最大的序号
|
||||||
|
let maxNum = 0;
|
||||||
|
if (data.sound_card.play_list.length > 0) {
|
||||||
|
maxNum = Math.max(...data.sound_card.play_list.map(item => item.play.num || 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换时间格式(HH:MM 转为秒数)
|
||||||
|
const [startHour, startMinute] = this.newDefault.startTime.split(':').map(Number);
|
||||||
|
const [endHour, endMinute] = this.newDefault.endTime.split(':').map(Number);
|
||||||
|
const startSeconds = startHour * 3600 + startMinute * 60;
|
||||||
|
const endSeconds = endHour * 3600 + endMinute * 60;
|
||||||
|
|
||||||
|
// 转换星期格式(数组转为数字)
|
||||||
|
let weekValue = 0;
|
||||||
|
this.newDefault.repeatDays.forEach(day => {
|
||||||
|
weekValue |= (1 << day);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 构建新的播放项
|
||||||
|
const newPlayItem = {
|
||||||
|
play: {
|
||||||
|
num: maxNum + 1,
|
||||||
|
filename: this.newDefault.audioFile.name,
|
||||||
|
en: 1
|
||||||
|
},
|
||||||
|
time: {
|
||||||
|
begin: startSeconds,
|
||||||
|
end: endSeconds,
|
||||||
|
week: weekValue
|
||||||
|
},
|
||||||
|
speed: {
|
||||||
|
en: this.newDefault.radarEnabled ? 1 : 0,
|
||||||
|
min: this.newDefault.radarEnabled ? parseInt(this.newDefault.minSpeed) : 0,
|
||||||
|
max: this.newDefault.radarEnabled ? parseInt(this.newDefault.maxSpeed) : 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 添加到播放列表
|
||||||
|
data.sound_card.play_list.push(newPlayItem);
|
||||||
|
|
||||||
|
// 更新物模型shadow值
|
||||||
|
playListModel.shadow = 'JSON=' + JSON.stringify(data);
|
||||||
|
|
||||||
|
// 发送更新
|
||||||
|
try {
|
||||||
|
await this.mqttPublish(this.device, playListModel);
|
||||||
|
uni.showToast({
|
||||||
|
title: '添加成功',
|
||||||
icon: 'success'
|
icon: 'success'
|
||||||
});
|
});
|
||||||
this.showAddDefault = false;
|
this.showAddDefault = false;
|
||||||
|
|
||||||
|
// 重置表单
|
||||||
|
this.newDefault = {
|
||||||
|
startTime: '',
|
||||||
|
endTime: '',
|
||||||
|
repeatDays: [],
|
||||||
|
radarEnabled: false,
|
||||||
|
minSpeed: '',
|
||||||
|
maxSpeed: '',
|
||||||
|
audioFile: null
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('发送添加命令失败:', error);
|
||||||
|
uni.showToast({
|
||||||
|
title: '添加失败',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('解析或更新播放列表失败:', error);
|
||||||
|
uni.showToast({
|
||||||
|
title: '添加失败',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
async deleteAudio(index) {
|
async deleteAudio(index) {
|
||||||
if (!this.checkOnline()) return;
|
if (!this.checkOnline()) return;
|
||||||
@ -777,7 +903,8 @@
|
|||||||
success: async (res) => {
|
success: async (res) => {
|
||||||
if (res.confirm) {
|
if (res.confirm) {
|
||||||
// 获取当前的 mp3_list 模型
|
// 获取当前的 mp3_list 模型
|
||||||
const mp3ListModel = this.deviceInfo.thingsModels.find(model => model.id === 'mp3_list');
|
const mp3ListModel = this.deviceInfo.thingsModels.find(model => model
|
||||||
|
.id === 'mp3_list');
|
||||||
if (mp3ListModel && mp3ListModel.shadow) {
|
if (mp3ListModel && mp3ListModel.shadow) {
|
||||||
try {
|
try {
|
||||||
// 解析当前的 JSON 数据
|
// 解析当前的 JSON 数据
|
||||||
@ -824,12 +951,53 @@
|
|||||||
deleteDefault(index) {
|
deleteDefault(index) {
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
title: '提示',
|
title: '提示',
|
||||||
content: '确定要删除该默认音频吗?',
|
content: '确认删除该播放项吗?',
|
||||||
cancelText: '取消',
|
cancelText: '取消',
|
||||||
confirmText: '确定',
|
confirmText: '确定',
|
||||||
success: (res) => {
|
success: async (res) => {
|
||||||
if (res.confirm) {
|
if (res.confirm) {
|
||||||
this.defaultList.splice(index, 1);
|
const playListModel = this.deviceInfo.thingsModels.find(model => model.id ===
|
||||||
|
'play_list');
|
||||||
|
if (playListModel) {
|
||||||
|
try {
|
||||||
|
const jsonStr = playListModel.shadow.replace('JSON=', '');
|
||||||
|
const data = JSON.parse(jsonStr);
|
||||||
|
|
||||||
|
if (data.sound_card && data.sound_card.play_list) {
|
||||||
|
// 删除对应的播放项
|
||||||
|
data.sound_card.play_list.splice(index, 1);
|
||||||
|
|
||||||
|
// 更新序号
|
||||||
|
data.sound_card.play_list.forEach((item, index) => {
|
||||||
|
item.play.num = index + 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 更新物模型shadow值
|
||||||
|
playListModel.shadow = 'JSON=' + JSON.stringify(data);
|
||||||
|
|
||||||
|
// 发送更新
|
||||||
|
try {
|
||||||
|
await this.mqttPublish(this.device, playListModel);
|
||||||
|
uni.showToast({
|
||||||
|
title: '删除成功',
|
||||||
|
icon: 'success'
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('发送删除命令失败:', error);
|
||||||
|
uni.showToast({
|
||||||
|
title: '删除失败',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('解析或更新播放列表失败:', error);
|
||||||
|
uni.showToast({
|
||||||
|
title: '删除失败',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -960,6 +1128,99 @@
|
|||||||
} else {
|
} else {
|
||||||
console.log('no mp3ListModel or shadow is empty');
|
console.log('no mp3ListModel or shadow is empty');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 更新播放列表
|
||||||
|
const playListModel = this.deviceInfo.thingsModels.find(model => model.id === 'play_list');
|
||||||
|
if (playListModel && playListModel.shadow) {
|
||||||
|
try {
|
||||||
|
const jsonStr = playListModel.shadow.replace('JSON=', '');
|
||||||
|
const data = JSON.parse(jsonStr);
|
||||||
|
|
||||||
|
if (data.sound_card && data.sound_card.play_list) {
|
||||||
|
this.defaultList = data.sound_card.play_list.map((item, index) => {
|
||||||
|
// 转换时间格式
|
||||||
|
const beginTime = this.formatSecondsToTime(item.time.begin);
|
||||||
|
const endTime = this.formatSecondsToTime(item.time.end);
|
||||||
|
|
||||||
|
// 转换星期格式
|
||||||
|
const weekdays = this.convertWeekToArray(item.time.week);
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: index + 1,
|
||||||
|
name: item.play.filename,
|
||||||
|
playTime: `${beginTime} - ${endTime}`,
|
||||||
|
weekdays: weekdays.join(', '),
|
||||||
|
radarEnabled: item.speed.en === 1,
|
||||||
|
status: item.play.en === 1 ? '启用' : '禁用',
|
||||||
|
radarSpeed: item.speed.en === 1 ? `${item.speed.min}-${item.speed.max}km/h` :
|
||||||
|
''
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('解析播放列表失败:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 将秒数转换为时间格式 (HH:MM)
|
||||||
|
formatSecondsToTime(seconds) {
|
||||||
|
const hours = Math.floor(seconds / 3600);
|
||||||
|
const minutes = Math.floor((seconds % 3600) / 60);
|
||||||
|
return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`;
|
||||||
|
},
|
||||||
|
|
||||||
|
// 将星期数字转换为数组
|
||||||
|
convertWeekToArray(week) {
|
||||||
|
const weekdays = [];
|
||||||
|
for (let i = 0; i < 7; i++) {
|
||||||
|
if (week & (1 << i)) {
|
||||||
|
weekdays.push(this.weekDays[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return weekdays;
|
||||||
|
},
|
||||||
|
async handleStatusChange(index, value) {
|
||||||
|
const playListModel = this.deviceInfo.thingsModels.find(model => model.id === 'play_list');
|
||||||
|
if (playListModel) {
|
||||||
|
try {
|
||||||
|
const jsonStr = playListModel.shadow.replace('JSON=', '');
|
||||||
|
const data = JSON.parse(jsonStr);
|
||||||
|
|
||||||
|
if (data.sound_card && data.sound_card.play_list) {
|
||||||
|
// 更新播放项的启用状态
|
||||||
|
data.sound_card.play_list[index].play.en = value === '启用' ? 1 : 0;
|
||||||
|
|
||||||
|
// 更新物模型shadow值
|
||||||
|
playListModel.shadow = 'JSON=' + JSON.stringify(data);
|
||||||
|
|
||||||
|
// 发送更新
|
||||||
|
try {
|
||||||
|
await this.mqttPublish(this.device, playListModel);
|
||||||
|
uni.showToast({
|
||||||
|
title: '更新成功',
|
||||||
|
icon: 'success'
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('发送状态更新命令失败:', error);
|
||||||
|
uni.showToast({
|
||||||
|
title: '更新失败',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
// 恢复原状态
|
||||||
|
this.defaultList[index].status = value === '启用' ? '禁用' : '启用';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('解析或更新播放列表失败:', error);
|
||||||
|
uni.showToast({
|
||||||
|
title: '更新失败',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
// 恢复原状态
|
||||||
|
this.defaultList[index].status = value === '启用' ? '禁用' : '启用';
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -1129,17 +1390,37 @@
|
|||||||
|
|
||||||
.audio-info {
|
.audio-info {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: flex-start;
|
||||||
gap: 16rpx;
|
gap: 16rpx;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
|
.audio-details {
|
||||||
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
.audio-name {
|
.audio-name {
|
||||||
font-size: 26rpx;
|
font-size: 26rpx;
|
||||||
color: #333;
|
color: #333;
|
||||||
overflow: hidden;
|
margin-bottom: 8rpx;
|
||||||
text-overflow: ellipsis;
|
display: block;
|
||||||
white-space: nowrap;
|
}
|
||||||
|
|
||||||
|
.audio-meta {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 12rpx;
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: #666;
|
||||||
|
|
||||||
|
.time-info,
|
||||||
|
.week-info,
|
||||||
|
.radar-info {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
padding: 4rpx 12rpx;
|
||||||
|
border-radius: 4rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1148,13 +1429,6 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 24rpx;
|
gap: 24rpx;
|
||||||
margin-left: 16rpx;
|
margin-left: 16rpx;
|
||||||
|
|
||||||
.audio-duration {
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #999;
|
|
||||||
min-width: 72rpx;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user