<template>
	<view class="container">
		<!-- 状态栏 -->
		<view class="status-bar">
			<view class="status-item">
				<text class="status-label">蓝牙适配器</text>
				<text class="status-value" :class="adapterState.available ? 'available' : ''">
					{{ adapterState.available ? '就绪' : '未就绪' }}
				</text>
			</view>
			<view class="status-item">
				<text class="status-label">打印机</text>
				<text class="status-value" :class="{ connected: connected }">
					{{ connected ? '已连接' : '未连接' }}
				</text>
			</view>
		</view>

		<!-- 蓝牙操作 -->
		<view class="action-section">
			<button type="primary" size="mini" @click="initBluetooth" :disabled="isInitializing">
				{{ isInitializing ? '初始化中...' : '初始化蓝牙' }}
			</button>
			<button v-if="adapterState.available && !adapterState.discovering" type="primary" size="mini" @click="startDiscovery">
				搜索打印机
			</button>
			<button v-if="adapterState.discovering" type="default" size="mini" @click="stopDiscovery">
				停止搜索
			</button>
			<button v-if="connected" type="warn" size="mini" @click="disconnectPrinter">
				断开连接
			</button>
		</view>

		<!-- 设备列表 -->
		<view class="section" v-if="!connected">
			<view class="section-header">
				<text class="section-title">可用设备 ({{ deviceList.length }})</text>
			</view>
			<scroll-view class="device-list" scroll-y>
				<view 
					class="device-item" 
					v-for="device in deviceList" 
					:key="device.deviceId"
					:class="{ connecting: connectingDeviceId === device.deviceId }"
					@click="connectDevice(device)">
					<text class="device-name">{{ device.name || device.localName || '未知设备' }}</text>
					<text class="device-id">{{ device.deviceId }}</text>
					<text class="connect-hint" v-if="connectingDeviceId === device.deviceId">连接中...</text>
				</view>
				<view class="empty-tip" v-if="deviceList.length === 0 && !adapterState.discovering">
					<text>暂无设备，请点击搜索</text>
				</view>
			</scroll-view>
		</view>

		<!-- 打印控制区 -->
		<view class="section print-section" v-else>
			<view class="section-header">
				<text class="section-title">打印控制</text>
				<text class="printer-name">{{ connectedDeviceName }}</text>
			</view>

			<!-- 服务和特征值选择 -->
			<view class="service-select-section" v-if="serviceList.length > 0">
				<view class="section-header">
					<text class="section-title">蓝牙服务配置</text>
					<view class="header-actions">
						<switch :checked="showDebugInfo" @change="toggleDebugInfo" size="mini"/>
						<button size="mini" type="primary" @click="saveCurrentConfig" :disabled="!connected || !writeCharacteristicId">保存配置</button>
					</view>
				</view>
				
				<!-- 当前配置状态 -->
				<view class="current-config">
					<view class="config-item">
						<text class="config-label">服务UUID:</text>
						<text class="config-value" :class="{ active: writeServiceId }">{{ writeServiceId || '未选择' }}</text>
					</view>
					<view class="config-item">
						<text class="config-label">特征值UUID:</text>
						<text class="config-value" :class="{ active: writeCharacteristicId }">{{ writeCharacteristicId || '未选择' }}</text>
					</view>
				</view>

				<!-- 服务列表 -->
				<view class="service-list">
					<text class="list-title">服务列表 ({{ serviceList.length }})</text>
					<scroll-view class="service-scroll" scroll-x>
						<view 
							class="service-tag" 
							v-for="(service, index) in serviceList" 
							:key="index"
							:class="{ selected: selectedService && selectedService.uuid === service.uuid }"
							@click="selectService(service)">
							<text class="service-index">{{ index + 1 }}</text>
							<text class="service-uuid">{{ service.uuid }}</text>
							<text class="service-type">{{ service.isPrimary ? '主' : '从' }}</text>
						</view>
					</scroll-view>
				</view>

				<!-- 特征值列表 -->
				<view class="characteristic-list" v-if="characteristicList.length > 0">
					<text class="list-title">特征值列表 ({{ characteristicList.length }})</text>
					<scroll-view class="characteristic-scroll" scroll-y>
						<view 
							class="characteristic-item" 
							v-for="(char, index) in characteristicList" 
							:key="index"
							:class="{ 
								selected: writeCharacteristicId === char.uuid,
								writable: isWritable(char)
							}"
							@click="selectCharacteristic(char, serviceList.find(s => s.uuid === selectedServiceId))">
							<view class="char-info">
								<text class="char-uuid">{{ char.uuid }}</text>
								<view class="char-props">
									<text class="prop-tag" v-if="char.properties.write">write</text>
									<text class="prop-tag" v-if="char.properties.writeNoResponse">writeNoResp</text>
									<text class="prop-tag" v-if="char.properties.writeWithoutResponse">writeWithoutResp</text>
									<text class="prop-tag" v-if="char.properties.read">read</text>
									<text class="prop-tag" v-if="char.properties.notify">notify</text>
									<text class="prop-tag" v-if="char.properties.indicate">indicate</text>
								</view>
							</view>
							<text class="select-btn">{{ writeCharacteristicId === char.uuid ? '已选择' : '选择' }}</text>
						</view>
					</scroll-view>
				</view>

				<!-- 调试信息 -->
				<view class="debug-info" v-if="showDebugInfo">
					<text class="debug-title">完整服务/特征值信息:</text>
					<view class="debug-content">
						<text class="debug-json" user-select>{{ debugInfo }}</text>
					</view>
				</view>
			</view>

			<!-- 指令模板 -->
			<view class="template-section">
				<text class="template-title">常用指令模板</text>
				<scroll-view class="template-list" scroll-x>
					<view class="template-tags">
						<view 
							class="template-tag" 
							v-for="(template, index) in commandTemplates" 
							:key="index"
							@click="insertTemplate(template)">
							{{ template.name }}
						</view>
					</view>
				</scroll-view>
			</view>

			<!-- 指令类型选择 -->
			<view class="command-type">
				<view class="type-label">指令类型:</view>
				<view class="type-switch">
					<view 
						class="type-btn" 
						:class="{ active: commandType === 'CPCL' }"
						@click="commandType = 'CPCL'">
						CPCL
					</view>
					<view 
						class="type-btn" 
						:class="{ active: commandType === 'TSPL' }"
						@click="commandType = 'TSPL'">
						TSPL
					</view>
					<view 
						class="type-btn" 
						:class="{ active: commandType === 'ESC' }"
						@click="commandType = 'ESC'">
						ESC/POS
					</view>
				</view>
			</view>

			<!-- 指令输入 -->
			<view class="command-input">
				<view class="input-header">
					<text class="input-title">打印指令</text>
					<view class="input-actions">
						<button size="mini" @click="clearCommand">清空</button>
						<button size="mini" type="primary" @click="printCommand">发送打印</button>
					</view>
				</view>
				<textarea 
					class="command-textarea" 
					v-model="commandContent"
					:placeholder="commandPlaceholder"
					:disabled="!connected">
                </textarea>
			</view>

			<!-- 常用参数 -->
			<view class="params-section">
				<text class="params-title">快速参数</text>
				<view class="param-grid">
					<view class="param-item" @click="appendCommand(`TEXT 0 0 30 'Hello'`)">
						<text>文本</text>
					</view>
					<view class="param-item" @click="appendCommand('BARCODE 50 50 \'128\' 30 1 0 2 2 \'123456\'')">
						<text>条码</text>
					</view>
					<view class="param-item" @click="appendCommand('QRCODE 50 100 L 5 0 M2 \'https://\'')">
						<text>二维码</text>
					</view>
					<view class="param-item" @click="appendCommand('LINE 20 20 300 20 3')">
						<text>线条</text>
					</view>
					<view class="param-item" @click="appendCommand('BOX 20 20 300 150 3')">
						<text>方框</text>
					</view>
					<view class="param-item" @click="appendCommand('PRINT')">
						<text>打印</text>
					</view>
				</view>
			</view>

			<!-- 单字节发送 -->
			<view class="byte-section">
				<text class="byte-title">单字节发送</text>
				<view class="byte-row">
					<input class="byte-input" v-model="byteInput" placeholder="如: 48 或 0x30"></input>
					<button size="mini" type="primary" @click="sendByte">发送</button>
				</view>
				<text class="byte-hint">输入十进制(48)或十六进制(0x30)格式</text>
			</view>
		</view>

		<!-- 日志 -->
		<view class="section log-section">
			<view class="section-header">
				<text class="section-title">操作日志</text>
				<button size="mini" @click="clearLog">清空</button>
			</view>
			<scroll-view class="log-list" scroll-y>
				<text class="log-item" 
                    :class="log.type"
                    v-for="(log, index) in logList"
                    :key="index">
					[{{ log.time }}] {{ log.message }}
				</text>
			</scroll-view>
		</view>

	</view>
</template>

<script>
import * as iconv from 'iconv-lite';
export default {
	data() {
		return {
			adapterState: {
				available: false,
				discovering: false
			},
			isInitializing: false,
			deviceList: [],
			connectingDeviceId: '',
			connectedDeviceId: '',
			connectedDeviceName: '',
			connected: false,
			
			// 服务和特征值
			writeCharacteristicId: '',
			writeServiceId: '',
			serviceList: [],
			characteristicList: [],
			selectedService: null,
			selectedServiceId: '',
			showDebugInfo: false,
			debugInfo: '',
			
			// 指令相关
			commandType: 'TSPL',
			commandContent: '',
			byteInput: '',
			
			// 模板
			commandTemplates: [
				{ name: '初始化', command: 'SIZE 50 mm 30 mm\nGAP 2 mm\nDIRECTION 1\n' },
				{ name: '文本打印', command: 'CLS\nTEXT 50 50 "4" 0 1 1 "Hello World"\nPRINT' },
				{ name: '条码打印', command: 'CLS\nBARCODE 50 50 "128" 50 1 0 2 2 "1234567890"\nPRINT' },
				{ name: '二维码打印', command: 'CLS\nQRCODE 50 50 L 5 0 A 0 "https://www.example.com"\nPRINT' },
				{ name: '标签排版', command: 'CLS\nTEXT 20 20 "4" 0 1 1 "商品名称"\nTEXT 20 60 "3" 0 1 1 "价格: ¥99.00"\nBARCODE 20 100 "128" 40 1 0 2 2 "12345678"\nPRINT' },
				{ name: 'CPCL文本', command: '! 0 200 200 240 1\nSIZE 50mm 30mm\nGAP 2 mm\nCENTER\nTEXT 4 0 10 10 EN Test\nTEXT 4 0 10 50 测试中文\nFORM\nPRINT' },
				{ name: 'CPCL条码', command: '! 0 200 200 240 1\nSIZE 50mm 30mm\nGAP 2mm\nENCODING GB18030\nCENTER\nBARCODE 128 1 1 60 1 0 10 40 1234567890\nFORM\nPRINT' },
				{ name: 'CPCL二维码', command: '! 0 200 200 240 1\nSIZE 50mm 30mm\nB QR 300 10 M 2 U 6\nMA,https://www.example.com\nENDQR\nFORM\nPRINT' },
			],
			
			logList: []

		}
	},
	computed: {
		commandPlaceholder() {
			const placeholders = {
				'TSPL': 'TSPL/TSCL 指令，如:\nSIZE 50 mm 30 mm\nGAP 2 mm\nCLS\nTEXT 50 50 "4" 0 1 1 "Hello"\nPRINT',
				'CPCL': 'CPCL 指令，如:\n! U 200\nPAGE-WIDTH 600\nTEXT 0 0 30 "Hello"\nPRINT',
				'ESC': 'ESC/POS 指令，如:\n1B 40 (初始化)\n30 80 (打印文字)\n1B 56 00 (打印并切纸)'
			}
			return placeholders[this.commandType]
		}
	},
	onLoad() {
		this.initBluetooth()
		this.setupListeners()
	},
	onUnload() {
		this.cleanup()
	},
	methods: {
		addLog(message, type = 'info') {
			const now = new Date()
			const time = `${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}:${now.getSeconds().toString().padStart(2, '0')}`
			this.logList.unshift({ time, message, type })
			if (this.logList.length > 100) {
				this.logList.pop()
			}
			console.log(`[BLE Print] ${message}`)
		},
		clearLog() {
			this.logList = []
		},
		setupListeners() {
			uni.onBluetoothAdapterStateChange((res) => {
				this.addLog(`适配器: available=${res.available}, discovering=${res.discovering}`)
				this.adapterState.available = res.available
				this.adapterState.discovering = res.discovering
			})
			uni.onBluetoothDeviceFound((res) => {
				const devices = res.devices || []
				devices.forEach(device => {
					if (!device.name && !device.localName) return
					const index = this.deviceList.findIndex(d => d.deviceId === device.deviceId)
					if (index === -1) {
						this.deviceList.push(device)
						this.addLog(`发现: ${device.name || device.localName}`)
					}
				})
			})
			uni.onBLEConnectionStateChange((res) => {
				if (!res.connected && this.connectedDeviceId === res.deviceId) {
					this.connected = false
					this.connectedDeviceId = ''
					this.connectedDeviceName = ''
					this.addLog('设备已断开', 'warn')
				}
			})
		},
		initBluetooth() {
			if (this.isInitializing) return
			this.isInitializing = true
			this.addLog('初始化蓝牙...')
			uni.openBluetoothAdapter({
				success: (res) => {
					this.adapterState.available = true
					this.isInitializing = false
					this.addLog('蓝牙初始化成功')
					this.getKnownDevices()
				},
				fail: (err) => {
					this.isInitializing = false
					this.adapterState.available = false
					this.addLog(`初始化失败: ${err.errMsg}`, 'error')
				}
			})
		},
		getKnownDevices() {
			uni.getBluetoothDevices({
				success: (res) => {
					if (res.devices && res.devices.length > 0) {
						this.deviceList = res.devices.filter(d => d.name || d.localName)
					}
				}
			})
		},
		startDiscovery() {
			if (this.adapterState.discovering) return
			this.deviceList = []
			this.addLog('开始搜索...')
			uni.startBluetoothDevicesDiscovery({
				allowDuplicatesKey: true,
				success: () => {
					this.adapterState.discovering = true
					this.addLog('搜索中...')
					setTimeout(() => {
						if (this.adapterState.discovering) {
							this.stopDiscovery()
						}
					}, 15000)
				},
				fail: (err) => {
					this.addLog(`搜索失败: ${err.errMsg}`, 'error')
				}
			})
		},
		stopDiscovery() {
			uni.stopBluetoothDevicesDiscovery({
				success: () => {
					this.adapterState.discovering = false
					this.addLog('已停止搜索')
				}
			})
		},
		connectDevice(device) {
			if (this.connected) return
			this.connectingDeviceId = device.deviceId
			this.addLog(`连接 ${device.name || device.localName}...`)
			uni.createBLEConnection({
				deviceId: device.deviceId,
				timeout: 10000,
				success: () => {
					this.connected = true
					this.connectedDeviceId = device.deviceId
					this.connectedDeviceName = device.name || device.localName
					this.connectingDeviceId = ''
					this.addLog('连接成功')
					this.getPrinterServices()
				},
				fail: (err) => {
					this.connectingDeviceId = ''
					this.addLog(`连接失败: ${err.errMsg}`, 'error')
				}
			})
		},
		disconnectPrinter() {
			if (!this.connectedDeviceId) return
			this.addLog('断开连接...')
			uni.closeBLEConnection({
				deviceId: this.connectedDeviceId,
				success: () => {
					this.connected = false
					this.connectedDeviceId = ''
					this.connectedDeviceName = ''
					this.serviceList = []
					this.characteristicList = []
					this.addLog('已断开')
				},
				fail: (err) => {
					this.addLog(`断开失败: ${err.errMsg}`, 'error')
				}
			})
		},
		getPrinterServices() {
			this.addLog('获取服务...')
			uni.getBLEDeviceServices({
				deviceId: this.connectedDeviceId,
				success: (res) => {
					this.serviceList = res.services
					this.addLog(`找到 ${res.services.length} 个服务`)
					// 自动选择第一个主服务
					const primaryService = res.services.find(s => s.isPrimary)
					if (primaryService) {
						this.selectService(primaryService)
					}
				},
				fail: (err) => {
					this.addLog(`获取服务失败: ${err.errMsg}`, 'error')
				}
			})
		},
		selectService(service) {
			this.selectedService = service
			this.selectedServiceId = service.uuid
			this.addLog(`选择服务: ${service.uuid}`)
			uni.getBLEDeviceCharacteristics({
				deviceId: this.connectedDeviceId,
				serviceId: service.uuid,
				success: (res) => {
                    console.log(res)
					this.characteristicList = res.characteristics
					// 更新调试信息
					this.debugInfo = JSON.stringify({
						service: service,
						characteristics: res.characteristics
					}, null, 2)
					// 查找可写特征值
					const writableChar = res.characteristics.find(c => c.properties.write)
					if (writableChar) {
						this.writeCharacteristicId = writableChar.uuid
						this.writeServiceId = service.uuid
						this.addLog(`可写特征值: ${writableChar.uuid}`)
					} else {
						// 尝试找可写无响应的
						const writeNoRespChar = res.characteristics.find(c => c.properties.writeNoResponse)
						if (writeNoRespChar) {
							this.writeCharacteristicId = writeNoRespChar.uuid
							this.writeServiceId = service.uuid
							this.addLog(`可写特征值(writeNoResp): ${writeNoRespChar.uuid}`)
						} else {
							// 尝试 writeWithoutResponse
							const writeWithoutRespChar = res.characteristics.find(c => c.properties.writeWithoutResponse)
							if (writeWithoutRespChar) {
								this.writeCharacteristicId = writeWithoutRespChar.uuid
								this.writeServiceId = service.uuid
								this.addLog(`可写特征值(writeWithoutResp): ${writeWithoutRespChar.uuid}`)
							} else {
								// 没有找到可写特征值，列出所有特征值的属性
								const props = res.characteristics.map(c => ({
									uuid: c.uuid,
									props: c.properties
								}))
								this.addLog(`未找到可写特征值，特征值数: ${res.characteristics.length}`, 'warn')
							}
						}
					}
				},
				fail: (err) => {
					this.addLog(`获取特征值失败: ${err.errMsg}`, 'error')
				}
			})
		},
		selectCharacteristic(char, service) {
			if (!service) {
				this.addLog('请先选择服务', 'warn')
				return
			}
			// 检查是否有任何可写属性
			if (!this.isWritable(char)) {
				this.addLog('该特征值无可写属性', 'warn')
				return
			}
			this.writeCharacteristicId = char.uuid
			this.writeServiceId = service.uuid
			this.addLog(`已选择特征值: ${char.uuid}`)
			uni.showToast({ title: '特征值已选择', icon: 'success' })
		},
		isWritable(char) {
			return char.properties && (
				char.properties.write || 
				char.properties.writeNoResponse || 
				char.properties.writeWithoutResponse
			)
		},
		toggleDebugInfo(e) {
			this.showDebugInfo = e.detail.value
		},
		insertTemplate(template) {
			this.commandContent = template.command
			this.addLog(`已插入模板: ${template.name}`)
		},
		appendCommand(cmd) {
			if (this.commandContent) {
				this.commandContent += '\n' + cmd
			} else {
				this.commandContent = cmd
			}
		},
		clearCommand() {
			this.commandContent = ''
		},
		printCommand() {
			if (!this.connected) {
				uni.showToast({ title: '请先连接打印机', icon: 'none' })
				return
			}
			if (!this.commandContent.trim()) {
				uni.showToast({ title: '请输入打印指令', icon: 'none' })
				return
			}
			if (!this.writeCharacteristicId) {
				uni.showToast({ title: '未找到可写特征值', icon: 'none' })
				return
			}
			const buffer = this.stringToBuffer(this.commandContent)
			this.addLog(`发送指令 (${buffer.byteLength} bytes)`)
			uni.writeBLECharacteristicValue({
				deviceId: this.connectedDeviceId,
				serviceId: this.writeServiceId,
				characteristicId: this.writeCharacteristicId,
				value: buffer,
				writeType: 'writeNoResponse',
				success: () => {
					this.addLog('发送成功', 'success')
					uni.showToast({ title: '发送成功', icon: 'success' })
				},
				fail: (err) => {
					this.addLog(`发送失败: ${err.errMsg}`, 'error')
					uni.showToast({ title: '发送失败', icon: 'none' })
				}
			})
		},
		sendByte() {
			if (!this.connected || !this.writeCharacteristicId) {
				uni.showToast({ title: '请先连接打印机', icon: 'none' })
				return
			}
			if (!this.byteInput.trim()) {
				uni.showToast({ title: '请输入字节值', icon: 'none' })
				return
			}
			let byteValue
			const input = this.byteInput.trim()
			if (input.startsWith('0x') || input.startsWith('0X')) {
				byteValue = parseInt(input, 16)
			} else {
				byteValue = parseInt(input, 10)
			}
			if (isNaN(byteValue) || byteValue < 0 || byteValue > 255) {
				uni.showToast({ title: '请输入0-255的有效值', icon: 'none' })
				return
			}
			const buffer = new ArrayBuffer(1)
			const dataView = new DataView(buffer)
			dataView.setUint8(0, byteValue)
			this.addLog(`发送字节: ${byteValue} (0x${byteValue.toString(16).padStart(2, '0')})`)
			uni.writeBLECharacteristicValue({
				deviceId: this.connectedDeviceId,
				serviceId: this.writeServiceId,
				characteristicId: this.writeCharacteristicId,
				value: buffer,
				writeType: 'writeNoResponse',
				success: () => {
					this.addLog('字节发送成功', 'success')
				},
				fail: (err) => {
					this.addLog(`发送失败: ${err.errMsg}`, 'error')
				}
			})
		},
		// stringToBuffer(str) {
		// 	const buffer = new ArrayBuffer(str.length)
		// 	const dataView = new DataView(buffer)
		// 	for (let i = 0; i < str.length; i++) {
		// 		dataView.setUint8(i, str.charCodeAt(i))
		// 	}
		// 	return buffer
		// },
		stringToBuffer(str) {
			try {
				// 尝试使用 TextEncoder（UTF-8 编码）
				// const encoder = new TextEncoder()
				// const uint8Array = encoder.encode(str)
				// return uint8Array.buffer

				// 使用 iconv-lite 将字符串编码为 GBK 格式的字节数组
				// 这是一个 Uint8Array，需要转换成 writeBLECharacteristicValue 需要的 ArrayBuffer
				const uint8Array = iconv.encode(str, 'gbk');
				// 核心：转换为 ArrayBuffer
				return uint8Array.buffer;
			} catch (e) {
				console.warn('TextEncoder 不可用，使用回退方案', e)
				// 回退到原来的简单编码（可能仍有乱码）
				const buffer = new ArrayBuffer(str.length)
				const dataView = new DataView(buffer)
				for (let i = 0; i < str.length; i++) {
					dataView.setUint8(i, str.charCodeAt(i) & 0xFF) // 只取低8位
				}
				return buffer
			}
		},

		cleanup() {
			if (this.connected) {
				this.disconnectPrinter()
			}
			if (this.adapterState.discovering) {
				this.stopDiscovery()
			}
		},
		saveCurrentConfig() {
			if (!this.connected) {
				uni.showToast({ title: '请先连接打印机', icon: 'none' })
				return
			}
			if (!this.writeServiceId || !this.writeCharacteristicId) {
				uni.showToast({ title: '请先选择服务和特征值', icon: 'none' })
				return
			}
			const config = {
				deviceId: this.connectedDeviceId,
				serviceId: this.writeServiceId,
				writeCharId: this.writeCharacteristicId,
				deviceName: this.connectedDeviceName,
				lastUpdated: new Date().toISOString()
			}
			uni.setStorageSync('printerConfig', config)
			this.addLog(`配置已保存: ${this.connectedDeviceName}`, 'success')
			uni.showToast({
				title: '配置已保存',
				icon: 'success',
				duration: 2000
			})
		}
	}
}
</script>

<style scoped>
.container {
	padding: 20rpx;
	background: #f5f5f5;
	min-height: 100vh;
}
.status-bar {
	display: flex;
	background: #fff;
	padding: 20rpx;
	border-radius: 12rpx;
	margin-bottom: 20rpx;
}
.status-item {
	flex: 1;
	display: flex;
	flex-direction: column;
	align-items: center;
}
.status-label {
	font-size: 24rpx;
	color: #999;
	margin-bottom: 8rpx;
}
.status-value {
	font-size: 28rpx;
	font-weight: bold;
	color: #666;
}
.status-value.available {
	color: #007aff;
}
.status-value.connected {
	color: #34c759;
}
.action-section {
	display: flex;
	gap: 16rpx;
	margin-bottom: 20rpx;
	flex-wrap: wrap;
}
.action-section button {
	flex: 1;
	min-width: 150rpx;
}
.section {
	background: #fff;
	border-radius: 12rpx;
	padding: 20rpx;
	margin-bottom: 20rpx;
}
.header-actions {
	display: flex;
	align-items: center;
	gap: 16rpx;
}
.section-header {
	display: flex;
	justify-content: space-between;
	align-items: center;
	margin-bottom: 16rpx;
}
.section-title {
	font-size: 30rpx;
	font-weight: bold;
	color: #333;
}
.printer-name {
	font-size: 24rpx;
	color: #34c759;
}
.device-list {
	max-height: 300rpx;
}
.device-item {
	padding: 24rpx;
	border-bottom: 1rpx solid #eee;
}
.device-item:active {
	background: #f5f5f5;
}
.device-item.connecting {
	background: #e8f4ff;
}
.device-name {
	font-size: 28rpx;
	font-weight: bold;
	color: #333;
	display: block;
}
.device-id {
	font-size: 22rpx;
	color: #999;
	word-break: break-all;
}
.connect-hint {
	font-size: 24rpx;
	color: #007aff;
}
.empty-tip {
	text-align: center;
	padding: 40rpx;
	color: #999;
}
.print-section {
	min-height: 600rpx;
}
.template-section {
	margin-bottom: 20rpx;
}
.template-title {
	font-size: 26rpx;
	color: #666;
	margin-bottom: 12rpx;
	display: block;
}
.template-list {
	width: 100%;
}
.template-tags {
	display: flex;
	gap: 12rpx;
	padding: 4rpx;
}
.template-tag {
	padding: 12rpx 24rpx;
	background: #f0f0f0;
	border-radius: 8rpx;
	font-size: 24rpx;
	color: #333;
	white-space: nowrap;
}
.template-tag:active {
	background: #e0e0e0;
}
.command-type {
	display: flex;
	align-items: center;
	margin-bottom: 16rpx;
}
.type-label {
	font-size: 26rpx;
	color: #666;
	margin-right: 16rpx;
}
.type-switch {
	display: flex;
	border: 1rpx solid #007aff;
	border-radius: 8rpx;
	overflow: hidden;
}
.type-btn {
	padding: 12rpx 24rpx;
	font-size: 24rpx;
	color: #007aff;
	background: #fff;
}
.type-btn.active {
	background: #007aff;
	color: #fff;
}
.command-input {
	margin-bottom: 20rpx;
}
.input-header {
	display: flex;
	justify-content: space-between;
	align-items: center;
	margin-bottom: 12rpx;
}
.input-title {
	font-size: 26rpx;
	color: #666;
}
.input-actions {
	display: flex;
	gap: 12rpx;
}
.command-textarea {
	width: 100%;
	height: 200rpx;
	border: 1rpx solid #ddd;
	border-radius: 8rpx;
	padding: 16rpx;
	font-size: 26rpx;
	font-family: 'Courier New', monospace;
	box-sizing: border-box;
}
.params-section {
	margin-bottom: 20rpx;
}
.params-title {
	font-size: 26rpx;
	color: #666;
	margin-bottom: 12rpx;
	display: block;
}
.param-grid {
	display: flex;
	flex-wrap: wrap;
	gap: 12rpx;
}
.param-item {
	padding: 16rpx 24rpx;
	background: #f0f0f0;
	border-radius: 8rpx;
}
.param-item:active {
	background: #e0e0e0;
}
.param-item text {
	font-size: 24rpx;
	color: #333;
}
.byte-section {
	padding-top: 16rpx;
	border-top: 1rpx solid #eee;
}
.byte-title {
	font-size: 26rpx;
	color: #666;
	margin-bottom: 12rpx;
	display: block;
}
.byte-row {
	display: flex;
	gap: 12rpx;
	margin-bottom: 8rpx;
}
.byte-input {
	flex: 1;
	border: 1rpx solid #ddd;
	border-radius: 8rpx;
	padding: 12rpx 16rpx;
	font-size: 26rpx;
}
.byte-hint {
	font-size: 22rpx;
	color: #999;
}
.log-section {
	min-height: 200rpx;
}
.log-list {
	height: 250rpx;
	background: #1c1c1c;
	border-radius: 8rpx;
	padding: 16rpx;
}
.log-item {
	display: block;
	font-size: 22rpx;
	font-family: 'Courier New', monospace;
	color: #fff;
	margin-bottom: 8rpx;
	line-height: 1.4;
}
.log-item.success {
	color: #34c759;
}
.log-item.warn {
	color: #ff9500;
}
.log-item.error {
	color: #ff3b30;
}
/* 服务选择区域 */
.service-select-section {
	margin-bottom: 20rpx;
	padding: 16rpx;
	background: #f8f8f8;
	border-radius: 8rpx;
}
.current-config {
	padding: 16rpx;
	background: #fff;
	border-radius: 8rpx;
	margin-bottom: 16rpx;
}
.config-item {
	display: flex;
	margin-bottom: 8rpx;
}
.config-label {
	font-size: 24rpx;
	color: #666;
	min-width: 140rpx;
}
.config-value {
	font-size: 24rpx;
	color: #999;
	font-family: 'Courier New', monospace;
	word-break: break-all;
	flex: 1;
}
.config-value.active {
	color: #34c759;
}
.service-list {
	margin-bottom: 16rpx;
}
.list-title {
	font-size: 26rpx;
	color: #333;
	margin-bottom: 12rpx;
	display: block;
	font-weight: bold;
}
.service-scroll {
	width: 100%;
	white-space: nowrap;
}
.service-tag {
	display: inline-flex;
	align-items: center;
	padding: 12rpx 20rpx;
	background: #fff;
	border: 2rpx solid #ddd;
	border-radius: 8rpx;
	margin-right: 16rpx;
	white-space: nowrap;
}
.service-tag.selected {
	border-color: #007aff;
	background: #e8f4ff;
}
.service-index {
	font-size: 24rpx;
	color: #007aff;
	font-weight: bold;
	margin-right: 12rpx;
}
.service-uuid {
	font-size: 22rpx;
	font-family: 'Courier New', monospace;
	color: #333;
	max-width: 300rpx;
	overflow: hidden;
	text-overflow: ellipsis;
}
.service-type {
	font-size: 20rpx;
	color: #fff;
	background: #34c759;
	padding: 4rpx 8rpx;
	border-radius: 4rpx;
	margin-left: 12rpx;
}
.characteristic-list {
	margin-bottom: 16rpx;
}
.characteristic-scroll {
	max-height: 300rpx;
	background: #fff;
	border-radius: 8rpx;
}
.characteristic-item {
	display: flex;
	justify-content: space-between;
	align-items: center;
	padding: 16rpx;
	border-bottom: 1rpx solid #eee;
}
.characteristic-item:last-child {
	border-bottom: none;
}
.characteristic-item.selected {
	background: #e8f4ff;
}
.characteristic-item.writable {
	border-left: 4rpx solid #34c759;
}
.char-info {
	flex: 1;
}
.char-uuid {
	font-size: 24rpx;
	font-family: 'Courier New', monospace;
	color: #333;
	display: block;
	margin-bottom: 8rpx;
	word-break: break-all;
}
.char-props {
	display: flex;
	flex-wrap: wrap;
	gap: 8rpx;
}
.prop-tag {
	font-size: 20rpx;
	padding: 4rpx 8rpx;
	background: #f0f0f0;
	border-radius: 4rpx;
	color: #666;
}
.select-btn {
	font-size: 24rpx;
	color: #007aff;
	padding: 8rpx 16rpx;
}
.debug-info {
	margin-top: 16rpx;
}
.debug-title {
	font-size: 24rpx;
	color: #666;
	margin-bottom: 8rpx;
	display: block;
}
.debug-content {
	background: #1c1c1c;
	border-radius: 8rpx;
	padding: 16rpx;
	max-height: 300rpx;
	overflow-y: auto;
}
.debug-json {
	font-size: 20rpx;
	font-family: 'Courier New', monospace;
	color: #fff;
	white-space: pre-wrap;
	word-break: break-all;
}
</style>
