jiuyiUniapp/jiuyi/TUIKit/components/TUIChat/message-list/message-group-application/index.vue

337 lines
9.0 KiB
Vue

<template>
<div>
<div
v-if="groupApplicationCount > 0"
class="application-tips"
>
<div>
{{ groupApplicationCount }}{{ TUITranslateService.t("TUIChat.条入群申请") }}
</div>
<div
class="application-tips-btn"
@click="toggleGroupApplicationDrawerShow"
>
{{ TUITranslateService.t("TUIChat.点击处理") }}
</div>
</div>
<Drawer
ref="drawerDomInstanceRef"
:visible="isGroupApplicationDrawerShow"
:zIndex="998"
:popDirection="isMobile ? 'bottom' : 'right'"
:isFullScreen="isMobile"
:overlayColor="isMobile ? undefined : 'transparent'"
:drawerStyle="{
bottom: {
minHeight: '60vh',
maxHeight: '80vh',
borderRadius: '12px 12px 0 0',
},
right: {
width: '360px',
borderRadius: '12px 0 0 12px',
boxShadow: '0 0 10px 0 #d0d0d0',
}
}"
@onOverlayClick="toggleGroupApplicationDrawerShow"
>
<div
:class="{
'application-contaienr': true
}"
>
<header class="application-header">
<div
@click="toggleGroupApplicationDrawerShow"
>
<Icon
v-if="isPC"
:file="closeIcon"
:size="'16px'"
/>
<div v-else>
{{
TUITranslateService.t('关闭')
}}
</div>
</div>
</header>
<main>
<div
v-for="(item, index) in customGroupApplicationList"
:key="item.nick"
:class="{
'application-item': true,
'removed': item.isRemoved,
}"
>
<Avatar
:style="{
flex: '0 0 auto',
}"
:url="item.avatar"
:useSkeletonAnimation="true"
/>
<div class="application-item-info">
<div class="application-item-nick">
{{ item.nick }}
</div>
<div class="application-item-note">
{{ TUITranslateService.t("TUIChat.申请加入") }}
</div>
</div>
<div
class="application-item-operation"
>
<div
class="agree"
@click="handleApplication(item, 'Agree', index)"
>
{{ TUITranslateService.t("TUIChat.同意") }}
</div>
<div
class="reject"
@click="handleApplication(item, 'Reject', index)"
>
{{ TUITranslateService.t("TUIChat.拒绝") }}
</div>
</div>
</div>
</main>
</div>
</Drawer>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch } from '../../../../adapter-vue';
import {
TUIStore,
StoreName,
TUITranslateService,
TUIUserService,
TUIGroupService,
} from '@tencentcloud/chat-uikit-engine';
import Icon from '../../../common/Icon.vue';
import Avatar from '../../../common/Avatar/index.vue';
import Drawer from '../../../common/Drawer/index.vue';
import closeIcon from '../../../../assets/icon/close-dark.svg';
import { isPC, isMobile } from '../../../../utils/env';
import { IGroupApplication, IUserProfile, IChatResponese } from '../../../../interface';
interface IProps {
groupID: string;
}
interface ICustomGroupApplication {
nick: string;
avatar: string;
isRemoved: boolean;
application: IGroupApplication;
}
const props = withDefaults(defineProps<IProps>(), {
groupID: '',
});
const drawerDomInstanceRef = ref<InstanceType<typeof Drawer>>();
const groupApplicationCount = ref(0);
const isGroupApplicationDrawerShow = ref(false);
const customGroupApplicationList = ref<ICustomGroupApplication[]>([]);
watch(isGroupApplicationDrawerShow, (newVal) => {
if (newVal) {
generateCustomGroupApplicationList().then((list) => {
customGroupApplicationList.value = list;
groupApplicationCount.value = list.length;
});
}
});
watch(() => customGroupApplicationList.value.length, (newVal, oldVal) => {
if (oldVal > 0 && newVal === 0) {
isGroupApplicationDrawerShow.value = false;
}
});
/**
* Retrieves the current group application list based on the provided groupID.
*
* @return {Promise<IGroupApplication[]>} The list of group applications for the current group.
*/
async function getCurrentGroupApplicationList(): Promise<IGroupApplication[]> {
const result: IChatResponese<{ applicationList: IGroupApplication[] }> = await TUIGroupService.getGroupApplicationList();
const currentGroupApplicationList = result.data.applicationList.filter(application => application.groupID === props.groupID);
return currentGroupApplicationList;
}
function toggleGroupApplicationDrawerShow() {
isGroupApplicationDrawerShow.value = !isGroupApplicationDrawerShow.value;
}
async function generateCustomGroupApplicationList(): Promise<ICustomGroupApplication[]> {
const applicationList = await getCurrentGroupApplicationList();
if (applicationList.length === 0) {
return [];
}
const userIDList = applicationList.map(application => application.applicationType === 0 ? application.applicant : application.userID);
const { data: userProfileList } = await TUIUserService.getUserProfile({ userIDList }) as IChatResponese<IUserProfile[]>;
const mappingFromUserID2Profile: Record<string, IUserProfile> = {};
userProfileList.forEach((profile: IUserProfile) => {
mappingFromUserID2Profile[profile.userID] = profile;
});
const groupApplicationList: ICustomGroupApplication[] = applicationList.map((application) => {
const profile = mappingFromUserID2Profile[application.applicationType === 0 ? application.applicant : application.userID];
return {
nick: profile.nick || profile.userID || 'anonymous',
avatar: profile.avatar || '',
isRemoved: false,
application: application,
};
});
return groupApplicationList;
}
function handleApplication(customApplication: ICustomGroupApplication, action: 'Agree' | 'Reject', index: number) {
TUIGroupService.handleGroupApplication({
handleAction: action,
application: customApplication.application,
}).then(() => {
customGroupApplicationList.value[index].isRemoved = true;
setTimeout(() => {
customGroupApplicationList.value.splice(index, 1);
groupApplicationCount.value -= 1;
}, 150);
}).catch(() => {
// TODO: handle error
});
}
// --------------- mounted function ---------------
onMounted(() => {
// get current group application number on the first time entering the group
getCurrentGroupApplicationList().then((applicationList) => {
groupApplicationCount.value = applicationList.length;
});
TUIStore.watch(StoreName.GRP, {
groupSystemNoticeList: onGroupSystemNoticeListUpdated,
});
});
onUnmounted(() => {
TUIStore.unwatch(StoreName.GRP, {
groupSystemNoticeList: onGroupSystemNoticeListUpdated,
});
});
function onGroupSystemNoticeListUpdated() {
// Approving or rejecting existing applications will not trigger this callback, but new applications can trigger it.
generateCustomGroupApplicationList().then((list) => {
customGroupApplicationList.value = list;
groupApplicationCount.value = list.length;
});
}
</script>
<style scoped lang="scss">
:not(not) {
display: flex;
flex-direction: column;
box-sizing: border-box;
min-width: 0;
}
.flex-row {
flex-direction: row;
}
.application-tips {
display: flex;
flex-direction: row;
justify-content: center;
width: 100%;
padding: 5px 0;
font-size: 14px;
background-color: #fce4d3;
.application-tips-btn {
color: #006eff;
cursor: pointer;
margin-left: 12px;
}
}
.application-contaienr {
padding: 50px 18px 10px;
background-color: #fff;
height: 100%;
overflow: hidden auto;
font-size: 14px;
.application-header {
position: absolute;
top: 0;
left: 0;
right: 0;
padding: 10px 20px;
flex-direction: row-reverse;
color: #679ce1;
font-size: 14px;
}
.application-item {
display: flex;
flex-direction: row;
align-items: center;
padding: 10px 0;
transition: transform 0.15s ease-out;
& + .application-item {
border-top: 0.5px solid #d0d0d0;
}
.application-item-info {
margin-left: 8px;
margin-right: 8px;
font-size: 14px;
.application-item-nick {
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.application-item-note {
color: #989191;
font-size: 12px;
}
}
.application-item-operation {
flex-direction: row;
margin-left: auto;
padding: 8px;
flex: 0 0 auto;
font-size: 14px;
.agree{
color: #679ce1;
cursor: pointer
}
.reject{
margin-left: 12px;
color: #fb355d;
cursor: pointer
}
}
}
.removed {
transform: translateX(-100%);
}
}
</style>