<template>
	<view class="bill-page page-enter theme-transition" :style="{ background: themeConfig.bgColor }">
		<PageHeader
			title="账单管理"
			subtitle="理性消费，合理规划"
			:showRight="true"
		>
			<template #right>
				<view class="header-actions">
					<view
						class="header-btn"
						:style="{ backgroundColor: themeConfig.cardBgColor }"
						@click="toggleBatchMode"
					>
						<text
							class="batch-icon"
							:style="{ color: isBatchMode ? themeConfig.primaryColor : themeConfig.textSecondary }"
						>{{ isBatchMode ? '✓' : '☰' }}</text>
					</view>
					<view
						class="header-btn"
						:style="{ backgroundColor: themeConfig.cardBgColor }"
						@click="handleBudgetSetting"
					>
						<FaIcon icon="gear" :size="22" :color="themeConfig.textSecondary" />
					</view>
				</view>
			</template>
		</PageHeader>

		<view class="sticky-header card-enter" :style="{ background: themeConfig.bgColor }">
			<view class="search-bar">
				<view
					class="search-input"
					:style="{ backgroundColor: themeConfig.cardBgColor, boxShadow: `0 2px 8px ${themeConfig.shadowColor}` }"
				>
					<FaIcon icon="search" :size="22" :color="themeConfig.textSecondary" />
					<input
						v-model="searchWord"
						@input="handleSearch"
						placeholder="搜索备注/分类"
						:style="{ color: themeConfig.textPrimary }"
					/>
					<FaIcon
						v-if="searchWord"
						class="clear-icon"
						icon="xmark"
						:size="14"
						:color="themeConfig.textSecondary"
						@click="clearSearch"
					/>
				</view>

				<view class="filter-section">
					<view class="filter-row-label" :style="{ color: themeConfig.textSecondary }">类型</view>
					<CapsuleFilter
						:options="BILL_TYPE_FILTER_OPTIONS"
						:value="billType"
						@change="handleTypeFilterChange"
						size="small"
					/>
				</view>

				<view class="filter-section">
					<view class="filter-row-label" :style="{ color: themeConfig.textSecondary }">时间</view>
					<CapsuleFilter
						:options="BILL_TIME_FILTER_OPTIONS"
						:value="activeTimeTag"
						@change="handleTimeFilterChange"
						size="small"
						:scrollable="true"
					/>
				</view>
			</view>
		</view>

		<view class="modal" v-if="showCustomDateModal" @click="showCustomDateModal = false">
			<view
				class="modal-box date-picker-box theme-transition"
				:style="{ backgroundColor: themeConfig.cardBgColor }"
				@click.stop
			>
				<view class="modal-title" :style="{ color: themeConfig.textPrimary }">选择时间范围</view>
				<view class="form-field">
					<text class="field-label" :style="{ color: themeConfig.textSecondary }">开始日期：</text>
					<picker mode="date" :value="customStartDate" @change="e => customStartDate = e.detail.value">
						<view
							class="date-picker field-value"
							:style="{ backgroundColor: themeConfig.bgColor, color: themeConfig.textPrimary, borderColor: themeConfig.borderColor }"
						>{{ customStartDate }}</view>
					</picker>
				</view>
				<view class="form-field">
					<text class="field-label" :style="{ color: themeConfig.textSecondary }">结束日期：</text>
					<picker mode="date" :value="customEndDate" @change="e => customEndDate = e.detail.value">
						<view
							class="date-picker field-value"
							:style="{ backgroundColor: themeConfig.bgColor, color: themeConfig.textPrimary, borderColor: themeConfig.borderColor }"
						>{{ customEndDate }}</view>
					</picker>
				</view>
				<view class="btns">
					<button
						class="cancel-btn theme-transition"
						:style="{ backgroundColor: themeConfig.borderColor, color: themeConfig.textSecondary }"
						@click="showCustomDateModal = false"
					>取消</button>
					<button
					class="confirm-btn theme-transition btn btn--primary"
					@click="confirmCustomDate"
					>确认</button>
				</view>
			</view>
		</view>

		<scroll-view class="main-scroll" scroll-y :show-scrollbar="false">
			<AppCard
				class="budget-card"
				:padding="24"
				:radius="20"
				:marginBottom="20"
			>
				<view class="budget-title">
					<text :style="{ color: themeConfig.textPrimary }">本月预算</text>
					<text class="budget-value" :style="{ color: themeConfig.primaryColor }" v-if="monthlyBudget">¥{{ monthlyBudget }}</text>
					<text class="budget-set-btn" :style="{ color: themeConfig.primaryColor }" v-else @click="handleBudgetSetting">去设置</text>
				</view>
				<view v-if="monthlyBudget">
					<view class="progress-bar" :style="{ backgroundColor: themeConfig.bgColor }">
						<view class="progress-fill" :style="{ width: budgetProgress + '%', backgroundColor: getProgressColor() }"></view>
					</view>
					<view class="budget-info">
						<text :class="{ over: budgetProgress > 100 }" :style="{ color: budgetProgress > 100 ? themeConfig.dangerColor : themeConfig.textSecondary }">已支出 ¥{{ monthExpend }} / ¥{{ monthlyBudget }}</text>
						<text :style="{ color: themeConfig.textSecondary }">剩余预算：¥{{ remainingBudget }}</text>
						<text :style="{ color: themeConfig.textSecondary }">{{ budgetProgress.toFixed(1) }}%</text>
					</view>
				</view>
				<view class="budget-empty" v-else>
					<text :style="{ color: themeConfig.textSecondary }">尚未设置本月预算，点击右上角「去设置」添加</text>
				</view>
			</AppCard>

			<AppCard
				class="budget-card"
				v-if="activeTimeTag === 'lastMonth'"
				:padding="24"
				:radius="20"
				:marginBottom="20"
			>
				<view class="budget-title">
					<text :style="{ color: themeConfig.textPrimary }">上月预算</text>
					<text class="budget-value" :style="{ color: themeConfig.primaryColor }" v-if="lastMonthBudget">¥{{ lastMonthBudget }}</text>
					<text class="budget-set-btn" :style="{ color: themeConfig.primaryColor }" v-else @click="handleLastMonthBudgetSetting">去设置</text>
				</view>
				<view v-if="lastMonthBudget">
					<view class="progress-bar" :style="{ backgroundColor: themeConfig.bgColor }">
						<view class="progress-fill" :style="{ width: lastMonthBudgetProgress + '%', backgroundColor: getProgressColor() }"></view>
					</view>
					<view class="budget-info">
						<text :class="{ over: lastMonthBudgetProgress > 100 }" :style="{ color: lastMonthBudgetProgress > 100 ? themeConfig.dangerColor : themeConfig.textSecondary }">已支出 ¥{{ lastMonthExpend }} / ¥{{ lastMonthBudget }}</text>
						<text :style="{ color: themeConfig.textSecondary }">剩余预算：¥{{ lastMonthRemainingBudget }}</text>
						<text :style="{ color: themeConfig.textSecondary }">{{ lastMonthBudgetProgress.toFixed(1) }}%</text>
					</view>
				</view>
				<view class="budget-empty" v-else>
					<text :style="{ color: themeConfig.textSecondary }">尚未设置上月预算，点击右上角「去设置」添加</text>
				</view>
			</AppCard>

			<AppCard class="stat-card card-enter" :padding="24" :radius="12" :marginBottom="20">
				<scroll-view class="stat-scroll" scroll-x :show-scrollbar="false">
					<view class="stat-row">
						<view class="stat-item">
							<view class="stat-icon expend-icon">💸</view>
							<view class="stat-info">
								<text class="label" :style="{ color: themeConfig.textSecondary }">总支出</text>
								<text class="value expend" :style="{ color: themeConfig.dangerColor }">¥{{ totalExpend.toFixed(2) }}</text>
							</view>
						</view>
						<view class="stat-item">
							<view class="stat-icon income-icon">💰</view>
							<view class="stat-info">
								<text class="label" :style="{ color: themeConfig.textSecondary }">总收入</text>
								<text class="value income" :style="{ color: themeConfig.secondaryColor }">¥{{ totalIncome.toFixed(2) }}</text>
							</view>
						</view>
						<view class="stat-item">
							<view class="stat-icon balance-icon">📊</view>
							<view class="stat-info">
								<text class="label" :style="{ color: themeConfig.textSecondary }">当前结余</text>
								<text class="value balance" :style="{ color: currentPeriodBalance >= 0 ? themeConfig.secondaryColor : themeConfig.dangerColor }">
									{{ currentPeriodBalance >= 0 ? '+' : '-' }}¥{{ Math.abs(currentPeriodBalance).toFixed(2) }}
								</text>
							</view>
						</view>
						<view class="stat-item">
							<view class="stat-icon month-icon">📅</view>
							<view class="stat-info">
								<text class="label" :style="{ color: themeConfig.textSecondary }">累计结余</text>
								<text class="value balance" :style="{ color: monthlyTotalBalance >= 0 ? themeConfig.secondaryColor : themeConfig.dangerColor }">
									{{ monthlyTotalBalance >= 0 ? '+' : '-' }}¥{{ Math.abs(monthlyTotalBalance).toFixed(2) }}
								</text>
							</view>
						</view>
					</view>
				</scroll-view>
			</AppCard>

			<view class="cate-stat-section card-enter">
				<view class="cate-stat-single" v-if="cateStatList.length <= 2">
					<view
						class="cate-stat-item-wide theme-transition"
						v-for="item in cateStatList"
						:key="item.cate"
						@click="filterByCate(item.cate)"
						:style="{ backgroundColor: themeConfig.cardBgColor }"
					>
						<view class="cate-left-wide">
							<view class="cate-icon-wide" :style="{ backgroundColor: item.color }">{{ item.icon }}</view>
							<text class="cate-name-wide" :style="{ color: themeConfig.textPrimary }">{{ getCateLabel(item.cate) }}</text>
						</view>
						<view class="cate-right-wide">
							<view class="cate-money-row-wide">
								<text class="cate-money expend" :style="{ color: themeConfig.dangerColor }">支出：¥{{ item.expend.toFixed(2) }}</text>
								<text class="cate-money income" :style="{ color: themeConfig.secondaryColor }">收入：¥{{ item.income.toFixed(2) }}</text>
							</view>
							<view class="cate-rate-row-wide">
								<text class="cate-rate" :style="{ color: themeConfig.textSecondary }">占比：支出{{ item.expendRate }}% / 收入{{ item.incomeRate }}%</text>
							</view>
						</view>
					</view>
				</view>

				<view class="cate-stat-scroll-wrapper" v-else>
					<scroll-view class="cate-stat-scroll" scroll-x="true" :show-scrollbar="false" @scroll="onCateScroll">
						<view class="cate-stat-container-scroll">
							<view
								class="cate-stat-item-scroll theme-transition"
								v-for="item in cateStatList"
								:key="item.cate"
								@click="filterByCate(item.cate)"
								:style="{ backgroundColor: themeConfig.cardBgColor }"
							>
								<view class="cate-icon-scroll" :style="{ backgroundColor: item.color }">{{ item.icon }}</view>
								<text class="cate-name-scroll" :style="{ color: themeConfig.textPrimary }">{{ getCateLabel(item.cate) }}</text>
								<view class="cate-stat-row-scroll">
									<text class="cate-stat-text" :style="{ color: themeConfig.dangerColor }">支出 ¥{{ item.expend.toFixed(2) }}</text>
								</view>
								<view class="cate-stat-row-scroll">
									<text class="cate-stat-text" :style="{ color: themeConfig.secondaryColor }">收入 ¥{{ item.income.toFixed(2) }}</text>
								</view>
								<view class="cate-stat-row-scroll">
									<text class="cate-rate-scroll" :style="{ color: themeConfig.textSecondary }">占比 {{ item.expendRate }}%</text>
								</view>
							</view>
						</view>
					</scroll-view>
					<view class="scroll-indicator">
						<view
							class="indicator-dot"
							v-for="(item, index) in cateStatList"
							:key="index"
							:class="{ active: currentCateIndex === index }"
							:style="{ backgroundColor: currentCateIndex === index ? themeConfig.primaryColor : themeConfig.borderColor }"
						></view>
					</view>
				</view>
			</view>

			<view class="bill-list-container content-fade">
				<SkeletonScreen v-if="!billListLoaded" type="list" :count="5" />

				<AppCard
					v-else
					class="bill-list-card card-enter"
					:padding="16"
					:radius="20"
					:marginBottom="20"
				>
				<view v-if="Object.keys(groupedBillList).length === 0" class="bill-empty-wrap">
					<EmptyState
						type="bill"
						title="还没有账单记录"
						desc="点击按钮记录你的第一笔收支"
						actionText="记一笔"
						@action="openAddModal"
					/>
				</view>

					<view v-for="(group, dateKey) in groupedBillList" :key="dateKey" class="bill-group">
						<view class="bill-group-header">
							<text class="bill-group-date" :style="{ color: themeConfig.textSecondary }">{{ formatBillDate(dateKey) }}</text>
							<text class="bill-group-summary" :style="{ color: themeConfig.textSecondary }">
								收 +¥{{ group.income.toFixed(2) }} 支 -¥{{ group.expend.toFixed(2) }}
							</text>
						</view>

						<SwipeableItem
							v-for="item in group.items"
							:key="item.id"
							:actions="swipeActions"
							:index="item.id"
							@action="(action) => handleSwipeAction(action, item)"
							@closeOthers="closeOtherSwipe"
						>
							<view
								class="bill-item-content theme-transition"
								:style="{ backgroundColor: themeConfig.cardBgColor }"
							>
								<view class="bill-left">
									<text class="cate-icon" :style="{ backgroundColor: getCateColor(item.cate) }">{{ getCateIcon(item.cate) }}</text>
									<view class="bill-text">
										<text class="cate-name" :style="{ color: themeConfig.textPrimary }">{{ getCateLabel(item.cate) }}</text>
										<view class="bill-meta">
											<text class="channel" v-if="item.channel" :style="{ color: themeConfig.textSecondary }">{{ getChannelLabel(item.channel) }}</text>
											<text class="meta-divider" v-if="item.channel && item.note">·</text>
											<text class="note" v-if="item.note" :style="{ color: themeConfig.textSecondary }">{{ item.note }}</text>
										</view>
									</view>
								</view>
								<text
									class="money"
									:class="item.type === BILL_TYPE.EXPEND ? 'expend' : 'income'"
									:style="{ color: item.type === BILL_TYPE.EXPEND ? themeConfig.dangerColor : themeConfig.secondaryColor }"
								>
									{{ item.type === BILL_TYPE.EXPEND ? '-' : '+' }}{{ Number(item.money).toFixed(2) }}
								</text>
							</view>
						</SwipeableItem>
					</view>

					<view class="batch-bar" v-if="isBatchMode">
						<text :style="{ color: themeConfig.textSecondary }">已选 {{ selectedBillIds.length }} 项</text>
						<view class="batch-actions">
						<view class="batch-btn" :style="{ backgroundColor: themeConfig.dangerColor }" @click="batchDelete">批量删除</view>
						</view>
					</view>

					<view class="scroll-tip" v-if="showScrollTip" :style="{ color: themeConfig.textSecondary }">上滑查看更多</view>
					<view class="pagination-tip" v-if="hasMore" @click="loadMore">
						<text :style="{ color: themeConfig.primaryColor }">加载更多</text>
					</view>
					<view class="pagination-tip" v-else-if="billList.length > 0 && !hasMore" :style="{ color: themeConfig.textSecondary }">
						<text>已经到底了</text>
					</view>
				</AppCard>
			</view>
		</scroll-view>
	</view>

	<view class="modal" v-if="showBudgetModal" @click="showBudgetModal = false">
		<view
			class="modal-box budget-modal-box theme-transition"
			:style="{ backgroundColor: themeConfig.cardBgColor }"
			@click.stop
		>
			<view class="modal-title" :style="{ color: themeConfig.textPrimary }">设置预算</view>
			<view class="form-field">
				<text class="field-label" :style="{ color: themeConfig.textSecondary }">预算月份：</text>
				<picker mode="month" :value="selectedBudgetMonth" @change="onBudgetMonthChange">
					<view
						class="date-picker field-value"
						:style="{ backgroundColor: themeConfig.bgColor, color: themeConfig.textPrimary, borderColor: themeConfig.borderColor }"
					>{{ selectedBudgetMonth }}</view>
				</picker>
			</view>
			<view class="form-field">
				<text class="field-label" :style="{ color: themeConfig.textSecondary }">预算金额（元）</text>
				<input
					v-model="tempBudget"
					type="digit"
					placeholder="请输入预算金额"
					class="input money-input field-value"
					placeholder-class="input-placeholder"
					@input="validateMoneyInput(tempBudget, 'tempBudget')"
					:style="{ backgroundColor: themeConfig.bgColor, color: themeConfig.textPrimary, borderColor: themeConfig.borderColor }"
				/>
			</view>
			<view class="btns">
				<button
					class="cancel-btn theme-transition"
					:style="{ backgroundColor: themeConfig.borderColor, color: themeConfig.textSecondary }"
					@click="showBudgetModal = false"
				>取消</button>
				<button
					class="confirm-btn theme-transition btn btn--primary"
					@click="saveBudget"
				>确认设置</button>
			</view>
		</view>
	</view>

	<view class="float-buttons" @click.stop v-if="!showAdd && !isBatchMode">
		<view
			class="add-btn theme-transition"
			@click="handleAddBtnClick"
			:style="{ background: themeConfig.gradientSoft, transform: addBtnScale }"
		>
			<text class="add-btn-icon">+</text>
		</view>
	</view>

	<BottomSheet
		:visible="showAdd"
		:title="isEdit ? '编辑账单' : '记一笔'"
		height="85vh"
		@update:visible="val => showAdd = val"
		@close="handleSheetClose"
	>
		<view class="type-section">
			<view
				class="type-btn"
				:class="{ active: form.type === BILL_TYPE.EXPEND }"
				:style="{
					background: form.type === BILL_TYPE.EXPEND ? themeConfig.gradientSoft : themeConfig.borderColor,
					color: form.type === BILL_TYPE.EXPEND ? '#fff' : themeConfig.textSecondary
				}"
				@click="form.type = BILL_TYPE.EXPEND"
			>
				<text class="type-icon">💰</text>
				<text class="type-text">支出</text>
			</view>
			<view
				class="type-btn"
				:class="{ active: form.type === BILL_TYPE.INCOME }"
				:style="{
					background: form.type === BILL_TYPE.INCOME ? themeConfig.gradientSoft : themeConfig.borderColor,
					color: form.type === BILL_TYPE.INCOME ? '#fff' : themeConfig.textSecondary
				}"
				@click="form.type = BILL_TYPE.INCOME"
			>
				<text class="type-icon">📈</text>
				<text class="type-text">收入</text>
			</view>
		</view>

		<view class="amount-section">
			<text class="amount-label" :style="{ color: themeConfig.textSecondary }">金额</text>
			<view class="amount-input-wrap">
				<text class="amount-symbol" :style="{ color: form.type === BILL_TYPE.EXPEND ? themeConfig.dangerColor : themeConfig.secondaryColor }">¥</text>
				<input
					v-model="formattedMoney"
					type="digit"
					placeholder="0.00"
					class="amount-input"
					@input="handleMoneyInput"
					@blur="formatMoneyOnBlur"
					:style="{ color: form.type === BILL_TYPE.EXPEND ? themeConfig.dangerColor : themeConfig.secondaryColor }"
				/>
			</view>
			<view class="quick-amounts">
				<text
					class="quick-amount-btn"
					v-for="amount in QUICK_MONEY_AMOUNTS"
					:key="amount"
					@click="fillQuickMoney(amount)"
					:style="{ backgroundColor: themeConfig.borderColor, color: themeConfig.textSecondary }"
				>¥{{ amount }}</text>
			</view>
		</view>

		<view class="section">
			<text class="section-title" :style="{ color: themeConfig.textPrimary }">分类</text>
			<view class="recent-cate-row" v-if="recentCateList.length">
				<text class="recent-label" :style="{ color: themeConfig.textSecondary }">最近</text>
				<view class="recent-cate-items">
					<view
						class="recent-cate-item"
						v-for="cate in recentCateList"
						:key="cate.value"
						:class="{ active: form.cate === cate.value }"
						@click="form.cate = cate.value"
					>
						<text class="recent-cate-icon" :style="{ backgroundColor: cate.color }">{{ cate.icon }}</text>
						<text class="recent-cate-name" :style="{ color: themeConfig.textPrimary }">{{ cate.label }}</text>
					</view>
				</view>
			</view>
			<view class="cate-grid-new">
				<view
					class="cate-item-new"
					v-for="cate in cateList"
					:key="cate.value"
					:class="{ active: form.cate === cate.value }"
					@click="selectCate(cate)"
				>
					<view class="cate-icon-wrap" :style="{ backgroundColor: form.cate === cate.value ? cate.color : themeConfig.borderColor }">
						<text class="cate-icon">{{ cate.icon }}</text>
					</view>
					<text class="cate-label" :style="{ color: form.cate === cate.value ? cate.color : themeConfig.textSecondary }">{{ cate.label }}</text>
				</view>
				<view class="cate-item-new add-cate" @click="showCustomCate = true">
					<view class="cate-icon-wrap add-icon-wrap">
						<text class="cate-icon">+</text>
					</view>
					<text class="cate-label" :style="{ color: themeConfig.textSecondary }">自定义</text>
				</view>
			</view>
		</view>

		<view class="section">
			<text class="section-title" :style="{ color: themeConfig.textPrimary }">支付渠道</text>
			<view class="channel-grid">
				<text
					class="channel-btn"
					v-for="channel in currentChannels"
					:key="channel.value"
					:class="{ active: form.channel === channel.value }"
					@click="form.channel = channel.value"
					:style="{
						backgroundColor: form.channel === channel.value ? themeConfig.primaryColor : 'transparent',
						color: form.channel === channel.value ? '#fff' : themeConfig.textSecondary,
						borderColor: form.channel === channel.value ? themeConfig.primaryColor : themeConfig.borderColor
					}"
				>{{ channel.label }}</text>
			</view>
		</view>

		<view class="section">
			<text class="section-title" :style="{ color: themeConfig.textPrimary }">备注</text>
			<view class="note-input-wrap">
				<input
					v-model="form.note"
					type="text"
					placeholder="添加备注（选填）"
					class="note-input"
					:style="{ backgroundColor: themeConfig.bgColor, color: themeConfig.textPrimary }"
				/>
			</view>
			<view class="quick-tags">
				<text
					class="quick-tag"
					v-for="tag in QUICK_NOTE_TAGS"
					:key="tag"
					@click="form.note = tag"
					:style="{ backgroundColor: themeConfig.borderColor, color: themeConfig.textSecondary }"
				>#{{ tag }}</text>
			</view>
		</view>

		<view class="section">
			<text class="section-title" :style="{ color: themeConfig.textPrimary }">日期</text>
			<picker mode="date" :value="form.date" @change="e => form.date = e.detail.value">
				<view class="date-picker-wrap" :style="{ backgroundColor: themeConfig.bgColor }">
					<text class="date-text" :style="{ color: themeConfig.textPrimary }">
						{{ form.date === formatCurrentDate() ? '今天' : formatDate(form.date) }}
					</text>
					<FaIcon icon="chevron-right" :size="14" :color="themeConfig.textSecondary" />
				</view>
			</picker>
		</view>

		<view class="section" v-if="showAiSuggestion">
			<text class="section-title" :style="{ color: themeConfig.textPrimary }">AI 智能建议</text>
			<view
				class="ai-suggestion"
				:style="{ borderColor: themeConfig.primaryColor }"
				@click="applyAiSuggestion"
			>
				<text class="ai-suggestion-text" :style="{ color: themeConfig.primaryColor }">{{ aiSuggestionText }}</text>
				<text class="ai-suggestion-hint" :style="{ color: themeConfig.textSecondary }">点击应用</text>
			</view>
		</view>

		<template #footer>
			<view class="modal-footer">
				<button class="btn-cancel" :style="{ color: themeConfig.textSecondary }" @click="closeModal">取消</button>
				<button
					class="btn-confirm"
					:style="{ background: themeConfig.gradientSoft }"
					@click="submitBill"
					:loading="submitting"
				>{{ isEdit ? '保存修改' : '确认账单' }}</button>
			</view>
		</template>
	</BottomSheet>

	<view class="modal modal-center" v-if="showCustomCate" @click="showCustomCate = false">
		<view
			class="custom-cate-box theme-transition"
			:style="{ backgroundColor: themeConfig.cardBgColor }"
			@click.stop
		>
			<text class="modal-title" :style="{ color: themeConfig.textPrimary }">自定义分类</text>
			<input
				v-model="customCateName"
				placeholder="分类名称"
				class="input"
				maxlength="6"
				:style="{ backgroundColor: themeConfig.bgColor, color: themeConfig.textPrimary, borderColor: themeConfig.borderColor }"
			/>
			<view class="color-select">
				<text class="form-label" :style="{ color: themeConfig.textSecondary }">选择颜色</text>
				<view class="color-list">
					<view
						class="color-item"
						v-for="color in colorOptions"
						:key="color"
						:style="{ backgroundColor: color }"
						:class="{ active: selectedColor === color }"
						@click="selectedColor = color"
					></view>
				</view>
			</view>
			<input
				v-model="customCateIcon"
				placeholder="输入图标（如🍚）"
				class="input"
				maxlength="2"
				:style="{ backgroundColor: themeConfig.bgColor, color: themeConfig.textPrimary, borderColor: themeConfig.borderColor }"
			/>
			<view class="btns">
				<button
					class="cancel-btn theme-transition"
					:style="{ backgroundColor: themeConfig.borderColor, color: themeConfig.textSecondary }"
					@click="showCustomCate = false"
				>取消</button>
				<button
					class="confirm-btn theme-transition btn btn--primary"
					@click="addCustomCate"
				>确认添加</button>
			</view>
		</view>
	</view>

	<CenterModal
		:visible="showDeleteConfirm"
		title="确认删除"
		:showCancel="true"
		cancelText="取消"
		confirmText="删除"
		:confirmColor="themeConfig.dangerColor"
		@confirm="confirmDeleteBill"
		@cancel="showDeleteConfirm = false"
		@update:visible="val => showDeleteConfirm = val"
	>
		<text class="delete-confirm-text" :style="{ color: themeConfig.textPrimary }">
			{{ deleteConfirmMessage }}
		</text>
	</CenterModal>

	<CenterModal
		:visible="showBatchDeleteConfirm"
		title="批量删除确认"
		:showCancel="true"
		cancelText="取消"
		confirmText="删除"
		:confirmColor="themeConfig.dangerColor"
		@confirm="confirmBatchDelete"
		@cancel="showBatchDeleteConfirm = false"
	>
		<text class="delete-confirm-text" :style="{ color: themeConfig.textPrimary }">
			确定要删除选中的 {{ selectedBillIds.length }} 条账单吗？
		</text>
	</CenterModal>

	<GrowthModal
		:visible="growthModalVisible"
		:title="growthModalTitle"
		:message="growthModalMessage"
		:icon="growthModalIcon"
		:confirm-text="growthModalConfirmText"
		@close="growthModalVisible = false"
	/>
	
</template>

<script>
import { getBillList, addBill, editBill, deleteBill, getMonthBudget, setMonthBudget } from '@/api'
import { aiClassify as classifyBillApi } from '@/api/index.js'
import { checkLogin } from '@/utils/auth'
import { refreshNavBarTheme, forceApplyTabBarTheme } from '@/utils/themeGlobal'
import { getThemeConfigFromStorage, THEME_PRESETS } from '@/utils/theme'

import PageHeader from '@/components/PageHeader.vue'
import CapsuleFilter from '@/components/CapsuleFilter.vue'
import AppCard from '@/components/AppCard.vue'
import BottomSheet from '@/components/BottomSheet.vue'
import CenterModal from '@/components/CenterModal.vue'
import EmptyState from '@/components/EmptyState.vue'
import FaIcon from '@/components/FaIcon.vue'
import GrowthModal from '@/components/GrowthModal.vue'
import SwipeableItem from '@/components/SwipeableItem.vue'
import SkeletonScreen from '@/components/SkeletonScreen.vue'

import themeMixin from '@/mixins/themeMixin.js'
import growthModalMixin from '@/mixins/growthModalMixin.js'

import {
	DEFAULT_CATE_LIST,
	BILL_TYPE,
	COLOR_OPTIONS,
	SLIDE_BTN_WIDTH,
	BILL_FILTER_TYPE,
	TIME_TAG,
	QUICK_MONEY_AMOUNTS,
	QUICK_NOTE_TAGS,
	BUDGET_PROGRESS_COLOR,
	PROGRESS_COLORS,
	RECENT_CATE_MAX_COUNT,
	SLIDE_THRESHOLD,
	BILL_TYPE_FILTER_OPTIONS,
	BILL_TIME_FILTER_OPTIONS,
	PAY_CHANNELS,
	getChannelsByType,
	getChannelLabel,
	getCateLabel
} from '@/utils/constants'

const expenseCategories = DEFAULT_CATE_LIST.filter(c => c.type === BILL_TYPE.EXPEND)
const incomeCategories = DEFAULT_CATE_LIST.filter(c => c.type === BILL_TYPE.INCOME)

const TYPE_TO_CATEGORY = {
	[BILL_TYPE.EXPEND]: expenseCategories,
	[BILL_TYPE.INCOME]: incomeCategories
}

const CATEGORY_TO_TYPES = {}
DEFAULT_CATE_LIST.forEach(c => {
	CATEGORY_TO_TYPES[c.value] = c.type
})

export default {
	components: {
		PageHeader,
		CapsuleFilter,
		AppCard,
		BottomSheet,
		CenterModal,
		EmptyState,
		FaIcon,
		GrowthModal,
		SwipeableItem,
		SkeletonScreen
	},
	mixins: [themeMixin, growthModalMixin],
	data() {
		return {
			BILL_TYPE_FILTER_OPTIONS,
			BILL_TIME_FILTER_OPTIONS,
			QUICK_MONEY_AMOUNTS,
			QUICK_NOTE_TAGS,
			BILL_FILTER_TYPE,
			TIME_TAG,
			BILL_TYPE,
			expenseCategories,
			incomeCategories,
			TYPE_TO_CATEGORY,
			CATEGORY_TO_TYPES,

			searchWord: '',
			billType: BILL_FILTER_TYPE.ALL,
			activeTimeTag: TIME_TAG.TODAY,
			billList: [],
			billListLoaded: false,
			displayBillList: [],

			showAdd: false,
			isEdit: false,
			currentEditId: '',
			form: { type: BILL_TYPE.EXPEND, money: '', cate: '', channel: 'wechat', note: '', date: '' },
			formattedMoney: '',
			moneyInputError: '',

			allCateList: DEFAULT_CATE_LIST,
			showCustomCate: false,
			customCateName: '',
			customCateIcon: '',
			selectedColor: COLOR_OPTIONS[0],
			colorOptions: COLOR_OPTIONS,

			monthlyBudget: '',
			monthExpend: 0,
			budgetProgress: 0,
			remainingBudget: 0,
			totalExpend: 0,
			totalIncome: 0,
			totalBalance: 0,
			currentPeriodBalance: 0,
			monthlyTotalBalance: 0,
			cateStatList: [],
			currentCateIndex: 0,

			searchTimer: null,
			showBudgetModal: false,
			tempBudget: '',
			selectedBudgetMonth: '',
			refreshing: false,
			submitting: false,
			recentCateList: [],
			filterCate: '',
			showScrollTip: false,
			addBtnScale: 'scale(1)',

			showCustomDateModal: false,
			customStartDate: '',
			customEndDate: '',
			customDateRange: { start: '', end: '' },

			lastMonthBudget: '',
			lastMonthExpend: 0,
			lastMonthBudgetProgress: 0,
			lastMonthRemainingBudget: 0,

			isBatchMode: false,
			selectedBillIds: [],

			showDeleteConfirm: false,
			deleteConfirmMessage: '',
			pendingDeleteId: null,

			showBatchDeleteConfirm: false,

			currentMonthFirst: '',
			currentMonthLast: '',

			page: 1,
			pageSize: 20,
			hasMore: true,

			showAiSuggestion: false,
			aiSuggestionText: '',
			aiSuggestionData: null,

			swipeActions: [
				{ key: 'edit', label: '编辑' },
				{ key: 'delete', label: '删除' }
			]
		}
	},
	computed: {
		currentChannels() {
			return getChannelsByType(this.form.type)
		},
		cateList() {
			return this.allCateList.filter(item => item.type === this.form.type)
		},
		filteredBillList() {
			let list = this.getBillByTimeRange()
			if (this.billType === BILL_FILTER_TYPE.EXPEND) {
				list = list.filter(item => item.type === BILL_TYPE.EXPEND)
			} else if (this.billType === BILL_FILTER_TYPE.INCOME) {
				list = list.filter(item => item.type === BILL_TYPE.INCOME)
			}
			if (this.filterCate) list = list.filter(item => item.cate === this.filterCate)
			if (this.searchWord) {
				const keyword = this.searchWord.trim()
				list = list.filter(item =>
					(item.cate && item.cate.includes(keyword)) ||
					(item.note && item.note.includes(keyword))
				)
			}
			return list
		},
		groupedBillList() {
			const groups = {}
			this.displayBillList.forEach(item => {
				const dateKey = item.date
				if (!groups[dateKey]) {
					groups[dateKey] = { date: dateKey, items: [], income: 0, expend: 0 }
				}
				groups[dateKey].items.push(item)
				if (item.type === BILL_TYPE.INCOME) {
					groups[dateKey].income += Number(item.money) || 0
				} else if (item.type === BILL_TYPE.EXPEND) {
					groups[dateKey].expend += Number(item.money) || 0
				}
			})
			return groups
		}
	},
	onLoad(options) {
		this.themeChangeHandler = (themeData) => {
			try {
				let newTheme = null
				if (themeData?.key && THEME_PRESETS[themeData.key]) {
					newTheme = THEME_PRESETS[themeData.key]
				} else if (themeData?.config) {
					newTheme = themeData.config
				}
				if (newTheme) {
					this.themeConfig = newTheme
					this.$forceUpdate()
				}
			} catch (e) {
				console.error('主题更新失败:', e)
			}
		}
		uni.$on('themeChanged', this.themeChangeHandler)

		const now = new Date()
		const today = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`
		const paramsDate = options?.date || today
		this.selectedDate = paramsDate
		this.form.date = paramsDate
		this.initCurrentMonthDate()
		this.initBudgetMonth()
		this.recentCateList = uni.getStorageSync('recentCateList') || []
		checkLogin()
		this.getList()
		this.customStartDate = paramsDate
		this.customEndDate = paramsDate
		this.customDateRange = { start: paramsDate, end: paramsDate }
		this.getMonthBudgetData()
	},
	onUnload() {
		uni.$off('themeChanged', this.themeChangeHandler)
	},
	onShow() {
		const latestTheme = getThemeConfigFromStorage() || THEME_PRESETS['default']
		if (JSON.stringify(latestTheme) !== JSON.stringify(this.themeConfig)) {
			this.themeConfig = latestTheme
			this.$forceUpdate()
		}
		refreshNavBarTheme()
		setTimeout(() => {
			forceApplyTabBarTheme(latestTheme)
		}, 100)

		const now = new Date()
		const today = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`
		this.form.date = today
		this.selectedDate = today
		this._onShowId = Date.now()
		const currentId = this._onShowId
		setTimeout(() => {
			if (this._onShowId !== currentId) return
			this.getMonthBudgetData()
		}, 200)
	},
	onPullDownRefresh() {
		this.refreshing = true
		this.getList().finally(() => {
			this.refreshing = false
			uni.stopPullDownRefresh()
		})
	},
	watch: {
		activeTimeTag(newVal) {
			this.page = 1
			this.hasMore = true
			this.getList()
			if (newVal === TIME_TAG.MONTH) this.getMonthBudgetData()
			if (newVal === TIME_TAG.LAST_MONTH) this.getLastMonthBudgetData()
			this.$nextTick(() => {
				this.calcStatistics()
			})
		},
		billList() {
			this.calcStatistics()
		}
	},
	methods: {
		initCurrentMonthDate() {
			const now = new Date()
			const year = now.getFullYear()
			const month = String(now.getMonth() + 1).padStart(2, '0')
			const firstDay = '01'
			const lastDay = String(new Date(now.getFullYear(), now.getMonth() + 1, 0).getDate()).padStart(2, '0')
			this.currentMonthFirst = `${year}-${month}-${firstDay}`
			this.currentMonthLast = `${year}-${month}-${lastDay}`
		},
		initBudgetMonth() {
			const now = new Date()
			const year = now.getFullYear()
			const month = String(now.getMonth() + 1).padStart(2, '0')
			this.selectedBudgetMonth = `${year}-${month}`
		},
		onBudgetMonthChange(e) {
			this.selectedBudgetMonth = e.detail.value
		},
		formatDate(dateStr) {
			return dateStr || ''
		},
		getChannelLabel(value) {
			return getChannelLabel(value)
		},
		getCateLabel(value) {
			return getCateLabel(value)
		},
		formatCurrentDate() {
			const now = new Date()
			return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`
		},
		formatBillDate(dateStr) {
			if (!dateStr) return ''
			const date = new Date(dateStr)
			return `${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()}`
		},
		handleSearch() {
			clearTimeout(this.searchTimer)
			this.searchTimer = setTimeout(() => {}, 300)
		},
		clearSearch() {
			this.searchWord = ''
			this.$forceUpdate()
		},
		handleTypeFilterChange(val) {
			this.billType = val
			this.page = 1
			this.hasMore = true
			this.$nextTick(() => {
				this.loadFirstPage()
			})
		},
		handleTimeFilterChange(val) {
			if (val === TIME_TAG.CUSTOM) {
				this.openCustomDatePicker()
			} else {
				this.switchTimeTag(val)
			}
		},
		toggleBatchMode() {
			this.isBatchMode = !this.isBatchMode
			if (!this.isBatchMode) {
				this.selectedBillIds = []
			}
		},
		handleSwipeAction(action, item) {
			if (action === 'edit') {
				this.handleEditBill(item)
			} else if (action === 'delete') {
				this.handleDeleteBill(item.id)
			}
		},
		closeOtherSwipe(id) {
		},
		async getList() {
			if (this._listLoading) return
			this._listLoading = true
			this.billListLoaded = false
			try {
				const now = new Date()
				const today = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`
				let start = '', end = ''

				if (this.activeTimeTag === TIME_TAG.TODAY) {
					start = end = today
				} else if (this.activeTimeTag === TIME_TAG.WEEK) {
					const dayOfWeek = now.getDay() || 7
					const diffDays = dayOfWeek - 1
					const weekStart = new Date(now)
					weekStart.setDate(now.getDate() - diffDays)
					start = `${weekStart.getFullYear()}-${String(weekStart.getMonth() + 1).padStart(2, '0')}-${String(weekStart.getDate()).padStart(2, '0')}`
					end = today
				} else if (this.activeTimeTag === TIME_TAG.MONTH) {
					const monthStart = new Date(now.getFullYear(), now.getMonth(), 1)
					const monthEnd = new Date(now.getFullYear(), now.getMonth() + 1, 0)
					start = `${monthStart.getFullYear()}-${String(monthStart.getMonth() + 1).padStart(2, '0')}-${String(monthStart.getDate()).padStart(2, '0')}`
					end = `${monthEnd.getFullYear()}-${String(monthEnd.getMonth() + 1).padStart(2, '0')}-${String(monthEnd.getDate()).padStart(2, '0')}`
				} else if (this.activeTimeTag === TIME_TAG.LAST_MONTH) {
					const lastMonth = new Date(now.getFullYear(), now.getMonth() - 1, 1)
					const lastMonthEnd = new Date(now.getFullYear(), now.getMonth(), 0)
					start = `${lastMonth.getFullYear()}-${String(lastMonth.getMonth() + 1).padStart(2, '0')}-01`
					end = `${lastMonthEnd.getFullYear()}-${String(lastMonthEnd.getMonth() + 1).padStart(2, '0')}-${String(lastMonthEnd.getDate()).padStart(2, '0')}`
				} else if (this.activeTimeTag === TIME_TAG.THIS_YEAR) {
					start = `${now.getFullYear()}-01-01`
					end = today
				} else if (this.activeTimeTag === TIME_TAG.CUSTOM) {
					start = this.customDateRange.start || today
					end = this.customDateRange.end || today
				}

				const res = await getBillList({ start_time: start, end_time: end })
				this.billList = res.map(item => ({
					id: item.ID,
					type: item.type,
					money: item.money,
					cate: item.cate,
					channel: item.channel,
					note: item.note,
					date: item.date,
					from_account: item.from_account,
					to_account: item.to_account
				}))
				this.page = 1
				this.hasMore = this.billList.length > this.pageSize
				this.loadFirstPage()
			} catch (e) {
				console.error('获取账单失败：', e)
				this.billList = []
			} finally {
				this.billListLoaded = true
				this.refreshing = false
				this._listLoading = false
			}
		},
		loadFirstPage() {
			const firstPageData = this.filteredBillList.slice(0, this.pageSize)
			this.displayBillList = firstPageData
		},
		loadMore() {
			if (!this.hasMore) return
			this.page++
			const start = (this.page - 1) * this.pageSize
			const end = this.page * this.pageSize
			const nextPageData = this.filteredBillList.slice(start, end)
			this.displayBillList = [...this.displayBillList, ...nextPageData]
			const totalFiltered = this.filteredBillList.length
			this.hasMore = this.displayBillList.length < totalFiltered
		},
		async getMonthBudgetData() {
			try {
				const res = await getMonthBudget()
				this.monthlyBudget = res && res.amount ? Number(res.amount) : ''
				this.calcStatistics()
			} catch (e) {
				console.error('获取本月预算失败：', e)
				this.monthlyBudget = ''
				uni.showToast({ title: '获取预算失败', icon: 'none' })
			}
		},
		getProgressColor() {
			if (this.budgetProgress >= BUDGET_PROGRESS_COLOR.OVER) {
				return PROGRESS_COLORS.OVER
			} else if (this.budgetProgress >= BUDGET_PROGRESS_COLOR.WARNING) {
				return PROGRESS_COLORS.WARNING
			} else {
				return PROGRESS_COLORS.NORMAL
			}
		},
		handleBudgetSetting() {
			this.tempBudget = this.monthlyBudget ? this.monthlyBudget.toString() : ''
			this.initBudgetMonth()
			this.showBudgetModal = true
		},
		async saveBudget() {
			if (!checkLogin()) return
			const num = Number(this.tempBudget)
			if (!this.tempBudget || isNaN(num) || num <= 0) {
				uni.showToast({ title: '请输入有效的预算金额', icon: 'none' })
				return
			}
			try {
				await setMonthBudget({ amount: num, month: this.selectedBudgetMonth })
				const currentMonth = new Date().getMonth() + 1
				const budgetMonth = Number(this.selectedBudgetMonth.split('-')[1])
				if (budgetMonth === currentMonth) {
					this.monthlyBudget = num
				} else {
					this.lastMonthBudget = num
				}
				this.showBudgetModal = false
				this.tempBudget = ''
				this.calcStatistics()
				uni.showToast({ title: '预算设置成功', icon: 'success' })
			} catch (err) {
				console.error('设置预算失败：', err)
				uni.showToast({ title: '设置失败', icon: 'none' })
			}
		},
		calcStatistics() {
			this.totalExpend = 0
			this.totalIncome = 0
			this.monthExpend = 0
			this.monthlyTotalBalance = 0
			this.lastMonthExpend = 0
			const filteredByTime = this.getBillByTimeRange()
			const allMonthlyBills = this.getMonthlyBills()
			filteredByTime.forEach(item => {
				const money = Number(item.money) || 0
				if (item.type === BILL_TYPE.EXPEND) this.totalExpend += money
				else if (item.type === BILL_TYPE.INCOME) this.totalIncome += money
				if (item.type === BILL_TYPE.EXPEND && this.isCurrentMonth(item.date)) this.monthExpend += money
				if (item.type === BILL_TYPE.EXPEND) {
					if (this.isCurrentMonth(item.date)) {
						this.monthExpend += money
					}
					if (this.isLastMonth(item.date)) {
						this.lastMonthExpend += money
					}
				}
			})
			allMonthlyBills.forEach(item => {
				const money = Number(item.money) || 0
				if (item.type === BILL_TYPE.EXPEND) this.monthlyTotalBalance -= money
				else if (item.type === BILL_TYPE.INCOME) this.monthlyTotalBalance += money
			})
			this.currentPeriodBalance = Number((this.totalIncome - this.totalExpend).toFixed(2))
			this.totalBalance = this.currentPeriodBalance
			this.monthlyTotalBalance = Number(this.monthlyTotalBalance.toFixed(2))
			this.budgetProgress = this.monthlyBudget ? (this.monthExpend / this.monthlyBudget) * 100 : 0
			this.remainingBudget = this.monthlyBudget ? (this.monthlyBudget - this.monthExpend).toFixed(2) : 0
			this.lastMonthBudgetProgress = this.lastMonthBudget ? (this.lastMonthExpend / this.lastMonthBudget) * 100 : 0
			this.lastMonthRemainingBudget = this.lastMonthBudget ? (this.lastMonthBudget - this.lastMonthExpend).toFixed(2) : 0
			this.calcCateStatistics(filteredByTime)
		},
		getMonthlyBills() {
			const now = new Date()
			const monthStart = new Date(now.getFullYear(), now.getMonth(), 1, 0, 0, 0)
			const monthEnd = new Date(now.getFullYear(), now.getMonth() + 1, 0, 23, 59, 59)
			return this.billList.filter(item => {
				if (!item.date) return false
				const billDateStr = item.date.replace(/-/g, '/')
				const billTime = new Date(billDateStr).getTime()
				return billTime >= monthStart.getTime() && billTime <= monthEnd.getTime()
			})
		},
		getBillByTimeRange() {
			const now = new Date()
			const today = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0)
			let startDate, endDate

			if (this.activeTimeTag === TIME_TAG.TODAY) {
				startDate = new Date(today)
				endDate = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59)
			} else if (this.activeTimeTag === TIME_TAG.WEEK) {
				const dayOfWeek = today.getDay() || 7
				const diffDays = dayOfWeek - 1
				const weekStart = new Date(today)
				weekStart.setDate(today.getDate() - diffDays)
				startDate = weekStart
				endDate = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59)
			} else if (this.activeTimeTag === TIME_TAG.MONTH) {
				const monthStart = new Date(now.getFullYear(), now.getMonth(), 1, 0, 0, 0)
				const monthEnd = new Date(now.getFullYear(), now.getMonth() + 1, 0, 23, 59, 59)
				startDate = monthStart
				endDate = monthEnd
			} else if (this.activeTimeTag === TIME_TAG.LAST_MONTH) {
				const lastMonth = new Date(now.getFullYear(), now.getMonth() - 1, 1, 0, 0, 0)
				const lastMonthEnd = new Date(now.getFullYear(), now.getMonth(), 0, 23, 59, 59)
				startDate = lastMonth
				endDate = lastMonthEnd
			} else if (this.activeTimeTag === TIME_TAG.THIS_YEAR) {
				const yearStart = new Date(now.getFullYear(), 0, 1, 0, 0, 0)
				startDate = yearStart
				endDate = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59)
			} else if (this.activeTimeTag === TIME_TAG.CUSTOM) {
				if (!this.customDateRange.start || !this.customDateRange.end) {
					startDate = new Date(today)
					endDate = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59)
				} else {
					startDate = new Date(this.customDateRange.start)
					endDate = new Date(this.customDateRange.end)
					endDate.setHours(23, 59, 59)
				}
			} else {
				startDate = new Date(today)
				endDate = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59)
			}

			return this.billList.filter(item => {
				if (!item.date) return false
				const billTime = new Date(item.date).getTime()
				return billTime >= startDate.getTime() && billTime <= endDate.getTime()
			})
		},
		switchTimeTag(tag) {
			this.activeTimeTag = tag
			this.filterCate = ''
			this.page = 1
			this.hasMore = true
			this.$nextTick(() => {
				this.getList()
				this.calcStatistics()
			})
		},
		openCustomDatePicker() {
			this.showCustomDateModal = true
			const now = new Date()
			const today = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`
			this.customStartDate = today
			this.customEndDate = today
		},
		confirmCustomDate() {
			if (!this.customStartDate || !this.customEndDate) {
				uni.showToast({ title: '请选择完整的时间范围', icon: 'none' })
				return
			}
			if (new Date(this.customStartDate) > new Date(this.customEndDate)) {
				uni.showToast({ title: '开始日期不能晚于结束日期', icon: 'none' })
				return
			}
			this.customDateRange = {
				start: this.customStartDate,
				end: this.customEndDate
			}
			this.showCustomDateModal = false
			this.activeTimeTag = TIME_TAG.CUSTOM
			this.filterCate = ''
			this.page = 1
			this.hasMore = true
			this.$nextTick(() => {
				this.getList()
				this.calcStatistics()
			})
			uni.showToast({ title: '时间范围已选择', icon: 'success' })
		},
		isCurrentMonth(dateStr) {
			if (!dateStr) return false
			const date = new Date(dateStr.replace(/-/g, '/'))
			const now = new Date()
			return date.getMonth() === now.getMonth() && date.getFullYear() === now.getFullYear()
		},
		isLastMonth(dateStr) {
			if (!dateStr) return false
			const date = new Date(dateStr.replace(/-/g, '/'))
			const now = new Date()
			const lastMonth = new Date(now.getFullYear(), now.getMonth() - 1, 1)
			return date.getMonth() === lastMonth.getMonth() && date.getFullYear() === lastMonth.getFullYear()
		},
		calcCateStatistics(list) {
			const cateMap = {}
			const totalExpend = list.filter(item => item.type === BILL_TYPE.EXPEND).reduce((sum, item) => sum + Number(item.money), 0)
			const totalIncome = list.filter(item => item.type === BILL_TYPE.INCOME).reduce((sum, item) => sum + Number(item.money), 0)
			list.forEach(item => {
				if (item.type === BILL_TYPE.EXPEND || item.type === BILL_TYPE.INCOME) {
					const amount = Number(item.money)
					const cate = item.cate
					if (!cateMap[cate]) {
						cateMap[cate] = {
							cate: cate,
							expend: 0,
							income: 0,
							expendRate: 0,
							incomeRate: 0,
							icon: this.getCateIcon(cate),
							color: this.getCateColor(cate)
						}
					}
					if (item.type === BILL_TYPE.EXPEND) cateMap[cate].expend += amount
					else cateMap[cate].income += amount
				}
			})
			Object.values(cateMap).forEach(item => {
				item.expendRate = totalExpend > 0 ? ((item.expend / totalExpend) * 100).toFixed(1) : 0
				item.incomeRate = totalIncome > 0 ? ((item.income / totalIncome) * 100).toFixed(1) : 0
			})
			this.cateStatList = Object.values(cateMap).sort((a, b) => {
				const totalA = a.expend + a.income
				const totalB = b.expend + b.income
				return totalB - totalA
			})
		},
		getCateIcon(cate) {
			const findItem = this.allCateList.find(item => item.value === cate)
			return findItem ? findItem.icon : '📦'
		},
		getCateColor(cate) {
			const findItem = this.allCateList.find(item => item.value === cate)
			return findItem ? findItem.color : '#84b3d9'
		},
		openAddModal() {
			this.isEdit = false
			this.currentEditId = ''
			const now = new Date()
			const today = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`
			this.form = { type: BILL_TYPE.EXPEND, money: '', cate: '', channel: 'wechat', note: '', date: today }
			this.formattedMoney = ''
			this.moneyInputError = ''
			this.showAdd = true
			this.showAiSuggestion = false
			this.aiSuggestionText = ''
			this.aiSuggestionData = null
		},
		handleEditBill(item) {
			this.isEdit = true
			this.currentEditId = item.id
			this.form = {
				type: item.type,
				money: item.money.toString(),
				cate: item.cate,
				channel: item.channel || 'wechat',
				note: item.note || '',
				date: item.date
			}
			this.formatMoneyOnBlur()
			this.showAdd = true
			this.showAiSuggestion = false
			this.aiSuggestionText = ''
			this.aiSuggestionData = null
		},
		handleDeleteBill(id) {
			this.pendingDeleteId = id
			this.deleteConfirmMessage = '确定要删除这条账单吗？删除后不可恢复。'
			this.showDeleteConfirm = true
		},
		async confirmDeleteBill() {
			try {
				await deleteBill({ id: this.pendingDeleteId })
				uni.showToast({ title: '删除成功' })
				this.showDeleteConfirm = false
				this.pendingDeleteId = null
				this.getList()
			} catch (e) {
				console.error('删除账单失败：', e)
				uni.showToast({ title: '删除失败', icon: 'none' })
			}
		},
		batchEdit() {
			uni.showToast({ title: '批量编辑功能开发中', icon: 'none' })
		},
		batchDelete() {
			if (this.selectedBillIds.length === 0) {
				uni.showToast({ title: '请先选择账单', icon: 'none' })
				return
			}
			this.showBatchDeleteConfirm = true
		},
		async confirmBatchDelete() {
			try {
				const promises = this.selectedBillIds.map(id => deleteBill({ id }))
				await Promise.all(promises)
				uni.showToast({ title: '批量删除成功' })
				this.showBatchDeleteConfirm = false
				this.selectedBillIds = []
				this.isBatchMode = false
				this.getList()
			} catch (e) {
				console.error('批量删除失败：', e)
				uni.showToast({ title: '批量删除失败', icon: 'none' })
			}
		},
		handleSheetClose() {
			this.showAdd = false
		},
		closeModal() {
			this.showAdd = false
			const now = new Date()
			const today = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`
			this.form = { type: BILL_TYPE.EXPEND, money: '', cate: '', channel: 'wechat', note: '', date: today }
			this.formattedMoney = ''
			this.moneyInputError = ''
			this.showAiSuggestion = false
			this.aiSuggestionText = ''
			this.aiSuggestionData = null
		},
		async submitBill() {
			if (!checkLogin()) return
			this.formatMoneyOnBlur()
			if ((!this.form.money || Number(this.form.money) <= 0) || !this.form.cate) {
				return uni.showToast({ title: '请填写有效的金额和分类', icon: 'none' })
			}
			this.submitting = true
			try {
				const billData = {
					...this.form,
					money: parseFloat(this.form.money) || 0,
					from_account: '',
					to_account: ''
				}
				if (this.isEdit) {
					await editBill({ id: this.currentEditId, ...billData })
					uni.showToast({ title: '修改成功' })
				} else {
					const res = await addBill(billData)
					uni.showToast({ title: '账单成功' })
					if (res && res.growth) {
						this.showGrowthModal(res.growth)
					}
				}
				this.closeModal()
				this.getList()
			} catch (e) {
				console.error('提交账单失败：', e)
				uni.showToast({ title: this.isEdit ? '修改失败' : '账单失败', icon: 'none' })
			} finally {
				this.submitting = false
			}
		},
		async classifyBill(content) {
			try {
				const res = await classifyBillApi({ content })
				if (res && res.type === 'bill' && res.data) {
					this.aiSuggestionData = res.data
					const parts = []
					if (res.data.cate) parts.push(`分类：${getCateLabel(res.data.cate)}`)
					if (res.data.type) parts.push(`类型：${res.data.type === 1 ? '支出' : '收入'}`)
					if (res.data.channel) parts.push(`渠道：${getChannelLabel(res.data.channel)}`)
					this.aiSuggestionText = parts.join(' · ')
					this.showAiSuggestion = true
				}
			} catch (e) {
				console.log('AI分类未返回有效结果，跳过建议')
			}
		},
		applyAiSuggestion() {
			if (!this.aiSuggestionData) return
			const data = this.aiSuggestionData
			if (data.cate) this.form.cate = data.cate
			if (data.type) this.form.type = data.type
			if (data.channel) this.form.channel = data.channel
			this.showAiSuggestion = false
			this.aiSuggestionData = null
			uni.showToast({ title: '已应用AI建议', icon: 'success' })
		},
		addCustomCate() {
			if (!this.customCateName.trim()) {
				return uni.showToast({ title: '请输入分类名称', icon: 'none' })
			}
			const isExist = this.allCateList.some(item => item.value === this.customCateName)
			if (isExist) {
				return uni.showToast({ title: '分类已存在', icon: 'none' })
			}
			const newCate = {
				value: this.customCateName,
				label: this.customCateName,
				icon: this.customCateIcon || '📦',
				color: this.selectedColor,
				type: this.form.type
			}
			this.allCateList.push(newCate)
			this.form.cate = this.customCateName
			this.customCateName = ''
			this.customCateIcon = ''
			this.showCustomCate = false
			uni.showToast({ title: '分类添加成功' })
		},
		selectCate(cate) {
			this.form.cate = cate.value
			let recent = [...this.recentCateList]
			recent = recent.filter(item => item.value !== cate.value)
			recent.unshift(cate)
			this.recentCateList = recent.slice(0, RECENT_CATE_MAX_COUNT)
			uni.setStorageSync('recentCateList', this.recentCateList)
		},
		handleMoneyInput(e) {
			const value = e.detail.value
			this.validateMoneyInput(value, 'form.money')
		},
		validateMoneyInput(value, target) {
			this.moneyInputError = ''
			let cleanValue = value === null || value === undefined ? '' : String(value)
			cleanValue = cleanValue.replace(/[^\d.]/g, '')
			if (cleanValue.indexOf('.') !== -1) {
				const parts = cleanValue.split('.')
				if (parts.length > 2) {
					this.moneyInputError = '请输入有效金额，最多两位小数'
					cleanValue = parts[0] + '.' + parts[1].substring(0, 2)
				} else if (parts[1] && parts[1].length > 2) {
					this.moneyInputError = '请输入有效金额，最多两位小数'
					cleanValue = parts[0] + '.' + parts[1].substring(0, 2)
				}
			}
			if (target === 'form.money') {
				this.form.money = cleanValue
				this.formattedMoney = cleanValue
			} else if (target === 'tempBudget') {
				this.tempBudget = cleanValue
			}
		},
		formatMoneyOnBlur() {
			if (!this.form.money) {
				this.formattedMoney = ''
				return
			}
			let num = String(this.form.money).replace(/[^\d.]/g, '')
			if (num === '.') num = '0.00'
			else if (num.indexOf('.') === -1) num = `${num}.00`
			else {
				const parts = num.split('.')
				parts[1] = parts[1].padEnd(2, '0').substring(0, 2)
				num = `${parts[0]}.${parts[1]}`
			}
			this.formattedMoney = num
			this.form.money = num
		},
		fillQuickMoney(amount) {
			this.form.money = amount.toString()
			this.formattedMoney = `${amount}.00`
			this.moneyInputError = ''
		},
		filterByCate(cate) {
			this.filterCate = this.filterCate === cate ? '' : cate
			uni.showToast({
				title: this.filterCate ? `已筛选${cate}账单` : '已取消分类筛选',
				icon: 'none'
			})
			const index = this.cateStatList.findIndex(item => item.cate === cate)
			if (index !== -1) {
				this.currentCateIndex = index
			}
			this.page = 1
			this.hasMore = true
			this.$nextTick(() => {
				this.loadFirstPage()
			})
		},
		onCateScroll(e) {
			const scrollLeft = e.detail.scrollLeft
			const itemWidth = 216
			this.currentCateIndex = Math.round(scrollLeft / itemWidth)
		},
		handleScroll(e) {
			const { scrollTop, scrollHeight, windowHeight } = e.detail
			this.showScrollTip = scrollTop + windowHeight < scrollHeight - 100
		},
		handleAddBtnClick() {
			this.addBtnScale = 'scale(1.1)'
			setTimeout(() => {
				this.addBtnScale = 'scale(1)'
				this.openAddModal()
			}, 150)
		},
		getLastMonthFormat() {
			const now = new Date()
			const lastMonth = new Date(now.getFullYear(), now.getMonth() - 1, 1)
			const year = lastMonth.getFullYear()
			const month = String(lastMonth.getMonth() + 1).padStart(2, '0')
			return `${year}-${month}`
		},
		async getLastMonthBudgetData() {
			try {
				const lastMonth = this.getLastMonthFormat()
				const res = await getMonthBudget({ month: lastMonth })
				this.lastMonthBudget = res && res.amount ? Number(res.amount) : ''
				this.calcStatistics()
			} catch (e) {
				console.error('获取上月预算失败：', e)
				this.lastMonthBudget = ''
				uni.showToast({ title: '获取上月预算失败', icon: 'none' })
			}
		},
		handleLastMonthBudgetSetting() {
			this.tempBudget = this.lastMonthBudget ? this.lastMonthBudget.toString() : ''
			this.selectedBudgetMonth = this.getLastMonthFormat()
			this.showBudgetModal = true
		}
	}
}
</script>

<style lang="scss" scoped>
.bill-page {
	height: 100vh;
	position: relative;
	overflow: hidden;
	display: flex;
	flex-direction: column;
}

.sticky-header {
	flex-shrink: 0;
	z-index: 10;
	padding: 0 32rpx;
	padding-top: 12rpx;
	padding-bottom: 16rpx;
}

.main-scroll {
	flex: 1;
	height: 0;
}

.search-bar {
	display: flex;
	flex-direction: column;
	gap: 16rpx;
	margin-bottom: 20rpx;
}

.search-input {
	display: flex;
	align-items: center;
	border-radius: 12rpx;
	padding: 0 20rpx;
	height: 70rpx;
}

.search-input input {
	flex: 1;
	font-size: 24rpx;
}

.search-input .clear-icon {
	font-size: 24rpx;
	padding: 8rpx;
	border-radius: 50%;
	transition: all 0.2s ease;
}

.filter-section {
	display: flex;
	align-items: center;
	gap: 16rpx;
}

.filter-row-label {
	font-size: 24rpx;
	flex-shrink: 0;
	min-width: 60rpx;
}

.budget-card {
	margin-bottom: 20rpx;
}

.budget-title {
	display: flex;
	justify-content: space-between;
	align-items: center;
	margin-bottom: 16rpx;
}

.budget-title text {
	font-size: 20rpx;
	font-weight: 500;
}

.budget-value {
	font-weight: 600;
	font-size: 30rpx;
}

.budget-set-btn {
	font-size: 26rpx;
	padding: 8rpx 20rpx;
	border: 1rpx solid;
	border-radius: 10rpx;
	transition: all 0.2s ease;
}

.budget-empty {
	text-align: center;
	padding: 30rpx 0;
	font-size: 24rpx;
}

.progress-bar {
	height: 12rpx;
	border-radius: 6rpx;
	overflow: hidden;
	margin-bottom: 16rpx;
}

.progress-fill {
	height: 100%;
	border-radius: 6rpx;
	transition: width 0.3s ease;
}

.budget-info {
	display: flex;
	justify-content: space-between;
	align-items: center;
	font-size: 24rpx;
}

.budget-info text {
	flex: 1;
}

.budget-info text:nth-child(2) {
	text-align: center;
}

.budget-info text:last-child {
	text-align: right;
}

.stat-scroll {
	width: 100%;
}

.stat-row {
	display: flex;
	flex-wrap: nowrap;
	gap: 16rpx;
}

.stat-item {
	flex-shrink: 0;
	width: 200rpx;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 12rpx;
	padding: 28rpx 12rpx;
	border-radius: 18rpx;
	background: rgba(0, 0, 0, 0.03);
	box-sizing: border-box;
}

.stat-icon {
	width: 52rpx;
	height: 52rpx;
	border-radius: 14rpx;
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: 26rpx;
}

.expend-icon {
	background: rgba(239, 68, 68, 0.15);
}

.income-icon {
	background: rgba(34, 197, 94, 0.15);
}

.balance-icon {
	background: rgba(59, 130, 246, 0.15);
}

.month-icon {
	background: rgba(139, 92, 246, 0.15);
}

.stat-info {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 6rpx;
}

.stat-info .label {
	font-size: 22rpx;
}

.stat-info .value {
	font-size: 28rpx;
	font-weight: 700;
}

.cate-stat-section {
	padding: 0 32rpx;
	margin-bottom: 20rpx;
}

.cate-stat-single {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 16rpx;
}

.cate-stat-item-wide {
	display: flex;
	align-items: center;
	min-height: 140rpx;
	border-radius: 20rpx;
	padding: 20rpx 24rpx;
	box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
	transition: all 0.2s ease;
}

.cate-stat-item-wide:active {
	transform: scale(0.99);
}

.cate-left-wide {
	display: flex;
	flex-direction: column;
	align-items: center;
	margin-right: 20rpx;
	min-width: 80rpx;
}

.cate-icon-wide {
	width: 64rpx;
	height: 64rpx;
	line-height: 64rpx;
	border-radius: 20rpx;
	text-align: center;
	font-size: 32rpx;
	color: #fff;
}

.cate-name-wide {
	font-size: 28rpx;
	font-weight: 500;
	margin-top: 8rpx;
	text-align: center;
}

.cate-right-wide {
	flex: 1;
	display: flex;
	flex-direction: row;
	justify-content: space-between;
	align-items: center;
	flex-wrap: wrap;
	gap: 12rpx;
}

.cate-money-row-wide {
	display: flex;
	gap: 24rpx;
}

.cate-money {
	font-size: 24rpx;
	font-weight: bold;
}

.cate-rate-row-wide {
	padding-top: 10rpx;
	border-top: 1rpx solid #f0f5fa;
	margin-top: 6rpx;
	width: 100%;
}

.cate-rate {
	font-size: 22rpx;
}

.cate-stat-scroll-wrapper {
	margin-bottom: 20rpx;
}

.cate-stat-scroll {
	white-space: nowrap;
	padding: 8rpx 0;
}

.cate-stat-container-scroll {
	display: inline-flex;
	gap: 16rpx;
	padding: 0 20rpx;
}

.cate-stat-item-scroll {
	display: flex;
	flex-direction: column;
	align-items: center;
	width: 200rpx;
	min-height: 160rpx;
	border-radius: 20rpx;
	padding: 20rpx 16rpx;
	box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
	transition: all 0.2s ease;
	flex-shrink: 0;
}

.cate-icon-scroll {
	width: 56rpx;
	height: 56rpx;
	line-height: 56rpx;
	border-radius: 18rpx;
	text-align: center;
	font-size: 28rpx;
	color: #fff;
}

.cate-name-scroll {
	font-size: 26rpx;
	font-weight: 500;
	margin-top: 10rpx;
}

.cate-stat-row-scroll {
	margin-top: 6rpx;
}

.cate-stat-text {
	font-size: 22rpx;
	font-weight: 500;
}

.cate-rate-scroll {
	font-size: 20rpx;
}

.scroll-indicator {
	display: flex;
	justify-content: center;
	gap: 8rpx;
	margin-top: 12rpx;
}

.indicator-dot {
	width: 10rpx;
	height: 10rpx;
	border-radius: 50%;
	transition: all 0.2s ease;
}

.indicator-dot.active {
	width: 24rpx;
	border-radius: 10rpx;
}

.bill-list-container {
	width: 100%;
	margin-bottom: 160rpx;
}

.skeleton-container {
	padding: 16rpx;
	margin-top: 20rpx;
}

.skeleton-item {
	display: flex;
	align-items: center;
	height: 140rpx;
	margin: 12rpx 0;
	padding: 0 24rpx;
	border-radius: 20rpx;
	background: #f8f9fa;
}

.skeleton-icon {
	width: 56rpx;
	height: 56rpx;
	border-radius: 20rpx;
	background: #e8e8e8;
	margin-right: 20rpx;
}

.skeleton-text {
	flex: 1;
}

.skeleton-line {
	height: 30rpx;
	background: #e8e8e8;
	border-radius: 6rpx;
	margin-bottom: 8rpx;
	width: 60%;
}

.skeleton-line.short {
	width: 30%;
	height: 24rpx;
}

.skeleton-money {
	width: 120rpx;
	height: 36rpx;
	background: #e8e8e8;
	border-radius: 6rpx;
}

.bill-list-card {
	min-height: 500rpx;
	display: flex;
	flex-direction: column;
}

.bill-group {
	margin-bottom: 16rpx;
}

.bill-group-header {
	display: flex;
	justify-content: space-between;
	align-items: center;
	padding: 12rpx 8rpx;
	border-bottom: 1rpx solid #f0f5fa;
	margin-bottom: 8rpx;
}

.bill-group-date {
	font-size: 24rpx;
	font-weight: 500;
}

.bill-group-summary {
	font-size: 22rpx;
}

.bill-item-content {
	display: flex;
	justify-content: space-between;
	align-items: center;
	padding: 16rpx 24rpx;
	border-radius: 16rpx;
}

.bill-left {
	display: flex;
	align-items: center;
}

.bill-left .cate-icon {
	margin-right: 20rpx;
	width: 56rpx;
	height: 56rpx;
	line-height: 56rpx;
	border-radius: 16rpx;
	text-align: center;
	font-size: 28rpx;
	color: #fff;
}

.bill-text {
	display: flex;
	flex-direction: column;
}

.bill-text .cate-name {
	font-size: 30rpx;
	font-weight: bold;
	margin-bottom: 4rpx;
}

.bill-meta {
	display: flex;
	align-items: center;
	gap: 6rpx;
}

.bill-text .note {
	font-size: 22rpx;
}

.money {
	font-size: 34rpx;
	font-weight: bold;
	margin-left: 20rpx;
	padding: 4rpx 8rpx;
	border-radius: 8rpx;
}

.scroll-tip {
	text-align: center;
	font-size: 22rpx;
	padding: 16rpx 0;
}

.pagination-tip {
	text-align: center;
	font-size: 24rpx;
	padding: 20rpx 0;
	cursor: pointer;
}

.batch-bar {
	display: flex;
	justify-content: space-between;
	align-items: center;
	padding: 16rpx;
	margin-top: 16rpx;
	border-radius: 12rpx;
	background: rgba(0, 0, 0, 0.03);
}

.batch-actions {
	display: flex;
	gap: 16rpx;
}

.batch-btn {
	padding: 12rpx 24rpx;
	border-radius: 12rpx;
	color: #fff;
	font-size: 24rpx;
}

.header-actions {
	display: flex;
	gap: 16rpx;
}

.header-btn {
	width: 68rpx;
	height: 68rpx;
	border-radius: 14rpx;
	display: flex;
	align-items: center;
	justify-content: center;
	transition: all 0.25s ease;
	box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
}

.header-btn:active {
	transform: scale(0.93);
}

.batch-icon {
	font-size: 32rpx;
	font-weight: 600;
}

.float-buttons {
	position: fixed;
	bottom: calc(40rpx + constant(safe-area-inset-bottom));
	bottom: calc(40rpx + env(safe-area-inset-bottom));
	right: 30rpx;
	z-index: 9999;
}

.add-btn {
	width: 100rpx;
	height: 100rpx;
	border-radius: 50%;
	display: flex;
	align-items: center;
	justify-content: center;
	box-shadow: 0 6px 24rpx rgba(0, 0, 0, 0.15);
	position: relative;
}

.add-btn-icon {
	font-size: 48rpx;
	font-weight: 500;
	color: #fff;
}

.modal {
	position: fixed;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
	background: rgba(0, 0, 0, 0.45);
	display: flex;
	align-items: flex-end;
	justify-content: center;
	z-index: 10000;
}

.modal-center {
	align-items: center;
}

.modal-box {
	width: 100%;
	padding: 30rpx;
	padding-bottom: calc(30rpx + constant(safe-area-inset-bottom));
	padding-bottom: calc(30rpx + env(safe-area-inset-bottom));
	border-radius: 20rpx 20rpx 0 0;
}

.date-picker-box {
}

.modal-title {
	text-align: center;
	font-size: 34rpx;
	font-weight: bold;
	margin-bottom: 28rpx;
}

.form-field {
	display: flex;
	flex-direction: column;
	margin-bottom: 28rpx;
}

.field-label {
	font-size: 26rpx;
	font-weight: 500;
	margin-bottom: 12rpx;
}

.field-value {
	flex: 1;
}

.date-picker {
	padding: 20rpx;
	border: 1rpx solid;
	border-radius: 12rpx;
	font-size: 26rpx;
	box-sizing: border-box;
}

.input {
	border: 1rpx solid #f0f5fa;
	padding: 20rpx;
	border-radius: 12rpx;
	font-size: 26rpx;
}

.money-input {
	font-size: 34rpx;
	text-align: left;
}

.input-placeholder {
	color: #9AA4B2;
	font-size: 26rpx;
}

.btns {
	display: flex;
	justify-content: space-between;
	margin-top: 20rpx;
	gap: 16rpx;
}

.btns button {
	flex: 1;
	padding: 20rpx 30rpx;
	border-radius: 12rpx;
	font-size: 28rpx;
	transition: all 0.2s ease;
}

.cancel-btn {
	border: none;
}

.confirm-btn {
	border: none;
	color: #fff;
}

.confirm-btn::after {
	border: none;
}

.budget-modal-box {
	border-radius: 24rpx 24rpx 0 0;
}

.custom-cate-box {
	width: 85%;
	max-width: 650rpx;
	padding: 40rpx;
}

.color-select {
	margin-bottom: 20rpx;
}

.color-list {
	display: flex;
	flex-wrap: wrap;
	gap: 16rpx;
	margin-top: 8rpx;
}

.color-item {
	width: 40rpx;
	height: 40rpx;
	border-radius: 50%;
}

.color-item.active {
	border: 2rpx solid #2A3A4D;
}

.delete-confirm-text {
	font-size: 28rpx;
	line-height: 1.6;
	text-align: center;
}

.type-section {
	display: flex;
	gap: 12rpx;
	padding: 16rpx 0;
}

.type-btn {
	flex: 1;
	display: flex;
	flex-direction: row;
	align-items: center;
	justify-content: center;
	gap: 8rpx;
	padding: 14rpx 12rpx;
	border-radius: 12rpx;
	transition: all 0.25s ease;
	min-height: 64rpx;
}

.type-btn.active {
	transform: scale(1.02);
	box-shadow: 0 4rpx 12rpx rgba(132, 179, 217, 0.3);
}

.type-icon {
	font-size: 28rpx;
}

.type-text {
	font-size: 24rpx;
	font-weight: 500;
}

.amount-section {
	padding: 16rpx 0;
}

.amount-label {
	font-size: 26rpx;
	margin-bottom: 16rpx;
	display: block;
}

.amount-input-wrap {
	display: flex;
	align-items: flex-start;
	padding: 24rpx;
	background: rgba(132, 179, 217, 0.08);
	border-radius: 20rpx;
	margin-bottom: 16rpx;
}

.amount-symbol {
	font-size: 36rpx;
	font-weight: 600;
	line-height: 1.3;
	margin-right: 6rpx;
}

.amount-input {
	font-size: 44rpx;
	font-weight: 700;
	border: none;
	outline: none;
	background: transparent;
	flex: 1;
}

.quick-amounts {
	display: flex;
	flex-wrap: wrap;
	gap: 12rpx;
}

.quick-amount-btn {
	padding: 12rpx 24rpx;
	border-radius: 12rpx;
	font-size: 24rpx;
	transition: all 0.2s ease;
}

.quick-amount-btn:active {
	opacity: 0.8;
}

.section {
	padding: 16rpx 0;
}

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

.recent-cate-row {
	display: flex;
	align-items: center;
	gap: 16rpx;
	margin-bottom: 16rpx;
}

.recent-label {
	font-size: 24rpx;
	padding: 6rpx 16rpx;
	background: rgba(132, 179, 217, 0.1);
	border-radius: 12rpx;
}

.recent-cate-items {
	display: flex;
	gap: 12rpx;
	flex-wrap: wrap;
	flex: 1;
}

.recent-cate-item {
	display: flex;
	align-items: center;
	gap: 8rpx;
	padding: 8rpx 16rpx;
	background: rgba(132, 179, 217, 0.1);
	border-radius: 12rpx;
	transition: all 0.2s ease;
}

.recent-cate-item.active {
	background: #84b3d9;
}

.recent-cate-icon {
	font-size: 24rpx;
	width: 36rpx;
	height: 36rpx;
	border-radius: 50%;
	display: flex;
	align-items: center;
	justify-content: center;
}

.recent-cate-name {
	font-size: 22rpx;
}

.cate-grid-new {
	display: flex;
	flex-wrap: wrap;
	gap: 8rpx;
	justify-content: flex-start;
}

.cate-item-new {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 4rpx;
	width: 80rpx;
	padding: 8rpx 4rpx;
	border-radius: 10rpx;
	transition: all 0.2s ease;
}

.cate-item-new:active {
	transform: scale(0.95);
}

.cate-item-new.active {
	background: rgba(132, 179, 217, 0.12);
}

.cate-icon-wrap {
	width: 44rpx;
	height: 44rpx;
	border-radius: 50%;
	display: flex;
	align-items: center;
	justify-content: center;
}

.cate-icon {
	font-size: 22rpx;
}

.add-icon-wrap {
	border: 2rpx dashed #84b3d9;
	background: transparent;
}

.add-icon-wrap .cate-icon {
	color: #84b3d9;
	font-size: 26rpx;
	font-weight: 600;
}

.cate-label {
	font-size: 18rpx;
}

.channel-grid {
	display: flex;
	flex-wrap: wrap;
	gap: 10rpx;
}

.channel-btn {
	padding: 10rpx 22rpx;
	border-radius: 12rpx;
	font-size: 24rpx;
	border: 2rpx solid;
	transition: all 0.2s ease;
}

.channel-btn:active {
	transform: scale(0.95);
}

.note-input-wrap {
	margin-bottom: 10rpx;
}

.note-input {
	width: 100%;
	padding: 12rpx 16rpx;
	border-radius: 10rpx;
	font-size: 24rpx;
	box-sizing: border-box;
	min-height: 56rpx;
	line-height: 1.4;
}

.quick-tags {
	display: flex;
	flex-wrap: wrap;
	gap: 6rpx;
}

.quick-tag {
	padding: 6rpx 12rpx;
	border-radius: 12rpx;
	font-size: 18rpx;
}

.date-picker-wrap {
	display: flex;
	align-items: center;
	justify-content: space-between;
	padding: 24rpx;
	border-radius: 16rpx;
}

.date-text {
	font-size: 28rpx;
}

.modal-footer {
	display: flex;
	gap: 20rpx;
}

.btn-cancel {
	flex: 1;
	height: 84rpx;
	border-radius: 14rpx;
	border: 2rpx solid transparent;
	font-size: 28rpx;
	font-weight: 500;
	background: rgba(0, 0, 0, 0.04);
}

.btn-confirm {
	flex: 2;
	height: 84rpx;
	border-radius: 14rpx;
	border: none;
	color: #fff;
	font-size: 28rpx;
	font-weight: 600;
	transition: all 0.2s ease;
	box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.1);
}

.btn-confirm:active {
	transform: scale(0.98);
	opacity: 0.9;
}

.btn-confirm[disabled] {
	opacity: 0.5;
}

.ai-suggestion {
	display: flex;
	justify-content: space-between;
	align-items: center;
	padding: 20rpx;
	border: 2rpx dashed;
	border-radius: 12rpx;
}

.ai-suggestion-text {
	font-size: 26rpx;
	font-weight: 500;
}

.ai-suggestion-hint {
	font-size: 22rpx;
}

.theme-transition {
	transition: background-color 0.3s ease, color 0.3s ease,
	            border-color 0.3s ease, box-shadow 0.3s ease,
	            opacity 0.25s ease, transform 0.25s ease;
}

@keyframes pageFadeIn {
	0% { opacity: 0; transform: translateY(20rpx); }
	100% { opacity: 1; transform: translateY(0); }
}

@keyframes cardEnter {
	0% { opacity: 0; transform: translateY(16rpx); }
	100% { opacity: 1; transform: translateY(0); }
}

.content-fade {
	padding: 0 32rpx;
	transition: opacity 0.25s ease;
}
</style>