<template>
  <view class="bluetooth-container">
    <!-- 蓝牙状态显示 -->
    <view class="status-section">
      <text class="status-title">蓝牙状态:</text>
      <text class="status-value" :class="{'enabled': bluetoothEnabled}">
        {{ bluetoothEnabled ? '已开启' : '未开启' }}
      </text>
      <text class="connection-status" :class="{'connected': connected}">
        {{ connected ? '已连接' : '未连接' }}
      </text>
    </view>
		<!-- 已连接蓝牙名称显示 -->
		<view class="status-section" v-show="connected">
			<view>
				<text class="status-title">已连接:</text>
				<text class="connected">
					{{ currentDevice ? currentDevice.name : '' }}
				</text>
			</view>
			<view class="status-botton">
				<button size="mini" @click="reConnectDeivce">
					重新连接
				</button>
				<button size="mini" @click="disconnectDevice">
					断开连接
				</button>
				<button size="mini" @click="showMTUSetting" v-if="isBleDevice">
					设置MTU
				</button>
			</view>
		</view>

    <!-- 蓝牙控制按钮 -->
    <view class="control-section">
      <button size="mini" class="btn" @click="toggleBluetooth" :disabled="processing">
        {{ bluetoothEnabled ? '关闭蓝牙' : '开启蓝牙' }}
      </button>
      <button size="mini" class="btn" @click="startScan" :disabled="!bluetoothEnabled || scanning">
        {{ scanning ? '扫描中...' : '扫描设备' }}
      </button>
      <button size="mini" class="btn" @click="stopScan" :disabled="!scanning">
        停止扫描
      </button>
    </view>

    <!-- 设备列表 -->
    <view class="devices-section"  v-show="scanning">
      <text class="section-title">设备列表</text>
      <scroll-view class="devices-list" scroll-y>
        <view 
          v-for="device in devices" 
          :key="device.deviceId + device.type"
          class="device-item"
          @click="connectDevice(device)"
        >
          <text class="device-name">
						{{ device.name }}
						<text class="device-type">{{ device.type ? showDeviceType(device.type) : '' }}</text>
					</text>
          <text class="device-address">{{ device.deviceId}}</text>
        </view>
      </scroll-view>
    </view>

		<!-- 打印次数 -->
		<view class="data-section" v-if="connected">
      <text class="section-title">打印张数</text>
			<view class="input-area">
				<button size="mini" @click="decrease" :disabled="printCount <= 1">-</button>
				{{ printCount }}
				<button size="mini" @click="increase" :disabled="printCount >= 10">+</button>
			</view>
		</view>
		
    <!-- 数据收发区域 -->
    <view class="data-section" v-if="connected">
      <text class="section-title">数据收发</text>
			<view class="input-area">
				<button size="mini" class="btn" :disabled="!connected" @click="createLabel">条码指令</button>
				<button size="mini" style="margin-left: 10px;" class="btn" :disabled="!connected"
					@click="chooseLabelImg">本地图片</button>
				<button size="mini" style="margin-left: 10px;" class="btn" :disabled="!connected"
					@click="chooseAndroidPdf">本地PDF</button>
				<button size="mini" style="margin-left: 10px;" class="btn" :disabled="!connected"
					@click="chooseBase64">Base64</button>
			</view>
			<view class="input-area">
				<button :disabled="!connected" size="mini" type="default" @click="sendDataToDevice()">发送打印{{progress}}</button>
			</view>
			<!-- 网络图片URL打印 start -->
			<view class="input-section">
				<text class="section-title">图片URL:</text>
				<input 
					v-model="imageUrl" 
					placeholder="输入图片链接" 
					class="url-input"
					@confirm="chooseRemoteImg"
				/>
				<button size="mini" class="btn" @click="chooseRemoteImg" :disabled="!imageUrl || loading">
					{{ loading ? '处理中...' : '打印远程图片' }}
				</button>
			</view>
			<!-- 网络图片URL打印 end -->
    </view>

    <!-- 日志区域 -->
    <view class="log-section">
      <text class="section-title">操作日志</text>
      <scroll-view class="log-content" scroll-y>
        <text 
          v-for="(log, index) in logs" 
          :key="index"
          class="log-item"
        >
          {{ log }}
        </text>
      </scroll-view>
    </view>
		
		<!-- canvas图片 -->
		<view class="image-canvas">
			<canvas canvas-id="myCanvas" :style="{ width: canvasW + 'px', height: canvasH + 'px' }" id="myCanvas"></canvas>
		</view>
  </view>
</template>

<script>
const tsc = require('../../components/gprint/tsc.js')
const esc = require('../../components/gprint/esc.js')
const base64Data = require('../../components/data/base64Data.js')
// 引入经典蓝牙工具
const classicBluetooth = require('../../components/gprint/bluetoothTool.js');

export default {
  data() {
    return {
      // 蓝牙状态
      bluetoothEnabled: false,
      connected: false,
      scanning: false,
      processing: false,
      // 设备相关
      devices: [],
      currentDevice: null,
      // 数据相关
      sendData: null, // 字节数组
			canvasW: 320, // 画布宽度
			canvasH: 320, // 画布高度
      // 日志
      logs: [],
      // 蓝牙类型检测
      isBleDevice: false,
      bleDevices: [],
      classicDevices: [],
			bleMTU: 20, // 蓝牙每次传的数据长度，需要根据打印机性能来设置：22~512
			progress: '' ,// 下发数据进度,
			imageUrl: 'https://www.poscom.cn/demo/qrcode.jpg', // 远程默认测试图片
			loading: false,
			printCount: 1 // 打印次数
    };
  },
  
  onLoad() {
    this.initBluetooth();
  },
  
  onUnload() {
    this.disconnectDevice();
  },
  
  methods: {
		decrease() {
			if (this.printCount > 1) {
				this.printCount--
			}
		},
		increase() {
			if (this.printCount < 10) {
				this.printCount++
			}
		},
		// 显示MTU设置弹窗
		showMTUSetting() {
			uni.showModal({
				title: '设置MTU值',
				editable: true,
				placeholderText: '请输入MTU值(20-220)',
				content: this.bleMTU.toString(),
				success: (res) => {
					if (res.confirm && res.content) {
						this.setBLEMTU(res.content);
					}
				}
			});
		},
		
		// 设置BLE MTU值
		setBLEMTU(value) {
			const mtuValue = parseInt(value);
			
			// 验证MTU值范围
			if (isNaN(mtuValue) || mtuValue < 22 || mtuValue > 512) {
				uni.showToast({
					title: 'MTU值必须在22-512之间',
					icon: 'none',
					duration: 2000
				});
				return;
			}
			
			if (!this.connected || !this.isBleDevice || !this.currentDevice) {
				uni.showToast({
					title: '请先连接低功耗蓝牙设备',
					icon: 'none',
					duration: 2000
				});
				return;
			}
			
			this.addLog(`正在设置MTU值: ${mtuValue}`);
			
			// #ifdef APP-PLUS
			uni.setBLEMTU({
				deviceId: this.currentDevice.deviceId,
				mtu: mtuValue,
				success: (res) => {
					this.bleMTU = mtuValue;
					this.addLog(`MTU设置成功: ${mtuValue}`);
					uni.showToast({
						title: "MTU设置成功",
						duration: 2000
					});
				},
				fail: (err) => {
					this.addLog(`MTU设置失败: ${err.errMsg}`);
					uni.showToast({
						title: `MTU设置失败: ${err.errMsg}`,
						icon: 'none',
						duration: 2000
					});
				}
			});
			// #endif
			
			// #ifndef APP-PLUS
			this.addLog('当前平台不支持设置MTU');
			uni.showToast({
				title: '当前平台不支持设置MTU',
				icon: 'none',
				duration: 2000
			});
			// #endif
		},
				
    // 初始化蓝牙
    initBluetooth() {
			this.initBleBluetooth();
			this.initClassicBluetooth();
		},
		
		// 初始化经典蓝牙
		initClassicBluetooth() {
			var that = this;
      classicBluetooth.init({
        listenBTStatusCallback: (state) => {
          that.addLog(`经典蓝牙状态: ${state}`);
          that.bluetoothEnabled = classicBluetooth.state.bluetoothEnable;
					if(state == 'STATE_ON') {
						let lastBleDevice = uni.getStorageSync('lastBleDevice')
						if(lastBleDevice) {
							that.currentDevice = JSON.parse(lastBleDevice)
							that.connectDevice(that.currentDevice);
						}
						// 蓝牙开启时获取已配对设备
						that.getPairedDevices();
					}
        },
        discoveryDeviceCallback: (newDevice) => {
					if(newDevice != null && newDevice.name != "" && newDevice.name != '未知设备') {
						this.addLog(`发现蓝牙设备: ${newDevice.name}`);
						const device = {
						  ...newDevice
						};
						this.addDevice(device);
					}
        },
        discoveryFinishedCallback: () => {
          this.addLog('蓝牙扫描完成');
          this.scanning = false;
        },
        readDataCallback: (dataByteArr) => {
          const data = this.bytesToString(dataByteArr);
          this.addLog(`收到蓝牙数据: ${data}`);
        },
        connExceptionCallback: (e) => {
          this.addLog(`蓝牙连接异常: ${e}`);
          this.connected = false;
        }
      });
    },
    
		// 初始化低功耗蓝牙
		initBleBluetooth() {
			// 检查是否支持低功耗蓝牙
			this.checkBleSupport();
			this.openBleAdapter();
		},
				
    // 检查低功耗蓝牙支持
    checkBleSupport() {
      // #ifdef APP-PLUS
      if (uni.createBLEConnection) {
        this.addLog('设备支持低功耗蓝牙');
      } else {
        this.addLog('设备不支持低功耗蓝牙');
      }
      // #endif
    },
    
    // 切换蓝牙开关
    toggleBluetooth() {
      this.processing = true;
      
      if (this.bluetoothEnabled) {
        // 关闭蓝牙
        classicBluetooth.turnOffBluetooth();
        this.closeBleConnection();
        this.bluetoothEnabled = false;
        this.connected = false;
        this.devices = [];
        this.addLog('蓝牙已关闭');
      } else {
        // 开启蓝牙
        classicBluetooth.turnOnBluetooth();
        
        this.addLog('蓝牙已开启');
      }
      
      setTimeout(() => {
        this.processing = false;
      }, 1000);
    },
    
    // 开启低功耗蓝牙适配器
    openBleAdapter() {
      // #ifdef APP-PLUS
      uni.openBluetoothAdapter({
        success: (res) => {
          this.addLog('低功耗蓝牙适配器开启成功');
          this.bluetoothEnabled = true;
        },
        fail: (err) => {
          this.addLog(`低功耗蓝牙适配器开启失败: ${err.errMsg}`);
        }
      });
      // #endif
    },
    
    // 开始扫描设备
    startScan() {
      this.devices = [];
      this.scanning = true;
      this.addLog('开始扫描设备...');
      
      // 扫描经典蓝牙设备
      classicBluetooth.discoveryNewDevice();
      // 扫描已配对设备
      this.getPairedDevices();
      // 扫描低功耗蓝牙设备
      this.startBleScan();
    },
    
    // 停止扫描
    stopScan() {
      this.scanning = false;
      classicBluetooth.cancelDiscovery();
      this.stopBleScan();
      this.addLog('停止扫描设备');
    },
		// 获取已配对设备
		getPairedDevices() {
		  try {
		    const pairedDevices = classicBluetooth.getPairedDevices();
				console.log(">>> getPairedDevices", pairedDevices)
		    this.addLog(`找到 ${pairedDevices.length} 个已配对设备`);
		    
		    pairedDevices.forEach(device => {
		      // 标记为已配对设备
		      const pairedDevice = {
		        ...device
		      };
		      this.addDevice(pairedDevice);
		    });
		  } catch (error) {
		    this.addLog(`获取已配对设备失败: ${error}`);
		  }
		},
    
    // 开始低功耗蓝牙扫描
    startBleScan() {
      // #ifdef APP-PLUS
      uni.startBluetoothDevicesDiscovery({
        services: [],
        allowDuplicatesKey: false,
        success: (res) => {
          this.addLog('低功耗蓝牙扫描开始');
          
          // 监听寻找到新设备的事件
          uni.onBluetoothDeviceFound((res) => {
            res.devices.forEach(device => {
              if (device != null && device.name != "" && device.name != '未知设备') {
                const newDevice = {
                  ...device,
                  type: 'ble'
                };
                this.addLog(`发现低功耗蓝牙设备: ${device.name}`);
                this.addDevice(newDevice);
              }
            });
          });
        },
        fail: (err) => {
          this.addLog(`低功耗蓝牙扫描失败: ${err.errMsg}`);
        }
      });
      // #endif
    },
    
    // 停止低功耗蓝牙扫描
    stopBleScan() {
      // #ifdef APP-PLUS
      uni.stopBluetoothDevicesDiscovery({
        success: (res) => {
          this.addLog('低功耗蓝牙扫描停止');
        }
      });
      // #endif
    },
    
		// 生成设备唯一key
		generateDeviceKey(device) {
		  return `${device.deviceId}-${device.type || 'unknown'}`;
		},
		
		/**
		 * @param {Object} device
		 */
		showDeviceType(type) {
			switch(type) {
				case 'ble': return '低功耗蓝牙'; break;
				case 'classic': return '经典蓝牙'; break;
				case 'dual': return '双模'; break;
				default: return '未知'
			}
		},
		/**
		 * 设备类型判断
		 */
		getDeviceConnectType(device) {
			console.log(">>> getDeviceConnectType", device)
			const { type, name, deviceId } = device;
			// 非双模设备直接返回
			if (type.toLowerCase() !== 'dual') {
				return type;
			}
			// 检查名称中的BLE标识
			if (name.toUpperCase().includes('BLE')) {
					return 'ble';
			}
			// 检查MAC地址
			if (deviceId) {
					const mac = deviceId.replace(/:/g, '').toUpperCase();
					if (mac.length === 12) {
							const secondChar = mac[1];
							// 随机MAC地址的第二个字符通常是2,6,A,E
							if (['2', '6', 'A', 'E'].includes(secondChar)) {
									return 'ble';
							}
					}
			}
			return "classic";
		},
		
    // 添加设备到列表（去重）
    addDevice(newDevice) {
			// 生成唯一标识符
			const deviceKey = this.generateDeviceKey(newDevice);
			
			// 检查是否已存在
			const existingIndex = this.devices.findIndex(device => 
				this.generateDeviceKey(device) === deviceKey
			);
			//console.log(">>> addDevice.newDevice", existingIndex, newDevice)
    
      if (existingIndex === -1) {
        this.devices.push(newDevice);
      } else {
				// 更新已存在设备的信息
				const existingDevice = this.devices[existingIndex];
				this.devices[existingIndex] = { 
					...existingDevice, 
					...newDevice
				};
			}
    },
    
    // 连接设备
    connectDevice(device) {
      this.processing = true;
			console.log("connectDevice", device)
      this.addLog(`正在连接设备: ${device.name}`);
      uni.showLoading({
				title: '正在连接...'
			})
			// 确定连接类型
			const connectType = this.getDeviceConnectType(device);
			this.addLog(`确定使用 ${connectType} 模式连接`);
      if (connectType === 'ble') {
        this.connectBleDevice(device);
      } else {
        this.connectClassicDevice(device);
      }
			this.stopScan();
			uni.hideLoading();
    },
		
		// 重新连接设备
		reConnectDeivce() {
			let lastBleDevice = uni.getStorageSync('lastBleDevice');
			if(!lastBleDevice) {
				uni.showToast({
					title: '设备信息不存在',
					duration: 1500
				});
				return;
			}
			console.log(">>> reConnectDeivce.lastBleDevice", lastBleDevice)
			let device = JSON.parse(lastBleDevice);
			this.processing = true;
			this.addLog(`正在重新连接设备: ${device.name}`);
			if (device.type === 'ble') {
			  this.connectBleDevice(device);
			} else {
			  this.connectClassicDevice(device);
			}
		},
    
    // 连接经典蓝牙设备
    connectClassicDevice(device) {
      this.isBleDevice = false;
      classicBluetooth.connDevice(device.deviceId, (success) => {
        this.processing = false;
        if (success) {
          this.connected = true;
          this.currentDevice = device;
					uni.setStorageSync('lastBleDevice', JSON.stringify(device));
          this.addLog(`经典蓝牙设备连接成功: ${device.name}`);
					//关闭搜索
					this.stopScan();
				} else {
					this.addLog(`经典蓝牙设备连接失败: ${device.name}`);
				}
      });
    },
    
    // 连接低功耗蓝牙设备
    connectBleDevice(device) {
      this.isBleDevice = true;
      // #ifdef APP-PLUS
      uni.createBLEConnection({
        deviceId: device.deviceId,
        success: (res) => {
          this.connected = true;
          this.currentDevice = device;
          this.processing = false;
          this.addLog(`低功耗蓝牙设备连接成功: ${device.name}`);
          
          // 获取服务
          this.getBLEDeviceServices(device.deviceId);
					
					// 连接成功后自动设置MTU（可选）
					// this.autoSetBLEMTU(device.deviceId);
        },
        fail: (err) => {
          this.processing = false;
          this.addLog(`低功耗蓝牙设备连接失败: ${err.errMsg}`);
        }
      });
      // #endif
    },
		
		// 自动设置MTU（可选功能）
		autoSetBLEMTU(deviceId) {
			// #ifdef APP-PLUS
			// 可以根据设备类型或名称自动设置合适的MTU值
			const autoMTU = 128; // 默认值，可以根据需要调整
			
			uni.setBLEMTU({
				deviceId: deviceId,
				mtu: autoMTU,
				success: (res) => {
					this.bleMTU = autoMTU;
					this.addLog(`自动设置MTU成功: ${autoMTU}`);
				},
				fail: (err) => {
					this.addLog(`自动设置MTU失败: ${err.errMsg}`);
				}
			});
			// #endif
		},
    
    // 获取低功耗蓝牙设备服务
    getBLEDeviceServices(deviceId) {
      // #ifdef APP-PLUS
      uni.getBLEDeviceServices({
        deviceId: deviceId,
        success: (res) => {
          this.addLog(`获取到${res.services.length}个服务`);
          for (var s = 0; s < res.services.length; s++) {
						// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
            this.getBLEDeviceCharacteristics(deviceId, res.services[s].uuid);
          }
        },
        fail: (err) => {
          this.addLog(`获取服务失败: ${err.errMsg}`);
        }
      });
      // #endif
    },
    
    // 获取低功耗蓝牙设备特征值
    getBLEDeviceCharacteristics(deviceId, serviceId) {
			var that = this;
      // #ifdef APP-PLUS
      uni.getBLEDeviceCharacteristics({
        deviceId: deviceId,
        serviceId: serviceId,
        success: (res) => {
          this.addLog(`获取到${res.characteristics.length}个特征值`);
          var re = JSON.parse(JSON.stringify(res))
					//console.log(">>> getBLEDeviceCharacteristics ---", re)
          for (var c = 0; c < re.characteristics.length; c++) {
          	if (re.characteristics[c].properties.write == true) {
          		let uuid = re.characteristics[c].uuid
          		for (var index in that.devices) {
          			if (that.devices[index].deviceId == deviceId) {
									that.devices[index].services = []
									that.currentDevice.services = []
									//console.log(that.currentDevice)
									//console.log(that.devices[index])
          				that.devices[index].services.push({
          					serviceId: serviceId,
          					characteristicId: uuid
          				})
									that.currentDevice.services.push({
          					serviceId: serviceId,
          					characteristicId: uuid
          				})
									uni.setStorageSync('lastBleDevice', JSON.stringify(that.currentDevice));
          				break
          			}
          		}
          	}
          }
          // 监听特征值变化
					/*
          res.characteristics.forEach(characteristic => {
            if (characteristic.properties.notify || characteristic.properties.indicate) {
              uni.notifyBLECharacteristicValueChange({
                deviceId: deviceId,
                serviceId: serviceId,
                characteristicId: characteristic.uuid,
                state: true,
                success: () => {
                  this.addLog('开启特征值监听成功');
                  
                  // 监听特征值变化
                  uni.onBLECharacteristicValueChange((res) => {
                    const data = this.ab2hex(res.value);
                    this.addLog(`收到低功耗蓝牙数据: ${data}`);
                  });
                }
              });
            }
          });
					*/
        },
        fail: (err) => {
          this.addLog(`获取特征值失败: ${err.errMsg}`);
        }
      });
      // #endif
    },
    
    // 断开设备连接
    disconnectDevice() {
      if (this.connected && this.currentDevice) {
				console.log(">>> disconnectDevice.currentDevice", this.currentDevice)
        if (this.isBleDevice) {
          this.closeBleConnection();
        } else {
          classicBluetooth.disConnDevice();
        }
        this.connected = false;
        this.currentDevice = null;
        this.addLog('设备已断开连接');
      }
    },
    
    // 关闭低功耗蓝牙连接
    closeBleConnection() {
      // #ifdef APP-PLUS
      if (this.currentDevice && this.isBleDevice) {
        uni.closeBLEConnection({
          deviceId: this.currentDevice.deviceId
        });
      }
      // #endif
    },
    
    // 发送数据到设备
    sendDataToDevice() {
      if (!this.sendData) {
				uni.showToast({
					title: '没有打印数据',
					duration: 1500
				});
			};
			console.log(">>> sendDataToDevice.sendData", this.sendData)
			if (this.isBleDevice) {
				this.sendBleData(this.sendData);
			} else {
				this.sendClassicData(this.sendData);
			}
      this.sendData = null;
    },
    
    // 发送数据到经典蓝牙设备
    sendClassicData(data) {
			var sendData = [];
			// 添加字节符号转换
			//#ifdef APP-PLUS
			sendData = data.map(byte => {
				let b = byte & 0xFF;
				if (b >= 128) {
					return b % 128 - 128;  // 转换为有符号
				}
				return b;
			});
			//#endif
			// 而微信小程序不需要，因为小程序api接收的是 无符号8位
			//#ifdef MP-WEIXIN
			sendData = data
			//#endif
      classicBluetooth.sendByteData(sendData);
			uni.hideLoading();
    },
    
    // 发送数据到低功耗蓝牙设备
    sendBleData(data) {
			console.log('>>> sendBleData.currentDevice', this.currentDevice)
			if (!this.currentDevice) {
				uni.showToast({
					title: '请连接打印机'
				})
				return;
			}
					
			let deviceId = this.currentDevice.deviceId;
			let serviceId = this.currentDevice.services[0].serviceId;
			let characteristicId = this.currentDevice.services[0].characteristicId;
			let uint8Array = this.sendData
			var that = this
					
			//console.log('>>> sendBleData.deviceId = [' + deviceId + ']  serviceId = [' + serviceId + '] characteristics=[' + characteristicId + ']')
			uni.showToast({
				title: '发送打印数据成功',
				duration: 1500
			});
			var uint8Buf = Array.from(uint8Array);
					
			function split_array(datas, size) {
				var result = {};
				var j = 0
				for (var i = 0; i < datas.length; i += size) {
					result[j] = datas.slice(i, i + size)
					j++
				}
				//console.log('>>> sendBleData.split_array ', result)
				return result
			}
			function split_array1(datas, size) {
				var result = []; 
				for (var i = 0; i < datas.length; i += size) {
					result.push(datas.slice(i, i + size)) 
				}
				console.log('>>> sendBleData.split_array1 ', result)
				return result
			}
					
			var sendloop = split_array1(uint8Buf, that.bleMTU);
			// console.log(sendloop.length)
			function realWriteData(sendloop, i) {
				var data = sendloop[i]
				// console.log("准备下发：" + data)
				if (typeof(data) == "undefined") {
					uni.hideLoading()
					uni.showToast({
						title: '下发完毕'
					})
					that.progress = ''
					return
				}
				
				that.progress = '：'+ Math.round(i / sendloop.length * 100) + '%'
				 
				console.log("第" + i + "次写数据：" + data.length)
				var buffer = new ArrayBuffer(data.length)
				var dataView = new DataView(buffer)
				for (var j = 0; j < data.length; j++) {
					dataView.setUint8(j, data[j]);
				}
				uni.writeBLECharacteristicValue({
					deviceId,
					serviceId,
					characteristicId,
					value: buffer,
					success(res) {
						// console.log("------- 结果", res)
						setTimeout(() => {
							realWriteData(sendloop, i + 1);
						}, 10);
					
					},
					fail(res) {
						console.log(">>> writeBLECharacteristicValue --- 失败", res)
						uni.hideLoading()
						uni.showToast({
							title: '下发失败'
						})
						that.progress = ''
					}
				})
			}
			uni.showLoading({
				title: '开始下发'
			});
			var i = 0;
			realWriteData(sendloop, i);
    },
		
		// pdf打印
		chooseAndroidPdf() {
			this.drawEmptyCanvas()

			var that = this
			console.log('platform', uni.getSystemInfoSync().platform);
			// if (uni.getSystemInfoSync().platform === 'android') {...}
			const Intent = plus.android.importClass('android.content.Intent');
			const main = plus.android.runtimeMainActivity();
			const intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);

			intent.setType('application/pdf');
			intent.addCategory(Intent.CATEGORY_OPENABLE);
			main.startActivityForResult(intent, 1);

			main.onActivityResult = (requestCode, resultCode, data) => {
				console.log('>>> requestCode', requestCode);
				console.log('>>> resultCode', resultCode);
				if (requestCode === 1 && resultCode === -1) {
					const uri = data.getData();
					console.log("uri", uri.toString());
					try {
						uni.showLoading({
							title: '正在处理'
						})
						// that.processSelectedPdf(uri);
						// const myApiSyncTest = myApiSync(uri.toString());
						const path = that.savePdfAsFile(uri)
						// if (path === null) {...}
						that.drawCanvasImage(path)

					} catch (e) {
						console.error('处理 PDF 文件出错:', e);
					}
				}
			};
		},
		savePdfAsFile(uri) {
			var that = this
			// if (uni.getSystemInfoSync().platform === 'android') {...}
			// android
			const context = plus.android.runtimeMainActivity();
			const Intent = plus.android.importClass('android.content.Intent');
			const ContentResolver = plus.android.importClass('android.content.ContentResolver');
			const PdfRenderer = plus.android.importClass('android.graphics.pdf.PdfRenderer');
			const Bitmap = plus.android.importClass('android.graphics.Bitmap');
			const Matrix = plus.android.importClass('android.graphics.Matrix');
			const File = plus.android.importClass('java.io.File');
			const FileOutputStream = plus.android.importClass('java.io.FileOutputStream');
			const DisplayMetrics = plus.android.importClass('android.util.DisplayMetrics');
			const Canvas = plus.android.importClass('android.graphics.Canvas');
			const Paint = plus.android.importClass('android.graphics.Paint');
			const Color = plus.android.importClass('android.graphics.Color');

			// 授予权限
			context.grantUriPermission(context.getPackageName(), uri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent
				.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);

			const cr = context.getContentResolver();
			// 获取持久化权限
			cr.takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent
				.FLAG_GRANT_WRITE_URI_PERMISSION);

			const fileDescriptor = cr.openFileDescriptor(uri, "r");

			const renderer = new PdfRenderer(fileDescriptor);
			const page = renderer.openPage(0);

			// bitmap 设置保存尺寸
			const useWidth = 50 * 8;
			const useHeight = Math.floor(page.getHeight() / page.getWidth() * useWidth)

			// 创建空白 bitmap
			let bitmap = Bitmap.createBitmap(useWidth, useHeight, Bitmap.Config.ARGB_8888);

			// bitmap 填充白色背景

			const canvas = new Canvas(bitmap);
			const paint = new Paint();
			paint.setColor(Color.WHITE);
			canvas.drawRect(0, 0, bitmap.getWidth(), bitmap.getHeight(), paint);

			// bitmap.eraseColor(0xFFFFFFFF);

			// PDF 内容绘制到 bitmap
			page.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY);
			page.close();
			renderer.close();

			// const matrix = new Matrix();
			// matrix.postScale(useWidth / page.getWidth(), useHeight / page.getHeight());

			//  console.log('bitmap width',  bitmap.getWidth());
			//  console.log('page width',  page.getWidth());
			// bitmap = Bitmap.createScaledBitmap(
			// 	bitmap,
			// 	useWidth, useHeight, true
			// );

			// const widthMM = bitmap.getWidth() / that.pixelRatio / 160 * 25.4
			// console.log('widthMM',  widthMM);
			// const newPixelWidth = 70 / 25.4 * 160 * that.pixelRatio
			// console.log('newPixelWidth',  newPixelWidth);

			// 保存 Bitmap 为本地图片文件
			const storageDir = context.getExternalFilesDir(null);
			const fileName = "temp_" + Date.now() + ".jpg";
			const file = new File(storageDir, fileName);
			if (file.exists()) {
				const deleteResult = file.delete()
				console.log('>>> 删除已存在的文件 ---', deleteResult);
			}
			console.log('>>> 即将创建文件 ---', file.getAbsolutePath());
			try {
				const fos = new FileOutputStream(file);
				bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
				fos.flush();
				fos.close();

				// 返回保存后的文件地址
				const savedFilePath = file.getAbsolutePath();
				console.log('>>> PDF 第一页已保存到:', savedFilePath);
				return savedFilePath;
			} catch (e) {
				console.error('>>> 保存图片时出错:', e);
				uni.showToast({
					title: '保存图片时出错',
					duration: 1500
				});
				return null;
			}
		},
		
		// 图片base64格式打印
		chooseBase64() {
			var that = this
			that.drawEmptyCanvas()
			// 将 Base64 字符串转换为二进制数据
			uni.showLoading({
				title: '正在处理'
			})
			const path = that.saveBase64AsFile(base64Data)
			// if (path === null) {...}
			that.drawCanvasImage(path)
		},
		saveBase64AsFile(data) {
			const Bitmap = plus.android.importClass('android.graphics.Bitmap');
			const BitmapFactory = plus.android.importClass('android.graphics.BitmapFactory');
			const Base64 = plus.android.importClass('android.util.Base64');
			const File = plus.android.importClass('java.io.File');
			const FileOutputStream = plus.android.importClass('java.io.FileOutputStream');
			const context = plus.android.runtimeMainActivity();

			// base64 = /9j/4A...
			const decodedBytes = Base64.decode(data, Base64.DEFAULT);
			console.log('decodedBytes', decodedBytes)
			// const arrayBuffer = uni.base64ToArrayBuffer(data)
			// console.log('arrayBuffer', arrayBuffer)
			// const byteArray = new Uint8Array(arrayBuffer);
			// console.log('byteArray', byteArray.length)
			const bitmap = BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.length);
			console.log('bitmap', bitmap)
			const storageDir = context.getExternalFilesDir(null);
			const fileName = "temp_" + Date.now() + ".jpg";
			const file = new File(storageDir, fileName);
			if (file.exists()) {
				const deleteResult = file.delete()
				console.log('>>> 删除已存在的文件', deleteResult);
			}
			console.log('>>> 即将创建文件', file.getAbsolutePath());
			try {
				const fos = new FileOutputStream(file);
				bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
				fos.flush();
				fos.close();
				// 返回保存后的文件地址
				const savedFilePath = file.getAbsolutePath();
				console.log('>>> base64已保存到:', savedFilePath);
				return savedFilePath;
			} catch (e) {
				console.error('>>> 保存图片时出错:', e);
				uni.showToast({
					title: '保存图片时出错',
					duration: 1500
				});
				return null;
			}
		},
		
		// 条码打印
		createLabel() {
			var command = tsc.jpPrinter.createNew()
			command.setSize(100, 30)
			command.setGap(0)
			command.setCls()
			command.setText(50, 10, "TSS24.BF2", 1, 1, "打印测试") // 文本
			command.setQR(50, 50, "L", 5, "A", "www.poscom.cn") // 条码
			command.setBar(50, 180, "128", 64, 1, 2, 4, "200902125410") // 二维码
			command.setPagePrint(this.printCount)
			command.setFeed(1)
			this.sendData = command.getData();
			this.sendDataToDevice();
		},
					
		// 远程图片打印
		chooseRemoteImg() {
			var that = this
			if (!that.imageUrl) return;
			/*
			var sendData = "SIZE 100 mm,30 mm\n\r" + 
							"GAP 0 mm,0 mm\n\r" +
							"REFERENCE 0,0\n\r" +
							"SPEED 4\n\r" + 
							"DENSITY 8\n\r" + 
							"DIRECTION 0\n\r" + 
							"SET HEAD ON\n\r" + 
							"SET PRINTKEY OFF\n\r" + 
							"SET KEY1 ON\n\r" + 
							"SET KEY2 ON\n\r" + 
							"SHIFT 0\n\r" + 
							"CLS\n\r" + 
							"TEXT 30,10,\"TSS24.BF2\",0,1,1,\"打印测试\"\n\r" + 
							"BARCODE 30,75,\"128\",64,1,0,2,4,\"200902125410\"\n\r" + 
							"QRCODE 30,180,L,6,A,0,\"www.poscom.cn\"\n\r" + 
							"TEXT 220,180,\"TSS24.BF2\",90,2,2,\"请扫码\"\n\r" + 
							"PRINT 1,1\n\r";
			classicBluetooth.sendData(sendData)
			*/
			try {
				// 先下载图片到本地
				uni.downloadFile({
					url: that.imageUrl,
					success: (res) => {
						if (res.statusCode === 200) {
							uni.showLoading({
								title: '正在处理'
							})
							const path = res.tempFilePath
							that.drawCanvasImage(path)
							// 删除下载的图片
						}
					},
					fail: (err) => {
						console.error('>>> 下载失败:', err)
						uni.showToast({
							title: '>>> 下载失败: ' + err.message,
							icon: 'none'
						})
					},
				})
			} catch (error) {
				console.error('>>> 打印失败:', error)
				uni.showToast({
					title: '打印失败: ' + error.message,
					icon: 'none'
				})
			} finally {
				that.loading = false
			}
		},
    
		// 画布
		drawEmptyCanvas() {
			var that = this
			const ctx = uni.createCanvasContext('myCanvas', that)
			ctx.setFillStyle('white')
			// ctx.clearRect(0, 0, that.canvasW, that.canvasH)
			ctx.fillRect(0, 0, that.canvasW, that.canvasH)
			ctx.draw()
		},
		
		// 图片
		chooseLabelImg() {
			this.drawEmptyCanvas()
		
			var that = this
			uni.chooseImage({
				count: 1,
				mediaType: ['image'],
				sourceType: ['album'],
				maxDuration: 30,
				camera: 'back',
				success: function(res) {
					const ctx = uni.createCanvasContext('myCanvas', that)
					console.log('chooseImage', res)
					// 2025-02-21 查看日志修改文件路径 src
					// const src = res.tempFiles[0].tempFilePath
					const path = res.tempFilePaths[0]
					uni.showLoading({
						title: '正在处理'
					})
					that.drawCanvasImage(path)
				},
				fail: function(res) {
					uni.showToast({
						title: '获取文件失败',
						duration: 1500
					});
				}
			})
		},
		
		// 画图并打印
		drawCanvasImage(path) {
			var that = this
			console.log('>>> drawCanvasImage.path', path)
			uni.getImageInfo({
				src: path,
				success: function(image) {
					console.log('image', image)
					that.canvasH = image.height
					const mw = image.width % 8
					// 将 image 的宽度调整为最接近且大于等于当前宽度的 8 的倍数
					// that.canvasW = mw === 0 ? image.width : image.width + 8 - mw
					// that.canvasH = image.height / image.width * that.canvasW
					//that.canvasW = 70 * 8
					that.canvasW = mw === 0 ? image.width : image.width + 8 - mw
					that.canvasH = image.height / image.width * that.canvasW
					console.log('>>> drawCanvasImage.that.canvasW', that.canvasW + "x" + that.canvasH)
					that.$forceUpdate()
		
					setTimeout(() => {
						const ctx = uni.createCanvasContext('myCanvas', that)
		
						ctx.setFillStyle('white')
						// ctx.clearRect(0, 0, that.canvasW, that.canvasH)
						ctx.fillRect(0, 0, that.canvasW, that.canvasH)
						ctx.drawImage(image.path, 0, 0, that.canvasW, that.canvasH)
						ctx.draw(false, () => {
							console.log('>>> drawCanvasImage.draw end 1')
							setTimeout(function() {
								uni.canvasGetImageData({
									canvasId: 'myCanvas',
									x: 0,
									y: 0,
									width: that.canvasW,
									height: that.canvasH,
									success(data) {
										that.printImage(data)
									}
								})
							}, 500);
						})
					}, 500)
					// that.$nextTick(() => {
		
					// })
		
				}
			});
		},
		
		// 打印图片
		printImage(data) {
			var that = this
			var command = tsc.jpPrinter.createNew()
			command.setSize(that.canvasW / 8, that.canvasH / 8)
			// command.setGap(1) // GP-1224T(V1.3 2024-08-14) 实测设置间隙无效
			// command.setDirection(0)
			// command.setReference(0, 0)
			command.setGapMM(0, 0) // 如果是连续纸，需要设置 0，确保不会触发间隙判断，导致不必要的走纸
			command.setDensity(14) // GP-1224T(V1.3 2024-08-14) 实测设置浓度成功：0~15
			command.setSpeed(5) // GP-1224T(V1.3 2024-08-14) 实测设置速度成功：2~6
			// cls 前进行好全部设置
			command.setCls()
			command.setBitmap(50, 5, that.canvasW, that.canvasH, 0, data)
			command.setPagePrint(this.printCount)
			that.sendData = command.getData();
			// uni.showToast({
			// 	title: '生成图片指令',
			// 	duration: 1500
			// });
			// that.senSKData()
			setTimeout(function() {
				that.sendDataToDevice()
			}, 500)
		},
		
    // 工具方法：ArrayBuffer转16进制字符串
    ab2hex(buffer) {
      const hexArr = Array.prototype.map.call(
        new Uint8Array(buffer),
        bit => ('00' + bit.toString(16)).slice(-2)
      );
      return hexArr.join('');
    },
    
    // 工具方法：字节数组转字符串
    bytesToString(byteArray) {
      return String.fromCharCode.apply(null, byteArray);
    },
    
    // 添加日志
    addLog(message) {
      const timestamp = this.getReadableTimestamp();
      this.logs.unshift(`[${timestamp}] ${message}`);
      
      // 限制日志数量
      if (this.logs.length > 50) {
        this.logs.pop();
      }
    },
		
		// 获取可读的时间戳
		getReadableTimestamp() {
		    const now = new Date();
		    const date = now.toISOString().split('T')[0];
		    const time = now.toTimeString().split(' ')[0];
		    return `${date} ${time}`;
		}
  }
};
</script>

<style scoped>
.bluetooth-container {
  padding: 20rpx;
  background-color: #f5f5f5;
  min-height: 100vh;
}

.status-section {
  margin-bottom: 30rpx;
  padding: 20rpx;
  background-color: white;
  border-radius: 10rpx;
}

.status-title {
  font-weight: bold;
  margin-right: 20rpx;
}
.status-botton {
	display: inline-block;
	margin: 20rpx 0 0 80rpx;
}
.status-botton button {
	margin-right: 10rpx;
}
.status-value {
  margin-right: 30rpx;
  padding: 3rpx 6rpx;
  border-radius: 10rpx;
  background-color: #ff4444;
  color: white;
}

.status-value.enabled {
  background-color: #4CAF50;
}

.connection-status {
  padding: 3rpx 6rpx;
  border-radius: 10rpx;
  background-color: #ff9800;
  color: white;
}

.connection-status.connected {
  background-color: #2196F3;
}

.control-section {
  display: flex;
  flex-wrap: wrap;
  margin-bottom: 30rpx;
}

.btn {
  margin: 10rpx;
  padding: 10rpx 20rpx;
  background-color: #2196F3;
  color: white;
  border: none;
  border-radius: 10rpx;
  flex: 1;
  min-width: 140rpx;
}

.btn:disabled {
  background-color: #cccccc;
}

.devices-section, .data-section, .log-section {
  background-color: white;
  border-radius: 10rpx;
  padding: 20rpx;
  margin-bottom: 30rpx;
}

.section-title {
  font-weight: bold;
  margin-bottom: 20rpx;
  display: block;
}

.devices-list, .log-content {
  max-height: 360rpx;
}

.device-item {
  padding: 20rpx;
  border-bottom: 1rpx solid #eeeeee;
}

.device-item:active {
  background-color: #f0f0f0;
}

.device-name {
  font-weight: bold;
  display: block;
}

.device-address {
  font-size: 24rpx;
  color: #666666;
  display: block;
}

.device-type {
  font-size: 24rpx;
  color: #2196F3;
}

.input-area {
  display: flex;
  margin-bottom: 20rpx;
}

.data-input {
  flex: 1;
  border: 1rpx solid #cccccc;
  border-radius: 10rpx;
  padding: 20rpx;
  margin-right: 20rpx;
}

.send-btn {
  flex: 0 0 150rpx;
}
.log-item {
  display: block;
  padding: 10rpx 0;
  border-bottom: 1rpx solid #eeeeee;
  font-size: 24rpx;
  color: #666666;
}
.image-canvas {
	position: absolute;
	right: 99999rpx;
	bottom: 99999px;
}
</style>