- {{ formatFileSize(msg.file_size) }}
+
+
+
+
+
-
-
- 打开
-
-
- 打开目录
-
+
+
{{ msg.file_name }}
+
+ {{ formatFileSize(msg.file_size) }}
+
+
+
+ 打开
+
+
+ 打开目录
+
+
-
-
-
- 病例分享: 姓名:{{ JSON.parse(msg.content).name }}, 年龄:{{
- JSON.parse(msg.content).age
- }}, 性别:{{ JSON.parse(msg.content).sex }},
-
+
- 病例ID:{{ JSON.parse(msg.content).report_id }}
-
-
+ 病例分享: 姓名:{{ JSON.parse(msg.content).name }}, 年龄:{{
+ JSON.parse(msg.content).age
+ }}, 性别:{{ JSON.parse(msg.content).sex }},
+
+ 病例ID:{{ JSON.parse(msg.content).report_id }}
+
+
-
-
- 知识库分享:
-
+
- 资源名称:{{ JSON.parse(msg.content).file_name }}
-
-
-
- 视讯邀请:{{ JSON.parse(msg.content).name }}邀请您参加会诊
-
+ 资源名称:{{ JSON.parse(msg.content).file_name }}
+
+
+
- 会诊口令:{{ JSON.parse(msg.content).room_id }}
-
-
-
-
-
-
-
- 标题:{{ JSON.parse(msg.content).title }}
-
-
- 内容:{{ JSON.parse(msg.content).content }}
-
-
-
- 进入阅读
-
+ 视讯邀请:{{ JSON.parse(msg.content).name }}邀请您参加会诊
+
+ 会诊口令:{{ JSON.parse(msg.content).room_id }}
+
+
+
+
+
+
+
+ 标题:{{ JSON.parse(msg.content).title }}
+
+
+ 内容:{{ JSON.parse(msg.content).content }}
+
+
+
+ 进入阅读
+
+
-
-
-
-
发送中...
-
失败
-
- 已读
-
-
{{
- currentChat.scene === 4
- ? msg.unread_count
- ? msg.unread_count + "人未读"
- : "未读"
- : "对方未读"
- }}
+
+
+ 发送中...
+ 失败
+
+
+ {{ currentChat.user_num - msg.read_user_ids.length }}人未读
+
+
+ 未读
+
+
@@ -323,12 +365,15 @@ export default {
data() {
return {
MessageType,
+ ContactsScene,
loadingHistory: false,
hasMoreHistory: true,
loadingNewer: false,
hasMoreNewer: true,
+ scrollDebounceHistory: false,
+ scrollDebounceNewer: false,
baseMessageId: 0,
- pageSize: 4,
+ pageSize: 10,
previewVisible: false,
previewImageUrl: "",
isNearBottom: true,
@@ -380,12 +425,47 @@ export default {
this.setMessages({ key, messages: [] });
// 默认 base_message_id 为 0,加载最新消息
await this.loadMessages({ up: 1, baseMessageId: 0 });
+
+ // 自动加载历史消息直到填满可视区域
+ await this.$nextTick();
+ await this.preloadHistoryMessages();
+
this.$nextTick(() => {
this.scrollToBottom();
});
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 表示加载历史消息(向上滚动)
async loadMessages({ up, baseMessageId }) {
@@ -424,7 +504,7 @@ export default {
base_message_id: currentBaseMessageId,
page: 1,
size: this.pageSize,
- up: up,
+ up: 1,
target_id: this.currentChat.id,
};
@@ -453,12 +533,17 @@ export default {
const processed = list.map((m) => this.processMessage(m));
let merged;
+ // 创建已存在消息ID的集合用于去重
+ const existingIds = new Set(existing.map(m => m.message_id || m.id));
+
if (up === 0) {
// 加载更新消息:追加到尾部
- merged = [...existing, ...processed];
+ const newMessages = processed.filter(m => !existingIds.has(m.message_id || m.id));
+ merged = [...existing, ...newMessages];
} else {
// 加载历史消息:插入到头部
- merged = [...processed, ...existing];
+ const newMessages = processed.filter(m => !existingIds.has(m.message_id || m.id));
+ merged = [...newMessages, ...existing];
}
this.setMessages({ key, messages: merged });
@@ -486,25 +571,30 @@ export default {
handleScroll(e) {
const el = e.target;
const scrollTop = el.scrollTop;
- const clientHeight = el.clientHeight;
const scrollHeight = el.scrollHeight;
- const isNearBottom = scrollTop + clientHeight >= scrollHeight - 50;
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;
- this.loadMessages({ up: 1 }).then(() => {
- this.$nextTick(() => {
- const newHeight = el.scrollHeight;
- el.scrollTop = newHeight - oldHeight;
+ this.loadMessages({ up: 1 })
+ .then(() => {
+ this.$nextTick(() => {
+ const newHeight = el.scrollHeight;
+ el.scrollTop = newHeight - oldHeight;
+ });
+ })
+ .finally(() => {
+ setTimeout(() => {
+ this.scrollDebounceHistory = false;
+ }, 1000);
});
- });
}
},
@@ -645,7 +735,11 @@ export default {
// 下载文件
handleDownload(item) {
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 {
this.$message.warning("文件链接不可用");
}
@@ -656,7 +750,9 @@ export default {
this.$modal.msg("浏览器安全限制:请下载文件后在下载列表中打开文件夹");
// 先触发下载
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.target = "_blank";
document.body.appendChild(a);
@@ -680,10 +776,11 @@ export default {
},
handleOpenKnowledge(msg) {
- const knowledgeId = msg.payload.knowledge_id;
- if (knowledgeId) {
- this.$router.push(`/knowledge-base?id=${knowledgeId}`);
- }
+ window.open(
+ this.$store.state.user.netConfig.MINIO_ENDPOINT_HTTPS +
+ JSON.parse(msg.content).file_path,
+ "_blank"
+ );
},
handleOpenConsultationInvite(msg) {
this.$router.push({
@@ -754,6 +851,7 @@ export default {
});
}
this.$emit("clear-unread", this.currentChat.id, scene);
+ this.$emit("refresh-list");
} catch (e) {
console.error("标记已读失败", e);
}
diff --git a/src/views/message/components/MessageEditor.vue b/src/views/message/components/MessageEditor.vue
index 1a65c72..be7970c 100644
--- a/src/views/message/components/MessageEditor.vue
+++ b/src/views/message/components/MessageEditor.vue
@@ -2,195 +2,144 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
-
- {{ user.name }}
-
-
- 无匹配成员
-
+ 发送
+
+
+
+ {{ sendModeLabel }}
+
+
+
+ Enter发送
+ Ctrl+Enter发送
+
+
-
-
+
handleFileChange(e, 'file')"
/>
-
-
-
-
-
-
-
-
-
-
{{ currentChat.name || '通话中' }}
-
{{ callStatus }}
-
-
- {{ formatCallTime(callDuration) }}
-
-
-
- {{ videoEnabled ? '关闭摄像头' : '开启摄像头' }}
-
-
- {{ micEnabled ? '静音' : '取消静音' }}
-
-
- 结束通话
-
-
-
-