web端聊天界面时间显示和气泡布局

This commit is contained in:
2026-03-27 22:16:22 +08:00
parent 67c78e7202
commit d8bc3636cf
2 changed files with 101 additions and 25 deletions

View File

@@ -408,7 +408,7 @@ export const MessageBubble: React.FC<MessageBubbleProps> = ({
)}
<View style={styles.messageContent}>
{/* 群聊模式:显示发送者昵称 */}
{/* 群聊模式:显示发送者昵称 - 放在气泡上方 */}
{isGroupChat && !isMe && senderInfo && (
<Text style={styles.senderName}>{senderInfo.nickname}</Text>
)}

View File

@@ -266,6 +266,43 @@ export const EmbeddedChat: React.FC<EmbeddedChatProps> = ({ conversation, onBack
}
};
// 格式化时间
const formatTime = (dateString: string) => {
const date = new Date(dateString);
const now = new Date();
const isToday = date.toDateString() === now.toDateString();
if (isToday) {
return date.toLocaleTimeString('zh-CN', {
hour: '2-digit',
minute: '2-digit',
hour12: false
});
} else {
return date.toLocaleString('zh-CN', {
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
hour12: false
});
}
};
// 判断是否需要显示时间与上一条消息间隔超过5分钟
const shouldShowTime = (index: number) => {
if (index === 0) return true;
const currentMsg = messages[index];
const prevMsg = messages[index - 1];
if (!currentMsg || !prevMsg) return true;
const currentTime = new Date(currentMsg.created_at).getTime();
const prevTime = new Date(prevMsg.created_at).getTime();
const diffMinutes = (currentTime - prevTime) / (1000 * 60);
return diffMinutes >= 5;
};
// 渲染消息内容
const renderMessageContent = (item: MessageResponse) => {
// 撤回消息
@@ -356,8 +393,9 @@ export const EmbeddedChat: React.FC<EmbeddedChatProps> = ({ conversation, onBack
};
// 渲染消息
const renderMessage = ({ item }: { item: MessageResponse }) => {
const renderMessage = ({ item, index }: { item: MessageResponse; index: number }) => {
const isMe = String(item.sender_id) === String(currentUser?.id);
const showTime = shouldShowTime(index);
// 处理指针事件(鼠标右键)- 使用 onPointerDown 检测鼠标右键
const handlePointerDown = (e: any) => {
@@ -372,31 +410,46 @@ export const EmbeddedChat: React.FC<EmbeddedChatProps> = ({ conversation, onBack
};
return (
<View
style={[styles.messageRow, isMe ? styles.messageRowRight : styles.messageRowLeft]}
// @ts-ignore - React Native for Web 支持 pointer events
onPointerDown={handlePointerDown}
>
{!isMe && (
<Avatar
source={item.sender?.avatar}
size={36}
name={item.sender?.nickname || item.sender?.username}
/>
<View>
{/* 时间分隔 */}
{showTime && (
<View style={styles.timeContainer}>
<Text style={styles.timeText}>{formatTime(item.created_at)}</Text>
</View>
)}
<View style={[styles.messageBubble, isMe ? styles.messageBubbleMe : styles.messageBubbleOther]}>
{isGroupChat && !isMe && (
<Text style={styles.senderName}>{item.sender?.nickname || item.sender?.username}</Text>
<View
style={[styles.messageRow, isMe ? styles.messageRowRight : styles.messageRowLeft]}
// @ts-ignore - React Native for Web 支持 pointer events
onPointerDown={handlePointerDown}
>
{!isMe && (
<View style={styles.avatarContainer}>
<Avatar
source={item.sender?.avatar}
size={36}
name={item.sender?.nickname || item.sender?.username}
/>
</View>
)}
<View style={styles.messageContent}>
{/* 群聊模式:显示发送者昵称 - 顶部与头像对齐 */}
{isGroupChat && !isMe && (
<Text style={styles.senderName}>{item.sender?.nickname || item.sender?.username}</Text>
)}
<View style={[styles.messageBubble, isMe ? styles.messageBubbleMe : styles.messageBubbleOther]}>
{renderMessageContent(item)}
</View>
</View>
{isMe && (
<View style={styles.avatarContainer}>
<Avatar
source={currentUser?.avatar}
size={36}
name={currentUser?.nickname || currentUser?.username}
/>
</View>
)}
{renderMessageContent(item)}
</View>
{isMe && (
<Avatar
source={currentUser?.avatar}
size={36}
name={currentUser?.nickname || currentUser?.username}
/>
)}
</View>
);
};
@@ -664,9 +717,24 @@ const styles = StyleSheet.create({
padding: spacing.md,
paddingBottom: spacing.xl,
},
timeContainer: {
alignItems: 'center',
marginVertical: spacing.md,
},
timeText: {
color: '#8E8E93',
fontSize: 12,
backgroundColor: 'rgba(142, 142, 147, 0.12)',
paddingHorizontal: spacing.md,
paddingVertical: 6,
borderRadius: 14,
fontWeight: '600',
overflow: 'hidden',
letterSpacing: 0.3,
},
messageRow: {
flexDirection: 'row',
alignItems: 'flex-end',
alignItems: 'flex-start',
marginBottom: spacing.md,
maxWidth: screenWidth * 0.7,
},
@@ -677,6 +745,9 @@ const styles = StyleSheet.create({
alignSelf: 'flex-end',
justifyContent: 'flex-end',
},
avatarContainer: {
marginTop: 0,
},
messageBubble: {
maxWidth: screenWidth * 0.5,
paddingHorizontal: spacing.md,
@@ -693,10 +764,15 @@ const styles = StyleSheet.create({
borderBottomLeftRadius: 4,
...shadows.sm,
},
messageContent: {
maxWidth: screenWidth * 0.5,
alignItems: 'flex-start',
},
senderName: {
fontSize: 12,
color: '#999',
marginBottom: 2,
marginLeft: 4,
},
messageText: {
fontSize: 15,