Compare commits
No commits in common. "932ec63261d20bca7b811367d7aa1ab2abcee391" and "2fe645a8861042fbaf3cb8cfa67362bf84c3f53d" have entirely different histories.
932ec63261
...
2fe645a886
3
App.vue
3
App.vue
@ -1,7 +1,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import dbStore from "@/store/db";
|
import dbStore from "@/store/db";
|
||||||
import accountStore from "@/store/account";
|
import accountStore from "@/store/account";
|
||||||
import { globalUnreadListenerManager } from "@/utils/global-unread-listener.js";
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
async onLaunch() {
|
async onLaunch() {
|
||||||
@ -39,8 +38,6 @@ export default {
|
|||||||
const success = await account.initIMAfterLogin();
|
const success = await account.initIMAfterLogin();
|
||||||
if (success) {
|
if (success) {
|
||||||
console.log("IM 初始化成功");
|
console.log("IM 初始化成功");
|
||||||
// IM 初始化成功后,设置全局未读消息监听
|
|
||||||
globalUnreadListenerManager.setup();
|
|
||||||
} else {
|
} else {
|
||||||
console.warn("IM 初始化失败");
|
console.warn("IM 初始化失败");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,7 +25,7 @@ const props = defineProps({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const list = computed(() => props.avatarList.map(i => i || '/static/default-avatar.png'))
|
const list = computed(() => props.avatarList.map(i => i || '/static/default-avatar.svg'))
|
||||||
|
|
||||||
const size = computed(() => {
|
const size = computed(() => {
|
||||||
const val = Number.isInteger(props.size) && props.size > 0 ? props.size : 144;
|
const val = Number.isInteger(props.size) && props.size > 0 ? props.size : 144;
|
||||||
|
|||||||
@ -134,7 +134,6 @@ async function addArchive() {
|
|||||||
mobile: account.value.mobile,
|
mobile: account.value.mobile,
|
||||||
miniAppId: account.value.openid,
|
miniAppId: account.value.openid,
|
||||||
externalUserId: externalUserId.value,
|
externalUserId: externalUserId.value,
|
||||||
realUnionid: account.value.unionid || '',
|
|
||||||
}
|
}
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
const res = await api('addCustomer', { params });
|
const res = await api('addCustomer', { params });
|
||||||
@ -155,7 +154,7 @@ async function bindArchive(customerId) {
|
|||||||
await toast('绑定成功');
|
await toast('绑定成功');
|
||||||
set('home-invite-teamId', teamId.value);
|
set('home-invite-teamId', teamId.value);
|
||||||
uni.switchTab({
|
uni.switchTab({
|
||||||
url: '/pages/home/home'
|
url:'/pages/home/home'
|
||||||
})
|
})
|
||||||
// uni.reLaunch({ url: `/pages/home/home?corpId=${corpId.value}&teamId=${teamId.value}` })
|
// uni.reLaunch({ url: `/pages/home/home?corpId=${corpId.value}&teamId=${teamId.value}` })
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -254,7 +254,7 @@ const selectCate = async (cateId) => {
|
|||||||
|
|
||||||
function goToDetail(item) {
|
function goToDetail(item) {
|
||||||
if (!item?._id) return;
|
if (!item?._id) return;
|
||||||
uni.navigateTo({ url: `/pages/article/article-detail?id=${item._id}&corpId=${corpId.value}` });
|
uni.navigateTo({ url: `/pages/article/article-detail?id=${item._id}` });
|
||||||
}
|
}
|
||||||
|
|
||||||
onLoad(async (options) => {
|
onLoad(async (options) => {
|
||||||
|
|||||||
@ -54,7 +54,7 @@ const articleIds = computed(() => {
|
|||||||
|
|
||||||
function goToDetail(article) {
|
function goToDetail(article) {
|
||||||
if (!article?._id) return;
|
if (!article?._id) return;
|
||||||
uni.navigateTo({ url: `/pages/article/article-detail?id=${article._id}&corpId=${props.team.corpId}` });
|
uni.navigateTo({ url: `/pages/article/article-detail?id=${article._id}` });
|
||||||
}
|
}
|
||||||
|
|
||||||
const loadArticles = async () => {
|
const loadArticles = async () => {
|
||||||
|
|||||||
@ -20,7 +20,7 @@
|
|||||||
<yc-home v-else />
|
<yc-home v-else />
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, ref, watch } from "vue";
|
import { computed, ref } from "vue";
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from "pinia";
|
||||||
import { onLoad, onShow } from "@dcloudio/uni-app";
|
import { onLoad, onShow } from "@dcloudio/uni-app";
|
||||||
// import useGuard from "@/hooks/useGuard";
|
// import useGuard from "@/hooks/useGuard";
|
||||||
@ -103,13 +103,6 @@ onShow(async () => {
|
|||||||
teams.value = [];
|
teams.value = [];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
watch(account, (n, o) => {
|
|
||||||
if (n && !o) {
|
|
||||||
getTeams();
|
|
||||||
} else if (!n && o) {
|
|
||||||
teams.value = [];
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.home-container {
|
.home-container {
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
<view v-for="i in teamates" :key="i.userid"
|
<view v-for="i in teamates" :key="i.userid"
|
||||||
class="member-card flex flex-shrink-0 min-w-120 mr-15 p-15"
|
class="member-card flex flex-shrink-0 min-w-120 mr-15 p-15"
|
||||||
@click="toHomePage(i)">
|
@click="toHomePage(i)">
|
||||||
<image class="flex-shrink-0 avatar mr-10" :src="i.avatar || '/static/default-avatar.png'" />
|
<image class="flex-shrink-0 avatar mr-10" :src="i.avatar || '/static/default-avatar.svg'" />
|
||||||
<view class="flex-grow flex flex-col justify-between">
|
<view class="flex-grow flex flex-col justify-between">
|
||||||
<view>
|
<view>
|
||||||
<view class="member-name leading-normal h-24 text-base font-semibold text-dark whitespace-nowrap">
|
<view class="member-name leading-normal h-24 text-base font-semibold text-dark whitespace-nowrap">
|
||||||
|
|||||||
@ -6,24 +6,17 @@ $text-color-sub: #999;
|
|||||||
$primary-color: #0877F1;
|
$primary-color: #0877F1;
|
||||||
|
|
||||||
.chat-page {
|
.chat-page {
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
height: 100vh;
|
||||||
background-color: #f5f5f5;
|
background-color: #f5f5f5;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
transition: padding-bottom 0.25s cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 患者信息栏样式 */
|
/* 患者信息栏样式 */
|
||||||
.patient-info-bar {
|
.patient-info-bar {
|
||||||
position: fixed;
|
position: sticky;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-bottom: 1rpx solid #f0f0f0;
|
border-bottom: 1rpx solid #f0f0f0;
|
||||||
padding: 20rpx 32rpx;
|
padding: 20rpx 32rpx;
|
||||||
@ -117,15 +110,11 @@ $primary-color: #0877F1;
|
|||||||
}
|
}
|
||||||
|
|
||||||
.chat-content {
|
.chat-content {
|
||||||
position: fixed;
|
flex: 1;
|
||||||
top: 100rpx; /* 患者信息栏高度,根据实际调整 */
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 120rpx; /* 输入框高度,根据实际调整 */
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
transition: bottom 0.25s cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
min-height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-content-compressed {
|
.chat-content-compressed {
|
||||||
@ -390,24 +379,18 @@ $primary-color: #0877F1;
|
|||||||
}
|
}
|
||||||
|
|
||||||
.input-section {
|
.input-section {
|
||||||
position: fixed;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-top: 1rpx solid #e0e0e0;
|
border-top: 1rpx solid #e0e0e0;
|
||||||
|
position: relative;
|
||||||
z-index: 200;
|
z-index: 200;
|
||||||
|
padding-bottom: env(safe-area-inset-bottom);
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
transform: translateZ(0); /* 开启硬件加速,提升性能 */
|
|
||||||
transition: bottom 0.25s cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
|
||||||
will-change: bottom;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-toolbar {
|
.input-toolbar {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 12rpx 20rpx;
|
padding: 16rpx 20rpx;
|
||||||
padding-bottom: env(safe-area-inset-bottom);
|
|
||||||
gap: 12rpx;
|
gap: 12rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -513,8 +496,7 @@ $primary-color: #0877F1;
|
|||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-top: 1rpx solid #eee;
|
border-top: 1rpx solid #eee;
|
||||||
padding: 20rpx 0 20rpx 60rpx;
|
padding: 20rpx 0 40rpx 60rpx;
|
||||||
padding-bottom: env(safe-area-inset-bottom);
|
|
||||||
gap: 40rpx 50rpx;
|
gap: 40rpx 50rpx;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
background-color: #f5f5f5;
|
background-color: #f5f5f5;
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="input-section" :style="{ bottom: props.keyboardHeight + 'px' }">
|
<view class="input-section">
|
||||||
<view class="input-toolbar">
|
<view class="input-toolbar">
|
||||||
<view @click="toggleVoiceInput" class="voice-toggle-btn">
|
<view @click="toggleVoiceInput" class="voice-toggle-btn">
|
||||||
<image v-if="showVoiceInput" src="/static/jianpan.png" class="voice-toggle-icon" mode="aspectFit"></image>
|
<image v-if="showVoiceInput" src="/static/jianpan.png" class="voice-toggle-icon" mode="aspectFit"></image>
|
||||||
@ -8,7 +8,7 @@
|
|||||||
<view class="input-area">
|
<view class="input-area">
|
||||||
<textarea v-if="!showVoiceInput" class="text-input" v-model="inputText" placeholder="我来说两句..."
|
<textarea v-if="!showVoiceInput" class="text-input" v-model="inputText" placeholder="我来说两句..."
|
||||||
@confirm="sendTextMessage" @focus="handleInputFocus" @input="handleInput"
|
@confirm="sendTextMessage" @focus="handleInputFocus" @input="handleInput"
|
||||||
:auto-height="true" :show-confirm-bar="false" :adjust-position="false" :hold-keyboard="true" />
|
:auto-height="true" :show-confirm-bar="false" :adjust-position="true" :cursor-spacing="40" />
|
||||||
<input v-else class="voice-input-btn" :class="{ recording: isRecording }" @touchstart="startRecord"
|
<input v-else class="voice-input-btn" :class="{ recording: isRecording }" @touchstart="startRecord"
|
||||||
@touchmove="onRecordTouchMove" @touchend="stopRecord" @touchcancel="cancelRecord" :placeholder="isRecording ? '松开发送' : '按住说话'" disabled>
|
@touchmove="onRecordTouchMove" @touchend="stopRecord" @touchcancel="cancelRecord" :placeholder="isRecording ? '松开发送' : '按住说话'" disabled>
|
||||||
</input>
|
</input>
|
||||||
@ -77,7 +77,6 @@ const props = defineProps({
|
|||||||
groupId: { type: String, default: '' },
|
groupId: { type: String, default: '' },
|
||||||
userId: { type: String, default: '' },
|
userId: { type: String, default: '' },
|
||||||
corpId: { type: String, default: '' },
|
corpId: { type: String, default: '' },
|
||||||
keyboardHeight: { type: Number, default: 0 },
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Emits
|
// Emits
|
||||||
@ -151,15 +150,11 @@ const initRecorderManager = () => {
|
|||||||
const sendTextMessage = async () => {
|
const sendTextMessage = async () => {
|
||||||
if (!inputText.value.trim()) return;
|
if (!inputText.value.trim()) return;
|
||||||
|
|
||||||
const textToSend = inputText.value;
|
await sendMessage("text", inputText.value);
|
||||||
inputText.value = "";
|
inputText.value = "";
|
||||||
|
|
||||||
await sendMessage("text", textToSend);
|
// 收起键盘
|
||||||
|
uni.hideKeyboard();
|
||||||
// 发送后保持焦点,不收起键盘
|
|
||||||
nextTick(() => {
|
|
||||||
// hold-keyboard 属性会自动保持键盘显示
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ export default function useGroupAvatars() {
|
|||||||
const groupAvatarMap = ref({}) // { groupID: [avatarUrl1, avatarUrl2, ...] }
|
const groupAvatarMap = ref({}) // { groupID: [avatarUrl1, avatarUrl2, ...] }
|
||||||
const teamStore = useTeamStore()
|
const teamStore = useTeamStore()
|
||||||
const patientDefaultAvatar = '/static/default-patient-avatar.png'
|
const patientDefaultAvatar = '/static/default-patient-avatar.png'
|
||||||
const teamMemberDefaultAvatar = '/static/default-avatar.png'
|
const teamMemberDefaultAvatar = '/static/default-avatar.svg'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取单个群聊的头像列表
|
* 获取单个群聊的头像列表
|
||||||
@ -25,6 +25,7 @@ export default function useGroupAvatars() {
|
|||||||
console.warn(`群聊 ${groupID} 没有 teamId,无法获取头像`)
|
console.warn(`群聊 ${groupID} 没有 teamId,无法获取头像`)
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取团队成员的头像和名称
|
// 获取团队成员的头像和名称
|
||||||
const memberMap = await teamStore.getTeamMemberAvatarsAndName(teamId)
|
const memberMap = await teamStore.getTeamMemberAvatarsAndName(teamId)
|
||||||
|
|
||||||
|
|||||||
@ -47,7 +47,7 @@ export default function useGroupChat(groupID) {
|
|||||||
const getUserAvatar = (userId) => {
|
const getUserAvatar = (userId) => {
|
||||||
const member = chatMember.value[userId]
|
const member = chatMember.value[userId]
|
||||||
if (!member) {
|
if (!member) {
|
||||||
return userId === openid.value ? '/static/default-patient-avatar.png' : '/static/default-avatar.png'
|
return userId === openid.value ? '/static/default-patient-avatar.png' : '/static/default-avatar.svg'
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果有头像且不为空字符串,返回头像
|
// 如果有头像且不为空字符串,返回头像
|
||||||
@ -55,7 +55,7 @@ export default function useGroupChat(groupID) {
|
|||||||
return member.avatar
|
return member.avatar
|
||||||
}
|
}
|
||||||
|
|
||||||
return member.isTeamMember ? '/static/default-avatar.png' : '/static/default-patient-avatar.png'
|
return member.isTeamMember ? '/static/default-avatar.svg' : '/static/default-patient-avatar.png'
|
||||||
}
|
}
|
||||||
// 获取群聊信息和成员头像
|
// 获取群聊信息和成员头像
|
||||||
async function getGroupInfo() {
|
async function getGroupInfo() {
|
||||||
@ -76,7 +76,6 @@ export default function useGroupChat(groupID) {
|
|||||||
|
|
||||||
// 2. 如果有teamId,获取团队成员头像和名称
|
// 2. 如果有teamId,获取团队成员头像和名称
|
||||||
if (groupResult.data.teamId) {
|
if (groupResult.data.teamId) {
|
||||||
|
|
||||||
const memberMap = await teamStore.getTeamMemberAvatarsAndName(groupResult.data.teamId)
|
const memberMap = await teamStore.getTeamMemberAvatarsAndName(groupResult.data.teamId)
|
||||||
|
|
||||||
// 3. 存储团队成员ID列表
|
// 3. 存储团队成员ID列表
|
||||||
|
|||||||
@ -1,8 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<page-meta
|
<view class="chat-page">
|
||||||
:page-style="'overflow:' + (keyboardHeight > 0 ? 'hidden' : 'visible')"
|
|
||||||
></page-meta>
|
|
||||||
<view class="chat-page" :style="{ paddingBottom: keyboardHeight + 'px' }">
|
|
||||||
<!-- 患者信息栏 -->
|
<!-- 患者信息栏 -->
|
||||||
<view class="patient-info-bar" v-if="patientInfo.name">
|
<view class="patient-info-bar" v-if="patientInfo.name">
|
||||||
<view class="patient-info-content">
|
<view class="patient-info-content">
|
||||||
@ -25,9 +22,6 @@
|
|||||||
<!-- 聊天消息区域 -->
|
<!-- 聊天消息区域 -->
|
||||||
<scroll-view
|
<scroll-view
|
||||||
class="chat-content"
|
class="chat-content"
|
||||||
:style="{
|
|
||||||
bottom: (keyboardHeight > 0 ? keyboardHeight + 60 : 60) + 'px',
|
|
||||||
}"
|
|
||||||
scroll-y="true"
|
scroll-y="true"
|
||||||
enhanced="true"
|
enhanced="true"
|
||||||
bounces="false"
|
bounces="false"
|
||||||
@ -152,7 +146,6 @@
|
|||||||
"
|
"
|
||||||
:userId="openid"
|
:userId="openid"
|
||||||
:corpId="corpId.value"
|
:corpId="corpId.value"
|
||||||
:keyboardHeight="keyboardHeight"
|
|
||||||
@scrollToBottom="() => scrollToBottom(true)"
|
@scrollToBottom="() => scrollToBottom(true)"
|
||||||
@messageSent="() => scrollToBottom(true)"
|
@messageSent="() => scrollToBottom(true)"
|
||||||
/>
|
/>
|
||||||
@ -165,7 +158,6 @@ import { onLoad, onShow, onHide } from "@dcloudio/uni-app";
|
|||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from "pinia";
|
||||||
import useAccountStore from "@/store/account.js";
|
import useAccountStore from "@/store/account.js";
|
||||||
import { globalTimChatManager } from "@/utils/tim-chat.js";
|
import { globalTimChatManager } from "@/utils/tim-chat.js";
|
||||||
import { globalUnreadListenerManager } from "@/utils/global-unread-listener.js";
|
|
||||||
import {
|
import {
|
||||||
startIMMonitoring,
|
startIMMonitoring,
|
||||||
stopIMMonitoring,
|
stopIMMonitoring,
|
||||||
@ -220,9 +212,6 @@ const chatInfo = ref({
|
|||||||
avatar: "/static/home/avatar.svg",
|
avatar: "/static/home/avatar.svg",
|
||||||
});
|
});
|
||||||
|
|
||||||
// 键盘高度
|
|
||||||
const keyboardHeight = ref(0);
|
|
||||||
|
|
||||||
// 评价弹窗状态
|
// 评价弹窗状态
|
||||||
const isEvaluationPopupOpen = ref(false);
|
const isEvaluationPopupOpen = ref(false);
|
||||||
|
|
||||||
@ -267,7 +256,6 @@ const scrollIntoView = ref("");
|
|||||||
const isLoadingMore = ref(false);
|
const isLoadingMore = ref(false);
|
||||||
const isCompleted = ref(false);
|
const isCompleted = ref(false);
|
||||||
const lastFirstMessageId = ref("");
|
const lastFirstMessageId = ref("");
|
||||||
const isCallbacksInitialized = ref(false); // 标记回调是否已初始化
|
|
||||||
|
|
||||||
// 判断是否为系统消息
|
// 判断是否为系统消息
|
||||||
function isSystemMessage(message) {
|
function isSystemMessage(message) {
|
||||||
@ -299,13 +287,10 @@ function isSystemMessage(message) {
|
|||||||
// 获取群组订单状态
|
// 获取群组订单状态
|
||||||
const fetchGroupOrderStatus = async () => {
|
const fetchGroupOrderStatus = async () => {
|
||||||
try {
|
try {
|
||||||
const result = await api(
|
const result = await api("getGroupListByGroupId", {
|
||||||
"getGroupListByGroupId",
|
|
||||||
{
|
|
||||||
groupId: groupId.value,
|
groupId: groupId.value,
|
||||||
},
|
});
|
||||||
false
|
|
||||||
);
|
|
||||||
if (result.success && result.data) {
|
if (result.success && result.data) {
|
||||||
orderStatus.value = result.data.orderStatus || "";
|
orderStatus.value = result.data.orderStatus || "";
|
||||||
corpId.value = result.data.corpId || "";
|
corpId.value = result.data.corpId || "";
|
||||||
@ -457,22 +442,6 @@ onLoad((options) => {
|
|||||||
chatInfo.value.userID = options.userID;
|
chatInfo.value.userID = options.userID;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 监听键盘高度变化
|
|
||||||
uni.onKeyboardHeightChange((res) => {
|
|
||||||
console.log("键盘高度变化:", res.height);
|
|
||||||
const oldHeight = keyboardHeight.value;
|
|
||||||
keyboardHeight.value = res.height;
|
|
||||||
|
|
||||||
// 键盘弹出时(从0变为非0),自动滚动到底部
|
|
||||||
if (oldHeight === 0 && res.height > 0) {
|
|
||||||
nextTick(() => {
|
|
||||||
setTimeout(() => {
|
|
||||||
scrollToBottom(true);
|
|
||||||
}, 100);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
checkLoginAndInitTIM();
|
checkLoginAndInitTIM();
|
||||||
updateNavigationTitle();
|
updateNavigationTitle();
|
||||||
});
|
});
|
||||||
@ -507,14 +476,12 @@ const checkLoginAndInitTIM = async () => {
|
|||||||
|
|
||||||
// 初始化IM回调函数
|
// 初始化IM回调函数
|
||||||
const initTIMCallbacks = async () => {
|
const initTIMCallbacks = async () => {
|
||||||
// 标记回调已初始化
|
|
||||||
isCallbacksInitialized.value = true;
|
|
||||||
|
|
||||||
timChatManager.setCallback("onSDKReady", () => {
|
timChatManager.setCallback("onSDKReady", () => {
|
||||||
if (messageList.value.length === 0 && !isLoading.value) {
|
if (messageList.value.length === 0 && !isLoading.value) {
|
||||||
loadMessageList();
|
loadMessageList();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
timChatManager.setCallback("onSDKNotReady", () => {});
|
timChatManager.setCallback("onSDKNotReady", () => {});
|
||||||
|
|
||||||
timChatManager.setCallback("onMessageReceived", (message) => {
|
timChatManager.setCallback("onMessageReceived", (message) => {
|
||||||
@ -560,10 +527,9 @@ const initTIMCallbacks = async () => {
|
|||||||
.setMessageRead({
|
.setMessageRead({
|
||||||
conversationID: chatInfo.value.conversationID,
|
conversationID: chatInfo.value.conversationID,
|
||||||
})
|
})
|
||||||
.then(async () => {
|
.then(() => {
|
||||||
console.log("✓ 收到新消息后已标记为已读");
|
console.log("✓ 收到新消息后已标记为已读");
|
||||||
// 标记为已读后,立即刷新 tabBar 徽章
|
// 标记为已读后,刷新 tabBar 徽章
|
||||||
await globalUnreadListenerManager.refreshBadge();
|
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error("✗ 标记已读失败:", error);
|
console.error("✗ 标记已读失败:", error);
|
||||||
@ -714,10 +680,9 @@ const loadMessageList = async () => {
|
|||||||
.setMessageRead({
|
.setMessageRead({
|
||||||
conversationID: chatInfo.value.conversationID,
|
conversationID: chatInfo.value.conversationID,
|
||||||
})
|
})
|
||||||
.then(async () => {
|
.then(() => {
|
||||||
console.log("✓ 会话已标记为已读:", chatInfo.value.conversationID);
|
console.log("✓ 会话已标记为已读:", chatInfo.value.conversationID);
|
||||||
// 标记为已读后,立即刷新 tabBar 徽章
|
// 标记为已读后,刷新 tabBar 徽章
|
||||||
await globalUnreadListenerManager.refreshBadge();
|
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error("✗ 标记会话已读失败:", error);
|
console.error("✗ 标记会话已读失败:", error);
|
||||||
@ -861,49 +826,17 @@ onShow(() => {
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isIMInitialized.value) {
|
if (!isIMInitialized.value) {
|
||||||
checkLoginAndInitTIM();
|
checkLoginAndInitTIM();
|
||||||
} else if (timChatManager.tim && !timChatManager.isLoggedIn) {
|
} else if (timChatManager.tim && !timChatManager.isLoggedIn) {
|
||||||
// IM未登录,尝试重连
|
timChatManager.ensureIMConnection();
|
||||||
timChatManager.ensureIMConnection().then(() => {
|
|
||||||
// 重连成功后重新注册回调
|
|
||||||
if (timChatManager.isLoggedIn && chatInfo.value.conversationID) {
|
|
||||||
console.log("✓ 重连成功,重新注册消息监听回调");
|
|
||||||
initTIMCallbacks();
|
|
||||||
timChatManager.setConversationID(chatInfo.value.conversationID);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else if (
|
} else if (
|
||||||
timChatManager.tim &&
|
timChatManager.tim &&
|
||||||
timChatManager.isLoggedIn &&
|
timChatManager.isLoggedIn &&
|
||||||
chatInfo.value.conversationID
|
chatInfo.value.conversationID
|
||||||
) {
|
)
|
||||||
// IM已登录,只需要重新设置会话ID,不重新注册回调(避免影响正在发送的消息)
|
|
||||||
console.log("✓ 页面显示,重新设置当前会话ID");
|
|
||||||
timChatManager.setConversationID(chatInfo.value.conversationID);
|
|
||||||
|
|
||||||
// 如果回调未初始化,才进行初始化
|
|
||||||
if (!isCallbacksInitialized.value) {
|
|
||||||
console.log("✓ 回调未初始化,进行初始化");
|
|
||||||
initTIMCallbacks();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 标记会话为已读
|
|
||||||
if (timChatManager.tim && timChatManager.isLoggedIn) {
|
|
||||||
timChatManager.tim
|
|
||||||
.setMessageRead({
|
|
||||||
conversationID: chatInfo.value.conversationID,
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
console.log("✓ 页面显示时已标记会话为已读");
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error("✗ 标记会话已读失败:", error);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
startIMMonitoring(30000);
|
startIMMonitoring(30000);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 页面隐藏
|
// 页面隐藏
|
||||||
@ -912,11 +845,6 @@ onHide(() => {
|
|||||||
// 清空当前会话ID,避免离开页面后收到的消息被错误标记为已读
|
// 清空当前会话ID,避免离开页面后收到的消息被错误标记为已读
|
||||||
timChatManager.currentConversationID = null;
|
timChatManager.currentConversationID = null;
|
||||||
console.log("✓ 页面隐藏,已清空当前会话ID");
|
console.log("✓ 页面隐藏,已清空当前会话ID");
|
||||||
|
|
||||||
// 页面隐藏时刷新 tabBar 徽章,确保显示正确的未读数
|
|
||||||
if (globalUnreadListenerManager.isInitialized) {
|
|
||||||
globalUnreadListenerManager.refreshBadge();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 处理取消申请
|
// 处理取消申请
|
||||||
@ -986,13 +914,10 @@ const handleApplyConsult = async () => {
|
|||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
// 获取当前群组信息,提取客户ID和corpId
|
// 获取当前群组信息,提取客户ID和corpId
|
||||||
const groupInfo = await api(
|
const groupInfo = await api("getGroupListByGroupId", {
|
||||||
"getGroupListByGroupId",
|
|
||||||
{
|
|
||||||
groupId: groupId.value,
|
groupId: groupId.value,
|
||||||
},
|
});
|
||||||
false
|
|
||||||
);
|
|
||||||
if (!groupInfo.success || !groupInfo.data) {
|
if (!groupInfo.success || !groupInfo.data) {
|
||||||
throw new Error("获取群组信息失败");
|
throw new Error("获取群组信息失败");
|
||||||
}
|
}
|
||||||
@ -1065,9 +990,6 @@ const handleApplyConsult = async () => {
|
|||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
clearMessageCache();
|
clearMessageCache();
|
||||||
|
|
||||||
// 移除键盘监听
|
|
||||||
uni.offKeyboardHeightChange();
|
|
||||||
|
|
||||||
timChatManager.setCallback("onSDKReady", null);
|
timChatManager.setCallback("onSDKReady", null);
|
||||||
timChatManager.setCallback("onSDKNotReady", null);
|
timChatManager.setCallback("onSDKNotReady", null);
|
||||||
timChatManager.setCallback("onMessageReceived", null);
|
timChatManager.setCallback("onMessageReceived", null);
|
||||||
|
|||||||
@ -76,13 +76,12 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, onUnmounted } from "vue";
|
import { ref, computed } from "vue";
|
||||||
import { onLoad, onShow, onHide } from "@dcloudio/uni-app";
|
import { onLoad, onShow, onHide } from "@dcloudio/uni-app";
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from "pinia";
|
||||||
import useAccountStore from "@/store/account.js";
|
import useAccountStore from "@/store/account.js";
|
||||||
import { globalTimChatManager } from "@/utils/tim-chat.js";
|
import { globalTimChatManager } from "@/utils/tim-chat.js";
|
||||||
import { mergeConversationWithGroupDetails } from "@/utils/conversation-merger.js";
|
import { mergeConversationWithGroupDetails } from "@/utils/conversation-merger.js";
|
||||||
import { globalUnreadListenerManager } from "@/utils/global-unread-listener.js";
|
|
||||||
import useGroupAvatars from "./hooks/use-group-avatars.js";
|
import useGroupAvatars from "./hooks/use-group-avatars.js";
|
||||||
import GroupAvatar from "@/components/group-avatar.vue";
|
import GroupAvatar from "@/components/group-avatar.vue";
|
||||||
|
|
||||||
@ -252,10 +251,12 @@ const loadConversationList = async () => {
|
|||||||
// 防抖更新定时器
|
// 防抖更新定时器
|
||||||
let updateTimer = null;
|
let updateTimer = null;
|
||||||
|
|
||||||
// 会话列表更新处理函数
|
// 设置会话列表监听,实时更新列表
|
||||||
const handleConversationListUpdate = async (eventData) => {
|
const setupConversationListener = () => {
|
||||||
console.log("【消息列表页】会话列表更新事件:", eventData);
|
if (!globalTimChatManager) return;
|
||||||
|
// 监听会话列表更新事件
|
||||||
|
globalTimChatManager.setCallback("onConversationListUpdated", (eventData) => {
|
||||||
|
console.log("会话列表更新事件:", eventData);
|
||||||
// 处理单个会话更新(标记已读的情况)
|
// 处理单个会话更新(标记已读的情况)
|
||||||
if (eventData && !Array.isArray(eventData) && eventData.conversationID) {
|
if (eventData && !Array.isArray(eventData) && eventData.conversationID) {
|
||||||
const conversationID = eventData.conversationID;
|
const conversationID = eventData.conversationID;
|
||||||
@ -269,23 +270,16 @@ const handleConversationListUpdate = async (eventData) => {
|
|||||||
conversationList.value[existingIndex].unreadCount =
|
conversationList.value[existingIndex].unreadCount =
|
||||||
eventData.unreadCount;
|
eventData.unreadCount;
|
||||||
console.log(
|
console.log(
|
||||||
`【消息列表页】已更新会话未读数: ${conversationList.value[existingIndex].name}, unreadCount: ${eventData.unreadCount}`
|
`已清空会话未读数: ${conversationList.value[existingIndex].name}, unreadCount: ${eventData.unreadCount}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// 更新最后消息
|
|
||||||
if (eventData.lastMessage) {
|
|
||||||
conversationList.value[existingIndex].lastMessage = eventData.lastMessage.messageForShow || '';
|
|
||||||
conversationList.value[existingIndex].lastMessageTime = eventData.lastMessage.lastTime || Date.now();
|
|
||||||
// 重新排序
|
|
||||||
conversationList.value.sort((a, b) => b.lastMessageTime - a.lastMessageTime);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// eventData 是一个数组,包含所有更新的会话
|
// eventData 是一个数组,包含所有更新的会话
|
||||||
if (!eventData || !Array.isArray(eventData)) {
|
if (!eventData || !Array.isArray(eventData)) {
|
||||||
console.warn("【消息列表页】会话列表更新事件数据格式错误");
|
console.warn("会话列表更新事件数据格式错误");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -300,7 +294,7 @@ const handleConversationListUpdate = async (eventData) => {
|
|||||||
(conv) => conv.conversationID && conv.conversationID.startsWith("GROUP")
|
(conv) => conv.conversationID && conv.conversationID.startsWith("GROUP")
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log(`【消息列表页】收到 ${groupConversations.length} 个群聊会话更新`);
|
console.log(`收到 ${groupConversations.length} 个群聊会话更新`);
|
||||||
|
|
||||||
// 使用 TimChatManager 的格式化方法转换为标准格式
|
// 使用 TimChatManager 的格式化方法转换为标准格式
|
||||||
const formattedConversations = groupConversations.map((conv) =>
|
const formattedConversations = groupConversations.map((conv) =>
|
||||||
@ -313,7 +307,7 @@ const handleConversationListUpdate = async (eventData) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (!mergedConversations || mergedConversations.length === 0) {
|
if (!mergedConversations || mergedConversations.length === 0) {
|
||||||
console.log("【消息列表页】合并后的会话数据为空,跳过更新");
|
console.log("合并后的会话数据为空,跳过更新");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,19 +333,20 @@ const handleConversationListUpdate = async (eventData) => {
|
|||||||
...conversationData,
|
...conversationData,
|
||||||
// 保持原有头像,避免闪动
|
// 保持原有头像,避免闪动
|
||||||
avatar: existing.avatar || conversationData.avatar,
|
avatar: existing.avatar || conversationData.avatar,
|
||||||
// 直接使用 TIM SDK 返回的未读数
|
// 【修复】直接使用 TIM SDK 返回的未读数,不使用 Math.max
|
||||||
|
// 这样才能正确处理标记已读的情况(unreadCount 从 N 变为 0)
|
||||||
unreadCount: conversationData.unreadCount || 0
|
unreadCount: conversationData.unreadCount || 0
|
||||||
};
|
};
|
||||||
needSort = true;
|
needSort = true;
|
||||||
console.log(
|
console.log(
|
||||||
`【消息列表页】已更新会话: ${conversationData.name}, unreadCount: ${conversationList.value[existingIndex].unreadCount}`
|
`已更新会话: ${conversationData.name}, unreadCount: ${conversationList.value[existingIndex].unreadCount}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 添加新会话
|
// 添加新会话
|
||||||
conversationList.value.push(conversationData);
|
conversationList.value.push(conversationData);
|
||||||
needSort = true;
|
needSort = true;
|
||||||
console.log(`【消息列表页】已添加新会话: ${conversationData.name}`);
|
console.log(`已添加新会话: ${conversationData.name}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -362,33 +357,19 @@ const handleConversationListUpdate = async (eventData) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}, 100); // 100ms 防抖延迟
|
}, 100); // 100ms 防抖延迟
|
||||||
};
|
});
|
||||||
|
|
||||||
// 消息接收处理函数
|
// 监听消息接收事件(用于更新未读数)
|
||||||
const handleMessageReceived = (message) => {
|
globalTimChatManager.setCallback("onMessageReceived", (message) => {
|
||||||
console.log("【消息列表页】收到新消息:", message);
|
console.log("消息列表页面收到新消息:", message);
|
||||||
|
|
||||||
|
// 【修复】不再手动更新未读数
|
||||||
// TIM SDK 会在收到新消息时自动更新会话的未读数,并触发 onConversationListUpdated 事件
|
// TIM SDK 会在收到新消息时自动更新会话的未读数,并触发 onConversationListUpdated 事件
|
||||||
// 因此这里不需要手动处理,只记录日志
|
// 手动 +1 可能导致未读数不准确(重复计数)
|
||||||
};
|
//
|
||||||
|
// 注意:onConversationListUpdated 事件会在消息接收后自动触发,
|
||||||
// 设置会话列表监听,实时更新列表
|
// 其中包含了正确的未读数,因此这里不需要手动处理
|
||||||
const setupConversationListener = () => {
|
});
|
||||||
if (!globalTimChatManager) return;
|
|
||||||
|
|
||||||
console.log("【消息列表页】设置会话监听器");
|
|
||||||
|
|
||||||
// 将回调添加到全局未读监听器的回调链中
|
|
||||||
// 这样不会覆盖全局未读监听器,而是与之共存
|
|
||||||
if (globalUnreadListenerManager.isInitialized) {
|
|
||||||
globalUnreadListenerManager.addCallback("onConversationListUpdated", handleConversationListUpdate);
|
|
||||||
globalUnreadListenerManager.addCallback("onMessageReceived", handleMessageReceived);
|
|
||||||
console.log("【消息列表页】已添加回调到全局监听器回调链");
|
|
||||||
} else {
|
|
||||||
console.warn("【消息列表页】全局未读监听器未初始化,使用直接回调方式");
|
|
||||||
// 如果全局监听器未初始化,直接设置回调(兼容处理)
|
|
||||||
globalTimChatManager.setCallback("onConversationListUpdated", handleConversationListUpdate);
|
|
||||||
globalTimChatManager.setCallback("onMessageReceived", handleMessageReceived);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 格式化消息时间
|
// 格式化消息时间
|
||||||
@ -436,8 +417,6 @@ const formatMessageTime = (timestamp) => {
|
|||||||
// 点击会话
|
// 点击会话
|
||||||
const handleClickConversation = async (conversation) => {
|
const handleClickConversation = async (conversation) => {
|
||||||
console.log("点击会话:", conversation);
|
console.log("点击会话:", conversation);
|
||||||
|
|
||||||
// 立即清除本地未读数显示
|
|
||||||
const conversationIndex = conversationList.value.findIndex(
|
const conversationIndex = conversationList.value.findIndex(
|
||||||
(conv) => conv.conversationID === conversation.conversationID
|
(conv) => conv.conversationID === conversation.conversationID
|
||||||
);
|
);
|
||||||
@ -445,21 +424,6 @@ const handleClickConversation = async (conversation) => {
|
|||||||
conversationList.value[conversationIndex].unreadCount = 0;
|
conversationList.value[conversationIndex].unreadCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 标记会话为已读
|
|
||||||
if (globalTimChatManager && globalTimChatManager.tim) {
|
|
||||||
try {
|
|
||||||
await globalTimChatManager.tim.setMessageRead({
|
|
||||||
conversationID: conversation.conversationID,
|
|
||||||
});
|
|
||||||
console.log("✓ 已标记会话为已读:", conversation.conversationID);
|
|
||||||
|
|
||||||
// 立即刷新 tabBar 徽章
|
|
||||||
await globalUnreadListenerManager.refreshBadge();
|
|
||||||
} catch (error) {
|
|
||||||
console.error("✗ 标记会话已读失败:", error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 跳转到聊天页面
|
// 跳转到聊天页面
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: `/pages/message/index?conversationID=${conversation.conversationID}&groupID=${conversation.groupID}`,
|
url: `/pages/message/index?conversationID=${conversation.conversationID}&groupID=${conversation.groupID}`,
|
||||||
@ -513,42 +477,19 @@ const cleanMessageText = (text) => {
|
|||||||
|
|
||||||
// 页面显示
|
// 页面显示
|
||||||
onShow(async () => {
|
onShow(async () => {
|
||||||
// 页面显示时刷新 tabBar 徽章
|
|
||||||
if (globalUnreadListenerManager.isInitialized) {
|
|
||||||
await globalUnreadListenerManager.refreshBadge();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 页面隐藏
|
// 页面隐藏
|
||||||
onHide(() => {
|
onHide(() => {
|
||||||
console.log("【消息列表页】页面隐藏");
|
|
||||||
|
|
||||||
// 清除防抖定时器
|
// 清除防抖定时器
|
||||||
if (updateTimer) {
|
if (updateTimer) {
|
||||||
clearTimeout(updateTimer);
|
clearTimeout(updateTimer);
|
||||||
updateTimer = null;
|
updateTimer = null;
|
||||||
}
|
}
|
||||||
|
if (globalTimChatManager) {
|
||||||
// 注意:不要清除 globalTimChatManager 的回调
|
globalTimChatManager.setCallback("onConversationListUpdated", null);
|
||||||
// 因为全局未读监听器需要持续工作
|
globalTimChatManager.setCallback("onMessageReceived", null);
|
||||||
// 回调链会在页面销毁时自动清理
|
|
||||||
});
|
|
||||||
|
|
||||||
// 页面卸载
|
|
||||||
onUnmounted(() => {
|
|
||||||
console.log("【消息列表页】页面卸载,清理回调");
|
|
||||||
|
|
||||||
// 清除防抖定时器
|
|
||||||
if (updateTimer) {
|
|
||||||
clearTimeout(updateTimer);
|
|
||||||
updateTimer = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 从全局未读监听器的回调链中移除本页面的回调
|
|
||||||
if (globalUnreadListenerManager.isInitialized) {
|
|
||||||
globalUnreadListenerManager.removeCallback("onConversationListUpdated", handleConversationListUpdate);
|
|
||||||
globalUnreadListenerManager.removeCallback("onMessageReceived", handleMessageReceived);
|
|
||||||
console.log("【消息列表页】已从回调链移除回调");
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
<view v-if="member" class="flex flex-col h-full items-center justify-center">
|
<view v-if="member" class="flex flex-col h-full items-center justify-center">
|
||||||
<view class="business-card">
|
<view class="business-card">
|
||||||
<view class="flex">
|
<view class="flex">
|
||||||
<image class="mr-10 avatar" :src="member.avatar || '/static/default-avatar.png'"></image>
|
<image class="mr-10 avatar" :src="member.avatar || '/static/default-avatar.svg'"></image>
|
||||||
<view class="w-0 flex-grow leading-normal">
|
<view class="w-0 flex-grow leading-normal">
|
||||||
<view class="flex items-center">
|
<view class="flex items-center">
|
||||||
<view class="mr-5 text-lg font-semibold text-dark">{{ member.anotherName }}</view>
|
<view class="mr-5 text-lg font-semibold text-dark">{{ member.anotherName }}</view>
|
||||||
|
|||||||
@ -25,7 +25,7 @@
|
|||||||
</view>
|
</view>
|
||||||
<view v-for="i in teammate.leaders" :key="i._id" class="mt-12 flex p-10 border-primary rounded-sm"
|
<view v-for="i in teammate.leaders" :key="i._id" class="mt-12 flex p-10 border-primary rounded-sm"
|
||||||
@click="toHomePage(i.userid)">
|
@click="toHomePage(i.userid)">
|
||||||
<image class="flex-shrink-0 mr-10 avatar" :src="i.avatar || '/static/default-avatar.png'"></image>
|
<image class="flex-shrink-0 mr-10 avatar" :src="i.avatar || '/static/default-avatar.svg'"></image>
|
||||||
<view class="w-0 flex-grow leading-normal">
|
<view class="w-0 flex-grow leading-normal">
|
||||||
<view class="flex items-center justify-between">
|
<view class="flex items-center justify-between">
|
||||||
<view class="flex-shrink-0 mr-5 view-lg text-dark font-semibold">{{ i.anotherName }}</view>
|
<view class="flex-shrink-0 mr-5 view-lg text-dark font-semibold">{{ i.anotherName }}</view>
|
||||||
@ -50,7 +50,7 @@
|
|||||||
</view>
|
</view>
|
||||||
<view v-for="i in teammate.members" :key="i._id" class="mt-12 flex p-10 border-primary rounded-sm"
|
<view v-for="i in teammate.members" :key="i._id" class="mt-12 flex p-10 border-primary rounded-sm"
|
||||||
@click="toHomePage(i.userid)">
|
@click="toHomePage(i.userid)">
|
||||||
<image class="flex-shrink-0 mr-10 avatar" :src="i.avatar || '/static/default-avatar.png'"></image>
|
<image class="flex-shrink-0 mr-10 avatar" :src="i.avatar || '/static/default-avatar.svg'"></image>
|
||||||
<view class="w-0 flex-grow leading-normal">
|
<view class="w-0 flex-grow leading-normal">
|
||||||
<view class="flex items-center justify-between">
|
<view class="flex items-center justify-between">
|
||||||
<view class="flex-shrink-0 mr-5 view-lg text-dark font-semibold">{{ i.anotherName }}</view>
|
<view class="flex-shrink-0 mr-5 view-lg text-dark font-semibold">{{ i.anotherName }}</view>
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import { defineStore } from "pinia";
|
|||||||
import api from '@/utils/api';
|
import api from '@/utils/api';
|
||||||
import { toast } from '@/utils/widget';
|
import { toast } from '@/utils/widget';
|
||||||
import { initGlobalTIM, globalTimChatManager } from "@/utils/tim-chat.js";
|
import { initGlobalTIM, globalTimChatManager } from "@/utils/tim-chat.js";
|
||||||
import { globalUnreadListenerManager } from "@/utils/global-unread-listener.js";
|
|
||||||
const env = __VITE_ENV__;
|
const env = __VITE_ENV__;
|
||||||
|
|
||||||
export default defineStore("accountStore", () => {
|
export default defineStore("accountStore", () => {
|
||||||
@ -77,10 +76,6 @@ export default defineStore("accountStore", () => {
|
|||||||
|
|
||||||
isIMInitialized.value = true;
|
isIMInitialized.value = true;
|
||||||
console.log('IM 初始化成功');
|
console.log('IM 初始化成功');
|
||||||
|
|
||||||
// IM 初始化成功后,设置全局未读消息监听
|
|
||||||
globalUnreadListenerManager.setup();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('IM初始化异常,跳过 IM 初始化:', error.message);
|
console.log('IM初始化异常,跳过 IM 初始化:', error.message);
|
||||||
@ -96,11 +91,6 @@ export default defineStore("accountStore", () => {
|
|||||||
await globalTimChatManager.destroy();
|
await globalTimChatManager.destroy();
|
||||||
console.log('腾讯IM退出成功');
|
console.log('腾讯IM退出成功');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 清除全局未读监听
|
|
||||||
if (globalUnreadListenerManager.isInitialized) {
|
|
||||||
globalUnreadListenerManager.destroy();
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('退出腾讯IM失败:', error);
|
console.error('退出腾讯IM失败:', error);
|
||||||
}
|
}
|
||||||
@ -113,11 +103,6 @@ export default defineStore("accountStore", () => {
|
|||||||
// 清除本地存储
|
// 清除本地存储
|
||||||
uni.removeStorageSync('account');
|
uni.removeStorageSync('account');
|
||||||
uni.removeStorageSync('openid');
|
uni.removeStorageSync('openid');
|
||||||
|
|
||||||
// 清除 tabBar 徽章
|
|
||||||
uni.removeTabBarBadge({
|
|
||||||
index: 1
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getExternalUserId(corpId) {
|
async function getExternalUserId(corpId) {
|
||||||
|
|||||||
@ -44,7 +44,7 @@ export default defineStore("teamStore", () => {
|
|||||||
const res = await api('getTeamMemberAvatarsAndName', {
|
const res = await api('getTeamMemberAvatarsAndName', {
|
||||||
teamId,
|
teamId,
|
||||||
corpId: account.value.corpId
|
corpId: account.value.corpId
|
||||||
}, false);
|
});
|
||||||
if (res && res.success && res.data) {
|
if (res && res.success && res.data) {
|
||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -144,7 +144,7 @@ function mergeConversationData(conversation, groupDetailsMap) {
|
|||||||
name: formatConversationName(groupDetail),
|
name: formatConversationName(groupDetail),
|
||||||
|
|
||||||
// 更新头像(优先使用已有头像,避免闪动)
|
// 更新头像(优先使用已有头像,避免闪动)
|
||||||
avatar: conversation.avatar || groupDetail.patient?.avatar || '/static/default-avatar.png',
|
avatar: conversation.avatar || groupDetail.patient?.avatar || '/static/default-avatar.svg',
|
||||||
|
|
||||||
// 【修复】保留未读消息数(确保不被覆盖)
|
// 【修复】保留未读消息数(确保不被覆盖)
|
||||||
unreadCount: conversation.unreadCount || 0
|
unreadCount: conversation.unreadCount || 0
|
||||||
|
|||||||
@ -7,11 +7,8 @@ import { globalTimChatManager } from './tim-chat.js';
|
|||||||
class GlobalUnreadListenerManager {
|
class GlobalUnreadListenerManager {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.isInitialized = false;
|
this.isInitialized = false;
|
||||||
this.callbackChain = {
|
this.originalConversationListCallback = null;
|
||||||
onConversationListUpdated: [],
|
this.originalMessageReceivedCallback = null;
|
||||||
onMessageReceived: []
|
|
||||||
};
|
|
||||||
this.updateTimer = null; // 防抖定时器
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -28,76 +25,39 @@ class GlobalUnreadListenerManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存原始回调到回调链
|
// 保存原始回调(在覆盖前保存)
|
||||||
const originalConversationListCallback = globalTimChatManager.callbacks.onConversationListUpdated;
|
this.originalConversationListCallback = globalTimChatManager.callbacks.onConversationListUpdated;
|
||||||
const originalMessageReceivedCallback = globalTimChatManager.callbacks.onMessageReceived;
|
this.originalMessageReceivedCallback = globalTimChatManager.callbacks.onMessageReceived;
|
||||||
|
|
||||||
if (originalConversationListCallback && typeof originalConversationListCallback === 'function') {
|
console.log('保存原始回调:', {
|
||||||
this.callbackChain.onConversationListUpdated.push(originalConversationListCallback);
|
hasConversationListCallback: !!this.originalConversationListCallback,
|
||||||
}
|
hasMessageReceivedCallback: !!this.originalMessageReceivedCallback
|
||||||
if (originalMessageReceivedCallback && typeof originalMessageReceivedCallback === 'function') {
|
|
||||||
this.callbackChain.onMessageReceived.push(originalMessageReceivedCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('全局未读监听初始化,回调链长度:', {
|
|
||||||
onConversationListUpdated: this.callbackChain.onConversationListUpdated.length,
|
|
||||||
onMessageReceived: this.callbackChain.onMessageReceived.length
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 监听会话列表更新事件(包括消息接收和已读状态变化)
|
// 监听会话列表更新事件(包括消息接收和已读状态变化)
|
||||||
globalTimChatManager.setCallback('onConversationListUpdated', (eventData) => {
|
globalTimChatManager.setCallback('onConversationListUpdated', (eventData) => {
|
||||||
console.log('【全局未读监听】onConversationListUpdated 触发,回调链长度:', this.callbackChain.onConversationListUpdated.length);
|
console.log('onConversationListUpdated 触发,调用原始回调');
|
||||||
|
// 调用原始回调(如果存在)
|
||||||
// 执行回调链中的所有回调
|
if (this.originalConversationListCallback && typeof this.originalConversationListCallback === 'function') {
|
||||||
this.callbackChain.onConversationListUpdated.forEach((callback, index) => {
|
this.originalConversationListCallback(eventData);
|
||||||
try {
|
|
||||||
console.log(`【全局未读监听】执行回调链 #${index + 1}`);
|
|
||||||
callback(eventData);
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`【全局未读监听】执行 onConversationListUpdated 回调 #${index + 1} 失败:`, error);
|
|
||||||
}
|
}
|
||||||
});
|
// 更新 tabBar 徽章
|
||||||
|
this.updateTabBarBadge();
|
||||||
// 防抖更新 tabBar 徽章
|
|
||||||
this.debouncedUpdateTabBarBadge();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 监听消息接收事件
|
// 监听消息接收事件
|
||||||
globalTimChatManager.setCallback('onMessageReceived', (message) => {
|
globalTimChatManager.setCallback('onMessageReceived', (message) => {
|
||||||
console.log('【全局未读监听】onMessageReceived 触发,回调链长度:', this.callbackChain.onMessageReceived.length);
|
console.log('onMessageReceived 触发,调用原始回调');
|
||||||
|
// 调用原始回调(如果存在)
|
||||||
// 执行回调链中的所有回调
|
if (this.originalMessageReceivedCallback && typeof this.originalMessageReceivedCallback === 'function') {
|
||||||
this.callbackChain.onMessageReceived.forEach((callback, index) => {
|
this.originalMessageReceivedCallback(message);
|
||||||
try {
|
|
||||||
console.log(`【全局未读监听】执行回调链 #${index + 1}`);
|
|
||||||
callback(message);
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`【全局未读监听】执行 onMessageReceived 回调 #${index + 1} 失败:`, error);
|
|
||||||
}
|
}
|
||||||
});
|
// 更新 tabBar 徽章
|
||||||
|
this.updateTabBarBadge();
|
||||||
// 防抖更新 tabBar 徽章
|
|
||||||
this.debouncedUpdateTabBarBadge();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.isInitialized = true;
|
this.isInitialized = true;
|
||||||
console.log('全局未读消息监听已设置');
|
console.log('全局未读消息监听已设置');
|
||||||
|
|
||||||
// 初始化时立即更新一次徽章
|
|
||||||
this.updateTabBarBadge();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 防抖更新 tabBar 徽章
|
|
||||||
* 避免频繁更新导致性能问题
|
|
||||||
*/
|
|
||||||
debouncedUpdateTabBarBadge() {
|
|
||||||
if (this.updateTimer) {
|
|
||||||
clearTimeout(this.updateTimer);
|
|
||||||
}
|
|
||||||
this.updateTimer = setTimeout(() => {
|
|
||||||
this.updateTabBarBadge();
|
|
||||||
}, 200); // 减少到 200ms 防抖延迟,提高响应速度
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -107,22 +67,21 @@ class GlobalUnreadListenerManager {
|
|||||||
async updateTabBarBadge() {
|
async updateTabBarBadge() {
|
||||||
try {
|
try {
|
||||||
if (!globalTimChatManager || !globalTimChatManager.tim) {
|
if (!globalTimChatManager || !globalTimChatManager.tim) {
|
||||||
console.warn('【全局未读监听】globalTimChatManager 或 tim 未初始化');
|
console.warn('globalTimChatManager 或 tim 未初始化');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await globalTimChatManager.tim.getConversationList();
|
const response = await globalTimChatManager.tim.getConversationList();
|
||||||
|
|
||||||
if (!response || !response.data || !response.data.conversationList) {
|
if (!response || !response.data || !response.data.conversationList) {
|
||||||
console.warn('【全局未读监听】获取会话列表返回数据异常');
|
console.warn('获取会话列表返回数据异常');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const totalUnreadCount = this.calculateGroupUnreadCount(response.data.conversationList);
|
const totalUnreadCount = this.calculateGroupUnreadCount(response.data.conversationList);
|
||||||
console.log('【全局未读监听】计算总未读数:', totalUnreadCount);
|
|
||||||
this.setTabBarBadge(totalUnreadCount);
|
this.setTabBarBadge(totalUnreadCount);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('【全局未读监听】更新 tabBar 徽章失败:', error);
|
console.error('更新 tabBar 徽章失败:', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,68 +107,25 @@ class GlobalUnreadListenerManager {
|
|||||||
index: tabIndex,
|
index: tabIndex,
|
||||||
text: count > 99 ? '99+' : String(count)
|
text: count > 99 ? '99+' : String(count)
|
||||||
});
|
});
|
||||||
console.log(`✓ 已更新 tabBar 徽章(索引 ${tabIndex}):`, count);
|
console.log(`已更新 tabBar 徽章(索引 ${tabIndex}):`, count);
|
||||||
} else {
|
} else {
|
||||||
uni.removeTabBarBadge({
|
// uni.removeTabBarBadge({
|
||||||
index: tabIndex
|
// index: tabIndex
|
||||||
});
|
// });
|
||||||
console.log(`✓ 已移除 tabBar 徽章(索引 ${tabIndex})`);
|
console.log(`已移除 tabBar 徽章(索引 ${tabIndex})`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 手动刷新徽章
|
|
||||||
* 用于页面显示时强制刷新
|
|
||||||
*/
|
|
||||||
async refreshBadge() {
|
async refreshBadge() {
|
||||||
console.log('手动刷新 tabBar 徽章');
|
console.log('手动刷新 tabBar 徽章');
|
||||||
await this.updateTabBarBadge();
|
await this.updateTabBarBadge();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加回调到回调链
|
|
||||||
* @param {string} eventName - 事件名称
|
|
||||||
* @param {Function} callback - 回调函数
|
|
||||||
*/
|
|
||||||
addCallback(eventName, callback) {
|
|
||||||
if (this.callbackChain[eventName] && typeof callback === 'function') {
|
|
||||||
// 避免重复添加同一个回调
|
|
||||||
if (!this.callbackChain[eventName].includes(callback)) {
|
|
||||||
this.callbackChain[eventName].push(callback);
|
|
||||||
console.log(`✓ 已添加回调到 ${eventName} 回调链,当前链长度:`, this.callbackChain[eventName].length);
|
|
||||||
} else {
|
|
||||||
console.log(`⚠️ 回调已存在于 ${eventName} 回调链中,跳过添加`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 从回调链中移除回调
|
|
||||||
* @param {string} eventName - 事件名称
|
|
||||||
* @param {Function} callback - 回调函数
|
|
||||||
*/
|
|
||||||
removeCallback(eventName, callback) {
|
|
||||||
if (this.callbackChain[eventName]) {
|
|
||||||
const index = this.callbackChain[eventName].indexOf(callback);
|
|
||||||
if (index > -1) {
|
|
||||||
this.callbackChain[eventName].splice(index, 1);
|
|
||||||
console.log(`✓ 已从 ${eventName} 回调链移除回调,当前链长度:`, this.callbackChain[eventName].length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 清除监听(可选)
|
* 清除监听(可选)
|
||||||
*/
|
*/
|
||||||
destroy() {
|
destroy() {
|
||||||
if (this.updateTimer) {
|
|
||||||
clearTimeout(this.updateTimer);
|
|
||||||
this.updateTimer = null;
|
|
||||||
}
|
|
||||||
this.callbackChain = {
|
|
||||||
onConversationListUpdated: [],
|
|
||||||
onMessageReceived: []
|
|
||||||
};
|
|
||||||
this.isInitialized = false;
|
this.isInitialized = false;
|
||||||
console.log('全局未读消息监听已清除');
|
console.log('全局未读消息监听已清除');
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user