商品以及商品详情
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
export default definePageConfig({
|
||||
navigationBarTitleText: '对话',
|
||||
navigationStyle: 'custom',
|
||||
})
|
||||
@@ -0,0 +1,160 @@
|
||||
/* ========================================
|
||||
对话页
|
||||
======================================== */
|
||||
|
||||
.chat-page {
|
||||
min-height: 100vh;
|
||||
background: #f7f8fa;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* ========== 导航栏 ========== */
|
||||
.chat-nav {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 100;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.06);
|
||||
|
||||
.nav-content {
|
||||
height: 44px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 24px;
|
||||
position: relative;
|
||||
|
||||
.nav-back {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-left: -10px;
|
||||
}
|
||||
|
||||
.nav-info {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.nav-name {
|
||||
font-size: 32px;
|
||||
font-weight: 500;
|
||||
color: #1a1a1a;
|
||||
}
|
||||
|
||||
.nav-role {
|
||||
font-size: 22px;
|
||||
color: #969799;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-placeholder {
|
||||
width: 50px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ========== 消息列表滚动区 ========== */
|
||||
.chat-scroll {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* ========== 消息列表容器 ========== */
|
||||
.message-list {
|
||||
padding: 16px 24px;
|
||||
}
|
||||
|
||||
/* ========== 消息项 ========== */
|
||||
.message-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-bottom: 24px;
|
||||
|
||||
/* 接收消息:左对齐 */
|
||||
&.received {
|
||||
align-items: flex-start;
|
||||
|
||||
.bubble {
|
||||
background: #fff;
|
||||
color: #323233;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
}
|
||||
|
||||
/* 发送消息:右对齐 */
|
||||
&.sent {
|
||||
align-items: flex-end;
|
||||
|
||||
.bubble {
|
||||
background: linear-gradient(135deg, #1989fa 0%, #06b7f0 100%);
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.bubble {
|
||||
max-width: 70%;
|
||||
padding: 20px 24px;
|
||||
border-radius: 16px;
|
||||
font-size: 30px;
|
||||
line-height: 1.5;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.msg-time {
|
||||
font-size: 22px;
|
||||
color: #c8c9cc;
|
||||
margin-top: 8px;
|
||||
padding: 0 4px;
|
||||
}
|
||||
}
|
||||
|
||||
/* ========== 底部输入栏 ========== */
|
||||
.chat-input-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 16px 24px;
|
||||
background: #fff;
|
||||
border-top: 1px solid #f2f3f5;
|
||||
gap: 16px;
|
||||
|
||||
.input-wrap {
|
||||
flex: 1;
|
||||
background: #f7f8fa;
|
||||
border-radius: 40px;
|
||||
padding: 12px 24px;
|
||||
|
||||
.chat-input {
|
||||
font-size: 28px;
|
||||
height: 44px;
|
||||
line-height: 44px;
|
||||
}
|
||||
}
|
||||
|
||||
.send-btn {
|
||||
flex-shrink: 0;
|
||||
padding: 12px 28px;
|
||||
background: #1989fa;
|
||||
border-radius: 40px;
|
||||
|
||||
.send-text {
|
||||
font-size: 28px;
|
||||
color: #fff;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ========== 底部安全区占位 ========== */
|
||||
.scroll-bottom-safe {
|
||||
height: 120px;
|
||||
}
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user