<template>
	<view class="voice-control">
		<!-- 设备状态卡片 -->
		<view class="card">
			<view class="status-titletop">{{ title }}</view>
			<view style="padding:20rpx;">
				<u--form labelPosition="left" labelWidth="100"
					:labelStyle="{ marginRight: '16px', lineHeight: '32px', width: '50px', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', color: '#000000' }">
					<view class="version-wrap">
						<u-form-item :label="$tt('status.deviceVersion')">
							<u-row>
								<u-col span="8">
									<u--text :text="'Version ' + device.firmwareVersion"></u--text>
								</u-col>
							</u-row>
						</u-form-item>
					</view>
				</u--form>
			</view>
		</view>
		<!-- 		<button @click="print()">测试打印</button -->
		<!-- 基础信息 -->
		<view class="card basic-info">
			<view class="section-title">基础信息</view>
			<view class="info-content">
				<!-- 音量控制 -->
				<view class="volume-slider">
					<view class="volume-icon">
						<image src="https://xaznkj.cn/doc/photo/voice.svg" mode="aspectFit" class="volume-svg">
						</image>
					</view>
					<view class="slider-container">
						<u-slider v-model="volume" :min="0" :max="100" :step="1" @change="volumeChange"
							:disabled="device.status !== 3" height="4" activeColor="#2979ff" blockSize="18"
							:showValue="false">
						</u-slider>
						<view class="volume-marks">
							<text>0</text>
							<text>50</text>
							<text>100</text>
						</view>
					</view>
					<view class="volume-value">{{ volume }}%</view>
				</view>

				<!-- 音频开关 -->
				<view class="audio-switch">
					<text>音频开关</text>
					<u-switch v-model="audioEnabled" @change="audioSwitchChange" :disabled="device.status !== 3"
						size="22"></u-switch>
				</view>
			</view>
		</view>

		<!-- 音频列表 -->
		<view class="card audio-list">
			<view class="section-title">
				<text>音频列表</text>
				<image src="https://xaznkj.cn/doc/photo/add.svg" mode="aspectFit" class="add-icon"
					@click="showAddAudioModal"></image>
			</view>
			<view class="list-container">
				<view class="empty-tip" v-if="audioList.length === 0">
					<u-icon name="music" size="50" color="#c0c4cc"></u-icon>
					<text>暂无音频文件</text>
				</view>
				<view class="audio-item" v-for="(item, index) in audioList" :key="index">
					<view class="audio-info">
						<u-icon name="play-right" size="18" color="#2979ff"></u-icon>
						<text class="audio-name">{{ item.name }}</text>
					</view>
					<view class="audio-actions">
						<text class="audio-duration">{{ item.duration }}</text>
						<u-icon name="trash" size="18" color="#ff4d4f" @click="deleteAudio(index)"></u-icon>
					</view>
				</view>
			</view>
		</view>

		<!-- 默认音频列表 -->
		<view class="card default-list">
			<view class="section-title">
				<text>播放列表</text>
				<image src="https://xaznkj.cn/doc/photo/add.svg" mode="aspectFit" class="add-icon"
					@click="showAddDefaultModal"></image>
			</view>
			<view class="list-container">
				<view class="empty-tip" v-if="defaultList.length === 0">
					<u-icon name="star" size="50" color="#c0c4cc"></u-icon>
					<text>暂无默认音频</text>
				</view>
				<view class="audio-item" v-for="(item, index) in defaultList" :key="index">
					<view class="audio-info">
						<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>
							<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 class="audio-actions">
						<u-switch v-model="item.status" :active-value="'启用'" :inactive-value="'禁用'"
							@change="(value) => handleStatusChange(index, value)" size="22"></u-switch>
						<u-icon name="edit-pen" size="18" color="#2979ff" @click="editDefault(index)"></u-icon>
						<u-icon name="trash" size="18" color="#ff4d4f" @click="deleteDefault(index)"></u-icon>
					</view>
				</view>
			</view>
		</view>

		<!-- 远程喊话 -->
		<view class="card remote-talk">
			<view class="talk-container">
				<!-- 录音状态显示 -->
				<view class="recorder-status">
					<view class="status-indicator" :class="{ recording: isRecording }">
						<image
							:src="isRecording ? 'https://xaznkj.cn/doc/photo/recording.png' : 'https://xaznkj.cn/doc/photo/record.png'"
							class="mic-img" mode="aspectFit" />
					</view>
					<text class="status-text">{{ recordingStatus }}</text>
				</view>

				<!-- 录音时长显示 -->
				<view class="timer-display" v-if="isRecording">
					{{ formatTime(recordingTime) }}
				</view>

				<!-- 录音控制按钮 -->
				<view class="control-buttons">
					<view class="talk-button" :class="{ recording: isRecording }" @touchstart="startRecording"
						@touchend="stopRecording" @touchcancel="cancelRecording">
						<image
							:src="isRecording ? 'https://xaznkj.cn/doc/photo/micred.png' : 'https://xaznkj.cn/doc/photo/mic.png'"
							class="mic-img" mode="aspectFit" />
						<text>{{ isRecording ? '录音中...' : '按住说话' }}</text>
					</view>
				</view>

				<!-- 录音状态提示 -->
				<view class="recording-tips" v-if="!hasRecording && !isRecording">
					<text class="tip-text">按住按钮开始录音，松开自动结束并上传</text>
				</view>

				<!-- 录音预览（仅在上传失败时显示） -->
				<!-- 		<view class="recording-preview" v-if="hasRecording && uploadFailed">
					<view class="preview-title">录音预览</view>
					<view class="audio-player">
						<audio :src="audioUrl" controls style="width: 100%; height: 40px;"></audio>
						<view class="preview-controls">
							<u-button type="primary" size="small" @click="uploadRecording">
								重新上传
							</u-button>
							<u-button type="text" size="small" @click="reRecord">
								重新录制
							</u-button>
						</view>
					</view>
				</view> -->

				<!-- 最近录音列表 -->
				<!-- 		<view class="recording-list" v-if="recordings.length > 0">
					<view class="list-title">最近录音</view>
					<scroll-view scroll-y style="height: 200px;">
						<view v-for="(recording, index) in recordings" :key="index" class="recording-item">
							<view class="recording-info">
								<text class="recording-name">{{ recording.name }}</text>
								<text class="recording-time">{{ recording.time }}</text>
							</view>
							<u-icon name="trash" size="18" color="#ff4d4f" @click="deleteRecording(index)"></u-icon>
						</view>
					</scroll-view>
				</view> -->
			</view>
		</view>

		<!-- 添加音频弹窗 -->
		<u-popup :show="showAddAudio" mode="center" @close="showAddAudio = false" round="8">
			<view class="add-audio-modal">
				<view class="modal-title">添加音频</view>
				<view class="modal-content">
					<u-form :model="newAudio" ref="audioForm">
						<u-form-item label="备注名" prop="name" borderBottom>
							<u-input v-model="newAudio.name" placeholder="请输入备注名"></u-input>
						</u-form-item>
						<u-form-item label="主持人" prop="per" borderBottom>
							<u-radio-group v-model="newAudio.per">
								<u-radio label="小美" name="0"></u-radio>
								<u-radio label="小宇" name="1"></u-radio>
								<u-radio label="逍遥" name="3"></u-radio>
								<u-radio label="丫丫" name="4"></u-radio>
							</u-radio-group>
						</u-form-item>
						<u-form-item label="合成语速" prop="spd" borderBottom>
							<view class="slider-with-value">
								<u-slider v-model="newAudio.spd" :min="0" :max="15" :step="1" :showValue="true"
									class="custom-slider" height="12" blockSize="28" style="width: 100%;" />
							</view>
						</u-form-item>
						<u-form-item label="合成音调" prop="pit" borderBottom>
							<view class="slider-with-value">
								<u-slider v-model="newAudio.pit" :min="0" :max="15" :step="1" :showValue="true"
									class="custom-slider" height="12" blockSize="28" style="width: 100%;" />
							</view>
						</u-form-item>
						<u-form-item label="合成音量" prop="vol" borderBottom>
							<view class="slider-with-value">
								<u-slider v-model="newAudio.vol" :min="0" :max="15" :step="1" :showValue="true"
									class="custom-slider" height="12" blockSize="28" style="width: 100%;" />
							</view>
						</u-form-item>
						<u-form-item label="合成文本" prop="text" borderBottom>
							<u-input v-model="newAudio.text" type="textarea" placeholder="请输入合成文本"
								height="100"></u-input>
						</u-form-item>
					</u-form>
				</view>
				<view class="modal-footer">
					<u-button @click="showAddAudio = false" plain size="small">取消</u-button>
					<u-button type="primary" @click="confirmAddAudio" size="small">确定</u-button>
				</view>
			</view>
		</u-popup>

		<!-- 添加默认音频弹窗 -->
		<u-popup :show="showAddDefault" mode="center" @close="showAddDefault = false" round="8">
			<view class="add-audio-modal">
				<view class="modal-title">添加播放列表</view>
				<view class="modal-content">
					<u-form :model="newDefault" ref="defaultForm">
						<u-form-item label="开始时间" prop="startTime" borderBottom>
							<picker mode="time" :value="newDefault.startTime" start="00:00" end="23:59"
								@change="startTimeChange">
								<view class="picker-value">{{ newDefault.startTime || '请选择开始时间' }}</view>
							</picker>

						</u-form-item>
						<u-form-item label="结束时间" prop="endTime" borderBottom>
							<picker mode="time" :value="newDefault.endTime" start="00:00" end="23:59"
								@change="endTimeChange">
								<view class="picker-value">{{ newDefault.endTime || '请选择结束时间' }}</view>
							</picker>
						</u-form-item>
						<u-form-item label="重复" prop="repeat" borderBottom>
							<view class="week-picker">
								<view class="week-item" v-for="(day, index) in weekDays" :key="index"
									:class="{ active: newDefault.repeatDays.includes(index) }"
									@click="toggleWeekDay(index)">
									{{ day }}
								</view>
							</view>
						</u-form-item>
						<u-form-item label="雷达开关" prop="radarEnabled" borderBottom>
							<u-switch v-model="newDefault.radarEnabled" @change="radarSwitchChange"></u-switch>
						</u-form-item>
						<template v-if="newDefault.radarEnabled">
							<u-form-item label="速度范围" prop="speedRange" borderBottom>
								<view class="speed-range">
									<u-input v-model="newDefault.minSpeed" type="number" placeholder="最小速度"></u-input>
									<text class="separator">-</text>
									<u-input v-model="newDefault.maxSpeed" type="number" placeholder="最大速度"></u-input>
									<text class="unit">km/h</text>
								</view>
							</u-form-item>
						</template>
						<u-form-item label="选择音频" prop="audioFile" borderBottom>
							<picker :range="audioList" range-key="name" :value="audioIndex" @change="audioChange">
								<view class="picker-value">{{ selectedAudioName || '请选择音频' }}</view>
							</picker>
						</u-form-item>
					</u-form>
				</view>
				<view class="modal-footer">
					<u-button @click="showAddDefault = false" plain size="small">取消</u-button>
					<u-button type="primary" @click="confirmAddDefault" size="small">确定</u-button>
				</view>
			</view>
		</u-popup>
	</view>
</template>

<script>
	import {
		serviceInvoke
	} from '@/apis/modules/runtime.js';

	export default {
		name: 'VoiceControl',
		props: {
			device: {
				type: Object,
				required: true
			}
		},
		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');
						this.attributeList = this.deviceInfo.thingsModels && this.deviceInfo.thingsModels.filter((
							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();
				}
			}
		},
		data() {
			return {
				title: '设备离线',
				volume: 50,
				audioEnabled: true,
				isRecording: false,
				recorderManager: null,
				recordingTime: 0,
				recordingTimer: null,
				tempFilePath: '',
				hasRecording: false,
				audioUrl: '',
				uploadFailed: false,
				recordings: [],
				recordingStatus: '准备录音',
				showAddAudio: false,
				showAddDefault: false,
				showStartTimePicker: false,
				showEndTimePicker: false,
				showAudioPicker: false,
				weekDays: ['日', '一', '二', '三', '四', '五', '六'],
				audioIndex: -1,
				newAudio: {
					name: '',
					per: '0',
					spd: '5',
					pit: '5',
					vol: '5',
					text: '',
					file: null
				},
				deviceInfo: {
					chartList: [],
				},
				newDefault: {
					startTime: '',
					endTime: '',
					repeatDays: [],
					radarEnabled: false,
					minSpeed: '',
					maxSpeed: '',
					audioFile: null
				},
				audioFiles: [],
				audioList: [],
				defaultList: [],
				audioUrl: '',
				uploadFailed: false,
				isEditDefault: false,
				editDefaultIndex: null
			};
		},
		created() {
			if (this.device !== null && Object.keys(this.device).length !== 0) {
				this.deviceInfo = this.device;
				this.updateDeviceStatus(this.deviceInfo);
			};
			this.mqttCallback();
			this.recorderManager = uni.getRecorderManager();
			this.initRecorder();
			this.updateBasicSettings();
		},
		beforeDestroy() {
			if (this.recordingTimer) {
				clearInterval(this.recordingTimer);
				this.recordingTimer = null;
			}
		},
		methods: {
			print() {
				console.log("测试打印", JSON.stringify(this.deviceInfo.thingsModels))
			},
			checkOnline(callback, ...args) {
				if (this.device.status !== 3) {
					uni.showToast({
						title: '设备离线，无法操作',
						icon: 'none'
					});
					return false;
				}
				if (typeof callback === 'function') {
					return callback.apply(this, args);
				}
				return true;
			},
			async uploadRecording() {
				if (!this.tempFilePath) return;

				try {
					this.recordingStatus = '上传中...';

					// 在 uni-app 中直接使用 uni.uploadFile，不需要 FormData
					const uploadUrl = 'https://xaznkj.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 {
					const volumeModel = this.device.thingsModels.find(item => item.id === '103#volume');
					if (volumeModel) {
						volumeModel.shadow = value.toString();
						await this.mqttPublish(this.device, volumeModel);
					}
				} catch (error) {
					console.error('调整音量失败:', error);
					uni.showToast({
						title: '操作失败: ' + error.message,
						icon: 'none'
					});
				}
			},
			mqttCallback() {
				this.$mqttTool.client.on('message', (topic, message, buffer) => {
					let topics = topic.split('/');
					let productId = topics[1];
					let deviceNum = topics[2];
					message = JSON.parse(message.toString());
					if (topics[3] == 'status') {
						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();
						}
					}
					if (topics[4] == 'reply') {
						uni.showToast({
							icon: 'none',
							title: 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++) {
									if (this.deviceInfo.thingsModels[k].id == message.message[j].id) {
										this.deviceInfo.thingsModels[k].shadow = 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
											.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;
												isComplete = true;
												break;
											}
										}
									} 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
													.arrayParams.length; n++) {
													for (let m = 0; m < this.deviceInfo.thingsModels[k].datatype
														.arrayParams[n].length; m++) {
														if (this.deviceInfo.thingsModels[k].datatype.arrayParams[n]
															[m].id == message.message[j].id) {
															this.deviceInfo.thingsModels[k].datatype.arrayParams[n]
																[m].shadow = message.message[j].value;
															isComplete = true;
															break;
														}
													}
													if (isComplete) {
														break;
													}
												}
											} else {
												for (let n = 0; n < this.deviceInfo.thingsModels[k].datatype
													.arrayParams.length; n++) {
													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]
															[m].id == prefix + message.message[j].id) {
															this.deviceInfo.thingsModels[k].datatype.arrayParams[n]
																[m].shadow = message.message[j].value;
															isComplete = true;
														}
													}
													if (isComplete) {
														break;
													}
												}
											}
										} else {
											for (let n = 0; n < this.deviceInfo.thingsModels[k].datatype.arrayModel
												.length; n++) {
												if (this.deviceInfo.thingsModels[k].datatype.arrayModel[n].id ==
													message.message[j].id) {
													this.deviceInfo.thingsModels[k].datatype.arrayModel[n].shadow =
														message.message[j].value;
													isComplete = true;
													break;
												}
											}
										}
									}
								};
								for (let k = 0; k < this.deviceInfo.chartList.length && !isComplete; k++) {
									if (this.deviceInfo.chartList[k].id.indexOf("array_") == 0) {
										if (this.deviceInfo.chartList[k].id == message.message[j].id) {
											this.deviceInfo.chartList[k].shadow = message.message[j].value;
											isComplete = true;
											break;
										}
									} else {
										if (this.deviceInfo.chartList[k].id == message.message[j].id) {
											this.deviceInfo.chartList[k].shadow = message.message[j].value;
											isComplete = true;
											break;
										}
									}
									if (isComplete) {
										break;
									}
								};
							}
						}
						this.updateBasicSettings();
					}
				});
			},
			async mqttPublish(device, model) {
				const command = {};
				command[model.id] = model.shadow;
				const data = {
					serialNumber: device.serialNumber,
					productId: device.productId,
					remoteCommand: command,
					identifier: model.id,
					modelName: model.name,
					isShadow: device.status != 3,
					type: model.type
				};
				serviceInvoke(data).then(response => {
					if (response.code === 200) {
						uni.showToast({
							icon: 'none',
							title: this.$tt('status.service')
						});
					}
				});
			},
			updateDeviceStatus(device) {
				if (device.status === 3) {
					this.title = this.$tt('status.online');
				} else {
					this.title = device.isShadow === 1 ? this.$tt('status.shadow') : this.$tt('status.deviceOffline');
				}
			},
			initRecorder() {
				if (!this.recorderManager) return;
				this.recorderManager.onStart(() => {
					this.recordingStatus = '正在录音...';
				});
				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() || !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 || !this.recorderManager) return;
				this.isRecording = false;
				this.recordingStatus = '录音完成，正在上传...';
				if (this.recordingTimer) {
					clearInterval(this.recordingTimer);
					this.recordingTimer = null;
				}
				this.recorderManager.stop();
			},
			cancelRecording() {
				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',
				});
			},
			showAddAudioModal() {
				this.showAddAudio = true;
			},
			showAddDefaultModal() {
				this.showAddDefault = true;
			},
			async confirmAddAudio() {
				if (!this.checkOnline()) return;

				try {
					const mp3ListModel = this.deviceInfo.thingsModels.find(model => model.id === '103#mp3List');
					if (!mp3ListModel) {
						throw new Error('未找到 mp3_list 模型');
					}

					const jsonStr = mp3ListModel.shadow.replace('JSON=', '');
					const data = JSON.parse(jsonStr);

					let maxId = 0;
					console.log("data", JSON.stringify(data))
					if (data.mp3_list) {
						data.mp3_list.forEach(item => {
							const id = parseInt(item.split('_')[0]);
							if (!isNaN(id) && id > maxId) {
								maxId = id;
							}
						});
					}

					const newId = maxId + 1;

					const ttsData = {
						JSON_id: 1,

						TTS: {
							per: parseInt(this.newAudio.per),
							spd: parseInt(this.newAudio.spd),
							pit: parseInt(this.newAudio.pit),
							vol: parseInt(this.newAudio.vol),
							tex_utf8: this.newAudio.text,
							filename: `${newId}_${this.newAudio.name}`
						}

					};
					console.log("103#mp3List", JSON.stringify(ttsData))
					mp3ListModel.shadow = 'JSON=' + JSON.stringify(ttsData);
					await this.mqttPublish(this.device, mp3ListModel);

					this.newAudio = {
						name: '',
						per: '0',
						spd: '5',
						pit: '5',
						vol: '5',
						text: '',
						file: null
					};

					this.showAddAudio = false;

					uni.showToast({
						title: '添加成功',
						icon: 'success'
					});
				} catch (error) {
					console.error('添加音频失败:', error);
					uni.showToast({
						title: '添加失败: ' + error.message,
						icon: 'none'
					});
				}
			},
			async confirmAddDefault() {
				if (!this.checkOnline()) return;

				if (!this.newDefault.startTime || !this.newDefault.endTime || !this.newDefault.audioFile) {
					uni.showToast({
						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 === '103#playList');
				if (playListModel) {
					try {
						const jsonStr = playListModel.shadow.replace('JSON=', '');
						const data = JSON.parse(jsonStr);

						if (!data) {
							data = {};
						}
						if (!data.play_list) {
							data.play_list = [];
						}

						let maxNum = 0;
						if (data.play_list.length > 0) {
							maxNum = Math.max(...data.play_list.map(item => item.play.num || 0));
						}

						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: this.isEditDefault && this.editDefaultIndex !== null && data.play_list[this.editDefaultIndex] ? data.play_list[this.editDefaultIndex].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
							}
						};

						if (this.isEditDefault && this.editDefaultIndex !== null) {
							data.play_list[this.editDefaultIndex] = newPlayItem;
						} else {
							data.play_list.push(newPlayItem);
						}

						playListModel.shadow = 'JSON=' + JSON.stringify(data);

						try {
							await this.mqttPublish(this.device, playListModel);
							uni.showToast({
								title: '添加成功',
								icon: 'success'
							});
							this.showAddDefault = false;

							this.newDefault = {
								startTime: '',
								endTime: '',
								repeatDays: [],
								radarEnabled: false,
								minSpeed: '',
								maxSpeed: '',
								audioFile: null
							};
							this.isEditDefault = false;
							this.editDefaultIndex = null;
						} catch (error) {
							console.error('发送添加命令失败:', error);
							uni.showToast({
								title: '添加失败',
								icon: 'none'
							});
						}
					} catch (error) {
						console.error('解析或更新播放列表失败:', error);
						uni.showToast({
							title: '添加失败',
							icon: 'none'
						});
					}
				}
			},
			async deleteAudio(index) {
				if (!this.checkOnline()) return;

				try {
					uni.showModal({
						title: '提示',
						content: '确定要删除该音频吗？',
						cancelText: '取消',
						confirmText: '确定',
						success: async (res) => {
							if (res.confirm) {
								const mp3ListModel = this.deviceInfo.thingsModels.find(model => model
									.id === '103#mp3List');
								if (mp3ListModel && mp3ListModel.shadow) {
									try {
										const jsonStr = mp3ListModel.shadow.replace('JSON=', '');
										const data = JSON.parse(jsonStr);

										if (data.mp3_list) {
											data.mp3_list.splice(index, 1);

											mp3ListModel.shadow = 'JSON=' + JSON.stringify(data);

											await this.mqttPublish(this.device, mp3ListModel);

											this.audioList.splice(index, 1);

											uni.showToast({
												title: '删除成功',
												icon: 'success'
											});
										}
									} catch (error) {
										console.error('删除音频失败:', error);
										uni.showToast({
											title: '删除失败: ' + error.message,
											icon: 'none'
										});
									}
								}
							}
						}
					});
				} catch (error) {
					console.error('删除音频失败:', error);
					uni.showToast({
						title: '删除失败: ' + error.message,
						icon: 'none'
					});
				}
			},
			deleteDefault(index) {
				uni.showModal({
					title: '提示',
					content: '确认删除该播放项吗？',
					cancelText: '取消',
					confirmText: '确定',
					success: async (res) => {
						if (res.confirm) {
							const playListModel = this.deviceInfo.thingsModels.find(model => model.id ===
								'103#playList');
							if (playListModel) {
								try {
									const jsonStr = playListModel.shadow.replace('JSON=', '');
									const data = JSON.parse(jsonStr);

									if (data.play_list) {
										data.play_list.splice(index, 1);

										data.play_list.forEach((item, index) => {
											item.play.num = index + 1;
										});

										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'
									});
								}
							}
						}
					}
				});
			},
			afterAudioRead(file) {
				this.audioFiles.push(file);
			},
			deleteAudioFile(index) {
				this.audioFiles.splice(index, 1);
			},
			beforeAudioUpload(file) {
				const isValidType = file.name.toLowerCase().endsWith('.mp3');
				const isValidSize = file.size / 1024 / 1024 < 10;

				if (!isValidType) {
					uni.showToast({
						title: '只能上传MP3格式',
						icon: 'none'
					});
					return false;
				}
				if (!isValidSize) {
					uni.showToast({
						title: '文件大小不能超过10MB',
						icon: 'none'
					});
					return false;
				}
				return true;
			},
			async audioSwitchChange() {
				if (!this.checkOnline()) return;
				try {
					const playEnModel = this.device.thingsModels.find(item => item.id === '103#playEn');
					if (playEnModel) {
						playEnModel.shadow = this.audioEnabled ? '1' : '0';
						await this.mqttPublish(this.device, playEnModel);
					}
				} catch (error) {
					console.error('切换音频开关失败:', error);
					uni.showToast({
						title: '操作失败: ' + error.message,
						icon: 'none'
					});
				}
			},
			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;
			},
			endTimeChange(e) {
				this.newDefault.endTime = e.detail.value;
			},
			toggleWeekDay(index) {
				const position = this.newDefault.repeatDays.indexOf(index);
				if (position === -1) {
					this.newDefault.repeatDays.push(index);
				} else {
					this.newDefault.repeatDays.splice(position, 1);
				}
			},
			radarSwitchChange(value) {
				this.newDefault.radarEnabled = value;
				if (!value) {
					this.newDefault.minSpeed = '';
					this.newDefault.maxSpeed = '';
				}
			},
			audioChange(e) {
				this.audioIndex = e.detail.value;
				this.newDefault.audioFile = this.audioList[this.audioIndex];
			},
			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#mp3List');
				if (mp3ListModel && mp3ListModel.shadow) {
					try {
						const jsonStr = mp3ListModel.shadow.replace('JSON=', '');
						const data = JSON.parse(jsonStr);

						if (data && data.mp3_list) {
							this.audioList = data.mp3_list.map((item, index) => {
								const name = item.split('_')[1] || item;
								return {
									id: index + 1,
									name: name
								};
							});
						}
					} catch (error) {
						console.error('解析音频列表失败:', error);
					}
				}

				const playListModel = this.deviceInfo.thingsModels.find(model => model.id === '103#playList');
				if (playListModel && playListModel.shadow) {
					try {
						const jsonStr = playListModel.shadow.replace('JSON=', '');
						const data = JSON.parse(jsonStr);

						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 {
									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);
					}
				}
			},
			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 === '103#playList');
				if (playListModel) {
					try {
						const jsonStr = playListModel.shadow.replace('JSON=', '');
						const data = JSON.parse(jsonStr);

						if (data.play_list) {
							data.play_list[index].play.en = value === '启用' ? 1 : 0;

							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 === '启用' ? '禁用' : '启用';
					}
				}
			},
			deleteRecording(index) {
				uni.showModal({
					title: '提示',
					content: '确定要删除该录音吗？',
					cancelText: '取消',
					confirmText: '确定',
					success: (res) => {
						if (res.confirm) {
							this.recordings.splice(index, 1);
							uni.showToast({
								title: '删除成功',
								icon: 'success'
							});
						}
					}
				});
			},
			editDefault(index) {
				const item = this.defaultList[index];
				const audioFile = this.audioList.find(a => a.name === item.name);
				const audioIndex = this.audioList.findIndex(a => a.name === item.name);
				this.newDefault = {
					startTime: item.playTime.split(' - ')[0],
					endTime: item.playTime.split(' - ')[1],
					repeatDays: this.weekDays.map((d, i) => item.weekdays.includes(d) ? i : -1).filter(i => i !== -1),
					radarEnabled: item.radarEnabled,
					minSpeed: item.radarEnabled && item.radarSpeed ? item.radarSpeed.split('-')[0] : '',
					maxSpeed: item.radarEnabled && item.radarSpeed ? item.radarSpeed.split('-')[1].replace('km/h', '') : '',
					audioFile: audioFile
				};
				this.audioIndex = audioIndex;
				this.isEditDefault = true;
				this.editDefaultIndex = index;
				this.showAddDefault = true;
			}
		},
		computed: {
			startTimeLabel() {
				return this.newDefault.startTime ? this.formatTime(this.newDefault.startTime) : '请选择开始时间';
			},
			endTimeLabel() {
				return this.newDefault.endTime ? this.formatTime(this.newDefault.endTime) : '请选择结束时间';
			},
			selectedAudioName() {
				return this.audioIndex >= 0 ? this.audioList[this.audioIndex].name : '';
			}
		}
	};
</script>

<style lang="scss" scoped>
	// @import "@/uni_modules/uview-ui/scss/index.scss";

	.voice-control {
		padding: 20rpx;
		background-color: #f7f8fa;
		min-height: 100vh;

		.card {
			background-color: #fff;
			border-radius: 16rpx;
			margin-bottom: 20rpx;
			box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
			overflow: hidden;
		}

		.status-titletop {
			font-weight: bold;
			font-size: 15px;
			color: #333333;
			line-height: 42rpx;
			text-align: left;
			padding: 15rpx 28rpx;
			background-color: #eef6ff;
			border-bottom: 1rpx solid #dceaff;
		}

		.version-wrap {
			background-color: #F7F7F7;
			border-radius: 10rpx;
			padding: 0 42rpx;
			font-size: 24rpx;
			color: #000000;
			line-height: 42rpx;
		}

		.section-title {
			font-size: 30rpx;
			font-weight: 600;
			color: #333;
			padding: 24rpx;
			border-bottom: 1rpx solid #f5f5f5;
			display: flex;
			align-items: center;

			.add-icon {
				width: 40rpx;
				height: 40rpx;
				margin-left: auto;
			}
		}

		.info-content {
			padding: 16rpx 24rpx 24rpx;
		}

		.volume-slider {
			display: flex;
			align-items: center;
			gap: 16rpx;
			margin-bottom: 20rpx;
			padding: 16rpx 0;
			background-color: #f9f9f9;
			border-radius: 16rpx;

			.volume-icon {
				width: 40rpx;
				height: 40rpx;
				display: flex;
				justify-content: center;
				align-items: center;

				.volume-svg {
					width: 40rpx;
					height: 40rpx;
				}
			}

			.slider-container {
				flex: 1;
				position: relative;

				.volume-marks {
					display: flex;
					justify-content: space-between;
					margin-top: 8rpx;
					padding: 0 8rpx;

					text {
						font-size: 22rpx;
						color: #999;
					}
				}
			}

			.volume-value {
				min-width: 72rpx;
				text-align: right;
				color: #2979ff;
				font-size: 26rpx;
				font-weight: 500;
			}
		}

		.audio-switch {
			display: flex;
			align-items: center;
			justify-content: space-between;
			padding: 16rpx 0;

			text {
				font-size: 28rpx;
				color: #333;
			}
		}

		.audio-list,
		.default-list {
			.list-container {
				padding: 0 24rpx 16rpx;
			}

			.empty-tip {
				display: flex;
				flex-direction: column;
				align-items: center;
				justify-content: center;
				padding: 60rpx 0;
				color: #c0c4cc;
				font-size: 28rpx;
				gap: 20rpx;
				opacity: 0.8;
				transition: all 0.3s ease;

				&:active {
					transform: scale(0.98);
					opacity: 0.6;
				}
			}

			.audio-item {
				display: flex;
				justify-content: space-between;
				align-items: center;
				padding: 20rpx 0;
				border-bottom: 1rpx solid #f5f5f5;

				&:last-child {
					border-bottom: none;
				}

				.audio-info {
					display: flex;
					align-items: flex-start;
					gap: 16rpx;
					flex: 1;
					overflow: hidden;

					.audio-details {
						flex: 1;
						overflow: hidden;

						.audio-name {
							font-size: 26rpx;
							color: #333;
							margin-bottom: 8rpx;
							display: block;
						}

						.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;
							}
						}
					}
				}

				.audio-actions {
					display: flex;
					align-items: center;
					gap: 24rpx;
					margin-left: 16rpx;
				}
			}
		}

		.remote-talk {
			.talk-container {
				padding: 24rpx;
				display: flex;
				flex-direction: column;
				align-items: center;
				gap: 20rpx;

				.recorder-status {
					display: flex;
					flex-direction: column;
					align-items: center;
					margin-bottom: 20rpx;

					.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;
						}
					}

					.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);
			}
		}

		.add-audio-modal {
			width: 80vw;
			max-width: 600rpx;
			padding: 0;
			border-radius: 16rpx;
			background-color: #fff;
			overflow: hidden;

			.modal-title {
				font-size: 30rpx;
				font-weight: 600;
				color: #333;
				padding: 28rpx 28rpx 20rpx;
				text-align: center;
				border-bottom: 1rpx solid #f5f5f5;
			}

			.modal-content {
				padding: 0 28rpx;
				margin: 20rpx 0;
				max-height: 60vh;
				overflow-y: auto;

				.u-form-item {
					padding: 20rpx 0;

					:deep(.u-form-item__body) {
						padding: 0;
					}

					:deep(.u-form-item__body__left) {
						width: 160rpx;
					}

					:deep(.u-form-item__body__right) {
						flex: 1;
					}
				}

				.slider-with-value {
					width: 100% !important;
					display: block !important;
					.custom-slider {
						width: 100% !important;
						min-width: 0 !important;
						max-width: 100% !important;
						flex: 1 !important;
						display: block !important;
						margin-right: 0 !important;
					}
				}

				:deep(.u-radio-group) {
					display: flex;
					flex-wrap: wrap;
					gap: 20rpx;
				}
			}

			.modal-footer {
				display: flex;
				justify-content: space-between;
				padding: 16rpx 28rpx 28rpx;
				border-top: 1rpx solid #f5f5f5;

				.u-button {
					width: 48%;
					height: 72rpx;
					font-size: 26rpx;
					border-radius: 40rpx;
				}
			}
		}

		.week-picker {
			display: flex;
			flex-wrap: wrap;
			gap: 10rpx;
			padding: 10rpx 0;

			.week-item {
				width: 60rpx;
				height: 60rpx;
				display: flex;
				align-items: center;
				justify-content: center;
				border-radius: 30rpx;
				background-color: #f5f5f5;
				font-size: 24rpx;
				color: #666;
				transition: all 0.3s ease;

				&.active {
					background-color: #2979ff;
					color: #fff;
				}
			}
		}

		.speed-range {
			display: flex;
			align-items: center;
			gap: 10rpx;

			.u-input {
				flex: 1;
			}

			.separator {
				color: #666;
				padding: 0 10rpx;
			}

			.unit {
				color: #666;
				font-size: 24rpx;
				margin-left: 10rpx;
			}
		}

		.picker-value {
			height: 80rpx;
			line-height: 80rpx;
			font-size: 28rpx;
			color: #333;
			padding: 0 20rpx;
			background-color: #f9f9f9;
			border-radius: 8rpx;
		}

		.mic-img {
			width: 56rpx;
			height: 56rpx;
			margin-bottom: 8rpx;
		}
	}
</style>