Эх сурвалжийг харах

支持输入框粘贴图片

xie.bx 2 жил өмнө
parent
commit
2c59c6a86c

+ 4 - 1
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)

+ 144 - 36
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>

+ 9 - 8
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 {

+ 1 - 1
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);