fix: 聊天页面适配暗黑模式
将 scoped CSS 硬编码颜色全部替换为 Tailwind 语义类: - 背景色: bg-card, bg-muted, bg-accent, bg-primary - 文字色: text-foreground, text-muted-foreground, text-primary-foreground - 边框色: border-border - 选中态: bg-primary/10 dark:bg-accent
This commit is contained in:
parent
dfa70b7ef4
commit
a67764a705
@ -26,7 +26,7 @@ const activeMessages = computed(() => imStore.activeMessages);
|
|||||||
const sortedConversations = computed(() =>
|
const sortedConversations = computed(() =>
|
||||||
[...imStore.conversations].toSorted((a, b) => {
|
[...imStore.conversations].toSorted((a, b) => {
|
||||||
const timeA = a.lastMessageAt ? new Date(a.lastMessageAt).getTime() : 0;
|
const timeA = a.lastMessageAt ? new Date(a.lastMessageAt).getTime() : 0;
|
||||||
const timeB = b.lastMessageAt ? new Date(b.lastMessageAt).getTime() : 0;
|
const timeB = b.lastMessageAt ? new Date(a.lastMessageAt).getTime() : 0;
|
||||||
return timeB - timeA;
|
return timeB - timeA;
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
@ -57,7 +57,6 @@ async function selectConversation(conversationId: string) {
|
|||||||
await imStore.loadMessages(conversationId);
|
await imStore.loadMessages(conversationId);
|
||||||
await nextTick();
|
await nextTick();
|
||||||
scrollToBottom();
|
scrollToBottom();
|
||||||
// Mark as read
|
|
||||||
const msgs = imStore.activeMessages;
|
const msgs = imStore.activeMessages;
|
||||||
if (msgs.length > 0) {
|
if (msgs.length > 0) {
|
||||||
const lastMsg = msgs[msgs.length - 1];
|
const lastMsg = msgs[msgs.length - 1];
|
||||||
@ -66,7 +65,7 @@ async function selectConversation(conversationId: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function handleSend(e?: any) {
|
async function handleSend(e?: any) {
|
||||||
if (e?.shiftKey) return; // Shift+Enter for newline
|
if (e?.shiftKey) return;
|
||||||
e?.preventDefault?.();
|
e?.preventDefault?.();
|
||||||
|
|
||||||
const content = inputMessage.value.trim();
|
const content = inputMessage.value.trim();
|
||||||
@ -135,20 +134,30 @@ onUnmounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="chat-container">
|
<div
|
||||||
<div class="chat-sidebar">
|
class="flex h-[calc(100vh-120px)] overflow-hidden rounded-lg border border-border bg-card"
|
||||||
<div class="sidebar-header">
|
>
|
||||||
<h3 style=" padding: 16px;margin: 0">消息</h3>
|
<!-- Sidebar -->
|
||||||
|
<div
|
||||||
|
class="flex w-[300px] shrink-0 flex-col border-r border-border"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="flex items-center justify-between border-b border-border px-4 py-3"
|
||||||
|
>
|
||||||
|
<h3 class="m-0 p-0 text-base font-medium text-foreground">消息</h3>
|
||||||
<a-button type="primary" size="small" @click="showCreateGroup = true">
|
<a-button type="primary" size="small" @click="showCreateGroup = true">
|
||||||
创建群聊
|
创建群聊
|
||||||
</a-button>
|
</a-button>
|
||||||
</div>
|
</div>
|
||||||
<div class="conversation-list">
|
|
||||||
|
<div class="flex-1 overflow-y-auto">
|
||||||
<div
|
<div
|
||||||
v-for="conv in sortedConversations"
|
v-for="conv in sortedConversations"
|
||||||
:key="conv.id"
|
:key="conv.id"
|
||||||
class="conversation-item"
|
class="flex cursor-pointer items-center px-4 py-3 transition-colors hover:bg-accent"
|
||||||
:class="{ active: conv.id === activeConversationId }"
|
:class="{
|
||||||
|
'bg-primary/10 dark:bg-accent': conv.id === activeConversationId,
|
||||||
|
}"
|
||||||
@click="selectConversation(conv.id)"
|
@click="selectConversation(conv.id)"
|
||||||
>
|
>
|
||||||
<a-avatar v-if="conv.type === 2" :size="40">
|
<a-avatar v-if="conv.type === 2" :size="40">
|
||||||
@ -157,16 +166,22 @@ onUnmounted(() => {
|
|||||||
<a-avatar v-else :size="40">
|
<a-avatar v-else :size="40">
|
||||||
{{ conv.otherUserName?.charAt(0) || 'U' }}
|
{{ conv.otherUserName?.charAt(0) || 'U' }}
|
||||||
</a-avatar>
|
</a-avatar>
|
||||||
<div class="conversation-info">
|
|
||||||
<div class="conversation-name">
|
<div class="ml-3 flex-1 overflow-hidden">
|
||||||
|
<div
|
||||||
|
class="truncate text-sm font-medium text-foreground"
|
||||||
|
>
|
||||||
{{
|
{{
|
||||||
conv.type === 2 ? conv.groupName : conv.otherUserName || '私聊'
|
conv.type === 2
|
||||||
|
? conv.groupName
|
||||||
|
: conv.otherUserName || '私聊'
|
||||||
}}
|
}}
|
||||||
</div>
|
</div>
|
||||||
<div class="conversation-last-msg">
|
<div class="mt-1 truncate text-xs text-muted-foreground">
|
||||||
{{ conv.lastMessageContent || '暂无消息' }}
|
{{ conv.lastMessageContent || '暂无消息' }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<a-badge
|
<a-badge
|
||||||
v-if="conv.unreadCount > 0"
|
v-if="conv.unreadCount > 0"
|
||||||
:count="conv.unreadCount"
|
:count="conv.unreadCount"
|
||||||
@ -176,9 +191,12 @@ onUnmounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="chat-main">
|
<!-- Main chat area -->
|
||||||
|
<div class="flex flex-1 flex-col">
|
||||||
<template v-if="activeConversation">
|
<template v-if="activeConversation">
|
||||||
<div class="chat-header">
|
<div
|
||||||
|
class="flex items-center justify-between border-b border-border px-4 py-3 font-medium text-foreground"
|
||||||
|
>
|
||||||
<span>
|
<span>
|
||||||
{{
|
{{
|
||||||
activeConversation.type === 2
|
activeConversation.type === 2
|
||||||
@ -195,28 +213,39 @@ onUnmounted(() => {
|
|||||||
</a-button>
|
</a-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div ref="messageListRef" class="message-list" @scroll="onScroll">
|
<div
|
||||||
|
ref="messageListRef"
|
||||||
|
class="flex-1 overflow-y-auto px-4 py-4"
|
||||||
|
@scroll="onScroll"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
v-for="msg in activeMessages"
|
v-for="msg in activeMessages"
|
||||||
:key="msg.id"
|
:key="msg.id"
|
||||||
class="message-item"
|
class="mb-4"
|
||||||
:class="{ 'message-self': isSelfMessage(msg) }"
|
:class="{ 'text-right': isSelfMessage(msg) }"
|
||||||
>
|
>
|
||||||
<div class="message-sender">
|
<div class="mb-1 text-xs text-muted-foreground">
|
||||||
{{ msg.senderName || msg.senderId.substring(0, 8) }}
|
{{ msg.senderName || msg.senderId.substring(0, 8) }}
|
||||||
</div>
|
</div>
|
||||||
<div class="message-content">
|
<div
|
||||||
|
class="inline-block max-w-[60%] break-words rounded-lg px-3 py-2"
|
||||||
|
:class="
|
||||||
|
isSelfMessage(msg)
|
||||||
|
? 'bg-primary text-primary-foreground'
|
||||||
|
: 'bg-muted text-foreground'
|
||||||
|
"
|
||||||
|
>
|
||||||
<template v-if="msg.contentType === 0">
|
<template v-if="msg.contentType === 0">
|
||||||
{{ msg.content }}
|
{{ msg.content }}
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="msg.contentType === 1">
|
<template v-else-if="msg.contentType === 1">
|
||||||
<img
|
<img
|
||||||
:src="msg.metadata?.imageUrl"
|
:src="msg.metadata?.imageUrl"
|
||||||
style="max-width: 200px; border-radius: 8px"
|
class="max-w-[200px] rounded-lg"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="msg.contentType === 4">
|
<template v-else-if="msg.contentType === 4">
|
||||||
<span style="font-size: 24px">{{ msg.content }}</span>
|
<span class="text-2xl">{{ msg.content }}</span>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
[{{
|
[{{
|
||||||
@ -224,11 +253,15 @@ onUnmounted(() => {
|
|||||||
}}]
|
}}]
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div class="message-time">{{ formatTime(msg.createdAt) }}</div>
|
<div class="mt-1 text-[11px] text-muted-foreground/60">
|
||||||
|
{{ formatTime(msg.createdAt) }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="chat-input">
|
<div
|
||||||
|
class="flex gap-2 border-t border-border px-4 py-3"
|
||||||
|
>
|
||||||
<a-textarea
|
<a-textarea
|
||||||
v-model:value="inputMessage"
|
v-model:value="inputMessage"
|
||||||
placeholder="输入消息..."
|
placeholder="输入消息..."
|
||||||
@ -241,7 +274,10 @@ onUnmounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div v-else class="chat-empty">
|
<div
|
||||||
|
v-else
|
||||||
|
class="flex flex-1 items-center justify-center text-muted-foreground"
|
||||||
|
>
|
||||||
<p>选择一个会话开始聊天</p>
|
<p>选择一个会话开始聊天</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -263,146 +299,3 @@ onUnmounted(() => {
|
|||||||
</a-modal>
|
</a-modal>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.chat-container {
|
|
||||||
display: flex;
|
|
||||||
height: calc(100vh - 120px);
|
|
||||||
overflow: hidden;
|
|
||||||
background: #fff;
|
|
||||||
border-radius: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-sidebar {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
width: 300px;
|
|
||||||
border-right: 1px solid #f0f0f0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-header {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 12px 16px;
|
|
||||||
border-bottom: 1px solid #f0f0f0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.conversation-list {
|
|
||||||
flex: 1;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.conversation-item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
padding: 12px 16px;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: background 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.conversation-item:hover {
|
|
||||||
background: #f5f5f5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.conversation-item.active {
|
|
||||||
background: #e6f4ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.conversation-info {
|
|
||||||
flex: 1;
|
|
||||||
margin-left: 12px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.conversation-name {
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 500;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.conversation-last-msg {
|
|
||||||
margin-top: 4px;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
font-size: 12px;
|
|
||||||
color: #999;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-main {
|
|
||||||
display: flex;
|
|
||||||
flex: 1;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-header {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 12px 16px;
|
|
||||||
font-weight: 500;
|
|
||||||
border-bottom: 1px solid #f0f0f0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-list {
|
|
||||||
flex: 1;
|
|
||||||
padding: 16px;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-item {
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-item.message-self {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-sender {
|
|
||||||
margin-bottom: 4px;
|
|
||||||
font-size: 12px;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-content {
|
|
||||||
display: inline-block;
|
|
||||||
max-width: 60%;
|
|
||||||
padding: 8px 12px;
|
|
||||||
overflow-wrap: anywhere;
|
|
||||||
background: #f0f0f0;
|
|
||||||
border-radius: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-item.message-self .message-content {
|
|
||||||
color: #fff;
|
|
||||||
background: #1677ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-time {
|
|
||||||
margin-top: 4px;
|
|
||||||
font-size: 11px;
|
|
||||||
color: #ccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-input {
|
|
||||||
display: flex;
|
|
||||||
gap: 8px;
|
|
||||||
padding: 12px 16px;
|
|
||||||
border-top: 1px solid #f0f0f0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-input .ant-input {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-empty {
|
|
||||||
display: flex;
|
|
||||||
flex: 1;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user