123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357 |
- <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: #00b693;
- 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: #00b693;
- cursor: pointer;
- }
- .reject {
- margin-left: 12px;
- color: #fb355d;
- cursor: pointer;
- }
- }
- }
- .removed {
- transform: translateX(-100%);
- }
- }
- </style>
|