|
|
@@ -1,92 +1,96 @@
|
|
|
<template>
|
|
|
- <el-container class="group-page">
|
|
|
- <el-aside width="260px" class="group-list-box">
|
|
|
- <div class="group-list-header">
|
|
|
- <el-input class="search-text" size="small" placeholder="搜索" v-model="searchText">
|
|
|
- <i class="el-icon-search el-input__icon" slot="prefix"> </i>
|
|
|
- </el-input>
|
|
|
- <el-button plain class="add-btn" icon="el-icon-plus" title="创建群聊" @click="onCreateGroup()"></el-button>
|
|
|
- </div>
|
|
|
- <el-scrollbar class="group-list-items">
|
|
|
- <div v-for="(groups, i) in groupValues" :key="i">
|
|
|
- <div class="index-title">{{ groupKeys[i] }}</div>
|
|
|
- <div v-for="group in groups" :key="group.id">
|
|
|
- <group-item :group="group" :active="group.id == activeGroup.id" @click.native="onActiveItem(group)">
|
|
|
- </group-item>
|
|
|
- </div>
|
|
|
- <div v-if="i < groupValues.length - 1" class="divider"></div>
|
|
|
- </div>
|
|
|
- </el-scrollbar>
|
|
|
- </el-aside>
|
|
|
- <el-container class="group-box">
|
|
|
- <div class="group-header" v-show="activeGroup.id">
|
|
|
- {{ activeGroup.showGroupName }}({{ groupMembers.length }})
|
|
|
- </div>
|
|
|
- <div class="group-container">
|
|
|
- <div v-show="activeGroup.id">
|
|
|
- <div class="group-info">
|
|
|
- <div>
|
|
|
- <file-upload v-show="isOwner" class="avatar-uploader" :action="imageAction" :showLoading="true"
|
|
|
- :maxSize="maxSize" @success="onUploadSuccess"
|
|
|
- :fileTypes="['image/jpeg', 'image/png', 'image/jpg', 'image/webp']">
|
|
|
- <img v-if="activeGroup.headImage" :src="activeGroup.headImage" class="avatar">
|
|
|
- <i v-else class="el-icon-plus avatar-uploader-icon"></i>
|
|
|
- </file-upload>
|
|
|
- <head-image v-show="!isOwner" class="avatar" :size="160" :url="activeGroup.headImage"
|
|
|
- :name="activeGroup.showGroupName" radius="10%">
|
|
|
- </head-image>
|
|
|
- <el-button class="send-btn" icon="el-icon-position" type="primary" @click="onSendMessage()">发消息
|
|
|
- </el-button>
|
|
|
- </div>
|
|
|
- <el-form class="group-form" label-width="130px" :model="activeGroup" :rules="rules" size="small"
|
|
|
- ref="groupForm">
|
|
|
- <el-form-item label="群聊名称" prop="name">
|
|
|
- <el-input v-model="activeGroup.name" :disabled="!isOwner" maxlength="20"></el-input>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="群主">
|
|
|
- <el-input :value="ownerName" disabled></el-input>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="群名备注">
|
|
|
- <el-input v-model="activeGroup.remarkGroupName" :placeholder="activeGroup.name"
|
|
|
- maxlength="20"></el-input>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="我在本群的昵称">
|
|
|
- <el-input v-model="activeGroup.remarkNickName" maxlength="20"
|
|
|
- :placeholder="$store.state.userStore.userInfo.nickName"></el-input>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="群公告">
|
|
|
- <el-input v-model="activeGroup.notice" :disabled="!isOwner" type="textarea" :rows="3" maxlength="1024"
|
|
|
- placeholder="群主未设置"></el-input>
|
|
|
- </el-form-item>
|
|
|
- <div>
|
|
|
- <el-button type="warning" v-show="isOwner" @click="onInviteMember()">邀请</el-button>
|
|
|
- <el-button type="success" @click="onSaveGroup()">保存</el-button>
|
|
|
- <el-button type="danger" v-show="!isOwner" @click="onQuit()">退出</el-button>
|
|
|
- <el-button type="danger" v-show="isOwner" @click="onDissolve()">解散</el-button>
|
|
|
- </div>
|
|
|
- </el-form>
|
|
|
- </div>
|
|
|
- <el-divider content-position="center"></el-divider>
|
|
|
- <el-scrollbar ref="scrollbar" :style="'height: ' + scrollHeight + 'px'">
|
|
|
- <div class="group-member-list">
|
|
|
- <div class="group-invite">
|
|
|
- <div class="invite-member-btn" title="邀请好友进群聊" @click="onInviteMember()">
|
|
|
- <i class="el-icon-plus"></i>
|
|
|
- </div>
|
|
|
- <div class="invite-member-text">邀请</div>
|
|
|
- <add-group-member :visible="showAddGroupMember" :groupId="activeGroup.id" :members="groupMembers"
|
|
|
- @reload="loadGroupMembers" @close="onCloseAddGroupMember"></add-group-member>
|
|
|
- </div>
|
|
|
- <div v-for="(member, idx) in showMembers" :key="member.id">
|
|
|
- <group-member v-if="idx < showMaxIdx" class="group-member" :member="member"
|
|
|
- :showDel="isOwner && member.userId != activeGroup.ownerId" @del="onKick"></group-member>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </el-scrollbar>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </el-container>
|
|
|
- </el-container>
|
|
|
+ <el-container class="group-page">
|
|
|
+ <el-aside width="260px" class="group-list-box">
|
|
|
+ <div class="group-list-header">
|
|
|
+ <el-input class="search-text" size="small" placeholder="搜索" v-model="searchText">
|
|
|
+ <i class="el-icon-search el-input__icon" slot="prefix"> </i>
|
|
|
+ </el-input>
|
|
|
+ <el-button plain class="add-btn" icon="el-icon-plus" title="创建群聊" @click="onCreateGroup()"></el-button>
|
|
|
+ </div>
|
|
|
+ <el-scrollbar class="group-list-items">
|
|
|
+ <div v-for="(groups, i) in groupValues" :key="i">
|
|
|
+ <div class="index-title">{{ groupKeys[i] }}</div>
|
|
|
+ <div v-for="group in groups" :key="group.id">
|
|
|
+ <group-item :group="group" :active="group.id == activeGroup.id"
|
|
|
+ @click.native="onActiveItem(group)">
|
|
|
+ </group-item>
|
|
|
+ </div>
|
|
|
+ <div v-if="i < groupValues.length - 1" class="divider"></div>
|
|
|
+ </div>
|
|
|
+ </el-scrollbar>
|
|
|
+ </el-aside>
|
|
|
+ <el-container class="group-box">
|
|
|
+ <div class="group-header" v-show="activeGroup.id">
|
|
|
+ {{ activeGroup.showGroupName }}({{ groupMembers.length }})
|
|
|
+ </div>
|
|
|
+ <div class="group-container">
|
|
|
+ <div v-show="activeGroup.id">
|
|
|
+ <div class="group-info">
|
|
|
+ <div>
|
|
|
+ <file-upload v-show="isOwner" class="avatar-uploader" :action="imageAction"
|
|
|
+ :showLoading="true" :maxSize="maxSize" @success="onUploadSuccess"
|
|
|
+ :fileTypes="['image/jpeg', 'image/png', 'image/jpg', 'image/webp']">
|
|
|
+ <img v-if="activeGroup.headImage" :src="activeGroup.headImage" class="avatar">
|
|
|
+ <i v-else class="el-icon-plus avatar-uploader-icon"></i>
|
|
|
+ </file-upload>
|
|
|
+ <head-image v-show="!isOwner" class="avatar" :size="160" :url="activeGroup.headImage"
|
|
|
+ :name="activeGroup.showGroupName" radius="10%">
|
|
|
+ </head-image>
|
|
|
+ <el-button class="send-btn" icon="el-icon-position" type="primary"
|
|
|
+ @click="onSendMessage()">发消息
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+ <el-form class="group-form" label-width="130px" :model="activeGroup" :rules="rules" size="small"
|
|
|
+ ref="groupForm">
|
|
|
+ <el-form-item label="群聊名称" prop="name">
|
|
|
+ <el-input v-model="activeGroup.name" :disabled="!isOwner" maxlength="20"></el-input>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="群主">
|
|
|
+ <el-input :value="ownerName" disabled></el-input>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="群名备注">
|
|
|
+ <el-input v-model="activeGroup.remarkGroupName" :placeholder="activeGroup.name"
|
|
|
+ maxlength="20"></el-input>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="我在本群的昵称">
|
|
|
+ <el-input v-model="activeGroup.remarkNickName" maxlength="20"
|
|
|
+ :placeholder="$store.state.userStore.userInfo.nickName"></el-input>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="群公告">
|
|
|
+ <el-input v-model="activeGroup.notice" :disabled="!isOwner" type="textarea" :rows="3"
|
|
|
+ maxlength="1024" placeholder="群主未设置"></el-input>
|
|
|
+ </el-form-item>
|
|
|
+ <div>
|
|
|
+ <el-button type="warning" v-show="isOwner" @click="onInviteMember()">邀请</el-button>
|
|
|
+ <el-button type="success" @click="onSaveGroup()">保存</el-button>
|
|
|
+ <el-button type="danger" v-show="!isOwner" @click="onQuit()">退出</el-button>
|
|
|
+ <el-button type="danger" v-show="isOwner" @click="onDissolve()">解散</el-button>
|
|
|
+ </div>
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+ <el-divider content-position="center"></el-divider>
|
|
|
+ <el-scrollbar ref="scrollbar" :style="'height: ' + scrollHeight + 'px'">
|
|
|
+ <div class="group-member-list">
|
|
|
+ <div class="group-invite">
|
|
|
+ <div class="invite-member-btn" title="邀请好友进群聊" @click="onInviteMember()">
|
|
|
+ <i class="el-icon-plus"></i>
|
|
|
+ </div>
|
|
|
+ <div class="invite-member-text">邀请</div>
|
|
|
+ <add-group-member :visible="showAddGroupMember" :groupId="activeGroup.id"
|
|
|
+ :members="groupMembers" @reload="loadGroupMembers"
|
|
|
+ @close="onCloseAddGroupMember"></add-group-member>
|
|
|
+ </div>
|
|
|
+ <div v-for="(member, idx) in showMembers" :key="member.id">
|
|
|
+ <group-member v-if="idx < showMaxIdx" class="group-member" :member="member"
|
|
|
+ :showDel="isOwner && member.userId != activeGroup.ownerId"
|
|
|
+ @del="onKick"></group-member>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-scrollbar>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-container>
|
|
|
+ </el-container>
|
|
|
</template>
|
|
|
|
|
|
|
|
|
@@ -99,387 +103,394 @@ import HeadImage from '../components/common/HeadImage.vue';
|
|
|
import { pinyin } from 'pinyin-pro';
|
|
|
|
|
|
export default {
|
|
|
- name: "group",
|
|
|
- components: {
|
|
|
- GroupItem,
|
|
|
- GroupMember,
|
|
|
- FileUpload,
|
|
|
- AddGroupMember,
|
|
|
- HeadImage
|
|
|
- },
|
|
|
- data() {
|
|
|
- return {
|
|
|
- searchText: "",
|
|
|
- maxSize: 5 * 1024 * 1024,
|
|
|
- activeGroup: {},
|
|
|
- groupMembers: [],
|
|
|
- showAddGroupMember: false,
|
|
|
- showMaxIdx: 150,
|
|
|
- rules: {
|
|
|
- name: [{
|
|
|
- required: true,
|
|
|
- message: '请输入群聊名称',
|
|
|
- trigger: 'blur'
|
|
|
- }]
|
|
|
- }
|
|
|
- };
|
|
|
- },
|
|
|
- methods: {
|
|
|
- onCreateGroup() {
|
|
|
- this.$prompt('请输入群聊名称', '创建群聊', {
|
|
|
- confirmButtonText: '确定',
|
|
|
- cancelButtonText: '取消',
|
|
|
- inputPattern: /\S/,
|
|
|
- inputErrorMessage: '请输入群聊名称'
|
|
|
- }).then((o) => {
|
|
|
- let userInfo = this.$store.state.userStore.userInfo;
|
|
|
- let data = {
|
|
|
- name: o.value
|
|
|
- }
|
|
|
- this.$http({
|
|
|
- url: `/group/create?groupName=${o.value}`,
|
|
|
- method: 'post',
|
|
|
- data: data
|
|
|
- }).then((group) => {
|
|
|
- this.$store.commit("addGroup", group);
|
|
|
- })
|
|
|
- })
|
|
|
- },
|
|
|
- onActiveItem(group) {
|
|
|
- this.showMaxIdx = 150;
|
|
|
- // store数据不能直接修改,所以深拷贝一份内存
|
|
|
- this.activeGroup = JSON.parse(JSON.stringify(group));
|
|
|
- // 重新加载群成员
|
|
|
- this.loadGroupMembers();
|
|
|
- },
|
|
|
- onInviteMember() {
|
|
|
- this.showAddGroupMember = true;
|
|
|
- },
|
|
|
- onCloseAddGroupMember() {
|
|
|
- this.showAddGroupMember = false;
|
|
|
- },
|
|
|
- onUploadSuccess(data) {
|
|
|
- this.activeGroup.headImage = data.originUrl;
|
|
|
- this.activeGroup.headImageThumb = data.thumbUrl;
|
|
|
- },
|
|
|
- onSaveGroup() {
|
|
|
- this.$refs['groupForm'].validate((valid) => {
|
|
|
- if (valid) {
|
|
|
- let vo = this.activeGroup;
|
|
|
- this.$http({
|
|
|
- url: "/group/modify",
|
|
|
- method: "put",
|
|
|
- data: vo
|
|
|
- }).then((group) => {
|
|
|
- this.$store.commit("updateGroup", group);
|
|
|
- this.$message.success("修改成功");
|
|
|
- })
|
|
|
- }
|
|
|
- });
|
|
|
- },
|
|
|
- onDissolve() {
|
|
|
- this.$confirm(`确认要解散'${this.activeGroup.name}'吗?`, '确认解散?', {
|
|
|
- confirmButtonText: '确定',
|
|
|
- cancelButtonText: '取消',
|
|
|
- type: 'warning'
|
|
|
- }).then(() => {
|
|
|
- this.$http({
|
|
|
- url: `/group/delete/${this.activeGroup.id}`,
|
|
|
- method: 'delete'
|
|
|
- }).then(() => {
|
|
|
- this.$message.success(`群聊'${this.activeGroup.name}'已解散`);
|
|
|
- this.$store.commit("removeGroup", this.activeGroup.id);
|
|
|
- this.reset();
|
|
|
- });
|
|
|
- })
|
|
|
- },
|
|
|
- onKick(member) {
|
|
|
- this.$confirm(`确定将成员'${member.showNickName}'移出群聊吗?`, '确认移出?', {
|
|
|
- confirmButtonText: '确定',
|
|
|
- cancelButtonText: '取消',
|
|
|
- type: 'warning'
|
|
|
- }).then(() => {
|
|
|
- this.$http({
|
|
|
- url: `/group/kick/${this.activeGroup.id}`,
|
|
|
- method: 'delete',
|
|
|
- params: {
|
|
|
- userId: member.userId
|
|
|
- }
|
|
|
- }).then(() => {
|
|
|
- this.$message.success(`已将${member.showNickName}移出群聊`);
|
|
|
- member.quit = true;
|
|
|
- });
|
|
|
- })
|
|
|
+ name: "group",
|
|
|
+ components: {
|
|
|
+ GroupItem,
|
|
|
+ GroupMember,
|
|
|
+ FileUpload,
|
|
|
+ AddGroupMember,
|
|
|
+ HeadImage
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ searchText: "",
|
|
|
+ maxSize: 5 * 1024 * 1024,
|
|
|
+ activeGroup: {},
|
|
|
+ groupMembers: [],
|
|
|
+ showAddGroupMember: false,
|
|
|
+ showMaxIdx: 150,
|
|
|
+ rules: {
|
|
|
+ name: [{
|
|
|
+ required: true,
|
|
|
+ message: '请输入群聊名称',
|
|
|
+ trigger: 'blur'
|
|
|
+ }]
|
|
|
+ }
|
|
|
+ };
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ onCreateGroup() {
|
|
|
+ this.$prompt('请输入群聊名称', '创建群聊', {
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ inputPattern: /\S/,
|
|
|
+ inputErrorMessage: '请输入群聊名称'
|
|
|
+ }).then((o) => {
|
|
|
+ let userInfo = this.$store.state.userStore.userInfo;
|
|
|
+ let data = {
|
|
|
+ name: o.value
|
|
|
+ }
|
|
|
+ this.$http({
|
|
|
+ url: `/group/create?groupName=${o.value}`,
|
|
|
+ method: 'post',
|
|
|
+ data: data
|
|
|
+ }).then((group) => {
|
|
|
+ this.$store.commit("addGroup", group);
|
|
|
+ })
|
|
|
+ })
|
|
|
+ },
|
|
|
+ onActiveItem(group) {
|
|
|
+ this.showMaxIdx = 150;
|
|
|
+ // store数据不能直接修改,所以深拷贝一份内存
|
|
|
+ this.activeGroup = JSON.parse(JSON.stringify(group));
|
|
|
+ // 重新加载群成员
|
|
|
+ this.loadGroupMembers();
|
|
|
+ },
|
|
|
+ onInviteMember() {
|
|
|
+ this.showAddGroupMember = true;
|
|
|
+ },
|
|
|
+ onCloseAddGroupMember() {
|
|
|
+ this.showAddGroupMember = false;
|
|
|
+ },
|
|
|
+ onUploadSuccess(data) {
|
|
|
+ this.activeGroup.headImage = data.originUrl;
|
|
|
+ this.activeGroup.headImageThumb = data.thumbUrl;
|
|
|
+ },
|
|
|
+ onSaveGroup() {
|
|
|
+ this.$refs['groupForm'].validate((valid) => {
|
|
|
+ if (valid) {
|
|
|
+ let vo = this.activeGroup;
|
|
|
+ this.$http({
|
|
|
+ url: "/group/modify",
|
|
|
+ method: "put",
|
|
|
+ data: vo
|
|
|
+ }).then((group) => {
|
|
|
+ this.$store.commit("updateGroup", group);
|
|
|
+ this.$message.success("修改成功");
|
|
|
+ })
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ onDissolve() {
|
|
|
+ this.$confirm(`确认要解散'${this.activeGroup.name}'吗?`, '确认解散?', {
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning'
|
|
|
+ }).then(() => {
|
|
|
+ this.$http({
|
|
|
+ url: `/group/delete/${this.activeGroup.id}`,
|
|
|
+ method: 'delete'
|
|
|
+ }).then(() => {
|
|
|
+ this.$message.success(`群聊'${this.activeGroup.name}'已解散`);
|
|
|
+ this.$store.commit("removeGroup", this.activeGroup.id);
|
|
|
+ this.reset();
|
|
|
+ });
|
|
|
+ })
|
|
|
+ },
|
|
|
+ onKick(member) {
|
|
|
+ this.$confirm(`确定将成员'${member.showNickName}'移出群聊吗?`, '确认移出?', {
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning'
|
|
|
+ }).then(() => {
|
|
|
+ this.$http({
|
|
|
+ url: `/group/kick/${this.activeGroup.id}`,
|
|
|
+ method: 'delete',
|
|
|
+ params: {
|
|
|
+ userId: member.userId
|
|
|
+ }
|
|
|
+ }).then(() => {
|
|
|
+ this.$message.success(`已将${member.showNickName}移出群聊`);
|
|
|
+ member.quit = true;
|
|
|
+ });
|
|
|
+ })
|
|
|
|
|
|
- },
|
|
|
- onQuit() {
|
|
|
- this.$confirm(`确认退出'${this.activeGroup.showGroupName}',并清空聊天记录吗?`, '确认退出?', {
|
|
|
- confirmButtonText: '确定',
|
|
|
- cancelButtonText: '取消',
|
|
|
- type: 'warning'
|
|
|
- }).then(() => {
|
|
|
- this.$http({
|
|
|
- url: `/group/quit/${this.activeGroup.id}`,
|
|
|
- method: 'delete'
|
|
|
- }).then(() => {
|
|
|
- this.$message.success(`您已退出'${this.activeGroup.name}'`);
|
|
|
- this.$store.commit("removeGroup", this.activeGroup.id);
|
|
|
- this.$store.commit("removeGroupChat", this.activeGroup.id);
|
|
|
- this.reset();
|
|
|
- });
|
|
|
- })
|
|
|
- },
|
|
|
- onSendMessage() {
|
|
|
- let chat = {
|
|
|
- type: 'GROUP',
|
|
|
- targetId: this.activeGroup.id,
|
|
|
- showName: this.activeGroup.showGroupName,
|
|
|
- headImage: this.activeGroup.headImage,
|
|
|
- };
|
|
|
- this.$store.commit("openChat", chat);
|
|
|
- this.$store.commit("activeChat", 0);
|
|
|
- this.$router.push("/home/chat");
|
|
|
- },
|
|
|
- onScroll(e) {
|
|
|
- const scrollbar = e.target;
|
|
|
- // 滚到底部
|
|
|
- if (scrollbar.scrollTop + scrollbar.clientHeight >= scrollbar.scrollHeight - 30) {
|
|
|
- if (this.showMaxIdx < this.showMembers.length) {
|
|
|
- this.showMaxIdx += 50;
|
|
|
- }
|
|
|
- }
|
|
|
- },
|
|
|
- loadGroupMembers() {
|
|
|
- this.$http({
|
|
|
- url: `/group/members/${this.activeGroup.id}`,
|
|
|
- method: "get"
|
|
|
- }).then((members) => {
|
|
|
- this.groupMembers = members;
|
|
|
- })
|
|
|
- },
|
|
|
- reset() {
|
|
|
- this.activeGroup = {};
|
|
|
- this.groupMembers = [];
|
|
|
- },
|
|
|
- firstLetter(strText) {
|
|
|
- // 使用pinyin-pro库将中文转换为拼音
|
|
|
- let pinyinOptions = {
|
|
|
- toneType: 'none', // 无声调
|
|
|
- type: 'normal' // 普通拼音
|
|
|
- };
|
|
|
- let pyText = pinyin(strText, pinyinOptions);
|
|
|
- return pyText[0];
|
|
|
- },
|
|
|
- isEnglish(character) {
|
|
|
- return /^[A-Za-z]+$/.test(character);
|
|
|
- }
|
|
|
- },
|
|
|
- computed: {
|
|
|
- groupStore() {
|
|
|
- return this.$store.state.groupStore;
|
|
|
- },
|
|
|
- ownerName() {
|
|
|
- let member = this.groupMembers.find((m) => m.userId == this.activeGroup.ownerId);
|
|
|
- return member && member.showNickName;
|
|
|
- },
|
|
|
- isOwner() {
|
|
|
- return this.activeGroup.ownerId == this.$store.state.userStore.userInfo.id;
|
|
|
- },
|
|
|
- imageAction() {
|
|
|
- return `/image/upload`;
|
|
|
- },
|
|
|
- groupMap() {
|
|
|
- // 按首字母分组
|
|
|
- let map = new Map();
|
|
|
- this.groupStore.groups.forEach((g) => {
|
|
|
- if (g.quit || (this.searchText && !g.showGroupName.includes(this.searchText))) {
|
|
|
- return;
|
|
|
- }
|
|
|
- let letter = this.firstLetter(g.showGroupName).toUpperCase();
|
|
|
- // 非英文一律为#组
|
|
|
- if (!this.isEnglish(letter)) {
|
|
|
- letter = "#"
|
|
|
- }
|
|
|
- if (map.has(letter)) {
|
|
|
- map.get(letter).push(g);
|
|
|
- } else {
|
|
|
- map.set(letter, [g]);
|
|
|
- }
|
|
|
- })
|
|
|
- // 排序
|
|
|
- let arrayObj = Array.from(map);
|
|
|
- arrayObj.sort((a, b) => {
|
|
|
- // #组在最后面
|
|
|
- if (a[0] == '#' || b[0] == '#') {
|
|
|
- return b[0].localeCompare(a[0])
|
|
|
- }
|
|
|
- return a[0].localeCompare(b[0])
|
|
|
- })
|
|
|
- map = new Map(arrayObj.map(i => [i[0], i[1]]));
|
|
|
- return map;
|
|
|
- },
|
|
|
- groupKeys() {
|
|
|
- return Array.from(this.groupMap.keys());
|
|
|
- },
|
|
|
- groupValues() {
|
|
|
- return Array.from(this.groupMap.values());
|
|
|
- },
|
|
|
- showMembers() {
|
|
|
- return this.groupMembers.filter((m) => !m.quit)
|
|
|
- },
|
|
|
- scrollHeight() {
|
|
|
- return Math.min(300, 80 + this.showMembers.length / 10 * 80);
|
|
|
- }
|
|
|
- },
|
|
|
- mounted() {
|
|
|
- let scrollWrap = this.$refs.scrollbar.$el.querySelector('.el-scrollbar__wrap');
|
|
|
- scrollWrap.addEventListener('scroll', this.onScroll);
|
|
|
- }
|
|
|
+ },
|
|
|
+ onQuit() {
|
|
|
+ this.$confirm(`确认退出'${this.activeGroup.showGroupName}',并清空聊天记录吗?`, '确认退出?', {
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning'
|
|
|
+ }).then(() => {
|
|
|
+ this.$http({
|
|
|
+ url: `/group/quit/${this.activeGroup.id}`,
|
|
|
+ method: 'delete'
|
|
|
+ }).then(() => {
|
|
|
+ this.$message.success(`您已退出'${this.activeGroup.name}'`);
|
|
|
+ this.$store.commit("removeGroup", this.activeGroup.id);
|
|
|
+ this.$store.commit("removeGroupChat", this.activeGroup.id);
|
|
|
+ this.reset();
|
|
|
+ });
|
|
|
+ })
|
|
|
+ },
|
|
|
+ onSendMessage() {
|
|
|
+ let chat = {
|
|
|
+ type: 'GROUP',
|
|
|
+ targetId: this.activeGroup.id,
|
|
|
+ showName: this.activeGroup.showGroupName,
|
|
|
+ headImage: this.activeGroup.headImage,
|
|
|
+ };
|
|
|
+ this.$store.commit("openChat", chat);
|
|
|
+ this.$store.commit("activeChat", 0);
|
|
|
+ this.$router.push("/home/chat");
|
|
|
+ },
|
|
|
+ onScroll(e) {
|
|
|
+ const scrollbar = e.target;
|
|
|
+ // 滚到底部
|
|
|
+ if (scrollbar.scrollTop + scrollbar.clientHeight >= scrollbar.scrollHeight - 30) {
|
|
|
+ if (this.showMaxIdx < this.showMembers.length) {
|
|
|
+ this.showMaxIdx += 50;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ loadGroupMembers() {
|
|
|
+ this.$http({
|
|
|
+ url: `/group/members/${this.activeGroup.id}`,
|
|
|
+ method: "get"
|
|
|
+ }).then((members) => {
|
|
|
+ this.groupMembers = members;
|
|
|
+ })
|
|
|
+ },
|
|
|
+ reset() {
|
|
|
+ this.activeGroup = {};
|
|
|
+ this.groupMembers = [];
|
|
|
+ },
|
|
|
+ firstLetter(strText) {
|
|
|
+ // 使用pinyin-pro库将中文转换为拼音
|
|
|
+ let pinyinOptions = {
|
|
|
+ toneType: 'none', // 无声调
|
|
|
+ type: 'normal' // 普通拼音
|
|
|
+ };
|
|
|
+ let pyText = pinyin(strText, pinyinOptions);
|
|
|
+ return pyText[0];
|
|
|
+ },
|
|
|
+ isEnglish(character) {
|
|
|
+ return /^[A-Za-z]+$/.test(character);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ groupStore() {
|
|
|
+ return this.$store.state.groupStore;
|
|
|
+ },
|
|
|
+ ownerName() {
|
|
|
+ let member = this.groupMembers.find((m) => m.userId == this.activeGroup.ownerId);
|
|
|
+ return member && member.showNickName;
|
|
|
+ },
|
|
|
+ isOwner() {
|
|
|
+ return this.activeGroup.ownerId == this.$store.state.userStore.userInfo.id;
|
|
|
+ },
|
|
|
+ imageAction() {
|
|
|
+ return `/image/upload`;
|
|
|
+ },
|
|
|
+ groupMap() {
|
|
|
+ // 按首字母分组
|
|
|
+ let map = new Map();
|
|
|
+ this.groupStore.groups.forEach((g) => {
|
|
|
+ if (g.quit || (this.searchText && !g.showGroupName.includes(this.searchText))) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ let letter = this.firstLetter(g.showGroupName).toUpperCase();
|
|
|
+ // 非英文一律为#组
|
|
|
+ if (!this.isEnglish(letter)) {
|
|
|
+ letter = "#"
|
|
|
+ }
|
|
|
+ if (map.has(letter)) {
|
|
|
+ map.get(letter).push(g);
|
|
|
+ } else {
|
|
|
+ map.set(letter, [g]);
|
|
|
+ }
|
|
|
+ })
|
|
|
+ // 排序
|
|
|
+ let arrayObj = Array.from(map);
|
|
|
+ arrayObj.sort((a, b) => {
|
|
|
+ // #组在最后面
|
|
|
+ if (a[0] == '#' || b[0] == '#') {
|
|
|
+ return b[0].localeCompare(a[0])
|
|
|
+ }
|
|
|
+ return a[0].localeCompare(b[0])
|
|
|
+ })
|
|
|
+ map = new Map(arrayObj.map(i => [i[0], i[1]]));
|
|
|
+ return map;
|
|
|
+ },
|
|
|
+ groupKeys() {
|
|
|
+ return Array.from(this.groupMap.keys());
|
|
|
+ },
|
|
|
+ groupValues() {
|
|
|
+ return Array.from(this.groupMap.values());
|
|
|
+ },
|
|
|
+ showMembers() {
|
|
|
+ return this.groupMembers.filter((m) => !m.quit)
|
|
|
+ },
|
|
|
+ scrollHeight() {
|
|
|
+ return Math.min(300, 80 + this.showMembers.length / 10 * 80);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ let scrollWrap = this.$refs.scrollbar.$el.querySelector('.el-scrollbar__wrap');
|
|
|
+ scrollWrap.addEventListener('scroll', this.onScroll);
|
|
|
+ }
|
|
|
}
|
|
|
</script>
|
|
|
|
|
|
<style lang="scss">
|
|
|
.group-page {
|
|
|
- .group-list-box {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- background: var(--im-background);
|
|
|
+ .group-list-box {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ background: var(--im-background);
|
|
|
|
|
|
- .group-list-header {
|
|
|
- height: 50px;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- padding: 0 8px;
|
|
|
+ .group-list-header {
|
|
|
+ height: 50px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ padding: 0 8px;
|
|
|
|
|
|
- .add-btn {
|
|
|
- padding: 5px !important;
|
|
|
- margin: 5px;
|
|
|
- font-size: 16px;
|
|
|
- border-radius: 50%;
|
|
|
- }
|
|
|
- }
|
|
|
+ .add-btn {
|
|
|
+ padding: 5px !important;
|
|
|
+ margin: 5px;
|
|
|
+ font-size: 16px;
|
|
|
+ border-radius: 50%;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- .group-list-items {
|
|
|
- flex: 1;
|
|
|
- }
|
|
|
- }
|
|
|
+ .group-list-items {
|
|
|
+ flex: 1;
|
|
|
|
|
|
- .group-box {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
+ .index-title {
|
|
|
+ text-align: left;
|
|
|
+ font-size: var(--im-larger-size-larger);
|
|
|
+ padding: 5px 15px;
|
|
|
+ color: var(--im-text-color-light);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- .group-header {
|
|
|
- display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- padding: 0 12px;
|
|
|
- line-height: 50px;
|
|
|
- font-size: var(--im-font-size-larger);
|
|
|
- border-bottom: var(--im-border);
|
|
|
- }
|
|
|
+ .group-box {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
|
|
|
- .el-divider--horizontal {
|
|
|
- margin: 16px 0;
|
|
|
- }
|
|
|
+ .group-header {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ padding: 0 12px;
|
|
|
+ line-height: 50px;
|
|
|
+ font-size: var(--im-font-size-larger);
|
|
|
+ border-bottom: var(--im-border);
|
|
|
+ }
|
|
|
|
|
|
- .group-container {
|
|
|
- overflow: auto;
|
|
|
- padding: 20px;
|
|
|
- flex: 1;
|
|
|
+ .el-divider--horizontal {
|
|
|
+ margin: 16px 0;
|
|
|
+ }
|
|
|
|
|
|
- .group-info {
|
|
|
- display: flex;
|
|
|
- padding: 5px 20px;
|
|
|
+ .group-container {
|
|
|
+ overflow: auto;
|
|
|
+ padding: 20px;
|
|
|
+ flex: 1;
|
|
|
|
|
|
- .group-form {
|
|
|
- flex: 1;
|
|
|
- padding-left: 40px;
|
|
|
- max-width: 700px;
|
|
|
- }
|
|
|
+ .group-info {
|
|
|
+ display: flex;
|
|
|
+ padding: 5px 20px;
|
|
|
|
|
|
- .avatar-uploader {
|
|
|
- --width: 160px;
|
|
|
- text-align: left;
|
|
|
+ .group-form {
|
|
|
+ flex: 1;
|
|
|
+ padding-left: 40px;
|
|
|
+ max-width: 700px;
|
|
|
+ }
|
|
|
|
|
|
- .el-upload {
|
|
|
- border: 1px dashed #d9d9d9 !important;
|
|
|
- border-radius: 6px;
|
|
|
- cursor: pointer;
|
|
|
- position: relative;
|
|
|
- overflow: hidden;
|
|
|
- }
|
|
|
+ .avatar-uploader {
|
|
|
+ --width: 160px;
|
|
|
+ text-align: left;
|
|
|
|
|
|
- .el-upload:hover {
|
|
|
- border-color: #409EFF;
|
|
|
- }
|
|
|
+ .el-upload {
|
|
|
+ border: 1px dashed #d9d9d9 !important;
|
|
|
+ border-radius: 6px;
|
|
|
+ cursor: pointer;
|
|
|
+ position: relative;
|
|
|
+ overflow: hidden;
|
|
|
+ }
|
|
|
|
|
|
- .avatar-uploader-icon {
|
|
|
- font-size: 28px;
|
|
|
- color: #8c939d;
|
|
|
- width: var(--width);
|
|
|
- height: var(--width);
|
|
|
- line-height: var(--width);
|
|
|
- text-align: center;
|
|
|
- }
|
|
|
+ .el-upload:hover {
|
|
|
+ border-color: #409EFF;
|
|
|
+ }
|
|
|
|
|
|
- .avatar {
|
|
|
- width: var(--width);
|
|
|
- height: var(--width);
|
|
|
- display: block;
|
|
|
- }
|
|
|
- }
|
|
|
+ .avatar-uploader-icon {
|
|
|
+ font-size: 28px;
|
|
|
+ color: #8c939d;
|
|
|
+ width: var(--width);
|
|
|
+ height: var(--width);
|
|
|
+ line-height: var(--width);
|
|
|
+ text-align: center;
|
|
|
+ }
|
|
|
|
|
|
- .send-btn {
|
|
|
- margin-top: 12px;
|
|
|
- }
|
|
|
- }
|
|
|
+ .avatar {
|
|
|
+ width: var(--width);
|
|
|
+ height: var(--width);
|
|
|
+ display: block;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- .group-member-list {
|
|
|
- padding: 0 12px;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- flex-wrap: wrap;
|
|
|
- text-align: center;
|
|
|
+ .send-btn {
|
|
|
+ margin-top: 12px;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- .group-member {
|
|
|
- margin-right: 5px;
|
|
|
- }
|
|
|
+ .group-member-list {
|
|
|
+ padding: 0 12px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ text-align: center;
|
|
|
|
|
|
- .group-invite {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- align-items: center;
|
|
|
- width: 60px;
|
|
|
+ .group-member {
|
|
|
+ margin-right: 5px;
|
|
|
+ }
|
|
|
|
|
|
- .invite-member-btn {
|
|
|
- width: 38px;
|
|
|
- height: 38px;
|
|
|
- line-height: 38px;
|
|
|
- border: var(--im-border);
|
|
|
- font-size: 14px;
|
|
|
- cursor: pointer;
|
|
|
- box-sizing: border-box;
|
|
|
+ .group-invite {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ width: 60px;
|
|
|
|
|
|
- &:hover {
|
|
|
- border: #aaaaaa solid 1px;
|
|
|
- }
|
|
|
- }
|
|
|
+ .invite-member-btn {
|
|
|
+ width: 38px;
|
|
|
+ height: 38px;
|
|
|
+ line-height: 38px;
|
|
|
+ border: var(--im-border);
|
|
|
+ font-size: 14px;
|
|
|
+ cursor: pointer;
|
|
|
+ box-sizing: border-box;
|
|
|
|
|
|
- .invite-member-text {
|
|
|
- font-size: var(--im-font-size-smaller);
|
|
|
- text-align: center;
|
|
|
- width: 100%;
|
|
|
- height: 30px;
|
|
|
- line-height: 30px;
|
|
|
- white-space: nowrap;
|
|
|
- text-overflow: ellipsis;
|
|
|
- overflow: hidden
|
|
|
- }
|
|
|
- }
|
|
|
+ &:hover {
|
|
|
+ border: #aaaaaa solid 1px;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- }
|
|
|
- }
|
|
|
+ .invite-member-text {
|
|
|
+ font-size: var(--im-font-size-smaller);
|
|
|
+ text-align: center;
|
|
|
+ width: 100%;
|
|
|
+ height: 30px;
|
|
|
+ line-height: 30px;
|
|
|
+ white-space: nowrap;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ overflow: hidden
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- }
|
|
|
+
|
|
|
+ }
|
|
|
}
|
|
|
-</style>
|
|
|
+</style>
|