chat-pc/src/components/group/GroupPanel.vue

617 lines
15 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script lang="ts" setup>
import { reactive, computed, watch, ref } from 'vue'
import { NEmpty, NPopover, NPopconfirm } from 'naive-ui'
import { useUserStore } from '@/store'
import GroupLaunch from './GroupLaunch.vue'
import GroupManage from './manage/index.vue'
import { Comment, Search, Close, Plus } from '@icon-park/vue-next'
import {
ServeGroupDetail,
ServeGetGroupMembers,
ServeSecedeGroup,
ServeUpdateGroupCard
} from '@/api/group'
import { useInject } from '@/hooks'
import customModal from '@/components/common/customModal.vue'
const userStore = useUserStore()
const { showUserInfoModal } = useInject()
const emit = defineEmits(['close', 'to-talk'])
const props = defineProps({
gid: {
type: Number,
default: 0
}
})
watch(props, () => {
loadDetail()
loadMembers()
})
const editCardPopover = ref(false)
const isShowGroup = ref(false)
const isShowManage = ref(false)
const state = reactive({
keywords: '',
detail: {
avatar: '',
name: '',
profile: '',
visit_card: '',
notice: ''
},
remark: '',
isShowModal: false, //是否显示提示模态框
customModalStyle: {
width: '724px',
height: '314px'
}, //自定义模态框样式
chatSettingOperateHint: '', // 提示信息
chatSettingOperateSubHint: '', // 次要提示信息
actionBtns: {
confirmBtn: true,
cancelBtn: true
}, // 操作按钮
})
const members = ref<any[]>([])
const search = computed<any[]>(() => {
if (state.keywords) {
return members.value.filter((item: any) => {
return (
item.nickname.match(state.keywords) != null || item.remark.match(state.keywords) != null
)
})
}
return members.value
})
const isLeader = computed(() => {
return members.value.some((item: any) => {
return item.user_id == userStore.uid && item.leader >= 1
})
})
const isAdmin = computed(() => {
return members.value.some((item: any) => {
return item.user_id == userStore.uid && item.leader == 2
})
})
const onShowManage = (vallue: any) => {
isShowManage.value = vallue
}
const onGroupCallBack = () => {}
const onToInfo = (item: any) => {
showUserInfoModal(item.user_id)
}
/**
* 加载群信息
*/
function loadDetail() {
ServeGroupDetail({
group_id: props.gid
}).then((res) => {
if (res.code == 200) {
let result = res.data
state.detail.avatar = result.avatar
state.detail.name = result.group_name
state.detail.profile = result.profile
state.detail.visit_card = result.visit_card
state.remark = result.visit_card
if (result.notice) {
state.detail.notice = result.notice
}
}
})
}
/**
* 加载成员列表
*/
function loadMembers() {
ServeGetGroupMembers({
group_id: props.gid
}).then((res) => {
if (res.code == 200) {
members.value = res.data.items || []
}
})
}
const onClose = () => {
emit('close')
}
const onSignOut = () => {
ServeSecedeGroup({
group_id: props.gid
}).then((res) => {
if (res.code == 200) {
window['$message'].success('已退出群聊')
onClose()
} else {
window['$message'].error(res.message)
}
})
}
const onChangeRemark = () => {
ServeUpdateGroupCard({
group_id: props.gid,
visit_card: state.remark
}).then(({ code, message }) => {
if (code == 200) {
// @ts-ignore
editCardPopover.value.setShow(false)
state.detail.visit_card = state.remark
window['$message'].success('已更新群名片')
loadMembers()
} else {
window['$message'].error(message)
}
})
}
loadDetail()
loadMembers()
// 处理模态框的确认
const handleModalConfirm = (closeLoading) => {
setTimeout(() => {
closeLoading()
state.isShowModal = false
}, 2000)
}
//显示聊天设置操作提示模态框
const showChatSettingOperateModal = (type: string) => {
state.isShowModal = true
switch (type) {
case 'clear':
state.chatSettingOperateHint = '确定清空聊天记录'
break
case 'dismiss':
state.chatSettingOperateHint = '确定解散本群'
break
case 'quit':
state.chatSettingOperateHint = '确定退出群聊'
const findAdmin = search.value.find((item) => item.leader === 2 || item.leader === 1)
const isLastAdmin = findAdmin && findAdmin.user_id === userStore.uid
if (isLastAdmin) {
state.chatSettingOperateSubHint = '退出后,本群将被解散'
} else {
state.chatSettingOperateSubHint = '退出后,聊天记录将被清空'
}
break
}
}
</script>
<template>
<section class="el-container is-vertical section">
<header class="el-header header bdr-b">
<div class="left-icon" @click="emit('to-talk')">
<n-icon size="21" :component="Comment" />
</div>
<div class="center-text">
<!-- <span>群信息</span> -->
<span>聊天设置</span>
</div>
<div class="right-icon">
<!-- <n-icon size="21" :component="Close" @click="onClose" /> -->
<img src="@/assets/image/icon/close-btn-grey.png" alt="" @click="onClose" />
</div>
</header>
<main class="el-main main me-scrollbar me-scrollbar-thumb">
<div class="info-box">
<div class="b-box">
<div class="block">
<div class="title">群成员</div>
<div class="text">{{ members.length }}</div>
</div>
<div class="describe">群主已开启新成员入群可查看所有聊天记录</div>
</div>
<div class="b-box">
<div class="block">
<div class="title">群名称</div>
</div>
<div class="describe">{{ state.detail.name }}</div>
</div>
<!-- <div class="b-box">
<div class="block">
<div class="title">群名片</div>
<div class="text">
<n-popover trigger="click" placement="left" ref="editCardPopover">
<template #trigger>
<n-button type="primary" text> 设置 </n-button>
</template>
<template #header> 设置我的群名片 </template>
<div style="display: flex">
<n-input
type="text"
placeholder="设置我的群名片"
maxlength="10"
v-model:value="state.remark"
@keydown.enter="onChangeRemark"
/>
<n-button type="primary" class="mt-l5" @click="onChangeRemark"> 确定 </n-button>
</div>
</n-popover>
</div>
</div>
<div class="describe">{{ state.detail.visit_card || '未设置' }}</div>
</div> -->
<!-- <div class="b-box">
<div class="block">
<div class="title">群简介</div>
</div>
<div class="describe">
{{ state.detail.profile ? state.detail.profile : '暂无群简介' }}
</div>
</div> -->
<div class="b-box">
<div class="block">
<div class="title">群类型</div>
</div>
<div class="describe">
{{ '暂无群类型' }}
</div>
</div>
<div class="b-box">
<div class="block">
<div class="title">群公告</div>
<!-- <div class="text"> -->
<!-- <n-button type="primary" text> 更多 </n-button> -->
<img class="icon-right" src="@/assets/image/icon/arrow-right-grey.png" alt="" />
<!-- </div> -->
</div>
<div class="describe">管理员未设置</div>
</div>
</div>
<div class="member-box">
<div class="flex">
<n-input placeholder="搜索" v-model:value="state.keywords" :clearable="true" round>
<template #prefix>
<n-icon :component="Search" />
</template>
</n-input>
<n-button @click="isShowGroup = true" circle class="mt-l15">
<template #icon>
<n-icon :component="Plus" color="rgb(165 165 170)" />
</template>
</n-button>
</div>
<div class="table">
<div class="theader">
<div class="avatar"></div>
<div class="nickname">用户昵称</div>
<div class="card">群名片</div>
</div>
<div class="row pointer" v-for="item in search" :key="item.id" @click="onToInfo(item)">
<div class="avatar">
<im-avatar :size="20" :src="item.avatar" :username="item.nickname" />
</div>
<div class="nickname text-ellipsis">
<span>{{ item.nickname ? item.nickname : '-' }}</span>
<span class="badge master" v-show="item.leader === 2">群主</span>
<span class="badge leader" v-show="item.leader === 1">管理员</span>
</div>
<div class="card text-ellipsis grey">
{{ item.remark || '-' }}
</div>
</div>
<div class="mt-t20 pd-t20" v-if="search.length == 0">
<n-empty size="200" description="暂无相关数据">
<template #icon>
<img src="@/assets/image/no-data.svg" alt="" />
</template>
</n-empty>
</div>
</div>
</div>
<div class="chat-settings-btns">
<n-button class="btn" type="error" ghost @click="showChatSettingOperateModal('clear')">
清空聊天记录
</n-button>
<n-button
v-if="isAdmin || isLeader"
class="btn"
type="error"
ghost
@click="showChatSettingOperateModal('dismiss')"
>
解散该群
</n-button>
<n-button class="btn" type="error" ghost @click="showChatSettingOperateModal('quit')">
退出群聊
</n-button>
</div>
</main>
<!-- <footer class="el-footer footer bdr-t"> -->
<!-- <template v-if="!isAdmin">
<n-popconfirm negative-text="取消" positive-text="确定" @positive-click="onSignOut">
<template #trigger>
<n-button class="btn" type="error" ghost> 退出群聊 </n-button>
</template>
确定要退出群吗? 退出后不再接收此群消息!
</n-popconfirm>
</template> -->
<!-- <n-button
class="btn"
type="primary"
text-color="#ffffff"
v-if="isLeader"
@click="onShowManage(true)"
>
群聊管理
</n-button> -->
<!-- </footer> -->
</section>
<GroupLaunch
v-if="isShowGroup"
:gid="gid"
@close="isShowGroup = false"
@on-submit="onGroupCallBack"
/>
<GroupManage v-if="isShowManage" :gid="gid" @close="onShowManage(false)" />
<customModal
v-model:show="state.isShowModal"
title="提示"
:style="state.customModalStyle"
:closable="false"
@confirm="handleModalConfirm"
:actionBtns="state.actionBtns"
>
<template #content>
<div class="custom-modal-content">
<text>{{ state.chatSettingOperateHint }}</text>
<text style="font-size: 16px; color: #999999; margin: 0; line-height: 22px;">{{
state.chatSettingOperateSubHint
}}</text>
</div>
</template>
</customModal>
</template>
<style lang="less" scoped>
.section {
width: 100%;
height: 100%;
.header {
width: 100%;
height: 60px;
display: flex;
align-items: center;
justify-content: center;
> div {
display: flex;
align-items: center;
justify-content: center;
}
.center-text {
flex: auto;
font-weight: 500;
font-size: 16px;
}
.left-icon,
.right-icon {
width: 50px;
height: 100%;
flex-shrink: 0;
cursor: pointer;
img {
width: 30px;
height: 30px;
}
}
}
.main {
padding: 15px;
.info-box {
.b-box {
display: flex;
align-items: center;
min-height: 30px;
margin: 12px 0;
flex-direction: column;
&:first-child {
margin-top: 0;
}
.block {
width: 100%;
// height: 30px;
display: flex;
align-items: center;
justify-content: space-between;
.title {
// height: 100%;
// line-height: 30px;
// flex: auto;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
font-size: 14px;
line-height: 20px;
color: #191919;
font-weight: bold;
}
.text {
// height: 100%;
// line-height: 30px;
// width: 30%;
text-align: right;
}
.icon-right {
width: 5px;
height: 9px;
}
}
.describe {
width: 100%;
// min-height: 24px;
// line-height: 24px;
// font-size: 13px;
// color: #b1b1b1;
// font-weight: 300;
overflow: hidden;
word-break: break-word;
font-size: 14px;
line-height: 20px;
color: #999999;
}
}
}
.member-box {
min-height: 180px;
padding: 20px 15px;
margin-bottom: 20px;
border: 1px solid var(--border-color);
border-radius: 10px;
.table {
margin-top: 15px;
.theader {
height: 36px;
border-bottom: 1px solid var(--border-color);
margin-bottom: 15px;
}
.row {
height: 30px;
margin: 3px 0;
&:hover {
.nickname {
color: #1890ff;
}
}
}
.theader,
.row {
display: flex;
align-items: center;
justify-content: center;
> div {
height: 30px;
display: flex;
align-items: center;
font-size: 13px;
}
.avatar {
width: 30px;
justify-content: flex-start;
}
.nickname {
flex: auto;
}
.card {
width: 100px;
padding-right: 8px;
justify-content: flex-end;
&.grey {
font-size: 13px;
font-weight: 300;
}
}
}
}
}
}
.chat-settings-btns {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
gap: 30px;
.btn {
width: calc(100% - 50px);
background-color: #fff;
color: #CF3050;
}
}
.footer {
display: flex;
align-items: center;
justify-content: space-around;
height: 60px;
padding: 15px;
.btn {
width: 48%;
}
}
}
.badge {
margin-left: 3px;
&.master {
color: #dc9b04 !important;
background-color: #faf1d1 !important;
}
&.leader {
color: #3370ff;
background-color: #e1eaff;
}
}
.custom-modal-content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
text {
font-size: 20px;
font-weight: 400;
color: #1f2225;
}
}
</style>