169 lines
5.2 KiB
TypeScript
169 lines
5.2 KiB
TypeScript
import { useState, useMemo, useCallback, useRef, useEffect } from 'react'
|
|
import Taro, { useDidShow } from '@tarojs/taro'
|
|
import { View, Text, ScrollView, Input } from '@tarojs/components'
|
|
import { Icon } from '@antmjs/vantui'
|
|
import { chatList } from '@/mock/messages'
|
|
import { conversations } from '@/mock/conversations'
|
|
import type { ChatMessage } from '@/mock/conversations'
|
|
import './index.less'
|
|
|
|
/** 角色标签映射 */
|
|
const ROLE_LABEL: Record<string, string> = {
|
|
rider: '骑手',
|
|
merchant: '商家',
|
|
user: '同学',
|
|
}
|
|
|
|
function getStatusBarH(): number {
|
|
try { return Taro.getSystemInfoSync().statusBarHeight || 20 }
|
|
catch { return 20 }
|
|
}
|
|
|
|
function getSafeBottom(): number {
|
|
try {
|
|
const info = Taro.getSystemInfoSync()
|
|
return (info.screenHeight - info.safeArea!.bottom) || 0
|
|
} catch { return 0 }
|
|
}
|
|
|
|
export default function ChatPage() {
|
|
const id = String(Taro.getCurrentInstance().router?.params?.id || '')
|
|
|
|
/* ---- 查找聊天对象 ---- */
|
|
const partner = useMemo(() => chatList.find((c) => c.id === id), [id])
|
|
|
|
/* ---- 对话消息 ---- */
|
|
const [messages, setMessages] = useState<ChatMessage[]>([])
|
|
const [inputValue, setInputValue] = useState('')
|
|
|
|
const statusBarH = useMemo(getStatusBarH, [])
|
|
const safeBottom = useMemo(getSafeBottom, [])
|
|
|
|
// 初始化消息
|
|
useDidShow(() => {
|
|
if (id && conversations[id]) {
|
|
setMessages(conversations[id])
|
|
}
|
|
})
|
|
|
|
/* ---- 事件 ---- */
|
|
const handleBack = useCallback(() => {
|
|
Taro.navigateBack()
|
|
}, [])
|
|
|
|
const handleSend = useCallback(() => {
|
|
const text = inputValue.trim()
|
|
if (!text) return
|
|
|
|
const now = new Date()
|
|
const time = `${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}`
|
|
|
|
const newMsg: ChatMessage = {
|
|
id: `m${Date.now()}`,
|
|
sender: 'me',
|
|
content: text,
|
|
time,
|
|
}
|
|
|
|
setMessages((prev) => [...prev, newMsg])
|
|
setInputValue('')
|
|
|
|
// 模拟对方自动回复(1.5 秒后)
|
|
if (partner) {
|
|
setTimeout(() => {
|
|
const autoReply: ChatMessage = {
|
|
id: `m${Date.now() + 1}`,
|
|
sender: 'other',
|
|
content: '好的,收到你的消息了~',
|
|
time: `${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes() + 1).padStart(2, '0')}`,
|
|
}
|
|
setMessages((prev) => [...prev, autoReply])
|
|
}, 1500)
|
|
}
|
|
}, [inputValue, partner])
|
|
|
|
if (!partner) {
|
|
return (
|
|
<View className='chat-page'>
|
|
<View className='chat-nav' style={{ paddingTop: `${statusBarH}px` }}>
|
|
<View className='nav-content'>
|
|
<View className='nav-back' onClick={handleBack}>
|
|
<Icon name='arrow-left' size={22} color='#323233' />
|
|
</View>
|
|
<View className='nav-info'>
|
|
<Text className='nav-name'>未知用户</Text>
|
|
</View>
|
|
<View className='nav-placeholder' />
|
|
</View>
|
|
</View>
|
|
<View style={{ height: `${statusBarH + 44}px` }} />
|
|
<View style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', flex: 1 }}>
|
|
<Text style={{ color: '#969799', fontSize: '30px' }}>对话不存在</Text>
|
|
</View>
|
|
</View>
|
|
)
|
|
}
|
|
|
|
const roleLabel = partner.role ? ROLE_LABEL[partner.role] : ''
|
|
|
|
return (
|
|
<View className='chat-page'>
|
|
{/* ===== 导航栏 ===== */}
|
|
<View className='chat-nav' style={{ paddingTop: `${statusBarH}px` }}>
|
|
<View className='nav-content'>
|
|
<View className='nav-back' onClick={handleBack}>
|
|
<Icon name='arrow-left' size={22} color='#323233' />
|
|
</View>
|
|
<View className='nav-info'>
|
|
<Text className='nav-name'>{partner.name}</Text>
|
|
{roleLabel && <Text className='nav-role'>{roleLabel}</Text>}
|
|
</View>
|
|
<View className='nav-placeholder' />
|
|
</View>
|
|
</View>
|
|
<View style={{ height: `${statusBarH + 44}px` }} />
|
|
|
|
{/* ===== 消息列表 ===== */}
|
|
<ScrollView
|
|
className='chat-scroll'
|
|
scrollY
|
|
enhanced
|
|
showScrollbar={false}
|
|
scrollTop={99999}
|
|
scrollWithAnimation
|
|
>
|
|
<View className='message-list'>
|
|
{messages.map((msg) => (
|
|
<View
|
|
key={msg.id}
|
|
className={`message-item ${msg.sender === 'me' ? 'sent' : 'received'}`}
|
|
>
|
|
<Text className='bubble'>{msg.content}</Text>
|
|
<Text className='msg-time'>{msg.time}</Text>
|
|
</View>
|
|
))}
|
|
</View>
|
|
<View className='scroll-bottom-safe' />
|
|
</ScrollView>
|
|
|
|
{/* ===== 底部输入栏 ===== */}
|
|
<View className='chat-input-bar' style={{ paddingBottom: `${safeBottom}px` }}>
|
|
<View className='input-wrap'>
|
|
<Input
|
|
className='chat-input'
|
|
value={inputValue}
|
|
placeholder='输入消息...'
|
|
placeholderStyle='color: #c8c9cc;'
|
|
onInput={(e) => setInputValue(String(e.detail.value))}
|
|
confirmType='send'
|
|
onConfirm={handleSend}
|
|
/>
|
|
</View>
|
|
<View className='send-btn' onClick={handleSend}>
|
|
<Text className='send-text'>发送</Text>
|
|
</View>
|
|
</View>
|
|
</View>
|
|
)
|
|
}
|