发送红包接口有问题,添加群恢复
This commit is contained in:
@@ -1,8 +1,5 @@
|
||||
<template>
|
||||
<div
|
||||
ref="conversationListInnerDomRef"
|
||||
class="tui-conversation-list"
|
||||
>
|
||||
<div ref="conversationListInnerDomRef" class="tui-conversation-list">
|
||||
<ActionsMenu
|
||||
v-if="isShowOverlay"
|
||||
:selectedConversation="currentConversation"
|
||||
@@ -16,7 +13,7 @@
|
||||
:key="index"
|
||||
:class="[
|
||||
'tui-conversation-content',
|
||||
isMobile && 'tui-conversation-content-h5 disable-select',
|
||||
isMobile && 'tui-conversation-content-h5 disable-select'
|
||||
]"
|
||||
>
|
||||
<div
|
||||
@@ -25,11 +22,15 @@
|
||||
'tui-conversation-item',
|
||||
currentConversationID === conversation.conversationID &&
|
||||
'tui-conversation-item-selected',
|
||||
conversation.isPinned && 'tui-conversation-item-pinned',
|
||||
conversation.isPinned && 'tui-conversation-item-pinned'
|
||||
]"
|
||||
@click="enterConversationChat(conversation.conversationID)"
|
||||
@longpress="showConversationActionMenu($event, conversation, index)"
|
||||
@contextmenu="showConversationActionMenu($event, conversation, index, true)"
|
||||
@longpress="
|
||||
showConversationActionMenu($event, conversation, index)
|
||||
"
|
||||
@contextmenu="
|
||||
showConversationActionMenu($event, conversation, index, true)
|
||||
"
|
||||
>
|
||||
<aside class="left">
|
||||
<Avatar
|
||||
@@ -38,17 +39,19 @@
|
||||
size="40px"
|
||||
/>
|
||||
<div
|
||||
v-if="userOnlineStatusMap && isShowUserOnlineStatus(conversation)"
|
||||
v-if="
|
||||
userOnlineStatusMap && isShowUserOnlineStatus(conversation)
|
||||
"
|
||||
:class="[
|
||||
'online-status',
|
||||
Object.keys(userOnlineStatusMap).length > 0 &&
|
||||
Object.keys(userOnlineStatusMap).includes(
|
||||
conversation.userProfile.userID
|
||||
) &&
|
||||
userOnlineStatusMap[conversation.userProfile.userID]
|
||||
.statusType === 1
|
||||
Object.keys(userOnlineStatusMap).includes(
|
||||
conversation.userProfile.userID
|
||||
) &&
|
||||
userOnlineStatusMap[conversation.userProfile.userID]
|
||||
.statusType === 1
|
||||
? 'online-status-online'
|
||||
: 'online-status-offline',
|
||||
: 'online-status-offline'
|
||||
]"
|
||||
/>
|
||||
<span
|
||||
@@ -56,7 +59,9 @@
|
||||
class="num"
|
||||
>
|
||||
{{
|
||||
conversation.unreadCount > 99 ? "99+" : conversation.unreadCount
|
||||
conversation.unreadCount > 99
|
||||
? '99+'
|
||||
: conversation.unreadCount
|
||||
}}
|
||||
</span>
|
||||
<span
|
||||
@@ -69,26 +74,40 @@
|
||||
<label class="content-header-label">
|
||||
<p class="name">{{ conversation.getShowName() }}</p>
|
||||
</label>
|
||||
<div class="middle-box">
|
||||
<div v-if="isRedEnvelope(conversation)" class="middle-box">
|
||||
<div class="middle-box-content">
|
||||
{{ redEnvelopeText(conversation) }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="middle-box">
|
||||
<span
|
||||
v-if="conversation.draftText && conversation.conversationID !== currentConversationID"
|
||||
v-if="
|
||||
conversation.draftText &&
|
||||
conversation.conversationID !== currentConversationID
|
||||
"
|
||||
class="middle-box-draft"
|
||||
>{{ TUITranslateService.t('TUIChat.[草稿]') }}</span>
|
||||
>
|
||||
{{ TUITranslateService.t('TUIChat.[草稿]') }}
|
||||
</span>
|
||||
<span
|
||||
v-else-if="
|
||||
conversation.type === 'GROUP' &&
|
||||
conversation.groupAtInfoList &&
|
||||
conversation.groupAtInfoList.length > 0
|
||||
conversation.groupAtInfoList &&
|
||||
conversation.groupAtInfoList.length > 0
|
||||
"
|
||||
class="middle-box-at"
|
||||
>{{ conversation.getGroupAtInfo() }}</span>
|
||||
>
|
||||
{{ conversation.getGroupAtInfo() }}
|
||||
</span>
|
||||
<div class="middle-box-content">
|
||||
{{ conversation.getLastMessage("text") }}
|
||||
{{ conversation.getLastMessage('text') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-footer">
|
||||
<span class="time">{{ conversation.getLastMessage("time") }}</span>
|
||||
<span class="time">
|
||||
{{ conversation.getLastMessage('time') }}
|
||||
</span>
|
||||
<Icon
|
||||
v-if="conversation.isMuted"
|
||||
:file="muteIcon"
|
||||
@@ -102,210 +121,262 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
interface IUserStatus {
|
||||
statusType: number;
|
||||
customStatus: string;
|
||||
}
|
||||
|
||||
interface IUserStatusMap {
|
||||
[userID: string]: IUserStatus;
|
||||
}
|
||||
|
||||
import { ref, onMounted, onUnmounted } from '../../../adapter-vue';
|
||||
import TUIChatEngine, {
|
||||
TUIStore,
|
||||
StoreName,
|
||||
TUIConversationService,
|
||||
TUITranslateService,
|
||||
IConversationModel,
|
||||
} from '@tencentcloud/chat-uikit-engine-lite';
|
||||
import { TUIGlobal, isIOS, addLongPressListener } from '@tencentcloud/universal-api';
|
||||
import Icon from '../../common/Icon.vue';
|
||||
import Avatar from '../../common/Avatar/index.vue';
|
||||
import ActionsMenu from '../actions-menu/index.vue';
|
||||
import muteIcon from '../../../assets/icon/mute.svg';
|
||||
import { isPC, isH5, isUniFrameWork, isMobile } from '../../../utils/env';
|
||||
|
||||
const emits = defineEmits(['handleSwitchConversation', 'getPassingRef']);
|
||||
const currentConversation = ref<IConversationModel>();
|
||||
const currentConversationID = ref<string>();
|
||||
const currentConversationDomRect = ref<DOMRect>();
|
||||
const isShowOverlay = ref<boolean>(false);
|
||||
const conversationList = ref<IConversationModel[]>([]);
|
||||
const conversationListDomRef = ref<HTMLElement | undefined>();
|
||||
const conversationListInnerDomRef = ref<HTMLElement | undefined>();
|
||||
const actionsMenuPosition = ref<{
|
||||
top: number;
|
||||
left: number | undefined;
|
||||
conversationHeight: number | undefined;
|
||||
}>({
|
||||
top: 0,
|
||||
left: undefined,
|
||||
conversationHeight: undefined,
|
||||
});
|
||||
const displayOnlineStatus = ref(false);
|
||||
const userOnlineStatusMap = ref<IUserStatusMap>();
|
||||
|
||||
let lastestOpenActionsMenuTime: number | null = null;
|
||||
|
||||
onMounted(() => {
|
||||
TUIStore.watch(StoreName.CONV, {
|
||||
currentConversationID: onCurrentConversationIDUpdated,
|
||||
conversationList: onConversationListUpdated,
|
||||
currentConversation: onCurrentConversationUpdated,
|
||||
});
|
||||
|
||||
TUIStore.watch(StoreName.USER, {
|
||||
displayOnlineStatus: onDisplayOnlineStatusUpdated,
|
||||
userStatusList: onUserStatusListUpdated,
|
||||
});
|
||||
|
||||
if (!isUniFrameWork && isIOS && !isPC) {
|
||||
addLongPressHandler();
|
||||
interface IUserStatus {
|
||||
statusType: number
|
||||
customStatus: string
|
||||
}
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
TUIStore.unwatch(StoreName.CONV, {
|
||||
currentConversationID: onCurrentConversationIDUpdated,
|
||||
conversationList: onConversationListUpdated,
|
||||
currentConversation: onCurrentConversationUpdated,
|
||||
});
|
||||
interface IUserStatusMap {
|
||||
[userID: string]: IUserStatus
|
||||
}
|
||||
|
||||
TUIStore.unwatch(StoreName.USER, {
|
||||
displayOnlineStatus: onDisplayOnlineStatusUpdated,
|
||||
userStatusList: onUserStatusListUpdated,
|
||||
});
|
||||
});
|
||||
import { ref, onMounted, onUnmounted } from '../../../adapter-vue'
|
||||
import TUIChatEngine, {
|
||||
TUIStore,
|
||||
StoreName,
|
||||
TUIConversationService,
|
||||
TUITranslateService,
|
||||
IConversationModel
|
||||
} from '@tencentcloud/chat-uikit-engine-lite'
|
||||
import {
|
||||
TUIGlobal,
|
||||
isIOS,
|
||||
addLongPressListener
|
||||
} from '@tencentcloud/universal-api'
|
||||
import Icon from '../../common/Icon.vue'
|
||||
import Avatar from '../../common/Avatar/index.vue'
|
||||
import ActionsMenu from '../actions-menu/index.vue'
|
||||
import muteIcon from '../../../assets/icon/mute.svg'
|
||||
import {
|
||||
isPC,
|
||||
isH5,
|
||||
isUniFrameWork,
|
||||
isMobile
|
||||
} from '../../../utils/env'
|
||||
import { CHAT_MSG_CUSTOM_TYPE } from '../../../constant'
|
||||
|
||||
const isShowUserOnlineStatus = (conversation: IConversationModel): boolean => {
|
||||
return (
|
||||
displayOnlineStatus.value
|
||||
&& conversation.type === TUIChatEngine.TYPES.CONV_C2C
|
||||
);
|
||||
};
|
||||
const emits = defineEmits(['handleSwitchConversation', 'getPassingRef'])
|
||||
const currentConversation = ref<IConversationModel>()
|
||||
const currentConversationID = ref<string>()
|
||||
const currentConversationDomRect = ref<DOMRect>()
|
||||
const isShowOverlay = ref<boolean>(false)
|
||||
const conversationList = ref<IConversationModel[]>([])
|
||||
const conversationListDomRef = ref<HTMLElement | undefined>()
|
||||
const conversationListInnerDomRef = ref<HTMLElement | undefined>()
|
||||
const actionsMenuPosition = ref<{
|
||||
top: number
|
||||
left: number | undefined
|
||||
conversationHeight: number | undefined
|
||||
}>({
|
||||
top: 0,
|
||||
left: undefined,
|
||||
conversationHeight: undefined
|
||||
})
|
||||
const displayOnlineStatus = ref(false)
|
||||
const userOnlineStatusMap = ref<IUserStatusMap>()
|
||||
|
||||
const showConversationActionMenu = (
|
||||
event: Event,
|
||||
conversation: IConversationModel,
|
||||
index: number,
|
||||
isContextMenuEvent?: boolean,
|
||||
) => {
|
||||
if (isContextMenuEvent) {
|
||||
event.preventDefault();
|
||||
if (isUniFrameWork) {
|
||||
return;
|
||||
let lastestOpenActionsMenuTime: number | null = null
|
||||
|
||||
onMounted(() => {
|
||||
TUIStore.watch(StoreName.CONV, {
|
||||
currentConversationID: onCurrentConversationIDUpdated,
|
||||
conversationList: onConversationListUpdated,
|
||||
currentConversation: onCurrentConversationUpdated
|
||||
})
|
||||
|
||||
TUIStore.watch(StoreName.USER, {
|
||||
displayOnlineStatus: onDisplayOnlineStatusUpdated,
|
||||
userStatusList: onUserStatusListUpdated
|
||||
})
|
||||
|
||||
if (!isUniFrameWork && isIOS && !isPC) {
|
||||
addLongPressHandler()
|
||||
}
|
||||
}
|
||||
currentConversation.value = conversation;
|
||||
lastestOpenActionsMenuTime = Date.now();
|
||||
getActionsMenuPosition(event, index);
|
||||
};
|
||||
})
|
||||
|
||||
const closeConversationActionMenu = () => {
|
||||
// Prevent continuous triggering of overlay tap events
|
||||
if (
|
||||
lastestOpenActionsMenuTime
|
||||
&& Date.now() - lastestOpenActionsMenuTime > 300
|
||||
) {
|
||||
currentConversation.value = undefined;
|
||||
isShowOverlay.value = false;
|
||||
}
|
||||
};
|
||||
onUnmounted(() => {
|
||||
TUIStore.unwatch(StoreName.CONV, {
|
||||
currentConversationID: onCurrentConversationIDUpdated,
|
||||
conversationList: onConversationListUpdated,
|
||||
currentConversation: onCurrentConversationUpdated
|
||||
})
|
||||
|
||||
const getActionsMenuPosition = (event: Event, index: number) => {
|
||||
if (isUniFrameWork) {
|
||||
if (typeof conversationListDomRef.value === 'undefined') {
|
||||
emits('getPassingRef', conversationListDomRef);
|
||||
}
|
||||
const query = TUIGlobal?.createSelectorQuery().in(conversationListDomRef.value);
|
||||
query.select(`#convlistitem-${index}`).boundingClientRect((data) => {
|
||||
if (data) {
|
||||
actionsMenuPosition.value = {
|
||||
// The uni-page-head of uni-h5 is not considered a member of the viewport, so the height of the head is manually increased.
|
||||
top: data.bottom - 44,
|
||||
// @ts-expect-error in uniapp event has touches property
|
||||
left: event.touches[0].pageX,
|
||||
conversationHeight: data.height,
|
||||
};
|
||||
isShowOverlay.value = true;
|
||||
TUIStore.unwatch(StoreName.USER, {
|
||||
displayOnlineStatus: onDisplayOnlineStatusUpdated,
|
||||
userStatusList: onUserStatusListUpdated
|
||||
})
|
||||
})
|
||||
|
||||
const isShowUserOnlineStatus = (
|
||||
conversation: IConversationModel
|
||||
): boolean => {
|
||||
return (
|
||||
displayOnlineStatus.value &&
|
||||
conversation.type === TUIChatEngine.TYPES.CONV_C2C
|
||||
)
|
||||
}
|
||||
|
||||
const showConversationActionMenu = (
|
||||
event: Event,
|
||||
conversation: IConversationModel,
|
||||
index: number,
|
||||
isContextMenuEvent?: boolean
|
||||
) => {
|
||||
if (isContextMenuEvent) {
|
||||
event.preventDefault()
|
||||
if (isUniFrameWork) {
|
||||
return
|
||||
}
|
||||
}).exec();
|
||||
} else {
|
||||
const rect = ((event.currentTarget || event.target) as HTMLElement)?.getBoundingClientRect() || {};
|
||||
if (rect) {
|
||||
actionsMenuPosition.value = {
|
||||
top: rect.bottom,
|
||||
left: isPC ? (event as MouseEvent).clientX : undefined,
|
||||
conversationHeight: rect.height,
|
||||
};
|
||||
}
|
||||
isShowOverlay.value = true;
|
||||
currentConversation.value = conversation
|
||||
lastestOpenActionsMenuTime = Date.now()
|
||||
getActionsMenuPosition(event, index)
|
||||
}
|
||||
};
|
||||
|
||||
const enterConversationChat = (conversationID: string) => {
|
||||
emits('handleSwitchConversation', conversationID);
|
||||
TUIConversationService.switchConversation(conversationID);
|
||||
};
|
||||
|
||||
function addLongPressHandler() {
|
||||
if (!conversationListInnerDomRef.value) {
|
||||
return;
|
||||
const closeConversationActionMenu = () => {
|
||||
// Prevent continuous triggering of overlay tap events
|
||||
if (
|
||||
lastestOpenActionsMenuTime &&
|
||||
Date.now() - lastestOpenActionsMenuTime > 300
|
||||
) {
|
||||
currentConversation.value = undefined
|
||||
isShowOverlay.value = false
|
||||
}
|
||||
}
|
||||
addLongPressListener({
|
||||
element: conversationListInnerDomRef.value,
|
||||
onLongPress: (event, target) => {
|
||||
const index = (Array.from(conversationListInnerDomRef.value!.children) as HTMLElement[]).indexOf(target!);
|
||||
showConversationActionMenu(event, conversationList.value[index], index);
|
||||
},
|
||||
options: {
|
||||
eventDelegation: {
|
||||
subSelector: '.tui-conversation-content',
|
||||
|
||||
const getActionsMenuPosition = (event: Event, index: number) => {
|
||||
if (isUniFrameWork) {
|
||||
if (typeof conversationListDomRef.value === 'undefined') {
|
||||
emits('getPassingRef', conversationListDomRef)
|
||||
}
|
||||
const query = TUIGlobal?.createSelectorQuery().in(
|
||||
conversationListDomRef.value
|
||||
)
|
||||
query
|
||||
.select(`#convlistitem-${index}`)
|
||||
.boundingClientRect(data => {
|
||||
if (data) {
|
||||
actionsMenuPosition.value = {
|
||||
// The uni-page-head of uni-h5 is not considered a member of the viewport, so the height of the head is manually increased.
|
||||
top: data.bottom - 44,
|
||||
// @ts-expect-error in uniapp event has touches property
|
||||
left: event.touches[0].pageX,
|
||||
conversationHeight: data.height
|
||||
}
|
||||
isShowOverlay.value = true
|
||||
}
|
||||
})
|
||||
.exec()
|
||||
} else {
|
||||
const rect =
|
||||
(
|
||||
(event.currentTarget || event.target) as HTMLElement
|
||||
)?.getBoundingClientRect() || {}
|
||||
if (rect) {
|
||||
actionsMenuPosition.value = {
|
||||
top: rect.bottom,
|
||||
left: isPC ? (event as MouseEvent).clientX : undefined,
|
||||
conversationHeight: rect.height
|
||||
}
|
||||
}
|
||||
isShowOverlay.value = true
|
||||
}
|
||||
}
|
||||
|
||||
const enterConversationChat = (conversationID: string) => {
|
||||
emits('handleSwitchConversation', conversationID)
|
||||
TUIConversationService.switchConversation(conversationID)
|
||||
}
|
||||
|
||||
function addLongPressHandler() {
|
||||
if (!conversationListInnerDomRef.value) {
|
||||
return
|
||||
}
|
||||
addLongPressListener({
|
||||
element: conversationListInnerDomRef.value,
|
||||
onLongPress: (event, target) => {
|
||||
const index = (
|
||||
Array.from(
|
||||
conversationListInnerDomRef.value!.children
|
||||
) as HTMLElement[]
|
||||
).indexOf(target!)
|
||||
showConversationActionMenu(
|
||||
event,
|
||||
conversationList.value[index],
|
||||
index
|
||||
)
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function onCurrentConversationUpdated(conversation: IConversationModel) {
|
||||
currentConversation.value = conversation;
|
||||
}
|
||||
|
||||
function onConversationListUpdated(list: IConversationModel[]) {
|
||||
conversationList.value = list;
|
||||
}
|
||||
|
||||
function onCurrentConversationIDUpdated(id: string) {
|
||||
currentConversationID.value = id;
|
||||
}
|
||||
|
||||
function onDisplayOnlineStatusUpdated(status: boolean) {
|
||||
displayOnlineStatus.value = status;
|
||||
}
|
||||
|
||||
function onUserStatusListUpdated(list: Map<string, IUserStatus>) {
|
||||
if (list.size !== 0) {
|
||||
userOnlineStatusMap.value = [...list.entries()].reduce(
|
||||
(obj, [key, value]) => {
|
||||
obj[key] = value;
|
||||
return obj;
|
||||
},
|
||||
{} as IUserStatusMap,
|
||||
);
|
||||
options: {
|
||||
eventDelegation: {
|
||||
subSelector: '.tui-conversation-content'
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
// Expose to the parent component and close actionsMenu when a sliding event is detected
|
||||
defineExpose({ closeChildren: closeConversationActionMenu });
|
||||
|
||||
function onCurrentConversationUpdated(
|
||||
conversation: IConversationModel
|
||||
) {
|
||||
currentConversation.value = conversation
|
||||
}
|
||||
|
||||
/** 是否红包 */
|
||||
const isRedEnvelope = (item: IConversationModel) => {
|
||||
if (item?.lastMessage?.payload?.data) {
|
||||
const businessID = JSON?.parse(
|
||||
item?.lastMessage?.payload?.data
|
||||
)?.businessID
|
||||
return businessID === CHAT_MSG_CUSTOM_TYPE.RED_ENVELOPE
|
||||
}
|
||||
return false
|
||||
}
|
||||
/** 红包文案 */
|
||||
const redEnvelopeText = (item: IConversationModel) => {
|
||||
const payload = JSON.parse(item.lastMessage?.payload?.data)
|
||||
const text = item.getLastMessage('text')?.split(':')
|
||||
console.log(text)
|
||||
if (text && text.length > 1) {
|
||||
return `${text[0]}:[积分红包] ${payload.title}`
|
||||
} else {
|
||||
return `[积分红包] ${payload.title}`
|
||||
}
|
||||
}
|
||||
|
||||
function onConversationListUpdated(list: IConversationModel[]) {
|
||||
conversationList.value = list
|
||||
}
|
||||
|
||||
function onCurrentConversationIDUpdated(id: string) {
|
||||
currentConversationID.value = id
|
||||
}
|
||||
|
||||
function onDisplayOnlineStatusUpdated(status: boolean) {
|
||||
displayOnlineStatus.value = status
|
||||
}
|
||||
|
||||
function onUserStatusListUpdated(list: Map<string, IUserStatus>) {
|
||||
if (list.size !== 0) {
|
||||
userOnlineStatusMap.value = [...list.entries()].reduce(
|
||||
(obj, [key, value]) => {
|
||||
obj[key] = value
|
||||
return obj
|
||||
},
|
||||
{} as IUserStatusMap
|
||||
)
|
||||
}
|
||||
}
|
||||
// Expose to the parent component and close actionsMenu when a sliding event is detected
|
||||
defineExpose({ closeChildren: closeConversationActionMenu })
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped src="./style/index.scss"></style>
|
||||
<style lang="scss" scoped>
|
||||
.disable-select {
|
||||
-webkit-touch-callout:none;
|
||||
-webkit-user-select:none;
|
||||
-khtml-user-select:none;
|
||||
-moz-user-select:none;
|
||||
-ms-user-select:none;
|
||||
user-select:none;
|
||||
}
|
||||
.disable-select {
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user