<template>
	<view class="content">
		<view class="navbox">
			<view class="status_bar"></view>
			<uni-nav-bar
				left-icon="left"
				title="患者列表"
				@clickLeft="goBack"
				color="#8B2316"
				:border="false"
				backgroundColor="#eee"
			>
				<template #right>
					<view class="nav-right">
						<uni-icons type="search" size="24" color="#8B2316" @click="searchPatients"></uni-icons>
						<uni-icons type="plusempty" size="24" color="#8B2316" @click="goCode" style="margin-left: 30rpx;"></uni-icons>
					</view>
				</template>
			</uni-nav-bar>
		</view>

		<view class="patient-list">
			<view class="listbox alertContent" v-if="showAlert">
				<image :src="delImg" class="del-img" mode="widthFix" @click="hideAlert"></image>
				<image :src="alertImg" class="alert-img" mode="widthFix"></image>
			</view>

			<view class="listbox patient-building" v-if="patientDataLoading && !loadFinish">
				<text class="patient-building-text">正在整理患者数据，请稍候...</text>
			</view>

			<view class="listbox" v-show="patientList.length > 0">
				<scroll-view
					class="groups-scroll"
					scroll-y="true"
					:scroll-into-view="scrollIntoViewId"
					:scroll-with-animation="true"
					@scroll="onGroupsScroll"
					@scrolltolower="onGroupsScrollToLower"
					:lower-threshold="120"
					v-show="loadFinish"
				>
					<view class="special-actions">
						<view class="action-item" @click="addNewPatient">
							<view class="action-icon new-patient">
								<up-image :src="newPatientImg" width="60rpx" height="60rpx"></up-image>
							</view>
							<text class="action-text">新的患者<text class="new-patient-count" v-if="applyList.length > 0">(待审核{{ applyList.length }}人)</text></text>
							<uni-icons type="right" size="20" color="#999"></uni-icons>
						</view>

						<view class="action-item" @click="managePatientGroups">
							<view class="action-icon group-icon">
								<view class="grid-icon">
									<view class="grid-item"></view>
									<view class="grid-item"></view>
									<view class="grid-item"></view>
									<view class="grid-item"></view>
								</view>
							</view>
							<text class="action-text">患者分组 <text class="new-patient-count" v-if="patientList.length > 0">(随访{{ patientListTotal }}人)</text></text>
							<uni-icons type="right" size="20" color="#999"></uni-icons>
						</view>
					</view>

					<view class="group-section" v-for="group in patientGroups" :key="group.letter" :id="`anchor-${group.letter}`">
						<view class="group-header">{{ group.letter }}</view>
						<view class="patient-item" v-for="item in group.items" :key="item.uuid || item.id" @longpress="onPatientItemLongPress(item)" @click="goPatientDetail(item.uuid)">
							<image
								v-if="hasPatientAvatar(item)"
								class="patient-avatar"
								:src="getPatientAvatar(item)"
								mode="aspectFill"
								lazy-load="true"
								@error="handlePatientAvatarError(item)"
								@click.stop="goPatientDetail(item.uuid)"
							></image>
							<view v-else class="patient-avatar avatar-placeholder"></view>
							<view class="patient-info">
								<text class="patient-name">{{ item.nickname || item.realName }}</text>
							</view>
							<view class="patient-status">
								<view class="edit-icon" @click.stop="editPatient(item.uuid)">
									<view class="edit-pen"></view>
								</view>
								<text class="follow-date">随访于{{ item.joinDateYMD }}</text>
							</view>
						</view>
					</view>
					<view class="load-more" v-if="patientListLoadingMore">
						<text class="load-more-text">加载中...</text>
					</view>
					<view class="load-more" v-else-if="!patientListHasMore && patientList.length > 0">
						<text class="load-more-text">没有更多了</text>
					</view>
				</scroll-view>

				<view class="letter-index" v-if="loadFinish && indexList.length > 0">
					<view class="letter-item" v-for="letter in indexList" :key="letter" :class="{ active: activeLetter === letter }" @click="onLetterTap(letter)">
						{{ letter }}
					</view>
				</view>
			</view>

			<view class="listbox" v-show="patientList.length === 0 && !patientDataLoading">
				<view class="special-actions">
					<view class="action-item" @click="addNewPatient">
						<view class="action-icon new-patient">
							<up-image :src="newPatientImg" width="60rpx" height="60rpx"></up-image>
						</view>
						<text class="action-text">新的患者<text class="new-patient-count" v-if="applyList.length > 0">(待审核{{ applyList.length }}人)</text></text>
						<uni-icons type="right" size="20" color="#999"></uni-icons>
					</view>
					<view class="action-item" @click="managePatientGroups">
						<view class="action-icon group-icon">
							<view class="grid-icon">
								<view class="grid-item"></view>
								<view class="grid-item"></view>
								<view class="grid-item"></view>
								<view class="grid-item"></view>
							</view>
						</view>
						<text class="action-text">患者分组</text>
						<uni-icons type="right" size="20" color="#999"></uni-icons>
					</view>
				</view>
				<empty></empty>
			</view>
		</view>

		<view class="tab-bar">
			<view class="tab-item" @click="goMessageTab">
				<text class="tab-text">患者消息</text>
			</view>
			<view class="tab-item active">
				<text class="tab-text">患者列表</text>
				<view class="tab-dot" v-if="hasNewPatient"><uni-badge class="uni-badge-left-margin" :text="applyList.length" :offset="[-3, -3]" size="small"></uni-badge></view>
			</view>
			<view class="tab-item" @click="goPlanTab">
				<text class="tab-text">随访计划</text>
			</view>
		</view>
	</view>
	<unidialog :visible="visible" :content="message" @close="visible=false" @confirm="deleteFollowUpFromList"></unidialog>
</template>

<script setup>
import { computed, nextTick, ref, shallowRef } from 'vue';
import { onBackPress, onLoad, onShow } from '@dcloudio/uni-app';
import dayjs from 'dayjs';
import pinyin from 'pinyin';
import api from '@/api/api.js';
import navTo from '@/utils/navTo.js';
import docUrl from '@/utils/docUrl.js';
import unidialog from '@/components/dialog/dialog.vue';
import newPatientImg from '@/static/new_patient.png';
import delImg from '@/static/iv_delete.png';
import alertImg from '@/static/patientgif.png';

const patientList = ref([]);
const patientDataLoaded = ref(false);
const patientDataLoading = ref(false);
const loadFinish = ref(false);
const showAlert = ref(false);
const applyList = ref([]);
const visible = ref(false);
const message = ref('');
const selectedPatientUuid = ref('');
const selectedPatientName = ref('');

const firstLetterCache = new Map();
const LETTER_ORDER = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
const GROUP_BUILD_CHUNK_SIZE = 180;
const PERF_TRACE = true;
const SCROLL_LOG_MIN_INTERVAL = 180;

const activeLetter = ref('');
const scrollIntoViewId = ref('');
const groupScrollRanges = ref([]);
const indexList = ref([]);
const avatarErrorMap = ref({});
const patientGroups = shallowRef([]);
const allPatientGroups = shallowRef([]);
const lastScrollTop = ref(0);
const lastScrollLogAt = ref(0);
const buildStartedAt = ref(0);
const fetchStartedAt = ref(0);
const patientListPage = ref(1);
const patientListPageSize = ref(300);
const patientListHasMore = ref(true);
const patientListLoadingMore = ref(false);
const canTriggerLowerLoad = ref(true);
const lastLowerTriggerTop = ref(0);
const LOWER_RESET_DISTANCE = 120;
const patientListTotal = ref(0);

const hasNewPatient = computed(() => applyList.value.length > 0);
const perfLog = (...args) => {
	if (!PERF_TRACE) return;
	console.log('[patientList/perf]', ...args);
};

const sortLetter = (a, b) => {
	if (a === '#') return 1;
	if (b === '#') return -1;
	const ai = LETTER_ORDER.indexOf(a);
	const bi = LETTER_ORDER.indexOf(b);
	if (ai === -1 && bi === -1) return String(a).localeCompare(String(b));
	if (ai === -1) return 1;
	if (bi === -1) return -1;
	return ai - bi;
};
const formatYMD = (input) => {
	if (!input) return '';
	const d = dayjs(input);
	return d.isValid() ? d.format('YYYY-MM-DD') : '';
};
const getFirstLetter = (name = '') => {
	const firstChar = String(name).trim().charAt(0);
	if (!firstChar) return '#';
	if (/^[A-Za-z]$/.test(firstChar)) return firstChar.toUpperCase();
	if (firstLetterCache.has(firstChar)) return firstLetterCache.get(firstChar);
	try {
		const py = pinyin(firstChar, { style: pinyin.STYLE_NORMAL })?.[0]?.[0] || '';
		const letter = py ? py.charAt(0).toUpperCase() : '#';
		firstLetterCache.set(firstChar, letter);
		return letter;
	} catch (error) {
		return '#';
	}
};

const getAvatarKey = (item = {}) => String(item.uuid || item.id || item.realName || item.nickname || '');
const normalizeAvatarUrl = (photo) => {
	const raw = String(photo || '').trim();
	if (!raw) return '';
	if (/^https?:\/\//i.test(raw)) return raw;
	return `${docUrl}${raw}`;
};
const hasPatientAvatar = (item = {}) => {
	const key = getAvatarKey(item);
	if (!item.avatarUrl) return false;
	if (key && avatarErrorMap.value[key]) return false;
	return true;
};
const getPatientAvatar = (item = {}) => {
	return item.avatarUrl || '';
};
const handlePatientAvatarError = (item) => {
	if (!item) return;
	const key = getAvatarKey(item);
	if (!key) return;
	avatarErrorMap.value = { ...avatarErrorMap.value, [key]: true };
};

const rebuildIndexList = () => {
	indexList.value = allPatientGroups.value
		.map(g => String(g?.letter || '').toUpperCase())
		.filter((letter, index, arr) => (letter === '#' || /^[A-Z]$/.test(letter)) && arr.indexOf(letter) === index)
		.sort(sortLetter);
	activeLetter.value = indexList.value[0] || '';
};
const rpxToPx = (rpx) => {
	const { screenWidth } = uni.getSystemInfoSync();
	return Math.round((screenWidth / 750) * rpx);
};
const buildGroupScrollRanges = () => {
	const actionHeight = rpxToPx(120);
	const headerHeight = rpxToPx(80);
	const itemHeight = rpxToPx(150);
	let cursor = actionHeight * 2;
	groupScrollRanges.value = patientGroups.value.map(group => {
		const groupHeight = headerHeight + (group.items?.length || 0) * itemHeight;
		const range = { letter: group.letter, start: cursor, end: cursor + groupHeight };
		cursor += groupHeight;
		return range;
	});
};
const onGroupsScroll = (e) => {
	const top = Number(e?.detail?.scrollTop || 0);
	if (!canTriggerLowerLoad.value && top < lastLowerTriggerTop.value - LOWER_RESET_DISTANCE) {
		canTriggerLowerLoad.value = true;
	}
	if (!groupScrollRanges.value.length) return;
	let current = groupScrollRanges.value[0].letter;
	for (let i = 0; i < groupScrollRanges.value.length; i++) {
		const range = groupScrollRanges.value[i];
		if (top >= range.start) {
			current = range.letter;
		} else {
			break;
		}
	}
	activeLetter.value = current;
	const now = Date.now();
	if (now - lastScrollLogAt.value >= SCROLL_LOG_MIN_INTERVAL) {
		perfLog('scroll', {
			top,
			deltaTop: top - lastScrollTop.value,
			activeLetter: current,
			groupCount: patientGroups.value.length,
			patientCount: patientList.value.length
		});
		lastScrollLogAt.value = now;
		lastScrollTop.value = top;
	}
};
const onLetterTap = (letter) => {
	if (!letter) return;
	activeLetter.value = letter;
	const targetId = `anchor-${letter}`;
	if (scrollIntoViewId.value === targetId) {
		scrollIntoViewId.value = '';
		nextTick(() => {
			scrollIntoViewId.value = targetId;
		});
		return;
	}
	scrollIntoViewId.value = targetId;
};

const waitForNextFrame = () => new Promise(resolve => setTimeout(resolve, 0));
const buildGroupsFromPatients = async () => {
	buildStartedAt.value = Date.now();
	perfLog('build:start', { count: patientList.value.length });
	avatarErrorMap.value = {};
	const map = new Map();
	const source = patientList.value || [];
	for (let i = 0; i < source.length; i++) {
		const p = source[i] || {};
		const normalized = { ...p, avatarUrl: normalizeAvatarUrl(p.photo), joinDateYMD: formatYMD(p.join_date) };
		const first = getFirstLetter(normalized.nickname || normalized.realName);
		const letter = /^[A-Z]$/.test(first) ? first : '#';
		if (!map.has(letter)) map.set(letter, []);
		map.get(letter).push(normalized);
		if (i > 0 && i % GROUP_BUILD_CHUNK_SIZE === 0) {
			await waitForNextFrame();
		}
	}
	const letters = Array.from(map.keys()).sort(sortLetter);
	allPatientGroups.value = letters.map(l => ({ letter: l, items: map.get(l) }));
	patientGroups.value = allPatientGroups.value;
	rebuildIndexList();
	buildGroupScrollRanges();
	perfLog('build:done', {
		costMs: Date.now() - buildStartedAt.value,
		groupCount: patientGroups.value.length,
		patientCount: patientList.value.length
	});
};

const getApplyList = async () => {
	try {
		const res = await api.applyList();
		if (res && res.code === 200) applyList.value = res.data || [];
	} catch (error) {}
};
const isApiSuccess = (res) => Number(res?.code) === 1 || Number(res?.code) === 200;
const parsePagedPatients = (res) => {
	const data = res?.data;
	if (Array.isArray(data)) {
		return { list: data, total: undefined, pageNum: undefined, pages: undefined, isLastPage: undefined };
	}
	const list =
		(Array.isArray(data?.list) && data.list) ||
		(Array.isArray(data?.records) && data.records) ||
		(Array.isArray(data?.rows) && data.rows) ||
		(Array.isArray(data?.data) && data.data) ||
		[];
	const total = Number(
		data?.total ??
		data?.count ??
		data?.totalCount ??
		undefined
	);
	const pageNum = Number(data?.pageNum ?? data?.page ?? data?.current ?? undefined);
	const pages = Number(data?.pages ?? data?.pageCount ?? undefined);
	const isLastPage =
		typeof data?.isLastPage === 'boolean'
			? data.isLastPage
			: undefined;
	return {
		list,
		total: Number.isFinite(total) ? total : undefined
		,
		pageNum: Number.isFinite(pageNum) ? pageNum : undefined,
		pages: Number.isFinite(pages) ? pages : undefined,
		isLastPage
	};
};
const mergePatientListUnique = (base = [], incoming = []) => {
	if (!incoming.length) return base;
	const seen = new Set();
	const merged = [];
	const pushUnique = (item) => {
		const key = String(item?.uuid || item?.id || item?.mobile || '');
		if (!key) {
			merged.push(item);
			return;
		}
		if (seen.has(key)) return;
		seen.add(key);
		merged.push(item);
	};
	for (let i = 0; i < base.length; i++) pushUnique(base[i]);
	for (let i = 0; i < incoming.length; i++) pushUnique(incoming[i]);
	return merged;
};
const applyPatientListData = async (list, total) => {
	patientList.value = list || [];
	patientListTotal.value = total || 0;
	await buildGroupsFromPatients();
	loadFinish.value = true;
	patientDataLoaded.value = true;
	if (patientListTotal.value > 1000) {
		const hasAlert = uni.getStorageSync('hasAlert');
		showAlert.value = !hasAlert;
	}
};
const patientListByGBKPage = async ({ showLoading = true, reset = false } = {}) => {
	if (patientDataLoading.value || patientListLoadingMore.value) return;
	if (!reset && !patientListHasMore.value) return;
	if (reset) {
		patientDataLoading.value = true;
		loadFinish.value = false;
		patientListPage.value = 1;
		patientListHasMore.value = true;
		canTriggerLowerLoad.value = true;
		lastLowerTriggerTop.value = 0;
	} else {
		patientListLoadingMore.value = true;
	}
	fetchStartedAt.value = Date.now();
	perfLog('api:start', { showLoading, reset, page: patientListPage.value, pageSize: patientListPageSize.value });
	if (showLoading) uni.showLoading({ title: '加载中...', mask: true });
	try {
		const requestPage = patientListPage.value;
		const res = await api.patientListByGBKPage({
			page: requestPage,
			pageSize: patientListPageSize.value,
		});
		if (isApiSuccess(res)) {
			const { list, total, pageNum, pages, isLastPage } = parsePagedPatients(res);
			const merged = reset ? list : mergePatientListUnique(patientList.value, list);
			await applyPatientListData(merged, total);
			if (typeof isLastPage === 'boolean') {
				patientListHasMore.value = !isLastPage;
			} else if (typeof pages === 'number' && typeof pageNum === 'number') {
				patientListHasMore.value = pageNum < pages;
			} else if (typeof total === 'number') {
				patientListHasMore.value = merged.length < total;
			} else {
				patientListHasMore.value = list.length >= patientListPageSize.value;
			}
			if (patientListHasMore.value) {
				if (typeof pageNum === 'number') {
					patientListPage.value = pageNum + 1;
				} else {
					patientListPage.value = requestPage + 1;
				}
			}
			perfLog('api:done', {
				totalMs: Date.now() - fetchStartedAt.value,
				requestPage,
				page: typeof pageNum === 'number' ? pageNum : (reset ? 1 : patientListPage.value - 1),
				pageDataCount: list.length,
				mergedCount: merged.length,
				hasMore: patientListHasMore.value
			});
		} else {
			perfLog('api:bad-code', { code: res.code });
		}
	} catch (error) {
		perfLog('api:error', error?.message || error);
		throw error;
	} finally {
		patientDataLoading.value = false;
		patientListLoadingMore.value = false;
		if (showLoading) uni.hideLoading();
	}
};
const onGroupsScrollToLower = () => {
	
	void patientListByGBKPage({ showLoading: false, reset: false });
};

const goPatientDetail = (uuid) => {
	navTo({ url: `/pages_app/patientDetail/patientDetail?uuid=${uuid}` });
};
const editPatient = (uuid) => {
	navTo({ url: `/pages_app/patientSetting/patientSetting?uuid=${uuid}` });
};
const searchPatients = () => {
	navTo({ url: '/pages_app/searchPatient/searchPatient' });
};
const addNewPatient = () => {
	navTo({ url: '/pages_app/myPatient/myPatient?from=patientMsg' });
};
const managePatientGroups = () => {
	navTo({ url: '/pages_app/patientGroup/patientGroup?from=patientMsg' });
};
const goCode = () => {
	navTo({ url: '/pages_app/myCode/myCode' });
};
const hideAlert = () => {
	showAlert.value = false;
	uni.setStorageSync('hasAlert', true);
};
const onPatientItemLongPress = (item) => {
	if (!item?.uuid) return;
	selectedPatientUuid.value = item.uuid;
	selectedPatientName.value = item.nickname || item.realName;
	message.value = `确认解除[${selectedPatientName.value || '该患者'}]的随访关系？`;
	visible.value = true;
};
const deleteFollowUpFromList = async () => {
	if (!selectedPatientUuid.value) {
		visible.value = false;
		return;
	}
	const res = await api.cancelRes({ patientUuid: selectedPatientUuid.value });
	if (isApiSuccess(res)) {
		uni.showToast({ title: '解除成功', icon: 'none' });
		await patientListByGBKPage({ showLoading: true, reset: true });
	}
	visible.value = false;
};

const goBack = () => {
	plus.runtime.quit();
};
const goMessageTab = () => {
	navTo({ url: '/pages_app/patientMsg/patientMsg' });
};
const goPlanTab = () => {
	navTo({ url: '/pages_app/patientMsg/patientPlan' });
};

onBackPress(() => {
	plus.runtime.quit();
	return true;
});
onLoad(async () => {
	perfLog('lifecycle:onLoad');
	getApplyList();
	void patientListByGBKPage({ showLoading: true, reset: true });
});
onShow(async () => {
	perfLog('lifecycle:onShow', { patientDataLoaded: patientDataLoaded.value });
	getApplyList();
	if (!patientDataLoaded.value) {
		void patientListByGBKPage({ showLoading: true, reset: true });
	}
});
</script>

<style lang="scss" scoped>
.content {
	background-color: #f5f5f5;
	height: 100vh;
	overflow-y: hidden;
}
.nav-right {
	display: flex;
	align-items: center;
}
.tab-bar {
	position: fixed;
	bottom: 0;
	left: 0;
	right: 0;
	height: 100rpx;
	background-color: #f8f8f8;
	display: flex;
	align-items: center;
	border-top: 1rpx solid #e0e0e0;
	z-index: 999;
}
.tab-item {
	flex: 1;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	position: relative;
	height: 100%;
}
.tab-item:nth-child(2) {
	border: 2rpx solid #ccc;
	border-top: none;
	border-bottom: none;
}
.tab-item .tab-text {
	font-size: 32rpx;
	color: #999;
}
.tab-item.active .tab-text {
	color: #8B2316;
	font-weight: 500;
}
.tab-dot {
	position: absolute;
	top: 18rpx;
	right: 28rpx;
}
.patient-list {
	width: 100%;
	margin-top: calc(var(--status-bar-height) + 44px);
	height: calc(100vh - var(--status-bar-height) - 44px - 103rpx);
	overflow: hidden;
	background-color: #fff;
	display: flex;
	flex-direction: column;
}
.listbox {
	flex: 1;
	min-height: 0;
}
.patient-building {
	display: flex;
	align-items: center;
	justify-content: center;
}
.patient-building-text {
	font-size: 28rpx;
	color: #999;
}
.groups-scroll {
	height: 100%;
}
.load-more {
	display: flex;
	align-items: center;
	justify-content: center;
	height: 80rpx;
}
.load-more-text {
	font-size: 24rpx;
	color: #999;
}
.special-actions {
	background-color: #fff;
	border-bottom: 1rpx solid #f0f0f0;
}
.action-item {
	display: flex;
	align-items: center;
	padding: 30rpx;
	border-bottom: 1rpx solid #f0f0f0;
}
.action-icon {
	width: 60rpx;
	height: 60rpx;
	border-radius: 50%;
	display: flex;
	align-items: center;
	justify-content: center;
	margin-right: 20rpx;
}
.new-patient,
.group-icon {
	background-color: #8B2316;
}
.grid-icon {
	display: grid;
	grid-template-columns: 1fr 1fr;
	grid-template-rows: 1fr 1fr;
	gap: 2rpx;
	width: 32rpx;
	height: 32rpx;
}
.grid-item {
	background-color: #fff;
	border-radius: 2rpx;
}
.action-text {
	flex: 1;
	font-size: 32rpx;
	color: #333;
}
.new-patient-count {
	color: red;
	font-size: 32rpx;
	margin-left: 10rpx;
}
.group-header {
	padding: 20rpx 30rpx;
	background-color: #e4e4e4;
	font-size: 36rpx;
	color: #666;
}
.patient-item {
	display: flex;
	align-items: center;
	padding: 30rpx 80rpx 20rpx 30rpx;
	border-bottom: 1rpx solid #f0f0f0;
	background-color: #fff;
}
.patient-avatar {
	width: 90rpx;
	height: 90rpx;
	border-radius: 10rpx;
	margin-right: 20rpx;
}
.avatar-placeholder {
	position: relative;
	background: #e0e0e0;
	border-radius: 50%;
}
.avatar-placeholder::before {
	content: '';
	position: absolute;
	width: 28rpx;
	height: 28rpx;
	border-radius: 50%;
	background: #ffffff;
	top: 16rpx;
	left: 31rpx;
}
.avatar-placeholder::after {
	content: '';
	position: absolute;
	width: 56rpx;
	height: 30rpx;
	border-radius: 28rpx 28rpx 12rpx 12rpx;
	background: #ffffff;
	left: 17rpx;
	bottom: 14rpx;
}
.patient-info {
	flex: 1;
}
.patient-name {
	font-size: 32rpx;
	color: #333;
	font-weight: 500;
}
.patient-status {
	display: flex;
	align-items: flex-end;
	flex-direction: column;
}
.edit-icon {
	width: 40rpx;
	height: 40rpx;
	display: flex;
	align-items: center;
	justify-content: center;
}
.edit-pen {
	position: relative;
	width: 24rpx;
	height: 6rpx;
	background: #8B2316;
	border-radius: 3rpx;
	transform: rotate(-35deg);
}
.edit-pen::before {
	content: '';
	position: absolute;
	left: -8rpx;
	top: 0;
	width: 0;
	height: 0;
	border-top: 3rpx solid transparent;
	border-bottom: 3rpx solid transparent;
	border-right: 8rpx solid #8B2316;
}
.edit-pen::after {
	content: '';
	position: absolute;
	right: -5rpx;
	top: 0;
	width: 5rpx;
	height: 6rpx;
	background: #d9d9d9;
	border-radius: 0 3rpx 3rpx 0;
}
.follow-date {
	margin-top: 8rpx;
	font-size: 24rpx;
	color: #666;
}
.letter-index {
	position: fixed;
	right: 10rpx;
	top: 50%;
	transform: translateY(-50%);
	background-color: rgba(255, 255, 255, 0.9);
	border-radius: 20rpx;
	padding: 10rpx 5rpx;
	z-index: 999;
}
.letter-item {
	padding: 8rpx 12rpx;
	font-size: 24rpx;
	color: #666;
	text-align: center;
	border-radius: 10rpx;
}
.letter-item.active {
	color: #8B2316;
	font-weight: 600;
}
.alertContent {
	z-index: 99;
	position: fixed;
	bottom: 100rpx;
	width: 100%;
	top: calc(var(--status-bar-height) + 44px);
	pointer-events: none;
}
.alert-img {
	width: 100%;
}
.del-img {
	position: absolute;
	top: 280rpx;
	z-index: 999;
	right: 100rpx;
	width: 48rpx;
	height: 48rpx;
	pointer-events: auto;
}
</style>
