Browse Source

群聊@功能(开发中)

master
xsx 2 years ago
parent
commit
40bf60e1dc
  1. 6
      im-platform/src/main/java/com/bx/implatform/service/impl/GroupMessageServiceImpl.java
  2. 9
      im-ui/src/components/chat/ChatAtBox.vue
  3. 15
      im-ui/src/components/chat/ChatBox.vue
  4. 10
      im-ui/src/components/chat/ChatGroupSide.vue
  5. 8
      im-ui/src/components/chat/ChatHistory.vue
  6. 12
      im-ui/src/components/chat/ChatItem.vue
  7. 22
      im-ui/src/components/chat/ChatMessageItem.vue
  8. 40
      im-ui/src/components/chat/ChatVoice.vue
  9. 4
      im-ui/src/components/common/Emotion.vue
  10. 6
      im-ui/src/components/common/FileUpload.vue
  11. 6
      im-ui/src/components/common/FullImage.vue
  12. 4
      im-ui/src/components/common/RightMenu.vue
  13. 8
      im-ui/src/components/common/UserInfo.vue
  14. 14
      im-ui/src/components/friend/AddFriend.vue
  15. 14
      im-ui/src/components/friend/FriendItem.vue
  16. 22
      im-ui/src/components/group/AddGroupMember.vue
  17. 12
      im-ui/src/components/group/GroupItem.vue
  18. 4
      im-ui/src/components/group/GroupMember.vue
  19. 14
      im-ui/src/components/setting/Setting.vue
  20. 5
      im-ui/src/store/friendStore.js
  21. 4
      im-ui/src/store/groupStore.js
  22. 9
      im-ui/src/view/Group.vue

6
im-platform/src/main/java/com/bx/implatform/service/impl/GroupMessageServiceImpl.java

@ -67,8 +67,8 @@ public class GroupMessageServiceImpl extends ServiceImpl<GroupMessageMapper, Gro
} }
// 是否在群聊里面 // 是否在群聊里面
GroupMember member = groupMemberService.findByGroupAndUserId(dto.getGroupId(), session.getUserId()); GroupMember member = groupMemberService.findByGroupAndUserId(dto.getGroupId(), session.getUserId());
if (Objects.isNull(member)) { if (Objects.isNull(member)||member.getQuit()) {
throw new GlobalException(ResultCode.PROGRAM_ERROR, "您已不在群聊里面,无法撤回消息"); throw new GlobalException(ResultCode.PROGRAM_ERROR, "您已不在群聊里面,无法发送消息");
} }
// 群聊成员列表 // 群聊成员列表
List<Long> userIds = groupMemberService.findUserIdsByGroupId(group.getId()); List<Long> userIds = groupMemberService.findUserIdsByGroupId(group.getId());
@ -116,7 +116,7 @@ public class GroupMessageServiceImpl extends ServiceImpl<GroupMessageMapper, Gro
} }
// 判断是否在群里 // 判断是否在群里
GroupMember member = groupMemberService.findByGroupAndUserId(msg.getGroupId(), session.getUserId()); GroupMember member = groupMemberService.findByGroupAndUserId(msg.getGroupId(), session.getUserId());
if (member == null) { if (Objects.isNull(member)||member.getQuit()) {
throw new GlobalException(ResultCode.PROGRAM_ERROR, "您已不在群聊里面,无法撤回消息"); throw new GlobalException(ResultCode.PROGRAM_ERROR, "您已不在群聊里面,无法撤回消息");
} }
// 修改数据库 // 修改数据库

9
im-ui/src/components/chat/ChatAtBox.vue

@ -4,7 +4,7 @@
<div v-for="(member,idx) in showMembers" :key="member.id"> <div v-for="(member,idx) in showMembers" :key="member.id">
<div class="member-item" :class="idx==activeIdx?'active':''" @click="onSelectMember(member)"> <div class="member-item" :class="idx==activeIdx?'active':''" @click="onSelectMember(member)">
<div class="member-avatar"> <div class="member-avatar">
<head-image :size="30" :name="member.aliasName" :url="member.headImage"> </head-image> <head-image :size="25" :name="member.aliasName" :url="member.headImage"> </head-image>
</div> </div>
<div class="member-name"> <div class="member-name">
<div>{{member.aliasName}}</div> <div>{{member.aliasName}}</div>
@ -140,9 +140,8 @@
height: 35px; height: 35px;
margin-bottom: 1px; margin-bottom: 1px;
position: relative; position: relative;
padding-left: 10px; padding: 0 5px;
align-items: center; align-items: center;
padding-right: 5px;
background-color: #fafafa; background-color: #fafafa;
white-space: nowrap; white-space: nowrap;
box-sizing: border-box; box-sizing: border-box;
@ -157,8 +156,8 @@
.member-avatar { .member-avatar {
width: 30px; width: 25px;
height: 30px; height: 25px;
} }
.member-name { .member-name {

15
im-ui/src/components/chat/ChatBox.vue

@ -691,9 +691,8 @@
.chat-box { .chat-box {
position: relative; position: relative;
width: 100%; width: 100%;
background: white; background: #f8f8f8;
border: #dddddd solid 1px; border: #dddddd solid 1px;
.el-header { .el-header {
padding: 5px; padding: 5px;
background-color: white; background-color: white;
@ -764,9 +763,9 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 100%; height: 100%;
background-color: #f8f8f8 !important; background-color: white !important;
outline-color: rgba(83, 160, 231, 0.61);
.send-text-area { .send-text-area {
box-sizing: border-box; box-sizing: border-box;
padding: 5px; padding: 5px;
@ -775,8 +774,8 @@
resize: none; resize: none;
font-size: 16px; font-size: 16px;
color: black; color: black;
background-color: #f8f8f8 !important;
outline-color: rgba(83, 160, 231, 0.61); outline-color: rgba(83, 160, 231, 0.61);
text-align: left; text-align: left;
line-height: 30 px; line-height: 30 px;
@ -794,13 +793,13 @@
.send-image-area { .send-image-area {
text-align: left; text-align: left;
border: #53a0e7 solid 1px;
.send-image-box { .send-image-box {
position: relative; position: relative;
display: inline-block; display: inline-block;
.send-image { .send-image {
max-height: 190px; max-height: 180px;
border: 1px solid #ccc; border: 1px solid #ccc;
border-radius: 2%; border-radius: 2%;
margin: 2px; margin: 2px;

10
im-ui/src/components/chat/ChatGroupSide.vue

@ -39,9 +39,9 @@
</el-form-item> </el-form-item>
<div class="btn-group"> <div class="btn-group">
<el-button v-show="editing" type="success" @click="handleSaveGroup()">提交</el-button> <el-button v-show="editing" type="success" @click="onSaveGroup()">提交</el-button>
<el-button v-show="!editing" type="primary" @click="editing=!editing">编辑</el-button> <el-button v-show="!editing" type="primary" @click="editing=!editing">编辑</el-button>
<el-button type="danger" v-show="!isOwner" @click="handleQuit()">退出群聊</el-button> <el-button type="danger" v-show="!isOwner" @click="onQuit()">退出群聊</el-button>
</div> </div>
</el-form> </el-form>
</el-scrollbar> </el-scrollbar>
@ -75,7 +75,7 @@
} }
}, },
methods: { methods: {
handleClose() { onClose() {
this.$emit('close'); this.$emit('close');
}, },
loadGroupMembers() { loadGroupMembers() {
@ -86,7 +86,7 @@
this.groupMembers = members; this.groupMembers = members;
}) })
}, },
handleSaveGroup() { onSaveGroup() {
let vo = this.group; let vo = this.group;
this.$http({ this.$http({
url: "/group/modify", url: "/group/modify",
@ -98,7 +98,7 @@
this.$message.success("修改成功"); this.$message.success("修改成功");
}) })
}, },
handleQuit() { onQuit() {
this.$confirm('退出群聊后将不再接受群里的消息,确认退出吗?', '确认退出?', { this.$confirm('退出群聊后将不再接受群里的消息,确认退出吗?', '确认退出?', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',

8
im-ui/src/components/chat/ChatHistory.vue

@ -1,5 +1,5 @@
<template> <template>
<el-drawer title="聊天历史记录" size="700px" :visible.sync="visible" direction="rtl" :before-close="handleClose"> <el-drawer title="聊天历史记录" size="700px" :visible.sync="visible" direction="rtl" :before-close="onClose">
<div class="chat-history" v-loading="loading" <div class="chat-history" v-loading="loading"
element-loading-text="拼命加载中"> element-loading-text="拼命加载中">
<el-scrollbar class="chat-history-scrollbar" ref="scrollbar" id="historyScrollbar" > <el-scrollbar class="chat-history-scrollbar" ref="scrollbar" id="historyScrollbar" >
@ -51,13 +51,13 @@
} }
}, },
methods: { methods: {
handleClose() { onClose() {
this.page = 1; this.page = 1;
this.messages = []; this.messages = [];
this.loadAll = false; this.loadAll = false;
this.$emit('close'); this.$emit('close');
}, },
handleScroll() { onScroll() {
let high = this.$refs.scrollbar.$refs.wrap.scrollTop; // let high = this.$refs.scrollbar.$refs.wrap.scrollTop; //
let timeDiff = new Date().getTime() - this.lastScrollTime.getTime(); let timeDiff = new Date().getTime() - this.lastScrollTime.getTime();
if ( high < 30 && timeDiff>500) { if ( high < 30 && timeDiff>500) {
@ -139,7 +139,7 @@
if (newValue) { if (newValue) {
this.loadMessages(); this.loadMessages();
this.$nextTick(() => { this.$nextTick(() => {
document.getElementById('historyScrollbar').addEventListener("mousewheel", this.handleScroll,true); document.getElementById('historyScrollbar').addEventListener("mousewheel", this.onScroll,true);
}); });
} }
} }

12
im-ui/src/components/chat/ChatItem.vue

@ -1,7 +1,7 @@
<template> <template>
<div class="chat-item" :class="active ? 'active' : ''" @contextmenu.prevent="showRightMenu($event)"> <div class="chat-item" :class="active ? 'active' : ''" @contextmenu.prevent="showRightMenu($event)">
<div class="chat-left"> <div class="chat-left">
<head-image :url="chat.headImage" :name="chat.showName" :size="50" <head-image :url="chat.headImage" :name="chat.showName" :size="45"
:id="chat.type=='PRIVATE'?chat.targetId:0"></head-image> :id="chat.type=='PRIVATE'?chat.targetId:0"></head-image>
<div v-show="chat.unreadCount>0" class="unread-text">{{chat.unreadCount}}</div> <div v-show="chat.unreadCount>0" class="unread-text">{{chat.unreadCount}}</div>
</div> </div>
@ -94,13 +94,13 @@
<style lang="scss"> <style lang="scss">
.chat-item { .chat-item {
height: 65px; height: 50px;
display: flex; display: flex;
margin-bottom: 1px; margin-bottom: 1px;
position: relative; position: relative;
padding: 5px;
padding-left: 10px; padding-left: 10px;
align-items: center; align-items: center;
padding-right: 5px;
background-color: #fafafa; background-color: #fafafa;
white-space: nowrap; white-space: nowrap;
color: black; color: black;
@ -117,8 +117,8 @@
.chat-left { .chat-left {
position: relative; position: relative;
display: flex; display: flex;
width: 50px; width: 45px;
height: 50px; height: 45x;
.unread-text { .unread-text {
position: absolute; position: absolute;
@ -147,7 +147,7 @@
.chat-name { .chat-name {
display: flex; display: flex;
line-height: 25px; line-height: 25px;
height: 25px;
.chat-name-text { .chat-name-text {
flex: 1; flex: 1;
font-size: 15px; font-size: 15px;

22
im-ui/src/components/chat/ChatMessageItem.vue

@ -26,7 +26,7 @@
<img class="send-image" :src="JSON.parse(msgInfo.content).thumbUrl" <img class="send-image" :src="JSON.parse(msgInfo.content).thumbUrl"
@click="showFullImageBox()" /> @click="showFullImageBox()" />
</div> </div>
<span title="发送失败" v-show="loadFail" @click="handleSendFail" <span title="发送失败" v-show="loadFail" @click="onSendFail"
class="send-fail el-icon-warning"></span> class="send-fail el-icon-warning"></span>
</div> </div>
<div class="chat-msg-file" v-if="msgInfo.type==$enums.MESSAGE_TYPE.FILE"> <div class="chat-msg-file" v-if="msgInfo.type==$enums.MESSAGE_TYPE.FILE">
@ -40,11 +40,11 @@
<span type="primary" class="el-icon-document"></span> <span type="primary" class="el-icon-document"></span>
</div> </div>
</div> </div>
<span title="发送失败" v-show="loadFail" @click="handleSendFail" <span title="发送失败" v-show="loadFail" @click="onSendFail"
class="send-fail el-icon-warning"></span> class="send-fail el-icon-warning"></span>
</div> </div>
<div class="chat-msg-voice" v-if="msgInfo.type==$enums.MESSAGE_TYPE.AUDIO" <div class="chat-msg-voice" v-if="msgInfo.type==$enums.MESSAGE_TYPE.AUDIO"
@click="handlePlayVoice()"> @click="onPlayVoice()">
<audio controls :src="JSON.parse(msgInfo.content).url"></audio> <audio controls :src="JSON.parse(msgInfo.content).url"></audio>
</div> </div>
<span class="chat-readed" v-show="msgInfo.selfSend && !msgInfo.groupId <span class="chat-readed" v-show="msgInfo.selfSend && !msgInfo.groupId
@ -56,7 +56,7 @@
</div> </div>
<right-menu v-show="menu && rightMenu.show" :pos="rightMenu.pos" :items="menuItems" <right-menu v-show="menu && rightMenu.show" :pos="rightMenu.pos" :items="menuItems"
@close="rightMenu.show=false" @select="handleSelectMenu"></right-menu> @close="rightMenu.show=false" @select="onSelectMenu"></right-menu>
</div> </div>
</template> </template>
@ -110,7 +110,7 @@
}, },
methods: { methods: {
handleSendFail() { onSendFail() {
this.$message.error("该文件已发送失败,目前不支持自动重新发送,建议手动重新发送") this.$message.error("该文件已发送失败,目前不支持自动重新发送,建议手动重新发送")
}, },
showFullImageBox() { showFullImageBox() {
@ -119,13 +119,13 @@
this.$store.commit('showFullImageBox', imageUrl); this.$store.commit('showFullImageBox', imageUrl);
} }
}, },
handlePlayVoice() { onPlayVoice() {
if (!this.audio) { if (!this.audio) {
this.audio = new Audio(); this.audio = new Audio();
} }
this.audio.src = JSON.parse(this.msgInfo.content).url; this.audio.src = JSON.parse(this.msgInfo.content).url;
this.audio.play(); this.audio.play();
this.handlePlayVoice = 'RUNNING'; this.onPlayVoice = 'RUNNING';
}, },
showRightMenu(e) { showRightMenu(e) {
this.rightMenu.pos = { this.rightMenu.pos = {
@ -134,7 +134,7 @@
}; };
this.rightMenu.show = "true"; this.rightMenu.show = "true";
}, },
handleSelectMenu(item) { onSelectMenu(item) {
this.$emit(item.key.toLowerCase(), this.msgInfo); this.$emit(item.key.toLowerCase(), this.msgInfo);
} }
}, },
@ -233,7 +233,7 @@
line-height: 30px; line-height: 30px;
margin-top: 3px; margin-top: 3px;
padding: 7px; padding: 7px;
background-color: rgb(235, 235, 245); background-color: white;
border-radius: 10px; border-radius: 10px;
color: black; color: black;
display: block; display: block;
@ -241,7 +241,7 @@
text-align: left; text-align: left;
white-space: pre-wrap; white-space: pre-wrap;
word-break: break-all; word-break: break-all;
box-shadow: 2px 2px 2px #c0c0f0; box-shadow: 1px 1px 1px #c0c0f0;
&:after { &:after {
content: ""; content: "";
@ -383,7 +383,7 @@
background-color: rgb(88, 127, 240); background-color: rgb(88, 127, 240);
color: #fff; color: #fff;
vertical-align: top; vertical-align: top;
box-shadow: 2px 2px 1px #ccc; box-shadow: 1px 1px 1px #ccc;
&:after { &:after {
left: auto; left: auto;

40
im-ui/src/components/chat/ChatVoice.vue

@ -1,23 +1,23 @@
<template> <template>
<el-dialog class="chat-voice" title="语音录制" :visible.sync="visible" width="600px" :before-close="handleClose"> <el-dialog class="chat-voice" title="语音录制" :visible.sync="visible" width="600px" :before-close="onClose">
<div v-show="mode=='RECORD'"> <div v-show="mode=='RECORD'">
<div class="chat-voice-tip">{{stateTip}}</div> <div class="chat-voice-tip">{{stateTip}}</div>
<div>时长: {{state=='STOP'?0:parseInt(rc.duration)}}s</div> <div>时长: {{state=='STOP'?0:parseInt(rc.duration)}}s</div>
</div> </div>
<audio v-show="mode=='PLAY'" :src="url" controls ref="audio" @ended="handleStopAudio()"></audio> <audio v-show="mode=='PLAY'" :src="url" controls ref="audio" @ended="onStopAudio()"></audio>
<el-divider content-position="center"></el-divider> <el-divider content-position="center"></el-divider>
<el-row class="chat-voice-btn-group"> <el-row class="chat-voice-btn-group">
<el-button round type="primary" v-show="state=='STOP'" @click="handleStartRecord()">开始录音</el-button> <el-button round type="primary" v-show="state=='STOP'" @click="onStartRecord()">开始录音</el-button>
<el-button round type="warning" v-show="state=='RUNNING'" @click="handlePauseRecord()">暂停录音</el-button> <el-button round type="warning" v-show="state=='RUNNING'" @click="onPauseRecord()">暂停录音</el-button>
<el-button round type="primary" v-show="state=='PAUSE'" @click="handleResumeRecord()">继续录音</el-button> <el-button round type="primary" v-show="state=='PAUSE'" @click="onResumeRecord()">继续录音</el-button>
<el-button round type="danger" v-show="state=='RUNNING'||state=='PAUSE'" @click="handleCompleteRecord()"> <el-button round type="danger" v-show="state=='RUNNING'||state=='PAUSE'" @click="onCompleteRecord()">
结束录音</el-button> 结束录音</el-button>
<el-button round type="success" v-show="state=='COMPLETE' && mode!='PLAY'" @click="handlePlayAudio()">播放录音 <el-button round type="success" v-show="state=='COMPLETE' && mode!='PLAY'" @click="onPlayAudio()">播放录音
</el-button> </el-button>
<el-button round type="warning" v-show="state=='COMPLETE' && mode=='PLAY'" @click="handleStopAudio()">停止播放 <el-button round type="warning" v-show="state=='COMPLETE' && mode=='PLAY'" @click="onStopAudio()">停止播放
</el-button> </el-button>
<el-button round type="primary" v-show="state=='COMPLETE'" @click="handleRestartRecord()">重新录音</el-button> <el-button round type="primary" v-show="state=='COMPLETE'" @click="onRestartRecord()">重新录音</el-button>
<el-button round type="primary" v-show="state=='COMPLETE'" @click="handleSendRecord()">立即发送</el-button> <el-button round type="primary" v-show="state=='COMPLETE'" @click="onSendRecord()">立即发送</el-button>
</el-row> </el-row>
</el-dialog> </el-dialog>
@ -45,7 +45,7 @@
} }
}, },
methods: { methods: {
handleClose() { onClose() {
// //
this.rc.destroy(); this.rc.destroy();
this.rc = new Recorder(); this.rc = new Recorder();
@ -55,7 +55,7 @@
this.stateTip = '未开始'; this.stateTip = '未开始';
this.$emit("close"); this.$emit("close");
}, },
handleStartRecord() { onStartRecord() {
this.rc.start().then((stream) => { this.rc.start().then((stream) => {
this.state = 'RUNNING'; this.state = 'RUNNING';
this.stateTip = "正在录音..."; this.stateTip = "正在录音...";
@ -67,34 +67,34 @@
}, },
handlePauseRecord() { onPauseRecord() {
this.rc.pause(); this.rc.pause();
this.state = 'PAUSE'; this.state = 'PAUSE';
this.stateTip = "已暂停录音"; this.stateTip = "已暂停录音";
}, },
handleResumeRecord() { onResumeRecord() {
this.rc.resume(); this.rc.resume();
this.state = 'RUNNING'; this.state = 'RUNNING';
this.stateTip = "正在录音..."; this.stateTip = "正在录音...";
}, },
handleCompleteRecord() { onCompleteRecord() {
this.rc.pause(); this.rc.pause();
this.state = 'COMPLETE'; this.state = 'COMPLETE';
this.stateTip = "已结束录音"; this.stateTip = "已结束录音";
}, },
handlePlayAudio() { onPlayAudio() {
let wav = this.rc.getWAVBlob(); let wav = this.rc.getWAVBlob();
let url = URL.createObjectURL(wav); let url = URL.createObjectURL(wav);
this.$refs.audio.src = url; this.$refs.audio.src = url;
this.$refs.audio.play(); this.$refs.audio.play();
this.mode = 'PLAY'; this.mode = 'PLAY';
}, },
handleStopAudio() { onStopAudio() {
console.log(this.$refs.audio); console.log(this.$refs.audio);
this.$refs.audio.pause(); this.$refs.audio.pause();
this.mode = 'RECORD'; this.mode = 'RECORD';
}, },
handleRestartRecord() { onRestartRecord() {
this.rc.destroy(); this.rc.destroy();
this.rc = new Recorder() this.rc = new Recorder()
this.rc.start(); this.rc.start();
@ -102,7 +102,7 @@
this.mode = 'RECORD'; this.mode = 'RECORD';
this.stateTip = "正在录音..."; this.stateTip = "正在录音...";
}, },
handleSendRecord() { onSendRecord() {
let wav = this.rc.getWAVBlob(); let wav = this.rc.getWAVBlob();
let name = new Date().getDate() + '.wav'; let name = new Date().getDate() + '.wav';
var formData = new window.FormData() var formData = new window.FormData()
@ -120,7 +120,7 @@
url: url url: url
} }
this.$emit("send", data); this.$emit("send", data);
this.handleClose(); this.onClose();
}) })
} }
} }

4
im-ui/src/components/common/Emotion.vue

@ -4,7 +4,7 @@
<el-scrollbar style="height:250px"> <el-scrollbar style="height:250px">
<div class="emotion-item-list"> <div class="emotion-item-list">
<div class="emotion-item" v-for="(emoText, i) in $emo.emoTextList" :key="i" <div class="emotion-item" v-for="(emoText, i) in $emo.emoTextList" :key="i"
@click="clickHandler(emoText)" v-html="$emo.textToImg(emoText)"> @click="onClickEmo(emoText)" v-html="$emo.textToImg(emoText)">
</div> </div>
</div> </div>
</el-scrollbar> </el-scrollbar>
@ -25,7 +25,7 @@
} }
}, },
methods: { methods: {
clickHandler(emoText) { onClickEmo(emoText) {
let emotion = `#${emoText};` let emotion = `#${emoText};`
this.$emit('emotion', emotion) this.$emit('emotion', emotion)
}, },

6
im-ui/src/components/common/FileUpload.vue

@ -1,6 +1,6 @@
<template> <template>
<el-upload :action="action" :headers="uploadHeaders" :accept="fileTypes==null?'':fileTypes.join(',')" <el-upload :action="action" :headers="uploadHeaders" :accept="fileTypes==null?'':fileTypes.join(',')"
:show-file-list="false" :on-success="handleSuccess" :on-error="handleError" :disabled="disabled" :before-upload="beforeUpload"> :show-file-list="false" :on-success="onSuccess" :on-error="onError" :disabled="disabled" :before-upload="beforeUpload">
<slot></slot> <slot></slot>
</el-upload> </el-upload>
</template> </template>
@ -37,7 +37,7 @@
} }
}, },
methods: { methods: {
handleSuccess(res, file) { onSuccess(res, file) {
this.loading && this.loading.close(); this.loading && this.loading.close();
if (res.code == 200) { if (res.code == 200) {
this.$emit("success", res.data, file); this.$emit("success", res.data, file);
@ -46,7 +46,7 @@
this.$emit("fail", res, file); this.$emit("fail", res, file);
} }
}, },
handleError(err, file) { onError(err, file) {
this.$emit("fail", err, file); this.$emit("fail", err, file);
}, },
beforeUpload(file) { beforeUpload(file) {

6
im-ui/src/components/common/FullImage.vue

@ -1,10 +1,10 @@
<template> <template>
<div class="full-image" v-show="visible" :before-close="handleClose" :modal="true"> <div class="full-image" v-show="visible" :before-close="onClose" :modal="true">
<div class="mask"></div> <div class="mask"></div>
<div class="image-box"> <div class="image-box">
<img :src="url"/> <img :src="url"/>
</div> </div>
<div class="close" @click="handleClose">x</div> <div class="close" @click="onClose">x</div>
</div> </div>
</template> </template>
@ -17,7 +17,7 @@
} }
}, },
methods: { methods: {
handleClose() { onClose() {
this.$emit("close"); this.$emit("close");
} }
}, },

4
im-ui/src/components/common/RightMenu.vue

@ -3,7 +3,7 @@
<div class="right-menu" :style="{'left':pos.x+'px','top':pos.y+'px'}"> <div class="right-menu" :style="{'left':pos.x+'px','top':pos.y+'px'}">
<el-menu text-color="#333333"> <el-menu text-color="#333333">
<el-menu-item v-for="(item) in items" :key="item.key" :title="item.name" <el-menu-item v-for="(item) in items" :key="item.key" :title="item.name"
@click="handleSelectMenu(item)"> @click="onSelectMenu(item)">
<span :class="item.icon"></span> <span :class="item.icon"></span>
<span>{{item.name}}</span> <span>{{item.name}}</span>
@ -31,7 +31,7 @@
close() { close() {
this.$emit("close"); this.$emit("close");
}, },
handleSelectMenu(item) { onSelectMenu(item) {
this.$emit("select", item); this.$emit("select", item);
} }
} }

8
im-ui/src/components/common/UserInfo.vue

@ -18,8 +18,8 @@
</div> </div>
<el-divider content-position="center"></el-divider> <el-divider content-position="center"></el-divider>
<div class="user-btn-group"> <div class="user-btn-group">
<el-button v-show="isFriend" type="primary" @click="handleSendMessage()">发消息</el-button> <el-button v-show="isFriend" type="primary" @click="onSendMessage()">发消息</el-button>
<el-button v-show="!isFriend" type="primary" @click="handleAddFriend()">加为好友</el-button> <el-button v-show="!isFriend" type="primary" @click="onAddFriend()">加为好友</el-button>
</div> </div>
</div> </div>
</div> </div>
@ -47,7 +47,7 @@
} }
}, },
methods: { methods: {
handleSendMessage() { onSendMessage() {
let user = this.user; let user = this.user;
let chat = { let chat = {
type: 'PRIVATE', type: 'PRIVATE',
@ -62,7 +62,7 @@
} }
this.$emit("close"); this.$emit("close");
}, },
handleAddFriend() { onAddFriend() {
this.$http({ this.$http({
url: "/friend/add", url: "/friend/add",
method: "post", method: "post",

14
im-ui/src/components/friend/AddFriend.vue

@ -1,7 +1,7 @@
<template> <template>
<el-dialog title="添加好友" :visible.sync="dialogVisible" width="30%" :before-close="handleClose"> <el-dialog title="添加好友" :visible.sync="dialogVisible" width="30%" :before-close="onClose">
<el-input placeholder="输入用户名或昵称,最多展示20条" class="input-with-select" v-model="searchText" @keyup.enter.native="handleSearch()"> <el-input placeholder="输入用户名或昵称,最多展示20条" class="input-with-select" v-model="searchText" @keyup.enter.native="onSearch()">
<el-button slot="append" icon="el-icon-search" @click="handleSearch()"></el-button> <el-button slot="append" icon="el-icon-search" @click="onSearch()"></el-button>
</el-input> </el-input>
<el-scrollbar style="height:400px"> <el-scrollbar style="height:400px">
<div v-for="(user) in users" :key="user.id" v-show="user.id != $store.state.userStore.userInfo.id"> <div v-for="(user) in users" :key="user.id" v-show="user.id != $store.state.userStore.userInfo.id">
@ -21,7 +21,7 @@
<div>昵称:{{user.nickName}}</div> <div>昵称:{{user.nickName}}</div>
</div> </div>
</div> </div>
<el-button type="success" size="small" v-show="!isFriend(user.id)" plain @click="handleAddFriend(user)">添加</el-button> <el-button type="success" size="small" v-show="!isFriend(user.id)" plain @click="onAddFriend(user)">添加</el-button>
<el-button type="info" size="small" v-show="isFriend(user.id)" plain disabled>已添加</el-button> <el-button type="info" size="small" v-show="isFriend(user.id)" plain disabled>已添加</el-button>
</div> </div>
</div> </div>
@ -48,10 +48,10 @@
} }
}, },
methods: { methods: {
handleClose() { onClose() {
this.$emit("close"); this.$emit("close");
}, },
handleSearch() { onSearch() {
this.$http({ this.$http({
url: "/user/findByName", url: "/user/findByName",
method: "get", method: "get",
@ -62,7 +62,7 @@
this.users = data; this.users = data;
}) })
}, },
handleAddFriend(user){ onAddFriend(user){
this.$http({ this.$http({
url: "/friend/add", url: "/friend/add",
method: "post", method: "post",

14
im-ui/src/components/friend/FriendItem.vue

@ -1,7 +1,7 @@
<template> <template>
<div class="friend-item" :class="active ? 'active' : ''" @contextmenu.prevent="showRightMenu($event)"> <div class="friend-item" :class="active ? 'active' : ''" @contextmenu.prevent="showRightMenu($event)">
<div class="friend-avatar"> <div class="friend-avatar">
<head-image :name="friend.nickName" :url="friend.headImage" :online="friend.online"> <head-image :size="45" :name="friend.nickName" :url="friend.headImage" :online="friend.online">
</head-image> </head-image>
</div> </div>
<div class="friend-info"> <div class="friend-info">
@ -14,7 +14,7 @@
</div> </div>
</div> </div>
<right-menu v-show="menu && rightMenu.show" :pos="rightMenu.pos" :items="rightMenu.items" <right-menu v-show="menu && rightMenu.show" :pos="rightMenu.pos" :items="rightMenu.items"
@close="rightMenu.show=false" @select="handleSelectMenu"></right-menu> @close="rightMenu.show=false" @select="onSelectMenu"></right-menu>
<slot></slot> <slot></slot>
</div> </div>
</template> </template>
@ -57,7 +57,7 @@
}; };
this.rightMenu.show = "true"; this.rightMenu.show = "true";
}, },
handleSelectMenu(item) { onSelectMenu(item) {
this.$emit(item.key.toLowerCase(), this.msgInfo); this.$emit(item.key.toLowerCase(), this.msgInfo);
} }
}, },
@ -83,13 +83,13 @@
<style scope lang="scss"> <style scope lang="scss">
.friend-item { .friend-item {
height: 65px; height: 50px;
display: flex; display: flex;
margin-bottom: 1px; margin-bottom: 1px;
position: relative; position: relative;
padding: 5px;
padding-left: 10px; padding-left: 10px;
align-items: center; align-items: center;
padding-right: 5px;
background-color: #fafafa; background-color: #fafafa;
white-space: nowrap; white-space: nowrap;
cursor: pointer; cursor: pointer;
@ -106,8 +106,8 @@
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
width: 50px; width: 45px;
height: 50px; height: 45px;
} }
.friend-info { .friend-info {

22
im-ui/src/components/group/AddGroupMember.vue

@ -1,13 +1,13 @@
<template> <template>
<el-dialog title="邀请好友" :visible.sync="visible" width="50%" :before-close="handleClose"> <el-dialog title="邀请好友" :visible.sync="visible" width="50%" :before-close="onClose">
<div class="agm-container"> <div class="agm-container">
<div class="agm-l-box"> <div class="agm-l-box">
<el-input width="200px" placeholder="搜索好友" class="input-with-select" v-model="searchText" @keyup.enter.native="handleSearch()"> <el-input width="200px" placeholder="搜索好友" class="input-with-select" v-model="searchText" @keyup.enter.native="onSearch()">
<el-button slot="append" icon="el-icon-search" @click="handleSearch()"></el-button> <el-button slot="append" icon="el-icon-search" @click="onSearch()"></el-button>
</el-input> </el-input>
<el-scrollbar style="height:400px;"> <el-scrollbar style="height:400px;">
<div v-for="(friend,index) in friends" :key="friend.id"> <div v-for="(friend,index) in friends" :key="friend.id">
<friend-item v-show="friend.nickName.startsWith(searchText)" :showDelete="false" @click.native="handleSwitchCheck(friend)" <friend-item v-show="friend.nickName.startsWith(searchText)" :showDelete="false" @click.native="onSwitchCheck(friend)"
:menu="false" :friend="friend" :index="index" :active="index === activeIndex"> :menu="false" :friend="friend" :index="index" :active="index === activeIndex">
<el-checkbox :disabled="friend.disabled" @click.native.stop="" class="agm-friend-checkbox" v-model="friend.isCheck" <el-checkbox :disabled="friend.disabled" @click.native.stop="" class="agm-friend-checkbox" v-model="friend.isCheck"
size="medium"></el-checkbox> size="medium"></el-checkbox>
@ -20,7 +20,7 @@
<el-scrollbar style="height:400px;"> <el-scrollbar style="height:400px;">
<div v-for="(friend,index) in friends" :key="friend.id"> <div v-for="(friend,index) in friends" :key="friend.id">
<friend-item v-if="friend.isCheck && !friend.disabled" :friend="friend" <friend-item v-if="friend.isCheck && !friend.disabled" :friend="friend"
:index="index" :active="false" @del="handleRemoveFriend(friend,index)" :index="index" :active="false" @del="onRemoveFriend(friend,index)"
:menu="false"> :menu="false">
</friend-item> </friend-item>
</div> </div>
@ -28,8 +28,8 @@
</div> </div>
</div> </div>
<span slot="footer" class="dialog-footer"> <span slot="footer" class="dialog-footer">
<el-button @click="handleClose()"> </el-button> <el-button @click="onClose()"> </el-button>
<el-button type="primary" @click="handleOk()"> </el-button> <el-button type="primary" @click="onOk()"> </el-button>
</span> </span>
</el-dialog> </el-dialog>
</template> </template>
@ -50,10 +50,10 @@
} }
}, },
methods: { methods: {
handleClose() { onClose() {
this.$emit("close"); this.$emit("close");
}, },
handleOk() { onOk() {
let inviteVO = { let inviteVO = {
groupId: this.groupId, groupId: this.groupId,
@ -76,10 +76,10 @@
}) })
} }
}, },
handleRemoveFriend(friend, index) { onRemoveFriend(friend, index) {
friend.isCheck = false; friend.isCheck = false;
}, },
handleSwitchCheck(friend) { onSwitchCheck(friend) {
if (!friend.disabled) { if (!friend.disabled) {
friend.isCheck = !friend.isCheck friend.isCheck = !friend.isCheck
} }

12
im-ui/src/components/group/GroupItem.vue

@ -1,7 +1,7 @@
<template> <template>
<div class="group-item" :class="active ? 'active' : ''"> <div class="group-item" :class="active ? 'active' : ''">
<div class="group-avatar"> <div class="group-avatar">
<head-image :name="group.remark" :url="group.headImage"> </head-image> <head-image :size="45" :name="group.remark" :url="group.headImage"> </head-image>
</div> </div>
<div class="group-name"> <div class="group-name">
<div>{{group.remark}}</div> <div>{{group.remark}}</div>
@ -34,13 +34,13 @@
<style lang="scss" > <style lang="scss" >
.group-item { .group-item {
height: 65px; height: 50px;
display: flex; display: flex;
margin-bottom: 1px; margin-bottom: 1px;
position: relative; position: relative;
padding: 5px;
padding-left: 10px; padding-left: 10px;
align-items: center; align-items: center;
padding-right: 5px;
background-color: #fafafa; background-color: #fafafa;
white-space: nowrap; white-space: nowrap;
&:hover { &:hover {
@ -52,15 +52,15 @@
} }
.group-avatar { .group-avatar {
width: 50px; width: 45px;
height: 50px; height: 45px;
} }
.group-name { .group-name {
padding-left: 10px; padding-left: 10px;
height: 100%; height: 100%;
text-align: left; text-align: left;
line-height: 65px; line-height: 50px;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
font-size: 14px; font-size: 14px;

4
im-ui/src/components/group/GroupMember.vue

@ -3,7 +3,7 @@
<head-image :id="member.userId" :name="member.aliasName" <head-image :id="member.userId" :name="member.aliasName"
:url="member.headImage" :size="50" :url="member.headImage" :size="50"
:online="member.online" > :online="member.online" >
<div v-if="showDel" @click.stop="handleDelete()" class="btn-kick el-icon-error"></div> <div v-if="showDel" @click.stop="onDelete()" class="btn-kick el-icon-error"></div>
</head-image> </head-image>
<div class="member-name">{{member.aliasName}}</div> <div class="member-name">{{member.aliasName}}</div>
@ -29,7 +29,7 @@
} }
}, },
methods:{ methods:{
handleDelete(){ onDelete(){
this.$emit("del",this.member); this.$emit("del",this.member);
} }
} }

14
im-ui/src/components/setting/Setting.vue

@ -1,12 +1,12 @@
<template> <template>
<el-dialog class="setting" title="设置" :visible.sync="visible" width="500px" :before-close="handleClose"> <el-dialog class="setting" title="设置" :visible.sync="visible" width="500px" :before-close="onClose">
<el-form :model="userInfo" label-width="80px" :rules="rules" ref="settingForm"> <el-form :model="userInfo" label-width="80px" :rules="rules" ref="settingForm">
<el-form-item label="头像"> <el-form-item label="头像">
<file-upload class="avatar-uploader" <file-upload class="avatar-uploader"
:action="imageAction" :action="imageAction"
:showLoading="true" :showLoading="true"
:maxSize="maxSize" :maxSize="maxSize"
@success="handleUploadSuccess" @success="onUploadSuccess"
:fileTypes="['image/jpeg', 'image/png', 'image/jpg','image/webp']"> :fileTypes="['image/jpeg', 'image/png', 'image/jpg','image/webp']">
<img v-if="userInfo.headImage" :src="userInfo.headImage" class="avatar"> <img v-if="userInfo.headImage" :src="userInfo.headImage" class="avatar">
@ -31,8 +31,8 @@
</el-form> </el-form>
<span slot="footer" class="dialog-footer"> <span slot="footer" class="dialog-footer">
<el-button @click="handleClose()"> </el-button> <el-button @click="onClose()"> </el-button>
<el-button type="primary" @click="handleSubmit()"> </el-button> <el-button type="primary" @click="onSubmit()"> </el-button>
</span> </span>
</el-dialog> </el-dialog>
</template> </template>
@ -65,10 +65,10 @@
}, },
methods: { methods: {
handleClose() { onClose() {
this.$emit("close"); this.$emit("close");
}, },
handleSubmit() { onSubmit() {
this.$refs['settingForm'].validate((valid) => { this.$refs['settingForm'].validate((valid) => {
if (!valid) { if (!valid) {
return false; return false;
@ -84,7 +84,7 @@
}) })
}); });
}, },
handleUploadSuccess(res, file) { onUploadSuccess(res, file) {
this.userInfo.headImage = res.data.originUrl; this.userInfo.headImage = res.data.originUrl;
this.userInfo.headImageThumb = res.data.thumbUrl; this.userInfo.headImageThumb = res.data.thumbUrl;
} }

5
im-ui/src/store/friendStore.js

@ -27,13 +27,10 @@ export default {
}, },
removeFriend(state, index) { removeFriend(state, index) {
state.friends.splice(index, 1); state.friends.splice(index, 1);
if(state.activeIndex >= state.friends.length){ state.activeIndex = -1;
state.activeIndex = state.friends.length-1;
}
}, },
addFriend(state, friend) { addFriend(state, friend) {
state.friends.push(friend); state.friends.push(friend);
state.activeIndex = state.friends.length-1;
}, },
refreshOnlineStatus(state){ refreshOnlineStatus(state){
let userIds = []; let userIds = [];

4
im-ui/src/store/groupStore.js

@ -20,9 +20,7 @@ export default {
state.groups.forEach((g, index) => { state.groups.forEach((g, index) => {
if (g.id == groupId) { if (g.id == groupId) {
state.groups.splice(index, 1); state.groups.splice(index, 1);
if (state.activeIndex >= state.groups.length) { state.activeIndex = -1;
state.activeIndex = state.groups.length - 1;
}
} }
}) })

9
im-ui/src/view/Group.vue

@ -191,9 +191,8 @@
}).then(() => { }).then(() => {
this.$message.success(`群聊'${this.activeGroup.name}'已解散`); this.$message.success(`群聊'${this.activeGroup.name}'已解散`);
this.$store.commit("removeGroup", this.activeGroup.id); this.$store.commit("removeGroup", this.activeGroup.id);
this.$store.commit("activeGroup", -1);
this.$store.commit("removeGroupChat", this.activeGroup.id); this.$store.commit("removeGroupChat", this.activeGroup.id);
this.activeGroup = {}; this.reset();
}); });
}) })
@ -228,8 +227,8 @@
method: 'delete' method: 'delete'
}).then(() => { }).then(() => {
this.$store.commit("removeGroup", this.activeGroup.id); this.$store.commit("removeGroup", this.activeGroup.id);
this.$store.commit("activeGroup", -1);
this.$store.commit("removeGroupChat", this.activeGroup.id); this.$store.commit("removeGroupChat", this.activeGroup.id);
this.reset();
}); });
}) })
@ -252,6 +251,10 @@
}).then((members) => { }).then((members) => {
this.groupMembers = members; this.groupMembers = members;
}) })
},
reset(){
this.activeGroup={};
this.groupMembers=[];
} }
}, },
computed: { computed: {

Loading…
Cancel
Save