diff --git a/pagesA/home/device/status/voice.vue b/pagesA/home/device/status/voice.vue index 7bf1294..9aee408 100644 --- a/pagesA/home/device/status/voice.vue +++ b/pagesA/home/device/status/voice.vue @@ -114,12 +114,65 @@ - 按住按钮开始录音,松开结束录音 - - - {{ isRecording ? '录音中...' : '按住说话' }} + + + + + + {{ recordingStatus }} + + + + + {{ formatTime(recordingTime) }} + + + + + + + {{ isRecording ? '录音中...' : '按住说话' }} + + + + + + 按住按钮开始录音,松开自动结束并上传 + + + + + 录音预览 + + + + + 重新上传 + + + 重新录制 + + + + + + + + 最近录音 + + + + {{ recording.name }} + {{ recording.time }} + + + + @@ -243,26 +296,19 @@ } }, watch: { - // 兼容小程序 device: function(newVal, oldVal) { if (newVal.deviceName !== '') { this.deviceInfo = newVal; if (this.deviceInfo.deviceType != 3) { - //分-属性和操作 this.operateList = this.deviceInfo.thingsModels && this.deviceInfo.thingsModels.filter(( - item) => - item.isReadonly == '0'); + item) => item.isReadonly == '0'); this.attributeList = this.deviceInfo.thingsModels && this.deviceInfo.thingsModels.filter(( - item) => - item.isReadonly == '1'); - //排序 + item) => item.isReadonly == '1'); this.attributeList = this.attributeList.sort((a, b) => b.order - a.order); this.operateList = this.operateList.sort((a, b) => b.order - a.order); } this.updateDeviceStatus(this.deviceInfo); this.updateBasicSettings(); - - console.log("wumoxing", JSON.stringify(this.deviceInfo.thingsModels)) } } }, @@ -273,7 +319,14 @@ audioEnabled: true, isRecording: false, recorderManager: null, + recordingTime: 0, + recordingTimer: null, tempFilePath: '', + hasRecording: false, + audioUrl: '', + uploadFailed: false, + recordings: [], + recordingStatus: '准备录音', showAddAudio: false, showAddDefault: false, showStartTimePicker: false, @@ -303,47 +356,30 @@ audioFile: null }, audioFiles: [], - audioList: [{ - name: '欢迎语.mp3', - duration: '00:15' - }, - { - name: '提示音.mp3', - duration: '00:05' - }, - { - name: '背景音乐.mp3', - duration: '03:45' - } - ], - defaultList: [{ - name: '默认欢迎语.mp3', - duration: '00:10' - }, - { - name: '默认提示音.mp3', - duration: '00:03' - } - ] + audioList: [], + defaultList: [], + audioUrl: '', + uploadFailed: false }; }, created() { if (this.device !== null && Object.keys(this.device).length !== 0) { this.deviceInfo = this.device; this.updateDeviceStatus(this.deviceInfo); - // this.initChart(); - // console.log("deviceinfo", JSON.stringify(this.deviceInfo)) }; this.mqttCallback(); this.recorderManager = uni.getRecorderManager(); this.initRecorder(); this.updateBasicSettings(); - // this.print(); - + }, + beforeDestroy() { + if (this.recordingTimer) { + clearInterval(this.recordingTimer); + this.recordingTimer = null; + } }, methods: { print() { - console.log("测试打印", JSON.stringify(this.deviceInfo.thingsModels)) }, checkOnline(callback, ...args) { @@ -359,6 +395,97 @@ } return true; }, + async uploadRecording() { + if (!this.tempFilePath) return; + + try { + this.recordingStatus = '上传中...'; + + // 在 uni-app 中直接使用 uni.uploadFile,不需要 FormData + const uploadUrl = 'https://iot-xcwl.cn/common/upload/audio'; + const token = + 'Bearer eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6ImU3MWM2OTg4LTNlMzMtNDYyMy05M2M3LWE4YzZmMTNlMjZkZSJ9.wgsL8b3WDmyuesG8JTA3LcNFp2FigkB90h6Inwxt7OFadH6rc5np5TjAyU1pzU2_b5cmG8BYXMEdAqEdJzoDcA'; + + // 使用 uni.uploadFile 上传录音文件 + const [error, res] = await new Promise((resolve) => { + uni.uploadFile({ + url: uploadUrl, + filePath: this.tempFilePath, + name: 'file', + header: { + 'Authorization': token + }, + success: (res) => resolve([null, res]), + fail: (err) => resolve([err, null]) + }); + }); + + if (error) throw error; + + if (res.statusCode === 200) { + const result = typeof res.data === 'string' ? JSON.parse(res.data) : res.data; + if (result.code === 200) { + this.recordingStatus = '上传成功'; + this.uploadFailed = false; + + uni.showToast({ + title: '上传成功', + icon: 'success' + }); + + // 提取返回的 URL 并通过 MQTT 下发到 103#onlinePlay + if (result.url || result.resourcePath) { + const onlinePlayModel = this.deviceInfo.thingsModels?.find(model => model.id === + '103#onlinePlay'); + if (onlinePlayModel) { + // 构建包含 interrupt 参数的 JSON 数据 + const playData = 'JSON=' + JSON.stringify({ + online_play: { + url: "http://1.94.62.14:8080" + (result.resourcePath || result + .url), + }, + interrupt: 98 + }); + onlinePlayModel.shadow = playData; + await this.mqttPublish(this.deviceInfo, onlinePlayModel); + uni.showToast({ + title: '音频已下发到设备', + icon: 'success' + }); + } else { + uni.showToast({ + title: '未找到 103#onlinePlay 物模型', + icon: 'none' + }); + } + } + } else { + throw new Error(result.msg || '上传失败'); + } + } else { + throw new Error('上传失败,状态码: ' + res.statusCode); + } + } catch (error) { + console.error('上传失败:', error); + this.recordingStatus = '上传失败'; + this.uploadFailed = true; + + let errorMsg = '上传失败'; + if (error.message && error.message.includes('Mixed Content')) { + errorMsg = '由于安全策略,无法在 HTTPS 页面访问 HTTP 接口。请联系管理员配置接口支持 HTTPS。'; + } + + uni.showToast({ + title: errorMsg || error.message || '上传失败', + icon: 'none' + }); + } + }, + reRecord() { + this.hasRecording = false; + this.uploadFailed = false; + this.recordingStatus = '准备录音'; + }, async volumeChange(value) { if (!this.checkOnline()) return; try { @@ -375,7 +502,6 @@ }); } }, - /* Mqtt回调处理 */ mqttCallback() { this.$mqttTool.client.on('message', (topic, message, buffer) => { let topics = topic.split('/'); @@ -383,78 +509,50 @@ let deviceNum = topics[2]; message = JSON.parse(message.toString()); if (topics[3] == 'status') { - console.log('接收到【设备状态-运行】主题:', topic); - console.log('接收到【设备状态-运行】内容:', message); - // 更新列表中设备的状态 if (this.deviceInfo.serialNumber == deviceNum) { this.deviceInfo.status = message.status; this.deviceInfo.isShadow = message.isShadow; this.deviceInfo.rssi = message.rssi; this.updateDeviceStatus(this.deviceInfo); this.updateBasicSettings(); - console.log("wumoxing", JSON.stringify(this.deviceInfo.thingsModels)) } } - //兼容设备回复 if (topics[4] == 'reply') { uni.showToast({ icon: 'none', title: message, }) } - if (topics[3] == 'property' || topics[3] == 'function' || topic.endsWith( - 'ws/service')) { - console.log('接收到【物模型】主题:', topic); - console.log('接收到【物模型】内容:', message); - // 更新列表中设备的属性 + if (topics[3] == 'property' || topics[3] == 'function' || topic.endsWith('ws/service')) { if (this.deviceInfo.serialNumber == deviceNum) { for (let j = 0; j < message.message.length; j++) { let isComplete = false; - // 设备状态 - for (let k = 0; k < this.deviceInfo.thingsModels.length && ! - isComplete; k++) { + for (let k = 0; k < this.deviceInfo.thingsModels.length && !isComplete; k++) { if (this.deviceInfo.thingsModels[k].id == message.message[j].id) { - // 普通类型 this.deviceInfo.thingsModels[k].shadow = message.message[j].value; - if (message.message[j].id === 'mp3_list') { - console.log('收到mp3_list更新:', message.message[j].value); - } isComplete = true; break; - } else if (this.deviceInfo.thingsModels[k].datatype.type == - "object") { - // 对象类型 - for (let n = 0; n < this.deviceInfo.thingsModels[k] - .datatype.params + } else if (this.deviceInfo.thingsModels[k].datatype.type == "object") { + for (let n = 0; n < this.deviceInfo.thingsModels[k].datatype.params .length; n++) { - if (this.deviceInfo.thingsModels[k].datatype.params[n] - .id == message.message[j] - .id) { - this.deviceInfo.thingsModels[k].datatype.params[n] - .shadow = - message.message[j].value; + if (this.deviceInfo.thingsModels[k].datatype.params[n].id == message + .message[j].id) { + this.deviceInfo.thingsModels[k].datatype.params[n].shadow = message + .message[j].value; isComplete = true; break; } } - } else if (this.deviceInfo.thingsModels[k].datatype.type == - "array") { - // 数组类型 - if (this.deviceInfo.thingsModels[k].datatype.arrayType == - "object") { - // 1.对象类型数组,id为数组中一个元素,例如:array_01_gateway_temperature + } else if (this.deviceInfo.thingsModels[k].datatype.type == "array") { + if (this.deviceInfo.thingsModels[k].datatype.arrayType == "object") { if (String(message.message[j].id).indexOf("array_") == 0) { - for (let n = 0; n < this.deviceInfo.thingsModels[k] - .datatype + for (let n = 0; n < this.deviceInfo.thingsModels[k].datatype .arrayParams.length; n++) { - for (let m = 0; m < this.deviceInfo - .thingsModels[k].datatype + for (let m = 0; m < this.deviceInfo.thingsModels[k].datatype .arrayParams[n].length; m++) { - if (this.deviceInfo.thingsModels[k] - .datatype.arrayParams[n] + if (this.deviceInfo.thingsModels[k].datatype.arrayParams[n] [m].id == message.message[j].id) { - this.deviceInfo.thingsModels[k] - .datatype.arrayParams[n] + this.deviceInfo.thingsModels[k].datatype.arrayParams[n] [m].shadow = message.message[j].value; isComplete = true; break; @@ -465,20 +563,15 @@ } } } else { - // 2.对象类型数组,例如:gateway_temperature,消息ID添加前缀后匹配 - for (let n = 0; n < this.deviceInfo.thingsModels[k] - .datatype + for (let n = 0; n < this.deviceInfo.thingsModels[k].datatype .arrayParams.length; n++) { - for (let m = 0; m < this.deviceInfo - .thingsModels[k].datatype + for (let m = 0; m < this.deviceInfo.thingsModels[k].datatype .arrayParams[n].length; m++) { let index = n > 9 ? String(n) : '0' + k; let prefix = 'array_' + index + '_'; - if (this.deviceInfo.thingsModels[k] - .datatype.arrayParams[n] + if (this.deviceInfo.thingsModels[k].datatype.arrayParams[n] [m].id == prefix + message.message[j].id) { - this.deviceInfo.thingsModels[k] - .datatype.arrayParams[n] + this.deviceInfo.thingsModels[k].datatype.arrayParams[n] [m].shadow = message.message[j].value; isComplete = true; } @@ -489,15 +582,11 @@ } } } else { - // 整数、小数和字符串类型数组 - for (let n = 0; n < this.deviceInfo.thingsModels[k] - .datatype.arrayModel + for (let n = 0; n < this.deviceInfo.thingsModels[k].datatype.arrayModel .length; n++) { - if (this.deviceInfo.thingsModels[k].datatype - .arrayModel[n].id == + if (this.deviceInfo.thingsModels[k].datatype.arrayModel[n].id == message.message[j].id) { - this.deviceInfo.thingsModels[k].datatype - .arrayModel[n].shadow = + this.deviceInfo.thingsModels[k].datatype.arrayModel[n].shadow = message.message[j].value; isComplete = true; break; @@ -506,63 +595,16 @@ } } }; - // 监测数据 - for (let k = 0; k < this.deviceInfo.chartList.length && ! - isComplete; k++) { + for (let k = 0; k < this.deviceInfo.chartList.length && !isComplete; k++) { if (this.deviceInfo.chartList[k].id.indexOf("array_") == 0) { - // 数组类型匹配,例如:array_00_gateway_temperature if (this.deviceInfo.chartList[k].id == message.message[j].id) { - // let shadows = message[j].value.split(","); this.deviceInfo.chartList[k].shadow = message.message[j].value; - // 更新图表 - for (let m = 0; m < this.monitorChart.length; m++) { - if (this.deviceInfo.chartList[k].id == this - .monitorChart[m].id) { - // uchart中data取值范围0-1,需要最小数+监测值,然后除于区间值 - let value = (Number(message.message[j].value) + Math - .abs(this - .deviceInfo.chartList[k].datatype - .min)) / (Math.abs( - this.deviceInfo.chartList[k] - .datatype.min) + Math - .abs(this.deviceInfo.chartList[k] - .datatype.max)); - this.monitorChart[m].data.series[0].data = - value; - this.monitorChart[m].opts.title.name = message.message[ - j].value + ' ' + - this.deviceInfo.chartList[k].datatype.unit; - break; - } - } isComplete = true; break; } } else { - // 普通类型匹配 if (this.deviceInfo.chartList[k].id == message.message[j].id) { this.deviceInfo.chartList[k].shadow = message.message[j].value; - // 更新图表 - for (let m = 0; m < this.monitorChart.length; m++) { - if (this.deviceInfo.chartList[k].id == this - .monitorChart[m].id) { - // uchart中data取值范围0-1,需要最小数+监测值,然后除于区间值 - let value = (Number(message.message[j].value) + Math - .abs(this - .deviceInfo.chartList[k].datatype - .min)) / (Math.abs( - this.deviceInfo.chartList[k] - .datatype.min) + Math - .abs(this.deviceInfo.chartList[k] - .datatype.max)); - this.monitorChart[m].data.series[0].data = - value; - this.monitorChart[m].opts.title.name = message.message[ - j].value + ' ' + - this.deviceInfo.chartList[k].datatype.unit; - break; - } - } isComplete = true; break; } @@ -606,90 +648,87 @@ } }, initRecorder() { - this.recorderManager.onStart(() => console.log('录音开始')); - this.recorderManager.onStop(res => { - console.log('录音结束', res); - this.tempFilePath = res.tempFilePath; - this.uploadAudio(res.tempFilePath); + if (!this.recorderManager) return; + this.recorderManager.onStart(() => { + this.recordingStatus = '正在录音...'; }); - this.recorderManager.onError(res => { - console.error('录音错误', res); - uni.showToast({ - title: '录音失败', - icon: 'none' + this.recorderManager.onStop((res) => { + this.tempFilePath = res.tempFilePath; + this.audioUrl = res.tempFilePath; + this.hasRecording = true; + this.recordingStatus = '录音完成,正在上传...'; + this.recordings.unshift({ + name: `录音_${this.formatTime(res.duration ? Math.floor(res.duration/1000) : this.recordingTime)}`, + time: new Date().toLocaleString(), + path: res.tempFilePath, + duration: res.duration ? Math.floor(res.duration / 1000) : this.recordingTime }); + this.uploadRecording(); + }); + this.recorderManager.onError((res) => { + this.isRecording = false; + this.recordingStatus = '录音失败'; + uni.showToast({ + title: res.errMsg || '录音失败', + icon: 'none', + }); + if (this.recordingTimer) { + clearInterval(this.recordingTimer); + this.recordingTimer = null; + } }); }, startRecording() { - if (!this.checkOnline()) return; - this.isRecording = true; - this.recorderManager.start({ - format: 'mp3', - duration: 60000, - sampleRate: 16000, - numberOfChannels: 1, - encodeBitRate: 48000, - frameSize: 1 - }); + if (!this.checkOnline() || !this.recorderManager) return; + try { + this.isRecording = true; + this.recordingStatus = '正在录音...'; + this.recordingTime = 0; + this.recordingTimer = setInterval(() => { + this.recordingTime++; + }, 1000); + this.recorderManager.start({ + duration: 60000, + sampleRate: 16000, + numberOfChannels: 1, + encodeBitRate: 48000, + format: 'mp3', + frameSize: 1, + }); + } catch (e) { + this.isRecording = false; + this.recordingStatus = '录音启动失败'; + uni.showToast({ + title: '录音启动失败,请检查权限', + icon: 'none', + }); + } }, stopRecording() { - if (!this.isRecording) return; + if (!this.isRecording || !this.recorderManager) return; this.isRecording = false; + this.recordingStatus = '录音完成,正在上传...'; + if (this.recordingTimer) { + clearInterval(this.recordingTimer); + this.recordingTimer = null; + } this.recorderManager.stop(); }, cancelRecording() { - if (!this.isRecording) return; + if (!this.isRecording || !this.recorderManager) return; this.isRecording = false; + this.recordingStatus = '准备录音'; + if (this.recordingTimer) { + clearInterval(this.recordingTimer); + this.recordingTimer = null; + } + this.recordingTime = 0; this.recorderManager.stop(); uni.showToast({ title: '已取消录音', - icon: 'none' + icon: 'none', }); }, - async uploadAudio(filePath) { - try { - uni.showLoading({ - title: '正在上传...' - }); - const uploadRes = await uni.uploadFile({ - url: 'YOUR_UPLOAD_API_URL', - filePath: filePath, - name: 'file', - formData: { - deviceId: this.device.deviceId - } - }); - if (uploadRes.statusCode === 200) { - const result = JSON.parse(uploadRes.data); - const audioListModel = this.device.thingsModels.find(item => item.id === 'audio_list'); - if (audioListModel) { - audioListModel.shadow = JSON.stringify({ - ...JSON.parse(audioListModel.shadow || '{}'), - files: [...(JSON.parse(audioListModel.shadow || '{}').files || []), { - name: result.fileName, - url: result.fileUrl, - duration: result.duration - }] - }); - await this.mqttPublish(this.device, audioListModel); - } - uni.showToast({ - title: '上传成功', - icon: 'success' - }); - } else { - throw new Error('上传失败'); - } - } catch (error) { - console.error('上传音频失败:', error); - uni.showToast({ - title: '上传失败: ' + error.message, - icon: 'none' - }); - } finally { - uni.hideLoading(); - } - }, showAddAudioModal() { this.showAddAudio = true; }, @@ -700,17 +739,14 @@ if (!this.checkOnline()) return; try { - // 获取当前的 mp3_list 模型 const mp3ListModel = this.deviceInfo.thingsModels.find(model => model.id === '103#mp3List'); if (!mp3ListModel) { throw new Error('未找到 mp3_list 模型'); } - // 解析当前的 mp3_list 数据 const jsonStr = mp3ListModel.shadow.replace('JSON=', ''); const data = JSON.parse(jsonStr); - // 获取当前最大的 id let maxId = 0; if (data.sound_card && data.sound_card.mp3_list) { data.sound_card.mp3_list.forEach(item => { @@ -721,10 +757,8 @@ }); } - // 生成新的 id const newId = maxId + 1; - // 构建 TTS 请求数据 const ttsData = { JSON_id: 1, sound_card: { @@ -739,11 +773,9 @@ } }; - // 更新 shadow 值并发送 mp3ListModel.shadow = 'JSON=' + JSON.stringify(ttsData); await this.mqttPublish(this.device, mp3ListModel); - // 重置表单 this.newAudio = { name: '', per: '0', @@ -754,7 +786,6 @@ file: null }; - // 关闭弹窗 this.showAddAudio = false; uni.showToast({ @@ -772,7 +803,6 @@ async confirmAddDefault() { if (!this.checkOnline()) return; - // 验证必填项 if (!this.newDefault.startTime || !this.newDefault.endTime || !this.newDefault.audioFile) { uni.showToast({ title: '请填写完整信息', @@ -781,7 +811,6 @@ return; } - // 验证雷达速度范围 if (this.newDefault.radarEnabled) { if (!this.newDefault.minSpeed || !this.newDefault.maxSpeed) { uni.showToast({ @@ -805,7 +834,6 @@ const jsonStr = playListModel.shadow.replace('JSON=', ''); const data = JSON.parse(jsonStr); - // 确保 sound_card 和 play_list 存在 if (!data.sound_card) { data.sound_card = {}; } @@ -813,25 +841,21 @@ 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, @@ -850,13 +874,10 @@ } }; - // 添加到播放列表 data.sound_card.play_list.push(newPlayItem); - // 更新物模型shadow值 playListModel.shadow = 'JSON=' + JSON.stringify(data); - // 发送更新 try { await this.mqttPublish(this.device, playListModel); uni.showToast({ @@ -865,7 +886,6 @@ }); this.showAddDefault = false; - // 重置表单 this.newDefault = { startTime: '', endTime: '', @@ -902,26 +922,20 @@ confirmText: '确定', success: async (res) => { if (res.confirm) { - // 获取当前的 mp3_list 模型 const mp3ListModel = this.deviceInfo.thingsModels.find(model => model - .id === 'mp3_list'); + .id === '103#mp3List'); if (mp3ListModel && mp3ListModel.shadow) { try { - // 解析当前的 JSON 数据 const jsonStr = mp3ListModel.shadow.replace('JSON=', ''); const data = JSON.parse(jsonStr); - // 从音频列表中删除指定索引的项 if (data.sound_card && data.sound_card.mp3_list) { data.sound_card.mp3_list.splice(index, 1); - // 更新 shadow 值 mp3ListModel.shadow = 'JSON=' + JSON.stringify(data); - // 发送更新到设备 await this.mqttPublish(this.device, mp3ListModel); - // 更新本地音频列表 this.audioList.splice(index, 1); uni.showToast({ @@ -964,18 +978,14 @@ 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({ @@ -1044,11 +1054,10 @@ }); } }, - formatTime(timestamp) { - const date = new Date(timestamp); - const hours = date.getHours().toString().padStart(2, '0'); - const minutes = date.getMinutes().toString().padStart(2, '0'); - return `${hours}:${minutes}`; + formatTime(seconds) { + const minutes = Math.floor(seconds / 60); + const remainingSeconds = seconds % 60; + return `${minutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}`; }, startTimeChange(e) { this.newDefault.startTime = e.detail.value; @@ -1078,58 +1087,36 @@ updateBasicSettings() { if (!this.deviceInfo.thingsModels) return; - // 更新音频开关状态 const playEnModel = this.deviceInfo.thingsModels.find(model => model.id === '103#playEn'); if (playEnModel) { this.audioEnabled = playEnModel.shadow === '1'; } - // 更新音量设置 const volumeModel = this.deviceInfo.thingsModels.find(model => model.id === '103#volume'); if (volumeModel) { this.volume = parseInt(volumeModel.shadow) || 50; } - // 更新音频列表 - const mp3ListModel = this.deviceInfo.thingsModels.find(model => model.id === '103#mp3_list'); - console.log('mp3ListModel:', mp3ListModel); - + const mp3ListModel = this.deviceInfo.thingsModels.find(model => model.id === '103#mp3List'); if (mp3ListModel && mp3ListModel.shadow) { try { - // 解析 JSON 字符串 const jsonStr = mp3ListModel.shadow.replace('JSON=', ''); - console.log('jsonStr:', jsonStr); - const data = JSON.parse(jsonStr); - console.log('parsed data:', data); - // 获取 mp3_list 数组 if (data && data.mp3_list) { - console.log('mp3_list:', data.mp3_list); - - // 更新音频列表 this.audioList = data.mp3_list.map((item, index) => { - // 从 "1_def" 格式中提取名称 const name = item.split('_')[1] || item; - console.log('item:', item, 'name:', name); return { id: index + 1, name: name }; }); - console.log('updated audioList:', this.audioList); - } else { - console.log('no mp3_list found in data'); } } catch (error) { console.error('解析音频列表失败:', error); - console.error('原始数据:', mp3ListModel.shadow); } - } else { - console.log('no mp3ListModel or shadow is empty'); } - // 更新播放列表 const playListModel = this.deviceInfo.thingsModels.find(model => model.id === '103#playList'); if (playListModel && playListModel.shadow) { try { @@ -1138,11 +1125,8 @@ if (data && data.play_list) { this.defaultList = data.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 { @@ -1162,15 +1146,11 @@ } } }, - - // 将秒数转换为时间格式 (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++) { @@ -1188,13 +1168,10 @@ 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({ @@ -1207,7 +1184,6 @@ title: '更新失败', icon: 'none' }); - // 恢复原状态 this.defaultList[index].status = value === '启用' ? '禁用' : '启用'; } } @@ -1217,10 +1193,26 @@ title: '更新失败', icon: 'none' }); - // 恢复原状态 this.defaultList[index].status = value === '启用' ? '禁用' : '启用'; } } + }, + deleteRecording(index) { + uni.showModal({ + title: '提示', + content: '确定要删除该录音吗?', + cancelText: '取消', + confirmText: '确定', + success: (res) => { + if (res.confirm) { + this.recordings.splice(index, 1); + uni.showToast({ + title: '删除成功', + icon: 'success' + }); + } + } + }); } }, computed: { @@ -1441,34 +1433,181 @@ align-items: center; gap: 20rpx; - .talk-tip { - font-size: 26rpx; - color: #999; - text-align: center; - } - - .talk-button { - width: 120rpx; - height: 120rpx; - border-radius: 50%; - background-color: #f0f6ff; + .recorder-status { display: flex; flex-direction: column; align-items: center; - justify-content: center; - gap: 10rpx; - transition: all 0.3s ease; + margin-bottom: 20rpx; - &.recording { - background-color: #fff1f0; - transform: scale(1.05); + .status-indicator { + width: 60rpx; + height: 60rpx; + border-radius: 50%; + background: #f4f4f5; + display: flex; + align-items: center; + justify-content: center; + margin-bottom: 10rpx; + transition: all 0.3s; + + &.recording { + background: #fef0f0; + animation: pulse 1.5s infinite; + } } - text { - font-size: 24rpx; - color: #666; + .status-text { + font-size: 26rpx; + color: #606266; } } + + .timer-display { + font-size: 48rpx; + font-weight: bold; + color: #303133; + margin-bottom: 20rpx; + } + + .control-buttons { + display: flex; + justify-content: center; + gap: 20rpx; + margin-bottom: 20rpx; + + .talk-button { + width: 120rpx; + height: 120rpx; + border-radius: 50%; + background-color: #f0f6ff; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 10rpx; + transition: all 0.3s ease; + border: 2rpx solid #e1e8ff; + box-shadow: 0 4rpx 12rpx rgba(41, 121, 255, 0.2); + + &.recording { + background-color: #fff1f0; + border-color: #ff4d4f; + transform: scale(1.05); + box-shadow: 0 6rpx 16rpx rgba(245, 77, 79, 0.3); + } + + &:active { + transform: scale(0.95); + } + + text { + font-size: 24rpx; + color: #666; + font-weight: 500; + } + } + } + + .recording-tips { + margin-top: 20rpx; + padding: 24rpx; + background: #f8f9fa; + border-radius: 16rpx; + width: 100%; + + .tip-text { + font-size: 28rpx; + color: #606266; + text-align: center; + } + } + + .recording-preview { + margin-top: 20rpx; + padding: 24rpx; + background: #f8f9fa; + border-radius: 16rpx; + width: 100%; + + .preview-title { + font-size: 28rpx; + color: #606266; + margin-bottom: 20rpx; + text-align: left; + } + + .audio-player { + display: flex; + flex-direction: column; + align-items: center; + gap: 20rpx; + + audio { + width: 100%; + height: 80rpx; + } + + .preview-controls { + display: flex; + justify-content: center; + margin-top: 10rpx; + } + } + } + + .recording-list { + text-align: left; + border-top: 1rpx solid #ebeef5; + padding-top: 20rpx; + width: 100%; + + .list-title { + font-size: 28rpx; + color: #606266; + margin-bottom: 20rpx; + } + + .recording-item { + display: flex; + align-items: center; + padding: 16rpx 0; + border-bottom: 1rpx solid #ebeef5; + + .recording-info { + flex: 1; + display: flex; + flex-direction: column; + gap: 8rpx; + + .recording-name { + font-size: 26rpx; + color: #303133; + } + + .recording-time { + font-size: 22rpx; + color: #909399; + } + } + } + } + } + } + + @keyframes pulse { + 0% { + transform: scale(1); + box-shadow: 0 0 0 0 rgba(245, 108, 108, 0.4); + } + + 70% { + transform: scale(1.1); + box-shadow: 0 0 0 10rpx rgba(245, 108, 108, 0); + } + + 100% { + transform: scale(1); + box-shadow: 0 0 0 0 rgba(245, 108, 108, 0); } } @@ -1599,5 +1738,11 @@ background-color: #f9f9f9; border-radius: 8rpx; } + + .mic-img { + width: 56rpx; + height: 56rpx; + margin-bottom: 8rpx; + } } \ No newline at end of file