<template>
	<view class="project-container">
		<!-- 顶部一排：项目选择 + 全局设置 + 添加分组 -->
		<view class="header-row">
			<view class="header-item project-select-half" @click="showProjectSelect = true">
				<text class="header-text">{{ selectedProject?.name || '请选择项目' }}</text>
				<view class="header-icon-wrap gray">
					<u-icon name="arrow-down" size="14" color="#666"></u-icon>
				</view>
			</view>
			<view v-if="selectedProject" class="header-item global-setting-half" @click="showSetting = true">
				<view class="header-setting-text">{{ setting.mode=='interval'?'间隔':'一起'  }}{{ setting.mode=='interval'?'·'+ setting.interval+'s':'' }}</view>
				<view class="header-icon-wrap blue">
					<u-icon name="setting" size="14" color="#1890ff"></u-icon>
				</view>
			</view>
			<view v-if="selectedProject" class="header-item add-group-half" @click="addGroup">
				<text class="header-text">添加分组</text>
				<view class="header-icon-wrap green">
					<u-icon name="plus" size="14" color="#52c41a"></u-icon>
				</view>
			</view>
		</view>

		<!-- 分组计时器列表 -->
		<view v-for="group in groups" :key="group.id" class="card-section">
			<view class="section-header">
				<view class="group-title-wrapper">
					<text class="section-title">{{ group.name }} · 总时长  {{  group.allTime}} </text>
				</view>
				<view class="group-controls">
						<view @click="deleteGroup(group)" class="group-control-btn setting-btn">
							<u-icon name="trash" size="16" color="#fff"></u-icon>
						</view>
						<view @click="addTimer(group)" class="group-control-btn setting-btn">
							<u-icon name="plus" size="16" blod='true' color="#fff"></u-icon>
						</view>
						<!-- 有运行中/间隔出发中的学生时显示暂停按钮 -->
						<view v-if="!isGroupAllCompleted(group) && (isGroupAllRunning(group) || isGroupDeparting(group))"
							class="group-control-btn pause-btn" @click="pauseGroup(group)">
							<u-icon name="pause-circle" size="16" color="#fff"></u-icon>
						</view>
						<!-- 有未出发或暂停学生时显示开始按钮 -->
						<view v-else-if="!isGroupAllCompleted(group) && hasGroupStartable(group)"
							class="group-control-btn start-btn" @click="startGroup(group)">
							<u-icon name="play-circle" size="16" color="#fff"></u-icon>
						</view>
				</view>
			</view>

			<view class="timers-grid">
				<view v-for="(timer, index) in group.timers" :key="timer.id" class="timer-card-wrapper">
					<view class="timer-circle" :class="{ resting: timer.isResting }" @click="recordTimer(timer)">
						<view class="timer-header">
							<view class="timer-name-top-left" @click.stop="openTimerDetail(timer)">
								<text class="name-text">{{ timer.studentName }}</text>
							</view>
							<view class="delete-btn-wrapper">
								<view class="delete-btn" @click.stop="deleteTimer(timer, group, index)">
									<u-icon name="trash" size="14" color="#fff"></u-icon>
								</view>
							</view>
						</view>

						<view class="circle-content-wrapper" >
							<view class="circle-content" :class="{ resting: timer.isResting }">
								<view class="circle-inner">
									<view v-if="timer.status === 'completed'" class="timer-status-completed">
										已完成
									</view>
									<view v-else-if="timer.isResting" class="timer-rest-countdown">
										<text class="rest-label">休息</text>
										<text class="rest-time">{{ formatRestCountdown(timer.restCountdown || 0) }}</text>
									</view>
									<view v-else class="">
										<text class="timer-label">目标时间：{{  formatTime(timer.targetTime) }}</text>
										<view  class="timer-time">{{ formatTime(timer) }}</view>
									</view>
									<view class="timer-info">
										<text class="timer-duration">{{ timer.records.length }}/{{ timer.totalLapCount || 4 }}圈</text>
									</view>
								</view>
							</view>
						</view>

						<view class="timer-controls">
							<view @click.stop="openTimerDetail(timer)">
								<u-icon name="edit-pen" size="24" color="#22a6f2"></u-icon>
							</view>
							<view @click.stop="toggleTimer(timer)" class="">
								<u-icon
									:name="timer.status === 'running' || timer.status === 'resting' ? 'pause-circle' : 'play-circle'"
									size="24" :color="timer.status === 'resting' ? '#faad14' : '#22a6f2'"></u-icon>
							</view>
						</view>
					</view>
				</view>
			</view>
		</view>

		<!-- 底部按钮区域 -->
		<view v-if="selectedProject" class="bottom-buttons-section">
			<view class="bottom-buttons">

				
				<button v-if="!hasRunningTimers" class="bottom-btn start-all-btn" @click="startAllTimers">
					<u-icon name="play-circle" size="20" color="#fff"></u-icon>
					<text class="btn-text">全部开始</text>
				</button>
				<button v-else class="bottom-btn pause-all-btn" @click="pauseAllTimers">
					<u-icon name="pause-circle" size="20" color="#fff"></u-icon>
					<text class="btn-text">全部暂停</text>
				</button>
				<button class="bottom-btn reset-all-btn" @click="resetAllTimers">
					<u-icon name="reload" size="20" color="#fff"></u-icon>
					<text class="btn-text">重置</text>
				</button>
				<button class="bottom-btn submit-btn" @click="submitData">
					<u-icon name="checkmark" size="20" color="#fff"></u-icon>
					<text class="btn-text">提交</text>
				</button>
			</view>
		</view>

		<!-- 底部弹出框 - 秒表详情 -->
		<u-popup v-model:show="showTimerDetail" :safeAreaInsetTop='true' :mode="isLandscape ? 'center' : 'bottom'" :width="isLandscape ? '55vw' : '100%'" :round="20" :closeable="true" closeOnClickOverlay>
			<view class="timer-detail-popup" :class="{ landscape: isLandscape }">
				<view class="mode-tabs">
					<view class="mode-tab" :class="{ active: !isEditMode }" @click="isEditMode = false">
						<text class="mode-tab-text">计时详情</text>
					</view>
					<view class="mode-tab" :class="{ active: isEditMode }" @click="isEditMode = true">
						<text class="mode-tab-text">编辑设置</text>
					</view>
				</view>

				<view v-if="!isEditMode">
					<view class="detail-name">{{ selectedTimer?.studentName || '计时器' }}</view>
					<view class="stopwatch-display">
						<text class="stopwatch-time">{{ formatStopwatchTime(selectedTimer?.elapsedTime || 0) }}</text>
						<text class="stopwatch-millis">{{ formatMillis(selectedTimer?.elapsedTime || 0) }}</text>
					</view>
					<view class="current-settings-info">
						<view class="setting-info-item">
							<text class="setting-info-label">目标时间:</text>
							<text
								class="setting-info-value">{{ formatTargetTime(selectedTimer?.targetTime || 0) }}</text>
						</view>
						<view class="setting-info-item">
							<text class="setting-info-label">休息时间:</text>
							<text class="setting-info-value">{{ selectedTimer?.restTime || 0 }}秒</text>
						</view>
						<view class="setting-info-item">
							<text class="setting-info-label">总圈数:</text>
							<text class="setting-info-value">{{ selectedTimer?.totalLapCount || 0 }}圈</text>
						</view>
					</view>
					<scroll-view scroll-y class="records-list"
						v-if="selectedTimer?.records && selectedTimer.records.length > 0">
						<view v-for="(record, idx) in selectedTimer.records" :key="idx" class="record-item">
							<view class="record-info">
								<text class="record-index">记录 {{ idx + 1 }}</text>
								<text class="record-time">{{ formatAdjustedRecordTime(record.time, selectedTimer) }}</text>
							</view>
						</view>
					</scroll-view>
					<view class="detail-buttons">
						<view class="detail-btn detail-btn-reset" @click="resetSelectedTimer">
							<u-icon name="reload" size="28" color="#fff"></u-icon>
							<text class="btn-label">重置</text>
						</view>
						<view class="detail-btn detail-btn-main" @click="toggleSelectedTimer">
							<u-icon :name="selectedTimer?.status === 'running' || selectedTimer?.status === 'resting' ? 'pause-circle' : 'play-circle'" size="36"
								color="#fff"></u-icon>
							<text class="btn-label">{{ selectedTimer?.status === 'running' || selectedTimer?.status === 'resting' ? '暂停' : '开始' }}</text>
						</view>
						<view class="detail-btn detail-btn-record" @click="recordLap"
							:class="{ disabled: selectedTimer?.status !== 'running' && selectedTimer?.status !== 'resting' }">
							<u-icon name="edit-pen" size="28"
								:color="selectedTimer?.status === 'running' || selectedTimer?.status === 'resting' ? '#fff' : '#bfbfbf'"></u-icon>
							<text class="btn-label">记录</text>
						</view>
					</view>
				</view>

				<view v-else>
					<view class="edit-form">
						<view class="form-group">
							<text class="form-label">学生姓名</text>
							<view class="form-input-readonly">{{ selectedTimer?.studentName || '计时器' }}</view>
						</view>
						<view class="form-row">
							<view class="form-group">
								<text class="form-label">最大速度+几秒（秒）</text>
								<input class="form-input" v-model="editForm.additionalTime" type="number"
									placeholder="请输入最大速度+几秒" />
							</view>
							<view class="form-group">
								<text class="form-label">休息时间（秒）</text>
								<input class="form-input" v-model="editForm.restTime" type="number" placeholder="请输入休息时间" />
							</view>
							<view class="form-group">
								<text class="form-label">圈数</text>
								<input class="form-input" v-model="editForm.lapCount" type="number" placeholder="请输入圈数" />
							</view>
						</view>
						<view class="form-hint">
							<text class="hint-text">目标时间 = 学生最快速度 + 最大速度+几秒</text>
						</view>
					</view>
					<view class="edit-buttons">
						<view class="edit-btn edit-btn-cancel" @click="cancelEdit">
							<text class="edit-btn-text">取消</text>
						</view>
						<view class="edit-btn edit-btn-save" @click="saveEdit">
							<text class="edit-btn-text">保存</text>
						</view>
					</view>
				</view>
			</view>
		</u-popup>

		<!-- 添加计时器弹窗 -->
		<u-popup v-model:show="showAddTimerModal" mode="center" :round="20" :closeable="true" closeOnClickOverlay :width="isLandscape ? '55vw' : '600rpx'">
			<view class="add-timer-modal" :class="{ landscape: isLandscape }">
				<view class="modal-title">添加学生到本组</view>
				<scroll-view scroll-y class="add-timer-scroll">
					<view class="form-group">
						<text class="form-label">选择学生</text>
						<view class="student-selector">
							<view v-for="student in studentNames" :key="student.studentId" class="student-option"
								:class="{ selected: selectedStudent === student.studentId }"
								@click="selectAddTimerStudent(student)">
								<view class="student-checkbox">
									<u-icon v-if="selectedStudent === student.studentId" name="checkmark" size="16"
										color="#fff"></u-icon>
								</view>
								<text class="student-name">{{ student.name }}</text>
							</view>
							<view v-if="studentNames.length==0" style=" background-color: #f6f6f6; font-size: 28rpx; border-radius: 4rpx; padding: 14rpx 0; text-align: center; font-weight: bold; width: 100%; " class=""> 暂无可选学生</view>
						</view>
					</view>
					<view class="form-row">
						<view class="form-group">
							<text class="form-label">最快时间＋几秒</text>
							<input class="form-input" v-model="targetTimeInput" type="number" placeholder="请输入最快时间+几秒" />
						</view>
						<view class="form-group">
							<text class="form-label">休息时间（秒）</text>
							<input class="form-input" v-model="restTimeInput" type="number" placeholder="请输入休息时间" />
						</view>
						<view class="form-group">
							<text class="form-label">圈数</text>
							<input class="form-input" v-model="lapCountInput" type="number" placeholder="请输入圈数" />
						</view>
					</view>
					<view class="" style="width: 100%;  height: 90px; " >
						
					</view>
				</scroll-view>
				<view class="modal-buttons">
					<view class="modal-btn cancel-btn" @click="showAddTimerModal = false">取消</view>
					<view class="modal-btn confirm-btn" @click="confirmAddTimer">确认添加</view>
				</view>
			</view>
		</u-popup>

		<!-- 项目选择弹窗 -->
		<u-popup v-model:show="showProjectSelect" :mode="isLandscape ? 'left' : 'bottom'" :width="isLandscape ? '35%' : '100%'" :round="isLandscape ? 0 : 16" :closeable="true" closeOnClickOverlay>
			<view class="project-select-popup" :class="{ landscape: isLandscape }">
				<view class="popup-title">选择项目</view>
				<scroll-view scroll-y class="project-list-scroll">
					<view class="project-list">
						<view v-for="project in projects" :key="project.planId" class="project-item"
							:class="{ active: selectedProject?.planId === project.planId }"
							@click="selectProject(project)">
							<text class="project-name">{{ project.name }}</text>
							<u-icon v-if="selectedProject?.planId === project.planId" name="checkmark" size="20"
								color="#1890ff"></u-icon>
						</view>
					</view>
				</scroll-view>
			</view>
		</u-popup>

		<!-- 全局设置弹窗 -->
		<u-popup v-model:show="showSetting" mode="center" :round="16" :safeAreaInsetBottom='false' :closeable="true" >
			<view class="setting-modal" :class="{ landscape: isLandscape }">
				<view class="setting-title">出发设置</view>
				<view class="setting-item" :class="{ active: setting.mode === 'together' }"
					@click="setting.mode = 'together'">
					<view class="setting-radio">
						<view v-if="setting.mode === 'together'" class="radio-dot"></view>
					</view>
					<text class="setting-text">一起出发</text>
				</view>
				<view class="setting-item" :class="{ active: setting.mode === 'interval' }"
					@click="setting.mode = 'interval'">
					<view class="setting-radio">
						<view v-if="setting.mode === 'interval'" class="radio-dot"></view>
					</view>
					<text class="setting-text">间隔出发</text>
					<view v-if="setting.mode === 'interval'" class="interval-input-box">
						<input class="interval-input" v-model="setting.interval" type="number" placeholder="5" />
						<text class="interval-unit">秒</text>
					</view>
				</view>
				<view class="setting-confirm" @click="saveSetting">确定</view>
			</view>
		</u-popup>

		<!-- 组别设置弹窗 -->
		<u-popup v-model:show="showGroupSettingModal" mode="center" :round="20" :closeable="true" closeOnClickOverlay>
			<view class="group-setting-modal" :class="{ landscape: isLandscape }">
				<view class="modal-title">{{ groupSettingMode === 'add' ? '添加分组' : '组别设置' }}</view>
				<scroll-view scroll-y class="setting-scroll">
					<view class="form-group">
						<text class="form-label">组名</text>
						<input class="form-input" v-model="editingGroupName" placeholder="请输入组名" />
					</view>
					<view class="form-group">
						<text class="form-label">学生选择</text>
						<view class="student-selector">
							<view v-for="student in studentNames" :key="student.studentId" class="student-option"
								:class="{ selected: editingGroupStudents.includes(student.studentId) }"
								@click="toggleEditingGroupStudent(student)">
								<view class="student-checkbox">
									<u-icon v-if="editingGroupStudents.includes(student.studentId)" name="checkmark"
										size="16" color="#fff"></u-icon>
								</view>
								<text class="student-name">{{ student.name }}</text>
							</view>
						</view>
					</view>
					<view class="form-row">
						<view class="form-group">
							<text class="form-label">最快时间＋几秒</text>
							<input class="form-input" v-model="editingTargetTime" type="number" placeholder="秒" />
						</view>
						<view class="form-group">
							<text class="form-label">休息时间</text>
							<input class="form-input" v-model="editingRestTime" type="number" placeholder="秒" />
						</view>
						<view class="form-group">
							<text class="form-label">圈数</text>
							<input class="form-input" v-model="editingLapCount" type="number" placeholder="圈" />
						</view>
					</view>
					<view class="" style="width: 100%; height: 80px;" >
						
					</view>
				</scroll-view>
				
				<view class="modal-buttons">
					<view class="modal-btn cancel-btn" @click="showGroupSettingModal = false">取消</view>
					<view class="modal-btn confirm-btn" @click="confirmGroupSetting">
						{{ groupSettingMode === 'add' ? '确认添加' : '确认' }}
					</view>
				</view>
			</view>
		</u-popup>
	</view>
</template>

<script setup lang="ts">
	/**
	 * ================================================================================
	 * 项目计时页面 - 核心逻辑说明
	 * ================================================================================
	 * 
	 * 页面职责：
	 * 1. 展示并选择"计时项目"计划
	 * 2. 根据计划详情（plan）渲染分组和学生计时器
	 * 3. 支持"一起出发"和"间隔出发"两种模式的全局/分组计时控制
	 * 4. 支持学生卡片的圈数记录、休息倒计时、编辑设置
	 * 5. 支持添加/删除分组、添加/删除学生、保存计划设置
	 * 
	 * 核心数据公式：
	 * - 学生每圈目标时间（秒） = quicklyTime + pb
	 * - quicklyTime：学生最快时间（接口返回）
	 * - pb：在最快时间基础上增加的秒数（目标时间加成）
	 * - rest：每圈记录后的休息时间（秒）
	 * - circle：总圈数
	 */
	import { ref, computed, onUnmounted } from 'vue'
	import { onLoad } from '@dcloudio/uni-app'
	import { Service, PlanService } from '@/Service/swimming/PlanService'

	// ===================== 类型定义 =====================

	/** 单条圈数记录 */
	interface RecordItem {
		time : number // 记录时刻的当前累计时间（秒）
	}

	/** 单个学生计时器 */
	interface TimerItem {
		id : string // 唯一标识
		studentId : string // 学生ID
		currentTime : number // 当前累计游泳时间（秒），休息期间不累计
		countdownTime : number // 当前圈目标时间倒计时（秒），用于显示
		elapsedTime : number // 真实经过时间（秒），用于记录成绩，休息不暂停
		status : 'idle' | 'running' | 'paused' | 'completed' | 'resting'
		studentName : string // 学生姓名
		quicklyTime : number // 学生最快时间（秒）
		pb : number // 目标时间加成（秒）
		records : RecordItem[] // 每圈记录列表
		lapCount : number // 已完成圈数（兼容旧逻辑，实际使用 records.length）
		targetTime : number // 目标时间 = quicklyTime + pb（秒）
		groupId : string // 所属分组ID
		hasStarted : boolean // 是否已出发过（用于间隔出发模式）
		restTime : number // 休息时间（秒）
		totalLapCount : number // 总圈数
		restCountdown : number // 休息剩余时间（秒），用于显示
		isResting : boolean // 是否正在休息，用于显示
		pausedRestCountdown : number // 暂停时保存的剩余休息时间（秒）
		startTimestamp : number // 项目开始的真实时间戳（毫秒）
		lastRecordTimestamp : number // 上次记录时的真实时间戳（毫秒）
		currentLapTime : number // 当前圈已用时间（秒），用于记录
		hasRecordedThisLap : boolean // 当前圈是否已手动记录
	}

	/** 分组 */
	interface Group {
		id : string
		name : string
		timers : TimerItem[]
		hasStarted : boolean // 分组是否已出发（间隔出发模式用）
		targetTime : number // 分组默认pb（用于弹窗回显）
		restTime : number // 分组默认休息（用于弹窗回显）
		lapCount : number // 分组默认圈数（用于弹窗回显）
		allTime : number // 计划总时长（秒）
		students : string[] // 组内学生ID列表
		departureTimerId : number | null // 组内间隔出发定时器ID
		departureDueAt : number // 下次出发的预定时间戳（毫秒）
	}

	/** 学生选项（页面内用于选择） */
	interface StudentOption {
		studentId : string
		name : string
		quicklyTime : number
	}

	/** 接口返回的原始学生结构 */
	interface PlanStudentRaw {
		studentId : string
		name : string
		quicklyTime ?: number | string
		pb ?: number | string
		rest ?: number | string
		circle ?: number | string
	}

	/** 接口返回的原始分组结构 */
	interface PlanGroupRaw {
		groupId ?: string
		groupName ?: string
		gruopName ?: string // 接口历史拼写兼容
		group ?: PlanStudentRaw[] | string | null
		allTime ?: number | string // 计划总时长（秒）
	}

	/** 接口返回的原始计划结构 */
	interface PlanRaw {
		planId ?: string
		name ?: string
		departType ?: string // '一起出发' 或 '间隔出发'
		interval ?: number | string // 间隔出发的间隔秒数
		groupInt ?: number | string
		users ?: PlanStudentRaw[] | string | null // 未分组学生
		group ?: PlanGroupRaw[] | string | null // 分组数据
		addTime ?: string
		planType ?: string
		project ?: any
		subsectionDistance ?: any
		subsectionInt ?: any
		userId ?: string
	}

	// ===================== 通用工具函数 =====================

	/**
	 * 安全转换任意值为数字
	 * @param v 输入值
	 * @param d 转换失败时的默认值
	 */
	const toNumber = (v : any, d = 0) : number => {
		const n = Number(v)
		return Number.isFinite(n) ? n : d
	}

	/**
	 * 统一解析接口里的数组字段（有的接口直接给数组，有的给JSON字符串）
	 * @param v 接口原始值
	 */
	const parsePlanList = <T,>(v : T[] | string | null | undefined) : T[] => {
		if (Array.isArray(v)) return v
		if (typeof v === 'string' && v.trim()) {
			try {
				const p = JSON.parse(v)
				return Array.isArray(p) ? p : []
			} catch {
				return []
			}
		}
		return []
	}

	/** 生成分组唯一ID */
	const createGroupId = () : string => `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`

	/** 生成计时器唯一ID */
	const createTimerId = (groupId : string, studentId : string) : string => `${groupId}-${studentId}-${Date.now()}`

	/**
	 * 根据学生原始数据构建计时器对象
	 * @param student 学生原始数据
	 * @param groupId 所属分组ID
	 * @param overrides 可覆盖的字段（如pb、restTime、totalLapCount）
	 * 
	 * 业务说明：
	 * - targetTime（目标时间）= quicklyTime + pb
	 * - currentTime 初始为0，status为idle
	 */
	const buildTimer = (student : PlanStudentRaw, groupId : string, overrides ?: Partial<TimerItem>) : TimerItem => {
		const quicklyTime = toNumber(student.quicklyTime, 0)
		const pb = toNumber(overrides?.pb ?? student.pb, 5)
		const restTime = toNumber(overrides?.restTime ?? student.rest, 10)
		const totalLapCount = toNumber(overrides?.totalLapCount ?? student.circle, 4)
		return {
			id: createTimerId(groupId, student.studentId),
			studentId: student.studentId,
			currentTime: 0,
			countdownTime: 0,
			elapsedTime: 0,
			status: 'idle',
			studentName: student.name,
			quicklyTime,
			pb,
			records: [],
			lapCount: 0,
			targetTime: quicklyTime + pb,
			groupId,
			hasStarted: false,
			restTime,
			totalLapCount,
		restCountdown: 0,
		isResting: false,
		pausedRestCountdown: 0,
		startTimestamp: 0,
		lastRecordTimestamp: 0,
		currentLapTime: 0,
		hasRecordedThisLap: false
	}
}

	/**
	 * 根据接口原始分组构建页面内 Group 对象
	 * @param raw 接口分组数据
	 * @param index 分组索引，用于生成默认组名
	 */
	const buildGroup = (raw : PlanGroupRaw, index : number) : Group => {
		const id = raw.groupId || createGroupId()
		const timers = parsePlanList(raw.group).map(s => buildTimer(s, id))
		
		return {
			id,
			name: raw.groupName || raw.gruopName || `第${index + 1}组`,
			timers,
			hasStarted: false,
			targetTime: timers[0]?.pb || 5,
			restTime: timers[0]?.restTime || 10,
			lapCount: timers[0]?.totalLapCount || 4,
			allTime: raw.allTime,
			students: timers.map(t => t.studentId),
			departureTimerId: null,
			departureDueAt: 0
		}
	}

	// ===================== 页面状态 =====================

	const projects = ref<any[]>([]) // 项目列表（计划列表）
	const selectedProject = ref<any>(null) // 当前选中的项目
	const groups = ref<Group[]>([]) // 分组列表
	const ungroupedStudents = ref<StudentOption[]>([]) // 未分组学生（可用于添加）
	const studentNames = ref<StudentOption[]>([]) // 弹窗里展示的学生选项池
	const planSnapshot = ref<PlanRaw | null>(null) // 接口原始计划快照，用于保存时复用其他字段

	const showProjectSelect = ref(false) // 项目选择弹窗
	const showSetting = ref(false) // 全局出发设置弹窗
	const setting = ref({ mode: 'together', interval: '5' }) // together=一起出发, interval=间隔出发

	/**
	 * 将接口返回的 plan 数据应用到页面状态
	 * @param raw 接口原始 plan 数据
	 * 
	 * 处理逻辑：
	 * 1. 保存 plan 快照
	 * 2. 解析 users 为未分组学生
	 * 3. 解析 group 为页面分组和学生计时器
	 * 4. 设置出发模式和间隔时间
	 * 5. 重置全局计时器
	 */
	const applyPlan = (raw : PlanRaw) => {
		planSnapshot.value = { ...raw }
		groups.value = parsePlanList<PlanGroupRaw>(raw.group).map((g, i) => buildGroup(g, i))
		setting.value.mode = raw.departType === '间隔出发' ? 'interval' : 'together'
		setting.value.interval = String(toNumber(raw.interval, 5))
		globalTimerTime.value = 0
		stopGlobalTimer()
	}

	/** 计算属性：获取所有分组下的全部计时器 */
	const getAllTimers = computed(() : TimerItem[] => groups.value.flatMap(g => g.timers))

	/** 计算属性：是否存在正在运行或休息中的计时器 */
	const hasRunningTimers = computed(() => getAllTimers.value.some(t => t.status === 'running' || t.status === 'resting'))

	/** 计算属性：是否所有计时器都已完成 */
	const allTimersCompleted = computed(() => getAllTimers.value.length > 0 && getAllTimers.value.every(t => t.status === 'completed'))

	// ===================== 数据加载 =====================

	/**
	 * 获取项目（计划）列表
	 * 如果当前已选中项目，则匹配后自动拉取项目详情
	 */
	const getData = () => {
		PlanService.GetPlanList('计时项目', '1').then(res => {
			if (res.code === 0) {
				projects.value = res.data || []
				if (selectedProject.value?.planId) {
					const matched = projects.value.find((p : any) => p.planId === selectedProject.value.planId)
					if (matched) {
						selectedProject.value = matched
						getProjectData()
					}
				}
			} else {
				Service.Msg(res.msg)
			}
		})
	}


	/** 接口返回的未选择学生原始结构 */
	interface NoSelectStudentRaw {
		addTime : string
		address : string | null
		birthday : string
		name : string
		quicklyTime : number
		school : string | null
		sex : string
		studentId : string
		userId : string
	}

	/**
	 * 获取当前项目下尚未分组的学生列表
	 * 返回结构：{ studentList: NoSelectStudentRaw[] }
	 * 获取成功后同步更新 ungroupedStudents，用于"添加学生到本组"弹窗
	 */
	const GetNoSelectStudent = () => {
		if (!selectedProject.value?.planId) return
		PlanService.GetNoSelectStudent(selectedProject.value.planId).then(res => {
			if (res.code === 0) {
				const list : NoSelectStudentRaw[] = res.data?.studentList || []
				ungroupedStudents.value = list.map(s => ({
					studentId: s.studentId,
					name: s.name,
					quicklyTime: toNumber(s.quicklyTime, 0)
				}))
				return true
			} else {
				Service.Msg(res.msg || '获取未选择学生失败')
			}
		})
	}


	/**
	 * 获取当前选中项目的详情数据
	 * 入口：用户手动选择项目 或 页面加载后自动匹配
	 */
	const getProjectData = () => {
		if (!selectedProject.value?.planId) return

		PlanService.GetPlanInfo(selectedProject.value.planId).then(res => {
			if (res.code === 0 && res.data?.plan) {
				selectedProject.value = res.data?.plan
				applyPlan(res.data.plan)
			} else {
				Service.Msg(res.msg || '获取计划详情失败')
			}
		})
	}

	/**
	 * 用户点击选择项目
	 * 选择后关闭弹窗，提示用户，并拉取项目详情
	 */
	const selectProject = (project : any) => {
		selectedProject.value = project
		showProjectSelect.value = false
		getProjectData()
	}

	/**
	 * 页面生命周期：onLoad
	 * 如果路由带了 id，则预选中项目，然后拉取列表
	 */
	const isLandscape = ref(false)

	const updateOrientation = () => {
		const sys = uni.getSystemInfoSync()
		isLandscape.value = sys.windowWidth > sys.windowHeight
	}

	onLoad((options : any) => {
		updateOrientation()
		uni.onWindowResize(updateOrientation)
		if (options?.id) {
			selectedProject.value = { planId: options.id, name: options.name || '' }
		}
		getData()
	})

	// ===================== 学生计时器核心逻辑 =====================

	/**
	 * 存储每个学生的主计时器 setInterval ID
	 * Key = studentId，Value = intervalId
	 */
	const studentIntervals = new Map<string, number>()

	/**
	 * 存储每个学生的休息倒计时 setInterval ID
	 * Key = studentId，Value = intervalId
	 */
	const studentRestIntervals = new Map<string, number>()

	/** 清除指定学生的主计时器定时器 */
	const clearStudentInterval = (studentId : string) => {
		const id = studentIntervals.get(studentId)
		if (id) {
			clearInterval(id)
			studentIntervals.delete(studentId)
		}
	}

	/** 清除指定学生的休息倒计时定时器 */
	const clearStudentRestInterval = (studentId : string) => {
		const id = studentRestIntervals.get(studentId)
		if (id) {
			clearInterval(id)
			studentRestIntervals.delete(studentId)
		}
	}

	/**
	 * 存储每个学生的真实时间计时器 setInterval ID
	 * 用于 elapsedTime，不受休息影响，只在 pause/complete/reset 时停止
	 */
	const elapsedTimeIntervals = new Map<string, number>()

	/** 启动真实时间计时器（不受休息影响） */
	const startElapsedTimeTimer = (timer : TimerItem) => {
		if (elapsedTimeIntervals.has(timer.studentId)) return
		if (timer.startTimestamp === 0) {
			timer.startTimestamp = Date.now()
		}
		const id = setInterval(() => {
			timer.elapsedTime = (Date.now() - timer.startTimestamp) / 1000
		}, 50) as unknown as number
		elapsedTimeIntervals.set(timer.studentId, id)
	}

	/** 停止真实时间计时器 */
	const stopElapsedTimeTimer = (studentId : string) => {
		const id = elapsedTimeIntervals.get(studentId)
		if (id) {
			clearInterval(id)
			elapsedTimeIntervals.delete(studentId)
		}
	}

	/**
	 * 启动学生主计时器
	 * 逻辑：
	 * 1. 如果当前已经在运行中或已完成，则直接返回
	 * 2. 先清理旧的定时器（防止重复启动多个interval导致时间加速）
	 * 3. 设置状态为 running，记录 hasStarted = true
	 * 4. 通过 Date.now() 与 currentTime 反推出"开始时刻"，然后用 setInterval 每50ms更新 currentTime
	 * 
	 * 注意：允许从 resting 状态恢复计时，所以不拦截 resting
	 */
	const startStudentTimer = (timer : TimerItem) => {
		if (timer.status === 'running' || timer.status === 'completed') return
		// 如果有保存的暂停休息时间，优先恢复休息倒计时
		if (timer.pausedRestCountdown > 0) {
			startRestFromPause(timer)
			return
		}
		clearStudentInterval(timer.studentId)
		clearStudentRestInterval(timer.studentId)
		timer.status = 'running'
		timer.hasStarted = true
		// 如果倒计时已归零，重置为目标时间
		if (timer.countdownTime <= 0) {
			timer.countdownTime = timer.targetTime
		}
		// 启动真实时间计时器（不受休息影响）
		startElapsedTimeTimer(timer)
		// 通过当前累计时间反推开始时刻，保证暂停后继续计时的连续性
		const startAt = Date.now() - timer.currentTime * 1000
		// 当前圈开始时刻（用于计算 currentLapTime）
		let currentLapStartAt = Date.now() - timer.currentLapTime * 1000
		const id = setInterval(() => {
			// 更新累计游泳时间
			timer.currentTime = (Date.now() - startAt) / 1000
			// 更新当前圈已用时间
			timer.currentLapTime = (Date.now() - currentLapStartAt) / 1000
			
			// 计算周期和显示状态
			const cycleTime = timer.targetTime + timer.restTime
			if (timer.currentLapTime <= timer.targetTime) {
				// 游泳阶段：显示目标倒计时
				timer.countdownTime = Math.max(0, timer.targetTime - timer.currentLapTime)
				timer.isResting = false
				timer.restCountdown = 0
			} else if (timer.currentLapTime < cycleTime) {
				// 休息阶段：显示休息倒计时
				timer.isResting = true
				timer.restCountdown = Math.max(0, cycleTime - timer.currentLapTime)
				timer.countdownTime = 0
			}
			
			// 检查是否达到周期（目标时间 + 休息时间）
			if (timer.currentLapTime >= cycleTime && timer.status === 'running') {
				// 周期结束，自动记录0分（如果本圈还没被记录过）
				if (!timer.hasRecordedThisLap && timer.records.length < timer.totalLapCount) {
					timer.records.push({ time: 0 })
				}
				// 清零，准备下一轮
				timer.currentLapTime = 0
				timer.hasRecordedThisLap = false
				timer.countdownTime = timer.targetTime
				timer.isResting = false
				timer.restCountdown = 0
				currentLapStartAt = Date.now()
				// 检查是否完成所有圈数
				if (timer.records.length >= timer.totalLapCount) {
					completeTimer(timer)
				}
			}
		}, 50) as unknown as number
		studentIntervals.set(timer.studentId, id)
	}

	/**
	 * 自动完成一圈（倒计时结束时触发，不记录成绩）
	 * 注意：包括最后一圈在内，每圈完成后都进入休息
	 */
	const autoCompleteLap = (timer : TimerItem) => {
		timer.lapCount += 1
		// if (timer.lapCount >= timer.totalLapCount) {
		// 	// 最后一圈已完成，进入休息（休息结束后自动标记为完成）
		// 	Service.Msg(`${timer.studentName} 所有圈数已完成，进入休息`)
		// }
		startRest(timer)
	}

	/**
	 * 暂停学生计时器
	 * 逻辑：
	 * 1. 清除主计时器和休息倒计时
	 * 2. 如果当前在 running 或 resting，状态改为 paused
	 * 3. 重置 resting 相关标志
	 */
	const pauseStudentTimer = (timer : TimerItem) => {
		clearStudentInterval(timer.studentId)
		clearStudentRestInterval(timer.studentId)
		stopElapsedTimeTimer(timer.studentId)
		if (timer.status === 'running' || timer.status === 'resting') {
			// 如果正在休息，保存剩余休息时间
			if (timer.status === 'resting' && timer.restCountdown > 0) {
				timer.pausedRestCountdown = timer.restCountdown
			}
			timer.status = 'paused'
			timer.isResting = false
			timer.restCountdown = 0
		}
	}

	/**
	 * 启动休息倒计时
	 * 触发时机：学生完成一圈后（自动完成，不记录成绩）
	 * 
	 * 逻辑：
	 * 1. 先停止主计时器（休息时间不计入 currentTime）
	 * 2. 不停止 elapsedTime 计时器（休息期间继续计时）
	 * 3. 设置状态为 resting，开始倒计时
	 * 4. 每50ms更新 restCountdown
	 * 5. 倒计时结束后：如果是最后一圈则标记为完成，否则开始下一轮
	 */
	const startRest = (timer : TimerItem) => {
		const restTime = timer.restTime || 0
		clearStudentInterval(timer.studentId)
		clearStudentRestInterval(timer.studentId)
		timer.status = 'resting'
		timer.isResting = true
		timer.restCountdown = restTime
		// 如果没有休息时间，直接处理后续逻辑
		if (restTime <= 0) {
			if (timer.lapCount >= timer.totalLapCount) {
				// 最后一圈且没有休息时间，直接标记为完成
				completeTimer(timer)
				Service.Msg(`${timer.studentName} 已完成所有圈数`)
			} else {
				// 非最后一圈且没有休息时间，开始下一轮
				timer.countdownTime = timer.targetTime
				startStudentTimer(timer)
			}
			return
		}
		const restStart = Date.now()
		const id = setInterval(() => {
			const remaining = Math.max(0, restTime - (Date.now() - restStart) / 1000)
			timer.restCountdown = remaining
			if (remaining <= 0) {
				clearStudentRestInterval(timer.studentId)
				// 休息结束，判断是否为最后一圈
				if (timer.lapCount >= timer.totalLapCount) {
					// 最后一圈休息结束，标记为完成
					// completeTimer(timer)
					Service.Msg(`${timer.studentName} 休息结束，已完成所有圈数`)
				} else {
					// 非最后一圈，开始下一轮
					timer.countdownTime = timer.targetTime
					startStudentTimer(timer)
				}
			}
		}, 50) as unknown as number
		studentRestIntervals.set(timer.studentId, id)
		const isLastLap = timer.lapCount >= timer.totalLapCount
		// Service.Msg(isLastLap ? '最后一圈完成，进入休息' : `完成一圈，休息${restTime}秒`)
	}

	/**
	 * 从暂停状态恢复休息倒计时
	 * 触发时机：学生在休息中暂停后再次点击开始
	 */
	const startRestFromPause = (timer : TimerItem) => {
		const restTime = timer.pausedRestCountdown
		if (restTime <= 0) {
			// 没有剩余休息时间，判断是否为最后一圈
			timer.pausedRestCountdown = 0
			if (timer.lapCount >= timer.totalLapCount) {
				completeTimer(timer)
				Service.Msg(`${timer.studentName} 休息结束，已完成所有圈数`)
			} else {
				timer.countdownTime = timer.targetTime
				startStudentTimer(timer)
			}
			return
		}
		clearStudentInterval(timer.studentId)
		clearStudentRestInterval(timer.studentId)
		timer.status = 'resting'
		timer.isResting = true
		timer.restCountdown = restTime
		const restStart = Date.now()
		const id = setInterval(() => {
			const remaining = Math.max(0, restTime - (Date.now() - restStart) / 1000)
			timer.restCountdown = remaining
			if (remaining <= 0) {
				clearStudentRestInterval(timer.studentId)
				// 休息结束，判断是否为最后一圈
				timer.pausedRestCountdown = 0
				if (timer.lapCount >= timer.totalLapCount) {
					completeTimer(timer)
					Service.Msg(`${timer.studentName} 休息结束，已完成所有圈数`)
				} else {
					timer.countdownTime = timer.targetTime
					startStudentTimer(timer)
				}
			}
		}, 50) as unknown as number
		studentRestIntervals.set(timer.studentId, id)
		const isLastLap = timer.lapCount >= timer.totalLapCount
		Service.Msg(isLastLap ? '最后一圈休息中...' : `继续休息，剩余${restTime.toFixed(1)}秒`)
	}

	/**
	 * 将学生计时器标记为已完成
	 * 触发时机：lapCount 达到 totalLapCount
	 */
	const completeTimer = (timer : TimerItem) => {
		clearStudentInterval(timer.studentId)
		clearStudentRestInterval(timer.studentId)
		stopElapsedTimeTimer(timer.studentId)
		timer.status = 'completed'
		timer.isResting = false
		timer.restCountdown = 0
	}

	/**
	 * 记录学生成绩（手动点击，不增加圈数）
	 * 触发时机：点击学生圆形卡片、或详情弹窗点击"记录"
	 * 
	 * 逻辑：
	 * 1. 校验：未运行/未休息时不能记录
	 * 2. 如果记录数已达上限，不能记录
	 * 3. 计算净游泳时间 = elapsedTime - restTime * 已记录数 - sum(所有已记录时间)
	 *    记录1 = elapsedTime
	 *    记录2 = elapsedTime - restTime - 记录1
	 *    记录3 = elapsedTime - restTime*2 - 记录1 - 记录2
	 *    以此类推
	 * 4. 当前圈继续运行，不进入下一轮
	 */
	const recordLapForTimer = (timer : TimerItem) => {
		if (timer.status !== 'running' && timer.status !== 'resting') {
			Service.Msg('请在运行或休息中记录')
			return
		}
		if (timer.records.length >= timer.totalLapCount) {
			Service.Msg('已达到最大记录数')
			return
		}
		if (timer.hasRecordedThisLap) {
			Service.Msg('本圈已记录，请等待下一圈')
			return
		}
		// 记录当前圈时间
		timer.records.push({ time: Number(timer.currentLapTime.toFixed(3)) })
		timer.hasRecordedThisLap = true
		// 如果达到目标圈数，完成
		if (timer.records.length >= timer.totalLapCount) {
			completeTimer(timer)
			Service.Msg(`${timer.studentName} 已完成所有记录`)
			return
		}
		Service.Msg(`${timer.studentName} 已记录`)
	}

	/**
	 * 重置单个学生计时器
	 * 将所有时间和状态恢复为初始值
	 */
	const resetTimer = (timer : TimerItem) => {
		pauseStudentTimer(timer)
		timer.currentTime = 0
		timer.countdownTime = 0
		timer.elapsedTime = 0
		timer.status = 'idle'
		timer.records = []
		timer.lapCount = 0
		timer.hasStarted = false
		timer.isResting = false
		timer.restCountdown = 0
		timer.pausedRestCountdown = 0
		timer.startTimestamp = 0
		timer.lastRecordTimestamp = 0
		timer.currentLapTime = 0
		timer.hasRecordedThisLap = false
	}

	/**
	 * 切换单个学生计时器的运行/暂停状态
	 * 已完成时不可切换
	 */
	const toggleTimer = (timer : TimerItem) => {
		if (timer.status === 'completed') return
		if (timer.status === 'running' || timer.status === 'resting') {
			pauseStudentTimer(timer)
		} else {
			startStudentTimer(timer)
		}
	}

	/** 卡片点击记录圈数的代理函数 */
	const recordTimer = (timer : TimerItem) => recordLapForTimer(timer)

	// ===================== 全局计时器（间隔出发模式） =====================

	const globalTimerTime = ref(0) // 全局累计时间（秒）
	const globalTimerRunning = ref(false) // 全局计时器是否运行中
	let globalTimerInterval : number | null = null // 全局定时器ID
	let globalBaseTime = 0 // 暂停前已积累的时间
	let globalStartAt = 0 // 本次启动的时刻戳

	/** 停止全局计时器，并保存当前已计时的时间 */
	const stopGlobalTimer = () => {
		if (globalTimerRunning.value) {
			globalTimerTime.value = globalBaseTime + (Date.now() - globalStartAt) / 1000
		}
		globalTimerRunning.value = false
		if (globalTimerInterval) {
			clearInterval(globalTimerInterval)
			globalTimerInterval = null
		}
	}

	/**
	 * 启动全局计时器
	 * 
	 * 逻辑：
	 * 1. 先停止旧全局计时器
	 * 2. 恢复所有已暂停的学生计时器（间隔模式下）
	 * 3. 启动全局时间累计（每50ms更新 globalTimerTime）
	 * 4. "一起出发"模式下所有学生立即出发（startAt = 0）
	 * 5. "间隔出发"模式下每组内学生按索引 * 间隔秒数依次出发
	 * 6. 一旦 globalTimerTime >= 学生出发时间，且学生未出发过，则启动该学生计时器
	 */
	const startGlobalTimer = () => {
		stopGlobalTimer()
		globalTimerRunning.value = true
		globalStartAt = Date.now()
		globalBaseTime = globalTimerTime.value
		const intervalSec = toNumber(setting.value.interval, 5)
		
		// 间隔模式下：立即恢复所有已暂停的学生
		if (setting.value.mode === 'interval') {
			let resumedCount = 0
			groups.value.forEach((group) => {
				group.timers.forEach((t) => {
					if (t.status === 'paused') {
						startStudentTimer(t)
						resumedCount++
					}
				})
			})
			if (resumedCount > 0) {
				Service.Msg(`已恢复 ${resumedCount} 位学生`)
			}
		}
		
		globalTimerInterval = setInterval(() => {
			globalTimerTime.value = globalBaseTime + (Date.now() - globalStartAt) / 1000
			groups.value.forEach((group) => {
				group.timers.forEach((t, studentIndex) => {
					const startAt = setting.value.mode === 'together' ? 0 : studentIndex * intervalSec
					if (globalTimerTime.value >= startAt && !t.hasStarted && t.status !== 'completed' && t.status !== 'running' && t.status !== 'resting') {
						startStudentTimer(t)
						if (setting.value.mode !== 'together' && studentIndex > 0) {
							Service.Msg(`${t.studentName} 已出发`)
						}
					}
				})
			})
		}, 50) as unknown as number
	}

	// ===================== 分组级操作 =====================

	/** 判断分组内是否所有学生都在运行或休息中 */
	const isGroupAllRunning = (group : Group) => group.timers.length > 0 && group.timers.every(t => t.status === 'running' || t.status === 'resting')

	/** 判断分组内是否所有学生都已完成 */
	const isGroupAllCompleted = (group : Group) => group.timers.length > 0 && group.timers.every(t => t.status === 'completed')

	/** 判断分组内是否所有学生都已出发（hasStarted=true） */
	const isGroupAllDeparted = (group : Group) => group.timers.length > 0 && group.timers.every(t => t.hasStarted)

	/** 判断分组是否正在间隔出发中 */
	const isGroupDeparting = (group : Group) => !!group.departureTimerId

	/** 判断分组内是否有可启动的学生（未出发或已暂停） */
	const hasGroupStartable = (group : Group) =>
		group.timers.some(t => !t.hasStarted && t.status !== 'completed') ||
		group.timers.some(t => t.status === 'paused')

	/**
	 * 启动组内间隔出发
	 * 逻辑：
	 * 1. 如果有保存的 departureDueAt（暂停时保留），计算剩余时间并继续等待
	 * 2. 否则立即出发下一个未出发学生，并设置 interval 后的下一个出发
	 */
	const startGroupDeparture = (group : Group) => {
		if (group.departureTimerId) return

		const intervalMs = toNumber(setting.value.interval, 5) * 1000

		const departNext = () => {
			const nextTimer = group.timers.find(t => !t.hasStarted && t.status !== 'completed')
			if (!nextTimer) {
				group.departureDueAt = 0
				return
			}
			startStudentTimer(nextTimer)
			group.departureDueAt = Date.now() + intervalMs
			const nextId = setTimeout(() => {
				group.departureTimerId = null
				departNext()
			}, intervalMs) as unknown as number
			group.departureTimerId = nextId
		}

		if (group.departureDueAt > Date.now()) {
			const remainingMs = group.departureDueAt - Date.now()
			const waitId = setTimeout(() => {
				group.departureTimerId = null
				departNext()
			}, remainingMs) as unknown as number
			group.departureTimerId = waitId
		} else {
			departNext()
		}
	}

	/** 停止组内间隔出发 */
	const stopGroupDeparture = (group : Group) => {
		if (group.departureTimerId) {
			clearTimeout(group.departureTimerId)
			group.departureTimerId = null
		}
	}

	/**
	 * 启动指定分组
	 * 将分组内所有"未开始、未运行、未休息、未完成"的学生计时器启动
	 * 
	 * 间隔模式特殊处理：
	 * 1. 先恢复该组所有已暂停的学生
	 * 2. 如果还有未出发的学生，启动组内间隔出发
	 */
	const startGroup = (group : Group) => {
		if (setting.value.mode === 'interval') {
			// 步骤1：恢复当前组所有已暂停的学生
			let resumedCount = 0
			group.timers.forEach(t => {
				if (t.status === 'paused') {
					startStudentTimer(t)
					resumedCount++
				}
			})
			if (resumedCount > 0) {
				Service.Msg(`已恢复 ${resumedCount} 位学生`)
			}

			// 步骤2：如果还有未出发的学生，启动组内间隔出发
			const hasUnDeparted = group.timers.some(t => !t.hasStarted && t.status !== 'completed')
			if (hasUnDeparted) {
				startGroupDeparture(group)
			} else if (resumedCount === 0) {
				Service.Msg(`${group.name} 所有学生已出发`)
			}
		} else {
			// 一起出发模式：启动整组所有学生
			group.hasStarted = true
			group.timers.forEach(t => {
				if (t.status !== 'completed' && t.status !== 'running' && t.status !== 'resting') {
					startStudentTimer(t)
				}
			})
			Service.Msg(`${group.name} 已开始`)
		}
	}

	/**
	 * 暂停指定分组
	 * 将分组内所有正在运行或休息的学生计时器暂停
	 * 同时停止组内间隔出发
	 */
	const pauseGroup = (group : Group) => {
		stopGroupDeparture(group)
		group.timers.forEach(t => {
			if (t.status === 'running' || t.status === 'resting') {
				pauseStudentTimer(t)
			}
		})
	}

	/**
	 * 启动所有计时器
	 * 模式判断：
	 * - 一起出发：直接启动所有分组的全部学生计时器
	 * - 间隔出发：遍历所有组调用 startGroup，由各组独立控制间隔出发
	 */
	const startAllTimers = () => {
		if (setting.value.mode === 'together') {
			getAllTimers.value.forEach(t => {
				if (t.status !== 'completed' && t.status !== 'running' && t.status !== 'resting') {
					startStudentTimer(t)
				}
			})
			groups.value.forEach(g => g.hasStarted = true)
			Service.Msg('全部已开始')
		} else {
			groups.value.forEach(group => {
				startGroup(group)
			})
			Service.Msg('间隔出发已开始')
		}
	}

	/**
	 * 暂停所有计时器
	 * 停止全局计时器 + 停止所有组的间隔出发 + 暂停所有运行中/休息中的学生计时器
	 * 注意：不重置 hasStarted，保留出发记录
	 */
	const pauseAllTimers = () => {
		stopGlobalTimer()
		groups.value.forEach(group => {
			stopGroupDeparture(group)
		})
		getAllTimers.value.forEach(t => {
			if (t.status === 'running' || t.status === 'resting') {
				pauseStudentTimer(t)
			}
		})
		// Service.Msg('全部已暂停')
	}

	/**
	 * 重置所有计时器
	 * 停止全局计时器、清空全局时间、停止所有组间隔出发、重置所有分组和学生的状态
	 */
	const resetAllTimers = () => {
		stopGlobalTimer()
		globalTimerTime.value = 0
		groups.value.forEach(g => {
			stopGroupDeparture(g)
			g.departureDueAt = 0
			g.hasStarted = false
		})
		getAllTimers.value.forEach(t => resetTimer(t))
	}

	// ===================== 学生详情弹窗 =====================

	const showTimerDetail = ref(false) // 学生详情/编辑弹窗显示状态
	const selectedTimer = ref<TimerItem | null>(null) // 当前弹窗中选中的学生计时器
	const isEditMode = ref(false) // 当前弹窗是查看模式(false)还是编辑模式(true)
	const editForm = ref({ additionalTime: '', restTime: '', lapCount: '' }) // 编辑表单

	/**
	 * 打开学生详情弹窗
	 * 默认进入"计时详情"查看模式，并用当前计时器的值初始化编辑表单
	 */
	const openTimerDetail = (timer : TimerItem) => {
		selectedTimer.value = timer
		isEditMode.value = false
		editForm.value = {
			additionalTime: String(timer.pb || 0),
			restTime: String(timer.restTime || 0),
			lapCount: String(timer.totalLapCount || 4)
		}
		showTimerDetail.value = true
	}

	/** 取消编辑，切回查看模式 */
	const cancelEdit = () => { isEditMode.value = false }

	/**
	 * 保存学生计时器编辑
	 * 修改内容：pb（影响targetTime）、restTime、totalLapCount
	 * 同时同步更新该学生所属分组的默认配置（用于弹窗回显）
	 */
	const saveEdit = () => {
		if (!selectedTimer.value) return
		let data = {
			planId: selectedProject.value.planId,
			groupId: selectedTimer.value.groupId,
			studentId: selectedTimer.value.studentId,
			pb: editForm.value.additionalTime,
			rest: editForm.value.restTime,
			circle: editForm.value.lapCount
		}
		PlanService.UpdateGroupStudent(data).then(res => {
			if (res.code == 0) {
				Service.Msg('保存成功')
				getProjectData()
				isEditMode.value = false
			} else {
				Service.Msg(res.msg)
			}
		})


	}

	/** 详情弹窗中的开始/暂停切换 */
	const toggleSelectedTimer = () => { if (selectedTimer.value) toggleTimer(selectedTimer.value) }

	/** 详情弹窗中的重置 */
	const resetSelectedTimer = () => { if (selectedTimer.value) resetTimer(selectedTimer.value) }

	/** 详情弹窗中的记录圈数 */
	const recordLap = () => { if (selectedTimer.value) recordLapForTimer(selectedTimer.value) }

	// ===================== 添加学生弹窗 =====================

	const showAddTimerModal = ref(false)
	const currentGroup = ref<Group | null>(null) // 当前要添加学生的目标分组
	const selectedStudent = ref('') // 弹窗中选中的学生ID
	const targetTimeInput = ref('5') // pb输入默认值
	const restTimeInput = ref('10') // 休息输入默认值
	const lapCountInput = ref('4') // 圈数输入默认值

	/**
	 * 打开"添加学生到本组"弹窗
	 * 只允许从 ungroupedStudents（未分组学生池）中选择
	 */
	const addTimer = (group : Group) => {

		PlanService.GetNoSelectStudent(selectedProject.value.planId).then(res => {
			if (res.code === 0) {
				const list : NoSelectStudentRaw[] = res.data?.studentList || []
				ungroupedStudents.value = list.map(s => ({
					studentId: s.studentId,
					name: s.name,
					quicklyTime: toNumber(s.quicklyTime, 0)
				}))
				currentGroup.value = group
				selectedStudent.value = ''
				targetTimeInput.value = '0'
				restTimeInput.value = '0'
				lapCountInput.value = '0'
				studentNames.value = [...ungroupedStudents.value]
				showAddTimerModal.value = true
			} else {
				Service.Msg(res.msg || '获取未选择学生失败')
			}
		})

	}

	/** 单选学生 */
	const selectAddTimerStudent = (student : StudentOption) => {
		selectedStudent.value = student.studentId
	}

	/**
	 * 确认添加学生
	 * 从未分组学生池中找到选中学生，构建Timer并加入当前分组
	 * 然后从ungroupedStudents中移除该学生，避免重复添加
	 */
	const confirmAddTimer = () => {
		if (!currentGroup.value) return
		if (!selectedStudent.value) { Service.Msg('请选择学生'); return }
		let name = ''
		ungroupedStudents.value.map((item : any) => {
			if (item.studentId == selectedStudent.value) {
				name = item.name
			}
		})

		let data = {
			planId: selectedProject.value.planId,
			groupId: currentGroup.value.id,
			studentId: selectedStudent.value,
			name: name,
			pb: targetTimeInput.value,
			rest: restTimeInput.value,
			circle: lapCountInput.value
		}
		PlanService.AddStudentToGroup(data).then(res => {
			if (res.code == 0) {
				Service.Msg('添加成功')
				getProjectData()
				showAddTimerModal.value = false
			} else {
				Service.Msg(res.msg)
			}
		})
	}

	/**
	 * 删除分组内的某个学生计时器
	 * 删除后该学生回到未分组池（ungroupedStudents）
	 */
	const deleteTimer = (timer : TimerItem, group : Group, index : number) => {
		uni.showModal({
			title: '确认删除',
			content: `确定要删除 ${timer.studentName} 吗？`,
			success: (res) => {
				if (res.confirm) {
					let data = {
						planId: selectedProject.value.planId,
						groupId: timer.groupId,
						studentId: timer.studentId,
					}
					PlanService.RemoveStudentFromGroup(data).then(res => {
						if (res.code == 0) {
							Service.Msg('删除成功!')
							getProjectData()
						} else {
							Service.Msg(res.msg)
						}
					})
				}
			}
		})
	}

	// ===================== 分组设置弹窗（添加/编辑分组） =====================

	const showGroupSettingModal = ref(false)
	const groupSettingMode = ref<'add' | 'edit'>('add')
	const editingGroup = ref<Group | null>(null)
	const editingGroupName = ref('')
	const editingGroupStudents = ref<string[]>([])
	const editingTargetTime = ref('') // pb
	const editingRestTime = ref('')
	const editingLapCount = ref('')

	/**
	 * 获取当前页面中所有已知学生（用于弹窗选择）
	 * 来源：未分组学生 + 各分组内的学生
	 */
	const getAllKnownStudents = () : StudentOption[] => {
		const map = new Map<string, StudentOption>()
		ungroupedStudents.value.forEach(s => map.set(s.studentId, s))
		groups.value.forEach(g => g.timers.forEach(t => map.set(t.studentId, { studentId: t.studentId, name: t.studentName, quicklyTime: t.quicklyTime })))
		return Array.from(map.values())
	}

	/**
	 * 打开"添加分组"弹窗
	 * 只能从 ungroupedStudents 中选择学生
	 */
	const addGroup = () => {

		PlanService.GetNoSelectStudent(selectedProject.value.planId).then(res => {
			if (res.code === 0) {
				const list : NoSelectStudentRaw[] = res.data?.studentList || []
				ungroupedStudents.value = list.map(s => ({
					studentId: s.studentId,
					name: s.name,
					quicklyTime: toNumber(s.quicklyTime, 0)
				}))
				if (ungroupedStudents.value.length === 0) { Service.Msg('暂无可分组学生'); return }
				groupSettingMode.value = 'add'
				editingGroup.value = null
				editingGroupName.value = ''
				editingGroupStudents.value = []
				editingTargetTime.value = '5'
				editingRestTime.value = '10'
				editingLapCount.value = '4'
				studentNames.value = [...ungroupedStudents.value]
				showGroupSettingModal.value = true
			} else {
				Service.Msg(res.msg || '获取未选择学生失败')
			}
		})


	}

	/**
	 * 打开"编辑分组"弹窗
	 * 学生选项池 = 未分组学生 + 本分组已有学生
	 */
	const openGroupSetting = (group : Group) => {
		groupSettingMode.value = 'edit'
		editingGroup.value = group
		editingGroupName.value = group.name
		editingGroupStudents.value = group.timers.map(t => t.studentId)
		editingTargetTime.value = String(group.targetTime || 5)
		editingRestTime.value = String(group.restTime || 10)
		editingLapCount.value = String(group.lapCount || 4)
		const map = new Map<string, StudentOption>()
		ungroupedStudents.value.forEach(s => map.set(s.studentId, s))
		group.timers.forEach(t => map.set(t.studentId, { studentId: t.studentId, name: t.studentName, quicklyTime: t.quicklyTime }))
		studentNames.value = Array.from(map.values())
		showGroupSettingModal.value = true
	}

	/** 切换分组弹窗中某学生的选中/取消状态 */
	const toggleEditingGroupStudent = (student : StudentOption) => {
		const idx = editingGroupStudents.value.indexOf(student.studentId)
		if (idx > -1) editingGroupStudents.value.splice(idx, 1)
		else editingGroupStudents.value.push(student.studentId)
	}

	/**
	 * 删除整个分组
	 * 分组内所有学生恢复为未分组状态，并停止他们的计时器和间隔出发
	 */
	const deleteGroup = (group : Group) => {
		stopGroupDeparture(group)
		
		let index = selectedProject.value.group.findIndex((item : any) => {
			return item.groupId === group.id
		})
		uni.showModal({
			title: '确认删除分组',
			content: `确定要删除 ${group.name} 吗？`,
			success: (res) => {
				if (res.confirm) {
					selectedProject.value.group.splice(index, 1)
					let data = {
						planId: selectedProject.value.planId,
						name: selectedProject.value.name,
						planType: selectedProject.value.planType,
						departType: selectedProject.value.departType,
						interval: selectedProject.value.interval,
						groupInt: selectedProject.value.groupInt,
						subsectionDistance: '',
						subsectionInt: '',
						users: JSON.stringify(selectedProject.value.users),
						project: '',
						group: JSON.stringify(selectedProject.value.group),
					}

					PlanService.AddPlan(data).then(res => {
						if (res.code == 0) {
							Service.Msg('删除分组成功!')
							getProjectData()
						} else {
							Service.Msg(res.msg)
						}
					})
				}
			}
		})
	}

	/**
	 * 确认分组设置（添加或编辑）
	 * 
	 * 公共校验：
	 * - 组名非空
	 * - 至少选一个学生
	 * - pb、restTime、lapCount 数值合法
	 * 
	 * 添加模式逻辑：
	 * - 用 buildTimer 为每个选中学生新建计时器
	 * - 从 ungroupedStudents 中移除这些学生
	 * - 将新分组 push 到 groups
	 * 
	 * 编辑模式逻辑：
	 * - 找出被移除的学生：停止计时 -> 归还到 ungroupedStudents
	 * - 保留仍在组内的学生：更新 pb/rest/lapCount，保留原有计时状态（currentTime、records等）
	 * - 新加入的学生：buildTimer 新建
	 * - 从 ungroupedStudents 中移除新加入的学生
	 */
	const confirmGroupSetting = () => {
		if (!editingGroupName.value.trim()) { Service.Msg('请输入组名'); return }
		if (editingGroupStudents.value.length === 0) { Service.Msg('请至少选择一名学生'); return }
		const pb = toNumber(editingTargetTime.value, 5)
		const restTime = toNumber(editingRestTime.value, 10)
		const lapCount = toNumber(editingLapCount.value, 4)
		if (pb < 0 || restTime < 0 || lapCount <= 0) { Service.Msg('请输入有效的设置值'); return }

		const allStudents = getAllKnownStudents()
		const selectedStudents = editingGroupStudents.value
			.map(id => allStudents.find(s => s.studentId === id))
			.filter((s) : s is StudentOption => !!s)

		let groupItem = {
			groupName: editingGroupName.value,
			group: [{

			}]
		}
		groupItem.group = []

		selectedStudents.map((item : any) => {
			groupItem.group.push({
				circle: lapCount,
				name: item.name,
				pb: pb,
				quicklyTime: item.quicklyTime,
				rest: restTime,
				studentId: item.studentId
			})
		})
		console.log(selectedProject.value.group);
		let newGroup = [...selectedProject.value.group, groupItem]

		let users = JSON.stringify(selectedProject.value.users)
		let data = {
			planId: selectedProject.value.planId,
			name: selectedProject.value.name,
			planType: selectedProject.value.planType,
			departType: selectedProject.value.departType,
			interval: selectedProject.value.interval,
			groupInt: selectedProject.value.groupInt,
			subsectionDistance: '',
			subsectionInt: '',
			users: users,
			project: '',
			group: JSON.stringify(newGroup),
		}

		PlanService.AddPlan(data).then(res => {
			if (res.code == 0) {
				showGroupSettingModal.value = false
				Service.Msg('添加分组成功!')
				getProjectData()
			} else {
				Service.Msg(res.msg)
			}
		})
	}

	// ===================== 设置与保存 =====================

	/**
	 * 保存全局出发设置
	 * 校验间隔时间合法后，调用 AddPlan 提交整个计划数据
	 */
	const saveSetting = () => {
		if (setting.value.mode === 'interval') {
			const t = toNumber(setting.value.interval, 0)
			if (t <= 0) { Service.Msg('请输入有效的间隔时间'); return }
			setting.value.interval = String(t)
		}

		let data = {
			planId: selectedProject.value.planId,
			name: selectedProject.value.name,
			planType: selectedProject.value.planType,
			departType: setting.value.mode !== 'interval' ? '一起出发' : '间隔出发',
			interval: setting.value.interval,
			groupInt: selectedProject.value.groupInt,
			subsectionDistance: '',
			subsectionInt: '',
			users: JSON.stringify(selectedProject.value.users),
			project: '',
			group: JSON.stringify(selectedProject.value.group),
		}

		PlanService.AddPlan(data).then(res => {
			if (res.code == 0) {
				Service.Msg('修改成功!')
				getProjectData()
				showSetting.value = false
			} else {
				Service.Msg(res.msg)
			}
		})
	}



	/**
	 * 提交数据按钮
	 * 先全部暂停，校验有数据后提示成功并返回上一页
	 */
	const submitData = () => {
		pauseAllTimers()
		const hasData = getAllTimers.value.some(t => t.currentTime > 0)
		if (!hasData) { Service.Msg('暂无数据可提交'); return }

		let data = [
			{
				studentId: "",
				studentName: "",
				data: [{ circle: 0, time: "" }]
			}
		]
		data = []
		getAllTimers.value.map((item : any) => {

			let record = item.records.map((content : any, index : any) => {
				return {
					circle: index + 1,
					time: content.time
				}
			})

			data.push({
				studentId: item.studentId,
				studentName: item.studentName,
				data: record
			})
		})
		
		PlanService.AddPlanLog(selectedProject.value.planId,'包干项目','','',JSON.stringify(data)).then(res=>{
			if(res.code==0){
				Service.Msg('提交成功!')
				// resetAllTimers() 
			}else{
				Service.Msg(res.msg)
			}
		})
	}

	// ===================== 格式化函数 =====================

	/** 学生卡片主计时显示（目标时间倒计时）：分:秒:毫秒 */
	const formatTime = (timer : TimerItem) : string => {
		const time = Math.max(0, timer.countdownTime || 0)
		const mins = Math.floor(time / 60)
		const secs = Math.floor(time % 60)
		const millis = Math.floor((time % 1) * 100)
		return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}:${millis.toString().padStart(2, '0')}`
	}

	/** 计时器显示（真实经过时间）：分:秒:毫秒 */
	const formatElapsedTime = (seconds : number) : string => {
		const time = seconds || 0
		const mins = Math.floor(time / 60)
		const secs = Math.floor(time % 60)
		const millis = Math.floor((time % 1) * 100)
		return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}:${millis.toString().padStart(2, '0')}`
	}

	/** 目标时间显示：分:秒:毫秒 */
	const formatTargetTime = (seconds : number) : string => {
		const mins = Math.floor(seconds / 60)
		const secs = Math.floor(seconds % 60)
		const millis = Math.floor((seconds % 1) * 100)
		return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}:${millis.toString().padStart(2, '0')}`
	}

	/** 休息倒计时显示：秒.毫秒 */
	const formatRestCountdown = (seconds : number) : string => {
		const secs = Math.floor(seconds)
		const millis = Math.floor((seconds % 1) * 100)
		return `${secs.toString().padStart(2, '0')}.${millis.toString().padStart(2, '0')}`
	}

	/** 详情弹窗秒表大字体部分：分:秒 */
	const formatStopwatchTime = (seconds : number) : string => {
		const mins = Math.floor(seconds / 60)
		const secs = Math.floor(seconds % 60)
		return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`
	}

	/** 详情弹窗毫秒小字体部分 */
	const formatMillis = (seconds : number) : string => {
		const millis = Math.floor((seconds % 1) * 100)
		return `.${millis.toString().padStart(2, '0')}`
	}

	/** 完整时间：分:秒.毫秒 */
	const formatFullTime = (seconds : number) : string => {
		const mins = Math.floor(seconds / 60)
		const secs = Math.floor(seconds % 60)
		const millis = Math.floor((seconds % 1) * 100)
		return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}.${millis.toString().padStart(2, '0')}`
	}

	/** 全局计时器显示：分:秒.毫秒 */
	const formatGlobalTimer = (seconds : number) : string => {
		const mins = Math.floor(seconds / 60)
		const secs = Math.floor(seconds % 60)
		const millis = Math.floor((seconds % 1) * 100)
		return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}.${millis.toString().padStart(2, '0')}`
	}

	/**
	 * 详情弹窗中每条记录的单圈时间
	 * records 中存储的已经是净游泳时间（已扣除休息时间），直接显示即可
	 */
	const formatAdjustedRecordTime = (seconds : number, selectedTimer : any) : string => {
		if(seconds==0){
			return 0
		}
		return  Number(selectedTimer.targetTime-seconds).toFixed(3)
	}

	/**
	 * 页面卸载生命周期
	 * 必须清理所有 setInterval/setTimeout，防止页面离开后计时器仍在后台运行造成内存泄漏
	 */
	onUnmounted(() => {
		stopGlobalTimer()
		groups.value.forEach(g => stopGroupDeparture(g))
		studentIntervals.forEach(id => clearInterval(id))
		studentRestIntervals.forEach(id => clearInterval(id))
		elapsedTimeIntervals.forEach(id => clearInterval(id))
		studentIntervals.clear()
		studentRestIntervals.clear()
		elapsedTimeIntervals.clear()
		uni.offWindowResize(updateOrientation)
	})
</script>

<style lang="scss" scoped>
	.project-container {
		min-height: 100vh;
		background-color: #f6f6f6;
		padding: 20rpx 20rpx;
		padding-bottom: 200rpx;
	}

	.loading-section {
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
		padding: 100rpx 0;
	}

	.loading-text {
		font-size: 28rpx;
		color: #999;
		margin-top: 20rpx;
	}

	.empty-section {
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
		padding: 100rpx 0;
		text-align: center;
	}

	.empty-icon {
		margin-bottom: 30rpx;
	}

	.empty-text {
		font-size: 32rpx;
		color: #666;
		font-weight: 600;
		margin-bottom: 16rpx;
	}

	.empty-hint {
		font-size: 24rpx;
		color: #999;
	}

	.header-row {
		display: flex;
		gap: 16rpx;
		margin-bottom: 20rpx;
	}

	.header-item {
		flex: 1;
		display: flex;
		align-items: center;
		justify-content: space-between;
		background-color: #fff;
		border-radius: 12rpx;
		padding: 16rpx 20rpx;
		box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
		transition: all 0.2s ease;
		box-sizing: border-box;
		min-width: 0;

		&:active {
			transform: scale(0.98);
		}
	}

	.header-text {
		font-size: 28rpx;
		font-weight: 600;
		color: #333;
		overflow: hidden;
		text-overflow: ellipsis;
		white-space: nowrap;
		flex: 1;
		margin-right: 8rpx;
	}

	.header-setting-text {
		font-size: 26rpx;
		font-weight: 600;
		color: #333;
		flex: 1;
		overflow: hidden;
		text-overflow: ellipsis;
		white-space: nowrap;
		margin-right: 8rpx;
	}

	.header-icon-wrap {
		display: flex;
		align-items: center;
		justify-content: center;
		width: 28rpx;
		height: 28rpx;
		min-width: 28rpx;
		border-radius: 50%;
		transition: all 0.2s ease;
		flex-shrink: 0;

		&.gray {
			background-color: #f5f5f5;
		}

		&.blue {
			background-color: #f0f9ff;

			&:active {
				background-color: #e6f7ff;
				transform: scale(0.9);
			}
		}

		&.green {
			background-color: #f6ffed;
		}
	}

	.project-select-section {
		margin-bottom: 20rpx;
	}

	.project-select-wrapper {
		display: flex;
		align-items: center;
		justify-content: space-between;
		background-color: #fff;
		border-radius: 16rpx;
		padding: 24rpx 28rpx;
		box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
		transition: all 0.2s ease;

		&:active {
			transform: scale(0.98);
		}
	}

	.project-select-text {
		font-size: 30rpx;
		font-weight: 600;
		color: #333;
	}

	.project-select-popup {
		padding: 24px 0;
		height: 60vh;
		display: flex;
		flex-direction: column;
		box-sizing: border-box;

		&.landscape {
			height: 100vh;
		}
	}

	.popup-title {
		font-size: 20px;
		font-weight: 600;
		color: #333;
		text-align: center;
		margin-bottom: 20px;
		padding: 0 20px;
	}

	.project-list-scroll {
		flex: 1;
		padding: 0 20px;
		overflow: hidden;
	}

	.project-list {
		display: flex;
		flex-direction: column;
		gap: 10px;
	}

	.project-item {
		display: flex;
		align-items: center;
		justify-content: space-between;
		padding: 16px 14px;
		background-color: #f5f5f5;
		border-radius: 10px;
		transition: all 0.2s ease;
		border: 2px solid transparent;

		&.active {
			background-color: #e6f7ff;
			border-color: #1890ff;
		}

		&:active {
			transform: scale(0.98);
		}
	}

	.project-name {
		font-size: 16px;
		color: #333;
		font-weight: 500;
	}

	.card-section {
		background-color: #fff;
		border-radius: 16px;
		padding: 20px 14px;
		margin-bottom: 16px;
		box-shadow: 0 2px 10px rgba(0, 0, 0, 0.06);
	}

	.add-group-section {
		background-color: transparent;
		box-shadow: none;
		padding: 0;
	}

	.group-title-wrapper {
		display: flex;
		align-items: center;
		gap: 10px;
	}

	.delete-group-btn {
		width: 28px;
		height: 28px;
		background: linear-gradient(135deg, #ff4d4f 0%, #d9363e 100%);
		border-radius: 50%;
		display: flex;
		align-items: center;
		justify-content: center;
		box-shadow: 0 2px 8px rgba(255, 77, 79, 0.3);
		transition: all 0.2s ease;

		&:active {
			transform: scale(0.95);
		}
	}

	.add-group-btn {
		display: flex;
		align-items: center;
		justify-content: center;
		gap: 10px;
		background: linear-gradient(135deg, #52c41a 0%, #389e0d 100%);
		padding: 16px 24px;
		border-radius: 12px;
		box-shadow: 0 4px 12px rgba(82, 196, 26, 0.3);
		transition: all 0.3s ease;

		&:active {
			transform: scale(0.98);
			box-shadow: 0 2px 8px rgba(82, 196, 26, 0.2);
		}

		.add-group-text {
			font-size: 18px;
			color: #fff;
			font-weight: 600;
		}
	}

	.section-title {
		font-size: 20px;
		font-weight: 600;
		color: #262626;
		margin-bottom: 12px;
		position: relative;
		padding-left: 12px;

		&::before {
			content: '';
			position: absolute;
			left: 0;
			top: 50%;
			transform: translateY(-50%);
			width: 4px;
			height: 18px;
			background: linear-gradient(180deg, #1890ff 0%, #096dd9 100%);
			border-radius: 2px;
		}
	}

	.section-header {
		display: flex;
		justify-content: space-between;
		align-items: center;
		margin-bottom: 16px;

		.section-title {
			margin-bottom: 0;
			font-size: 15px;
			font-weight: 700;
			color: #262626;
		}

		.group-controls {
			display: flex;
			align-items: center;
			gap: 10px;
		}

		.group-control-btn {
			width: 30px;
			height: 30px;
			border-radius: 50%;
			display: flex;
			align-items: center;
			justify-content: center;
			transition: all 0.3s ease;
			box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);

			&:active {
				transform: scale(0.95);
			}
		}

		.group-control-btn.start-btn {
			background: linear-gradient(135deg, #52c41a 0%, #389e0d 100%);
			box-shadow: 0 2px 8px rgba(82, 196, 26, 0.3);
		}

		.group-control-btn.pause-btn {
			background: linear-gradient(135deg, #faad14 0%, #d48806 100%);
			box-shadow: 0 2px 8px rgba(250, 173, 20, 0.3);
		}

		.group-control-btn.setting-btn {
			background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%);
			box-shadow: 0 2px 8px rgba(24, 144, 255, 0.3);
		}
	}

	.global-timer-section {
		background: #fff;
		border: none;
		display: flex;
		flex-direction: column;
		align-items: center;
		padding: 40rpx 32rpx;
		position: relative;
	}

	.global-timer-header {
		width: 100%;
		display: flex;
		justify-content: center;
		align-items: center;
		position: relative;
		// margin-bottom: 20rpx;
	}

	.global-timer-label {
		font-size: 24rpx;
		color: #bfbfbf;
		font-weight: 400;
		letter-spacing: 4rpx;
		text-transform: uppercase;
	}

	.global-setting-btn {
		position: absolute;
		right: 0;
		top: 50%;
		transform: translateY(-50%);
		width: 48rpx;
		height: 48rpx;
		display: flex;
		align-items: center;
		justify-content: center;
		background: #f5f5f5;
		border-radius: 50%;
		transition: all 0.2s ease;

		&:active {
			transform: translateY(-50%) scale(0.95);
			background: #e8e8e8;
		}
	}

	.global-timer-display {
		display: flex;
		justify-content: center;
		align-items: center;
		padding: 0;
	}

	.global-timer-value {
		font-size: 80rpx;
		font-weight: 200;
		color: #262626;
		font-family: 'DIN Alternate', 'Helvetica Neue', 'SF Pro Display', -apple-system, monospace;
		letter-spacing: 10rpx;
		line-height: 1;
		font-variant-numeric: tabular-nums;
	}

	.timers-grid {
		display: grid;
		grid-template-columns: repeat(auto-fill, 162px);
		gap: 6px;
		justify-content: start;
	}

	.add-student-btn {
		display: flex;
		align-items: center;
		justify-content: center;
		gap: 12rpx;
		padding: 24rpx 32rpx;
		margin-top: 20rpx;
		background: linear-gradient(135deg, #f0f9ff 0%, #e6f7ff 100%);
		border-radius: 16rpx;
		border: 2rpx dashed #91d5ff;
		transition: all 0.3s ease;

		&:active {
			transform: scale(0.98);
			background: linear-gradient(135deg, #e6f7ff 0%, #d6f4ff 100%);
		}

		.add-student-text {
			font-size: 28rpx;
			color: #1890ff;
			font-weight: 500;
		}
	}

	.timer-circle {
		width: 100%;
		border-radius: 10px;
		background-color: #fff;
		display: flex;
		padding: 12px 10px;
		flex-direction: column;
		align-items: center;
		justify-content: center;
		position: relative;
		box-shadow: 0 2px 8px rgba(250, 140, 22, 0.2);
		transition: all 0.3s ease;
		gap: 6px;
		box-sizing: border-box;

		&.resting {
			box-shadow: 0 2px 12px rgba(255, 120, 117, 0.3);
			animation: cardPulse 1.5s ease-in-out infinite;
		}

		.timer-header {
			display: flex;
			justify-content: space-between;
			align-items: center;
			width: 100%;
			padding: 0 2px;
		}

		.timer-name-top-left {
			flex: 1;
			overflow: hidden;

			.name-text {
				font-size: 18px;
				font-weight: 600;
				color: #333;
			}
		}

		.delete-btn-wrapper {
			z-index: 10;
			margin-left: 8px;

			.delete-btn {
				width: 24px;
				height: 24px;
				background: linear-gradient(135deg, #ff4d4f 0%, #d9363e 100%);
				border-radius: 50%;
				display: flex;
				align-items: center;
				justify-content: center;
				box-shadow: 0 2px 6px rgba(255, 77, 79, 0.4);
				transition: all 0.2s ease;

				&:active {
					transform: scale(0.95);
				}
			}
		}

		.circle-content-wrapper {
			width: 100%;
			display: flex;
			justify-content: center;
		}

		.circle-content {
			width: 100%;
			padding: 6px 0;
			border-radius: 6px;
			border: 2px solid #faad14;
			background: linear-gradient(135deg, #fffbeb 0%, #ffffff 100%);
			position: relative;
			transition: all 0.3s ease;
			box-sizing: border-box;

			&.resting {
				border-color: #ff7875;
				background: linear-gradient(135deg, #fff1f0 0%, #ffffff 100%);
				animation: pulse 1.5s ease-in-out infinite;
			}

			.circle-inner {
				display: flex;
				flex-direction: column;
				align-items: center;
				justify-content: center;
				gap: 4px;
				padding: 0 8px;
				height: 100px;
			}
		}

		.timer-rest-countdown {
			display: flex;
			flex-direction: column;
			align-items: center;
			gap: 4px;

			.rest-label {
				font-size: 14px;
				color: #ff7875;
				font-weight: 600;
				padding: 2px 6px;
				border-radius: 4px;
				border: 1px solid #ffa39e;
				background: rgba(255, 255, 255, 0.8);
			}

			.rest-time {
				font-size: 24px;
				font-weight: bold;
				color: #ff7875;
				animation: countdownFlash 0.5s ease-in-out infinite;
			}
		}

		.timer-target {
			font-size: 12px;
			color: #666;
			font-weight: 500;
			background-color: #f0f5ff;
			padding: 2px 4px;
			border-radius: 4px;
			border: 1px solid #bae7ff;
			white-space: nowrap;
		}
		
		.timer-label {
			font-size: 12px;
			color: #333;
		}
		
		.timer-time {
			font-size: 24px;
			font-weight: bold;
			color: #333;
			line-height: 1.2;
		}

		.timer-duration {
			font-size: 12px;
			opacity: 0.9;
			background-color: #f6f6f6;
			padding: 2px 4px;
			border-radius: 4px;
			color: #666;
			white-space: nowrap;
		}

		.timer-info {
			display: flex;
			align-items: center;
			gap: 4px;
			flex-wrap: wrap;
		}

		.timer-rest {
			font-size: 10px;
			background-color: #fff7e6;
			padding: 2px 4px;
			border-radius: 4px;
			color: #fa8c16;
			border: 1px solid #ffe58f;
		}

		.timer-controls {
			display: flex;
			justify-content: space-between;
			align-items: center;
			width: 100%;
			margin-top: 8px;
			padding: 0 4px;

			u-icon {
				cursor: pointer;
				transition: all 0.2s ease;

				&:hover {
					transform: scale(1.1);
				}
			}
		}
	}

	.bottom-buttons-section {
		position: fixed;
		bottom: 0;
		left: 0;
		right: 0;
		background-color: #fff;
		padding: 20rpx 30rpx;
		border-top: 1rpx solid #f0f0f0;
		box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.08);
		z-index: 100;
	}

	.bottom-buttons {
		display: flex;
		gap: 16rpx;

		.bottom-btn {
			flex: 1;
			height: 88rpx;
			border-radius: 12rpx;
			border: none;
			display: flex;
			align-items: center;
			justify-content: center;
			gap: 12rpx;
			font-size: 28rpx;
			font-weight: 600;
			box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1);
			transition: all 0.2s ease;

			&:active {
				transform: scale(0.98);
			}

			.btn-text {
				font-size: 28rpx;
				color: #fff;
				font-weight: 600;
			}
		}

		.start-all-btn {
			background: linear-gradient(135deg, #52c41a 0%, #389e0d 100%);
		}

		.pause-all-btn {
			background: linear-gradient(135deg, #faad14 0%, #d48806 100%);
		}

		.submit-btn {
			background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%);
		}

		.reset-all-btn {
			background: linear-gradient(135deg, #722ed1 0%, #531dab 100%);
		}
	}

	@media (orientation: landscape) {
		.bottom-buttons-section {
			padding: 2.5vh 4vw;
		}

		.bottom-buttons {
			gap: 1.2vw;
		}

		.bottom-buttons .bottom-btn {
			height: 10vh;
			border-radius: 1.2vw;
			font-size: 2.2vw;
			gap: 1.2vw;
		}

		.bottom-buttons .bottom-btn .btn-text {
			font-size: 2.2vw;
		}
	}

	.timer-circle {
		cursor: pointer;
		transition: all 0.2s ease;

		&:active {
			transform: scale(0.98);
		}
	}

	.timer-detail-popup {
		padding: 0rpx 40rpx 50rpx;
		padding-bottom: calc(50rpx + env(safe-area-inset-bottom));
		// min-height: 450rpx;
		// max-height: 75vh;
		display: flex;
		flex-direction: column;
	}

	.detail-name {
		text-align: center;
		font-size: 32rpx;
		font-weight: 500;
		color: #8c8c8c;
		margin-bottom: 40rpx;
		letter-spacing: 2rpx;
	}

	.stopwatch-display {
		display: flex;
		align-items: baseline;
		justify-content: center;
		margin-bottom: 50rpx;
	}

	.stopwatch-time {
		font-size: 100rpx;
		font-weight: 300;
		color: #1a1a1a;
		font-family: 'DIN Alternate', 'Helvetica Neue', monospace;
		letter-spacing: 2rpx;
	}

	.stopwatch-millis {
		font-size: 48rpx;
		font-weight: 300;
		color: #bfbfbf;
		font-family: 'DIN Alternate', 'Helvetica Neue', monospace;
		margin-left: 4rpx;
	}

	.records-list {
		flex: 1;
		max-height: 280rpx;
		margin-bottom: 40rpx;
		background-color: #fafafa;
		border-radius: 16rpx;
		padding: 0 20rpx;
	}

	.record-item {
		padding: 20rpx 24rpx;
		margin-bottom: 12rpx;
		background-color: #fff;
		border-radius: 12rpx;
		box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
		transition: all 0.2s ease;

		&:active {
			transform: scale(0.98);
			box-shadow: 0 1rpx 4rpx rgba(0, 0, 0, 0.08);
		}
	}

	.record-info {
		display: flex;
		justify-content: space-between;
		align-items: center;
		margin-bottom: 8rpx;
	}

	.record-index {
		font-size: 24rpx;
		color: #8c8c8c;
		font-weight: 400;
		background: linear-gradient(135deg, #f0f0f0 0%, #fafafa 100%);
		padding: 4rpx 14rpx;
		border-radius: 8rpx;
	}

	.record-time {
		font-size: 32rpx;
		font-weight: 600;
		color: #262626;
		font-family: 'DIN Alternate', 'Helvetica Neue', monospace;
	}

	.detail-buttons {
		display: flex;
		justify-content: center;
		align-items: center;
		gap: 50rpx;
	}

	.detail-btn {
		width: 120rpx;
		height: 120rpx;
		border-radius: 60rpx;
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
		gap: 6rpx;
		transition: all 0.3s ease;
		cursor: pointer;
		position: relative;
		overflow: hidden;

		&::before {
			content: '';
			position: absolute;
			top: 0;
			left: 0;
			right: 0;
			bottom: 0;
			background: linear-gradient(135deg, rgba(255, 255, 255, 0.2) 0%, transparent 50%);
			pointer-events: none;
		}

		&:active {
			transform: scale(0.95);
		}

		.btn-label {
			font-size: 22rpx;
			font-weight: 500;
		}
	}

	.detail-btn-reset {
		background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%);
		box-shadow: 0 8rpxpx 24rpx rgba(24, 144, 255, 0.4);

		&:active {
			box-shadow: 0 4rpx 12rpx rgba(24, 144, 255, 0.3);
		}

		.btn-label {
			color: #fff;
		}
	}

	.detail-btn-main {
		width: 160rpx;
		height: 160rpx;
		border-radius: 80rpx;
		background: linear-gradient(135deg, #faad14 0%, #d48806 100%);
		box-shadow: 0 8rpx 24rpx rgba(250, 140, 22, 0.4);
		gap: 8rpx;

		&:active {
			box-shadow: 0 4rpx 12rpx rgba(250, 140, 22, 0.3);
		}

		.btn-label {
			color: #fff;
			font-size: 26rpx;
			font-weight: 600;
		}
	}

	.detail-btn-record {
		background: linear-gradient(135deg, #52c41a 0%, #389e0d 100%);
		box-shadow: 0 8rpx 24rpx rgba(82, 196, 26, 0.4);

		&:active {
			box-shadow: 0 4rpx 12rpx rgba(82, 196, 26, 0.3);
		}

		.btn-label {
			color: #fff;
		}
	}

	.detail-btn-record.disabled {
		background: #d9d9d9;
		box-shadow: none;
		pointer-events: none;

		.btn-label {
			color: #8c8c8c;
		}
	}

	.form-group {
		margin-bottom: 32rpx;

		&:last-child {
			margin-bottom: 0;
		}

		.form-label {
			display: block;
			font-size: 28rpx;
			font-weight: 600;
			color: #333;
			margin-bottom: 14rpx;
		}

		.form-input {
			width: 100%;
			height: 88rpx;
			background-color: #f5f5f5;
			border-radius: 16rpx;
			padding: 0 24rpx;
			font-size: 28rpx;
			color: #333;
			transition: all 0.2s ease;
		}
	}

	@keyframes fadeIn {
		from {
			opacity: 0;
		}

		to {
			opacity: 1;
		}
	}

	@keyframes slideUp {
		from {
			opacity: 0;
			transform: translate(-50%, -45%);
		}

		to {
			opacity: 1;
			transform: translate(-50%, -50%);
		}
	}

	@keyframes pulse {

		0%,
		100% {
			box-shadow: 0 0 0 0 rgba(255, 120, 117, 0.4);
		}

		50% {
			box-shadow: 0 0 20rpx 10rpx rgba(255, 120, 117, 0.2);
		}
	}

	@keyframes countdownFlash {

		0%,
		100% {
			opacity: 1;
		}

		50% {
			opacity: 0.6;
		}
	}

	@keyframes cardPulse {

		0%,
		100% {
			transform: scale(1);
		}

		50% {
			transform: scale(0.98);
		}
	}

	.add-group-modal {
		padding: 40rpx 32rpx;
		width: 600rpx;
	}

	.add-group-modal .modal-title {
		font-size: 36rpx;
		font-weight: 700;
		color: #333;
		text-align: center;
		margin-bottom: 40rpx;
		background: linear-gradient(135deg, #333 0%, #1890ff 100%);
		-webkit-background-clip: text;
		-webkit-text-fill-color: transparent;
		background-clip: text;
	}

	.add-group-modal .form-group {
		margin-bottom: 32rpx;
	}

	.add-group-modal .form-label {
		display: block;
		font-size: 30rpx;
		font-weight: 600;
		color: #333;
		margin-bottom: 16rpx;
	}

	.add-group-modal .form-input {
		width: 100%;
		height: 88rpx;
		background: linear-gradient(135deg, #fafbfc 0%, #f5f5f5 100%);
		border-radius: 16rpx;
		padding: 0 24rpx;
		font-size: 28rpx;
		color: #333;
		transition: all 0.3s ease;
		border: 2rpx solid transparent;
		box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04) inset;

		&:focus {
			background: #fff;
			border-color: #1890ff;
			box-shadow: 0 0 0 6rpx rgba(24, 144, 255, 0.1), 0 2rpx 8rpx rgba(0, 0, 0, 0.04) inset;
		}
	}

	.student-selector {
		display: flex;
		flex-wrap: wrap;
		gap: 16rpx;
	}

	.student-option {
		display: flex;
		align-items: center;
		gap: 12rpx;
		padding: 20rpx 24rpx;
		background: #f5f5f5;
		border-radius: 16rpx;
		border: 2rpx solid transparent;
		transition: all 0.3s ease;

		&.selected {
			background: linear-gradient(135deg, #e6f7ff 0%, #bae7ff 100%);
			border-color: #1890ff;
		}

		&:active {
			transform: scale(0.96);
		}
	}

	.student-checkbox {
		width: 36rpx;
		height: 36rpx;
		border-radius: 8rpx;
		border: 3rpx solid #d9d9d9;
		display: flex;
		align-items: center;
		justify-content: center;
		transition: all 0.3s ease;

		.student-option.selected & {
			background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%);
			border-color: #1890ff;
		}
	}

	.student-name {
		font-size: 28rpx;
		font-weight: 500;
		color: #333;
	}

	.add-group-modal .modal-buttons {
		display: flex;
		gap: 16rpx;
		margin-top: 20rpx;
	}

	.add-group-modal .modal-btn {
		flex: 1;
		height: 88rpx;
		border-radius: 16rpx;
		display: flex;
		align-items: center;
		justify-content: center;
		font-size: 30rpx;
		font-weight: 600;
		transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);

		&:active {
			transform: scale(0.96);
		}
	}

	.add-group-modal .cancel-btn {
		background: linear-gradient(135deg, #f5f5f5 0%, #e8e8e8 100%);
		color: #666;
		box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
	}

	.add-group-modal .confirm-btn {
		background: linear-gradient(135deg, #1890ff 0%, #40a9ff 50%, #096dd9 100%);
		color: #fff;
		box-shadow: 0 8rpx 24rpx rgba(24, 144, 255, 0.35);
	}

	.add-timer-modal {
		padding: 20rpx 32rpx;
		width: 600rpx;
		max-height: 80vh;
		display: flex;
		flex-direction: column;
		box-sizing: border-box;

		&.landscape {
			width: 55vw;
			max-width: 520px;
			
		}
	}

	.add-timer-scroll {
		flex: 1;
		max-height: 50vh;
		overflow-y: auto;
	}

	.add-timer-modal.landscape .add-timer-scroll {
		max-height: 55vh;
	}

	.add-timer-modal .form-row {
		display: flex;
		flex-direction: column;
		gap: 0;
	}

	.add-timer-modal.landscape .form-row {
		flex-direction: row;
		gap: 12px;
	}

	.add-timer-modal.landscape .form-row .form-group {
		flex: 1;
		margin-bottom: 0;
	}

	.add-timer-modal.landscape .form-label {
		font-size: 16px;
		margin-bottom: 8px;
	}

	.add-timer-modal.landscape .form-input {
		height: 44px;
		font-size: 15px;
		padding: 0 12px;
	}

	.add-timer-modal.landscape .modal-buttons {
		margin-top: 16px;
	}

	.add-timer-modal.landscape .modal-btn {
		height: 44px;
		font-size: 16px;
	}

	.add-timer-modal.landscape .modal-title {
		font-size: 22px;
		margin-bottom: 20px;
	}

	.add-timer-modal.landscape .form-group {
		margin-bottom: 18px;
	}

	.add-timer-modal.landscape .student-selector {
		gap: 10px;
	}

	.add-timer-modal.landscape .student-option {
		gap: 8px;
		padding: 12px 14px;
		border-radius: 10px;
		border-width: 2px;
	}

	.add-timer-modal.landscape .student-checkbox {
		width: 20px;
		height: 20px;
		border-radius: 6px;
		border-width: 2px;
	}

	.add-timer-modal.landscape .student-name {
		font-size: 16px;
	}

	.add-timer-modal .modal-title {
		font-size: 36rpx;
		font-weight: 700;
		color: #333;
		text-align: center;
		margin-bottom: 40rpx;
		background: linear-gradient(135deg, #333 0%, #1890ff 100%);
		-webkit-background-clip: text;
		-webkit-text-fill-color: transparent;
		background-clip: text;
	}

	.add-timer-modal .form-group {
		margin-bottom: 32rpx;
	}

	.add-timer-modal .form-label {
		display: block;
		font-size: 30rpx;
		font-weight: 600;
		color: #333;
		margin-bottom: 16rpx;
	}

	.picker-wrapper {
		width: 100%;
		height: 88rpx;
		background: linear-gradient(135deg, #fafbfc 0%, #f5f5f5 100%);
		border-radius: 16rpx;
		padding: 0 24rpx;
		display: flex;
		align-items: center;
		justify-content: space-between;
		border: 2rpx solid transparent;
		box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04) inset;
		transition: all 0.3s ease;

		&:active {
			background: #fff;
			border-color: #1890ff;
			box-shadow: 0 0 0 6rpx rgba(24, 144, 255, 0.1), 0 2rpx 8rpx rgba(0, 0, 0, 0.04) inset;
		}

		.picker-text {
			font-size: 28rpx;
			color: #333;
		}
	}

	.add-timer-modal .modal-buttons {
		display: flex;
		gap: 16rpx;
		margin-top: 40rpx;
	}

	.add-timer-modal .modal-btn {
		flex: 1;
		height: 88rpx;
		border-radius: 16rpx;
		display: flex;
		align-items: center;
		justify-content: center;
		font-size: 30rpx;
		font-weight: 600;
		transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);

		&:active {
			transform: scale(0.96);
		}
	}

	.add-timer-modal .cancel-btn {
		background: linear-gradient(135deg, #f5f5f5 0%, #e8e8e8 100%);
		color: #666;
		box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
	}

	.add-timer-modal .confirm-btn {
		background: linear-gradient(135deg, #1890ff 0%, #40a9ff 50%, #096dd9 100%);
		color: #fff;
		box-shadow: 0 8rpx 24rpx rgba(24, 144, 255, 0.35);
	}

	.add-timer-modal .form-input {
		width: 100%;
		height: 88rpx;
		background: linear-gradient(135deg, #fafbfc 0%, #f5f5f5 100%);
		border-radius: 16rpx;
		padding: 0 24rpx;
		font-size: 28rpx;
		color: #333;
		transition: all 0.3s ease;
		border: 2rpx solid transparent;
		box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04) inset;

		&:focus {
			background: #fff;
			border-color: #1890ff;
			box-shadow: 0 0 0 6rpx rgba(24, 144, 255, 0.1), 0 2rpx 8rpx rgba(0, 0, 0, 0.04) inset;
		}
	}

	.group-setting-modal {
		padding: 24px 20px;
		width: 90vw;
		max-width: 340px;
		max-height: 80vh;
		display: flex;
		flex-direction: column;
		box-sizing: border-box;

		&.landscape {
			width: 55vw;
			max-width: 520px;
		}
	}

	.group-setting-modal .modal-title {
		font-size: 22px;
		font-weight: 700;
		color: #333;
		text-align: center;
		margin-bottom: 20px;
		background: linear-gradient(135deg, #333 0%, #1890ff 100%);
		-webkit-background-clip: text;
		-webkit-text-fill-color: transparent;
		background-clip: text;
	}

	.group-setting-modal .setting-scroll {
		flex: 1;
		max-height: 50vh;
		overflow-y: auto;
	}

	.group-setting-modal .form-group {
		margin-bottom: 18px;
	}

	.group-setting-modal .form-row {
		display: flex;
		flex-direction: column;
		gap: 0;
	}

	.group-setting-modal .form-row .form-group {
		margin-bottom: 18px;
	}

	.group-setting-modal .form-label {
		display: block;
		font-size: 18px;
		font-weight: 600;
		color: #333;
		margin-bottom: 10px;
	}

	.group-setting-modal .form-input {
		width: 100%;
		height: 48px;
		background: linear-gradient(135deg, #fafbfc 0%, #f5f5f5 100%);
		border-radius: 10px;
		padding: 0 16px;
		font-size: 16px;
		color: #333;
		transition: all 0.3s ease;
		border: 2px solid transparent;
		box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04) inset;
		box-sizing: border-box;

		&:focus {
			background: #fff;
			border-color: #1890ff;
			box-shadow: 0 0 0 4px rgba(24, 144, 255, 0.1), 0 2px 8px rgba(0, 0, 0, 0.04) inset;
		}
	}

	.group-setting-modal.landscape .form-row {
		flex-direction: row;
		gap: 12px;
	}

	.group-setting-modal.landscape .form-row .form-group {
		flex: 1;
		margin-bottom: 0;
	}

	.group-setting-modal.landscape .form-label {
		font-size: 16px;
		margin-bottom: 8px;
	}

	.group-setting-modal.landscape .form-input {
		height: 44px;
		font-size: 15px;
		padding: 0 12px;
	}

	.group-setting-modal.landscape .modal-buttons {
		margin-top: 16px;
	}

	.group-setting-modal.landscape .modal-btn {
		height: 44px;
		font-size: 16px;
	}

	.group-setting-modal .student-selector {
		display: flex;
		flex-wrap: wrap;
		gap: 10px;
	}

	.group-setting-modal .student-option {
		display: flex;
		align-items: center;
		gap: 8px;
		padding: 12px 14px;
		background: #f5f5f5;
		border-radius: 10px;
		border: 2px solid transparent;
		transition: all 0.3s ease;

		&.selected {
			background: linear-gradient(135deg, #e6f7ff 0%, #bae7ff 100%);
			border-color: #1890ff;
		}

		&:active {
			transform: scale(0.96);
		}
	}

	.group-setting-modal .student-checkbox {
		width: 20px;
		height: 20px;
		border-radius: 6px;
		border: 2px solid #d9d9d9;
		display: flex;
		align-items: center;
		justify-content: center;
		transition: all 0.3s ease;
		flex-shrink: 0;

		.group-setting-modal .student-option.selected & {
			background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%);
			border-color: #1890ff;
		}
	}

	.group-setting-modal .student-name {
		font-size: 16px;
		font-weight: 500;
		color: #333;
	}

	.group-setting-modal .modal-buttons {
		display: flex;
		gap: 12px;
		margin-top: 20px;
	}

	.group-setting-modal .modal-btn {
		flex: 1;
		height: 48px;
		border-radius: 10px;
		display: flex;
		align-items: center;
		justify-content: center;
		font-size: 18px;
		font-weight: 600;
		transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);

		&:active {
			transform: scale(0.96);
		}
	}

	.group-setting-modal .cancel-btn {
		background: linear-gradient(135deg, #f5f5f5 0%, #e8e8e8 100%);
		color: #666;
		box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
	}

	.group-setting-modal .confirm-btn {
		background: linear-gradient(135deg, #1890ff 0%, #40a9ff 50%, #096dd9 100%);
		color: #fff;
		box-shadow: 0 8px 24px rgba(24, 144, 255, 0.35);
	}

	.add-timer-modal .student-selector {
		display: flex;
		flex-wrap: wrap;
		gap: 12rpx;
	}

	.add-timer-modal .student-option {
		display: flex;
		align-items: center;
		gap: 10rpx;
		padding: 16rpx 20rpx;
		background: #f5f5f5;
		border-radius: 12rpx;
		border: 2rpx solid transparent;
		transition: all 0.3s ease;

		&.selected {
			background: linear-gradient(135deg, #e6f7ff 0%, #bae7ff 100%);
			border-color: #1890ff;
		}

		&:active {
			transform: scale(0.96);
		}
	}

	.add-timer-modal .student-checkbox {
		width: 32rpx;
		height: 32rpx;
		border-radius: 6rpx;
		border: 2rpx solid #d9d9d9;
		display: flex;
		align-items: center;
		justify-content: center;
		transition: all 0.3s ease;

		.add-timer-modal .student-option.selected & {
			background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%);
			border-color: #1890ff;
		}
	}

	.add-timer-modal .student-name {
		font-size: 26rpx;
		font-weight: 500;
		color: #333;
	}

	.group-setting-modal .modal-buttons {
		display: flex;
		gap: 16rpx;
		margin-top: 30rpx;
	}

	.group-setting-modal .modal-btn {
		flex: 1;
		height: 88rpx;
		border-radius: 16rpx;
		display: flex;
		align-items: center;
		justify-content: center;
		font-size: 30rpx;
		font-weight: 600;
		transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);

		&:active {
			transform: scale(0.96);
		}
	}

	.group-setting-modal .cancel-btn {
		background: linear-gradient(135deg, #f5f5f5 0%, #e8e8e8 100%);
		color: #666;
		box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
	}

	.group-setting-modal .confirm-btn {
		background: linear-gradient(135deg, #1890ff 0%, #40a9ff 50%, #096dd9 100%);
		color: #fff;
		box-shadow: 0 8rpx 24rpx rgba(24, 144, 255, 0.35);
	}

	.mode-tabs {
		display: flex;
		background-color: #f5f5f5;
		border-radius: 16rpx;
		padding: 6rpx;
		margin-bottom: 32rpx;
	}

	.mode-tab {
		flex: 1;
		height: 72rpx;
		display: flex;
		align-items: center;
		justify-content: center;
		border-radius: 12rpx;
		transition: all 0.3s ease;

		&.active {
			background-color: #fff;
			box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.08);
		}

		&:active {
			transform: scale(0.98);
		}
	}

	.mode-tab-text {
		font-size: 28rpx;
		font-weight: 500;
		color: #666;

		.mode-tab.active & {
			color: #1890ff;
			font-weight: 600;
		}
	}

	.current-settings-info {
		display: flex;
		flex-direction: column;
		gap: 12rpx;
		margin-bottom: 24rpx;
		padding: 20rpx;
		background: linear-gradient(135deg, #f6ffed 0%, #f0f9ff 100%);
		border-radius: 12rpx;
		border: 2rpx solid #b7eb8f;
	}

	.setting-info-item {
		display: flex;
		align-items: center;
		gap: 12rpx;
	}

	.setting-info-label {
		font-size: 24rpx;
		color: #666;
		min-width: 140rpx;
	}

	.setting-info-value {
		font-size: 26rpx;
		color: #333;
		font-weight: 600;
		font-family: 'DIN Alternate', 'Helvetica Neue', monospace;
	}

	.edit-form {
		margin-bottom: 32rpx;
	}

	.form-input-readonly {
		width: 100%;
		height: 88rpx;
		background-color: #fafafa;
		border-radius: 16rpx;
		padding: 0 24rpx;
		font-size: 28rpx;
		color: #999;
		display: flex;
		align-items: center;
		border: 2rpx solid #e8e8e8;
	}

	.form-hint {
		margin-top: 16rpx;
		padding: 16rpx 20rpx;
		background: linear-gradient(135deg, #fff7e6 0%, #fffbe6 100%);
		border-radius: 12rpx;
		border-left: 6rpx solid #faad14;
	}

	.hint-text {
		font-size: 24rpx;
		color: #8c8c8c;
		line-height: 1.6;
	}

	.edit-buttons {
		display: flex;
		gap: 16rpx;
	}

	.edit-btn {
		flex: 1;
		height: 88rpx;
		border-radius: 16rpx;
		display: flex;
		align-items: center;
		justify-content: center;
		font-size: 30rpx;
		font-weight: 600;
		transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);

		&:active {
			transform: scale(0.96);
		}
	}

	.edit-btn-cancel {
		background: linear-gradient(135deg, #f5f5f5 0%, #e8e8e8 100%);
		color: #666;
		box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
	}

	.edit-btn-save {
		background: linear-gradient(135deg, #52c41a 0%, #73d13d 50%, #389e0d 100%);
		color: #fff;
		box-shadow: 0 8rpx 24rpx rgba(82, 196, 26, 0.35);
	}

	.edit-btn-text {
		font-size: 30rpx;
		font-weight: 600;
	}

	/* ==================== 秒表详情弹窗横屏适配 ==================== */
	.timer-detail-popup.landscape {
		padding: 20px 16px 0;
		padding-bottom: calc(14px + env(safe-area-inset-bottom));
		width: 55vw;
		margin: 0 auto;
		box-sizing: border-box;
	}

	.timer-detail-popup .form-row {
		display: flex;
		flex-direction: column;
		gap: 0;
	}

	.timer-detail-popup.landscape .form-row {
		flex-direction: row;
		gap: 10px;
	}

	.timer-detail-popup.landscape .form-row .form-group {
		flex: 1;
		margin-bottom: 0;
	}

	.timer-detail-popup.landscape .mode-tabs {
		margin-bottom: 12px;
		border-radius: 10px;
		padding: 4px;
	}

	.timer-detail-popup.landscape .mode-tab {
		height: 32px;
		border-radius: 8px;
	}

	.timer-detail-popup.landscape .mode-tab-text {
		font-size: 13px;
	}

	.timer-detail-popup.landscape .detail-name {
		font-size: 14px;
		margin-bottom: 8px;
	}

	.timer-detail-popup.landscape .stopwatch-time {
		font-size: 36px;
		letter-spacing: 1px;
	}

	.timer-detail-popup.landscape .stopwatch-millis {
		font-size: 18px;
		margin-left: 2px;
	}

	.timer-detail-popup.landscape .stopwatch-display {
		margin-bottom: 10px;
	}

	.timer-detail-popup.landscape .current-settings-info {
		padding: 8px 10px;
		margin-bottom: 8px;
		gap: 6px;
		border-radius: 8px;
	}

	.timer-detail-popup.landscape .setting-info-item {
		gap: 6px;
	}

	.timer-detail-popup.landscape .setting-info-label {
		font-size: 12px;
		min-width: 60px;
	}

	.timer-detail-popup.landscape .setting-info-value {
		font-size: 13px;
	}

	.timer-detail-popup.landscape .records-list {
		max-height: 100px;
		margin-bottom: 10px;
		border-radius: 8px;
		padding: 0 10px;
	}

	.timer-detail-popup.landscape .record-item {
		padding: 8px 10px;
		margin-bottom: 6px;
		border-radius: 6px;
	}

	.timer-detail-popup.landscape .record-index {
		font-size: 11px;
		padding: 2px 8px;
		border-radius: 4px;
	}

	.timer-detail-popup.landscape .record-time {
		font-size: 14px;
	}

	.timer-detail-popup.landscape .detail-buttons {
		gap: 16px;
	}

	.timer-detail-popup.landscape .detail-btn {
		width: 56px;
		height: 56px;
		border-radius: 28px;
		gap: 2px;
	}

	.timer-detail-popup.landscape .detail-btn-main {
		width: 72px;
		height: 72px;
		border-radius: 36px;
		gap: 4px;
	}

	.timer-detail-popup.landscape .detail-btn .btn-label {
		font-size: 11px;
	}

	.timer-detail-popup.landscape .detail-btn-main .btn-label {
		font-size: 13px;
	}

	.timer-detail-popup.landscape .edit-form {
		margin-bottom: 10px;
	}

	.timer-detail-popup.landscape .form-group {
		margin-bottom: 10px;
	}

	.timer-detail-popup.landscape .form-group .form-label {
		font-size: 13px;
		margin-bottom: 4px;
	}

	.timer-detail-popup.landscape .form-group .form-input {
		height: 32px;
		font-size: 13px;
		padding: 0 10px;
		border-radius: 6px;
	}

	.timer-detail-popup.landscape .form-input-readonly {
		height: 32px;
		font-size: 13px;
		padding: 0 10px;
		border-radius: 6px;
	}

	.timer-detail-popup.landscape .form-hint {
		margin-top: 6px;
		padding: 6px 8px;
		border-left-width: 3px;
		border-radius: 6px;
	}

	.timer-detail-popup.landscape .hint-text {
		font-size: 11px;
	}

	.timer-detail-popup.landscape .edit-buttons {
		gap: 8px;
	}

	.timer-detail-popup.landscape .edit-btn {
		height: 32px;
		border-radius: 6px;
	}

	.timer-detail-popup.landscape .edit-btn-text {
		font-size: 13px;
	}

	.setting-modal {
		width: 80vw;
		max-width: 320px;
		padding: 24px 20px 20px;
		box-sizing: border-box;

		&.landscape {
			width: 40vw;
			max-width: 360px;
		}
	}

	.setting-title {
		font-size: 20px;
		font-weight: 600;
		color: #333;
		text-align: center;
		margin-bottom: 20px;
	}

	.setting-item {
		display: flex;
		align-items: center;
		padding: 16px 14px;
		background-color: #f5f5f5;
		border-radius: 10px;
		margin-bottom: 12px;
		transition: all 0.2s ease;
		border: 2px solid transparent;

		&.active {
			background-color: #e6f7ff;
			border-color: #1890ff;
		}

		&:active {
			transform: scale(0.98);
		}
	}

	.setting-radio {
		width: 22px;
		height: 22px;
		border-radius: 50%;
		border: 2px solid #d9d9d9;
		display: flex;
		align-items: center;
		justify-content: center;
		margin-right: 12px;
		transition: all 0.2s ease;
		flex-shrink: 0;

		.setting-item.active & {
			border-color: #1890ff;
		}
	}

	.radio-dot {
		width: 12px;
		height: 12px;
		border-radius: 50%;
		background-color: #1890ff;
	}

	.setting-text {
		font-size: 16px;
		color: #333;
		font-weight: 500;
		flex: 1;
	}

	.interval-input-box {
		display: flex;
		align-items: center;
		background-color: #fff;
		border-radius: 6px;
		padding: 6px 12px;
		margin-left: 12px;
		border: 2px solid #e8e8e8;
		flex-shrink: 0;
	}

	.interval-input {
		width: 60px;
		font-size: 16px;
		color: #333;
		text-align: center;
	}

	.interval-unit {
		font-size: 14px;
		color: #999;
		margin-left: 6px;
	}

	.setting-confirm {
		margin-top: 16px;
		height: 48px;
		background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%);
		border-radius: 10px;
		display: flex;
		align-items: center;
		justify-content: center;
		font-size: 18px;
		font-weight: 600;
		color: #fff;
		transition: all 0.2s ease;

		&:active {
			transform: scale(0.98);
		}
	}
</style>