From d6851d72f2dd87913a33e5abae33a47d09dffc78 Mon Sep 17 00:00:00 2001
From: wangdongbo <949818794@qq.com>
Date: Fri, 30 Jan 2026 13:52:35 +0800
Subject: [PATCH] IM
---
pages/message/chat.scss | 70 +++++
pages/message/components/message-header.vue | 317 ++++++++++++++++++++
pages/message/index.vue | 71 ++++-
pages/message/message.vue | 282 +++--------------
static/zhuanhua.svg | 1 +
utils/conversation-merger.js | 13 +-
6 files changed, 505 insertions(+), 249 deletions(-)
create mode 100644 pages/message/components/message-header.vue
create mode 100644 static/zhuanhua.svg
diff --git a/pages/message/chat.scss b/pages/message/chat.scss
index a5f27fb..11736c7 100644
--- a/pages/message/chat.scss
+++ b/pages/message/chat.scss
@@ -16,6 +16,76 @@ $primary-color: #0877F1;
background-color: #f5f5f5;
}
+/* 患者信息栏样式 */
+.patient-info-bar {
+ position: relative;
+ background: #fff;
+ border-bottom: 1rpx solid #f0f0f0;
+ padding: 20rpx 32rpx;
+ z-index: 10;
+ flex-shrink: 0; /* 防止被压缩 */
+}
+
+.patient-info-content {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+}
+
+.patient-basic-info {
+ display: flex;
+ align-items: center;
+ gap: 16rpx;
+ flex: 1;
+ min-width: 0; /* 允许文字截断 */
+}
+
+.patient-name {
+ font-size: 32rpx;
+ color: #333;
+ font-weight: 600;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ max-width: 200rpx;
+}
+
+.patient-detail {
+ font-size: 28rpx;
+ color: #999;
+ white-space: nowrap;
+ flex-shrink: 0;
+}
+
+.patient-detail-btn {
+ display: flex;
+ align-items: center;
+ gap: 4rpx;
+ padding: 12rpx 24rpx;
+ background: linear-gradient(270deg, #1b5cc8 2.26%, #0877f1 94.33%);
+ border-radius: 40rpx;
+ transition: all 0.2s;
+ flex-shrink: 0; /* 防止按钮被压缩 */
+}
+
+.patient-detail-btn:active {
+ opacity: 0.8;
+ transform: scale(0.98);
+}
+
+.detail-btn-text {
+ font-size: 26rpx;
+ color: #fff;
+ font-weight: 500;
+}
+
+.arrow-icon {
+ font-size: 32rpx;
+ color: #fff;
+ font-weight: 600;
+ line-height: 1;
+}
+
.chat-content {
flex: 1;
box-sizing: border-box;
diff --git a/pages/message/components/message-header.vue b/pages/message/components/message-header.vue
new file mode 100644
index 0000000..1cf3a52
--- /dev/null
+++ b/pages/message/components/message-header.vue
@@ -0,0 +1,317 @@
+
+
+
+
+
+
+
diff --git a/pages/message/index.vue b/pages/message/index.vue
index 210933e..5357584 100644
--- a/pages/message/index.vue
+++ b/pages/message/index.vue
@@ -1,5 +1,18 @@
+
+
+
+
+ {{ patientInfo.name }}
+ {{ patientInfo.sex }} · {{ patientInfo.age }}岁
+
+
+ 查看档案
+
+
+
+
{
+const updateNavigationTitle = (title = "群聊") => {
uni.setNavigationBarTitle({
- title: "群聊",
+ title: title,
});
};
@@ -222,6 +239,14 @@ const isEvaluationPopupOpen = ref(false);
// 订单状态
const orderStatus = ref("");
+// 患者信息
+const patientInfo = ref({
+ name: "",
+ sex: "",
+ age: "",
+ mobile: "",
+});
+
// 计算弹框显示状态 - 只有 pending 状态才显示接受问诊组件
const showConsultAccept = computed(() => orderStatus.value === "pending");
@@ -281,8 +306,25 @@ const fetchGroupOrderStatus = async () => {
if (result.success && result.data) {
orderStatus.value = result.data.orderStatus || "";
+
+ // 更新导航栏标题为团队名称
+ const teamName = result.data.team?.name || "群聊";
+ updateNavigationTitle(teamName);
+
+ // 更新患者信息
+ if (result.data.patient) {
+ patientInfo.value = {
+ name: result.data.patient.name || "",
+ sex: result.data.patient.sex || "",
+ age: result.data.patient.age || "",
+ mobile: result.data.patient.mobile || "",
+ };
+ }
+
console.log("获取群组订单状态:", {
orderStatus: orderStatus.value,
+ teamName: teamName,
+ patientInfo: patientInfo.value,
groupId: groupId.value,
});
} else {
@@ -401,7 +443,11 @@ const initTIMCallbacks = async () => {
});
// 立即标记会话为已读,确保未读数为0
- if (timChatManager.tim && timChatManager.isLoggedIn && chatInfo.value.conversationID) {
+ if (
+ timChatManager.tim &&
+ timChatManager.isLoggedIn &&
+ chatInfo.value.conversationID
+ ) {
timChatManager.tim
.setMessageRead({
conversationID: chatInfo.value.conversationID,
@@ -409,9 +455,9 @@ const initTIMCallbacks = async () => {
.then(() => {
console.log("✓ 收到新消息后已标记为已读");
// 触发会话列表更新,确保未读数为0
- timChatManager.triggerCallback('onConversationListUpdated', {
+ timChatManager.triggerCallback("onConversationListUpdated", {
conversationID: chatInfo.value.conversationID,
- unreadCount: 0
+ unreadCount: 0,
});
})
.catch((error) => {
@@ -570,9 +616,9 @@ const loadMessageList = async () => {
.then(() => {
console.log("✓ 会话已标记为已读:", chatInfo.value.conversationID);
// 触发会话列表更新回调,通知消息列表页面清空未读数
- timChatManager.triggerCallback('onConversationListUpdated', {
+ timChatManager.triggerCallback("onConversationListUpdated", {
conversationID: chatInfo.value.conversationID,
- unreadCount: 0
+ unreadCount: 0,
});
})
.catch((error) => {
@@ -851,6 +897,15 @@ const handleRejectReasonConfirm = async (reason) => {
const handleRejectReasonCancel = () => {
showRejectReasonModal.value = false;
};
+
+// 处理查看患者详情
+const handleViewPatientDetail = () => {
+ // TODO: 跳转到患者详情页面
+ uni.showToast({
+ title: "患者详情功能开发中",
+ icon: "none",
+ });
+};
// 处理结束问诊
const handleEndConsult = async () => {
try {
diff --git a/pages/message/message.vue b/pages/message/message.vue
index 8908c6e..872161d 100644
--- a/pages/message/message.vue
+++ b/pages/message/message.vue
@@ -1,53 +1,11 @@
-
-
-
-
-
-
- 处理中
-
-
-
- 已结束
-
-
-
-
-
-
-
-
-
-
- {{ team.name }}
- ✓
-
-
-
-
+
+
{
- // 在团队列表前添加"全部会话消息"选项
- const allOption = { _id: "", name: "全部会话消息" };
- return [allOption, ...(teams.value || [])];
-});
-const currentTeamName = computed(() => {
- if (!currentTeamId.value) return "全部会话消息";
- const team = teams.value.find((t) => t._id === currentTeamId.value);
- return team ? team.name : "全部会话消息";
-});
// 监听 IM 初始化状态
watch(isIMInitialized, (newValue) => {
@@ -177,7 +128,7 @@ const activeTab = ref("processing");
// 根据 orderStatus 过滤会话列表
const filteredConversationList = computed(() => {
let filtered = [];
-
+
if (activeTab.value === "processing") {
// 处理中:pending(待处理) 和 processing(处理中)
filtered = conversationList.value.filter(
@@ -198,23 +149,21 @@ const filteredConversationList = computed(() => {
if (currentTeamId.value) {
filtered = filtered.filter((conv) => conv.teamId === currentTeamId.value);
}
-
return filtered;
});
-// 选择团队
-const selectTeam = (team) => {
- currentTeamId.value = team._id;
- showTeamPicker.value = false;
- console.log("切换到团队:", team.name);
+// 处理团队切换
+const handleTeamChange = (teamId) => {
+ currentTeamId.value = teamId;
+ console.log("切换到团队ID:", teamId);
};
-// 切换标签页
-const switchTab = (tab) => {
- if (activeTab.value === tab) return;
- activeTab.value = tab;
- console.log("切换到标签页:", tab);
-};
+// 邀请患者 - 使用 withInfo 包装,确保信息完善后才能使用
+const handleAddPatient = withInfo(() => {
+ uni.navigateTo({
+ url: "/pages/work/team/invite/invite-patient",
+ });
+});
// 初始化IM
const initIM = async () => {
@@ -381,7 +330,10 @@ const setupConversationListener = () => {
// 保持原有头像,避免闪动
avatar: existing.avatar || conversationData.avatar,
// 保留较大的未读数(避免被后端数据覆盖)
- unreadCount: Math.max(existing.unreadCount || 0, conversationData.unreadCount || 0)
+ unreadCount: Math.max(
+ existing.unreadCount || 0,
+ conversationData.unreadCount || 0
+ ),
};
needSort = true;
console.log(
@@ -421,11 +373,11 @@ const setupConversationListener = () => {
// 检查当前页面栈,判断用户是否正在查看该会话的聊天详情页
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];
-
+
// 获取当前页面的 groupID 参数(如果在聊天详情页)
const currentGroupID = currentPage?.options?.groupID;
- const isViewingThisConversation =
- currentPage?.route === "pages/message/index" &&
+ const isViewingThisConversation =
+ currentPage?.route === "pages/message/index" &&
currentGroupID === conversation.groupID;
// 如果用户正在查看这个具体的会话,不增加未读数
@@ -562,7 +514,7 @@ onShow(async () => {
try {
// 加载团队列表
await getTeams();
-
+
// 初始化IM
const imReady = await initIM();
if (!imReady) {
@@ -606,151 +558,6 @@ onHide(() => {
flex-direction: column;
}
-.header-container {
- background-color: #fff;
- padding: 20rpx 32rpx;
- border-bottom: 1rpx solid #f0f0f0;
- flex-shrink: 0;
-}
-
-.team-selector {
- display: flex;
- align-items: center;
- cursor: pointer;
-
- &:active {
- opacity: 0.7;
- }
-}
-
-.team-name {
- font-size: 36rpx;
- font-weight: 500;
- color: #333;
- flex: 1;
-}
-
-.arrow-icon {
- font-size: 20rpx;
- color: #999;
- margin-left: 12rpx;
- transform: scale(0.8);
-}
-
-.team-picker-overlay {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background-color: rgba(0, 0, 0, 0.5);
- z-index: 1000;
- display: flex;
- align-items: flex-start;
- justify-content: center;
- padding-top: 200rpx;
-}
-
-.team-picker-content {
- width: 600rpx;
- max-height: 800rpx;
- background-color: #fff;
- border-radius: 16rpx;
- overflow: hidden;
- display: flex;
- flex-direction: column;
-}
-
-.team-picker-header {
- padding: 32rpx;
- border-bottom: 1rpx solid #f0f0f0;
- text-align: center;
-}
-
-.picker-title {
- font-size: 36rpx;
- font-weight: 500;
- color: #333;
-}
-
-.team-list {
- flex: 1;
- overflow-y: auto;
-}
-
-.team-item {
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 32rpx;
- border-bottom: 1rpx solid #f0f0f0;
- cursor: pointer;
-
- &:active {
- background-color: #f5f5f5;
- }
-
- &.active {
- background-color: #e6f7ff;
-
- .team-item-name {
- color: #1890ff;
- }
- }
-}
-
-.team-item-name {
- font-size: 32rpx;
- color: #333;
- flex: 1;
-}
-
-.check-icon {
- font-size: 36rpx;
- color: #1890ff;
- font-weight: bold;
-}
-
-.tabs-container {
- display: flex;
- background-color: #fff;
- border-bottom: 1rpx solid #f0f0f0;
- flex-shrink: 0;
-}
-
-.tab-item {
- flex: 1;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- padding: 28rpx 0;
- position: relative;
- cursor: pointer;
-
- &.active {
- .tab-text {
- color: #1890ff;
- font-weight: 500;
- }
- }
-}
-
-.tab-text {
- font-size: 32rpx;
- color: #666;
- transition: color 0.3s;
-}
-
-.tab-indicator {
- position: absolute;
- bottom: 0;
- width: 60rpx;
- height: 6rpx;
- background-color: #1890ff;
- border-radius: 3rpx;
-}
-
.message-list {
width: 100%;
flex: 1;
@@ -784,7 +591,7 @@ onHide(() => {
.message-item {
display: flex;
align-items: center;
- padding: 10rpx 32rpx;
+ padding: 24rpx 32rpx;
background-color: #fff;
border-bottom: 1rpx solid #f0f0f0;
@@ -796,6 +603,7 @@ onHide(() => {
.avatar-container {
position: relative;
margin-right: 24rpx;
+ flex-shrink: 0;
}
.avatar {
@@ -839,14 +647,28 @@ onHide(() => {
margin-bottom: 8rpx;
}
+.name-info {
+ display: flex;
+ align-items: center;
+ flex: 1;
+ min-width: 0;
+}
+
.name {
- font-size: 32rpx;
+ font-size: 30rpx;
font-weight: 500;
color: #333;
- flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
+ flex-shrink: 1;
+}
+
+.patient-info {
+ font-size: 26rpx;
+ padding-left: 12rpx;
+ color: #999;
+ flex-shrink: 0;
}
.time {
@@ -862,7 +684,7 @@ onHide(() => {
}
.preview-text {
- font-size: 28rpx;
+ font-size: 26rpx;
color: #999;
overflow: hidden;
text-overflow: ellipsis;
@@ -878,10 +700,4 @@ onHide(() => {
font-size: 24rpx;
color: #999;
}
-
-.patient-info {
- font-size: 28rpx;
- padding-left: 10rpx;
- color: #999;
-}
diff --git a/static/zhuanhua.svg b/static/zhuanhua.svg
new file mode 100644
index 0000000..061cbf5
--- /dev/null
+++ b/static/zhuanhua.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/utils/conversation-merger.js b/utils/conversation-merger.js
index f5c59a2..ddeb727 100644
--- a/utils/conversation-merger.js
+++ b/utils/conversation-merger.js
@@ -60,19 +60,19 @@ export async function mergeConversationWithGroupDetails(conversationList, option
const formattedList = mergedList
.map((group) => ({
conversationID: group.conversationID || `GROUP${group.groupID}`,
- groupID: group.groupID,
- name: group.patientName
- ? `${group.patientName}的问诊`
- : group.name || "问诊群聊",
avatar: group.avatar || "/static/default-avatar.png",
lastMessage: group.lastMessage || "暂无消息",
lastMessageTime: group.lastMessageTime || Date.now(),
+ groupID: group.groupID,
unreadCount: group.unreadCount || 0,
doctorId: group.doctorId,
patientName: group.patientName,
patientSex: group.patientSex,
patientAge: group.patientAge,
orderStatus: group.orderStatus,
+ teamId: group.teamId,
+ teamName: group.teamName,
+ teamMemberList: group.teamMemberList,
}))
.sort((a, b) => b.lastMessageTime - a.lastMessageTime)
@@ -123,9 +123,6 @@ function mergeConversationData(conversation, groupDetailsMap) {
return {
// 保留原有的会话信息
...conversation,
-
- // 合并后端的群组信息
- _id: groupDetail._id,
corpId: groupDetail.corpId,
teamId: groupDetail.teamId,
customerId: groupDetail.customerId,
@@ -144,7 +141,7 @@ function mergeConversationData(conversation, groupDetailsMap) {
teamName: groupDetail.team?.name,
teamMemberList: groupDetail.team?.memberList,
teamDescription: groupDetail.team?.description,
-
+ teamId: groupDetail.teamId,
// 时间信息
createdAt: groupDetail.createdAt,
updatedAt: groupDetail.updatedAt,