mirror of
https://gitee.com/lijingbo-2021/open-anylink-web.git
synced 2026-05-21 06:37:52 +00:00
UserCard全局只放一个在顶层的LayoutContainer中,类似于单例组件的效果
This commit is contained in:
@@ -7,10 +7,9 @@ import { ArrowRight } from '@element-plus/icons-vue'
|
||||
import AvatarIcon from '@/components/common/AvatarIcon.vue'
|
||||
import AddButton from '@/components/common/AddButton.vue'
|
||||
import DeleteButton from '@/components/common/DeleteButton.vue'
|
||||
import UserCard from '@/components/card/UserCard.vue'
|
||||
import { combineId } from '@/js/utils/common'
|
||||
import { userQueryService } from '@/api/user'
|
||||
import { groupStore, userStore, messageStore } from '@/stores'
|
||||
import { groupStore, userStore, messageStore, userCardStore } from '@/stores'
|
||||
import SelectDialog from '../common/SelectDialog.vue'
|
||||
import { groupAddMembersService, groupDelMembersService } from '@/api/group'
|
||||
|
||||
@@ -20,6 +19,7 @@ const emit = defineEmits(['close'])
|
||||
const groupData = groupStore()
|
||||
const userData = userStore()
|
||||
const messageData = messageStore()
|
||||
const userCardData = userCardStore()
|
||||
const showDraw = ref(props.isShow)
|
||||
const isShowSelectDialog = ref(false)
|
||||
const method = ref('') //有加人,减人两中method
|
||||
@@ -83,8 +83,6 @@ const showMembersCount = computed(() => {
|
||||
return totalCount
|
||||
})
|
||||
|
||||
const isShowUserCard = ref(false)
|
||||
const userInfo = ref()
|
||||
const onShowUserCard = (account) => {
|
||||
const sessionId = combineId(account, myAccount.value)
|
||||
const loadingInstance = ElLoading.service(el_loading_options)
|
||||
@@ -104,11 +102,11 @@ const onShowUserCard = (account) => {
|
||||
}
|
||||
})
|
||||
}
|
||||
userInfo.value = res.data.data
|
||||
userCardData.setUserInfo(res.data.data)
|
||||
})
|
||||
.finally(() => {
|
||||
loadingInstance.close()
|
||||
isShowUserCard.value = true
|
||||
userCardData.setIsShow(true)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -272,11 +270,6 @@ const onConfirmSelect = (selected) => {
|
||||
</div>
|
||||
</div>
|
||||
</el-drawer>
|
||||
<UserCard
|
||||
:isShow="isShowUserCard"
|
||||
:userInfo="userInfo"
|
||||
@close="isShowUserCard = false"
|
||||
></UserCard>
|
||||
<SelectDialog
|
||||
v-model="isShowSelectDialog"
|
||||
:options="selectDialogOptions"
|
||||
|
||||
@@ -2,21 +2,19 @@
|
||||
import { ref, computed, onMounted, onUnmounted, nextTick } from 'vue'
|
||||
import { Close, Male, Female, Check, Edit } from '@element-plus/icons-vue'
|
||||
import avatar from '@/assets/default_avatar.png'
|
||||
import { userStore, messageStore } from '@/stores'
|
||||
import { userStore, messageStore, userCardStore } from '@/stores'
|
||||
import { combineId } from '@/js/utils/common'
|
||||
import { MsgType } from '@/proto/msg'
|
||||
import { msgChatCreateSessionService } from '@/api/message'
|
||||
|
||||
const props = defineProps(['isShow', 'userInfo'])
|
||||
const emit = defineEmits(['close'])
|
||||
|
||||
const userData = userStore()
|
||||
const messageData = messageStore()
|
||||
const userCardData = userCardStore()
|
||||
|
||||
const userCardRef = ref()
|
||||
|
||||
const sessionId = computed(() => {
|
||||
return combineId(userData.user.account, props.userInfo?.account)
|
||||
return combineId(userData.user.account, userCardData.userInfo?.account)
|
||||
})
|
||||
const mark = computed(() => {
|
||||
return messageData.sessionList[sessionId.value]?.mark || ''
|
||||
@@ -35,7 +33,7 @@ const partitioEditing = ref(false)
|
||||
const newPartitionId = ref(null)
|
||||
|
||||
const isSelf = computed(() => {
|
||||
return userData.user.account === props.userInfo.account
|
||||
return userData.user.account === userCardData.userInfo.account
|
||||
})
|
||||
|
||||
const preventClose = (event) => {
|
||||
@@ -43,7 +41,7 @@ const preventClose = (event) => {
|
||||
}
|
||||
|
||||
const closeCardIfOutside = (event) => {
|
||||
if (!props.isShow) return
|
||||
if (!userCardData.isShow) return
|
||||
if (
|
||||
!event.target.closest('.user-card') &&
|
||||
!event.target.closest('.avatar-session-item') &&
|
||||
@@ -63,14 +61,14 @@ const handleEscEvent = (event) => {
|
||||
}
|
||||
|
||||
const truncatedSignature = computed(() => {
|
||||
const signature = props.userInfo.signature || 'TA还没有个性签名。'
|
||||
const signature = userCardData.userInfo.signature || 'TA还没有个性签名。'
|
||||
const lengthLimit = 50
|
||||
return signature.length > lengthLimit ? signature.slice(0, lengthLimit) + '...' : signature
|
||||
})
|
||||
|
||||
// 关闭的时候触发
|
||||
const onClose = () => {
|
||||
emit('close')
|
||||
userCardData.setIsShow(false)
|
||||
markEditing.value = false
|
||||
}
|
||||
|
||||
@@ -88,7 +86,7 @@ const createSessionIfNotExist = async () => {
|
||||
const res = await msgChatCreateSessionService({
|
||||
sessionId: sessionId.value,
|
||||
account: userData.user.account,
|
||||
remoteId: props.userInfo.account,
|
||||
remoteId: userCardData.userInfo.account,
|
||||
sessionType: MsgType.CHAT
|
||||
})
|
||||
messageData.addSession(res.data.data)
|
||||
@@ -144,17 +142,21 @@ onUnmounted(() => {
|
||||
<template>
|
||||
<div ref="userCardRef">
|
||||
<transition name="fade">
|
||||
<div class="user-card" v-if="props.isShow" @click.self="preventClose($event)">
|
||||
<div class="user-card" v-if="userCardData.isShow" @click.self="preventClose($event)">
|
||||
<div class="header">
|
||||
<el-icon class="close-button" @click="onClose"><Close /></el-icon>
|
||||
<div class="main">
|
||||
<el-avatar class="avatar" :src="props.userInfo.avatarThumb || avatar" />
|
||||
<el-avatar class="avatar" :src="userCardData.userInfo.avatarThumb || avatar" />
|
||||
<div class="gender">
|
||||
<el-icon v-if="props.userInfo.gender === 1" color="#508afe"><Male /></el-icon>
|
||||
<el-icon v-if="props.userInfo.gender === 2" color="#ff5722"><Female /></el-icon>
|
||||
<el-icon v-if="userCardData.userInfo.gender === 1" color="#508afe"><Male /></el-icon>
|
||||
<el-icon v-if="userCardData.userInfo.gender === 2" color="#ff5722"
|
||||
><Female
|
||||
/></el-icon>
|
||||
</div>
|
||||
<div class="nickname">
|
||||
{{ props.userInfo.nickName || '未设置昵称' }}({{ props.userInfo.account }})
|
||||
{{ userCardData.userInfo.nickName || '未设置昵称' }}({{
|
||||
userCardData.userInfo.account
|
||||
}})
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -165,15 +167,15 @@ onUnmounted(() => {
|
||||
</el-text>
|
||||
<div class="info-item phone">
|
||||
<span class="label">手机:</span>
|
||||
<span class="value">{{ props.userInfo.phoneNum || '-' }}</span>
|
||||
<span class="value">{{ userCardData.userInfo.phoneNum || '-' }}</span>
|
||||
</div>
|
||||
<div class="info-item email">
|
||||
<span class="label">邮箱:</span>
|
||||
<span class="value">{{ props.userInfo.email || '-' }}</span>
|
||||
<span class="value">{{ userCardData.userInfo.email || '-' }}</span>
|
||||
</div>
|
||||
<div class="info-item nickname">
|
||||
<span class="label">部门:</span>
|
||||
<span class="value">{{ props.userInfo.organize || '-' }}</span>
|
||||
<span class="value">{{ userCardData.userInfo.organize || '-' }}</span>
|
||||
</div>
|
||||
<div v-if="!isSelf" class="info-item mark">
|
||||
<span class="label">备注:</span>
|
||||
|
||||
@@ -10,3 +10,4 @@ export * from './group'
|
||||
export * from './setting'
|
||||
export * from './message'
|
||||
export * from './search'
|
||||
export * from './userCard'
|
||||
|
||||
26
src/stores/userCard.js
Normal file
26
src/stores/userCard.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import {} from '@/api/group'
|
||||
|
||||
// userCard用户详情卡片相关的缓存数据,不持久化存储
|
||||
export const userCardStore = defineStore('anyim-userCard', () => {
|
||||
const isShow = ref(false)
|
||||
|
||||
const userInfo = ref({})
|
||||
|
||||
const setIsShow = (flag) => {
|
||||
isShow.value = flag
|
||||
}
|
||||
|
||||
const setUserInfo = (info) => {
|
||||
userInfo.value = info
|
||||
}
|
||||
|
||||
return {
|
||||
isShow,
|
||||
userInfo,
|
||||
|
||||
setIsShow,
|
||||
setUserInfo
|
||||
}
|
||||
})
|
||||
@@ -3,9 +3,8 @@ import { ref, onMounted, computed } from 'vue'
|
||||
import { Search } from '@element-plus/icons-vue'
|
||||
import AddButton from '@/components/common/AddButton.vue'
|
||||
import HashNoData from '@/components/common/HasNoData.vue'
|
||||
import UserCard from '@/components/card/UserCard.vue'
|
||||
import SelectDialog from '@/components/common/SelectDialog.vue'
|
||||
import { groupStore, userStore, messageStore } from '@/stores'
|
||||
import { groupStore, userStore, messageStore, userCardStore } from '@/stores'
|
||||
import { combineId } from '@/js/utils/common'
|
||||
import { userQueryService } from '@/api/user'
|
||||
import { ElLoading, ElMessage } from 'element-plus'
|
||||
@@ -19,6 +18,7 @@ const props = defineProps(['tab'])
|
||||
const groupData = groupStore()
|
||||
const userData = userStore()
|
||||
const messageData = messageStore()
|
||||
const userCardData = userCardStore()
|
||||
const searchKey = ref('')
|
||||
const isShowSelectDialog = ref(false)
|
||||
const showData = ref({})
|
||||
@@ -145,8 +145,6 @@ const onCreateGroup = () => {
|
||||
isShowSelectDialog.value = true
|
||||
}
|
||||
|
||||
const isShowUserCard = ref(false)
|
||||
const userInfo = ref()
|
||||
const onShowUserCard = (account) => {
|
||||
const sessionId = combineId(account, userData.user.account)
|
||||
const loadingInstance = ElLoading.service(el_loading_options)
|
||||
@@ -166,11 +164,11 @@ const onShowUserCard = (account) => {
|
||||
}
|
||||
})
|
||||
}
|
||||
userInfo.value = res.data.data
|
||||
userCardData.setUserInfo(res.data.data)
|
||||
})
|
||||
.finally(() => {
|
||||
loadingInstance.close()
|
||||
isShowUserCard.value = true
|
||||
userCardData.setIsShow(true)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -258,11 +256,6 @@ const onGroupCardClose = () => {
|
||||
<div style="font-size: 16px; font-weight: bold; white-space: nowrap">创建群组</div>
|
||||
</template>
|
||||
</SelectDialog>
|
||||
<UserCard
|
||||
:isShow="isShowUserCard"
|
||||
:userInfo="userInfo"
|
||||
@close="isShowUserCard = false"
|
||||
></UserCard>
|
||||
<GroupCard
|
||||
:isShow="isShowGroupCard"
|
||||
:groupInfo="showGroupInfo"
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
<script setup>
|
||||
import { ref, onMounted, computed } from 'vue'
|
||||
import { userQueryService } from '@/api/user'
|
||||
import { messageStore } from '@/stores'
|
||||
import { messageStore, userCardStore } from '@/stores'
|
||||
import ContactListUserItem from '@/views/contactList/user/components/ContactListUserItem.vue'
|
||||
import UserCard from '@/components/card/UserCard.vue'
|
||||
import { ElLoading } from 'element-plus'
|
||||
import { el_loading_options } from '@/const/commonConst'
|
||||
import { Search } from '@element-plus/icons-vue'
|
||||
@@ -11,6 +10,7 @@ import HashNoData from '@/components/common/HasNoData.vue'
|
||||
import { MsgType } from '@/proto/msg'
|
||||
|
||||
const messageData = messageStore()
|
||||
const userCardData = userCardStore()
|
||||
|
||||
const totalCount = computed(() => {
|
||||
return Object.keys(allData.value).length
|
||||
@@ -51,8 +51,6 @@ const allData = computed(() => {
|
||||
}
|
||||
})
|
||||
|
||||
const isShowUserCard = ref(false)
|
||||
const userInfo = ref()
|
||||
const onShowUserCard = ({ sessionId, account }) => {
|
||||
const loadingInstance = ElLoading.service(el_loading_options)
|
||||
userQueryService({ account: account })
|
||||
@@ -69,11 +67,11 @@ const onShowUserCard = ({ sessionId, account }) => {
|
||||
email: res.data.data.email
|
||||
}
|
||||
})
|
||||
userInfo.value = messageData.sessionList[sessionId].objectInfo
|
||||
userCardData.setUserInfo(messageData.sessionList[sessionId].objectInfo)
|
||||
})
|
||||
.finally(() => {
|
||||
loadingInstance.close()
|
||||
isShowUserCard.value = true
|
||||
userCardData.setIsShow(true)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
@@ -103,11 +101,6 @@ const onShowUserCard = ({ sessionId, account }) => {
|
||||
<HashNoData v-else :size="100"></HashNoData>
|
||||
</el-main>
|
||||
</el-container>
|
||||
<UserCard
|
||||
:isShow="isShowUserCard"
|
||||
:userInfo="userInfo"
|
||||
@close="isShowUserCard = false"
|
||||
></UserCard>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
<script setup>
|
||||
import { ref, onMounted, computed } from 'vue'
|
||||
import { userQueryService } from '@/api/user'
|
||||
import { messageStore } from '@/stores'
|
||||
import { messageStore, userCardStore } from '@/stores'
|
||||
import ContactListUserItem from '@/views/contactList/user/components/ContactListUserItem.vue'
|
||||
import UserCard from '@/components/card/UserCard.vue'
|
||||
import { ElLoading } from 'element-plus'
|
||||
import { el_loading_options } from '@/const/commonConst'
|
||||
import { Search } from '@element-plus/icons-vue'
|
||||
import HashNoData from '@/components/common/HasNoData.vue'
|
||||
|
||||
const messageData = messageStore()
|
||||
const userCardData = userCardStore()
|
||||
const totalCount = computed(() => {
|
||||
return Object.keys(markData.value).length
|
||||
})
|
||||
@@ -42,8 +42,6 @@ const markData = computed(() => {
|
||||
return data
|
||||
})
|
||||
|
||||
const isShowUserCard = ref(false)
|
||||
const userInfo = ref()
|
||||
const onShowUserCard = ({ sessionId, account }) => {
|
||||
const loadingInstance = ElLoading.service(el_loading_options)
|
||||
userQueryService({ account: account })
|
||||
@@ -60,11 +58,11 @@ const onShowUserCard = ({ sessionId, account }) => {
|
||||
email: res.data.data.email
|
||||
}
|
||||
})
|
||||
userInfo.value = messageData.sessionList[sessionId].objectInfo
|
||||
userCardData.setUserInfo(messageData.sessionList[sessionId].objectInfo)
|
||||
})
|
||||
.finally(() => {
|
||||
loadingInstance.close()
|
||||
isShowUserCard.value = true
|
||||
userCardData.setIsShow(true)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
@@ -95,11 +93,6 @@ const onShowUserCard = ({ sessionId, account }) => {
|
||||
<HashNoData v-else :size="100"></HashNoData>
|
||||
</el-main>
|
||||
</el-container>
|
||||
<UserCard
|
||||
:isShow="isShowUserCard"
|
||||
:userInfo="userInfo"
|
||||
@close="isShowUserCard = false"
|
||||
></UserCard>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -6,7 +6,6 @@ import EditDialog from '@/components/common/EditDialog.vue'
|
||||
import HashNoData from '@/components/common/HasNoData.vue'
|
||||
import PartitionOprMenu from '@/views/contactList/user/components/PartitionOprMenu.vue'
|
||||
import ContactListUserItem from '@/views/contactList/user/components/ContactListUserItem.vue'
|
||||
import UserCard from '@/components/card/UserCard.vue'
|
||||
import { userQueryService } from '@/api/user'
|
||||
import {
|
||||
msgCreatePartitionService,
|
||||
@@ -15,7 +14,7 @@ import {
|
||||
} from '@/api/message'
|
||||
import { PARTITION_TYPE } from '@/const/userConst'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { messageStore, userStore } from '@/stores'
|
||||
import { messageStore, userStore, userCardStore } from '@/stores'
|
||||
import { ElLoading } from 'element-plus'
|
||||
import { el_loading_options } from '@/const/commonConst'
|
||||
import SelectDialog from '@/components/common/SelectDialog.vue'
|
||||
@@ -23,6 +22,7 @@ import { combineId, highLightedText } from '@/js/utils/common'
|
||||
|
||||
const messageData = messageStore()
|
||||
const userData = userStore()
|
||||
const userCardData = userCardStore()
|
||||
const partitionSearchKey = ref('')
|
||||
const userSearchKey = ref('')
|
||||
const isShowAddPartitionDialog = ref(false)
|
||||
@@ -192,8 +192,6 @@ const onConfirmSelect = (selected) => {
|
||||
isShowSelectDialog.value = false
|
||||
}
|
||||
|
||||
const isShowUserCard = ref(false)
|
||||
const userInfo = ref()
|
||||
const onShowUserCard = ({ sessionId, account }) => {
|
||||
const loadingInstance = ElLoading.service(el_loading_options)
|
||||
userQueryService({ account: account })
|
||||
@@ -210,11 +208,11 @@ const onShowUserCard = ({ sessionId, account }) => {
|
||||
email: res.data.data.email
|
||||
}
|
||||
})
|
||||
userInfo.value = messageData.sessionList[sessionId].objectInfo
|
||||
userCardData.setUserInfo(messageData.sessionList[sessionId].objectInfo)
|
||||
})
|
||||
.finally(() => {
|
||||
loadingInstance.close()
|
||||
isShowUserCard.value = true
|
||||
userCardData.setIsShow(true)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -342,11 +340,6 @@ const onShowUserCardFromSelectDialog = (account) => {
|
||||
</div>
|
||||
</template>
|
||||
</SelectDialog>
|
||||
<UserCard
|
||||
:isShow="isShowUserCard"
|
||||
:userInfo="userInfo"
|
||||
@close="isShowUserCard = false"
|
||||
></UserCard>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
CREATE_WS_DELAY,
|
||||
SYNC_STATUS_INTERVAL
|
||||
} from '@/const/userConst'
|
||||
import UserCard from '@/components/card/UserCard.vue'
|
||||
|
||||
const myCardDialog = ref()
|
||||
const myAvatar = ref()
|
||||
@@ -221,6 +222,7 @@ const onExit = async () => {
|
||||
<router-view></router-view>
|
||||
</el-main>
|
||||
<MyCard ref="myCardDialog"></MyCard>
|
||||
<UserCard></UserCard>
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -23,9 +23,8 @@ import SessionItem from '@/views/message/components/SessionItem.vue'
|
||||
import InputTool from '@/views/message/components/InputTool.vue'
|
||||
import InputEditor from '@/views/message/components/InputEditor.vue'
|
||||
import MessageItem from '@/views/message/components/MessageItem.vue'
|
||||
import UserCard from '@/components/card/UserCard.vue'
|
||||
import GroupCard from '@/components/card/GroupCard.vue'
|
||||
import { userStore, settingStore, messageStore } from '@/stores'
|
||||
import { userStore, settingStore, messageStore, userCardStore } from '@/stores'
|
||||
import backgroupImage from '@/assets/messagebx_bg.webp'
|
||||
import { msgChatPullMsgService, msgChatCreateSessionService } from '@/api/message'
|
||||
import { MsgType } from '@/proto/msg'
|
||||
@@ -43,6 +42,7 @@ import EditDialog from '@/components/common/EditDialog.vue'
|
||||
const userData = userStore()
|
||||
const settingData = settingStore()
|
||||
const messageData = messageStore()
|
||||
const userCardData = userCardStore()
|
||||
const selectedSessionId = ref('') //当前被选中的session
|
||||
const sessionListRef = ref()
|
||||
|
||||
@@ -456,9 +456,6 @@ const onClickMsgContainer = () => {
|
||||
handleRead()
|
||||
}
|
||||
|
||||
const isShowUserCard = ref(false)
|
||||
const userInfoForShowCard = ref()
|
||||
|
||||
const isShowGroupCard = ref(false)
|
||||
const groupInfoForShowCard = ref()
|
||||
|
||||
@@ -468,9 +465,9 @@ const onShowUserCard = async ({ sessionId, account }) => {
|
||||
userData
|
||||
.updateUser()
|
||||
.then(() => {
|
||||
userInfoForShowCard.value = userData.user
|
||||
isShowGroupCard.value = false
|
||||
isShowUserCard.value = true
|
||||
userCardData.setUserInfo(userData.user)
|
||||
userCardData.setIsShow(true)
|
||||
})
|
||||
.finally(() => {
|
||||
//防止请求异常,导致loading关不掉
|
||||
@@ -491,9 +488,9 @@ const onShowUserCard = async ({ sessionId, account }) => {
|
||||
email: res.data.data.email
|
||||
}
|
||||
})
|
||||
userInfoForShowCard.value = messageData.sessionList[sessionId].objectInfo
|
||||
isShowGroupCard.value = false
|
||||
isShowUserCard.value = true
|
||||
userCardData.setIsShow(true)
|
||||
userCardData.setUserInfo(messageData.sessionList[sessionId].objectInfo)
|
||||
})
|
||||
.finally(() => {
|
||||
//防止请求异常,导致loading关不掉
|
||||
@@ -528,15 +525,15 @@ const onUpdateMarkConfirm = (inputValue) => {
|
||||
|
||||
// TODO
|
||||
const onShowGroupCard = () => {
|
||||
isShowUserCard.value = false
|
||||
userCardData.setIsShow(false)
|
||||
isShowGroupCard.value = true
|
||||
groupInfoForShowCard.value = {}
|
||||
}
|
||||
|
||||
const onShowContactCard = (contactInfo) => {
|
||||
userInfoForShowCard.value = contactInfo
|
||||
userCardData.setUserInfo(contactInfo)
|
||||
isShowGroupCard.value = false
|
||||
isShowUserCard.value = true
|
||||
userCardData.setIsShow(true)
|
||||
}
|
||||
|
||||
const onOpenSession = async ({ msgType, objectInfo }) => {
|
||||
@@ -794,11 +791,6 @@ const onNoneSelected = () => {
|
||||
</el-container>
|
||||
</el-main>
|
||||
</el-container>
|
||||
<UserCard
|
||||
:isShow="isShowUserCard"
|
||||
:userInfo="userInfoForShowCard"
|
||||
@close="isShowUserCard = false"
|
||||
></UserCard>
|
||||
<GroupCard
|
||||
:isShow="isShowGroupCard"
|
||||
:groupInfo="groupInfoForShowCard"
|
||||
|
||||
Reference in New Issue
Block a user