503 lines
14 KiB
Vue
503 lines
14 KiB
Vue
<template>
|
|
<div
|
|
v-if="!contactSearchingStatus"
|
|
:class="['tui-contact-list', !isPC && 'tui-contact-list-h5']"
|
|
>
|
|
<view v-if="!currentContactListKey">
|
|
<view class="top-list_box">
|
|
<view
|
|
v-for="(contactListObj, key) in contactListMap"
|
|
:key="key"
|
|
class="tui-contact-list-item"
|
|
>
|
|
<header
|
|
class="tui-contact-list-item-header"
|
|
@click="toggleCurrentContactList(key)"
|
|
>
|
|
<view class="tui-contact-list-item-header-left">
|
|
<Icon
|
|
v-if="contactListObj.icon"
|
|
:file="contactListObj.icon"
|
|
size="96rpx"
|
|
/>
|
|
<span
|
|
v-if="contactListObj.unreadCount"
|
|
class="tui-contact-list-item-header-left-unread"
|
|
>
|
|
{{ contactListObj.unreadCount }}
|
|
</span>
|
|
</view>
|
|
<view class="tui-contact-list-item-header-right">
|
|
<text>
|
|
{{ contactListObj.title }}
|
|
</text>
|
|
<!-- <Icon
|
|
:file="currentContactListKey === key ? downSVG : rightSVG"
|
|
size="20px"
|
|
/> -->
|
|
</view>
|
|
</header>
|
|
</view>
|
|
</view>
|
|
<FriendList @enterConversation="selectFriend" />
|
|
</view>
|
|
<template v-else>
|
|
<li
|
|
v-for="contactListItem in contactListMap[currentContactListKey]
|
|
.list"
|
|
:key="contactListItem.renderKey"
|
|
class="tui-contact-list-item-main-item"
|
|
:class="['selected']"
|
|
@click="selectItem(contactListItem)"
|
|
>
|
|
<ContactListItem
|
|
:key="contactListItem.renderKey"
|
|
:item="deepCopy(contactListItem)"
|
|
/>
|
|
</li>
|
|
</template>
|
|
</div>
|
|
|
|
<ul v-else-if="contactSearchingStatus" class="tui-contact-list">
|
|
<li
|
|
v-for="(item, key) in contactSearchResult"
|
|
:key="key"
|
|
class="tui-contact-list-item"
|
|
>
|
|
<div v-if="item.list[0]" class="tui-contact-search-list">
|
|
<div class="tui-contact-search-list-title">
|
|
{{ TUITranslateService.t(`TUIContact.${item.label}`) }}
|
|
</div>
|
|
<div
|
|
v-for="(listItem, index) in item.list"
|
|
:key="index"
|
|
class="tui-contact-search-list-item"
|
|
:class="['selected']"
|
|
@click="selectItem(listItem)"
|
|
>
|
|
<ContactListItem
|
|
:item="listItem"
|
|
:display-online-status="false"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</li>
|
|
<div
|
|
v-if="isContactSearchNoResult"
|
|
class="tui-contact-search-list-default"
|
|
>
|
|
{{ TUITranslateService.t('TUIContact.无搜索结果') }}
|
|
</div>
|
|
</ul>
|
|
</template>
|
|
<script setup lang="ts">
|
|
import {
|
|
TUITranslateService,
|
|
TUIStore,
|
|
StoreName,
|
|
TUIFriendService,
|
|
TUIUserService
|
|
} from '@tencentcloud/chat-uikit-engine-lite'
|
|
import TUICore, { TUIConstants } from '@tencentcloud/tui-core-lite'
|
|
import {
|
|
ref,
|
|
computed,
|
|
onMounted,
|
|
onUnmounted,
|
|
provide
|
|
} from '../../../adapter-vue'
|
|
import { isPC } from '../../../utils/env'
|
|
import { deepCopy } from '../../TUIChat/utils/utils'
|
|
|
|
import Icon from '../../common/Icon.vue'
|
|
import ContactListItem from './contact-list-item/index.vue'
|
|
import FriendList from './components/FriendList.vue'
|
|
|
|
import downSVG from '../../../assets/icon/down-icon.svg'
|
|
import rightSVG from '../../../assets/icon/right-icon.svg'
|
|
import newContactsSVG from '../../../assets/icon/friend-request-icon.svg'
|
|
import groupSVG from '../../../assets/icon/my-group-chat.svg'
|
|
import blackListSVG from '../../../assets/icon/blacklist-icon.svg'
|
|
import addFrienIcon from '../../../assets/icon/add-frien-icon.svg'
|
|
|
|
import type {
|
|
IContactList,
|
|
IContactSearchResult,
|
|
IBlackListUserItem,
|
|
IUserStatus,
|
|
IUserStatusMap,
|
|
IContactInfoType
|
|
} from '../../../interface'
|
|
import type {
|
|
IGroupModel,
|
|
Friend,
|
|
FriendApplication
|
|
} from '@tencentcloud/chat-uikit-engine-lite'
|
|
|
|
const currentContactListKey = ref<keyof IContactList>('')
|
|
const currentContactInfo = ref<IContactInfoType>({} as IContactInfoType)
|
|
const contactListMap = ref<IContactList>({
|
|
friendApplicationList: {
|
|
icon: newContactsSVG,
|
|
key: 'friendApplicationList',
|
|
title: '好友请求',
|
|
list: [] as FriendApplication[],
|
|
unreadCount: 0
|
|
},
|
|
currentContactSearchingStatus: {
|
|
icon: addFrienIcon,
|
|
key: 'currentContactSearchingStatus',
|
|
title: '添加好友',
|
|
list: [] as IGroupModel[]
|
|
},
|
|
groupList: {
|
|
icon: groupSVG,
|
|
key: 'groupList',
|
|
title: '我的群聊',
|
|
list: [] as IGroupModel[]
|
|
},
|
|
blackList: {
|
|
icon: blackListSVG,
|
|
key: 'blackList',
|
|
title: '黑名单',
|
|
list: [] as IBlackListUserItem[]
|
|
}
|
|
})
|
|
|
|
const contactSearchingStatus = ref<boolean>(false)
|
|
const contactSearchResult = ref<IContactSearchResult>()
|
|
const displayOnlineStatus = ref<boolean>(false)
|
|
const userOnlineStatusMap = ref<IUserStatusMap>()
|
|
|
|
const isContactSearchNoResult = computed(
|
|
(): boolean =>
|
|
!contactSearchResult?.value?.user?.list[0] &&
|
|
!contactSearchResult?.value?.group?.list[0]
|
|
)
|
|
|
|
onMounted(() => {
|
|
TUIStore.watch(StoreName.APP, {
|
|
enabledCustomerServicePlugin:
|
|
onCustomerServiceCommercialPluginUpdated
|
|
})
|
|
|
|
TUIStore.watch(StoreName.GRP, {
|
|
groupList: onGroupListUpdated
|
|
})
|
|
|
|
TUIStore.watch(StoreName.USER, {
|
|
userBlacklist: onUserBlacklistUpdated,
|
|
displayOnlineStatus: onDisplayOnlineStatusUpdated,
|
|
userStatusList: onUserStatusListUpdated
|
|
})
|
|
|
|
TUIStore.watch(StoreName.FRIEND, {
|
|
friendApplicationList: onFriendApplicationListUpdated,
|
|
friendApplicationUnreadCount: onFriendApplicationUnreadCountUpdated
|
|
})
|
|
|
|
TUIStore.watch(StoreName.CUSTOM, {
|
|
currentContactSearchingStatus:
|
|
onCurrentContactSearchingStatusUpdated,
|
|
currentContactSearchResult: onCurrentContactSearchResultUpdated,
|
|
currentContactListKey: onCurrentContactListKeyUpdated,
|
|
currentContactInfo: onCurrentContactInfoUpdated
|
|
})
|
|
})
|
|
|
|
onUnmounted(() => {
|
|
TUIStore.unwatch(StoreName.APP, {
|
|
enabledCustomerServicePlugin:
|
|
onCustomerServiceCommercialPluginUpdated
|
|
})
|
|
|
|
TUIStore.unwatch(StoreName.GRP, {
|
|
groupList: onGroupListUpdated
|
|
})
|
|
|
|
TUIStore.unwatch(StoreName.USER, {
|
|
userBlacklist: onUserBlacklistUpdated,
|
|
displayOnlineStatus: onDisplayOnlineStatusUpdated,
|
|
userStatusList: onUserStatusListUpdated
|
|
})
|
|
|
|
TUIStore.unwatch(StoreName.FRIEND, {
|
|
friendApplicationList: onFriendApplicationListUpdated,
|
|
friendApplicationUnreadCount: onFriendApplicationUnreadCountUpdated
|
|
})
|
|
|
|
TUIStore.unwatch(StoreName.CUSTOM, {
|
|
currentContactSearchingStatus:
|
|
onCurrentContactSearchingStatusUpdated,
|
|
currentContactSearchResult: onCurrentContactSearchResultUpdated,
|
|
currentContactListKey: onCurrentContactListKeyUpdated,
|
|
currentContactInfo: onCurrentContactInfoUpdated
|
|
})
|
|
})
|
|
|
|
function toggleCurrentContactList(key: keyof IContactList) {
|
|
if (key === 'currentContactSearchingStatus') {
|
|
TUIStore.update(StoreName.CUSTOM, key, true)
|
|
return
|
|
}
|
|
if (currentContactListKey.value === key) {
|
|
currentContactListKey.value = ''
|
|
currentContactInfo.value = {} as IContactInfoType
|
|
TUIStore.update(StoreName.CUSTOM, 'currentContactListKey', '')
|
|
TUIStore.update(
|
|
StoreName.CUSTOM,
|
|
'currentContactInfo',
|
|
{} as IContactInfoType
|
|
)
|
|
} else {
|
|
currentContactListKey.value = key
|
|
TUIStore.update(StoreName.CUSTOM, 'currentContactListKey', key)
|
|
|
|
if (key === 'friendApplicationList') {
|
|
TUIFriendService.setFriendApplicationRead()
|
|
}
|
|
}
|
|
}
|
|
|
|
function selectItem(item: any) {
|
|
currentContactInfo.value = item
|
|
// For a result in the search list, before viewing the contactInfo details,
|
|
// it is necessary to update the data for the "already in the group list/already in the friend list" situation to obtain more detailed information
|
|
if (contactSearchingStatus.value) {
|
|
let targetListItem
|
|
if ((currentContactInfo.value as Friend)?.userID) {
|
|
targetListItem = contactListMap.value?.friendList?.list?.find(
|
|
(item: IContactInfoType) =>
|
|
(item as Friend)?.userID ===
|
|
(currentContactInfo.value as Friend)?.userID
|
|
)
|
|
} else if ((currentContactInfo.value as IGroupModel)?.groupID) {
|
|
targetListItem = contactListMap.value?.groupList?.list?.find(
|
|
(item: IContactInfoType) =>
|
|
(item as IGroupModel)?.groupID ===
|
|
(currentContactInfo.value as IGroupModel)?.groupID
|
|
)
|
|
}
|
|
if (targetListItem) {
|
|
currentContactInfo.value = targetListItem
|
|
}
|
|
}
|
|
TUIStore.update(
|
|
StoreName.CUSTOM,
|
|
'currentContactInfo',
|
|
currentContactInfo.value
|
|
)
|
|
}
|
|
|
|
const selectFriend = (item: any) => {
|
|
TUIStore.update(
|
|
StoreName.CUSTOM,
|
|
'currentContactListKey',
|
|
'friendList'
|
|
)
|
|
selectItem(item)
|
|
}
|
|
|
|
function onDisplayOnlineStatusUpdated(status: boolean) {
|
|
displayOnlineStatus.value = status
|
|
}
|
|
|
|
function onUserStatusListUpdated(list: Map<string, IUserStatus>) {
|
|
if (list?.size > 0) {
|
|
userOnlineStatusMap.value = Object.fromEntries(list?.entries())
|
|
}
|
|
}
|
|
|
|
function onCustomerServiceCommercialPluginUpdated(isEnabled: boolean) {
|
|
if (!isEnabled) {
|
|
return
|
|
}
|
|
|
|
// After the customer purchases the customer service plug-in,
|
|
// the engine updates the enabledCustomerServicePlugin to true through the commercial capability bit.
|
|
const contactListExtensionID =
|
|
TUIConstants.TUIContact.EXTENSION.CONTACT_LIST.EXT_ID
|
|
const tuiContactExtensionList = TUICore.getExtensionList(
|
|
contactListExtensionID
|
|
)
|
|
|
|
const customerData = tuiContactExtensionList.find(
|
|
(extension: any) => {
|
|
const { name, accountList = [] } = extension.data || {}
|
|
return name === 'customer' && accountList.length > 0
|
|
}
|
|
)
|
|
|
|
if (customerData) {
|
|
const { data, text } = customerData
|
|
const { accountList } = (data || {}) as { accountList: string[] }
|
|
|
|
TUIUserService.getUserProfile({ userIDList: accountList })
|
|
.then(res => {
|
|
if (res.data.length > 0) {
|
|
const customerList = {
|
|
title: text,
|
|
list: res.data.map((item: any, index: number) => ({
|
|
...item,
|
|
renderKey: generateRenderKey('customerList', item, index),
|
|
infoKeyList: [],
|
|
btnKeyList: ['enterC2CConversation']
|
|
})),
|
|
key: 'customerList'
|
|
}
|
|
contactListMap.value = {
|
|
...contactListMap.value,
|
|
customerList
|
|
}
|
|
}
|
|
})
|
|
.catch(() => {})
|
|
}
|
|
}
|
|
|
|
function onGroupListUpdated(groupList: IGroupModel[]) {
|
|
updateContactListMap('groupList', groupList)
|
|
}
|
|
|
|
function onUserBlacklistUpdated(userBlacklist: IBlackListUserItem[]) {
|
|
updateContactListMap('blackList', userBlacklist)
|
|
}
|
|
|
|
function onFriendApplicationUnreadCountUpdated(
|
|
friendApplicationUnreadCount: number
|
|
) {
|
|
contactListMap.value.friendApplicationList.unreadCount =
|
|
friendApplicationUnreadCount
|
|
}
|
|
|
|
function onFriendApplicationListUpdated(
|
|
friendApplicationList: FriendApplication[]
|
|
) {
|
|
updateContactListMap('friendApplicationList', friendApplicationList)
|
|
}
|
|
|
|
function updateContactListMap(
|
|
key: keyof IContactList,
|
|
list: IContactInfoType[]
|
|
) {
|
|
contactListMap.value[key].list = list
|
|
contactListMap.value[key].list.map(
|
|
(item: IContactInfoType, index: number) =>
|
|
(item.renderKey = generateRenderKey(key, item, index))
|
|
)
|
|
updateCurrentContactInfoFromList(contactListMap.value[key].list, key)
|
|
}
|
|
|
|
function updateCurrentContactInfoFromList(
|
|
list: IContactInfoType[],
|
|
type: keyof IContactList
|
|
) {
|
|
if (
|
|
!(currentContactInfo.value as Friend)?.userID &&
|
|
!(currentContactInfo.value as IGroupModel)?.groupID
|
|
) {
|
|
return
|
|
}
|
|
if (
|
|
type === currentContactListKey.value ||
|
|
contactSearchingStatus.value
|
|
) {
|
|
currentContactInfo.value =
|
|
list?.find(
|
|
(item: any) =>
|
|
(item?.groupID &&
|
|
item?.groupID ===
|
|
(currentContactInfo.value as IGroupModel)?.groupID) ||
|
|
(item?.userID &&
|
|
item?.userID ===
|
|
(currentContactInfo.value as Friend)?.userID)
|
|
) || ({} as IContactInfoType)
|
|
TUIStore.update(
|
|
StoreName.CUSTOM,
|
|
'currentContactInfo',
|
|
currentContactInfo.value
|
|
)
|
|
}
|
|
}
|
|
|
|
function generateRenderKey(
|
|
contactListMapKey: keyof IContactList,
|
|
contactInfo: IContactInfoType,
|
|
index: number
|
|
) {
|
|
return `${contactListMapKey}-${
|
|
(contactInfo as Friend).userID ||
|
|
(contactInfo as IGroupModel).groupID ||
|
|
`index${index}`
|
|
}`
|
|
}
|
|
|
|
function onCurrentContactSearchResultUpdated(
|
|
searchResult: IContactSearchResult
|
|
) {
|
|
contactSearchResult.value = searchResult
|
|
}
|
|
|
|
function onCurrentContactSearchingStatusUpdated(
|
|
searchingStatus: boolean
|
|
) {
|
|
contactSearchingStatus.value = searchingStatus
|
|
TUIStore.update(
|
|
StoreName.CUSTOM,
|
|
'currentContactInfo',
|
|
{} as IContactInfoType
|
|
)
|
|
TUIStore.update(StoreName.CUSTOM, 'currentContactListKey', '')
|
|
}
|
|
|
|
function onCurrentContactInfoUpdated(contactInfo: IContactInfoType) {
|
|
currentContactInfo.value = contactInfo
|
|
}
|
|
|
|
function onCurrentContactListKeyUpdated(contactListKey: string) {
|
|
currentContactListKey.value = contactListKey
|
|
}
|
|
|
|
provide('userOnlineStatusMap', userOnlineStatusMap)
|
|
</script>
|
|
|
|
<style lang="scss" scoped src="./style/index.scss"></style>
|
|
|
|
<style lang="scss" scoped>
|
|
uni-page-body,
|
|
html,
|
|
body,
|
|
page {
|
|
width: 100% !important;
|
|
height: 100% !important;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.tui-contact-search-list-title {
|
|
padding: 16rpx 0;
|
|
}
|
|
|
|
.tui-contact-list-item-header {
|
|
&::after {
|
|
display: none !important;
|
|
}
|
|
}
|
|
|
|
.top-list_box {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
padding: 32rpx 50rpx;
|
|
.tui-contact-list-item {
|
|
.tui-contact-list-item-header {
|
|
padding: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
&:active {
|
|
background: none !important;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style>
|