消息模块-功能联调

main
ysn 4 days ago
parent 1ea1480e1c
commit 864215e901
  1. 14
      src/views/message/components/GroupSetting.vue
  2. 526
      src/views/message/components/MessageDisplay.vue
  3. 924
      src/views/message/components/MessageEditor.vue
  4. 25
      src/views/message/components/MessageList.vue
  5. 53
      src/views/message/components/SearchRecord.vue
  6. 15
      src/views/message/index.vue

@ -142,13 +142,13 @@ export default {
props: { props: {
chat: Object, chat: Object,
groupInfo: Object,
}, },
data() { data() {
return { return {
visible: false, visible: false,
isSearchVisible: false, isSearchVisible: false,
groupInfo: {},
isAdmin: false, isAdmin: false,
showDeleteBtn: null, showDeleteBtn: null,
currentUserId: this.$store.state.user.userInfo?.id, currentUserId: this.$store.state.user.userInfo?.id,
@ -162,18 +162,6 @@ export default {
methods: { methods: {
async loadGroupInfo() { async loadGroupInfo() {
this.visible = true; this.visible = true;
if (this.chat) {
if (!this.chat?.id) return;
try {
const res = await getMultiChatInfo({ multi_chat_id: this.chat.id });
this.groupInfo = {
...res.data,
user_list: res.data.user_list.sort((a, b) => a.id - b.id),
};
} catch (e) {
console.error("获取群信息失败", e);
}
}
}, },
editGroupName() { editGroupName() {

@ -4,8 +4,8 @@
<div class="chat-header"> <div class="chat-header">
<div class="chat-title"> <div class="chat-title">
<span class="name" v-if="currentChat">{{ currentChat.name }}</span> <span class="name" v-if="currentChat">{{ currentChat.name }}</span>
<span v-if="currentChat && currentChat.scene === 4"> <span v-if="currentChat && currentChat.scene === ContactsScene.GROUP">
({{ currentChat.user_num }}) ({{ currentChat.user_num - 1 }})
</span> </span>
</div> </div>
<div class="chat-actions"> <div class="chat-actions">
@ -13,12 +13,13 @@
type="text" type="text"
icon="el-icon-chat-line-round" icon="el-icon-chat-line-round"
@click="handleSearchRecord" @click="handleSearchRecord"
v-if="currentChat && currentChat.scene != ContactsScene.NOTIFY"
/> />
<el-button <el-button
type="text" type="text"
icon="el-icon-s-tools" icon="el-icon-s-tools"
@click="handleGroupSetting" @click="handleGroupSetting"
v-if="currentChat && currentChat.scene === 4" v-if="currentChat && currentChat.scene === ContactsScene.GROUP"
/> />
</div> </div>
</div> </div>
@ -41,90 +42,122 @@
<div <div
v-for="(msg, index) in currentMessages" v-for="(msg, index) in currentMessages"
:key="msg.message_id || msg.id || index" :key="msg.message_id || msg.id || index"
:class="['message-item', msg.is_self ? 'self' : 'other']" :class="[
'message-item',
msg.is_self ? 'self' : 'other',
{
'system-message':
msg.type === MessageType.MULTI_CHAT_INIT_JOIN ||
msg.type === MessageType.MULTI_CHAT_QUIT ||
msg.type === MessageType.MULTI_CHAT_EDIT ||
msg.type === MessageType.MULTI_CHAT_JOIN,
},
]"
> >
<!-- 时间分割线 --> <!-- 系统消息群成员变更通知 -->
<div class="time-divider">
{{ formatMessageTime(msg.create_time) }}
</div>
<div
v-if="msg.type === MessageType.MULTI_CHAT_INIT_JOIN"
class="time-divider"
>
{{
currentChat.user_num > 0
? `${currentChat.source_name || "成员"}邀请了${
currentChat.user_num
}人加入群聊`
: `${currentChat.source_name || "成员"}加入了群聊`
}}
</div>
<div
v-if="msg.type === MessageType.MULTI_CHAT_QUIT"
class="time-divider"
>
{{ msg.source_name || "成员" }}退出了群聊
</div>
<div <div
class="message-content-wrap"
v-if=" v-if="
msg.type !== MessageType.MULTI_CHAT_INIT_JOIN && msg.type === MessageType.MULTI_CHAT_INIT_JOIN ||
msg.type !== MessageType.MULTI_CHAT_QUIT msg.type === MessageType.MULTI_CHAT_JOIN
" "
> >
<!-- 头像 --> <div class="time-divider">
<el-avatar {{ formatMessageTime(msg.update_time) }}
:size="36" </div>
:src=" <div class="time-divider">
msg.is_self {{
? $store.state.user.netConfig.MINIO_ENDPOINT_HTTPS + (msg.source_name || "成员") +
$store.state.user.userInfo.avatar (JSON.parse(msg.content).invited_user_ids.length > 0
: $store.state.user.netConfig.MINIO_ENDPOINT_HTTPS + ? `邀请了${
currentChat.avatar JSON.parse(msg.content).invited_user_ids.length || 0
" }人加入群聊`
:icon="msg.is_self ? 'el-icon-user-solid' : 'el-icon-user'" : "加入了群聊")
class="message-avatar" }}
/> </div>
</div>
<div class="message-body">
<!-- 发送者名称群聊且非自己 --> <template v-else-if="msg.type === MessageType.MULTI_CHAT_QUIT">
<div <div class="time-divider">
class="message-name" {{ formatMessageTime(msg.update_time) }}
v-if="!msg.is_self && currentChat && currentChat.scene === 4" </div>
> <div class="time-divider">
{{ msg.sender_name || msg.source_name || "未知用户" }} {{ msg.source_name || "成员" }}退出了群聊
</div> </div>
<!-- 消息气泡 --> </template>
<div :class="['message-bubble', msg.type]">
<!-- 文本消息 --> <div v-else-if="msg.type === MessageType.MULTI_CHAT_EDIT">
<div <div class="time-divider">
v-if=" {{ formatMessageTime(msg.update_time) }}
msg.type === MessageType.TEXT || (!msg.type && msg.content) </div>
" <div class="time-divider">
class="text-message" {{
v-html="formatTextContent(msg.payload || msg.content)" (msg.sender_name || msg.source_name || "未知用户") +
/> `修改了群名为"${JSON.parse(msg.content).name || ""}"`
}}
<!-- 图片消息 --> </div>
</div>
<!-- 普通消息 -->
<div v-else>
<div class="time-divider">
{{ formatMessageTime(msg.update_time) }}
</div>
<div class="message-content-wrap">
<!-- 头像 -->
<el-avatar
:size="36"
:src="
msg.is_self
? $store.state.user.netConfig.MINIO_ENDPOINT_HTTPS +
$store.state.user.userInfo.avatar
: currentChat.scene === ContactsScene.GROUP
? $store.state.user.netConfig.MINIO_ENDPOINT_HTTPS +
msg.avatar
: $store.state.user.netConfig.MINIO_ENDPOINT_HTTPS +
currentChat.avatar
"
class="message-avatar"
/>
<div class="message-body">
<!-- 发送者名称群聊且非自己 -->
<div <div
v-else-if="msg.type === MessageType.IMAGE" class="message-name"
class="text-message" v-if="!msg.is_self && currentChat && currentChat.scene === 4"
> >
<el-image {{ msg.sender_name || msg.source_name || "未知用户" }}
:src=" </div>
$store.state.user.netConfig.MINIO_ENDPOINT_HTTPS + <!-- 消息气泡 -->
msg.file_path <div :class="['message-bubble', msg.type]">
<!-- 文本消息 -->
<div
v-if="
msg.type === MessageType.TEXT || (!msg.type && msg.content)
" "
:alt="msg.file_name" class="text-message"
:preview-src-list="[ v-html="formatTextContent(msg.payload || msg.content)"
$store.state.user.netConfig.MINIO_ENDPOINT_HTTPS +
msg.file_path,
]"
/> />
</div>
<!-- 视频消息 --> <!-- 图片消息 -->
<!-- <div <div
v-else-if="msg.type === MessageType.IMAGE"
class="text-message"
>
<el-image
:src="
$store.state.user.netConfig.MINIO_ENDPOINT_HTTPS +
msg.file_path
"
:alt="msg.file_name"
:preview-src-list="[
$store.state.user.netConfig.MINIO_ENDPOINT_HTTPS +
msg.file_path,
]"
/>
</div>
<!-- 视频消息 -->
<!-- <div
v-else-if="msg.type === MessageType.VIDEO" v-else-if="msg.type === MessageType.VIDEO"
class="video-message" class="video-message"
> >
@ -136,139 +169,148 @@
/> />
</div> --> </div> -->
<!-- 语音消息 --> <!-- 语音消息 -->
<!-- <div <!-- <div
v-else-if="msg.type === MessageType.AUDIO" v-else-if="msg.type === MessageType.AUDIO"
class="audio-message" class="audio-message"
> >
<audio :src="getFileUrl(msg.payload || msg.content)" controls /> <audio :src="getFileUrl(msg.payload || msg.content)" controls />
</div> --> </div> -->
<!-- 文件消息 --> <!-- 文件消息 -->
<div <div
v-else-if="msg.type === MessageType.FILE" v-else-if="msg.type === MessageType.FILE"
class="file-message" class="file-message"
> >
<div class="file-card" @click="handleDownloadFile(msg)"> <div class="file-card" @click="handleDownloadFile(msg)">
<div class="file-thumb"> <div class="file-thumb">
<i <i
:class="getFileIconClass(msg.file_name) + ' file-icon'" :class="getFileIconClass(msg.file_name) + ' file-icon'"
/> />
</div>
<div class="file-info">
<div class="file-name">{{ msg.file_name }}</div>
<div class="file-size">
{{ formatFileSize(msg.file_size) }}
</div> </div>
<div class="file-status"> <div class="file-info">
<el-button <div class="file-name">{{ msg.file_name }}</div>
type="text" <div class="file-size">
:underline="false" {{ formatFileSize(msg.file_size) }}
@click="handleDownload(msg)" </div>
> <div class="file-status">
打开 <el-button
</el-button> type="text"
<el-button :underline="false"
type="text" @click="handleDownload(msg)"
:underline="false" >
@click="handleOpenLocation(msg)" 打开
> </el-button>
打开目录 <el-button
</el-button> type="text"
:underline="false"
@click="handleOpenLocation(msg)"
>
打开目录
</el-button>
</div>
</div> </div>
</div> </div>
</div> </div>
</div>
<!-- 病例库分享 --> <!-- 病例库分享 -->
<div <div
v-else-if="msg.type === MessageType.REPORT_SHARE" v-else-if="msg.type === MessageType.REPORT_SHARE"
class="text-message" class="text-message"
>
病例分享: 姓名:{{ JSON.parse(msg.content).name }}, 年龄:{{
JSON.parse(msg.content).age
}}, 性别:{{ JSON.parse(msg.content).sex }},
<el-link
type="primary"
:underline="false"
@click="handleOpenReport(msg)"
> >
病例ID:{{ JSON.parse(msg.content).report_id }} 病例分享: 姓名:{{ JSON.parse(msg.content).name }}, 年龄:{{
</el-link> JSON.parse(msg.content).age
</div> }}, 性别:{{ JSON.parse(msg.content).sex }},
<el-link
type="primary"
:underline="false"
@click="handleOpenReport(msg)"
>
病例ID:{{ JSON.parse(msg.content).report_id }}
</el-link>
</div>
<!-- 知识分享 --> <!-- 知识分享 -->
<div <div
v-else-if="msg.type === MessageType.KNOWLEDGE_SHARE" v-else-if="msg.type === MessageType.KNOWLEDGE_SHARE"
class="text-message" class="text-message"
>
知识库分享:
<el-link
type="primary"
:underline="false"
@click="handleOpenKnowledge(msg)"
> >
资源名称:{{ JSON.parse(msg.content).file_name }} 知识库分享:
</el-link> <el-link
</div> type="primary"
<div :underline="false"
v-else-if="msg.type === MessageType.CONSULTATION_MESSAGE_INVITE" @click="handleOpenKnowledge(msg)"
class="text-message" >
> 资源名称:{{ JSON.parse(msg.content).file_name }}
视讯邀请:{{ JSON.parse(msg.content).name }}邀请您参加会诊 </el-link>
<el-link </div>
type="primary" <div
:underline="false" v-else-if="
@click="handleOpenConsultationInvite(msg)" msg.type === MessageType.CONSULTATION_MESSAGE_INVITE
"
class="text-message"
> >
会诊口令:{{ JSON.parse(msg.content).room_id }} 视讯邀请:{{ JSON.parse(msg.content).name }}邀请您参加会诊
</el-link> <el-link
</div> type="primary"
<!-- 系统通知 --> :underline="false"
<div @click="handleOpenConsultationInvite(msg)"
v-else-if="msg.type === MessageType.NOTIFY_CONTENT" >
class="file-message" 会诊口令:{{ JSON.parse(msg.content).room_id }}
> </el-link>
<div class="file-card"> </div>
<div class="file-info"> <!-- 系统通知 -->
<div class="file-name"> <div
标题:{{ JSON.parse(msg.content).title }} v-else-if="msg.type === MessageType.NOTIFY_CONTENT"
</div> class="file-message"
<div class="file-size"> >
内容:{{ JSON.parse(msg.content).content }} <div class="file-card">
</div> <div class="file-info">
<div class="file-status"> <div class="file-name">
<el-link 标题:{{ JSON.parse(msg.content).title }}
type="primary" </div>
:underline="false" <div class="file-size">
@click="handleOpenNotify(msg)" 内容:{{ JSON.parse(msg.content).content }}
> </div>
进入阅读 <div class="file-status">
</el-link> <el-link
type="primary"
:underline="false"
@click="handleOpenNotify(msg)"
>
进入阅读
</el-link>
</div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> <!-- 消息状态 -->
<!-- 消息状态 --> <div v-if="msg.is_self" class="message-status">
<div v-if="msg.is_self" class="message-status"> <span v-if="msg.sending" class="status-sending">发送中...</span>
<span v-if="msg.sending" class="status-sending">发送中...</span> <span v-else-if="msg.sendFailed" class="status-failed"
<span v-else-if="msg.sendFailed" class="status-failed" ><i class="el-icon-warning" /> 失败</span
><i class="el-icon-warning" /> 失败</span >
>
<span <span
v-else-if="msg.read_status === 1 || msg.read" v-if="
class="status-read" currentChat.scene === ContactsScene.GROUP &&
> currentChat.user_num - msg.read_user_ids.length != 0
已读 "
</span> class="status-read"
<span v-else class="status-unread">{{ >
currentChat.scene === 4 {{ currentChat.user_num - msg.read_user_ids.length }}人未读
? msg.unread_count </span>
? msg.unread_count + "人未读" <span
: "未读" v-else-if="
: "对方未读" currentChat.scene !== ContactsScene.GROUP &&
}}</span> msg.reader === 0
"
class="status-unread"
>
未读
</span>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -323,12 +365,15 @@ export default {
data() { data() {
return { return {
MessageType, MessageType,
ContactsScene,
loadingHistory: false, loadingHistory: false,
hasMoreHistory: true, hasMoreHistory: true,
loadingNewer: false, loadingNewer: false,
hasMoreNewer: true, hasMoreNewer: true,
scrollDebounceHistory: false,
scrollDebounceNewer: false,
baseMessageId: 0, baseMessageId: 0,
pageSize: 4, pageSize: 10,
previewVisible: false, previewVisible: false,
previewImageUrl: "", previewImageUrl: "",
isNearBottom: true, isNearBottom: true,
@ -380,12 +425,47 @@ export default {
this.setMessages({ key, messages: [] }); this.setMessages({ key, messages: [] });
// base_message_id 0 // base_message_id 0
await this.loadMessages({ up: 1, baseMessageId: 0 }); await this.loadMessages({ up: 1, baseMessageId: 0 });
//
await this.$nextTick();
await this.preloadHistoryMessages();
this.$nextTick(() => { this.$nextTick(() => {
this.scrollToBottom(); this.scrollToBottom();
}); });
this.markAsRead(); this.markAsRead();
}, },
async preloadHistoryMessages() {
const container = this.$refs.messageContainer;
if (!container) return;
const containerHeight = container.clientHeight;
let contentHeight = container.scrollHeight;
let prevHeight = 0;
let loadCount = 0;
const maxLoadCount = 10; // 10
//
while (
contentHeight < containerHeight &&
this.hasMoreHistory &&
!this.loadingHistory &&
loadCount < maxLoadCount
) {
prevHeight = contentHeight;
await this.loadMessages({ up: 1 });
await this.$nextTick();
contentHeight = container.scrollHeight;
loadCount++;
//
if (contentHeight === prevHeight) {
break;
}
}
},
// //
// up: 0 1 // up: 0 1
async loadMessages({ up, baseMessageId }) { async loadMessages({ up, baseMessageId }) {
@ -424,7 +504,7 @@ export default {
base_message_id: currentBaseMessageId, base_message_id: currentBaseMessageId,
page: 1, page: 1,
size: this.pageSize, size: this.pageSize,
up: up, up: 1,
target_id: this.currentChat.id, target_id: this.currentChat.id,
}; };
@ -453,12 +533,17 @@ export default {
const processed = list.map((m) => this.processMessage(m)); const processed = list.map((m) => this.processMessage(m));
let merged; let merged;
// ID
const existingIds = new Set(existing.map(m => m.message_id || m.id));
if (up === 0) { if (up === 0) {
// //
merged = [...existing, ...processed]; const newMessages = processed.filter(m => !existingIds.has(m.message_id || m.id));
merged = [...existing, ...newMessages];
} else { } else {
// //
merged = [...processed, ...existing]; const newMessages = processed.filter(m => !existingIds.has(m.message_id || m.id));
merged = [...newMessages, ...existing];
} }
this.setMessages({ key, messages: merged }); this.setMessages({ key, messages: merged });
@ -486,25 +571,30 @@ export default {
handleScroll(e) { handleScroll(e) {
const el = e.target; const el = e.target;
const scrollTop = el.scrollTop; const scrollTop = el.scrollTop;
const clientHeight = el.clientHeight;
const scrollHeight = el.scrollHeight; const scrollHeight = el.scrollHeight;
const isNearBottom = scrollTop + clientHeight >= scrollHeight - 50;
const isNearTop = scrollTop <= 30; const isNearTop = scrollTop <= 30;
//
if (isNearBottom && this.hasMoreNewer && !this.loadingNewer) {
this.loadMessages({ up: 1 });
}
// //
if (isNearTop && this.hasMoreHistory && !this.loadingHistory) { if (
isNearTop &&
this.hasMoreHistory &&
!this.loadingHistory &&
!this.scrollDebounceHistory
) {
this.scrollDebounceHistory = true;
const oldHeight = scrollHeight; const oldHeight = scrollHeight;
this.loadMessages({ up: 1 }).then(() => { this.loadMessages({ up: 1 })
this.$nextTick(() => { .then(() => {
const newHeight = el.scrollHeight; this.$nextTick(() => {
el.scrollTop = newHeight - oldHeight; const newHeight = el.scrollHeight;
el.scrollTop = newHeight - oldHeight;
});
})
.finally(() => {
setTimeout(() => {
this.scrollDebounceHistory = false;
}, 1000);
}); });
});
} }
}, },
@ -645,7 +735,11 @@ export default {
// //
handleDownload(item) { handleDownload(item) {
if (item.file_path) { if (item.file_path) {
window.open(this.$store.state.user.netConfig.MINIO_ENDPOINT_HTTPS + item.file_path, "_blank"); window.open(
this.$store.state.user.netConfig.MINIO_ENDPOINT_HTTPS +
item.file_path,
"_blank"
);
} else { } else {
this.$message.warning("文件链接不可用"); this.$message.warning("文件链接不可用");
} }
@ -656,7 +750,9 @@ export default {
this.$modal.msg("浏览器安全限制:请下载文件后在下载列表中打开文件夹"); this.$modal.msg("浏览器安全限制:请下载文件后在下载列表中打开文件夹");
// //
const a = document.createElement("a"); const a = document.createElement("a");
a.href = this.$store.state.user.netConfig.MINIO_ENDPOINT_HTTPS + item.file_path; a.href =
this.$store.state.user.netConfig.MINIO_ENDPOINT_HTTPS +
item.file_path;
a.download = item.file_name; a.download = item.file_name;
a.target = "_blank"; a.target = "_blank";
document.body.appendChild(a); document.body.appendChild(a);
@ -680,10 +776,11 @@ export default {
}, },
handleOpenKnowledge(msg) { handleOpenKnowledge(msg) {
const knowledgeId = msg.payload.knowledge_id; window.open(
if (knowledgeId) { this.$store.state.user.netConfig.MINIO_ENDPOINT_HTTPS +
this.$router.push(`/knowledge-base?id=${knowledgeId}`); JSON.parse(msg.content).file_path,
} "_blank"
);
}, },
handleOpenConsultationInvite(msg) { handleOpenConsultationInvite(msg) {
this.$router.push({ this.$router.push({
@ -754,6 +851,7 @@ export default {
}); });
} }
this.$emit("clear-unread", this.currentChat.id, scene); this.$emit("clear-unread", this.currentChat.id, scene);
this.$emit("refresh-list");
} catch (e) { } catch (e) {
console.error("标记已读失败", e); console.error("标记已读失败", e);
} }

File diff suppressed because it is too large Load Diff

@ -286,14 +286,15 @@ export default {
}); });
const contacts = res.data?.list || res.data || []; const contacts = res.data?.list || res.data || [];
this.setLatestContacts(contacts); this.setLatestContacts(contacts);
if (selectFirst && contacts.length > 0) { if (selectFirst && contacts.length > 0) {
// //
this.handleSelectContact(contacts[0]); this.handleSelectContact(contacts[0]);
} else if (keepCurrent && currentChatBackup && contacts.length > 0) { } else if (keepCurrent && currentChatBackup && contacts.length > 0) {
// //
const found = contacts.find( const found = contacts.find(
(c) => c.id === currentChatBackup.id && c.scene === currentChatBackup.scene (c) =>
c.id === currentChatBackup.id &&
c.scene === currentChatBackup.scene
); );
if (found) { if (found) {
this.handleSelectContact(found); this.handleSelectContact(found);
@ -454,6 +455,26 @@ export default {
return `${contact.source_name || "成员"}加入了群聊`; return `${contact.source_name || "成员"}加入了群聊`;
} }
}, },
[MessageType.MULTI_CHAT_JOIN]: () => {
try {
const payload =
typeof lastMsg.content === "string"
? JSON.parse(lastMsg.content)
: lastMsg.content;
const userIds = payload?.invited_user_ids || [];
if (userIds.length > 0) {
return `${contact.source_name || "成员"}邀请了${
userIds.length
}人加入群聊`;
}
return `${contact.source_name || "成员"}加入了群聊`;
} catch (e) {
return `${contact.source_name || "成员"}加入了群聊`;
}
},
[MessageType.MULTI_CHAT_EDIT]: () =>
(contact.source_name || "未知用户") +
`修改了群名为"${JSON.parse(lastMsg.content).name || ""}"`,
[MessageType.MULTI_CHAT_JOIN]: () => [MessageType.MULTI_CHAT_JOIN]: () =>
`${contact.source_name || "成员"}加入了群聊`, `${contact.source_name || "成员"}加入了群聊`,
[MessageType.MULTI_CHAT_QUIT]: () => [MessageType.MULTI_CHAT_QUIT]: () =>

@ -13,7 +13,15 @@
<div class="category-tabs"> <div class="category-tabs">
<el-tabs v-model="activeTab" @tab-click="handleTabClick"> <el-tabs v-model="activeTab" @tab-click="handleTabClick">
<el-tab-pane label="图片" name="image" /> <el-tab-pane label="图片" name="image" />
<el-tab-pane label="聊天记录" name="chat" /> <el-tab-pane label="聊天记录" name="chat">
<el-input
v-model="searchKeyword"
placeholder="搜索"
class="search-input"
@input="handleSearch"
prefix-icon="el-icon-search"
/>
</el-tab-pane>
</el-tabs> </el-tabs>
</div> </div>
@ -33,18 +41,13 @@
<!-- 聊天记录布局 --> <!-- 聊天记录布局 -->
<div v-else> <div v-else>
<div class="search-header">
<el-input
v-model="searchKeyword"
placeholder="搜索"
class="search-input"
@input="handleSearch"
prefix-icon="el-icon-search"
/>
</div>
<div class="chat-list"> <div class="chat-list">
<!-- 根据 identity 类型匹配用户信息 --> <!-- 根据 identity 类型匹配用户信息 -->
<div v-for="(item, index) in list" :key="item.id || index" class="result-item"> <div
v-for="(item, index) in list"
:key="item.id || index"
class="result-item"
>
<el-avatar <el-avatar
:size="40" :size="40"
:src="getImgUrl(item.sender_avatar)" :src="getImgUrl(item.sender_avatar)"
@ -53,12 +56,18 @@
{{ getFirstChar(item.sender_name) }} {{ getFirstChar(item.sender_name) }}
</el-avatar> </el-avatar>
<div class="result-content"> <div class="result-content">
<div class="result-name">{{ item.sender_name || '未知用户' }}</div> <div class="result-name">
<div v-if="item.file_type === 'image'" class="result-text">[图片]</div> {{ item.sender_name || "未知用户" }}
<div v-else class="result-text">{{ item.content || '' }}</div> </div>
<div v-if="item.file_type === 'image'" class="result-text">
[图片]
</div>
<div v-else class="result-text">{{ item.content || "" }}</div>
</div> </div>
<div class="result-right"> <div class="result-right">
<div class="result-time">{{ item.create_time || item.update_time || '' }}</div> <div class="result-time">
{{ item.create_time || item.update_time || "" }}
</div>
</div> </div>
</div> </div>
</div> </div>
@ -96,7 +105,7 @@ export default {
query: {}, query: {},
list: [], list: [],
page: 1, page: 1,
size: 60, size: 10,
loadingMore: false, loadingMore: false,
isNoMore: false, isNoMore: false,
// //
@ -179,7 +188,8 @@ export default {
const data = res.data.list || []; const data = res.data.list || [];
// //
const processedData = await this.processMessagesWithUserInfo(data); const processedData = await this.processMessagesWithUserInfo(data);
this.list = this.page === 1 ? processedData : [...this.list, ...processedData]; this.list =
this.page === 1 ? processedData : [...this.list, ...processedData];
if (data.length < this.size) { if (data.length < this.size) {
this.isNoMore = true; this.isNoMore = true;
} }
@ -296,15 +306,6 @@ export default {
flex-direction: column; flex-direction: column;
} }
.search-header {
padding: 10px 0;
border-bottom: 1px solid #eee;
}
.search-input {
width: 100%;
}
.category-tabs { .category-tabs {
padding: 10px 0; padding: 10px 0;
border-bottom: 1px solid #eee; border-bottom: 1px solid #eee;

@ -7,10 +7,12 @@
@clear-unread="handleClearUnread" @clear-unread="handleClearUnread"
@send-files="handleSendFiles" @send-files="handleSendFiles"
@group-setting="handleGroupSetting" @group-setting="handleGroupSetting"
@refresh-list="handleRefreshList"
/> />
<MessageEditor <MessageEditor
ref="messageEditor" ref="messageEditor"
:group-info="groupInfo"
@send-message="handleSendMessage" @send-message="handleSendMessage"
@update-message-status="handleUpdateMessageStatus" @update-message-status="handleUpdateMessageStatus"
/> />
@ -20,6 +22,7 @@
<GroupSetting <GroupSetting
ref="groupSettingRef" ref="groupSettingRef"
:chat="currentChat" :chat="currentChat"
:group-info="groupInfo"
@quit-group="handleQuitGroup" @quit-group="handleQuitGroup"
@dismiss-group="handleDismissGroup" @dismiss-group="handleDismissGroup"
@refresh-list="handleRefreshList" @refresh-list="handleRefreshList"
@ -33,7 +36,7 @@ import MessageList from "./components/MessageList.vue";
import MessageDisplay from "./components/MessageDisplay.vue"; import MessageDisplay from "./components/MessageDisplay.vue";
import GroupSetting from "./components/GroupSetting.vue"; import GroupSetting from "./components/GroupSetting.vue";
import MessageEditor from "./components/MessageEditor.vue"; import MessageEditor from "./components/MessageEditor.vue";
import { getMultiChatInfo, editMultiChatName } from '@/api/multichat' import { getMultiChatInfo, editMultiChatName } from "@/api/multichat";
import { MessageType, ContactsScene, MqttTopics } from "@/utils/constants"; import { MessageType, ContactsScene, MqttTopics } from "@/utils/constants";
export default { export default {
@ -48,6 +51,7 @@ export default {
data() { data() {
return { return {
groupInfo: null,
}; };
}, },
@ -300,8 +304,15 @@ export default {
handleSelectContact(contact) { handleSelectContact(contact) {
// MQTT // MQTT
if (contact.scene === ContactsScene.GROUP) { if (contact.scene == ContactsScene.GROUP) {
this.subscribe(MqttTopics.MULTI_CHAT + contact.id); this.subscribe(MqttTopics.MULTI_CHAT + contact.id);
//
getMultiChatInfo({ multi_chat_id: contact.id }).then((res) => {
this.groupInfo = res.data || null;
});
//
} else {
this.groupInfo = null;
} }
}, },

Loading…
Cancel
Save