<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>

		<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/brightness.png" 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" style="margin-top: 20rpx;">
					<text>屏幕开关</text>
					<u-switch v-model="audioEnabled" @change="audioSwitchChange" :disabled="device.status !== 3"
						size="22"></u-switch>
				</view>
				<!-- 屏幕参数 -->

				<view class="clear-screen-btn-wrap">
					<u-button type="error" size="medium" shape="circle" @click="clearScreen"
						customStyle="box-shadow:0 4rpx 12rpx rgba(255,77,79,0.15);font-weight:600;">
						<u-icon name="trash" size="18" color="#fff" style="margin-right:8rpx;" />
						清除屏幕
					</u-button>
				</view>
			</view>
		</view>

		<!-- 屏幕参数卡片 -->
		<view class="card screen-params">
			<view class="section-title">屏幕参数</view>
			<view class="screen-params-form">
				<u-cell-group>
					<picker mode="selector" :range="templateColumns" range-key="label" @change="onNativePickerChange">
						<view class="picker-cell u-cell u-cell--border-bottom"
							style="display:flex;align-items:center;justify-content:space-between;padding:24rpx 32rpx;margin-bottom:12rpx;">
							<text style="font-size:30rpx;color:#333;">屏幕模板</text>
							<text style="font-size:30rpx;color:#2979ff;">{{ screenParams.templateLabel || '请选择屏幕模板'
								}}</text>
						</view>
					</picker>
					<u-cell @click="showPicker('screenRotate')" title="屏幕旋转"
						:value="screenParams.screenRotateLabel || '请选择屏幕旋转'" isLink></u-cell>
				</u-cell-group>

				<u-form :model="screenParams" labelPosition="left" labelWidth="120">
					<u-form-item label="OE极性" prop="oePolarity" borderBottom>
						<view style="display:flex;align-items:center;">
							<u-switch v-model="screenParams.oePolarity" :active-value="'1'" :inactive-value="'0'"
								@change="val => screenParams.oePolarityLabel = val === '1' ? '1' : '0'" size="22"
								style="margin-right:12rpx;" />
							<u-input v-model="screenParams.oePolarityLabel" readonly border="none" style="flex:1;" />
						</view>
					</u-form-item>
					<u-form-item label="DATA极性" prop="dataPolarity" borderBottom>
						<view style="display:flex;align-items:center;">
							<u-switch v-model="screenParams.dataPolarity" :active-value="'1'" :inactive-value="'0'"
								@change="val => screenParams.dataPolarityLabel = val === '1' ? '1' : '0'" size="22"
								style="margin-right:12rpx;" />
							<u-input v-model="screenParams.dataPolarityLabel" readonly border="none" style="flex:1;" />
						</view>
					</u-form-item>
					<u-form-item label="屏宽" prop="width" borderBottom>
						<u-input v-model="screenParams.width" type="number" placeholder="请输入屏宽" />
					</u-form-item>
					<u-form-item label="屏高" prop="height" borderBottom>
						<u-input v-model="screenParams.height" type="number" placeholder="请输入屏高" />
					</u-form-item>
				</u-form>
				<view style="text-align:center;margin:20rpx 0;">
					<u-button type="primary" size="normal" @click="handleSendScreenParams">下发参数</u-button>
				</view>
			</view>
			<!-- <view style="text-align:center;margin:20rpx 0;">
				<u-button type="primary" size="mini" @click="testOpenPicker">测试弹窗</u-button>
			</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="qzone" 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">
						<u-switch v-model="item.enabled" :active-value="1" :inactive-value="0"
							@change="onProgramEnableChange(index, item.enabled)" size="22"
							:disabled="device.status !== 3"></u-switch>
						<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>
			</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">
						<text class="audio-name">{{ item.name }}</text>
					</view>
					<view class="audio-actions">
						<u-switch v-model="item.status" :active-value="'启用'" :inactive-value="'禁用'"
							@change="(value) => handleStatusChange(index, value)" size="22"></u-switch>
					</view>
				</view>
			</view>
		</view> -->

		<!-- 开机参数 -->
		<view class="card remote-talk">
			<view class="section-title">开机参数</view>
			<view class="info-content">
				<u-form :model="bootSettings" labelPosition="left" labelWidth="120">
					<u-form-item label="开机界面可选">
						<u-switch v-model="bootSettings.showBootScreen" @change="handleBootScreenSwitchChange"
							size="22"></u-switch>
					</u-form-item>
					<u-form-item label="重置开关">
						<u-switch v-model="bootSettings.resetEnabled" @change="handleResetSwitchChange"
							size="22"></u-switch>
					</u-form-item>
				</u-form>
			</view>
		</view>

		<!-- 传感器阈值卡片 -->
		<view class="card sensor-threshold">
			<view class="section-title">传感器阈值</view>
			<view class="sensor-form">
				<u-form :model="sensorThreshold" labelPosition="left" labelWidth="120">
					<u-form-item label="速度阈值">
						<u-input v-model="sensorThreshold.speed" type="number" placeholder="请输入速度阈值" />
					</u-form-item>
					<u-form-item label="温度阈值">
						<u-input v-model="sensorThreshold.temp" type="number" placeholder="请输入温度阈值" />
					</u-form-item>
					<u-form-item label="湿度阈值">
						<u-input v-model="sensorThreshold.humi" type="number" placeholder="请输入湿度阈值" />
					</u-form-item>
				</u-form>
				<view style="text-align:center;margin:20rpx 0;">
					<u-button type="primary" size="normal" @click="handleSendSensorThreshold">下发阈值</u-button>
				</view>
			</view>
		</view>

		<!-- 测试按钮 -->


		<!-- Pickers -->
		<u-picker :show="pickerShow.screenRotate" :columns="[screenRotateOptions]" keyName="label"
			@confirm="onPickerConfirm('screenRotate')" @cancel="closePicker('screenRotate')"
			safe-area-inset-bottom></u-picker>

		<!-- 编译信息卡片 -->
		<view class="card build-info">
			<view class="section-title" style="display:flex;align-items:center;justify-content:space-between;">
				<text>编译信息</text>
				<u-icon name="reload" size="32" color="#2979ff" @click="refreshBuildInfo"
					style="margin-left:12rpx;cursor:pointer;" />
			</view>
			<view class="info-content">
				<view class="info-item">
					<text class="info-label">编译版本：</text>
					<text class="info-value">{{ buildVersion || '加载中...' }}</text>
				</view>
				<view class="info-item">
					<text class="info-label">编译时间：</text>
					<text class="info-value">{{ buildTime || '加载中...' }}</text>
				</view>
			</view>
		</view>
	</view>
</template>

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

export default {
	name: 'VoiceControl',
	props: {
		device: {
			type: Object,
			required: true
		}
	},
	data() {
		return {
			title: '设备离线',
			volume: 50,
			audioEnabled: true,
			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,
			screenParams: {
				template: '',
				templateLabel: '',
				oePolarity: '0',
				oePolarityLabel: '0',
				dataPolarity: '0',
				dataPolarityLabel: '0',
				screenRotate: '',
				screenRotateLabel: '',
				width: '',
				height: ''
			},
			pickerShow: {
				screenRotate: false
			},
			templateColumns: [
				{ label: '自定义', value: '1', params: { oe: '', data: '', w: '', h: '', angle: '' } },
				{ label: '伸缩屏', value: '2', params: { oe: 1, data: 1, w: 64, h: 32, angle: 270 } },
				{ label: '大屏', value: '3', params: { oe: 1, data: 1, w: 64, h: 32, angle: 180 } },
				{ label: '小屏', value: '4', params: { oe: 1, data: 1, w: 64, h: 16, angle: 0 } }
			],
			screenRotateOptions: [{
				label: '0°',
				value: '0'
			},
			{
				label: '90°',
				value: '90'
			},
			{
				label: '180°',
				value: '180'
			},
			{
				label: '270°',
				value: '270'
			}
			],
			bootSettings: {
				showBootScreen: false,
				resetEnabled: false
			},
			sensorThreshold: {
				speed: 60,
				temp: 30,
				humi: 50
			},
			buildVersion: '',
			buildTime: '',
		};
	},
	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.updateBasicSettings();

		// 监听节目数据准备完成事件
		uni.$on('programDataReady', this.handleProgramData);
	},
	beforeDestroy() {
		if (this.recordingTimer) {
			clearInterval(this.recordingTimer);
			this.recordingTimer = null;
		}
		// 移除事件监听
		uni.$off('programDataReady', this.handleProgramData);
	},
	methods: {
		showPicker(type) {
			this.pickerShow[type] = true
		},
		closePicker(type) {
			this.pickerShow[type] = false
		},
		onPickerConfirm(type, e) {
			console.log('Picker confirm:', type, e);
			const value = e && e.value && Array.isArray(e.value) && e.value.length > 0 ? e.value[0] : undefined;
			if (!value) {
				uni.showToast({ title: '选择数据异常', icon: 'none' });
				this.closePicker(type);
				return;
			}
			this.screenParams[type] = value.value;
			this.screenParams[type + 'Label'] = value.label;
			this.closePicker(type);
			if (type === 'screenRotate') {
				this.handleScreenRotateChange(value.value);
			}
		},
		clearScreen() {
			uni.showToast({
				title: '已清除屏幕',
				icon: 'success'
			});
		},
		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 volumeChange(value) {
			if (!this.checkOnline()) return;
			try {
				const luminanceModel = this.device.thingsModels.find(item => item.id === '102#luminance');
				if (luminanceModel) {
					luminanceModel.shadow = value.toString();
					await this.mqttPublish(this.device, luminanceModel);
				}
			} 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) {
						this.updateParam({ serialNumber: this.deviceInfo.serialNumber, productId: this.deviceInfo.productId, data: message.message });
					}
				}
			});
		},
		// 1. 新增/同步 updateParam 方法，接收设备上报后刷新页面数据
		updateParam(params) {
			let { serialNumber, productId, data } = params;
			let isComplete = false;
			data = data.message;
			if (data) {
				for (let j = 0; j < data.length; j++) {
					for (let k = 0; k < this.deviceInfo.thingsModels.length && !isComplete; k++) {
						if (this.deviceInfo.thingsModels[k].id == data[j].id) {
							const variable = this.deviceInfo.thingsModels[k];
							if (this.deviceInfo.thingsModels[k].datatype.type == 'decimal' || this.deviceInfo.thingsModels[k].datatype.type == 'integer') {
								variable.shadow = Number(data[j].value);
							} else {
								variable.shadow = data[j].value;
							}
						}
						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 == data[j].id) {
									this.deviceInfo.thingsModels[k].datatype.params[n].shadow = data[j].value;
									isComplete = true;
									break;
								}
							}
						} else if (this.deviceInfo.thingsModels[k].datatype.type == 'array') {
							if (this.deviceInfo.thingsModels[k].datatype.arrayType == 'object') {
								if (String(data[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 == data[j].id) {
												this.deviceInfo.thingsModels[k].datatype.arrayParams[n][m].shadow = data[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 + data[j].id) {
												this.deviceInfo.thingsModels[k].datatype.arrayParams[n][m].shadow = data[j].value;
											}
										}
									}
								}
							} else {
								for (let n = 0; n < this.deviceInfo.thingsModels[k].datatype.arrayModel.length; n++) {
									if (this.deviceInfo.thingsModels[k].datatype.arrayModel[n].id == data[j].id) {
										this.deviceInfo.thingsModels[k].datatype.arrayModel[n].shadow = data[j].value;
										break;
									}
								}
							}
						}
					}
					for (let k = 0; k < this.deviceInfo.chartList.length; k++) {
						if (this.deviceInfo.chartList[k].id.indexOf('array_') == 0) {
							if (this.deviceInfo.chartList[k].id == data[j].id) {
								this.deviceInfo.chartList[k].shadow = data[j].value;
							}
						} else {
							if (this.deviceInfo.chartList[k].id == data[j].id) {
								this.deviceInfo.chartList[k].shadow = data[j].value;
							}
						}
						if (isComplete) {
							break;
						}
					}
				}
			}
			this.updateBasicSettings();
		},

		// 2. 同步 updateBasicSettings 方法，解析新版物模型 shadow 字段，字段与电脑版保持一致
		updateBasicSettings() {
			if (!this.deviceInfo.thingsModels) return;

			// 屏幕开关
			const screenEnModel = this.deviceInfo.thingsModels.find(model => model.id === '102#screenEn');
			if (screenEnModel) {
				this.audioEnabled = screenEnModel.shadow === '1';
			}

			// 屏幕亮度
			const luminanceModel = this.deviceInfo.thingsModels.find(model => model.id === '102#luminance');
			if (luminanceModel) {
				this.volume = parseInt(luminanceModel.shadow) || 50;
			}

			// 屏幕参数
			const scrParamModel = this.deviceInfo.thingsModels.find(model => model.id === '102#scrParam');
			if (scrParamModel && scrParamModel.shadow) {
				try {
					const jsonStr = scrParamModel.shadow.replace('JSON=', '');
					const data = JSON.parse(jsonStr);
					if (data.scr_param) {
						this.screenParams.oePolarity = data.scr_param.oe;
						this.screenParams.dataPolarity = data.scr_param.data;
						this.screenParams.width = data.scr_param.w;
						this.screenParams.height = data.scr_param.h;
						this.screenParams.screenRotate = data.scr_param.angle;
					}
				} catch (error) {
					console.error('解析屏幕参数失败:', error);
				}
			}

			// 节目列表
			const progListModel = this.deviceInfo.thingsModels.find(model => model.id === '102#progList');
			if (progListModel && progListModel.shadow) {
				try {
					const jsonStr = progListModel.shadow.replace('JSON=', '');
					const data = JSON.parse(jsonStr);
					if (data.prog_list && data.prog_list.length > 0) {
						this.audioList = data.prog_list.map((program, index) => {
							return {
								id: index + 1,
								name: program.rem ? program.rem.replace(/\0/g, '') : '未命名节目',
								duration: program.dur,
								mode: program.areaM,
								zones: program.aLst ? program.aLst.length : 0,
								content: program.aLst ? JSON.stringify(program.aLst) : '',
								enabled: 1,
								raw: program
							};
						});
					} else {
						this.audioList = [];
					}
				} catch (error) {
					console.error('解析节目列表失败:', error);
					this.audioList = [];
				}
			}

			// 节目使能状态
			const progEnModel = this.deviceInfo.thingsModels.find(model => model.id === '102#progEn');
			let enableArr = [];
			if (progEnModel && progEnModel.shadow) {
				try {
					const jsonStr = progEnModel.shadow.replace('JSON=', '');
					const data = JSON.parse(jsonStr);
					if (data.prog_en && Array.isArray(data.prog_en)) {
						enableArr = data.prog_en;
					}
				} catch (e) { }
			}
			if (progListModel && progListModel.shadow) {
				try {
					const jsonStr = progListModel.shadow.replace('JSON=', '');
					const data = JSON.parse(jsonStr);
					if (data.prog_list && data.prog_list.length > 0) {
						this.audioList = data.prog_list.map((program, index) => {
							return {
								id: index + 1,
								name: program.rem ? program.rem.replace(/\0/g, '') : '未命名节目',
								duration: program.dur,
								mode: program.areaM,
								zones: program.aLst ? program.aLst.length : 0,
								content: program.aLst ? JSON.stringify(program.aLst) : '',
								enabled: enableArr[index] === 1 ? 1 : 0,
								raw: program
							};
						});
					} else {
						this.audioList = [];
					}
				} catch (error) {
					console.error('解析节目列表失败:', error);
					this.audioList = [];
				}
			}

			// 开机参数
			const bootEnModel = this.deviceInfo.thingsModels.find(model => model.id === '102#bootEn');
			if (bootEnModel) {
				this.bootSettings.showBootScreen = bootEnModel.shadow === '1';
			}
			const factoryEnModel = this.deviceInfo.thingsModels.find(model => model.id === '102#factoryEn');
			if (factoryEnModel) {
				this.bootSettings.resetEnabled = factoryEnModel.shadow === '1';
			}

			// 传感器阈值
			const snsrThrModel = this.deviceInfo.thingsModels.find(model => model.id === '102#snsrThr');
			if (snsrThrModel && snsrThrModel.shadow) {
				try {
					const jsonStr = snsrThrModel.shadow.replace('JSON=', '');
					const data = JSON.parse(jsonStr);
					if (data.snsr_thr) {
						this.sensorThreshold.speed = data.snsr_thr.speed;
						this.sensorThreshold.temp = data.snsr_thr.temp;
						this.sensorThreshold.humi = data.snsr_thr.humi;
					}
				} catch (error) {
					console.error('解析传感器阈值失败:', error);
				}
			}

			// 编译信息
			const infoModel = this.deviceInfo.thingsModels.find(model => model.id === '102#info');
			if (infoModel && infoModel.shadow) {
				try {
					const jsonStr = infoModel.shadow.replace('JSON=', '');
					const data = JSON.parse(jsonStr);
					this.buildVersion = data.versions || '未知版本';
					this.buildTime = data.compile_time || '未知时间';
				} catch (e) {
					this.buildVersion = '未知版本';
					this.buildTime = '未知时间';
				}
			} else {
				this.buildVersion = '未知版本';
				this.buildTime = '未知时间';
			}
		},

		// 3. 同步 mqttPublish 方法，参数结构与电脑版一致，适配移动端
		async mqttPublish(device, model) {

			const command = {};
			command[model.id] = model.shadow;
			const params = {
				deviceId: device.deviceId,
				modelId: model.modelId
			}
			//判断是否有权限
			// const response = await getOrderControl(params);
			// if (response.code != 200) {
			// 	uni.$u.toast(response.msg);
			// 	return;
			// }
			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');
			}
		},
		showAddAudioModal() {
			// 将设备信息存储到本地，供 addProgram 页面使用
			uni.setStorageSync('currentDevice', this.device);
			uni.setStorageSync('currentDeviceInfo', this.deviceInfo);

			uni.navigateTo({
				url: '/pagesA/home/device/status/addProgram'
			});
			console.log('页面跳转');
		},
		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;
				if (data.sound_card && data.sound_card.mp3_list) {
					data.sound_card.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,
					sound_card: {
						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}`
						}
					}
				};

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

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

					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
						};
					} 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.sound_card && data.sound_card.mp3_list) {
										data.sound_card.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.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;
									});

									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 screenEnModel = this.device.thingsModels.find(item => item.id === '102#screenEn');
				if (screenEnModel) {
					screenEnModel.shadow = this.audioEnabled ? '1' : '0';
					await this.mqttPublish(this.device, screenEnModel);
				}
			} 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];
		},
		// 4. 同步 handleStatusChange 方法，更新播放项状态
		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.sound_card && data.sound_card.play_list) {
						data.sound_card.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'
						});
					}
				}
			});
		},
		// testOpenPicker(type) {
		// 	this.pickerShow[type] = true;
		// 	console.log('测试按钮：pickerShow.' + type + ' =', this.pickerShow[type]);
		// },
		// 处理从 addProgram 页面传来的节目数据
		async handleProgramData(data) {
			try {
				if (!this.checkOnline()) return;

				// 1. 找到 progList 物模型
				const progListModel = this.device.thingsModels.find(model => model.id === '102#progList');
				if (!progListModel) {
					uni.showToast({ title: '未找到节目物模型', icon: 'none' });
					return;
				}

				// 2. 解析原有节目列表
				let progListArr = [];
				if (progListModel.shadow) {
					try {
						const jsonStr = progListModel.shadow.replace('JSON=', '');
						const dataJson = JSON.parse(jsonStr);
						if (dataJson.prog_list && Array.isArray(dataJson.prog_list)) {
							progListArr = dataJson.prog_list;
						}
					} catch (e) {}
				}

				// 3. 组装新节目
				const program = data.form;
				const newProgram = {
					order: progListArr.length, // 新增节目order为当前长度
					rem: (program.remark || `自定义节目${Date.now()}`) + '\0',
					dur: parseInt(program.duration) || 10,
					areaM: program.mode,
					aLst: program.zones.map(zone => {
						const area = {
							size: {
								x: parseInt(zone.x) || 0,
								y: parseInt(zone.y) || 0,
								l: parseInt(zone.width) || 32,
								h: parseInt(zone.height) || 64
							},
							pLst: []
						};
						if (zone.playType === 0) {
							area.pLst.push({
								typ: 0,
								txt: {
									str: zone.displayText || '',
									fCn: (zone.font || 0) + 1,
									fS: parseInt((this.fontSizes && this.fontSizes[zone.fontSize]) ? this.fontSizes[zone.fontSize] : 16),
									col: zone.fontColor || 0,
									fW: zone.fontBold || 0,
									stch: zone.fontStretch || 0,
									hPos: zone.hAlign || 1,
									vPos: zone.vAlign || 1
								}
							});
						} else if (zone.playType === 1) {
							area.pLst.push({
								typ: 1,
								img: {
									num: 0,
									col: zone.imageColor || 0,
									w: parseInt((this.imageSizes && this.imageSizes[zone.imageSize]) ? this.imageSizes[zone.imageSize] : 32),
									h: parseInt((this.imageSizes && this.imageSizes[zone.imageSize]) ? this.imageSizes[zone.imageSize] : 32),
									data: ''
								},
								anim: {
									typ: (zone.effect || 0) + 1,
									spd: zone.speed || 4,
									pauseT: 1000,
									playT: 2000
								}
							});
						}
						return area;
					})
				};

				// 4. 添加到原有列表
				progListArr.push(newProgram);

				// 5. 下发
				const progListData = { del_prog: 0, prog_list: progListArr };
				progListModel.shadow = 'JSON=' + JSON.stringify(progListData);
				await this.mqttPublish(this.device, progListModel);

				uni.showToast({ title: '节目设置成功', icon: 'success' });
				this.updateBasicSettings();
			} catch (error) {
				console.error('处理节目数据失败:', error);
				uni.showToast({ title: '设置失败: ' + error.message, icon: 'none' });
			}
		},
		// 新增：开机参数开关下发
		handleBootScreenSwitchChange(val) {
			const bootEnModel = this.device.thingsModels.find(model => model.id === '102#bootEn');
			if (bootEnModel) {
				bootEnModel.shadow = val ? '1' : '0';
				this.mqttPublish(this.device, bootEnModel);
			}
		},
		handleResetSwitchChange(val) {
			const factoryEnModel = this.device.thingsModels.find(model => model.id === '102#factoryEn');
			if (factoryEnModel) {
				factoryEnModel.shadow = val ? '1' : '0';
				this.mqttPublish(this.device, factoryEnModel);
			}
		},
		// 屏幕模板选择逻辑
		handleTemplateChange(val) {
			const template = this.templateColumns.find(t => t.value === val);
			if (template && template.params) {
				const params = template.params;
				// 保证为字符串'1'或'0'，适配u-switch
				this.screenParams.oePolarity = params.oe === 1 ? '1' : (params.oe === 0 ? '0' : '0');
				this.screenParams.dataPolarity = params.data === 1 ? '1' : (params.data === 0 ? '0' : '0');
				this.screenParams.width = params.w;
				this.screenParams.height = params.h;
				this.screenParams.screenRotate = params.angle;
				// 同步旋转label
				const rotateOption = this.screenRotateOptions.find(opt => opt.value == params.angle);
				this.screenParams.screenRotateLabel = rotateOption ? rotateOption.label : '';
			}
		},
		// 下发屏幕参数
		handleSendScreenParams() {
			const model = this.device.thingsModels.find(m => m.id === '102#scrParam');
			if (model) {
				const param = {
					scr_param: {
						oe: this.screenParams.oePolarity,
						data: this.screenParams.dataPolarity,
						w: this.screenParams.width,
						h: this.screenParams.height,
						angle: this.screenParams.screenRotate
					}
				};
				model.shadow = 'JSON=' + JSON.stringify(param);
				this.mqttPublish(this.device, model);
				uni.showToast({ title: '参数已下发', icon: 'success' });
			} else {
				uni.showToast({ title: '未找到屏幕参数物模型', icon: 'none' });
			}
		},
		// 新增原生picker回调
		onNativePickerChange(e) {
			const index = e.detail.value;
			const value = this.templateColumns[index];
			this.screenParams.template = value.value;
			this.screenParams.templateLabel = value.label;
			this.handleTemplateChange(value.value);
		},
		handleSendSensorThreshold() {
			const model = this.device.thingsModels.find(m => m.id === '102#snsrThr');
			if (model) {
				const param = {
					snsr_thr: {
						speed: Number(this.sensorThreshold.speed),
						temp: Number(this.sensorThreshold.temp),
						humi: Number(this.sensorThreshold.humi)
					}
				};
				model.shadow = 'JSON=' + JSON.stringify(param);
				this.mqttPublish(this.device, model);
				uni.showToast({ title: '阈值已下发', icon: 'success' });
			} else {
				uni.showToast({ title: '未找到传感器阈值物模型', icon: 'none' });
			}
		},
		onProgramEnableChange(index, value) {
			// 组装10个元素的使能数组
			const enableArray = new Array(10).fill(0);
			this.audioList.forEach((item, idx) => {
				if (idx < 10) enableArray[idx] = item.enabled ? 1 : 0;
			});
			// 下发到 102#progEn
			const progEnModel = this.device.thingsModels.find(model => model.id === '102#progEn');
			if (progEnModel) {
				const progEnData = { prog_en: enableArray };
				progEnModel.shadow = 'JSON=' + JSON.stringify(progEnData);
				this.mqttPublish(this.device, progEnModel);
			}
		},
		refreshBuildInfo() {
			// 下发102#model=1，设备上报编译信息
			const model = this.device.thingsModels.find(m => m.id === '102#model');
			if (model) {
				model.shadow = '1';
				this.mqttPublish(this.device, model);
				uni.showToast({ title: '已发送刷新指令', icon: 'success' });
			} else {
				uni.showToast({ title: '未找到编译信息物模型', icon: 'none' });
			}
		},
	},
	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>
.voice-control {
	padding: 32rpx;
	background: #f7f9fc;
	min-height: 100vh;
	font-family: 'PingFang SC', 'Helvetica Neue', Arial, sans-serif;

	/* 统一卡片 */
	.card {
		background: #fff;
		border-radius: 24rpx;
		margin-bottom: 32rpx;
		box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, .06);
		overflow: hidden;
		transition: all .3s ease;

		&:active {
			transform: scale(.99);
		}
	}

	/* 标题栏 */
	.status-titletop {
		font-size: 34rpx;
		font-weight: 600;
		color: #2979ff;
		padding: 28rpx 40rpx;
		background: linear-gradient(135deg, #e8f2ff 0%, #f0f7ff 100%);
		border-bottom: 1rpx solid #dceaff;
	}

	.section-title {
		font-size: 34rpx;
		font-weight: 600;
		color: #333;
		padding: 32rpx 40rpx;
		border-bottom: 1rpx solid #f0f2f5;
		background: #fafbff;
		display: flex;
		align-items: center;

		.add-icon {
			width: 48rpx;
			height: 48rpx;
			margin-left: auto;
			transition: transform .2s;

			&:active {
				transform: scale(.85);
			}
		}
	}

	/* 内容区域统一内边距 */
	.info-content {
		padding: 32rpx 40rpx;
	}

	/* 音量滑条 */
	.volume-slider {
		display: flex;
		align-items: center;
		gap: 24rpx;
		padding: 32rpx;
		background: #f8fafc;
		border-radius: 20rpx;
		box-shadow: inset 0 0 0 1rpx #eaeef5;

		.volume-icon image {
			width: 48rpx;
			height: 48rpx;
		}

		.slider-container {
			flex: 1;

			.volume-marks {
				display: flex;
				justify-content: space-between;
				margin-top: 12rpx;
				font-size: 24rpx;
				color: #909399;
			}
		}

		.volume-value {
			min-width: 80rpx;
			text-align: right;
			font-size: 30rpx;
			font-weight: 600;
			color: #2979ff;
		}
	}

	/* 开关行 */
	.audio-switch {
		display: flex;
		justify-content: space-between;
		align-items: center;
		padding: 32rpx;
		background: #f8fafc;
		border-radius: 20rpx;
		margin-bottom: 32rpx;
		box-shadow: inset 0 0 0 1rpx #eaeef5;
		font-size: 30rpx;
		color: #333;
	}

	/* 按钮 */
	.clear-screen-btn-wrap {
		display: flex;
		justify-content: center;
		margin-top: 32rpx;

		::v-deep .u-button {
			width: 70%;
			height: 88rpx;
			font-size: 32rpx;
			border-radius: 44rpx;
			font-weight: 600;
		}
	}

	/* 表单 / 列表 */
	.screen-params-form {
		padding: 32rpx 40rpx;

		::v-deep .u-form-item {
			margin-bottom: 24rpx;

			&__body {
				padding: 24rpx 0;
				border-bottom: 1rpx solid #f0f2f5;

				&__left {
					font-size: 30rpx;
					color: #606266;
				}

				&__right .u-input {
					font-size: 30rpx;
					color: #333;
					text-align: right;
				}
			}
		}
	}

	.list-container {
		padding: 0 40rpx 32rpx;

		.empty-tip {
			display: flex;
			flex-direction: column;
			align-items: center;
			justify-content: center;
			padding: 80rpx 0;
			color: #c0c4cc;
			font-size: 30rpx;
			gap: 24rpx;
		}

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

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

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

				.audio-name {
					font-size: 30rpx;
					color: #333;
					white-space: nowrap;
					overflow: hidden;
					text-overflow: ellipsis;
				}
			}

			.audio-actions {
				display: flex;
				gap: 32rpx;
			}
		}
	}

	.picker-cell {
		background: #fff;
		border-radius: 24rpx;
		box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, .06);
		margin-bottom: 12rpx;
		transition: all .3s ease;

		&:active {
			transform: scale(.99);
		}
	}

	.sensor-threshold {
		background: #fff;
		border-radius: 24rpx;
		margin-bottom: 32rpx;
		box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, .06);
		overflow: hidden;
		transition: all .3s ease;

		.section-title {
			font-size: 34rpx;
			font-weight: 600;
			color: #333;
			padding: 32rpx 40rpx;
			border-bottom: 1rpx solid #f0f2f5;
			background: #fafbff;
			display: flex;
			align-items: center;
		}

		.sensor-form {
			padding: 32rpx 40rpx;

			.u-form-item {
				margin-bottom: 32rpx;
			}

			.u-input {
				background: #f8fafc;
				border-radius: 16rpx;
				padding: 0 20rpx;
				font-size: 30rpx;
				color: #333;
			}

			.u-button {
				width: 70%;
				height: 88rpx;
				font-size: 32rpx;
				border-radius: 44rpx;
				font-weight: 600;
				box-shadow: 0 4rpx 12rpx rgba(41, 121, 255, 0.15);
			}
		}
	}

	.build-info {
		background: #fff;
		border-radius: 24rpx;
		margin-bottom: 32rpx;
		box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, .06);
		overflow: hidden;
		transition: all .3s ease;

		.section-title {
			font-size: 34rpx;
			font-weight: 600;
			color: #333;
			padding: 32rpx 40rpx;
			border-bottom: 1rpx solid #f0f2f5;
			background: #fafbff;
			display: flex;
			align-items: center;
		}

		.info-content {
			padding: 32rpx 40rpx;

			.info-item {
				display: flex;
				align-items: center;
				margin-bottom: 18rpx;

				.info-label {
					font-size: 30rpx;
					color: #606266;
					min-width: 120rpx;
				}

				.info-value {
					font-size: 30rpx;
					color: #333;
				}
			}
		}
	}
}
</style>