商品以及商品详情

This commit is contained in:
liu
2026-07-06 11:32:58 +08:00
parent 97e7a6083c
commit c25cf0e8b3
32 changed files with 3585 additions and 45 deletions
+168
View File
@@ -0,0 +1,168 @@
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>
)
}