Files
uniapp-im-shop/TUIKit/components/TUIContact/contact-info/index.vue

511 lines
14 KiB
Vue

<template>
<div
v-if="
typeof contactInfoData === 'object' &&
Object.keys(contactInfoData).length
"
:class="['tui-contact-info', !isPC && 'tui-contact-info-h5']"
>
<Navigation>
<template #left>
<div @click="resetContactSearchingUIData">
<Icon :file="backSVG" />
</div>
</template>
</Navigation>
<div
:class="[
'tui-contact-info-basic',
!isPC && 'tui-contact-info-h5-basic'
]"
>
<div
:class="[
'tui-contact-info-basic-text',
!isPC && 'tui-contact-info-h5-basic-text'
]"
>
<div
:class="[
'tui-contact-info-basic-text-name',
!isPC && 'tui-contact-info-h5-basic-text-name'
]"
>
{{ generateContactInfoName(contactInfoData) }}
</div>
<div
v-for="item in contactInfoBasicList"
:key="item.label"
:class="[
'tui-contact-info-basic-text-other',
!isPC && 'tui-contact-info-h5-basic-text-other'
]"
>
{{
`${TUITranslateService.t(`TUIContact.${item.label}`)}:
${item.data}`
}}
</div>
</div>
<img
:class="[
'tui-contact-info-basic-avatar',
!isPC && 'tui-contact-info-h5-basic-avatar'
]"
:src="generateAvatar(contactInfoData)"
/>
</div>
<div
v-if="contactInfoMoreList[0]"
:class="[
'tui-contact-info-more',
!isPC && 'tui-contact-info-h5-more'
]"
>
<div
v-for="item in contactInfoMoreList"
:key="item.key"
:class="[
'tui-contact-info-more-item',
!isPC && 'tui-contact-info-h5-more-item',
item.labelPosition === CONTACT_INFO_LABEL_POSITION.TOP
? 'tui-contact-info-more-item-top'
: 'tui-contact-info-more-item-left'
]"
>
<div
:class="[
'tui-contact-info-more-item-label',
!isPC && 'tui-contact-info-h5-more-item-label'
]"
>
{{ `${TUITranslateService.t(`TUIContact.${item.label}`)}` }}
</div>
<div
:class="[
'tui-contact-info-more-item-content',
!isPC && 'tui-contact-info-h5-more-item-content'
]"
>
<div
v-if="!item.editing"
:class="[
'tui-contact-info-more-item-content-text',
!isPC && 'tui-contact-info-h5-more-item-content-text'
]"
>
<div
:class="[
'tui-contact-info-more-item-content-text-data',
!isPC && 'tui-contact-info-h5-more-item-content-text-data'
]"
>
{{ item.data }}
</div>
<div
v-if="item.editable"
:class="[
'tui-contact-info-more-item-content-text-icon',
!isPC && 'tui-contact-info-h5-more-item-content-text-icon'
]"
@click="setEditing(item)"
>
<Icon :file="editSVG" width="14px" height="14px" />
</div>
</div>
<input
v-else-if="
item.editType === CONTACT_INFO_MORE_EDIT_TYPE.INPUT
"
v-model="item.data"
:class="[
'tui-contact-info-more-item-content-input',
!isPC && 'tui-contact-info-h5-more-item-content-input'
]"
type="text"
@confirm="onContactInfoEmitSubmit(item)"
@keyup.enter="onContactInfoEmitSubmit(item)"
/>
<textarea
v-else-if="
item.editType === CONTACT_INFO_MORE_EDIT_TYPE.TEXTAREA
"
v-model="item.data"
:class="[
'tui-contact-info-more-item-content-textarea',
!isPC && 'tui-contact-info-h5-more-item-content-textarea'
]"
confirm-type="done"
/>
<div
v-else-if="
item.editType === CONTACT_INFO_MORE_EDIT_TYPE.SWITCH
"
@click="onContactInfoEmitSubmit(item)"
>
<SwitchBar :value="item.data" />
</div>
</div>
</div>
</div>
<div
:class="[
'tui-contact-info-button',
!isPC && 'tui-contact-info-h5-button'
]"
>
<button
v-for="item in contactInfoButtonList"
:key="item.key"
:class="[
'tui-contact-info-button-item',
!isPC && 'tui-contact-info-h5-button-item',
item.type === CONTACT_INFO_BUTTON_TYPE.CANCEL
? `tui-contact-info-button-item-cancel`
: `tui-contact-info-button-item-submit`
]"
@click="onContactInfoButtonClicked(item)"
>
{{ TUITranslateService.t(`TUIContact.${item.label}`) }}
</button>
</div>
</div>
</template>
<script setup lang="ts">
import TUIChatEngine, {
TUIStore,
StoreName,
TUITranslateService,
IGroupModel,
Friend,
FriendApplication,
TUIUserService
} from '@tencentcloud/chat-uikit-engine-lite'
import { TUIGlobal } from '@tencentcloud/universal-api'
import {
ref,
computed,
onMounted,
onUnmounted
} from '../../../adapter-vue'
import { isPC } from '../../../utils/env'
import {
generateAvatar,
generateContactInfoName,
generateContactInfoBasic,
isFriend,
isApplicationType
} from '../utils/index'
import {
contactMoreInfoConfig,
contactButtonConfig
} from './contact-info-config'
import Navigation from '../../common/Navigation/index.vue'
import Icon from '../../common/Icon.vue'
import editSVG from '../../../assets/icon/edit.svg'
import backSVG from '../../../assets/icon/back.svg'
import SwitchBar from '../../common/SwitchBar/index.vue'
import {
IBlackListUserItem,
IContactInfoMoreItem,
IContactInfoButton
} from '../../../interface'
import {
CONTACT_INFO_LABEL_POSITION,
CONTACT_INFO_MORE_EDIT_TYPE,
CONTACT_INFO_BUTTON_TYPE,
CONTACT_INFO_TITLE
} from '../../../constant'
import { deepCopy } from '../../TUIChat/utils/utils'
import { useUI } from '../../../../utils/use-ui'
type IContactInfoType =
| IGroupModel
| Friend
| FriendApplication
| IBlackListUserItem
const { showLoading, hideLoading } = useUI()
const emits = defineEmits(['switchConversation'])
const contactInfoData = ref<IContactInfoType>({} as IContactInfoType)
const contactInfoBasicList = ref<
Array<{ label: string; data: string }>
>([])
const contactInfoMoreList = ref<IContactInfoMoreItem[]>([])
const contactInfoButtonList = ref<IContactInfoButton[]>([])
const contactInfoTitle = ref<string>('')
const setEditing = (item: any) => {
item.editing = true
}
const isGroup = computed((): boolean =>
(contactInfoData.value as IGroupModel)?.groupID ? true : false
)
const isApplication = computed((): boolean => {
return isApplicationType(contactInfoData?.value)
})
// is both friend, if is group type always false
const isBothFriend = ref<boolean>(false)
// is group member, including ordinary member, admin, group owner
const isGroupMember = computed((): boolean => {
return (contactInfoData.value as IGroupModel)?.selfInfo?.userID
? true
: false
})
// is in black list, if is group type always false
const isInBlackList = computed((): boolean => {
return (
!isGroup.value &&
blackList.value?.findIndex(
(item: IBlackListUserItem) =>
item?.userID ===
(contactInfoData.value as IBlackListUserItem)?.userID
) >= 0
)
})
const blackList = ref<IBlackListUserItem[]>([])
onMounted(() => {
TUIStore.watch(StoreName.CUSTOM, {
currentContactInfo: onCurrentContactInfoUpdated,
currentContactListKey: onCurrentContactListKeyUpdated
})
TUIStore.watch(StoreName.USER, {
userBlacklist: onUserBlacklistUpdated
})
})
onUnmounted(() => {
TUIStore.unwatch(StoreName.CUSTOM, {
currentContactInfo: onCurrentContactInfoUpdated,
currentContactListKey: onCurrentContactListKeyUpdated
})
TUIStore.unwatch(StoreName.USER, {
userBlacklist: onUserBlacklistUpdated
})
})
const onCurrentContactListKeyUpdated = (key: string) => {
if (CONTACT_INFO_TITLE[key]) {
contactInfoTitle.value = TUITranslateService.t(
`TUIContact.${CONTACT_INFO_TITLE[key]}`
)
}
}
const resetContactInfoUIData = () => {
contactInfoData.value = {} as IContactInfoType
contactInfoBasicList.value = []
contactInfoMoreList.value = []
contactInfoButtonList.value = []
}
const resetContactSearchingUIData = () => {
TUIStore.update(StoreName.CUSTOM, 'currentContactInfo', {})
TUIStore.update(
StoreName.CUSTOM,
'currentContactSearchingStatus',
false
)
TUIGlobal?.closeSearching && TUIGlobal?.closeSearching()
}
const onContactInfoEmitSubmit = (item: any) => {
if (item.key === 'blackList') {
// item.data = true
// resetContactSearchingUIData()
const userID = (contactInfoData.value as { userID: string }).userID
if (item.data) {
showLoading()
TUIUserService.removeFromBlacklist({ userIDList: [userID] })
.then(() => {
item.data = false
})
.finally(() => {
hideLoading()
})
} else {
showLoading()
TUIUserService.addToBlacklist({ userIDList: [userID] })
.then(() => {
item.data = true
})
.finally(() => {
hideLoading()
})
}
} else {
item.editSubmitHandler &&
item.editSubmitHandler({
item,
contactInfoData: contactInfoData.value,
isBothFriend: isBothFriend.value,
isInBlackList: isInBlackList.value
})
}
}
const onContactInfoButtonClicked = (item: any) => {
item.onClick &&
item.onClick({
contactInfoData: contactInfoData.value,
contactInfoMoreList: contactInfoMoreList.value
})
if (
item.key === 'enterGroupConversation' ||
item.key === 'enterC2CConversation'
) {
emits('switchConversation', contactInfoData.value)
resetContactSearchingUIData()
}
}
const generateMoreInfo = async () => {
if (!isApplication.value) {
if (
(!isGroup.value && !isBothFriend.value && !isInBlackList.value) ||
(isGroup.value &&
!isGroupMember.value &&
(contactInfoData.value as IGroupModel)?.type !==
TUIChatEngine?.TYPES?.GRP_AVCHATROOM)
) {
contactMoreInfoConfig.setWords.data = ''
contactInfoMoreList.value.push(contactMoreInfoConfig.setWords)
}
if (!isGroup.value && !isInBlackList.value) {
contactMoreInfoConfig.setRemark.data =
(contactInfoData.value as Friend)?.remark || ''
contactMoreInfoConfig.setRemark.editing = false
contactInfoMoreList.value.push(contactMoreInfoConfig.setRemark)
}
if (!isGroup.value && (isBothFriend.value || isInBlackList.value)) {
contactMoreInfoConfig.blackList.data =
isInBlackList.value || false
contactInfoMoreList.value.push(contactMoreInfoConfig.blackList)
}
} else {
contactMoreInfoConfig.displayWords.data =
(contactInfoData.value as FriendApplication)?.wording || ''
contactInfoMoreList.value.push(contactMoreInfoConfig.displayWords)
}
}
const generateButton = () => {
if (isInBlackList.value) {
return
}
if (isApplication.value) {
if (
(contactInfoData.value as FriendApplication)?.type ===
TUIChatEngine?.TYPES?.SNS_APPLICATION_SENT_TO_ME
) {
contactInfoButtonList?.value?.push(
contactButtonConfig.refuseFriendApplication
)
contactInfoButtonList?.value?.push(
contactButtonConfig.acceptFriendApplication
)
}
} else {
if (isGroup.value && isGroupMember.value) {
switch ((contactInfoData.value as IGroupModel)?.selfInfo?.role) {
case 'Owner':
contactInfoButtonList?.value?.push(
contactButtonConfig.dismissGroup
)
break
default:
contactInfoButtonList?.value?.push(
contactButtonConfig.quitGroup
)
break
}
contactInfoButtonList?.value?.push(
contactButtonConfig.enterGroupConversation
)
} else if (!isGroup.value && isBothFriend.value) {
contactInfoButtonList?.value?.push(
contactButtonConfig.deleteFriend
)
contactInfoButtonList?.value?.push(
contactButtonConfig.enterC2CConversation
)
} else {
if (isGroup.value) {
contactInfoButtonList?.value?.push(
(contactInfoData.value as IGroupModel)?.type ===
TUIChatEngine?.TYPES?.GRP_AVCHATROOM
? contactButtonConfig.joinAVChatGroup
: contactButtonConfig.joinGroup
)
} else {
contactInfoButtonList?.value?.push(
contactButtonConfig.addFriend
)
}
}
}
}
function onUserBlacklistUpdated(userBlacklist: IBlackListUserItem[]) {
blackList.value = userBlacklist
}
async function onCurrentContactInfoUpdated(
contactInfo: IContactInfoType
) {
if (
contactInfoData.value &&
contactInfo &&
JSON.stringify(contactInfoData.value) ===
JSON.stringify(contactInfo)
) {
return
}
resetContactInfoUIData()
// deep clone
contactInfoData.value = deepCopy(contactInfo) || {}
if (
!contactInfoData.value ||
Object.keys(contactInfoData.value)?.length === 0
) {
return
}
contactInfoBasicList.value = generateContactInfoBasic(
contactInfoData.value
)
isBothFriend.value = await isFriend(contactInfoData.value)
generateMoreInfo()
generateButton()
if (contactInfo.infoKeyList) {
contactInfoMoreList.value = contactInfo.infoKeyList.map(
(key: string) => {
return (contactMoreInfoConfig as any)[key]
}
)
}
if (contactInfo.btnKeyList) {
contactInfoButtonList.value = contactInfo.btnKeyList.map(
(key: string) => {
return (contactButtonConfig as any)[key]
}
)
}
}
</script>
<style lang="scss" scoped src="./style/index.scss"></style>
<style lang="scss" scoped>
.tui-contact-info-basic-avatar {
border-radius: 100rpx;
}
</style>