|
|
|
|
|
<template>
|
|
|
|
|
|
<div class="msg-list-wrapper" @click="handleTapMessageList" :style="{'height':msgKeyHeight}">
|
|
|
|
|
|
|
|
|
|
|
|
<scroll-view id="message-scroll-list" scroll-y="true" @scroll="handleScroll" @click.stop="nothing"
|
|
|
|
|
|
:scroll-top="scrollTop" class="message-scroll-list g_flex_column_end" style="overflow-x: hidden;height: 100%" :style="{'height':msgKeyHeight}">
|
|
|
|
|
|
<view class="g_clear_scroll" style="overflow-y: auto;overflow-x: hidden;" :style="isWeapp ? '' :paddingBottom">
|
|
|
|
|
|
<!-- :style="paddingBottom" -->
|
|
|
|
|
|
<!-- <div v-show="!noMore" @click.stop="onLoadMore" class="view-more-text">
|
|
|
|
|
|
{{ t("viewMoreText") }}
|
|
|
|
|
|
底部往上推paddingBottom + {{paddingBottom}}
|
|
|
|
|
|
// 底部往上推paddingBottom + {{paddingBottom}}
|
|
|
|
|
|
// 聊天内容高度msgKeyHeight + {{msgKeyHeight}}
|
|
|
|
|
|
{{rell}}
|
|
|
|
|
|
</div> -->
|
|
|
|
|
|
|
|
|
|
|
|
<view class="msg-tip" v-show="noMore"></view>
|
|
|
|
|
|
<div v-for="(item, index) in finalMsgs" :key="item.renderKey">
|
|
|
|
|
|
聊天区域高度{{msgKeyHeight}}
|
|
|
|
|
|
<MessageItem :msg="item" :index="index" :key="item.renderKey" :reply-msgs-map="replyMsgsMap"
|
|
|
|
|
|
:broadcastNewAudioSrc="broadcastNewAudioSrc"> </MessageItem>
|
|
|
|
|
|
<!-- {{screenHeight1}}
|
|
|
|
|
|
顶部聊天区域高度传过来{{msgKeyHeight}} 本页面{{screenHeight1}} {{rell}}-->
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 滚动条位置scrollTop + {{scrollTop}}
|
|
|
|
|
|
底部往上推paddingBottom + {{paddingBottom}}
|
|
|
|
|
|
聊天内容高度msgKeyHeight + {{msgKeyHeight}}
|
|
|
|
|
|
-->
|
|
|
|
|
|
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</scroll-view>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script lang="ts" setup>
|
|
|
|
|
|
import { ref, computed, onBeforeMount, onMounted, onUnmounted, defineProps, withDefaults, getCurrentInstance, nextTick } from "../../../utils/transformVue";
|
|
|
|
|
|
import MessageItem from "./message-item.vue";
|
|
|
|
|
|
import { events } from "../../../utils/constants";
|
|
|
|
|
|
import { caculateTimeago } from "../../../utils/date";
|
|
|
|
|
|
import { t } from "../../../utils/i18n";
|
|
|
|
|
|
import { V2NIMMessageForUI } from "@xkit-yx/im-store-v2/dist/types/types";
|
|
|
|
|
|
import { V2NIMConst } from "nim-web-sdk-ng/dist/v2/NIM_UNIAPP_SDK";
|
|
|
|
|
|
import { V2NIMTeam } from "nim-web-sdk-ng/dist/v2/NIM_UNIAPP_SDK/V2NIMTeamService";
|
|
|
|
|
|
import { autorun } from "mobx";
|
|
|
|
|
|
import { deepClone } from "../../../utils";
|
|
|
|
|
|
|
|
|
|
|
|
const props = withDefaults(
|
|
|
|
|
|
defineProps<{
|
|
|
|
|
|
msgs : V2NIMMessageForUI[];
|
|
|
|
|
|
conversationType : V2NIMConst.V2NIMConversationType;
|
|
|
|
|
|
to : string;
|
|
|
|
|
|
// loadingMore?: boolean;
|
|
|
|
|
|
noMore ?: boolean;
|
|
|
|
|
|
replyMsgsMap ?: {
|
|
|
|
|
|
[key : string] : V2NIMMessageForUI;
|
|
|
|
|
|
};
|
|
|
|
|
|
}>(),
|
|
|
|
|
|
{}
|
|
|
|
|
|
);
|
|
|
|
|
|
let scroll_old = 0
|
|
|
|
|
|
let scroll_new = 0
|
|
|
|
|
|
onBeforeMount(() => {
|
|
|
|
|
|
let team : V2NIMTeam | undefined = undefined;
|
|
|
|
|
|
|
|
|
|
|
|
autorun(() => {
|
|
|
|
|
|
team = deepClone(uni.$UIKitStore.teamStore.teams.get(props.to));
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
if (props.conversationType === V2NIMConst.V2NIMConversationType.V2NIM_CONVERSATION_TYPE_TEAM) {
|
|
|
|
|
|
uni.$UIKitStore.teamMemberStore.getTeamMemberActive({
|
|
|
|
|
|
teamId: props.to,
|
|
|
|
|
|
queryOption: {
|
|
|
|
|
|
limit: Math.max((team as unknown as V2NIMTeam)?.memberLimit || 0, 200),
|
|
|
|
|
|
roleQueryType: 0,
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uni.$on(events.AUDIO_URL_CHANGE, (url) => {
|
|
|
|
|
|
broadcastNewAudioSrc.value = url;
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
uni.$on(events.ON_SCROLL_BOTTOM, () => {
|
|
|
|
|
|
scrollToBottom();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uni.$on(events.ON_LOAD_MORE, () => {
|
|
|
|
|
|
const msg = finalMsgs.value.filter((item) => !(item.messageType === V2NIMConst.V2NIMMessageType.V2NIM_MESSAGE_TYPE_CUSTOM && ["beReCallMsg", "reCallMsg"].includes(item.recallType || "")))[0];
|
|
|
|
|
|
if (msg) {
|
|
|
|
|
|
uni.$emit(events.GET_HISTORY_MSG, msg);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
uni.$on('newScroll', () => {
|
|
|
|
|
|
// // console.log('AAAA')
|
|
|
|
|
|
const query = uni.createSelectorQuery().in(instance.proxy);
|
|
|
|
|
|
query.select(".message-scroll-list")
|
|
|
|
|
|
// .selectViewport()
|
|
|
|
|
|
.scrollOffset((res) => {
|
|
|
|
|
|
scroll_new = res.scrollHeight;
|
|
|
|
|
|
// scrollTop.value = scroll_new - scroll_old;
|
|
|
|
|
|
|
|
|
|
|
|
// // console.log("竖直滚动位置", scroll_new);
|
|
|
|
|
|
})
|
|
|
|
|
|
.exec();
|
|
|
|
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
});
|
|
|
|
|
|
// 防抖函数实现
|
|
|
|
|
|
// const debounce = (func, delay) => {
|
|
|
|
|
|
// let timer = null;
|
|
|
|
|
|
// return (...args) => {
|
|
|
|
|
|
// clearTimeout(timer);
|
|
|
|
|
|
// timer = setTimeout(() => {
|
|
|
|
|
|
// func(...args);
|
|
|
|
|
|
// }, delay);
|
|
|
|
|
|
// };
|
|
|
|
|
|
// };
|
|
|
|
|
|
let timer = null;
|
|
|
|
|
|
|
|
|
|
|
|
const handleScroll = (event) => {
|
|
|
|
|
|
// console.log(event)
|
|
|
|
|
|
// console.log(event.detail.scrollTop);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const scrollTop = event.detail.scrollTop;
|
|
|
|
|
|
if (scrollTop <= 150) {
|
|
|
|
|
|
clearTimeout(timer);
|
|
|
|
|
|
timer = setTimeout(() => {
|
|
|
|
|
|
onLoadMore();
|
|
|
|
|
|
}, 300);
|
|
|
|
|
|
// debouncedOnLoadMore();
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
const paddingBottom = ref('');
|
|
|
|
|
|
const mlwHeight = ref("");
|
|
|
|
|
|
const msgKeyHeight = ref('100%')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const screenHeight1 = ref('')
|
|
|
|
|
|
const screenHeight2 = ref('')
|
|
|
|
|
|
const isWeapp = ref(true)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
|
|
|
|
|
|
|
// 键盘高度{{keyHeight}} 输入框距离底部距离{{writeStyle}}屏幕高度{{screenHeight}}顶部聊天区域高度{{msgKeyHeight}}
|
|
|
|
|
|
uni.$on('msgKeyHeight', (res) => {
|
|
|
|
|
|
mlwHeight.value = res;
|
|
|
|
|
|
screenHeight1.value = res;
|
|
|
|
|
|
// 无论是否为小程序,都直接应用高度(移除100%的特殊处理)
|
|
|
|
|
|
if (typeof res === 'number') {
|
|
|
|
|
|
msgKeyHeight.value = `${res - 34}px`;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
msgKeyHeight.value = res; // 处理'100%'的情况
|
|
|
|
|
|
}
|
|
|
|
|
|
// 强制刷新滚动位置
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
scrollToBottom();
|
|
|
|
|
|
}, 50);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// // console.log(finalMsgs.value.length +"========================")
|
|
|
|
|
|
|
|
|
|
|
|
const query = uni.createSelectorQuery().in(instance.proxy);
|
|
|
|
|
|
query.select(".g_clear_scroll")
|
|
|
|
|
|
// .selectViewport()
|
|
|
|
|
|
.boundingClientRect((res) => {
|
|
|
|
|
|
mlwHeight.value = res.height;
|
|
|
|
|
|
uni.$emit('msgHeight', mlwHeight.value);
|
|
|
|
|
|
// // console.log('message-scroll-list的高度',res)
|
|
|
|
|
|
})
|
|
|
|
|
|
.exec();
|
|
|
|
|
|
// query.select(".msg-list-wrapper")
|
|
|
|
|
|
// // .selectViewport()
|
|
|
|
|
|
// .boundingClientRect((res) => {
|
|
|
|
|
|
// // mlwHeight.value = res.height;
|
|
|
|
|
|
|
|
|
|
|
|
// console.log('screen的高度',res.scrollHeight)
|
|
|
|
|
|
// console.log('screen的高度',res.height)
|
|
|
|
|
|
|
|
|
|
|
|
// screenHeight1.value = res.height
|
|
|
|
|
|
// screenHeight2.value = res.scrollHeight
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// uni.$emit('screenHeight', res.height);
|
|
|
|
|
|
// // // console.log('screen的高度',res.height)
|
|
|
|
|
|
// })
|
|
|
|
|
|
// .exec();
|
|
|
|
|
|
|
|
|
|
|
|
// #ifdef MP-WEIXIN
|
|
|
|
|
|
isWeapp.value = true; // 判断是否是微信小程序
|
|
|
|
|
|
query.select(".msg-list-wrapper")
|
|
|
|
|
|
.boundingClientRect((res) => {
|
|
|
|
|
|
uni.$emit('screenHeight', res.height);
|
|
|
|
|
|
})
|
|
|
|
|
|
.exec();
|
|
|
|
|
|
// #endif
|
|
|
|
|
|
// #ifdef APP-PLUS
|
|
|
|
|
|
isWeapp.value = false; // 判断是否是微信小程序
|
|
|
|
|
|
uni.$emit('screenHeight', uni.getSystemInfoSync().windowHeight);
|
|
|
|
|
|
// #endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 在message-list.vue的KeyboardHeight监听中修改
|
|
|
|
|
|
uni.$on('KeyboardHeight',(e) =>{
|
|
|
|
|
|
rell.value = "新键盘高度" + e;
|
|
|
|
|
|
if (e > 0) {
|
|
|
|
|
|
// APP端不需要额外padding,通过高度控制;小程序保留padding
|
|
|
|
|
|
paddingBottom.value = isWeapp.value ? `padding-bottom:${e}px` : '';
|
|
|
|
|
|
} else {
|
|
|
|
|
|
paddingBottom.value = `padding-bottom:0px`;
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// // #ifdef MP-WEIXIN
|
|
|
|
|
|
// if(uni.getSystemInfoSync().osName == "ios"){
|
|
|
|
|
|
uni.$on(events.KeyboardEvent, (e) => {
|
|
|
|
|
|
rell.value = "键盘高度" + e
|
|
|
|
|
|
if (e > 0) {
|
|
|
|
|
|
paddingBottom.value = `padding-bottom:${e}px`
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// e == 0 时,直接设为 0
|
|
|
|
|
|
paddingBottom.value = `padding-bottom:0px`;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
scrollToBottom();
|
|
|
|
|
|
}, 1)
|
|
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
// // #endif
|
|
|
|
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
|
|
|
uni.$off(events.ON_SCROLL_BOTTOM);
|
|
|
|
|
|
|
|
|
|
|
|
uni.$off(events.ON_LOAD_MORE);
|
|
|
|
|
|
|
|
|
|
|
|
uni.$off(events.AUDIO_URL_CHANGE);
|
|
|
|
|
|
});
|
|
|
|
|
|
const rell = ref('');
|
|
|
|
|
|
const scrollTop = ref(99999);
|
|
|
|
|
|
const finalMsgs = computed(() => {
|
|
|
|
|
|
const res : V2NIMMessageForUI[] = [];
|
|
|
|
|
|
props.msgs.forEach((item, index) => {
|
|
|
|
|
|
// 如果两条消息间隔超过5分钟,插入一条自定义时间消息
|
|
|
|
|
|
if (index > 0 && item.createTime - props.msgs[index - 1].createTime > 5 * 60 * 1000) {
|
|
|
|
|
|
res.push({
|
|
|
|
|
|
...item,
|
|
|
|
|
|
messageClientId: "time-" + item.createTime,
|
|
|
|
|
|
messageType: V2NIMConst.V2NIMMessageType.V2NIM_MESSAGE_TYPE_CUSTOM,
|
|
|
|
|
|
sendingState: V2NIMConst.V2NIMMessageSendingState.V2NIM_MESSAGE_SENDING_STATE_SUCCEEDED,
|
|
|
|
|
|
// @ts-ignore
|
|
|
|
|
|
timeValue: caculateTimeago(item.createTime),
|
|
|
|
|
|
renderKey: `${item.createTime + 1}`,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
res.push({
|
|
|
|
|
|
...item,
|
|
|
|
|
|
// @ts-ignore
|
|
|
|
|
|
renderKey: `${item.createTime}`,
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
return res;
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const broadcastNewAudioSrc = ref<string>("");
|
|
|
|
|
|
|
|
|
|
|
|
// 消息滑动到底部,建议搭配 nextTick 使用
|
|
|
|
|
|
const scrollToBottom = () => {
|
|
|
|
|
|
scrollTop.value += 9999999;
|
|
|
|
|
|
const timer = setTimeout(() => {
|
|
|
|
|
|
scrollTop.value += 1;
|
|
|
|
|
|
clearTimeout(timer);
|
|
|
|
|
|
}, 1);
|
|
|
|
|
|
};
|
|
|
|
|
|
const instance = getCurrentInstance();
|
|
|
|
|
|
|
|
|
|
|
|
const onLoadMore = () => {
|
|
|
|
|
|
|
|
|
|
|
|
if (!uni.$events || !uni.$events[events.KeyboardEvent]) {
|
|
|
|
|
|
// 如果事件未注册,直接执行 else 逻辑
|
|
|
|
|
|
console.log("KeyboardEvent not registered, executing else logic");
|
|
|
|
|
|
const query = uni.createSelectorQuery().in(instance.proxy);
|
|
|
|
|
|
query
|
|
|
|
|
|
.select(".message-scroll-list")
|
|
|
|
|
|
.scrollOffset((res) => {
|
|
|
|
|
|
scroll_old = res.scrollHeight;
|
|
|
|
|
|
})
|
|
|
|
|
|
.exec();
|
|
|
|
|
|
|
|
|
|
|
|
console.log(finalMsgs)
|
|
|
|
|
|
|
|
|
|
|
|
const msg = finalMsgs.value.filter(
|
|
|
|
|
|
(item) =>
|
|
|
|
|
|
!(
|
|
|
|
|
|
item.messageType ===
|
|
|
|
|
|
V2NIMConst.V2NIMMessageType.V2NIM_MESSAGE_TYPE_CUSTOM &&
|
|
|
|
|
|
['beReCallMsg', 'reCallMsg'].includes(item.recallType || '')
|
|
|
|
|
|
)
|
|
|
|
|
|
)[0];
|
|
|
|
|
|
if (msg) {
|
|
|
|
|
|
uni.$emit(events.GET_HISTORY_MSG, msg);
|
|
|
|
|
|
}
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// uni.$on(events.KeyboardEvent, (e) => {
|
|
|
|
|
|
// if (e > 0) {
|
|
|
|
|
|
// console.log("e>0")
|
|
|
|
|
|
// return
|
|
|
|
|
|
// }else{
|
|
|
|
|
|
// console.log("e=0")
|
|
|
|
|
|
// const query = uni.createSelectorQuery().in(instance.proxy);
|
|
|
|
|
|
// query
|
|
|
|
|
|
// .select(".message-scroll-list")
|
|
|
|
|
|
// // .selectViewport()
|
|
|
|
|
|
// .scrollOffset((res) => {
|
|
|
|
|
|
// scroll_old = res.scrollHeight;
|
|
|
|
|
|
// // // console.log("竖直滚动位置", res.scrollHeight);
|
|
|
|
|
|
// })
|
|
|
|
|
|
// .exec();
|
|
|
|
|
|
// const msg = finalMsgs.value.filter(
|
|
|
|
|
|
// (item) =>
|
|
|
|
|
|
// !(
|
|
|
|
|
|
// item.messageType ===
|
|
|
|
|
|
// V2NIMConst.V2NIMMessageType.V2NIM_MESSAGE_TYPE_CUSTOM &&
|
|
|
|
|
|
// ['beReCallMsg', 'reCallMsg'].includes(item.recallType || '')
|
|
|
|
|
|
// )
|
|
|
|
|
|
// )[0]
|
|
|
|
|
|
// if (msg) {
|
|
|
|
|
|
// uni.$emit(events.GET_HISTORY_MSG, msg)
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
// })
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
const nothing = () => {
|
|
|
|
|
|
// // console.log("nothing")
|
|
|
|
|
|
uni.$emit(events.KeyboardEvent, 0)
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
uni.$emit(events.CLOSE_PANEL);
|
|
|
|
|
|
}, 100);
|
|
|
|
|
|
};
|
|
|
|
|
|
const handleTapMessageList = () => {
|
|
|
|
|
|
uni.$emit(events.KeyboardEvent, 0)
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
uni.$emit(events.CLOSE_PANEL);
|
|
|
|
|
|
}, 100);
|
|
|
|
|
|
};
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
|
|
|
.msg-list-wrapper {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
|
|
|
|
|
|
background-color: #ededed;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.msg-tip {
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
color: #b3b7bc;
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
margin-top: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.block {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 40px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.message-scroll-list {
|
|
|
|
|
|
// height: 100%;
|
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
|
padding-bottom: 1px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.view-more-text {
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
color: #b3b7bc;
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
margin-top: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
page>view>message>view>message-list {
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.first-msg {
|
|
|
|
|
|
margin-top: 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|