|
@@ -26,6 +26,11 @@
|
|
|
{{ chatMessage.message }}
|
|
|
</div>
|
|
|
</template>
|
|
|
+ <!-- 消息内容出发特效关键词 -->
|
|
|
+ <ChatEmojiAnimations
|
|
|
+ v-if="showChatEmojiAnimations"
|
|
|
+ class="chatEmojiAnimationsComponent"
|
|
|
+ :emojis="emojis"/>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="chat-editer-menu-container">
|
|
@@ -60,13 +65,14 @@
|
|
|
v-model:visible="videoModalVisible"
|
|
|
:width="1045"
|
|
|
:height="530"
|
|
|
+ class="custom-dark-modal"
|
|
|
:okButtonProps="{ style: { display: 'none' } }"
|
|
|
:cancelButtonProps="{ style: { display: 'none' } }"
|
|
|
@update:visible="handleVideoModalVisibleChange"
|
|
|
:maskClosable="false"
|
|
|
>
|
|
|
<template #title>
|
|
|
- <div class="modal-title">
|
|
|
+ <div class="modal-title" style="color: white">
|
|
|
正在与 <b style="color: brown">{{ selectChatUser?.userName }} </b>音视频通话
|
|
|
</div>
|
|
|
</template>
|
|
@@ -77,22 +83,77 @@
|
|
|
@close="handleVideoClose"/>
|
|
|
</a-modal>
|
|
|
|
|
|
+ <a-modal
|
|
|
+ v-model:visible="sendRedPacketModalVisible"
|
|
|
+ :width="400"
|
|
|
+ :height="450"
|
|
|
+ class="red-packet-modal"
|
|
|
+ :okButtonProps="{ style: { display: 'none' } }"
|
|
|
+ :cancelButtonProps="{ style: { display: 'none' } }"
|
|
|
+ >
|
|
|
+ <template #title>
|
|
|
+ <div class="modal-title">
|
|
|
+ 发红包
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <!-- 隐藏的文件上传input -->
|
|
|
+ <input
|
|
|
+ type="file"
|
|
|
+ ref="redPacketFileInput"
|
|
|
+ accept="image/*"
|
|
|
+ style="display: none;"
|
|
|
+ @change="handleFileUpload"
|
|
|
+ />
|
|
|
+ <a-input prefix="¥" suffix="RMB" class="red-packet-input" placeholder="红包金额 ¥0.00"/>
|
|
|
+ <a-input suffix="😊" class="red-packet-input" placeholder="恭喜发财,大吉大利"/>
|
|
|
+ <a-dropdown style="width: 100%">
|
|
|
+ <template #overlay>
|
|
|
+ <a-menu @click="uploadRedPacketCover">
|
|
|
+ <a-menu-item key="1">
|
|
|
+ <PictureOutlined />
|
|
|
+ 上传红包红面
|
|
|
+ </a-menu-item>
|
|
|
+ </a-menu>
|
|
|
+ </template>
|
|
|
+ <a-button class="red-packet-cover-button">
|
|
|
+ 红包封面 <RightOutlined />
|
|
|
+ <!-- 显示预览图 -->
|
|
|
+ <img
|
|
|
+ v-if="redPacketCover"
|
|
|
+ :src="redPacketCover"
|
|
|
+ class="cover-preview"
|
|
|
+ />
|
|
|
+ </a-button>
|
|
|
+ </a-dropdown>
|
|
|
+ <div class="red-packet-money">
|
|
|
+ ¥ {{redPacketMoney}}
|
|
|
+ </div>
|
|
|
+ <a-button type="primary" class="send-red-packet-button">塞钱进红包</a-button>
|
|
|
+
|
|
|
+ <div class="red-packet-tip">
|
|
|
+ 使用WebChat钱包余额直接发红包
|
|
|
+ </div>
|
|
|
+
|
|
|
+ </a-modal>
|
|
|
+
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
import axios from 'axios';
|
|
|
import { inject, defineComponent, ref, onMounted, onUnmounted, watch } from 'vue';
|
|
|
+ import { message } from 'ant-design-vue';
|
|
|
import Video2User from './video2User.vue';
|
|
|
+ import ChatEmojiAnimations from './animation/emojiAnimations.vue';
|
|
|
export default defineComponent({
|
|
|
props: {
|
|
|
selectChatUserRef: Object,
|
|
|
openVideoRef: Boolean
|
|
|
},
|
|
|
components: {
|
|
|
- Video2User
|
|
|
+ Video2User,
|
|
|
+ ChatEmojiAnimations
|
|
|
},
|
|
|
setup(props) {
|
|
|
-
|
|
|
const inputValue = ref('');
|
|
|
const socket = ref(null);
|
|
|
const messageQueue = ref([]); // 存储未发送的消息队列
|
|
@@ -104,6 +165,17 @@
|
|
|
const heartbeatInterval = ref(30000); // 心跳间隔时间,单位:毫秒
|
|
|
const chatMessageArr = ref([]);
|
|
|
const videoModalVisible = ref(false)
|
|
|
+ const sendRedPacketModalVisible = ref(false)
|
|
|
+ const redPacketMoney = ref(0.00)
|
|
|
+ const redPacketCover = ref(null);
|
|
|
+ const redPacketFileInput = ref(null);
|
|
|
+ const uploadUrl = `/client-service/chat/file/upload`; // 上传API
|
|
|
+ const showChatEmojiAnimations = ref(false);
|
|
|
+ const emojis = ref([""]);
|
|
|
+
|
|
|
+ // 维护关键词,emoji特效
|
|
|
+ const messageKeywords = ["生日快乐", "比心", "爱你", "礼物", "红包", "💣", "炸弹", "💩", "屎"];
|
|
|
+ const messageKeywordsEmojis = ["🍰", "♥️", "😘", "🎁", "🧧", "💣", "💣", "💩", "💩"];
|
|
|
|
|
|
const loadChatMessages = (chatUserId) => {
|
|
|
// 先清空
|
|
@@ -169,8 +241,8 @@
|
|
|
}
|
|
|
const messageType = socketMessage.type;
|
|
|
if (messageType === 1) {
|
|
|
- // 处理对话
|
|
|
chatMessageArr.value.push(socketMessage);
|
|
|
+ handleMessageKeyword(socketMessage.message);
|
|
|
}
|
|
|
};
|
|
|
|
|
@@ -202,14 +274,36 @@
|
|
|
// 链接ws
|
|
|
connectWebSocket();
|
|
|
|
|
|
+ const sendMessageObj = (message) => {
|
|
|
+ sendMessage(JSON.stringify(message));
|
|
|
+ }
|
|
|
+
|
|
|
const sendMessage = (message) => {
|
|
|
if (isConnected.value) {
|
|
|
socket.value.send(message);
|
|
|
} else {
|
|
|
messageQueue.value.push(message);
|
|
|
}
|
|
|
+ // 关键词出发emoji飘落特效
|
|
|
+ handleMessageKeyword(message);
|
|
|
};
|
|
|
|
|
|
+ // 关键词出发emoji飘落特效
|
|
|
+ const handleMessageKeyword = (message) => {
|
|
|
+ showChatEmojiAnimations.value = false;
|
|
|
+ emojis.value = [];
|
|
|
+ for(var i = 0; i < messageKeywords.length; i ++) {
|
|
|
+ if (message.includes(messageKeywords[i])) {
|
|
|
+ showChatEmojiAnimations.value = true;
|
|
|
+ emojis.value.push(messageKeywordsEmojis[i]);
|
|
|
+ // 延迟隐藏保证动画完成
|
|
|
+ setTimeout(() => {
|
|
|
+ showChatEmojiAnimations.value = false;
|
|
|
+ }, 8000)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
const handleInput = (event) => {
|
|
|
inputValue.value = event.target.value;
|
|
|
};
|
|
@@ -229,13 +323,57 @@
|
|
|
// 当前用户自己发送的消息直接提交到页面渲染
|
|
|
chatMessageArr.value.push(JSON.parse(chatMessage));
|
|
|
// ws发送消息
|
|
|
- socket.value.send(chatMessage);
|
|
|
+ sendMessage(chatMessage);
|
|
|
// 清空输入框
|
|
|
inputValue.value = '';
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ // 点击上传菜单项
|
|
|
+ const uploadRedPacketCover = ({ key }) => {
|
|
|
+ if (key === '1') {
|
|
|
+ // 触发隐藏的input点击
|
|
|
+ redPacketFileInput.value.click();
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 处理文件选择
|
|
|
+ const handleFileUpload = async (e) => {
|
|
|
+ const file = e.target.files[0];
|
|
|
+ if (!file) return;
|
|
|
+ // 校验文件类型
|
|
|
+ if (!file.type.startsWith('image/')) {
|
|
|
+ message.error('请选择图片文件');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 校验文件大小(示例限制2MB)
|
|
|
+ if (file.size > 10 * 1024 * 1024) {
|
|
|
+ message.error('图片大小不能超过10MB');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 方式2:上传到服务器(示例使用axios)
|
|
|
+ try {
|
|
|
+ const formData = new FormData();
|
|
|
+ formData.append('file', file);
|
|
|
+ const response = await axios.post(uploadUrl, formData, {
|
|
|
+ headers: {
|
|
|
+ 'Content-Type': 'multipart/form-data',
|
|
|
+ 'origin-url': window.location.href,
|
|
|
+ 'upload-path': 'images/redPacket'
|
|
|
+ }
|
|
|
+ });
|
|
|
+ if (response.data.code === 40001) {
|
|
|
+ window.location.href = response.data.redirect_url;
|
|
|
+ }
|
|
|
+ // 预览红包封面图
|
|
|
+ redPacketCover.value = response.data.data.url;
|
|
|
+ } catch (error) {
|
|
|
+ message.error('上传失败');
|
|
|
+ console.error('Upload error:', error);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
const handleClick = (type) => {
|
|
|
switch (type) {
|
|
|
case 'emoji':
|
|
@@ -245,6 +383,7 @@
|
|
|
case 'redPacket':
|
|
|
console.log('点击了红包按钮');
|
|
|
// 在此添加红包按钮的逻辑,例如打开红包发送界面等
|
|
|
+ sendRedPacketModalVisible.value = true;
|
|
|
break;
|
|
|
case 'audioVideo':
|
|
|
// 发起音视频通话
|
|
@@ -266,6 +405,9 @@
|
|
|
});
|
|
|
|
|
|
return {
|
|
|
+ uploadUrl,
|
|
|
+ redPacketCover,
|
|
|
+ redPacketFileInput,
|
|
|
openVideo,
|
|
|
videoModalVisible,
|
|
|
inputValue,
|
|
@@ -276,13 +418,20 @@
|
|
|
reconnectInterval,
|
|
|
heartbeatInterval,
|
|
|
chatMessageArr,
|
|
|
+ sendRedPacketModalVisible,
|
|
|
+ redPacketMoney,
|
|
|
+ showChatEmojiAnimations,
|
|
|
+ emojis,
|
|
|
handleVideoModalVisibleChange,
|
|
|
handleClick,
|
|
|
handleSendMessage,
|
|
|
handleInput,
|
|
|
connectWebSocket,
|
|
|
loadChatMessages,
|
|
|
- handleVideoClose
|
|
|
+ handleVideoClose,
|
|
|
+ handleFileUpload,
|
|
|
+ uploadRedPacketCover,
|
|
|
+ sendMessageObj,
|
|
|
};
|
|
|
}
|
|
|
});
|
|
@@ -418,4 +567,60 @@
|
|
|
border-style: solid;
|
|
|
border-color: transparent #f5f5f5 transparent transparent;
|
|
|
}
|
|
|
+/* 强制提升优先级 */
|
|
|
+.custom-dark-modal.ant-modal .ant-modal-content {
|
|
|
+ background: #000 !important;
|
|
|
+ color: white !important;
|
|
|
+}
|
|
|
+.custom-dark-modal.ant-modal .ant-modal-header {
|
|
|
+ background: #000 !important;
|
|
|
+}
|
|
|
+.red-packet-input, .red-packet-cover-button {
|
|
|
+ height: 50px;
|
|
|
+ margin-top: 15px;
|
|
|
+ background-color: white;
|
|
|
+}
|
|
|
+.red-packet-cover-button {
|
|
|
+ width: 100%;
|
|
|
+ text-align: left;
|
|
|
+}
|
|
|
+.send-red-packet-button {
|
|
|
+ background-color: #ff5e4b;
|
|
|
+ color: white;
|
|
|
+ width: 170px;
|
|
|
+ height: 45px;
|
|
|
+ margin-top: 30px;
|
|
|
+ margin-left: 100px;
|
|
|
+}
|
|
|
+.send-red-packet-button:hover {
|
|
|
+ background-color:rgb(252, 68, 48);
|
|
|
+}
|
|
|
+.red-packet-money {
|
|
|
+ position: relative;
|
|
|
+ width: 100%;
|
|
|
+ line-height: 50px;
|
|
|
+ font-size: 35px;
|
|
|
+ margin-top: 40px;
|
|
|
+ text-align: center;
|
|
|
+ font-weight: 700;
|
|
|
+}
|
|
|
+.red-packet-tip {
|
|
|
+ color: gray;
|
|
|
+ font-size: 12px;
|
|
|
+ margin-top: 100px;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+.cover-preview {
|
|
|
+ position: relative;
|
|
|
+ float: right;
|
|
|
+ height: 20px;
|
|
|
+}
|
|
|
+.chatEmojiAnimationsComponent {
|
|
|
+ position: absolute;
|
|
|
+ left: 0px;
|
|
|
+ top: 0px;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ z-index: 999;
|
|
|
+}
|
|
|
</style>
|