Browse Source

支持输入框粘贴图片

master
xie.bx 2 years ago
parent
commit
2c59c6a86c
  1. 5
      im-platform/src/main/java/com/bx/implatform/util/MinioUtil.java
  2. 180
      im-ui/src/components/chat/ChatBox.vue
  3. 17
      im-ui/src/components/chat/ChatMessageItem.vue
  4. 2
      im-ui/src/components/common/FileUpload.vue

5
im-platform/src/main/java/com/bx/implatform/util/MinioUtil.java

@ -106,7 +106,10 @@ public class MinioUtil {
if (StringUtils.isBlank(originalFilename)){
throw new RuntimeException();
}
String fileName = System.currentTimeMillis() + originalFilename.substring(originalFilename.lastIndexOf("."));
String fileName = System.currentTimeMillis()+"";
if(originalFilename.lastIndexOf(".") >= 0){
fileName +=originalFilename.substring(originalFilename.lastIndexOf("."));
}
String objectName = DateTimeUtils.getFormatDate(new Date(),DateTimeUtils.PARTDATEFORMAT)+ "/" + fileName;
try {
PutObjectArgs objectArgs = PutObjectArgs.builder().bucket(bucketName).object(path+"/" +objectName)

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

@ -2,7 +2,8 @@
<el-container class="chat-box">
<el-header height="60px">
<span>{{title}}</span>
<span title="群聊信息" v-show="this.chat.type=='GROUP'" class="btn-side el-icon-more" @click="showSide=!showSide"></span>
<span title="群聊信息" v-show="this.chat.type=='GROUP'" class="btn-side el-icon-more"
@click="showSide=!showSide"></span>
</el-header>
<el-main style="padding: 0;">
<el-container>
@ -11,8 +12,9 @@
<div class="im-chat-box">
<ul>
<li v-for="(msgInfo,idx) in chat.messages" :key="idx">
<chat-message-item :mine="msgInfo.sendId == mine.id" :headImage="headImage(msgInfo)" :showName="showName(msgInfo)"
:msgInfo="msgInfo" @delete="deleteMessage" @recall="recallMessage">
<chat-message-item :mine="msgInfo.sendId == mine.id" :headImage="headImage(msgInfo)"
:showName="showName(msgInfo)" :msgInfo="msgInfo" @delete="deleteMessage"
@recall="recallMessage">
</chat-message-item>
</li>
</ul>
@ -20,31 +22,44 @@
</el-main>
<el-footer height="240px" class="im-chat-footer">
<div class="chat-tool-bar">
<div title="表情" class="icon iconfont icon-biaoqing" ref="emotion" @click="switchEmotionBox()">
<div title="表情" class="icon iconfont icon-biaoqing" ref="emotion"
@click="switchEmotionBox()">
</div>
<div title="发送图片">
<file-upload :action="imageAction" :maxSize="5*1024*1024" :fileTypes="['image/jpeg', 'image/png', 'image/jpg', 'image/webp','image/gif']"
@before="handleImageBefore" @success="handleImageSuccess" @fail="handleImageFail">
<file-upload :action="imageAction" :maxSize="5*1024*1024"
:fileTypes="['image/jpeg', 'image/png', 'image/jpg', 'image/webp','image/gif']"
@before="handleImageBefore" @success="handleImageSuccess" @fail="handleImageFail">
<i class="el-icon-picture-outline"></i>
</file-upload>
</div>
<div title="发送文件">
<file-upload :action="fileAction" :maxSize="10*1024*1024" @before="handleFileBefore" @success="handleFileSuccess"
@fail="handleFileFail">
<file-upload :action="fileAction" :maxSize="10*1024*1024" @before="handleFileBefore"
@success="handleFileSuccess" @fail="handleFileFail">
<i class="el-icon-wallet"></i>
</file-upload>
</div>
<div title="发送语音" class="el-icon-microphone" @click="showVoiceBox()">
</div>
<div title="视频聊天" v-show="chat.type=='PRIVATE'" class="el-icon-phone-outline" @click="showVideoBox()">
<div title="视频聊天" v-show="chat.type=='PRIVATE'" class="el-icon-phone-outline"
@click="showVideoBox()">
</div>
<div title="聊天记录" class="el-icon-chat-dot-round" @click="showHistoryBox()"></div>
</div>
<textarea v-model="sendText" ref="sendBox" class="send-text-area"
:disabled="lockMessage" @keydown.enter="sendTextMessage()"
placeholder="聊点什么吧~"></textarea>
<div class="im-chat-send">
<el-button type="primary" size="small" @click="sendTextMessage()">发送</el-button>
<div class="send-content-area">
<textarea v-show="!sendImageUrl" v-model="sendText" ref="sendBox" class="send-text-area"
:disabled="lockMessage" @keydown.enter="sendTextMessage()" @paste="handlePaste"
placeholder="聊点什么吧~"></textarea>
<div v-show="sendImageUrl" class="send-image-area">
<div class="send-image-box">
<img class="send-image" :src="sendImageUrl" />
<span class="send-image-close el-icon-close" title="删除"
@click="removeSendImage()"></span>
</div>
</div>
<div class="send-btn-area">
<el-button type="primary" size="small" @click="handleSendMessage()">发送</el-button>
</div>
</div>
</el-footer>
</el-container>
@ -56,7 +71,8 @@
</el-main>
<emotion v-show="showEmotion" :pos="emoBoxPos" @emotion="handleEmotion"></Emotion>
<chat-voice :visible="showVoice" @close="closeVoiceBox" @send="handleSendVoice"></chat-voice>
<chat-history :visible="showHistory" :chat="chat" :friend="friend" :group="group" :groupMembers="groupMembers" @close="closeHistoryBox"></chat-history>
<chat-history :visible="showHistory" :chat="chat" :friend="friend" :group="group" :groupMembers="groupMembers"
@close="closeHistoryBox"></chat-history>
</el-container>
</template>
@ -89,6 +105,8 @@
group: {},
groupMembers: [],
sendText: "",
sendImageUrl: "",
sendImageFile: "",
showVoice: false, //
showSide: false, //
showEmotion: false, // emoji
@ -101,9 +119,29 @@
}
},
methods: {
handleImageSuccess(res, file) {
let msgInfo = JSON.parse(JSON.stringify(file.raw.msgInfo));
msgInfo.content = JSON.stringify(res.data);
handlePaste(e) {
let txt = event.clipboardData.getData('Text')
if (typeof(txt) == 'string') {
this.sendText += txt
}
const items = (event.clipboardData || window.clipboardData).items
if (items.length) {
for (let i = 0; i < items.length; i++) {
if (items[i].type.indexOf('image') !== -1) {
let file = items[i].getAsFile();
this.sendImageFile = file;
this.sendImageUrl = URL.createObjectURL(file);
}
}
}
},
removeSendImage() {
this.sendImageUrl = "";
this.sendImageFile = null;
},
handleImageSuccess(data, file) {
let msgInfo = JSON.parse(JSON.stringify(file.msgInfo || file.raw.msgInfo));
msgInfo.content = JSON.stringify(data);
this.$http({
url: this.messageAction,
method: 'post',
@ -114,8 +152,8 @@
this.$store.commit("insertMessage", msgInfo);
})
},
handleImageFail(res, file) {
let msgInfo = JSON.parse(JSON.stringify(file.raw.msgInfo));
handleImageFail(e, file) {
let msgInfo = JSON.parse(JSON.stringify(file.msgInfo || file.raw.msgInfo));
msgInfo.loadStatus = 'fail';
this.$store.commit("insertMessage", msgInfo);
},
@ -144,11 +182,11 @@
// file
file.msgInfo = msgInfo;
},
handleFileSuccess(res, file) {
handleFileSuccess(url, file) {
let data = {
name: file.name,
size: file.size,
url: res.data
url: url
}
let msgInfo = JSON.parse(JSON.stringify(file.raw.msgInfo));
msgInfo.content = JSON.stringify(data);
@ -162,7 +200,8 @@
this.$store.commit("insertMessage", msgInfo);
})
},
handleFileFail(res, file) {
handleFileFail(e, file) {
let msgInfo = JSON.parse(JSON.stringify(file.raw.msgInfo));
msgInfo.loadStatus = 'fail';
this.$store.commit("insertMessage", msgInfo);
@ -261,6 +300,30 @@
msgInfo.recvId = targetId;
}
},
handleSendMessage() {
if (this.sendImageFile) {
this.sendImageMessage();
} else {
this.sendTextMessage();
}
},
sendImageMessage() {
this.handleImageBefore(this.sendImageFile);
let formData = new FormData()
formData.append('file', this.sendImageFile.raw || this.sendImageFile)
this.$http.post("/image/upload", formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
}).then((data) => {
this.handleImageSuccess(data, this.sendImageFile);
}).catch((res) => {
this.handleImageSuccess(res, this.sendImageFile);
}).finally(() => {
this.sendImageFile = null;
this.sendImageUrl= ""
});
},
sendTextMessage() {
if (!this.sendText.trim()) {
this.$message.error("不能发送空白信息");
@ -498,22 +561,67 @@
}
}
.send-text-area {
box-sizing: border-box;
padding: 5px;
width: 100%;
flex: 1;
resize: none;
font-size: 16px;
color: black;
.send-content-area {
display: flex;
flex-direction: column;
height: 100%;
background-color: #f8f8f8 !important;
outline-color: rgba(83, 160, 231, 0.61);
}
.im-chat-send {
text-align: right;
padding: 7px;
.send-text-area {
box-sizing: border-box;
padding: 5px;
width: 100%;
flex: 1;
resize: none;
font-size: 16px;
color: black;
background-color: #f8f8f8 !important;
outline-color: rgba(83, 160, 231, 0.61);
text-align: left;
border: 0;
}
.send-image-area {
text-align: left;
.send-image-box {
position: relative;
display: inline-block;
.send-image {
max-height: 190px;
border: 1px solid #ccc;
border-radius: 2%;
margin: 2px;
}
.send-image-close {
position: absolute;
padding: 3px;
right: 7px;
top: 7px;
color: white;
cursor: pointer;
font-size: 15px;
font-weight: 600;
background-color: #aaa;
border-radius: 50%;
border: 1px solid #ccc;
}
}
}
.send-btn-area {
padding: 10px;
position: absolute;
bottom: 0;
right: 0;
}
}
}
.chat-group-side-box {
@ -521,4 +629,4 @@
animation: rtl-drawer-in .3s 1ms;
}
}
</style>
</style>

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

@ -21,7 +21,7 @@
<div class="chat-msg-image" v-if="msgInfo.type==$enums.MESSAGE_TYPE.IMAGE">
<div class="img-load-box" v-loading="loading" element-loading-text="上传中.."
element-loading-background="rgba(0, 0, 0, 0.4)">
<img class="send-image" :src="JSON.parse(msgInfo.content).thumbUrl"
<img class="send-image" :src="JSON.parse(msgInfo.content).thumbUrl"
@click="showFullImageBox()" />
</div>
<span title="发送失败" v-show="loadFail" @click="handleSendFail"
@ -201,6 +201,13 @@
.chat-msg-content {
text-align: left;
.send-fail {
color: #e60c0c;
font-size: 30px;
cursor: pointer;
margin: 0 20px;
}
.chat-msg-top {
display: flex;
flex-wrap: nowrap;
@ -262,13 +269,7 @@
border-radius: 6px;
cursor: pointer;
}
c
.send-fail {
color: #e60c0c;
font-size: 30px;
cursor: pointer;
margin: 0 20px;
}
}
.chat-msg-file {

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

@ -40,7 +40,7 @@
handleSuccess(res, file) {
this.loading && this.loading.close();
if (res.code == 200) {
this.$emit("success", res, file);
this.$emit("success", res.data, file);
} else {
this.$message.error(res.message);
this.$emit("fail", res, file);

Loading…
Cancel
Save