From 089bf5d2378b3c4a61d795b2a92bede2c193b771 Mon Sep 17 00:00:00 2001
From: admin <344137771@qq.com>
Date: Tue, 06 Jan 2026 11:22:58 +0800
Subject: [PATCH] 1
---
src/components/group/GroupManage.vue | 921 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 921 insertions(+), 0 deletions(-)
diff --git a/src/components/group/GroupManage.vue b/src/components/group/GroupManage.vue
new file mode 100644
index 0000000..7c60852
--- /dev/null
+++ b/src/components/group/GroupManage.vue
@@ -0,0 +1,921 @@
+<template>
+ <div class="lum-dialog-mask">
+ <div class="lum-dialog-box">
+ <el-container class="container">
+ <el-header class="header no-select" height="60px">
+ <p>群管理 ({{ detail.group_name }})</p>
+ <p class="tools">
+ <i class="el-icon-close" @click="$emit('close')" />
+ </p>
+ </el-header>
+ <el-main class="main no-padding">
+ <el-container class="full-height">
+ <el-aside width="100px" class="aside-border no-select">
+ <div
+ v-for="(menu, index) in menus"
+ :key="menu.name"
+ class="menu-list"
+ :class="{ selectd: tabIndex == index }"
+ v-text="menu.name"
+ @click="triggerTab(index)"
+ />
+ </el-aside>
+
+ <!-- 群介绍模块 -->
+ <el-main v-if="tabIndex == 0">
+ <el-row>
+ <el-col :span="14">
+ <el-form ref="groupForm" :model="form" :rules="rules">
+ <el-form-item label="群名:" prop="group_name">
+ <el-input
+ v-model="form.group_name"
+ size="medium"
+ placeholder="请输入群名称"
+ maxlength="30"
+ show-word-limit
+ />
+ </el-form-item>
+ <el-form-item label="群描述:">
+ <el-input
+ v-model="form.profile"
+ type="textarea"
+ rows="3"
+ placeholder="请输入群描述"
+ />
+ </el-form-item>
+ <el-form-item>
+ <el-button
+ type="primary"
+ icon="el-icon-edit"
+ size="small"
+ :loading="loading"
+ @click="editGroup"
+ >修改信息
+ </el-button>
+ </el-form-item>
+ </el-form>
+ </el-col>
+ <el-col :span="10" class="avatar-col">
+ <div class="avatar-box">
+ <img v-show="form.avatar" :src="form.avatar" />
+ <div class="upload-icon">
+ <i class="el-icon-upload" />
+ </div>
+ <div class="upload-mask" @click="isAvatarCropper = true">
+ <i class="el-icon-plus" />
+ </div>
+ </div>
+ <p style="margin-top: 20px">设置头像</p>
+ </el-col>
+ </el-row>
+ </el-main>
+
+ <!-- 群成员模块 -->
+ <el-main v-else-if="tabIndex == 1" class="no-padding">
+ <el-container class="full-height">
+ <el-header height="50px" class="notice-header">
+ <el-input
+ v-model="keywords"
+ style="width: 200px"
+ size="small"
+ clearable
+ prefix-icon="el-icon-search"
+ :placeholder="`搜索群成员 ( 共${members.length}人 )`"
+ />
+ <p>
+ <el-button
+ plain
+ size="small"
+ icon="el-icon-plus"
+ @click="inviteFriendBox = true"
+ >邀请好友
+ </el-button>
+ <el-button
+ v-if="batchDelMember"
+ type="danger"
+ size="small"
+ icon="el-icon-delete"
+ @click="deleteMembers"
+ >确认删除
+ </el-button>
+ <el-button
+ v-else
+ plain
+ size="small"
+ icon="el-icon-finished"
+ @click="batchDelMember = true"
+ >批量操作
+ </el-button>
+ </p>
+ </el-header>
+ <el-main class="no-padding">
+ <el-scrollbar
+ class="full-height"
+ tag="section"
+ :native="false"
+ >
+ <div class="members">
+ <div
+ v-for="member in searchs"
+ class="member no-select"
+ :class="{
+ selectd: member.is_delete && batchDelMember,
+ }"
+ :key="member.user_id"
+ >
+ <div class="item-header">
+ <div class="avatar" @click="catUserDetail(member)">
+ <el-avatar :size="30" :src="member.avatar">
+ <img src="~@/assets/image/detault-avatar.jpg" />
+ </el-avatar>
+ <span class="nickname" v-text="member.nickname" />
+ <span class="larkc-tag" v-show="member.leader == 2">
+ 群主
+ </span>
+ </div>
+ <div
+ v-show="batchDelMember && member.leader != 2"
+ class="tools"
+ >
+ <i
+ class="el-icon-success"
+ :class="{ 'is-delete': member.is_delete }"
+ @click.stop="triggerDelBtn(member)"
+ />
+ </div>
+ </div>
+ <div class="profile">
+ 签名 | {{ member.motto ? member.motto : '未设置' }}
+ </div>
+ </div>
+ </div>
+ </el-scrollbar>
+ </el-main>
+ </el-container>
+ </el-main>
+
+ <!-- 群公告模块 -->
+ <el-main v-else-if="tabIndex == 2" class="no-padding">
+ <el-container class="full-height">
+ <el-header
+ class="notice-header"
+ height="50px"
+ style="padding-left: 14px"
+ >
+ <span>群公告 ({{ notice.items.length }})</span>
+ <el-button
+ plain
+ size="small"
+ icon="el-icon-plus"
+ @click="showNoticeBox(0, '', '')"
+ >
+ 添加公告
+ </el-button>
+ </el-header>
+
+ <el-main class="no-padding">
+ <el-scrollbar
+ class="full-height"
+ tag="section"
+ :native="false"
+ >
+ <div v-if="notice.items.length == 0" class="empty-notice">
+ <SvgNotData style="width: 80px; margin-bottom: 10px" />
+ <span>暂无群公告</span>
+ </div>
+
+ <div v-else class="notices">
+ <div
+ v-for="(item, index) in notice.items"
+ :key="item.id"
+ class="notice"
+ >
+ <div class="title">
+ <span
+ class="left-title"
+ v-text="item.title"
+ @click="
+ showNoticeBox(item.id, item.title, item.content)
+ "
+ ></span>
+ <span
+ class="right-tools no-select"
+ @click="catNoticeDetail(index)"
+ >{{ item.isShow ? '收起' : '展开' }}</span
+ >
+ </div>
+ <p class="datetime">
+ <el-avatar :size="15" :src="item.avatar">
+ <img src="~@/assets/image/detault-avatar.jpg" />
+ </el-avatar>
+ <span
+ class="text nickname"
+ v-text="item.nickname"
+ @click="$user(item.user_id)"
+ />
+ <span class="text">
+ 发表于 {{ item.created_at.substr(0, 16) }}
+ </span>
+ </p>
+ <p
+ class="content"
+ :class="{ retract: !item.isShow }"
+ v-text="item.content"
+ ></p>
+ </div>
+ </div>
+ </el-scrollbar>
+ </el-main>
+ </el-container>
+ </el-main>
+
+ <el-main v-else-if="tabIndex == 3" class="no-padding"> </el-main>
+ </el-container>
+ </el-main>
+ </el-container>
+ </div>
+
+ <!-- 编辑公告信息 -->
+ <div class="lum-dialog-mask animated fadeIn" v-show="notice.isShowform">
+ <div class="notice-box">
+ <h4>编辑群公告</h4>
+ <el-form ref="noticeForm" :model="notice.form" :rules="notice.rules">
+ <el-form-item label="标题" prop="title">
+ <el-input
+ v-model="notice.form.title"
+ size="medium"
+ placeholder="请输入标题..."
+ maxlength="30"
+ show-word-limit
+ />
+ </el-form-item>
+ <el-form-item label="详情" prop="content">
+ <el-input
+ v-model="notice.form.content"
+ type="textarea"
+ rows="5"
+ placeholder="请输入公告详情..."
+ maxlength="500"
+ />
+ </el-form-item>
+ <el-form-item style="text-align: right">
+ <el-button plain size="small" @click="notice.isShowform = false">
+ 取消
+ </el-button>
+ <el-button
+ type="primary"
+ size="small"
+ :loading="notice.loading"
+ @click="onSubmitNotice"
+ >提交
+ </el-button>
+ </el-form-item>
+ </el-form>
+ </div>
+ </div>
+
+ <transition name="el-fade-in-linear">
+ <AvatarCropper v-if="isAvatarCropper" @close="closeAvatarCropper" />
+ </transition>
+
+ <transition name="el-fade-in-linear">
+ <GroupLaunch
+ v-if="inviteFriendBox"
+ :group-id="groupId"
+ @close="inviteFriendBox = false"
+ @invite-success="inviteSuccess"
+ />
+ </transition>
+ </div>
+</template>
+<script>
+import AvatarCropper from '@/components/layout/AvatarCropper'
+import GroupLaunch from '@/components/group/GroupLaunch'
+import { SvgNotData } from '@/core/icons'
+import {
+ ServeGetGroupMembers,
+ ServeGetGroupNotices,
+ ServeEditGroupNotice,
+ ServeRemoveMembersGroup,
+ ServeGroupDetail,
+ ServeEditGroup,
+} from '@/api/group'
+
+export default {
+ name: 'GroupManage',
+ props: {
+ groupId: {
+ type: [String, Number],
+ default: null,
+ },
+ },
+ components: {
+ AvatarCropper,
+ GroupLaunch,
+ SvgNotData,
+ },
+ data() {
+ return {
+ // 当前选中菜单
+ tabIndex: 0,
+ menus: [
+ { name: '群信息' },
+ { name: '群成员' },
+ { name: '群公告' },
+ { name: '群设置' },
+ ],
+
+ loading: false,
+ form: {
+ group_name: '',
+ profile: '',
+ avatar: '',
+ },
+ rules: {
+ group_name: [
+ {
+ required: true,
+ message: '用户昵称不能为空!',
+ trigger: 'blur',
+ },
+ ],
+ },
+
+ detail: {
+ group_name: '',
+ profile: '',
+ avatar: '',
+ },
+
+ // 群成员列表
+ batchDelMember: false,
+ members: [],
+ keywords:"",
+
+ // 群公告相关数据
+ notice: {
+ isShowform: false,
+ loading: false,
+ form: {
+ id: 0,
+ title: '',
+ content: '',
+ },
+ rules: {
+ title: [
+ {
+ required: true,
+ message: '标题不能为空!',
+ trigger: 'blur',
+ },
+ ],
+ content: [
+ {
+ required: true,
+ message: '详情不能为空',
+ trigger: 'blur',
+ },
+ ],
+ },
+ items: [],
+ },
+
+ inviteFriendBox: false,
+ isAvatarCropper: false,
+ }
+ },
+ computed: {
+ searchs() {
+ return this.keywords == ''
+ ? this.members
+ : this.members.filter(item => {
+ return (
+ item.nickname.match(this.keywords) != null ||
+ item.user_card.match(this.keywords) != null
+ )
+ })
+ },
+ },
+ created() {
+ this.loadGroupDetail()
+ this.loadMembers()
+ this.loadNotices()
+ },
+ methods: {
+ // 加载群信息
+ loadGroupDetail() {
+ ServeGroupDetail({
+ group_id: this.groupId,
+ }).then(({ code, data }) => {
+ if (code == 200) {
+ this.form = this.detail = {
+ group_name: data.group_name,
+ profile: data.profile,
+ avatar: data.avatar,
+ }
+ }
+ })
+ },
+
+ // 加载群组成员列表
+ loadMembers() {
+ ServeGetGroupMembers({
+ group_id: this.groupId,
+ }).then(res => {
+ if (res.code == 200) {
+ this.members = res.data.map(item => {
+ item.is_delete = false
+ return item
+ })
+ }
+ })
+ },
+
+ // 加载群组公告列表
+ loadNotices() {
+ ServeGetGroupNotices({
+ group_id: this.groupId,
+ }).then(res => {
+ if (res.code == 200) {
+ this.notice.items = res.data.rows.map(item => {
+ item.isShow = false
+ return item
+ })
+ }
+ })
+ },
+
+ // 修改群信息
+ editGroup() {
+ this.$refs.groupForm.validate(valid => {
+ if (!valid) return false
+ this.loading = true
+ ServeEditGroup({
+ group_id: parseInt(this.groupId),
+ group_name: this.form.group_name,
+ profile: this.form.profile,
+ avatar: this.form.avatar,
+ })
+ .then(res => {
+ if (res.code == 200) {
+ this.detail.group_name = this.form.group_name
+ this.detail.profile = this.form.profile
+ this.detail.avatar = this.form.avatar
+
+ this.$message({
+ message: '信息修改成功...',
+ type: 'success',
+ })
+ } else {
+ this.$message('信息修改失败...')
+ }
+ })
+ .finally(() => {
+ this.loading = false
+ })
+ })
+ },
+
+ // 左侧菜单栏切换事件
+ triggerTab(i) {
+ this.tabIndex = i
+ },
+
+ // 关闭头像裁剪弹出层
+ closeAvatarCropper(type, avatar = '') {
+ this.isAvatarCropper = false
+ if (type == 1 && avatar != '') {
+ this.form.avatar = avatar
+ }
+ },
+
+ // 显示编辑公告窗口
+ showNoticeBox(id = 0, title = '', content = '') {
+ this.notice.isShowform = true
+ this.notice.form.id = id
+ this.notice.form.title = title
+ this.notice.form.content = content
+ },
+
+ // 编辑公告提交事件
+ onSubmitNotice() {
+ this.$refs.noticeForm.validate(valid => {
+ if (!valid) return false
+
+ this.notice.loading = true
+ ServeEditGroupNotice({
+ notice_id: parseInt(this.notice.form.id),
+ group_id: parseInt(this.groupId),
+ title: this.notice.form.title,
+ content: this.notice.form.content,
+ is_top: 0,
+ is_confirm: 0,
+ })
+ .then(res => {
+ if (res.code == 200) {
+ this.notice.isShowform = false
+ this.loadNotices()
+ this.$notify({
+ title: '消息提示',
+ message: this.notice.form.id
+ ? '群公告修改成功...'
+ : '群公告添加成功...',
+ type: 'success',
+ })
+ } else {
+ this.$notify({
+ title: '消息提示',
+ message: this.notice.form.id
+ ? '群公告修改失败...'
+ : '群公告添加失败...',
+ type: 'success',
+ })
+ }
+ })
+ .catch(() => {
+ this.$notify({
+ title: '消息提示',
+ message: '网络异常,请稍后再试...',
+ position: 'bottom-right',
+ type: 'warning',
+ })
+ })
+ .finally(() => {
+ this.notice.loading = false
+ })
+ })
+ },
+
+ // 展开/收起群公告详情
+ catNoticeDetail(index) {
+ this.notice.items[index].isShow = !this.notice.items[index].isShow
+ },
+
+ // 查看群成员信息事件
+ catUserDetail(item) {
+ this.$user(item.user_id)
+ },
+
+ // 选中删除成员事件
+ triggerDelBtn(member) {
+ let i = this.members.findIndex(item => {
+ return item.id === member.id
+ })
+
+ this.members[i].is_delete = !this.members[i].is_delete
+ },
+
+ // 批量删除群成员
+ deleteMembers() {
+ let ids = [],
+ names = []
+
+ this.members.forEach(item => {
+ if (item.is_delete) {
+ ids.push(item.user_id)
+ names.push(item.nickname)
+ }
+ })
+
+ if (ids.length == 0) {
+ this.batchDelMember = false
+ return
+ }
+
+ this.$confirm(`您确定要将【 ${names.join('、')}】移出群聊?`, '温馨提示', {
+ confirmButtonText: '确定删除',
+ cancelButtonText: '取消',
+ dangerouslyUseHTMLString: true,
+ })
+ .then(() => {
+ ServeRemoveMembersGroup({
+ group_id: parseInt(this.groupId),
+ members_ids: ids.join(','),
+ }).then(res => {
+ if (res.code == 200) {
+ this.loadMembers()
+ this.$notify({
+ title: '删除成功',
+ message: `已成功将群成员移除群组...`,
+ type: 'success',
+ })
+ this.batchDelMember = false
+ }
+ })
+ })
+ .catch(() => {
+ this.members.map(item => {
+ return (item.is_delete = false)
+ })
+ this.batchDelMember = false
+ })
+ },
+
+ // 好友邀请成功回调方法
+ inviteSuccess() {
+ this.inviteFriendBox = false
+ this.loadMembers()
+ },
+ },
+}
+</script>
+<style lang="less" scoped>
+.lum-dialog-box {
+ width: 80%;
+ height: 500px;
+ max-width: 800px;
+}
+
+.aside-border {
+ display: flex;
+ flex-direction: column;
+ padding: 8px;
+ border-right: 1px solid #f5f5f5;
+
+ .menu-list {
+ height: 25px;
+ line-height: 25px;
+ margin: 8px 2px;
+ font-weight: 400;
+ font-size: 13px;
+ background-color: white;
+ cursor: pointer;
+ border-left: 3px solid white;
+ padding-left: 10px;
+
+ &.selectd {
+ color: #2196f3;
+ border-color: #2196f3;
+ }
+ }
+}
+
+.avatar-col {
+ display: flex;
+ justify-content: center;
+ flex-direction: column;
+ align-items: center;
+}
+
+.avatar-box {
+ width: 100px;
+ height: 100px;
+ box-shadow: 0px 0px 7px 1px #e8e4e4;
+ border-radius: 50%;
+ position: relative;
+ cursor: pointer;
+ transition: ease 0.5s;
+
+ .upload-icon {
+ position: absolute;
+ right: 0;
+ top: 0;
+ width: 40px;
+ height: 40px;
+ border-radius: 50%;
+ background-color: rgba(184, 184, 197, 0.2);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ i {
+ font-size: 30px;
+ color: #1bb0f3;
+ }
+ }
+
+ img {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ border-radius: 50%;
+ z-index: 0;
+ }
+
+ .upload-mask {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ border-radius: 50%;
+ background-color: rgba(0, 0, 0, 0.2);
+ z-index: 3;
+ display: none;
+ justify-content: center;
+ align-items: center;
+
+ i {
+ font-size: 30px;
+ color: white;
+ }
+ }
+
+ &:hover .upload-mask {
+ display: flex;
+ }
+}
+
+/* 群成员相关 start */
+.members {
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ padding: 5px 20px;
+ justify-content: space-between;
+
+ .member {
+ width: 48%;
+ height: 70px;
+ border-radius: 3px;
+ cursor: pointer;
+ border: 1px dashed #e2dcdc;
+ margin: 5px 0;
+ padding: 3px;
+ transition: ease 0.5s;
+
+ .larkc-tag {
+ color: #3370ff;
+ background-color: #e1eaff;
+ }
+
+ .item-header {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+
+ .avatar {
+ flex: 1 1;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ padding: 3px 5px;
+
+ .nickname {
+ font-size: 13px;
+ margin: 0 5px 0 15px;
+ }
+ }
+
+ .tools {
+ flex-basis: 50px;
+ overflow: hidden;
+ text-align: right;
+ padding-right: 5px;
+
+ i {
+ color: #cccccc;
+ }
+
+ .is-delete {
+ color: #03a9f4;
+ }
+ }
+ }
+
+ .profile {
+ color: #8f8a8a;
+ font-size: 12px;
+ padding: 3px 5px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ margin: 3px 0;
+ }
+
+ &:hover,
+ &.selectd {
+ border-color: #2196f3;
+ }
+ }
+}
+
+/* 群成员相关 end */
+
+/* 公告相关 start */
+.notice-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.empty-notice {
+ width: 100%;
+ height: 100%;
+ min-height: 200px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ flex-direction: column;
+
+ span {
+ color: #cccccc;
+ font-size: 13px;
+ }
+}
+
+.notices {
+ .notice {
+ cursor: pointer;
+ min-height: 76px;
+ overflow: hidden;
+ border-bottom: 1px dashed #e2dcdc;
+ margin-bottom: 15px;
+ margin-right: 15px;
+ padding-bottom: 5px;
+ margin: 2px 20px 15px 15px;
+
+ h6 {
+ font-size: 15px;
+ font-weight: 300;
+ }
+
+ .title {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-between;
+ height: 30px;
+
+ .left-title {
+ flex: 1 1;
+ height: 100%;
+ line-height: 30px;
+ font-size: 14px;
+ }
+
+ .right-tools {
+ flex-basis: 70px;
+ flex-shrink: 0;
+ height: 100%;
+ line-height: 30px;
+ text-align: right;
+ font-weight: 300;
+ font-size: 12px;
+ color: #2196f3;
+ }
+ }
+
+ .datetime {
+ font-size: 10px;
+ color: #a59696;
+ font-weight: 300;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ margin: 10px 0;
+
+ .text {
+ margin: 0 5px;
+ }
+
+ .nickname {
+ color: #2196f3;
+ font-weight: 400;
+ }
+ }
+
+ .retract {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+
+ .content {
+ font-size: 12px;
+ line-height: 28px;
+ font-weight: 500;
+ color: #7d7a7a;
+ }
+ }
+}
+
+.notice-box {
+ position: relative;
+ padding: 28px;
+ background: #fff;
+ box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.2);
+ border-radius: 10px;
+ overflow: hidden;
+ box-sizing: border-box;
+ height: 415px;
+ width: 420px;
+
+ h4 {
+ margin-bottom: 20px;
+ font-weight: 400;
+ }
+}
+
+/* 公告相关 end */
+
+/deep/.el-scrollbar__wrap {
+ overflow-x: hidden;
+}
+</style>
--
Gitblit v1.9.3