Compare commits
No commits in common. "3316e1bfa0a52c7c24c316c237db2200d29a7a60" and "a66bfce90176a3e8da95aa2dd4d619666fa2c457" have entirely different histories.
3316e1bfa0
...
a66bfce901
@ -7,14 +7,8 @@
|
|||||||
<view v-if="customScroll" class="page-scroll">
|
<view v-if="customScroll" class="page-scroll">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</view>
|
</view>
|
||||||
<scroll-view
|
<scroll-view v-else scroll-y="true" :scroll-top="scrollTop" class="page-scroll" @scrolltolower="scrolltolower"
|
||||||
v-else
|
@scroll="onScroll">
|
||||||
scroll-y="true"
|
|
||||||
:scroll-top="scrollTop"
|
|
||||||
class="page-scroll"
|
|
||||||
@scrolltolower="scrolltolower"
|
|
||||||
@scroll="onScroll"
|
|
||||||
>
|
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
</view>
|
</view>
|
||||||
@ -22,22 +16,22 @@
|
|||||||
<slot name="footer"></slot>
|
<slot name="footer"></slot>
|
||||||
</view>
|
</view>
|
||||||
<!-- #ifdef MP-->
|
<!-- #ifdef MP-->
|
||||||
<!-- <view v-if="showSafeArea" class="safeareaBottom"></view> -->
|
<view v-if="showSafeArea" class="safeareaBottom"></view>
|
||||||
<!-- #endif -->
|
<!-- #endif -->
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, useSlots, ref } from "vue";
|
import { computed, useSlots, ref } from 'vue';
|
||||||
import useDebounce from "@/utils/useDebounce";
|
import useDebounce from '@/utils/useDebounce';
|
||||||
|
|
||||||
const emits = defineEmits(["reachBottom"]);
|
const emits = defineEmits(['reachBottom']);
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
customScroll: { type: Boolean, default: false },
|
customScroll: { type: Boolean, default: false },
|
||||||
mainClass: { type: String, default: "" },
|
mainClass: { type: String, default: '' },
|
||||||
mainStyle: { default: "" },
|
mainStyle: { default: '' },
|
||||||
pageClass: { type: String, default: "" },
|
pageClass: { type: String, default: '' },
|
||||||
pageStyle: { default: "" },
|
pageStyle: { default: '' },
|
||||||
showSafeArea: { type: Boolean, default: true },
|
showSafeArea: { type: Boolean, default: true }
|
||||||
});
|
});
|
||||||
const slots = useSlots();
|
const slots = useSlots();
|
||||||
const hasHeader = computed(() => !!slots.header);
|
const hasHeader = computed(() => !!slots.header);
|
||||||
@ -46,7 +40,7 @@ const hasFooter = computed(() => !!slots.footer);
|
|||||||
const scrollTop = ref(0);
|
const scrollTop = ref(0);
|
||||||
|
|
||||||
const scrolltolower = useDebounce(() => {
|
const scrolltolower = useDebounce(() => {
|
||||||
emits("reachBottom");
|
emits('reachBottom');
|
||||||
});
|
});
|
||||||
|
|
||||||
const onScroll = useDebounce((e) => {
|
const onScroll = useDebounce((e) => {
|
||||||
@ -58,8 +52,9 @@ function scrollToBottom() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
scrollToBottom,
|
scrollToBottom
|
||||||
});
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.full-page {
|
.full-page {
|
||||||
|
|||||||
@ -65,12 +65,12 @@ const buttons = ref([
|
|||||||
icon: "/static/icon/zhuiwen.png",
|
icon: "/static/icon/zhuiwen.png",
|
||||||
loading: false,
|
loading: false,
|
||||||
},
|
},
|
||||||
// {
|
{
|
||||||
// id: "aiAssistant",
|
id: "aiAssistant",
|
||||||
// text: "开启AI助手",
|
text: "开启AI助手",
|
||||||
// icon: "/static/icon/kaiqiAI.png",
|
icon: "/static/icon/kaiqiAI.png",
|
||||||
// loading: false,
|
loading: false,
|
||||||
// },
|
},
|
||||||
{
|
{
|
||||||
id: "supplementRecord",
|
id: "supplementRecord",
|
||||||
text: "补充病历",
|
text: "补充病历",
|
||||||
@ -241,7 +241,7 @@ const handleCaseTypeSelect = async (type) => {
|
|||||||
title: error.message || "生成病历失败",
|
title: error.message || "生成病历失败",
|
||||||
icon: "none",
|
icon: "none",
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("补充病历失败:", error);
|
console.error("补充病历失败:", error);
|
||||||
@ -254,22 +254,13 @@ const handleCaseTypeSelect = async (type) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 流式请求处理
|
// 流式请求处理
|
||||||
const requestWithStream = async ({
|
const requestWithStream = async ({ url, data, onProgress, onComplete, onError }) => {
|
||||||
url,
|
|
||||||
data,
|
|
||||||
onProgress,
|
|
||||||
onComplete,
|
|
||||||
onError,
|
|
||||||
}) => {
|
|
||||||
try {
|
try {
|
||||||
// 调用接口时不显示全局 loading(第二个参数为 false)
|
// 调用接口时不显示全局 loading(第二个参数为 false)
|
||||||
const result = await request(
|
const result = await request({
|
||||||
{
|
url,
|
||||||
url,
|
data,
|
||||||
data,
|
}, false);
|
||||||
},
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
if (result.success && result.data) {
|
if (result.success && result.data) {
|
||||||
// 模拟流式处理(如果后端返回的是完整数据)
|
// 模拟流式处理(如果后端返回的是完整数据)
|
||||||
@ -284,7 +275,7 @@ const requestWithStream = async ({
|
|||||||
const [key, value] = fields[i];
|
const [key, value] = fields[i];
|
||||||
|
|
||||||
// 显示所有字段,包括空值(会在组件中显示为"暂无")
|
// 显示所有字段,包括空值(会在组件中显示为"暂无")
|
||||||
await new Promise((resolve) => setTimeout(resolve, delay));
|
await new Promise(resolve => setTimeout(resolve, delay));
|
||||||
onProgress({ key, value });
|
onProgress({ key, value });
|
||||||
progressValue += Math.floor(60 / fields.length);
|
progressValue += Math.floor(60 / fields.length);
|
||||||
progressRef.value?.updateProgress(Math.min(progressValue, 80));
|
progressRef.value?.updateProgress(Math.min(progressValue, 80));
|
||||||
|
|||||||
@ -1,13 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="message-page">
|
<view class="message-page">
|
||||||
<!-- 团队切换头部 -->
|
|
||||||
<view class="header-container">
|
|
||||||
<view class="team-selector" @click="showTeamPicker = true">
|
|
||||||
<text class="team-name">{{ currentTeamName }}</text>
|
|
||||||
<text class="arrow-icon">▼</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 标签页切换 -->
|
<!-- 标签页切换 -->
|
||||||
<view class="tabs-container">
|
<view class="tabs-container">
|
||||||
<view
|
<view
|
||||||
@ -28,27 +20,6 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 团队选择弹窗 -->
|
|
||||||
<view v-if="showTeamPicker" class="team-picker-overlay" @click="showTeamPicker = false">
|
|
||||||
<view class="team-picker-content" @click.stop>
|
|
||||||
<view class="team-picker-header">
|
|
||||||
<text class="picker-title">选择团队</text>
|
|
||||||
</view>
|
|
||||||
<scroll-view class="team-list" scroll-y>
|
|
||||||
<view
|
|
||||||
v-for="team in teamList"
|
|
||||||
:key="team._id"
|
|
||||||
class="team-item"
|
|
||||||
:class="{ active: currentTeamId === team._id }"
|
|
||||||
@click="selectTeam(team)"
|
|
||||||
>
|
|
||||||
<text class="team-item-name">{{ team.name }}</text>
|
|
||||||
<text v-if="currentTeamId === team._id" class="check-icon">✓</text>
|
|
||||||
</view>
|
|
||||||
</scroll-view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 消息列表 -->
|
<!-- 消息列表 -->
|
||||||
<scroll-view
|
<scroll-view
|
||||||
class="message-list"
|
class="message-list"
|
||||||
@ -130,33 +101,12 @@ import { ref, watch, 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 useTeamStore from "@/store/team.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";
|
||||||
|
|
||||||
// 获取登录状态
|
// 获取登录状态
|
||||||
const { account, openid, isIMInitialized } = storeToRefs(useAccountStore());
|
const { account, openid, isIMInitialized } = storeToRefs(useAccountStore());
|
||||||
const { initIMAfterLogin } = useAccountStore();
|
const { initIMAfterLogin } = useAccountStore();
|
||||||
|
|
||||||
// 获取团队信息
|
|
||||||
const teamStore = useTeamStore();
|
|
||||||
const { teams } = storeToRefs(teamStore);
|
|
||||||
const { getTeams } = teamStore;
|
|
||||||
|
|
||||||
// 团队相关状态
|
|
||||||
const showTeamPicker = ref(false);
|
|
||||||
const currentTeamId = ref(""); // 空字符串表示"全部会话消息"
|
|
||||||
const teamList = computed(() => {
|
|
||||||
// 在团队列表前添加"全部会话消息"选项
|
|
||||||
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 初始化状态
|
// 监听 IM 初始化状态
|
||||||
watch(isIMInitialized, (newValue) => {
|
watch(isIMInitialized, (newValue) => {
|
||||||
console.log("IM初始化状态变化:", newValue);
|
console.log("IM初始化状态变化:", newValue);
|
||||||
@ -176,39 +126,25 @@ const activeTab = ref("processing");
|
|||||||
|
|
||||||
// 根据 orderStatus 过滤会话列表
|
// 根据 orderStatus 过滤会话列表
|
||||||
const filteredConversationList = computed(() => {
|
const filteredConversationList = computed(() => {
|
||||||
let filtered = [];
|
|
||||||
|
|
||||||
if (activeTab.value === "processing") {
|
if (activeTab.value === "processing") {
|
||||||
// 处理中:pending(待处理) 和 processing(处理中)
|
// 处理中:pending(待处理) 和 processing(处理中)
|
||||||
filtered = conversationList.value.filter(
|
const filtered = conversationList.value.filter(
|
||||||
(conv) =>
|
(conv) =>
|
||||||
conv.orderStatus === "pending" || conv.orderStatus === "processing"
|
conv.orderStatus === "pending" || conv.orderStatus === "processing"
|
||||||
);
|
);
|
||||||
|
return filtered;
|
||||||
} else {
|
} else {
|
||||||
// 已结束:cancelled(已取消)、completed(已完成)、finished(已结束)
|
// 已结束:cancelled(已取消)、completed(已完成)、finished(已结束)
|
||||||
filtered = conversationList.value.filter(
|
const filtered = conversationList.value.filter(
|
||||||
(conv) =>
|
(conv) =>
|
||||||
conv.orderStatus === "cancelled" ||
|
conv.orderStatus === "cancelled" ||
|
||||||
conv.orderStatus === "completed" ||
|
conv.orderStatus === "completed" ||
|
||||||
conv.orderStatus === "finished"
|
conv.orderStatus === "finished"
|
||||||
);
|
);
|
||||||
|
return filtered;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果选择了团队,进一步过滤
|
|
||||||
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 switchTab = (tab) => {
|
const switchTab = (tab) => {
|
||||||
if (activeTab.value === tab) return;
|
if (activeTab.value === tab) return;
|
||||||
@ -375,17 +311,13 @@ const setupConversationListener = () => {
|
|||||||
existing.patientSex !== conversationData.patientSex ||
|
existing.patientSex !== conversationData.patientSex ||
|
||||||
existing.patientAge !== conversationData.patientAge
|
existing.patientAge !== conversationData.patientAge
|
||||||
) {
|
) {
|
||||||
// 只更新变化的字段,保持头像和未读数稳定
|
Object.assign(
|
||||||
conversationList.value[existingIndex] = {
|
conversationList.value[existingIndex],
|
||||||
...conversationData,
|
conversationData
|
||||||
// 保持原有头像,避免闪动
|
);
|
||||||
avatar: existing.avatar || conversationData.avatar,
|
|
||||||
// 保留较大的未读数(避免被后端数据覆盖)
|
|
||||||
unreadCount: Math.max(existing.unreadCount || 0, conversationData.unreadCount || 0)
|
|
||||||
};
|
|
||||||
needSort = true;
|
needSort = true;
|
||||||
console.log(
|
console.log(
|
||||||
`已更新会话: ${conversationData.name}, unreadCount: ${conversationList.value[existingIndex].unreadCount}`
|
`已更新会话: ${conversationData.name}, unreadCount: ${conversationData.unreadCount}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -418,23 +350,19 @@ const setupConversationListener = () => {
|
|||||||
if (conversationIndex !== -1) {
|
if (conversationIndex !== -1) {
|
||||||
const conversation = conversationList.value[conversationIndex];
|
const conversation = conversationList.value[conversationIndex];
|
||||||
|
|
||||||
// 检查当前页面栈,判断用户是否正在查看该会话的聊天详情页
|
// 检查当前页面栈,判断用户是否正在查看该会话
|
||||||
const pages = getCurrentPages();
|
const pages = getCurrentPages();
|
||||||
const currentPage = pages[pages.length - 1];
|
const currentPage = pages[pages.length - 1];
|
||||||
|
const isViewingConversation =
|
||||||
|
currentPage?.route === "pages/message/index";
|
||||||
|
|
||||||
// 获取当前页面的 groupID 参数(如果在聊天详情页)
|
// 如果用户正在查看该会话,不增加未读数
|
||||||
const currentGroupID = currentPage?.options?.groupID;
|
if (isViewingConversation) {
|
||||||
const isViewingThisConversation =
|
|
||||||
currentPage?.route === "pages/message/index" &&
|
|
||||||
currentGroupID === conversation.groupID;
|
|
||||||
|
|
||||||
// 如果用户正在查看这个具体的会话,不增加未读数
|
|
||||||
if (isViewingThisConversation) {
|
|
||||||
console.log("用户正在查看该会话,不增加未读数");
|
console.log("用户正在查看该会话,不增加未读数");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 只在用户不在该会话的聊天页面时才增加未读数
|
// 只在用户不在聊天页面时才增加未读数
|
||||||
conversation.unreadCount = (conversation.unreadCount || 0) + 1;
|
conversation.unreadCount = (conversation.unreadCount || 0) + 1;
|
||||||
console.log(
|
console.log(
|
||||||
"已更新会话未读数:",
|
"已更新会话未读数:",
|
||||||
@ -560,9 +488,6 @@ onLoad(() => {
|
|||||||
// 页面显示
|
// 页面显示
|
||||||
onShow(async () => {
|
onShow(async () => {
|
||||||
try {
|
try {
|
||||||
// 加载团队列表
|
|
||||||
await getTeams();
|
|
||||||
|
|
||||||
// 初始化IM
|
// 初始化IM
|
||||||
const imReady = await initIM();
|
const imReady = await initIM();
|
||||||
if (!imReady) {
|
if (!imReady) {
|
||||||
@ -606,111 +531,6 @@ onHide(() => {
|
|||||||
flex-direction: column;
|
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 {
|
.tabs-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
|
|||||||
@ -48,14 +48,18 @@ export async function mergeConversationWithGroupDetails(conversationList, option
|
|||||||
console.error('获取群组详细信息失败:', response?.message || '未知错误')
|
console.error('获取群组详细信息失败:', response?.message || '未知错误')
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
const groupDetailsMap = createGroupDetailsMap(response.data?.list || [])
|
const groupDetailsMap = createGroupDetailsMap(response.data?.list || [])
|
||||||
console.log('获取到的群组详细信息数量:', Object.keys(groupDetailsMap).size)
|
console.log('获取到的群组详细信息数量:', Object.keys(groupDetailsMap).size)
|
||||||
|
|
||||||
// 5. 合并数据并过滤
|
// 5. 合并数据并过滤
|
||||||
const mergedList = conversationList
|
const mergedList = conversationList
|
||||||
.map(conversation => mergeConversationData(conversation, groupDetailsMap))
|
.map(conversation => mergeConversationData(conversation, groupDetailsMap))
|
||||||
.filter(item => item !== null);
|
.filter(item => item !== null) // 过滤掉后端不存在的会话
|
||||||
|
|
||||||
console.log('合并后的会话列表数量:', mergedList.length)
|
console.log('合并后的会话列表数量:', mergedList.length)
|
||||||
console.log('过滤掉的会话数量:', conversationList.length - mergedList.length)
|
console.log('过滤掉的会话数量:', conversationList.length - mergedList.length)
|
||||||
|
|
||||||
// 6. 格式化并排序会话列表
|
// 6. 格式化并排序会话列表
|
||||||
const formattedList = mergedList
|
const formattedList = mergedList
|
||||||
.map((group) => ({
|
.map((group) => ({
|
||||||
@ -152,8 +156,8 @@ function mergeConversationData(conversation, groupDetailsMap) {
|
|||||||
// 更新显示名称(使用后端的患者信息)
|
// 更新显示名称(使用后端的患者信息)
|
||||||
name: formatConversationName(groupDetail),
|
name: formatConversationName(groupDetail),
|
||||||
|
|
||||||
// 更新头像(优先使用已有头像,避免闪动)
|
// 更新头像
|
||||||
avatar: conversation.avatar || groupDetail.patient?.avatar || '/static/default-avatar.png'
|
avatar: groupDetail.patient?.avatar || conversation.avatar || '/static/default-avatar.png'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user