<template>
	<view>
		<view v-if="showCheckinInfo">
			<view class="info">
				<view class="title">
					<view class="hotel-name">
						<!-- <u-text :text="hotelStore.hotel.name" bold color="#333333" size="30rpx"></u-text> -->
						<text>{{hotelStore.hotel.name}}</text>
					</view>
					<view class="tips">
						<!-- <u-text text="入住信息" color="#666666" size="24rpx"></u-text> -->
						<text>入住信息</text>
					</view>
				</view>
				<view class="checkin-info">
					<view class="checkin-info--item">
						<view class="checkin-info--item--text">
							<!-- <u-text text="所在楼层: " color="#999999" size="26rpx"></u-text> -->
							<text>所在楼层：</text>
						</view>
						<view class="checkin-info--item--text">
							<!-- <u-text :text="checkinInfo.floor + '楼'" color="#999999" size="26rpx"></u-text> -->
							<text>{{`${checkinInfo.floor}楼`}}</text>
						</view>
					</view>
					<view class="checkin-info--item">
						<view class="checkin-info--item--text">
							<!-- <u-text text="房间信息 : " color="#999999" size="26rpx"></u-text> -->
							<text>房间信息：</text>
						</view>
						<view class="checkin-info--item--text">
							<!-- <u-text :text="checkinInfo.room" color="#999999" size="26rpx"></u-text> -->
							<text>{{checkinInfo.room}}</text>
						</view>
					</view>
					<view class="checkin-info--item">
						<view class="checkin-info--item--text">
							<!-- <u-text text="起始时间 : " color="#999999" size="26rpx"></u-text> -->
							<text>起始时间：</text>
						</view>
						<view class="checkin-info--item--text">
							<!-- <u-text :text="formatDateTime(checkinInfo.startTime)" color="#999999" size="26rpx"></u-text> -->
							<text>{{formatDateTime(checkinInfo.startTime)}}</text>
						</view>
					</view>
					<view class="checkin-info--item">
						<view class="checkin-info--item--text">
							<!-- <u-text text="结束时间 : " color="#999999" size="26rpx"></u-text> -->
							<text>结束时间：</text>
						</view>
						<view class="checkin-info--item--text">
							<!-- <u-text :text="formatDateTime(checkinInfo.endTime)" color="#999999" size="26rpx"></u-text> -->
							<text>{{formatDateTime(checkinInfo.endTime)}}</text>
						</view>
					</view>
				</view>
			</view>

			<view class="room__operate">
				<view v-if="doorLockStatus === 'doorLockReady'" class="room__operate--display" @click="openBoYuanLock">
					<uni-icons type="locked" size="30"></uni-icons>
					<view class="display__desc">手机开门</view>
				</view>
				<view v-if="doorLockStatus === 'doorLockUnavailable'" class="room__operate--display">
					<uni-icons type="locked" size="30"></uni-icons>
					<view class="display__desc">手机开门</view>
				</view>
				<view v-if="doorLockStatus === 'doorLockOpening'" class="room__operate--display">
					<view class="display__desc">{{openDoorTips}}</view>
				</view>
			</view>
		</view>
		<view v-else class="not-checkin">
			<view class="not-checkin-text">
				<text>您还未入住！</text>
			</view>
			<view class="not-checkin-text">
				<text>若已退房或房间到期,请至前台办理</text>
			</view>
		</view>
	</view>
</template>

<script setup>
	import {
		ref
	} from "vue";
	import {
		getCheckinInfo,
		getOpenDoorInfo,
		unloadBLEOpenDoorLog
	} from "../../utils/api"
	import {
		useHotelStore
	} from '@/store/hotelStore.js'
	import {
		onLoad
	} from '@dcloudio/uni-app'
	import moment from "moment";
	import {
		isIosDevice,
		ErrorCode,
		TimeoutValue,
		needScanDevice,
		parseBELDeviceId,
		genReqSecretPkg,
		genOpDoorPkg,
		hexStringToUint8Array,
		decryptAes,
		Delayed
	} from "../../utils/emergencyKeyUtils";

	const hotelStore = useHotelStore()
	const showCheckinInfo = ref(false)
	const checkinInfo = ref(null)
	const openDoorInfo = ref(null)
	const doorLockReady = "doorLockReady"
	const doorLockOpening = "doorLockOpening"
	const doorLockStatus = ref("doorLockUnavailable")
	const openDoorTips = ref("正在扫描门锁蓝牙...")

	const openBoYuanLock = async () => {
		console.log("openDoorInfo", openDoorInfo.value);
		doorLockStatus.value = doorLockOpening
		openDoorTips.value = "正在扫描门锁蓝牙..."

		const BluetoothLifeData = {
			name: null, // 蓝牙门锁名称
			hotelId: null,
			operationType: 1, // 蓝牙开门
			isBluetoothOpened: false, // 蓝牙开关是否打开
			bluetoothConnected: false, // 蓝牙是否连接上
			deviceId: null, // 进行连接时，蓝牙的deviceId。安卓可以计算出来，iOS需要扫描
			originalSecret: null,
			sessionKey: null,
			serviceId: "0000FFF0-0000-1000-8000-00805F9B34FB", // 蓝牙交互服务的service的UUID。苹果端支付宝侧有点特殊，需进行处理
			characteristicId: "0000FFF1-0000-1000-8000-00805F9B34FB", // 特征值的UUID。苹果端支付宝侧有点特殊，需进行处理
			initBluetoothAdapterTime: null, // 进行蓝牙初始化时的时间
			startBluetoothDiscoveryTime: null, // 蓝牙初始化完成同时开始探索蓝牙  gap1蓝牙初始化
			targetBluetoothFoundTime: null, // 目标蓝牙被找到，同时开始蓝牙的连接 gap2探索目标蓝牙
			targetBluetoothConnectedTime: null, // 蓝牙被连接时的时间 gap3连接蓝牙
			opForIosEndedTime: null, // 连接蓝牙后，完成iOS设备所必须的操作时的时间 gap4 iOS服务耗时
			requestSessionKeyTime: null, // 请求会话秘钥的开始时间  gap5 订阅特征值变化
			getSessionKeyPackageTime: null, // 获取到请求会话秘钥ack的时间
			requestBleOpenDoorTime: null, // 发送开门请求的时间
			getOpenDoorPackageTime: null, // 获取到请求开门返回包的时间
			result: null, // 蓝牙操作结果，与错误码相对应
			endTime: null, // 流程中断的时间点
			mobileOs: null,
			totalTime: null,
			isLocationEnabled: false,
			androidOptimization: false,
			hostName: null, // 小程序宿主名
			hostVersion: null, // 小程序宿主版本
			openDoorParam: null, // 开门时的自定义参数
			bluetoothAuthorized: false, // 蓝牙授权开启情况
			errMessage: '',
			// 剩下的为上传相关记录的操作
			floor: null,
			room: null
		}

		BluetoothLifeData.androidOptimization = openDoorInfo.value.androidOptimization
		BluetoothLifeData.deviceId = openDoorInfo.value.doorLockDeviceId
		BluetoothLifeData.name = openDoorInfo.value.doorLockName
		BluetoothLifeData.openDoorParam = openDoorInfo.value.openDoorParam
		BluetoothLifeData.originalSecret = openDoorInfo.value.doorLockKey
		BluetoothLifeData.hotelId = hotelStore.hotel.hotelId
		BluetoothLifeData.room = checkinInfo.value.room
		BluetoothLifeData.floor = checkinInfo.value.floor

		const systemInfo = uni.getSystemInfoSync();
		//console.log("小程序宿主环境信息", systemInfo);
		BluetoothLifeData.hostName = systemInfo.hostName // 小程序的宿主名称，微信、支付宝等
		BluetoothLifeData.hostVersion = systemInfo.hostVersion; // 宿主环境的版本信息
		BluetoothLifeData.mobileOs = systemInfo.osName; // 收集操作系统
		// 后期考虑能否获取到开发环境基础库的版本，并添加进数据库

		// 处理宿主系统为ios且宿主环境为alipay时的服务id和特征值id
		if (isIosDevice(BluetoothLifeData) && BluetoothLifeData.hostName === 'alipay') {
			BluetoothLifeData.serviceId = 'FFF0'
			BluetoothLifeData.characteristicId = 'FFF1'
		}

		/**
		 * 蓝牙的开关以及在未开启安卓优化时位置的开关
		 */
		const systemSetting = uni.getSystemSetting()
		//console.log("获取系统设置信息", systemSetting);

		BluetoothLifeData.isBluetoothOpened = systemSetting.bluetoothEnabled
		// 处理手机蓝牙未打开
		if (!BluetoothLifeData.isBluetoothOpened) {
			return ErrorCode.get(10001)
		}

		// 不开启安卓优化，设备系统是安卓，校验位置是否开启
		BluetoothLifeData.isLocationEnabled = systemSetting.locationEnabled
		//console.log("BluetoothLifeData", BluetoothLifeData);

		/**
		 * 获取用户的当前设置(蓝牙的授权信息)。返回值中只会出现小程序已经向用户请求过的权限。
		 */
		const userSetting = await uni.getSetting()
		//console.log("获取用户系统设置信息", userSetting);
		if (BluetoothLifeData.hostName === "alipay") {
			BluetoothLifeData.bluetoothAuthorized = userSetting.authSetting['bluetooth'] ?
				userSetting.authSetting['bluetooth'] : false
		} else if (BluetoothLifeData.hostName === "WeChat") {
			BluetoothLifeData.bluetoothAuthorized = userSetting.authSetting['scope.bluetooth'] ?
				userSetting.authSetting['scope.bluetooth'] : false
		}
		//console.log("BluetoothLifeData.bluetoothAuthorized", BluetoothLifeData.bluetoothAuthorized);

		/**
		 *
		 * 开启蓝牙适配器，必须操作,并在Promise中处理授权相关的信息
		 */
		BluetoothLifeData.initBluetoothAdapterTime = +new Date();

		console.info("开始打开蓝牙适配器")
		let openBluetoothAdapter;
		try {
			// 请求授权时：同意：支付宝{isSupportBLE: true}
			// 请求授权时：拒绝：new Error()
			openBluetoothAdapter = await uni.openBluetoothAdapter()
			// console.log("openBluetoothAdapter", openBluetoothAdapter);
			if (BluetoothLifeData.hostName === "alipay") {
				BluetoothLifeData.bluetoothAuthorized = openBluetoothAdapter.isSupportBLE
			} else {
				BluetoothLifeData.bluetoothAuthorized = true
			}
		} catch (err) {
			BluetoothLifeData.bluetoothAuthorized = false
			//console.log("打开蓝牙适配器错误", err);
			if ((BluetoothLifeData.hostName === "alipay" && err.error === 2001) ||
				(BluetoothLifeData.hostName === "WeChat" && err.errno === 103)) {
				// 用户拒绝蓝牙授权，引导用户进行蓝牙授权
				await new Promise(async (resolve, reject) => {
					uni.showModal({
						title: "温馨提示",
						content: "蓝牙开门功能需要使用您的蓝牙，授权后才能开门。",
						showCancel: false,
						success: async (res) => {
							if (res.confirm) {
								await uni.openSetting().then(async (res) => {
									//console.log("openSetting", res);
									if (BluetoothLifeData.hostName ===
										"alipay") {
										BluetoothLifeData.bluetoothAuthorized =
											res.authSetting['bluetooth']
									} else if (BluetoothLifeData.hostName ===
										"WeChat") {
										BluetoothLifeData.bluetoothAuthorized =
											res.authSetting['scope.bluetooth']
									}
									try {
										await uni.openBluetoothAdapter()
									} catch (error) {
										//console.log(error);
									}
									resolve()
								})
							}
						},
					});
				})
			}
		}
		//console.log("1------------------>开启蓝牙适配器", openBluetoothAdapter);

		// 判断蓝牙是否授权，未授权直接return
		if (!BluetoothLifeData.bluetoothAuthorized) {
			BluetoothLifeData.endTime = new Date();
			BluetoothLifeData.totalTime =
				BluetoothLifeData.endTime - BluetoothLifeData.initBluetoothAdapterTime;

			// 蓝牙操作未授权
			BluetoothLifeData.result = 10002;
			const uploadRes = await unloadBLEOpenDoorLog(BluetoothLifeData);
			//console.log("上传开门记录结果", uploadRes);
			await closeBluetoothAdapter();
			doorLockStatus.value = doorLockReady
			return ErrorCode.get(10002);
		}

		/**
		 *
		 * 在Promise中调用onBluetoothDeviceFound，直到找到目的设备
		 * 针对android设备且开启了安卓设备优化，直接跳过此流程
		 */
		if (needScanDevice(BluetoothLifeData)) {
			console.info("发现目标蓝牙门锁")
			if (BluetoothLifeData.mobileOs === "android" && !BluetoothLifeData.isLocationEnabled) {
				BluetoothLifeData.result = 10008;

				BluetoothLifeData.endTime = new Date();
				BluetoothLifeData.totalTime =
					BluetoothLifeData.endTime - BluetoothLifeData.initBluetoothAdapterTime;

				await closeBluetoothAdapter();
				const uploadRes = await unloadBLEOpenDoorLog(BluetoothLifeData);
				doorLockStatus.value = doorLockReady
				//console.log("上传开门记录结果", uploadRes);
				return ErrorCode.get(10008);
			}
			await new Promise(async (resolve, reject) => {
				//console.log("1.1------------------>发现周边蓝牙设备");
				// 注册超时函数
				const timeout = setTimeout(() => {
					if (!BluetoothLifeData.targetBluetoothFoundTime) {
						//console.log("onBluetoothDeviceFound Promise 发现设备超时");
						BluetoothLifeData.result = 10003;
						uni.stopBluetoothDevicesDiscovery();
						reject("发现设备超时");
					}
				}, TimeoutValue.findDevice);
				// 注册发现蓝牙事件
				uni.onBluetoothDeviceFound((res) => {
					let devices = res.devices.filter((device) =>
						device.name === BluetoothLifeData.name
					);
					//console.log("onBluetoothDeviceFound 发现设备数", devices.length);
					if (devices.length <= 0) return;
					let {
						deviceId,
						name
					} = devices[0];
					// console.log("deviceId", deviceId, "deviceName", name);
					BluetoothLifeData.deviceId = deviceId;
					BluetoothLifeData.targetBluetoothFoundTime = +new Date();
					uni.stopBluetoothDevicesDiscovery()
					clearTimeout(timeout);
					resolve({
						bleFound: true
					});
				});
				// 调用扫描蓝牙API，扫描周边蓝牙
				BluetoothLifeData.startBluetoothDiscoveryTime = +new Date();
				let discovery = await uni.startBluetoothDevicesDiscovery({
					powerLevel: "high"
				});
				//console.log("startBluetoothDevicesDiscovery", discovery);
			}).catch((err) => {
				//console.log("onBluetoothDeviceFound Promise catch err", err);
			});
			/**
			 *
			 * 搜索蓝牙设备超时的处理逻辑
			 */
			if (!BluetoothLifeData.targetBluetoothFoundTime) {
				//console.log("超时时间内未发现门锁");

				BluetoothLifeData.endTime = new Date();
				BluetoothLifeData.totalTime =
					BluetoothLifeData.endTime - BluetoothLifeData.initBluetoothAdapterTime;

				await closeBluetoothAdapter();
				const uploadRes = await unloadBLEOpenDoorLog(BluetoothLifeData);
				doorLockStatus.value = doorLockReady
				//console.log("上传开门记录结果", uploadRes);
				return ErrorCode.get(10003)
			}
		} else {
			//该分支不进行蓝牙扫描
			BluetoothLifeData.startBluetoothDiscoveryTime = +new Date();
			BluetoothLifeData.targetBluetoothFoundTime = +new Date();

			// 根据转换规则，置android设备的deviceId
			BluetoothLifeData.deviceId = parseBELDeviceId(
				BluetoothLifeData.deviceId
			);
			//console.log("android设备连接蓝牙时的deviceId", BluetoothLifeData.deviceId);
		}
		/**
		 *
		 * 找到目标设备，开始进行蓝牙连接
		 * 在Promise中连接蓝牙设备，超时就  关闭蓝牙适配器  ，第一次超时return是否会影响第二次的成功连接
		 */
		console.info("开始连接目标蓝牙门锁")
		openDoorTips.value = "正在连接门锁蓝牙..."
		await new Promise(async (resolve, reject) => {
			//console.log("2------------------>进行蓝牙连接");
			// 注册超时函数
			const timeout = setTimeout(() => {
				if (!BluetoothLifeData.targetBluetoothConnectedTime) {
					BluetoothLifeData.result = 10004;
					//console.log("蓝牙连接超时");
					reject("蓝牙连接超时");
				}
			}, TimeoutValue.connectBLE)
			// 微信和支付宝连接蓝牙的函数不一样
			// 发起蓝牙连接
			uni.createBLEConnection({
				deviceId: BluetoothLifeData.deviceId,
				success: (res) => {
					clearTimeout(timeout)
					BluetoothLifeData.bluetoothConnected = true;
					BluetoothLifeData.targetBluetoothConnectedTime = +new Date();
					//console.log("蓝牙连接成功", res);
					resolve("蓝牙连接成功")
				},
				fail: (err) => {
					BluetoothLifeData.result = 10005;
					//console.log("蓝牙连接失败", err);
				}
			})
		}).catch(err => {
			//console.log("createBLEConnection Promise catch err", err);
		})

		// 判断蓝牙是否连接成功，若失败则直接return
		if (!BluetoothLifeData.bluetoothConnected) {

			BluetoothLifeData.endTime = new Date();
			BluetoothLifeData.totalTime =
				BluetoothLifeData.endTime - BluetoothLifeData.initBluetoothAdapterTime;

			await closeBluetoothAdapter();
			const uploadRes = await unloadBLEOpenDoorLog(BluetoothLifeData);
			//console.log("上传开门记录结果", uploadRes);
			doorLockStatus.value = doorLockReady

			if (BluetoothLifeData.result === 10004) {
				return ErrorCode.get(10004)
			} else {
				return ErrorCode.get(10005)
			}
		}
		/**
		 *
		 * 蓝牙连接成功后，对iOS设备而言，需对服务及特征值进行扫描
		 */
		if (isIosDevice(BluetoothLifeData)) {
			await new Promise((reslove, reject) => {
				uni.getBLEDeviceServices({
					deviceId: BluetoothLifeData.deviceId,
					success: res => {
						//console.log("获取蓝牙设备所有服务列表成功", res);
						reslove(res)
					},
					fail: err => {
						//console.log("获取蓝牙设备所有服务列表失败", err);
						reject(err)
					}
				})
			}).catch(err => {
				//console.log("获取蓝牙设备所有服务列表Promise err", err);
			})
			await new Promise((reslove, reject) => {
				uni.getBLEDeviceCharacteristics({
					deviceId: BluetoothLifeData.deviceId,
					serviceId: BluetoothLifeData.serviceId,
					success: res => {
						//console.log("获取低功耗蓝牙设备服务中所有特征成功", res);
						reslove(res)
					},
					fail: err => {
						//console.log("获取低功耗蓝牙设备服务中所有特征失败", err);
						reject(err)
					}
				})
			}).catch(err => {
				//console.log("获取低功耗蓝牙设备服务中所有特征Promise err", err);
			})
			BluetoothLifeData.opForIosEndedTime = +new Date();
		} else {
			BluetoothLifeData.opForIosEndedTime = +new Date();
		}

		// 对主服务特征值进行订阅
		await new Promise((resolve, reject) => {
			uni.notifyBLECharacteristicValueChange({
				deviceId: BluetoothLifeData.deviceId, // 蓝牙设备 id
				serviceId: BluetoothLifeData.serviceId, // 蓝牙特征对应服务的 UUID
				characteristicId: BluetoothLifeData.characteristicId, // 蓝牙特征的 UUID
				state: true, // 是否启用 notify
				success: function(res) {
					//console.log("对主服务特征值订阅成功", res);
					resolve(res);
				},
				fail: function(res) {
					//console.log("对主服务特征值订阅失败", res);
					reject(res);
				},
			});
		}).catch(err => {
			//console.log("对主服务特征值订阅Promise err", err);
		})

		// 向蓝牙发请求，请求会话秘钥(写特征值)，解出会话秘钥
		await new Promise(async (resolve, reject) => {
			//console.log("3------------------>请求会话秘钥");
			// 注册请求蓝牙会话秘钥超时函数
			const timeout = setTimeout(() => {
				if (!BluetoothLifeData.getSessionKeyPackageTime) {
					BluetoothLifeData.result = 10006;
					reject("请求会话秘钥超时");
				}
			}, TimeoutValue.requestSessionKey);

			uni.offBLECharacteristicValueChange();

			const submitSessionKeyReq = onBLECharacteristicValueChange();
			BluetoothLifeData.requestSessionKeyTime = +new Date();
			await writeBLECharacteristicValue(genReqSecretPkg());
			//console.log("发完请求会话密钥请求报文");
			submitSessionKeyReq.then((res) => {
				//console.log("请求会话密钥promise", res);
				if (res === 0x01) {
					clearTimeout(timeout);
					resolve({
						requestSessionKey: true
					});
				} else {
					clearTimeout(timeout);
					reject({
						message: "应答包获取错误，应为请求会话秘钥的应答包。",
					});
				}
			}).catch(err => {
				//console.log("处理会话密钥出现问题", err);

			})
		}).catch((err) => {
			//console.log("监听函数，请求会话秘钥。catch err", err);
		});

		// 获取会话秘钥超时的处理逻辑
		if (!BluetoothLifeData.getSessionKeyPackageTime) {
			BluetoothLifeData.endTime = new Date();
			BluetoothLifeData.totalTime =
				BluetoothLifeData.endTime - BluetoothLifeData.initBluetoothAdapterTime;

			const uploadRes = await unloadBLEOpenDoorLog(BluetoothLifeData);
			//console.log("上传开门记录结果", uploadRes);

			await closeBLEConnection(BluetoothLifeData.deviceId);
			await closeBluetoothAdapter();
			doorLockStatus.value = doorLockReady
			return ErrorCode.get(10006)
		}

		/**
		 *
		 * 解完请求会话秘钥后，发蓝牙开门报文，解蓝牙开门返回包
		 */
		openDoorTips.value = "正在开启门锁..."
		console.info("开启目标门锁中...")
		await new Promise(async (resolve, reject) => {
			//console.log("4------------------>发蓝牙开门报文");
			// 设置蓝牙开门的超时
			const timeout = setTimeout(() => {
				if (!BluetoothLifeData.getOpenDoorPackageTime) {
					BluetoothLifeData.result = 10007;
					reject("蓝牙开门超时");
				}
			}, TimeoutValue.openDoor);

			uni.offBLECharacteristicValueChange();

			const requestBLEOpenDoorRes = onBLECharacteristicValueChange();
			BluetoothLifeData.requestBleOpenDoorTime = +new Date();

			await writeBLECharacteristicValue(genOpDoorPkg(BluetoothLifeData.sessionKey));
			//console.log("发完蓝牙开门报文");
			requestBLEOpenDoorRes.then((res) => {
				if (res == 0x11) {
					clearTimeout(timeout);
					resolve({
						bluetoothOpenDoor: true
					});
				} else {
					clearTimeout(timeout);
					reject({
						message: "应答包获取错误，应为请求会话秘钥的应答包。",
					});
				}
			});
		}).catch((err) => {
			//console.log("监听函数，蓝牙开门。catch err", err);
		});

		// 判断蓝牙开门是否成功，如果失败，则return
		if (!BluetoothLifeData.getOpenDoorPackageTime) {
			//console.log("蓝牙开门失败");
			BluetoothLifeData.endTime = new Date();
			BluetoothLifeData.totalTime =
				BluetoothLifeData.endTime - BluetoothLifeData.initBluetoothAdapterTime;

			const uploadRes = await unloadBLEOpenDoorLog(BluetoothLifeData);
			//console.log("上传开门记录结果", uploadRes);

			await closeBLEConnection(BluetoothLifeData.deviceId);
			await closeBluetoothAdapter();
			doorLockStatus.value = doorLockReady
			return ErrorCode.get(10007)
		}

		// 断开蓝牙连接，关闭蓝牙适配器，并上传所有记录
		await closeBLEConnection(BluetoothLifeData.deviceId);
		await closeBluetoothAdapter();
		BluetoothLifeData.endTime = new Date();
		BluetoothLifeData.totalTime =
			BluetoothLifeData.endTime - BluetoothLifeData.initBluetoothAdapterTime;

		BluetoothLifeData.result = 10000
		const uploadRes = await unloadBLEOpenDoorLog(BluetoothLifeData);
		//console.log("上传开门记录结果", uploadRes);
		//console.log(BluetoothLifeData);
		doorLockStatus.value = doorLockReady
		return ErrorCode.get(10000)

		function onBLECharacteristicValueChange() {
			return new Promise((resolve, reject) => {
				const BleStruct = {
					firstPacketReceived: false, // 是否已接收第一个报文
					buffer: null, // 用于缓存数据流的 ArrayBuffer
					cmd: null, //返回数据包命令号
					length: 0, //数据包长度
					received: 0,
					errCode: 0,
				};
				uni.onBLECharacteristicValueChange(async (res) => {
					//console.log("onBLECharacteristicValueChange", res); //打印特征值
					let receiveBuffer = BluetoothLifeData.hostName === 'alipay' ?
						hexStringToUint8Array(res.value) : new Uint8Array(res.value);

					// 接收到的报文包含开始码等报文头数据
					if (receiveBuffer[0] === 0xa5 && BleStruct.firstPacketReceived === false) {
						BleStruct.firstPacketReceived = true;
						BleStruct.length = (receiveBuffer[5] << 8) + receiveBuffer[4] +
							6; //算出数据长度
						BleStruct.received = 0;
						BleStruct.cmd = receiveBuffer[1]; //命令号赋值
						BleStruct.errCode = receiveBuffer[6];
						BleStruct.buffer = new Uint8Array(BleStruct.length);
						// 错误码!= 0，丢弃报文
						if (BleStruct.errCode != 0) {
							BleStruct.firstPacketReceived = false;
							BluetoothLifeData.result = BleStruct.errCode;
							reject({
								message: "errCode != 0",
								errCode: BleStruct.errCode
							});
						}
					}
					// 接收到的报文的长度不对，丢弃报文
					if (receiveBuffer.length > BleStruct.length - BleStruct.received) {
						BleStruct.firstPacketReceived = false;
						reject({
							message: "onBLECharacteristicValueChange: length err",
							bleStruct: BleStruct,
							length: receiveBuffer.length,
						});
						return;
					}
					BleStruct.buffer.set(receiveBuffer, BleStruct
						.received); // 将接收到的报文放入buffer容器
					BleStruct.received += receiveBuffer.length;
					// 已经获取到全部报文
					if (BleStruct.received >= BleStruct.length) {
						BleStruct.firstPacketReceived = false;
						const returnCmd = analysisData(
							BleStruct.cmd,
							BleStruct.buffer.slice(7)
						);
						resolve(returnCmd);
					}
				});
			});
		}

		function analysisData(cmd, data) {
			// 请求会话密钥的返回包，对其进行处理
			if (cmd === 0x01) {
				BluetoothLifeData.getSessionKeyPackageTime = +new Date();
				const originalKey = BluetoothLifeData.originalSecret;
				const encryptedData = data;
				const sessionKey = decryptAes(originalKey, encryptedData);
				const hexString = Array.from(sessionKey)
					.map((byte) => byte.toString(16).padStart(2, "0"))
					.join("");
				BluetoothLifeData.sessionKey = hexString;
				return 0x01;
			}
			//蓝牙开门返回包，对其进行处理
			if (cmd == 0x11) {
				BluetoothLifeData.getOpenDoorPackageTime = +new Date();
				return 0x11;
			}
		}

		// 向蓝牙低功耗设备特征值中写入二进制数据
		async function writeBLECharacteristicValue(packetData) {
			while (packetData.byteLength > 0) {
				let len = Math.min(16, packetData.byteLength);
				try {
					await uni.writeBLECharacteristicValue({
						deviceId: BluetoothLifeData.deviceId,
						serviceId: BluetoothLifeData.serviceId,
						characteristicId: BluetoothLifeData.characteristicId,
						value: packetData.slice(0, len),
					});
				} catch (error) {
					//console.log("writeBLECharacteristicValue err", error);
				}
				packetData = packetData.slice(len);
				// 写完第一个报文后等待半秒
				await Delayed(500);
			}
		}

		// 关闭连接,也是异步操作
		function closeBLEConnection(deviceId = "") {
			return new Promise((resolve, reject) => {
				uni.closeBLEConnection({
					deviceId: deviceId,
					success: (res) => {
						//console.log("断开蓝牙连接成功", res);
						resolve(res);
					},
					fail: (res) => {
						//console.log("断开蓝牙连接失败", res);
						reject(res);
					},
				});
			});
		}

		// 关闭蓝牙模块
		function closeBluetoothAdapter() {
			return new Promise((resolve, reject) => {
				uni.closeBluetoothAdapter({
					success: function(res) {
						//console.log("success closeBluetoothAdapter:", res);
						resolve(res);
					},
					fail: function(res) {
						//console.log("fail closeBluetoothAdapter:", res);
						resolve();
					},
				});
			});
		}

	}

	onLoad(async (options) => {
		console.log("onLoad", options);
		try {
			const infoRes = await getCheckinInfo(hotelStore.hotel.hotelId)
			// console.log("获取入住记录结果", infoRes);
			if (!infoRes.data || !infoRes.success) {
				return
			}
			checkinInfo.value = infoRes.data
			showCheckinInfo.value = true
		} catch (err) {
			console.log("获取入住记录异常", err);
			return
		}

		try {
			console.log("checkinInfo", checkinInfo.value);
			const res = await getOpenDoorInfo({
				hotelId: hotelStore.hotel.hotelId,
				floor: checkinInfo.value.floor,
				room: checkinInfo.value.room
			})
			console.log("获取门锁信息结果", res);
			if (!res.data || !res.success) {
				return
			}
			openDoorInfo.value = res.data
			doorLockStatus.value = doorLockReady
		} catch (err) {
			console.log("获取门锁信息异常", err);
			return
		}
	})

	const formatDateTime = (dateTime) => {
		return moment(dateTime).format("YYYY年MM月DD日HH时mm分")
	}
</script>

<style lang="scss">
	page {
		background-color: #FFFFFF;

		.info {
			background: #F5F8FE;
			box-shadow: -6px 17px 21px 0px rgba(112, 152, 246, 0.14);
			margin-bottom: 200rpx;

			.title {
				display: flex;
				justify-content: space-between;
				padding: 0 40rpx;
				line-height: 80rpx;
				border-bottom: 2rpx solid #E0E8FB;
			}

			.checkin-info {
				margin: 20rpx auto;

				.checkin-info--item {
					display: flex;
					margin: 0 40rpx;

					.checkin-info--item--text {
						margin: 10rpx;
						margin-left: 0;
					}

					&:last-child {
						padding-bottom: 20rpx;
					}
				}
			}
		}

		.room__operate {
			height: 90rpx;
			display: flex;
			margin: 2*5rpx 2 * 15rpx;
			background-color: #9e97c3;
			align-items: center;
			justify-content: center;
			border-radius: 10rpx;

			.room__operate--display {
				height: 2 * 25rpx;
				margin: 5rpx;
				padding: 2 * 6rpx;
				display: flex;
				align-items: center;
				justify-content: center;
				width: 100%;

				.display__desc {
					height: 100%;
					display: flex;
					align-items: center;
					justify-content: center;
					padding-left: 10rpx;
					font-size: 40rpx;
					color: #FFFFFF;
					font-size: 32rpx;
				}
			}
		}
	}

	.not-checkin {
		margin-top: 40vh;

		.not-checkin-text {
			display: flex;
			justify-content: center;
		}
	}
</style>