<template>
	<view class="checkin-page">
		<!-- 顶部导航栏（固定顶部） -->
		<view class="header">
			<view class="header-title">会员签到</view>
			<view class="header-subtitle">扫码入场，开启今日训练</view>
		</view>

		<!-- 会员信息卡片 -->
		<view class="member-card card-default">
			<view class="member-avatar">
				<image src="/static/default-avatar.png" mode="aspectFill"></image>
			</view>
			<view class="member-info">
				<view class="member-name">尊敬的会员</view>
				<view class="member-level">
					<text class="level-badge">黄金会员</text>
					<text class="valid-date">有效期至 2026-12-31</text>
				</view>
			</view>
			<view class="member-points">
				<view class="points-value">1280</view>
				<view class="points-label">积分</view>
			</view>
		</view>

		<!-- 二维码核心区域 -->
		<view class="qr-container card-default">
			<view class="qr-header">
				<view class="qr-title">出示二维码签到</view>
				<view class="qr-tip">将二维码对准前台扫码设备</view>
			</view>
			
			<view class="QRBox">
				<view class="QR">
					<image :src="image" mode="" :style="{width: Math.min(width, 500) + 'rpx',height: Math.min(height, 500) + 'rpx' } "></image>
				</view>
				<!-- 加载动画区域 - 设置最小尺寸确保进入页面时可见 -->
				<view v-if="!image || STQRC" class="loadingBox" :style="{width: (width > 0 ? Math.min(width, 500) : 500) + 'rpx',height: (height > 0 ? Math.min(height, 500) : 500) + 'rpx' }">
					<view class="loading-spinner">
						<view v-if="!isCheckIn" class="spinner-circle"></view>
						<view v-else>
							<uni-icons type="checkmarkempty" size="30"></uni-icons>
						</view>
						<text class="loading-text">{{ QRStatus }}</text>
					</view>
				</view>
				
				<!-- 二维码装饰边框 -->
				<view v-else class="qr-border" :style="{width: Math.min(width, 500) + 80 + 'rpx',height: Math.min(height, 500) + 80 + 'rpx' }">
					<view class="corner top-left"></view>
					<view class="corner top-right"></view>
					<view class="corner bottom-left"></view>
					<view class="corner bottom-right"></view>
				</view>
			</view>
			
			<!-- 状态组件（传递状态和自定义错误文案）- 已签到时不显示 -->
			<QrStatus 
				v-if="!isCheckIn" 
				:status="status" 
				:errorText="errorText" 
			/>
		</view>

		<!-- 操作提示 -->
		<view class="tips-section">
			<view class="tips-title">温馨提示</view>
			<view class="tips-list">
				<view class="tip-item">
					<view class="tip-dot"></view>
					<text>二维码每5分钟自动刷新，请勿截图使用</text>
				</view>
				<view class="tip-item">
					<view class="tip-dot"></view>
					<text>签到成功后可进入场馆开始训练</text>
				</view>
				<view class="tip-item">
					<view class="tip-dot"></view>
					<text>如有问题请联系前台工作人员</text>
				</view>
			</view>
		</view>

		<!-- 底部按钮（仅保留刷新二维码，隐藏签到和清除缓存按钮） -->
		<view class="bottom-actions">
			<button class="btn-refresh" @tap="refreshQR">
				<uni-icons type="refresh" size="36rpx" color="#5E6F8D"></uni-icons>
				<text>刷新二维码</text>
			</button>
		</view>
	</view>
</template>

<script setup>
import { ref } from 'vue';
import { onLoad, onUnload } from '@dcloudio/uni-app'
// 引入状态组件（路径与你保持一致）
import QrStatus from '@/components/QRCode/StatusCard.vue'

	// 测试模式配置
	const TEST_MODE = true // 开启测试模式
	
	let image = ref("")
	let width = ref(0)
	let height = ref(0)
	let status = ref('loading')
	let socketTask = null
	const scanStatus = ref(false)
	const QRStatus = ref("生成中...")
	const STQRC = ref(false)//是否扫码
	const isCheckIn = ref(false)
	const webSoketURL = "ws://localhost:8084/webSocket/checkIn"
	
	const qrcode = ref("")
	
	// 新增：自定义错误文本变量
	const errorText = ref('')

	/**
	 * 缓存键名前缀
	 */
	const CACHE_PREFIX = 'QR_'

	/**
	 * 获取带前缀的缓存键名
	 * @param {string} key - 原始键名
	 * @returns {string} 带前缀的键名
	 */
	const getCacheKey = (key) => {
		return CACHE_PREFIX + key
	}

	/**
	 * 获取今日23:59:59的时间戳（当日过期时间）
	 * @returns {number} 今日23:59:59的时间戳
	 */
	const getTodayExpireTime = () => {
		const now = new Date()
		const expire = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59, 999)
		return expire.getTime()
	}

	/**
	 * 检查缓存是否过期
	 * @param {string} key - 缓存键名（不带前缀）
	 * @returns {boolean} 是否有效（未过期）
	 */
	const isCacheValid = (key) => {
		try {
			const cacheKey = getCacheKey(key)
			const cacheData = uni.getStorageSync(cacheKey)
			if (!cacheData) return false
			
			if (typeof cacheData === 'object' && cacheData.expireTime) {
				const now = Date.now()
				return now <= cacheData.expireTime
			}
			return false
		} catch (e) {
			console.error('检查缓存有效性失败:', e)
			return false
		}
	}

	/**
	 * 获取缓存数据（自动校验过期时间）
	 * @param {string} key - 缓存键名（不带前缀）
	 * @returns {any} 缓存数据（过期返回null）
	 */
	const getCacheData = (key) => {
		try {
			if (!isCacheValid(key)) {
				// 缓存已过期，清除缓存
				uni.removeStorageSync(getCacheKey(key))
				return null
			}
			
			const cacheData = uni.getStorageSync(getCacheKey(key))
			if (typeof cacheData === 'object' && cacheData.data !== undefined) {
				return cacheData.data
			}
			return null
		} catch (e) {
			console.error('获取缓存数据失败:', e)
			return null
		}
	}

	/**
	 * 设置缓存数据（自动设置当日23:59:59过期）
	 * @param {string} key - 缓存键名（不带前缀）
	 * @param {any} data - 要缓存的数据
	 */
	const setCacheData = (key, data) => {
		try {
			const cacheData = {
				data: data,
				expireTime: getTodayExpireTime()
			}
			uni.setStorageSync(getCacheKey(key), cacheData)
		} catch (e) {
			console.error('设置缓存数据失败:', e)
		}
	}

	/**
	 * 清除所有与签到相关的缓存（用于测试阶段）
	 */
	const clearQRCache = () => {
		try {
			const keys = uni.getStorageInfoSync().keys || []
			let clearedCount = 0
			for (const key of keys) {
				// 清除 QR_ 开头的缓存（页面内部缓存）
				if (key.startsWith(CACHE_PREFIX)) {
					uni.removeStorageSync(key)
					clearedCount++
				}
				// 清除 API_CACHE_ 开头的缓存（通过 utils/cache.js 缓存的接口数据）
				if (key.startsWith('API_CACHE_')) {
					// 只清除与签到相关的 API 缓存
					if (key.includes('checkIn') || key.includes('qrcode')) {
						uni.removeStorageSync(key)
						clearedCount++
					}
				}
			}
			console.log(`已清除 ${clearedCount} 个签到相关缓存`)
			return clearedCount
		} catch (e) {
			console.error('清除 QR 缓存失败:', e)
			return 0
		}
	}

	/**
	 * 测试用：手动清除缓存按钮点击事件
	 */
	const handleClearCache = () => {
		uni.showModal({
			title: '清除缓存',
			content: '确定要清除所有签到相关的缓存吗？（测试用）',
			confirmText: '确定',
			cancelText: '取消',
			success: (res) => {
				if (res.confirm) {
					const clearedCount = clearQRCache()
					// 重置页面状态
					image.value = ""
					width.value = 0
					height.value = 0
					status.value = 'loading'
					QRStatus.value = "生成中..."
					STQRC.value = false
					isCheckIn.value = false
					
					uni.showToast({
						title: `已清除 ${clearedCount} 个缓存`,
						icon: 'success',
						duration: 2000
					})
					
					// 重置页面状态后不再自动请求二维码
					uni.hideLoading()
				}
			}
		})
	}

	onLoad(() => {
		// 测试模式下不显示全局loading，让页面内的加载动画显示
		if (!TEST_MODE) {
			uni.showLoading({
			    title: '生成签到二维码...',
			    mask: true
			})
		}
		
		// 测试模式：直接生成假二维码，内容为"欢迎来到活氧舱"
		if (TEST_MODE) {
			console.log("测试模式：生成假二维码")
			generateTestQRCode()
			return
		}
		
		// 读取签到状态缓存（自动检查过期）
		// isCheckIn 代表签到状态，从缓存读取
		const cachedIsCheckIn = getCacheData("isCheckIn")
		// checkInTime 代表具体签到时间，从缓存读取（显示在 loading-text 中）
		const cachedCheckInTime = getCacheData("checkInTime")
		
		if(cachedIsCheckIn != null) {
			console.log("进入缓存 - 签到状态")
			isCheckIn.value = cachedIsCheckIn
			STQRC.value = true
		}
		
		// 如果已经签到成功，直接显示成功状态，不需要请求后端
		if(isCheckIn.value) {
			console.log("已签到且有缓存，无需请求后端")
			// 读取二维码图片缓存用于显示
			const cachedQRInfo = getCacheData("QRInfo")
			if(cachedQRInfo) {
				image.value = cachedQRInfo.qrCodeBase64
				width.value = cachedQRInfo.width * 2
				height.value = cachedQRInfo.height * 2
			}
			// QRStatus 显示具体签到时间（从缓存读取，显示在 loading-text 中）
			QRStatus.value = cachedCheckInTime || "已完成签到"
			uni.hideLoading()
			return
		}
		
		// 未签到或缓存失效，需要请求后端获取二维码
		// QRStatus 重置为默认的请求状态
		QRStatus.value = "生成中..."
		getStorage(null)
	})
	
	// 测试模式：生成假二维码（内容为"欢迎来到活氧舱"）
	// 不发送请求，使用缓存机制避免重复请求，二维码内容保持不变
	// @param {boolean} isRefresh - 是否是刷新操作（true=点击刷新按钮，false=首次进入页面）
	const generateTestQRCode = (isRefresh = false) => {
		// 检查是否有缓存的二维码图片
		const cachedQRImage = getCacheData("TestQRImage")
		const qrContent = "欢迎来到活氧舱"
		
		if (cachedQRImage) {
			// 使用缓存的二维码图片，不发送请求
			console.log("测试模式：使用缓存的二维码图片")
			image.value = cachedQRImage.image
			width.value = cachedQRImage.width
			height.value = cachedQRImage.height
			qrcode.value = qrContent
			status.value = 'waiting'
			QRStatus.value = '请出示二维码签到'
			uni.hideLoading()
			
			// 只有刷新操作才显示提示
			if (isRefresh) {
				uni.showToast({
					title: '二维码已刷新',
					icon: 'success',
					duration: 1500
				})
			}
			return
		}
		
		// 首次生成，发送一次请求并缓存
		console.log("测试模式：首次生成二维码，发送请求并缓存")
		setTimeout(() => {
			qrcode.value = qrContent
			
			const qrUrl = `https://api.qrserver.com/v1/create-qr-code/?size=300x300&data=${encodeURIComponent(qrContent)}`
			
			uni.request({
				url: qrUrl,
				method: 'GET',
				responseType: 'arraybuffer',
				success: (res) => {
					const base64 = uni.arrayBufferToBase64(res.data)
					const qrImage = `data:image/png;base64,${base64}`
					
					image.value = qrImage
					width.value = 500
					height.value = 500
					status.value = 'waiting'
					QRStatus.value = '请出示二维码签到'
					
					// 缓存二维码图片，后续刷新不再请求
					setCacheData("TestQRImage", {
						image: qrImage,
						width: 500,
						height: 500,
						content: qrContent
					})
					
					uni.hideLoading()
				},
				fail: () => {
					image.value = ''
					width.value = 500
					height.value = 500
					status.value = 'waiting'
					QRStatus.value = '测试模式 - 欢迎来到活氧舱'
					uni.hideLoading()
				}
			})
		}, 500)
	}
	
	// 页面卸载时关闭WebSocket连接（不清除缓存，让缓存自然过期）
	onUnload(() => {
		closeWebSocket()
		// 缓存会在当日23:59:59自动过期，页面卸载时不主动清除
		// 如需测试，使用页面上的"清除缓存"按钮手动清除
	})
	
	// 获取二维码接口
	const fetchQRCode = () => {
		console.log(1111)
	    status.value = ''
	    errorText.value = '' // 重置错误文本
	    image.value = ""
	    
	    getQRCode({ cache: true, cacheTime: 5 * 60 * 1000 }).then(res => {
	        console.log(res)
	        // 保存到本地缓存（用于签到状态判断）
	        setCacheData("QRInfo", res)
	        getStorage(res)
	        qrcode.value = res.qrContent
	    }).catch(err => {
	        console.error('获取二维码失败:', err)
	        status.value = 'error'
	        errorText.value = err.message || '获取二维码失败'
	        uni.showToast({
	            title: errorText.value,
	            icon: 'error'
	        })
	    }).finally(() => {
	        uni.hideLoading()
	    })
	}
	
	const refreshQR = () => {
		// 如果已签到，不允许刷新二维码
		if (isCheckIn.value) {
			uni.showToast({
				title: '您已签到',
				icon: 'none',
				duration: 2000
			})
			return
		}
		
		// 清空图片，显示加载状态
		image.value = ""
		QRStatus.value = "正在刷新二维码..."
		
		// 测试模式：重新生成二维码，但不发送请求，内容不变
		if (TEST_MODE) {
			// 延迟显示，让用户看到刷新效果
			setTimeout(() => {
				generateTestQRCode(true) // 传递 isRefresh=true
			}, 300)
			return
		}
		
		// 非测试模式：正常刷新逻辑
		setTimeout(() => {
			getStorage(null)
		}, 500)
	}
	
	const getStorage = res => {
		let data = res
		if(data == null) {
			// 使用带过期检查的缓存读取
			data = getCacheData("QRInfo")
			uni.hideLoading()
		}
		if(!data) fetchQRCode()
		
		if(data) {
			image.value = data.qrCodeBase64
			// 使用带过期时间的缓存（当日23:59:59过期）
			setCacheData("QRInfo", data)
			width.value = data.width * 2
			height.value = data.height * 2
			
			// 只有在未签到的情况下才连接WebSocket等待扫码
			if (data.qrContent && !isCheckIn.value) {
			    console.log("未签到，连接WebSocket等待扫码")
			    connectWebSocket(data.qrContent)
			} else if (isCheckIn.value) {
			    console.log("已签到，无需连接WebSocket")
			}
		}
	}
	
	const handleLongPress = () => {
		uni.scanCode({
			onlyFromCamera: false,
			scanType: ['qrCode'],
			success: (res) => {
				console.log('扫码结果:', res)
				// 测试模式下，如果扫描的是我们生成的二维码内容，直接模拟签到成功
				if (TEST_MODE && res.result === '欢迎来到活氧舱') {
					console.log('测试模式：模拟签到成功')
					handleTestModeCheckIn()
					return
				}
				checkIn(res.result)
			},
			fail: (err) => {
				console.error('扫码失败:', err)
				uni.showToast({
					title: '扫码失败',
					icon: 'none'
				})
			}
		})
	}
	
	// 测试模式：模拟签到成功（不请求后端）
	const handleTestModeCheckIn = () => {
		closeWebSocket()
		const now = new Date()
		const dateTime = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')} ${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}`
		
		status.value = 'scanned'
		errorText.value = ''
		QRStatus.value = `${dateTime} 成功签到`
		isCheckIn.value = true
		STQRC.value = true
		
		setCacheData("checkInTime", QRStatus.value)
		setCacheData("isCheckIn", isCheckIn.value)
		
		uni.showToast({
			title: '签到成功！',
			icon: 'success',
			duration: 2000
		})
	}
	
	// 手动签到接口
	const checkIn = (qrContent) => {
		console.log(qrContent)
		apiCheckIn({ qrContent }).then(res => {
			closeWebSocket()
			console.log(res)
			status.value = 'scanned'
			errorText.value = '' // 成功重置错误文本
			QRStatus.value = res.dateTime + " 成功签到"
			isCheckIn.value = true
			// 使用带过期时间的缓存（当日23:59:59过期）
			setCacheData("checkInTime", QRStatus.value)
			setCacheData("isCheckIn", isCheckIn.value)
			uni.showToast({
				title: '签到成功！',
				icon: 'success',
				duration: 2000
			})
		}).catch(err => {
			console.error('签到请求失败:', err)
			status.value = 'error'
			errorText.value = err.message || '签到失败，请重试' // 对应错误文案
			uni.showToast({
			    title: err.message,
			    icon: 'none'
			})
		})
	}
	
	// 建立WebSocket连接
	const connectWebSocket = (qrContent) => {
	    
	    console.log('WebSocket 连接地址:', webSoketURL)
	    
	    socketTask = uni.connectSocket({
	        url: webSoketURL,
	        success: () => {
	            console.log('WebSocket 连接中...')
	        },
	        fail: (err) => {
	            console.error('WebSocket 连接失败:', err)
	            status.value = 'error'
	            errorText.value = '连接失败，请重试' // 对应错误文案
	        }
	    })
	    
	    // 连接打开成功
	    socketTask.onOpen(() => {
	        console.log('WebSocket 连接成功')
	        status.value = 'waiting'
			errorText.value = '' // 成功重置错误文本
	        sendQRCodeInfo(qrContent)
	    })
	    
	    // 发送二维码信息到后端
	    const sendQRCodeInfo = (qrContent) => {
	        const qrCodeDto = {
	            qrContent: qrContent,
	            used: false
	        }
	        
	        console.log('发送二维码信息:', qrCodeDto)
	        
	        socketTask.send({
	            data: JSON.stringify(qrCodeDto),
	            success: () => {
	                console.log('二维码信息发送成功')
	            },
	            fail: (err) => {
	                console.error('发送失败:', err)
	                status.value = 'error'
	                errorText.value = '连接失败，请重试' // 对应错误文案
	            }
	        })
	    }
	    
	    // 接收后端消息
	    socketTask.onMessage((res) => {
	        console.log('收到 WebSocket 消息:', res.data)
	        const message = res.data

	        if (message === '正在进行签到') {
				// 显示遮罩，防止用户重复扫码
				QRStatus.value = "正在进行签到..."
				STQRC.value = true
	        } else if (message === '签到成功' || message.includes('签到成功')) {
				// 签到成功，更新状态
				status.value = 'scanned'
				errorText.value = ''
				isCheckIn.value = true
				QRStatus.value = "签到成功"
				// 缓存签到状态
				setCacheData("isCheckIn", true)
				setCacheData("checkInTime", "签到成功")
				uni.showToast({
				    title: '签到成功！',
				    icon: 'success',
				    duration: 2000
				})
				// 关闭WebSocket连接
				closeWebSocket()
	        } else if (message.startsWith('二维码无效')) {
	            uni.showToast({
	                title: message,
	                icon: 'none',
	                duration: 2000
	            })
	            status.value = 'error'
	            errorText.value = '二维码无效，请刷新'
				// 隐藏遮罩，允许用户重新操作
				STQRC.value = false
				QRStatus.value = "生成中..."
	            setTimeout(() => {
	                closeWebSocket()
	            }, 3000)
	        } else if (message === '消息格式错误') {
	            status.value = 'error'
	            errorText.value = '消息格式错误'
				// 隐藏遮罩，允许用户重新操作
				STQRC.value = false
				QRStatus.value = "生成中..."
	        } else if (message.includes('失败') || message.includes('错误')) {
				// 其他失败情况
				uni.showToast({
				    title: message,
				    icon: 'none',
				    duration: 2000
				})
				status.value = 'error'
				errorText.value = message
				// 隐藏遮罩，允许用户重新操作
				STQRC.value = false
				QRStatus.value = "生成中..."
			} else {
	            console.log('未知消息:', message)
	        }
	    })
	    
	    // 连接关闭
	    socketTask.onClose(() => {
	        console.log('WebSocket 连接关闭')
	        status.value = 'closed'
			errorText.value = '' // 重置错误文本
	    })
	    
	    // 连接错误
	    socketTask.onError((err) => {
	        console.error('WebSocket 错误:', err)
	        status.value = 'error'
	        errorText.value = '连接失败，请重试' // 对应错误文案
	    })
	}
	
	// 关闭WebSocket连接
	const closeWebSocket = () => {
	    if (socketTask) {
	        socketTask.close({
	            success: () => {
	                console.log('主动关闭 WebSocket')
	            }
	        })
	        socketTask = null
	    }
	}
</script>

<style lang="scss" scoped>
.checkin-page {
	min-height: 100vh;
	background-color: #F9FAFE;
	padding-top: 200rpx; /* 为固定顶部导航预留空间 */
	padding-bottom: 160rpx; /* 为底部按钮预留空间 */
	box-sizing: border-box;
}

/* 顶部导航（固定顶部） */
.header {
	position: fixed;
	top: 0;
	left: 0;
	right: 0;
	z-index: 99998; /* 低于底部按钮，确保底部按钮永远最上层 */
	background: linear-gradient(135deg, #7AB5CC 0%, #9CCFDF 100%);
	padding: 64rpx 48rpx 48rpx;
	text-align: center;
	color: #FFFFFF;
	border-bottom-left-radius: 56rpx;
	border-bottom-right-radius: 56rpx;
	box-shadow: 0 4rpx 20rpx rgba(120, 185, 215, 0.3);
	
	.header-title {
		font-size: 45rpx;
		font-weight: 700;
		margin-bottom: 8rpx;
	}
	
	.header-subtitle {
		font-size: 26rpx;
		opacity: 0.8;
	}
}

/* 通用卡片样式 */
.card-default {
	background: #FFFFFF;
	border-radius: 40rpx;
	box-shadow: 0 16rpx 40rpx rgba(0, 0, 0, 0.03), 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
	border: 1rpx solid #E9EDF2;
	padding: 32rpx;
}

/* 会员信息卡片 */
.member-card {
	margin: 0 32rpx 48rpx;
	display: flex;
	align-items: center;
	padding: 32rpx;
	flex-wrap: nowrap;
	
	.member-avatar {
		width: 120rpx;
		height: 120rpx;
		border-radius: 999px;
		overflow: hidden;
		border: 4rpx solid #7AB5CC;
		flex-shrink: 0;
		
		image {
			width: 100%;
			height: 100%;
		}
	}
	
	.member-info {
		flex: 1;
		margin-left: 32rpx;
		flex-shrink: 1;
		min-width: 0;
		
		.member-name {
			font-size: 32rpx;
			font-weight: 500;
			color: #1E2A3A;
			margin-bottom: 8rpx;
			white-space: nowrap;
			overflow: hidden;
			text-overflow: ellipsis;
		}
		
		.member-level {
			display: flex;
			align-items: center;
			gap: 16rpx;
			flex-wrap: wrap;
			
			.level-badge {
				background: linear-gradient(135deg, #7AB5CC 0%, #9CCFDF 100%);
				color: white;
				padding: 4rpx 16rpx;
				border-radius: 24rpx;
				font-size: 22rpx;
				font-weight: 500;
				flex-shrink: 0;
			}
			
			.valid-date {
				font-size: 22rpx;
				color: #5E6F8D;
				white-space: nowrap;
				overflow: hidden;
				text-overflow: ellipsis;
			}
		}
	}
	
	.member-points {
		text-align: center;
		flex-shrink: 0;
		margin-left: 16rpx;
		
		.points-value {
			font-size: 38rpx;
			font-weight: 700;
			color: #7AB5CC;
		}
		
		.points-label {
			font-size: 22rpx;
			color: #5E6F8D;
		}
	}
}

/* 二维码容器 */
.qr-container {
	margin: 0 32rpx 48rpx;
	padding: 48rpx 32rpx;
	text-align: center;
	
	.qr-header {
		margin-bottom: 64rpx;
		
		.qr-title {
			font-size: 38rpx;
			font-weight: 700;
			color: #1E2A3A;
			margin-bottom: 8rpx;
		}
		
		.qr-tip {
			font-size: 26rpx;
			color: #5E6F8D;
		}
	}
}

/* 二维码核心区域 */
.QRBox {
	position: relative;
	display: flex;
	justify-content: center;
	align-items: center;
	margin: 0 auto 64rpx;
	max-width: 100%;
	min-height: 580rpx; /* 设置最小高度确保加载动画区域可见 */

	.QR {
		position: relative;
		z-index: 2;
		padding: 20rpx;
		background: white;
		border-radius: 40rpx;
	}
	
	.loadingBox {
		position: absolute;
		top: 50%;
		left: 50%;
		transform: translate(-50%, -50%);
		z-index: 3;
		display: flex;
		justify-content: center;
		align-items: center;
		background: rgba(255, 255, 255, 0.95);
		border-radius: 40rpx;
		
		.loading-spinner {
			display: flex;
			flex-direction: column;
			align-items: center;
			gap: 16rpx;
			
			.spinner-circle {
				width: 80rpx;
				height: 80rpx;
				border: 6rpx solid #E9EDF2;
				border-top-color: #7AB5CC;
				border-radius: 50%;
				animation: spin 1s linear infinite;
			}
			
			.loading-text {
				font-size: 26rpx;
				color: #5E6F8D;
				width: 250rpx;
			}
		}
	}
	
	/* 二维码装饰边框 */
	.qr-border {
		position: absolute;
		top: 50%;
		left: 50%;
		transform: translate(-50%, -50%);
		z-index: 1;
		
		.corner {
			position: absolute;
			width: 48rpx;
			height: 48rpx;
			border: 6rpx solid #7AB5CC;
			
			&.top-left {
				top: 0;
				left: 0;
				border-right: none;
				border-bottom: none;
				border-top-left-radius: 40rpx;
			}
			
			&.top-right {
				top: 0;
				right: 0;
				border-left: none;
				border-bottom: none;
				border-top-right-radius: 40rpx;
			}
			
			&.bottom-left {
				bottom: 0;
				left: 0;
				border-right: none;
				border-top: none;
				border-bottom-left-radius: 40rpx;
			}
			
			&.bottom-right {
				bottom: 0;
				right: 0;
				border-left: none;
				border-top: none;
				border-bottom-right-radius: 40rpx;
			}
		}
	}
}

/* 温馨提示 */
.tips-section {
	margin: 0 32rpx 48rpx;
	
	.tips-title {
		font-size: 32rpx;
		font-weight: 500;
		color: #1E2A3A;
		margin-bottom: 32rpx;
	}
	
	.tips-list {
		background: #FFFFFF;
		border-radius: 40rpx;
		padding: 32rpx;
		border: 1rpx solid #E9EDF2;
		
		.tip-item {
			display: flex;
			align-items: flex-start;
			gap: 16rpx;
			margin-bottom: 16rpx;
			
			&:last-child {
				margin-bottom: 0;
			}
			
			.tip-dot {
				width: 12rpx;
				height: 12rpx;
				background: #7AB5CC;
				border-radius: 50%;
				margin-top: 12rpx;
				flex-shrink: 0;
			}
			
			text {
				font-size: 26rpx;
				color: #5E6F8D;
				line-height: 1.6;
			}
		}
	}
}

/* 底部按钮（z-index永久置顶+安全区域适配） */
.bottom-actions {
	position: fixed;
	bottom: 0;
	left: 0;
	right: 0;
	z-index: 99999; /* 极高z-index确保永远在最上层 */
	padding: 32rpx 48rpx calc(32rpx + env(safe-area-inset-bottom));
	background: #FFFFFF;
	border-top: 1rpx solid #E9EDF2;
	box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.05);

	.btn-refresh {
		width: 100%;
		height: 88rpx;
		background: #F2F5F9;
		color: #5E6F8D;
		border: none;
		border-radius: 999px;
		font-size: 29rpx;
		display: flex;
		align-items: center;
		justify-content: center;
		gap: 16rpx;
		margin-bottom: 20rpx;
		
		&:active {
			background: #E9EDF2;
		}
	}
}

/* 测试用：清除缓存按钮 */
.btn-clear-cache {
	width: calc(100% - 96rpx);
	height: 88rpx;
	background: #FEF2F2;
	color: #EF4444;
	border: 1rpx solid #FECACA;
	border-radius: 999px;
	font-size: 29rpx;
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 16rpx;
	
	&:active {
		background: #FEE2E2;
	}
}

/* 旋转动画 */
@keyframes spin {
	0% { transform: rotate(0deg); }
	100% { transform: rotate(360deg); }
}

/* 暗色模式适配 */
@media (prefers-color-scheme: dark) {
	.checkin-page {
		background-color: #121826;
	}
	
	.header {
		background: linear-gradient(135deg, #5A98B0 0%, #7AB5CC 100%);
		box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.3);
	}
	
	.card-default {
		background: #1E2636;
		border-color: #2A3346;
		box-shadow: 0 16rpx 40rpx rgba(0, 0, 0, 0.4);
	}
	
	.member-card .member-info .member-name {
		color: #EDF2F7;
	}
	
	.member-card .member-info .member-level .valid-date,
	.member-card .member-points .points-label {
		color: #9AA9C1;
	}
	
	.qr-container .qr-header .qr-title {
		color: #EDF2F7;
	}
	
	.qr-container .qr-header .qr-tip {
		color: #9AA9C1;
	}
	
	.QRBox .loadingBox {
		background: rgba(30, 38, 54, 0.95);
	}
	
	.QRBox .loadingBox .loading-spinner .loading-text {
		color: #9AA9C1;
	}
	
	.tips-section .tips-title {
		color: #EDF2F7;
	}
	
	.tips-section .tips-list {
		background: #1E2636;
		border-color: #2A3346;
	}
	
	.tips-section .tips-list .tip-item text {
		color: #9AA9C1;
	}
	
	.bottom-actions {
		background: #1E2636;
		border-color: #2A3346;
		box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.2);
	}
	
	.bottom-actions .btn-refresh {
		background: #0F141F;
		color: #9AA9C1;
		
		&:active {
			background: #2A3346;
		}
	}
	
	.btn-clear-cache {
		background: #3D1919;
		color: #FCA5A5;
		border-color: #5C2B2B;
		
		&:active {
			background: #4A2525;
		}
	}
}
</style>