<!-- pages/mall/consumer/chat.uvue -->
<template>
    <view class="chat-page">
        <!-- 聊天头部 -->
        <view class="chat-header" :style="{ paddingTop: navPaddingTop }">
            <view class="header-back" @click="goBack">
                <text class="back-icon">❮</text>
            </view>
            <view class="header-info">
                <view class="header-info-text-wrapper">
                    <text class="chat-title">{{ headerTitle }}</text>
                    <text class="chat-status">在线</text>
                </view>
            </view>
            <view class="header-actions">
                <view class="action-icon" @click="showMoreActions">
                    <text class="action-icon-text">⋯</text>
                </view>
            </view>
        </view>
        
        <!-- 聊天内容 -->
        <scroll-view 
            direction="vertical"
            class="chat-content"
            :scroll-into-view="scrollToView"
            :scroll-with-animation="true"
            :show-scrollbar="false"
            upper-threshold="100"
            @scrolltoupper="onScrollToUpper"
        >
            <!-- 聊天消息列表 -->
            <view class="chat-messages">
                <!-- 系统消息 -->
                <view class="message-item system">
                    <text class="system-text">客服 小美 已接入，请描述您的问题</text>
                </view>
                
                <!-- 时间分割线 -->
                <view class="time-divider">
                    <text class="time-text">今天 14:30</text>
                </view>
                
                <!-- 消息项 -->
                <view 
                    v-for="message in messages" 
                    :key="message.id"
                    :class="['message-item', message.type]"
                    :id="message.viewId"
                >
                    <!-- 对方消息 -->
                    <view v-if="message.type === 'received'" class="message-wrapper">
                        <image 
                            class="avatar" 
                            :src="merchantAvatar" 
                            mode="aspectFill"
                        />
                        <view class="message-content-wrapper">
                            <text class="sender-name">{{ headerTitle }}</text>
                            <view class="message-bubble received-bubble">
                                <!-- 图片消息 -->
                                <image 
                                    v-if="message.msgType == 'image'" 
                                    class="message-image" 
                                    :src="message.content" 
                                    mode="widthFix"
                                    @click="previewImage(message.content)"
                                />
                                <!-- 文本消息 -->
                                <text v-if="message.msgType != 'image'" class="message-text">{{ message.content }}</text>
                                <text class="message-time">{{ message.time }}</text>
                            </view>
                        </view>
                    </view>
                    
                    <!-- 我的消息 -->
                    <view v-else class="message-wrapper me">
                        <view class="message-content-wrapper">
                            <view class="message-bubble me">
                                <!-- 图片消息 -->
                                <image 
                                    v-if="message.msgType == 'image'" 
                                    class="message-image" 
                                    :src="message.content" 
                                    mode="widthFix"
                                    @click="previewImage(message.content)"
                                />
                                <!-- 文本消息 -->
                                <text v-if="message.msgType != 'image'" class="message-text">{{ message.content }}</text>
                                <text class="message-time">{{ message.time }}</text>
                            </view>
                        </view>
                        <image 
                            class="avatar me" 
                            src="/static/images/default.png" 
                            mode="aspectFill"
                        />
                    </view>
                </view>
            </view>
        </scroll-view>
        
        <!-- 聊天输入区 -->
        <view class="chat-input">
            <view class="input-tools">
                <text class="tool-icon" @click="showEmojiPicker">😊</text>
                <text class="tool-icon" @click="showImagePicker">📷</text>
                <text class="tool-icon" @click="showMoreTools">➕</text>
            </view>
            
            <view class="input-wrapper">
                <input 
                    class="message-input" 
                    v-model="inputMessage"
                    placeholder="请输入消息..."
                    :focus="inputFocus"
                    @confirm="sendMessage"
                    confirm-type="send"
                />
                <button 
                    class="send-button" 
                    :class="{ active: inputMessage.trim() }" 
                    @click="sendMessage"
                >
                    发送
                </button>
            </view>
        </view>
        
        <!-- 表情选择器 -->
        <scroll-view v-if="showEmoji" class="emoji-picker" direction="vertical">
            <view class="emoji-category">
                <text 
                    v-for="emoji in emojiList" 
                    :key="emoji"
                    class="emoji-item"
                    @click="insertEmoji(emoji)"
                >
                    {{ emoji }}
                </text>
            </view>
        </scroll-view>
    </view>
</template>

<script setup lang="uts">
import { ref, reactive, onMounted, onUnmounted, nextTick } from 'vue'
import { supabaseService, type ChatMessage } from '@/utils/supabaseService.uts'
import supa from '@/components/supadb/aksupainstance.uts'
import type { AkSupaRealtimeChannel } from '@/components/supadb/aksupa.uts'
import { getCurrentUser } from '@/utils/store.uts'

type UiChatMessage = {
	id: string
	viewId: string
	type: string
	content: string
	time: string
	msgType: string // 'text' | 'image'
}

// 响应式数据
const messages = ref<UiChatMessage[]>([])
const inputMessage = ref<string>('')
const inputFocus = ref<boolean>(false)
const showEmoji = ref<boolean>(false)
const scrollToView = ref<string>('')
const currentUserId = ref<string>('')
const merchantId = ref<string>('') // 商家ID
const headerTitle = ref<string>('在线客服')
const merchantAvatar = ref<string>('/static/images/default.png') // 商家头像
const navPaddingTop = ref<string>('30px') // 默认值，包含状态栏高度+原有内边距
const isInitialLoading = ref<boolean>(true)
let realtimeChannel: AkSupaRealtimeChannel | null = null

// 模拟表情列表
const emojiList = ['😊', '😂', '🤣', '😍', '😘', '🥰', '😭', '😡', '👍', '👏', '🙏', '🎉', '❤️', '🔥', '⭐']

function scrollToBottom() : void {
    if (messages.value.length === 0) return

    // 获取最后一条消息的 ID
    const lastMsg = messages.value[messages.value.length - 1]
    const targetId = lastMsg.viewId

    // 关键点：在 UVue 安卓端，直接连续赋值可能被合并。
    // 我们先清空 ID，然后在下一帧赋值，确保 scroll-view 监听到变化。
    scrollToView.value = ''

    // 延迟更久一点，确保安卓端列表排版彻底完成
    setTimeout(() => {
        scrollToView.value = targetId
        console.log('[scrollToBottom] 发起滚动定位:', targetId)
        
        // 分级校准：针对长消息或渲染抖动导致的高度变化
        setTimeout(() => {
            scrollToView.value = ''
            setTimeout(() => {
                scrollToView.value = targetId
                console.log('[scrollToBottom] 第一阶段校准:', targetId)
            }, 50)
        }, 500)

        // 最终深度校准（针对首屏数据较多时）
        setTimeout(() => {
            scrollToView.value = ''
            setTimeout(() => {
                scrollToView.value = targetId
                console.log('[scrollToBottom] 最终校准:', targetId)
            }, 50)
        }, 1200)
    }, 300)
}

function getCurrentTime(): string {
    const now = new Date()
    const hours = now.getHours().toString().padStart(2, '0')
    const minutes = now.getMinutes().toString().padStart(2, '0')
    return `${hours}:${minutes}`
}

function setupRealtimeSubscription(): void {
	console.log('开始建立聊天实时订阅...')
	console.log('当前用户ID:', currentUserId.value, '商家ID:', merchantId.value)
	
	realtimeChannel = supa.channel('chat-messages-' + Date.now().toString())
		.on('postgres_changes', {
			event: 'INSERT',
			schema: 'public',
			table: 'ml_chat_messages'
		}, (payload: any) => {
			console.log('=== 收到实时订阅回调 ===')
			const payloadObj = (payload instanceof UTSJSONObject) ? (payload as UTSJSONObject) : (JSON.parse(JSON.stringify(payload ?? {})) as UTSJSONObject)
			const newMsgAny = payloadObj.get('new')
			if (newMsgAny == null) {
				console.log('newMsgAny 为空，跳过')
				return
			}
			const newMsg = (newMsgAny instanceof UTSJSONObject) ? (newMsgAny as UTSJSONObject) : (JSON.parse(JSON.stringify(newMsgAny)) as UTSJSONObject)
			console.log('收到新消息:', newMsg)

			const senderId = newMsg.getString('sender_id') ?? ''
			const receiverId = newMsg.getString('receiver_id') ?? ''
			const msgId = newMsg.getString('id') ?? ''
			const content = newMsg.getString('content') ?? ''
			const msgType = newMsg.getString('msg_type') ?? 'text'
			
			console.log('=== 消息详情 ===')
			console.log('消息ID:', msgId)
			console.log('发送者ID:', senderId)
			console.log('接收者ID:', receiverId)
			console.log('当前用户ID:', currentUserId.value)
			console.log('商家ID:', merchantId.value)
			console.log('消息内容:', content)
			console.log('消息类型 msgType:', msgType)

			// 检查消息是否已经在列表中（避免重复）
			for (let i = 0; i < messages.value.length; i++) {
				if (messages.value[i].id == msgId) {
					console.log('消息已存在，跳过')
					return
				}
			}

			// 判断消息类型
			const isMyMessage = (senderId == currentUserId.value)
			const isForMe = (receiverId == currentUserId.value)
			const isRelatedToCurrentChat = (senderId == merchantId.value || receiverId == merchantId.value)
			
			console.log('=== 条件判断 ===')
			console.log('isMyMessage:', isMyMessage)
			console.log('isForMe:', isForMe)
			console.log('isRelatedToCurrentChat:', isRelatedToCurrentChat)

			// 如果消息与当前聊天无关，跳过
			if (!isRelatedToCurrentChat) {
				console.log('消息与当前聊天无关，跳过')
				return
			}

			// 如果是自己发送的消息，或者是发给自己的消息，都显示
			if (isMyMessage || isForMe) {
				const createdAt = newMsg.getString('created_at') ?? new Date().toISOString()
				const date = new Date(createdAt)
				const timeStr = `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`

				// 生成安全的 viewId
				const safeViewId = 'msg_' + msgId.replace(/[^a-zA-Z0-9]/g, '_')

				const incomingMsg: UiChatMessage = {
					id: msgId,
					viewId: safeViewId,
					type: isMyMessage ? 'sent' : 'received',
					content: content,
					time: timeStr,
					msgType: msgType
				}

				console.log('=== 添加新消息到列表 ===')
				console.log('消息类型:', incomingMsg.type)
				console.log('消息内容:', incomingMsg.content)
				messages.value.push(incomingMsg)
				scrollToBottom()
			} else {
				console.log('条件不满足，不添加消息')
			}
		})
		.subscribe((status: string, err: any | null) => {
			console.log('订阅状态:', status)
			if (err != null) {
				console.log('订阅错误:', err)
			}
		})
}

async function loadChatHistory(): Promise<void> {
    let rawMsgs : ChatMessage[] = []

    if (merchantId.value != '') {
        rawMsgs = await supabaseService.getChatMessages(merchantId.value)
    } else {
        console.warn("No merchant ID provided for chat")
        return
    }

    // 确保时间顺序是升序（旧的在前，新的在后）
    // Supabase 返回的消息如果是降序，我们需要 reverse 过来显示
    const sortedRawMsgs = rawMsgs.sort((a, b) => {
        const timeA = new Date(a.created_at ?? '').getTime()
        const timeB = new Date(b.created_at ?? '').getTime()
        return timeA - timeB
    })

    const uiMessages : UiChatMessage[] = []
    for (let i = 0; i < sortedRawMsgs.length; i++) {
        const m = sortedRawMsgs[i]
        const date = new Date(m.created_at ?? new Date().toISOString())
        const timeStr = `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`

        const sender = m.sender_id ?? ''
        const msgType = (currentUserId.value != '' && sender == currentUserId.value) ? 'sent' : 'received'
        const rawId = (m.id ?? '').toString()
        const msgId = rawId != '' ? rawId : Date.now().toString() + i.toString()
        const safeViewId = 'msg_' + msgId.replace(/[^a-zA-Z0-9]/g, '_')
        
        const uiMsg : UiChatMessage = {
            id: msgId,
            viewId: safeViewId,
            type: msgType,
            content: m.content ?? '',
            time: timeStr,
            msgType: m.msg_type ?? 'text'
        }
        uiMessages.push(uiMsg)
    }
    messages.value = uiMessages
    
    if (isInitialLoading.value) {
        // 增加一点初始化延迟，等待 scroll-view 渲染就绪
        setTimeout(() => {
            scrollToBottom()
            isInitialLoading.value = false
        }, 500)
    }
}

function onScrollToUpper(e: any): void {
    console.log('[onScrollToUpper] 触发加载历史记录')
}

async function loadMerchantInfo(): Promise<void> {
	if (merchantId.value == '') return
	
	try {
		const response = await supa
			.from('ml_shops')
			.select('shop_logo, shop_name')
			.eq('merchant_id', merchantId.value)
			.limit(1)
			.execute()
		
		if (response.error != null) {
			console.error('[loadMerchantInfo] 获取商家信息失败:', response.error)
			return
		}
		
		const rawData = response.data
		if (rawData == null) return
		
		const rawList = rawData as any[]
		if (rawList.length == 0) return
		
		const shopData = rawList[0]
		const shopObj = JSON.parse(JSON.stringify(shopData)) as UTSJSONObject
		
		const logo = shopObj.getString('shop_logo')
		if (logo != null && logo != '') {
			merchantAvatar.value = logo
		}
		
		const name = shopObj.getString('shop_name')
		if (name != null && name != '' && headerTitle.value == '在线客服') {
			headerTitle.value = name
		}
	} catch (e) {
		console.error('[loadMerchantInfo] 获取商家信息异常:', e)
	}
}

// 生命周期
onLoad((options: any) => {
    // 动态获取状态栏高度
    const sysInfo = uni.getSystemInfoSync()
    const statusBarH = sysInfo.statusBarHeight
    // 状态栏高度 + 10px 原有顶部内边距
    navPaddingTop.value = (statusBarH + 10) + 'px'

	const optObj = (options instanceof UTSJSONObject) ? (options as UTSJSONObject) : (JSON.parse(JSON.stringify(options ?? {})) as UTSJSONObject)
	const mid = optObj.getString('merchantId') ?? ''
	if (mid !== '') {
		merchantId.value = mid
	}
	const mname = optObj.getString('merchantName') ?? ''
	if (mname !== '') {
		headerTitle.value = mname
	}
})

onMounted(() => {
	supabaseService.ensureSession().then((uid) => {
		if (uid != null) {
			currentUserId.value = uid
		} else {
			getCurrentUser().then((user) => {
				if (user != null) {
					currentUserId.value = user.id ?? ''
				}
			})
		}

		loadMerchantInfo()
		loadChatHistory()
		setupRealtimeSubscription()
	})
})

onUnmounted(() => {
    if (realtimeChannel != null) {
        supa.removeChannel(realtimeChannel!!)
    }
})

const sendMessage = async () => {
    const content = inputMessage.value.trim()
    if (content == '') return
    
    // 清空输入框
    inputMessage.value = ''
    // 发送消息时确保收起表情面板
    showEmoji.value = false
    
    // 发送到 Supabase
    if (merchantId.value != '') {
        console.log('[sendMessage] 开始发送消息到:', merchantId.value)
        const success = await supabaseService.sendMessage(merchantId.value, content)
        console.log('[sendMessage] 发送结果:', success)
        if (!success) {
            uni.showToast({
                title: '发送失败',
                icon: 'none'
            })
        }
        // 不需要手动添加消息，等待实时订阅推送
    }
}

// 模拟客服回复 (已禁用，改用 Realtime)
/*
const simulateCustomerReply = async () => {
    // ...
}
*/

/* 移除不再使用的 simulateCustomerReply 和 addReceivedMessage */

// 插入表情
function insertEmoji(emoji: string): void {
    inputMessage.value += emoji
    showEmoji.value = false // 选中表情后收起表情列表
    inputFocus.value = true
}

// 显示表情选择器
function showEmojiPicker(): void {
    showEmoji.value = !showEmoji.value
    if (showEmoji.value) {
        // 如果打开表情，通常需要收起键盘
        uni.hideKeyboard()
    }
}

// 执行图片上传
async function doUploadImage(filePath: string): Promise<void> {
    console.log('[doUploadImage] 开始上传图片:', filePath)
    
    // 显示加载提示
    uni.showLoading({
        title: '发送中...',
        mask: true
    })
    
    try {
        // 上传图片
        const imageUrl = await supabaseService.uploadChatImage(filePath)
        
        uni.hideLoading()
        
        if (imageUrl == '') {
            uni.showToast({
                title: '图片上传失败',
                icon: 'none'
            })
            return
        }
        
        console.log('[doUploadImage] 图片上传成功:', imageUrl)
        
        // 发送图片消息
        const success = await supabaseService.sendMessage(merchantId.value, imageUrl, 'image')
        if (!success) {
            uni.showToast({
                title: '发送失败',
                icon: 'none'
            })
        }
    } catch (e) {
        uni.hideLoading()
        console.error('[doUploadImage] 上传异常:', e)
        uni.showToast({
            title: '上传失败',
            icon: 'none'
        })
    }
}

// 显示图片选择器
function showImagePicker(): void {
    uni.chooseImage({
        count: 1,
        success: (res) => {
            console.log('选择图片成功:', JSON.stringify(res))
            
            // 处理 tempFilePaths，兼容不同平台
            let filePath: string = ''
            const tempFilePaths = res.tempFilePaths as string[]
            if (tempFilePaths != null) {
                if (Array.isArray(tempFilePaths)) {
                    const arr = tempFilePaths as string[]
                    if (arr.length > 0) {
                        filePath = arr[0]
                    }
                } else if (tempFilePaths instanceof UTSJSONObject) {
                    const keys = UTSJSONObject.keys(tempFilePaths as UTSJSONObject)
                    if (keys.length > 0) {
                        filePath = (tempFilePaths as UTSJSONObject).getString(keys[0]) ?? ''
                    }
                } else if (typeof tempFilePaths === 'string') {
                    filePath = tempFilePaths as string
                }
            }
            
            // 尝试从 tempFiles 获取
            if (filePath == '' && res.tempFiles != null) {
                const tempFiles = res.tempFiles
                if (Array.isArray(tempFiles)) {
                    const files = tempFiles as any[]
                    if (files.length > 0) {
                        const firstFile = files[0]
                        if (firstFile instanceof UTSJSONObject) {
                            filePath = firstFile.getString('path') ?? ''
                        } else if (typeof firstFile === 'object' && firstFile != null) {
                            const fileObj = JSON.parse(JSON.stringify(firstFile)) as UTSJSONObject
                            filePath = fileObj.getString('path') ?? ''
                        }
                    }
                }
            }
            
            console.log('[showImagePicker] 文件路径:', filePath)
            
            if (filePath == '') {
                uni.showToast({
                    title: '获取图片路径失败',
                    icon: 'none'
                })
                return
            }
            
            // 执行上传
            doUploadImage(filePath)
        },
        fail: (err) => {
            console.log('选择图片失败:', err)
            uni.showToast({
                title: '选择图片失败',
                icon: 'none'
            })
        }
    })
}

// 预览图片
function previewImage(url: string): void {
    uni.previewImage({
        urls: [url],
        current: url
    })
}

// 显示更多工具
function showMoreTools(): void {
    uni.showActionSheet({
        itemList: ['发送位置', '发送文件', '发送语音'],
        success: (res) => {
            console.log('选择工具:', res.tapIndex)
        }
    })
}

// 显示更多操作
function showMoreActions(): void {
    uni.showActionSheet({
        itemList: ['投诉客服', '结束对话', '清除记录'],
        success: (res) => {
            switch (res.tapIndex) {
                case 0:
                    uni.navigateTo({ url: '/pages/mall/consumer/complaint' })
                    break
                case 1:
                    uni.showModal({
                        title: '确认结束',
                        content: '确定要结束本次对话吗？',
                        success: (res) => {
                            if (res.confirm) {
                                uni.navigateBack()
                            }
                        }
                    })
                    break
                case 2:
                    uni.showModal({
                        title: '确认清除',
                        content: '确定要清除聊天记录吗？',
                        success: (res) => {
                            if (res.confirm) {
                                messages.value = []
                            }
                        }
                    })
                    break
            }
        }
    })
}

// 返回
const goBack = () => {
    uni.navigateBack()
}
</script>

<style>
.chat-page {
    width: 100%;
    flex: 1;
    background-color: #f5f5f5;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

/* 聊天头部 */
.chat-header {
    background-color: white;
    padding: 10px 15px;
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    border-bottom: 1px solid #eee;
    flex-shrink: 0;
}

.header-back {
    width: 40px;
}

.back-icon {
    font-size: 20px;
    color: #333;
}

.header-info {
    flex: 1;
}

.header-info-text-wrapper {
    display: flex;
    flex-direction: column;
    align-items: center;
}

.chat-title {
    font-size: 16px;
    font-weight: bold;
    color: #333;
    margin-bottom: 2px;
}

.chat-status {
    font-size: 12px;
    color: #34c759;
}

.header-actions .action-icon {
    font-size: 20px;
    color: #333;
    width: 40px;
}

.action-icon-text {
    text-align: right;
    width: 100%;
}

/* 聊天内容区 */
.chat-content {
    flex: 1;
    height: 0;
    padding: 10px;
    padding-bottom: 20px;
    box-sizing: border-box;
}

.chat-messages {
    display: flex;
    flex-direction: column;
    padding-bottom: 80px;
}

/* 系统消息 */
.message-item.system {
    display: flex;
    flex-direction: row;
    justify-content: center;
    margin-bottom: 20px;
}

.system-text {
    font-size: 12px;
    color: #999;
    background-color: #f0f0f0;
    padding: 5px 15px;
    border-radius: 15px;
    text-align: center;
}

/* 时间分割线 */
.time-divider {
    display: flex;
    flex-direction: row;
    justify-content: center;
    margin: 20px 0;
}

.time-text {
    font-size: 12px;
    color: #999;
    background-color: #f0f0f0;
    padding: 3px 10px;
    border-radius: 10px;
    text-align: center;
}

/* 消息项 */
.message-wrapper {
    display: flex;
    flex-direction: row;
    margin-bottom: 15px;
}

.message-wrapper.me {
    justify-content: flex-end;
}

.avatar {
    width: 40px;
    height: 40px;
    border-radius: 20px;
    margin-right: 10px;
    flex-shrink: 0;
}

.avatar.me {
    margin-right: 0;
    margin-left: 10px;
    /* order: 2; removed for uni-app-x */
}

.message-content-wrapper {
    width: 260px;
    display: flex;
    flex-direction: column;
}

.message-bubble {
    background-color: white;
    padding: 10px 15px;
    border-radius: 12px;
    position: relative;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
}

.received-bubble {
    align-self: flex-start;
    border-top-left-radius: 2px;
}

.message-bubble.me {
    background-color: #95ec69;
    align-self: flex-end; /* 关键：靠右对齐且宽度自适应 */
    border-top-right-radius: 2px;
}

.sender-name {
    font-size: 11px;
    color: #999;
    margin-bottom: 2px;
    align-self: flex-start;
}

.message-text {
    font-size: 15px;
    color: #333;
    line-height: 1.4;
    margin-bottom: 5px;
    white-space: pre-wrap;
}

.message-image {
    max-width: 200px;
    min-width: 100px;
    border-radius: 8px;
    margin-bottom: 5px;
}

.message-time {
    font-size: 11px;
    color: #999;
    text-align: right;
}

/* 聊天输入区 */
.chat-input {
    background-color: white;
    border-top: 1px solid #eee;
    padding: 10px 15px;
    padding-bottom: 20px;
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    flex-shrink: 0;
}

.input-tools {
    display: flex;
    flex-direction: row;
    margin-bottom: 10px;
}

.tool-icon {
    font-size: 20px;
    margin-right: 15px;
    color: #666;
}

.input-wrapper {
    display: flex;
    flex-direction: row;
    align-items: center;
}

.message-input {
    flex: 1;
    background-color: #f5f5f5;
    border-radius: 20px;
    padding: 10px 15px;
    font-size: 15px;
    margin-right: 10px;
    min-height: 40px;
    max-height: 100px;
}

.send-button {
    background-color: #ccc;
    color: white;
    border: none;
    border-radius: 20px;
    padding: 8px 20px;
    font-size: 14px;
    min-width: 60px;
    transition: all 0.3s ease;
}

.send-button.active {
    background-color: #ff5000;
}

/* 表情选择器 */
.emoji-picker {
    background-color: white;
    border-top: 1px solid #eee;
    padding: 10px;
    height: 200px;
    position: fixed;
    bottom: 80px;
    left: 0;
    right: 0;
    z-index: 99;
}

.emoji-category {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
}

.emoji-item {
    font-size: 24px;
    padding: 8px;
    width: 45px;
    height: 45px;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* 响应式适配 removed for strict uv-app-x compliance */
</style>

