2
This commit is contained in:
parent
ad4672e49c
commit
c231ed0832
@ -120,5 +120,10 @@
|
||||
"keywords": "China National Heavy Duty Truck Group (CNHTC) HOWO, HOWO Trucks, Heavy Truck Products, Heavy duty Trucks, Commercial Vehicles, HOWO Models, CNHTC Products, HOWO Truck Series, Large Trucks, Commercial Vehicle Products",
|
||||
"description": "China National Heavy Duty Truck Group Co., Ltd. provides a rich range of HOWO truck products, including various models and configurations. Understand the performance, technical specifications, and industry advantages of our heavy-duty trucks to meet your procurement needs."
|
||||
}
|
||||
},
|
||||
"chat": {
|
||||
"title": "Online Service",
|
||||
"description": "Please enter your question... Press Enter to send.",
|
||||
"littleTitle": "Hello! It's a pleasure to assist you. How may I help you?"
|
||||
}
|
||||
}
|
@ -120,5 +120,10 @@
|
||||
"keywords": "中国重汽豪沃, 豪沃卡车, 重卡产品, 重型卡车, 商用车, 豪沃车型, 重汽产品, 豪沃卡车系列, 大型卡车, 商用车产品",
|
||||
"description": "中国重汽豪沃销售有限公司提供丰富的豪沃卡车产品系列,包括各种车型和配置。了解我们的重型卡车性能、技术参数及行业优势,满足您的采购需求。"
|
||||
}
|
||||
},
|
||||
"chat": {
|
||||
"title": "在线客服",
|
||||
"description": "请输入您的问题...按Enter发送",
|
||||
"littleTitle": "您好!很高兴为您服务,请问有什么可以帮您?"
|
||||
}
|
||||
}
|
@ -1,54 +1,54 @@
|
||||
<template>
|
||||
<!-- 选择产品对话框 -->
|
||||
<el-dialog :title="title" :visible.sync="open" @close="close" width="800px" append-to-body>
|
||||
<el-card style="height: 600px">
|
||||
<el-container class="AddressBook-container">
|
||||
<el-header class="AddressBook-header" style="height: 30px">
|
||||
<span></span>
|
||||
<!-- <span style="margin-left: 500px">当前在线人数:{{count.split(',')[1]}}</span>-->
|
||||
</el-header>
|
||||
<el-container>
|
||||
<el-container>
|
||||
<el-main class="AddressBook-main">
|
||||
<el-row style="margin-top: 20px" v-for="item in message" :key="item.createTime">
|
||||
<el-row v-if="item.dataFrom==='customer'" type="flex" justify="end">
|
||||
<el-col :span="8">
|
||||
<el-card shadow="always" :style="'item.dataFrom===customer'?'':'background-color: greenyellow;'">
|
||||
{{ item.content }}
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="2">
|
||||
<el-avatar shape="square" size="medium" icon="el-icon-user-solid"
|
||||
style="margin-left: 5px"></el-avatar>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row v-else type="flex" justify="start">
|
||||
<el-col :span="2">
|
||||
<el-avatar shape="square" size="medium" icon="el-icon-user-solid"
|
||||
style="margin-left: 5px"></el-avatar>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-card shadow="always" style="background-color: greenyellow">
|
||||
{{ item.content }}
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-dialog :title="$t('chat.title')" :visible.sync="open" @close="close" width="800px" append-to-body class="customer-service-dialog">
|
||||
<!-- 自定义标题栏 -->
|
||||
<div slot="header" class="dialog-header">
|
||||
<div class="service-info">
|
||||
<h3 class="service-name">{{ $t('chat.title') }}</h3>
|
||||
</div>
|
||||
<button class="close-btn" @click="close" aria-label="关闭对话框">×</button>
|
||||
</div>
|
||||
<!-- 聊天内容区域 -->
|
||||
<div class="chat-container">
|
||||
<!-- 消息列表(内部滚动) -->
|
||||
<div class="message-list-wrapper">
|
||||
<div class="message-list" ref="messageList">
|
||||
<!-- 系统欢迎消息 -->
|
||||
<div v-if="message.length === 0" class="system-message">
|
||||
{{ $t('chat.littleTitle') }}
|
||||
</div>
|
||||
|
||||
</el-row>
|
||||
</el-row>
|
||||
</el-main>
|
||||
<el-footer class="uesrtext" style="height:150px">
|
||||
<!-- 消息项 -->
|
||||
<div
|
||||
v-for="(msg, index) in message"
|
||||
:key="index"
|
||||
:class="['message-item', msg.dataFrom=='customer' ? 'self-message' : 'other-message']"
|
||||
>
|
||||
<div class="message-content">
|
||||
<div class="message-text">{{ msg.content }}</div>
|
||||
<div class="message-time">{{ formatTime(msg.createTime) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-input type="textarea"
|
||||
class="inputT"
|
||||
placeholder="按 Enter 发送" v-model="text"
|
||||
@keyup.enter.native="sendToServer"
|
||||
></el-input>
|
||||
<el-button type="primary" icon="el-icon-s-promotion" @click="sendToServer"></el-button>
|
||||
</el-footer>
|
||||
</el-container>
|
||||
</el-container>
|
||||
</el-container>
|
||||
</el-card>
|
||||
<!-- 输入区域 -->
|
||||
<div class="input-area">
|
||||
<textarea
|
||||
v-model="text"
|
||||
class="message-input"
|
||||
:placeholder="$t('chat.description')"
|
||||
@keydown.enter="handleEnterKey"
|
||||
:disabled="isInputDisabled"
|
||||
></textarea>
|
||||
<el-button type="primary"
|
||||
icon="el-icon-s-promotion"
|
||||
@click="sendToServer"
|
||||
:disabled="!text.trim() || isInputDisabled"
|
||||
>
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
@ -62,7 +62,7 @@ export default {
|
||||
// 设备唯一码
|
||||
deviceCode: null,
|
||||
open: false,
|
||||
title: null,
|
||||
isInputDisabled: false,
|
||||
// 消息集合
|
||||
message: [],
|
||||
// 会话ID
|
||||
@ -70,7 +70,7 @@ export default {
|
||||
// 客服ID
|
||||
serviceId: null,
|
||||
// 发送消息内容
|
||||
text: null,
|
||||
text: '',
|
||||
// 产品id
|
||||
productId: '',
|
||||
// 设备类型
|
||||
@ -80,154 +80,212 @@ export default {
|
||||
|
||||
beforeDestroy() {
|
||||
// 离开页面生命周期函数
|
||||
this.$store.dispatch('modules/websocket/websocket_close')
|
||||
this.closeWebSocket();
|
||||
},
|
||||
|
||||
watch: {
|
||||
message(val) {
|
||||
this.scrollBottom()
|
||||
message: {
|
||||
handler(newVal) {
|
||||
// 特别处理最后一个消息 type=3 的情况
|
||||
if (newVal && newVal.length > 0) {
|
||||
const lastMessage = newVal[newVal.length - 1];
|
||||
this.isInputDisabled = lastMessage.type && lastMessage.type === 3;
|
||||
}
|
||||
this.scrollBottom();
|
||||
},
|
||||
deep: true,
|
||||
immediate: false
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
mounted() {
|
||||
// 可以在这里添加初始化逻辑
|
||||
},
|
||||
|
||||
methods: {
|
||||
/**
|
||||
* 处理键盘回车事件
|
||||
* @param {Event} event - 键盘事件对象
|
||||
*/
|
||||
handleEnterKey(event) {
|
||||
// 如果按下 Shift+Enter,则允许换行
|
||||
if (event.shiftKey) {
|
||||
return; // 不阻止默认行为,允许换行
|
||||
}
|
||||
|
||||
/**用户列表*/
|
||||
getUserList() {
|
||||
|
||||
// 只按下 Enter,发送消息
|
||||
event.preventDefault();
|
||||
this.sendToServer();
|
||||
},
|
||||
/**
|
||||
* 显示聊天对话框组件
|
||||
* @param {string} id - 产品ID
|
||||
*/
|
||||
show(id) {
|
||||
this.open = true;
|
||||
this.productId = id;
|
||||
this.getChatMain();
|
||||
},
|
||||
|
||||
/**
|
||||
* 组件显示
|
||||
* 获取聊天主信息,包括设备指纹、WebSocket连接和聊天会话
|
||||
*/
|
||||
show(id) {
|
||||
this.open = true
|
||||
this.productId = id
|
||||
this.getChatMain()
|
||||
},
|
||||
|
||||
/**获取原有聊天记录*/
|
||||
getChatMain() {
|
||||
async getChatMain() {
|
||||
try {
|
||||
// 获取当前浏览器唯一id
|
||||
const components = await new Promise((resolve) => {
|
||||
Fingerprint2.get((components) => {
|
||||
resolve(components);
|
||||
});
|
||||
});
|
||||
|
||||
const values = components.map((component) => component.value);
|
||||
this.deviceCode = Fingerprint2.x64hash128(values.join(''), 31);
|
||||
|
||||
const userAgent = navigator.userAgent || navigator.vendor || window.opera;
|
||||
// 简单判断是否为手机端
|
||||
if (/android|webos|iphone|ipod|BlackBerry|iemobile|opera mini/i.test(userAgent.toLowerCase())) {
|
||||
this.equipment = '手机端';
|
||||
} else {
|
||||
this.equipment = 'pc端';
|
||||
}
|
||||
const websocketUrl = process.env.NUXT_ENV.VUE_APP_WEBSOCKET+`${this.deviceCode}`;
|
||||
// 调用Vuex dispatch,初始化WebSocket
|
||||
this.$store.dispatch('modules/websocket/websocket_init', websocketUrl)
|
||||
.then(() => {
|
||||
console.log('WebSocket 初始化成功');
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('WebSocket 初始化失败:', err);
|
||||
});
|
||||
// 这里使用箭头函数,确保 `this` 指向当前 Vue 实例
|
||||
this.$axios.$get('/chat/active?deviceCode='+this.deviceCode+'&prodId='+this.productId).then((res) => {
|
||||
if (null!=res && res.id != null) {
|
||||
//有活跃的聊天
|
||||
this.sessionId = res.id
|
||||
this.serviceId = res.userId
|
||||
//加载消息内容
|
||||
this.loadMessages()
|
||||
this.equipment = /android|webos|iphone|ipod|BlackBerry|iemobile|opera mini/i
|
||||
.test(userAgent.toLowerCase()) ? '手机端' : 'pc端';
|
||||
|
||||
// if (this.chatMain.jsonArray != null){
|
||||
// this.message = this.chatMain.jsonArray
|
||||
// this.$store.dispatch('modules/websocket/set_message',this.chatMain.jsonArray);
|
||||
// }
|
||||
const websocketUrl = `${process.env.NUXT_ENV.VUE_APP_WEBSOCKET}${this.deviceCode}`;
|
||||
|
||||
// 调用Vuex dispatch,初始化WebSocket
|
||||
await this.$store.dispatch('modules/websocket/websocket_init', websocketUrl);
|
||||
console.log('WebSocket 初始化成功');
|
||||
|
||||
// 获取活跃聊天
|
||||
const res = await this.$axios.$get(`/chat/active?deviceCode=${this.deviceCode}&prodId=${this.productId}`);
|
||||
|
||||
if (res && res.id != null) {
|
||||
// 有活跃的聊天
|
||||
this.sessionId = res.id;
|
||||
this.serviceId = res.userId;
|
||||
// 加载消息内容
|
||||
await this.loadMessages();
|
||||
} else {
|
||||
// 没有,创建新的消息对话
|
||||
this.createNewSession()
|
||||
await this.createNewSession();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('初始化聊天失败:', error);
|
||||
}
|
||||
}).catch(error => {
|
||||
console.error('请求错误:', error);
|
||||
});
|
||||
});
|
||||
},
|
||||
//加载消息内容
|
||||
loadMessages(){
|
||||
this.$axios.$get('/chat/session/'+this.sessionId).then((res) => {
|
||||
this.message = res
|
||||
|
||||
/**
|
||||
* 加载指定会话的消息内容
|
||||
*/
|
||||
async loadMessages() {
|
||||
try {
|
||||
const res = await this.$axios.$get(`/chat/session/${this.sessionId}`);
|
||||
this.message = res;
|
||||
this.$store.dispatch('modules/websocket/set_message', res);
|
||||
this.scrollBottom()
|
||||
}).catch(error => {
|
||||
console.error('连接客服失败,请稍后再试:', error);
|
||||
});
|
||||
this.scrollBottom();
|
||||
} catch (error) {
|
||||
console.error('加载消息失败:', error);
|
||||
}
|
||||
},
|
||||
createNewSession() {
|
||||
/**
|
||||
* 创建新的聊天会话
|
||||
*/
|
||||
async createNewSession() {
|
||||
try {
|
||||
const session = {
|
||||
cusCode: this.deviceCode,
|
||||
equipment: this.equipment,
|
||||
prodId: this.productId
|
||||
}
|
||||
this.$axios.$post('/chat/newChat', session).then((res) => {
|
||||
this.sessionId = res.id
|
||||
this.serviceId = res.userId
|
||||
};
|
||||
|
||||
const res = await this.$axios.$post('/chat/newChat', session);
|
||||
this.sessionId = res.id;
|
||||
this.serviceId = res.userId;
|
||||
|
||||
// 发个消息,通知客服建立会话关系
|
||||
const wsMsg = {
|
||||
type: 2,
|
||||
type: 2,// 2-建立会话关系
|
||||
toUserId: this.serviceId,
|
||||
sessionId: this.sessionId,
|
||||
fromUserId: this.deviceCode
|
||||
}
|
||||
};
|
||||
|
||||
this.$store.dispatch('modules/websocket/websocket_send', JSON.stringify(wsMsg));
|
||||
}).catch(error => {
|
||||
console.error('连接客服失败,请稍后再试:', error);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('创建新会话失败:', error);
|
||||
}
|
||||
},
|
||||
|
||||
/**弹窗关闭方法*/
|
||||
/**
|
||||
* 关闭聊天对话框
|
||||
*/
|
||||
close() {
|
||||
this.$store.dispatch('modules/websocket/websocket_close')
|
||||
// let data = {
|
||||
// id:this.chatMain.id,
|
||||
// jsonArray:this.message
|
||||
// }
|
||||
//关闭时将消息保存到数据库
|
||||
this.$axios.$post('/web/saveMessage', data).then((res)=>{
|
||||
console.log(res)
|
||||
})
|
||||
this.resetChat();
|
||||
this.open = false;
|
||||
},
|
||||
|
||||
/**发送消息*/
|
||||
sendToServer() {
|
||||
/**
|
||||
* 重置聊天状态,清空所有聊天数据
|
||||
*/
|
||||
resetChat() {
|
||||
this.message = [];
|
||||
this.$store.dispatch('modules/websocket/set_message', []);
|
||||
this.closeWebSocket();
|
||||
this.isInputDisabled = false;
|
||||
this.text = '';
|
||||
this.sessionId = null;
|
||||
this.serviceId = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* 关闭WebSocket连接
|
||||
*/
|
||||
closeWebSocket() {
|
||||
this.$store.dispatch('modules/websocket/websocket_close');
|
||||
},
|
||||
|
||||
/**
|
||||
* 发送消息到服务器
|
||||
*/
|
||||
async sendToServer() {
|
||||
// 如果没有输入内容或输入被禁用,则不发送
|
||||
if (!this.text || !this.text.trim() || this.isInputDisabled) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
// 构造消息对象
|
||||
const message = {
|
||||
mainId: this.sessionId,
|
||||
dataFrom: "customer", // 用户发送
|
||||
senderId: this.deviceCode, // 用设备编码作为用户标识
|
||||
dataFrom: "customer",
|
||||
senderId: this.deviceCode,
|
||||
receiverId: this.serviceId,
|
||||
content: this.text,
|
||||
}
|
||||
this.$axios.$post('/chat/newMes', message).then((res) => {
|
||||
};
|
||||
|
||||
await this.$axios.$post('/chat/newMes', message);
|
||||
|
||||
// 成功后再通过WebSocket实时发送给客服
|
||||
const wsMsg = {
|
||||
type: 1,
|
||||
type: 1,// 1-普通消息
|
||||
toUserId: this.serviceId,
|
||||
content: this.text,
|
||||
sessionId: this.sessionId,
|
||||
fromUserId: this.deviceCode
|
||||
}
|
||||
};
|
||||
|
||||
this.$store.dispatch('modules/websocket/websocket_send', JSON.stringify(wsMsg));
|
||||
this.addMyMsg()
|
||||
this.scrollBottom()
|
||||
}).catch(error => {
|
||||
console.error('消息发送失败,请关闭聊天窗口稍后再试:', error);
|
||||
});
|
||||
this.addMyMsg();
|
||||
this.scrollBottom();
|
||||
} catch (error) {
|
||||
console.error('消息发送失败:', error);
|
||||
}
|
||||
},
|
||||
//把自己发的消息添加的消息列表中
|
||||
|
||||
/**
|
||||
* 将自己发送的消息添加到消息列表中
|
||||
*/
|
||||
addMyMsg() {
|
||||
let newMsg = {
|
||||
id: new Date().getTime(), // 临时ID,实际应该从消息中获取
|
||||
const newMsg = {
|
||||
id: new Date().getTime(),
|
||||
mainId: this.sessionId,
|
||||
dataFrom: "customer", // 用户发送
|
||||
dataFrom: "customer",
|
||||
senderId: this.deviceCode,
|
||||
receiverId: this.serviceId,
|
||||
content: this.text,
|
||||
@ -240,8 +298,9 @@ watch:{
|
||||
second: '2-digit',
|
||||
hour12: false
|
||||
}).replace(/\//g, '-'),
|
||||
isRead: 1 // 已读
|
||||
}
|
||||
isRead: 1
|
||||
};
|
||||
|
||||
// 创建新的数组而不是直接修改原数组
|
||||
const updatedMessages = [...this.message, newMsg];
|
||||
this.$store.dispatch('modules/websocket/set_message', updatedMessages);
|
||||
@ -250,90 +309,358 @@ watch:{
|
||||
this.message = updatedMessages;
|
||||
this.text = '';
|
||||
},
|
||||
/**
|
||||
* 滚动消息列表到底部
|
||||
*/
|
||||
scrollBottom() {
|
||||
// 确保在对话框打开后滚动到底部
|
||||
this.$nextTick(() => {
|
||||
const chatBox = this.$el.querySelector('.AddressBook-main');
|
||||
if (chatBox) {
|
||||
chatBox.scrollTop = chatBox.scrollHeight;
|
||||
const messageList = this.$refs.messageList;
|
||||
if (messageList) {
|
||||
messageList.scrollTop = messageList.scrollHeight;
|
||||
}
|
||||
});
|
||||
},
|
||||
/**
|
||||
* 格式化时间显示
|
||||
* @param {string|number} time - 时间戳或时间字符串
|
||||
* @returns {string} 格式化后的时间字符串 HH:mm
|
||||
*/
|
||||
formatTime(time) {
|
||||
if (!time) return '';
|
||||
|
||||
try {
|
||||
const date = new Date(time);
|
||||
if (isNaN(date.getTime())) return ''; // 检查日期是否有效
|
||||
|
||||
return `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`;
|
||||
} catch (error) {
|
||||
console.error('时间格式化错误:', error);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
<style scoped>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
.el-card {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
|
||||
.customer-service-dialog {
|
||||
--primary-color: #409eff;
|
||||
--primary-light: #e8f3ff;
|
||||
--primary-dark: #337ecc;
|
||||
--bg-color: #f7f9fc;
|
||||
--text-color: #303133;
|
||||
--text-light: #909399;
|
||||
--border-radius: 12px;
|
||||
--shadow: 0 2px 10px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.AddressBook-container {
|
||||
/* 标题栏样式 */
|
||||
.dialog-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 16px 20px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.service-info {
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.service-name {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--text-color);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.service-status {
|
||||
font-size: 12px;
|
||||
color: var(--text-light);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.online-indicator {
|
||||
display: inline-block;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background-color: #52c41a;
|
||||
box-shadow: 0 0 0 3px rgba(82, 196, 26, 0.15);
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 18px;
|
||||
color: var(--text-light);
|
||||
cursor: pointer;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.close-btn:hover {
|
||||
background-color: var(--bg-color);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
/* 聊天容器 */
|
||||
.chat-container {
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 550px;
|
||||
background-color: var(--bg-color);
|
||||
}
|
||||
|
||||
/* 消息列表容器 */
|
||||
.message-list-wrapper {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 消息列表(内部滚动) */
|
||||
.message-list {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
border: 1px solid #909399;
|
||||
overflow-y: auto;
|
||||
padding: 20px;
|
||||
scroll-behavior: smooth;
|
||||
background-color: var(--bg-color);
|
||||
background-image:
|
||||
radial-gradient(var(--primary-color) 0.5px, transparent 0.5px),
|
||||
radial-gradient(var(--primary-color) 0.5px, var(--bg-color) 0.5px);
|
||||
background-size: 20px 20px;
|
||||
background-position: 0 0, 10px 10px;
|
||||
background-attachment: local;
|
||||
}
|
||||
|
||||
/* 自定义滚动条 */
|
||||
.message-list::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.message-list::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.message-list::-webkit-scrollbar-thumb {
|
||||
background-color: rgba(150, 150, 150, 0.3);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.AddressBook-header {
|
||||
background-color: #0b60b5;
|
||||
color: #d3dce6;
|
||||
display: flex;
|
||||
.message-list::-webkit-scrollbar-thumb:hover {
|
||||
background-color: rgba(150, 150, 150, 0.5);
|
||||
}
|
||||
|
||||
/* 系统消息 */
|
||||
.system-message {
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
color: var(--text-light);
|
||||
background-color: rgba(255, 255, 255, 0.85);
|
||||
padding: 6px 14px;
|
||||
border-radius: 14px;
|
||||
margin: 0 auto 20px;
|
||||
display: inline-block;
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
/* 消息项 */
|
||||
.message-item {
|
||||
margin-bottom: 18px;
|
||||
max-width: 70%;
|
||||
display: inline-block;
|
||||
animation: fadeIn 0.3s ease-out;
|
||||
}
|
||||
|
||||
.self-message {
|
||||
float: right;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.other-message {
|
||||
float: left;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.message-content {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.message-text {
|
||||
padding: 12px 16px;
|
||||
border-radius: var(--border-radius);
|
||||
line-height: 1.6;
|
||||
word-wrap: break-word;
|
||||
max-width: 100%;
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
/* 消息气泡样式 */
|
||||
.self-message .message-text {
|
||||
background-color: var(--primary-color);
|
||||
color: #fff;
|
||||
border-top-right-radius: 4px;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.self-message .message-text:hover {
|
||||
background-color: var(--primary-dark);
|
||||
}
|
||||
|
||||
.other-message .message-text {
|
||||
background-color: #fff;
|
||||
color: var(--text-color);
|
||||
border-top-left-radius: 4px;
|
||||
transition: box-shadow 0.2s;
|
||||
}
|
||||
|
||||
.other-message .message-text:hover {
|
||||
box-shadow: 0 3px 12px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
/* 消息时间 */
|
||||
.message-time {
|
||||
font-size: 11px;
|
||||
color: var(--text-light);
|
||||
margin-top: 5px;
|
||||
text-align: right;
|
||||
white-space: nowrap;
|
||||
opacity: 0.8;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
|
||||
.message-item:hover .message-time {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.other-message .message-time {
|
||||
text-align: left;
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
/* 正在输入指示器 */
|
||||
.typing-indicator {
|
||||
margin-bottom: 18px;
|
||||
max-width: 70%;
|
||||
float: left;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.typing-dots {
|
||||
background-color: #fff;
|
||||
padding: 12px 16px;
|
||||
border-radius: var(--border-radius);
|
||||
border-top-left-radius: 4px;
|
||||
box-shadow: var(--shadow);
|
||||
display: inline-flex;
|
||||
gap: 6px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.AddressBook-main {
|
||||
height: 380px;
|
||||
background-color: #DCDFE6;
|
||||
|
||||
.typing-dots span {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background-color: var(--text-light);
|
||||
border-radius: 50%;
|
||||
animation: typing 1.4s infinite ease-in-out both;
|
||||
}
|
||||
|
||||
.AddressBook-aside {
|
||||
background-color: #909399;
|
||||
.typing-dots span:nth-child(1) { animation-delay: -0.32s; }
|
||||
.typing-dots span:nth-child(2) { animation-delay: -0.16s; }
|
||||
|
||||
/* 输入区域 */
|
||||
.input-area {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
padding: 15px 20px;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.userList {
|
||||
padding-top: 3px;
|
||||
box-shadow: 0px 3px 3px #888888;
|
||||
|
||||
.name {
|
||||
vertical-align: top;
|
||||
/*margin-top: 2px;*/
|
||||
margin-left: 15px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.uesrtext {
|
||||
position: relative;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-top: solid 1px #DDD;
|
||||
background-color: white;
|
||||
|
||||
.inputT {
|
||||
padding-top: 10px;
|
||||
width: 100%;
|
||||
height: 200%;
|
||||
border: none;
|
||||
.message-input {
|
||||
flex: 1;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: var(--border-radius);
|
||||
padding: 12px 15px;
|
||||
min-height: 42px;
|
||||
max-height: 120px;
|
||||
resize: vertical;
|
||||
outline: none;
|
||||
transition: all 0.2s;
|
||||
font-family: inherit;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.el-button {
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
right: 10px;
|
||||
.message-input:focus {
|
||||
border-color: var(--primary-color);
|
||||
box-shadow: 0 0 0 3px var(--primary-light);
|
||||
}
|
||||
|
||||
.message-input:disabled {
|
||||
background-color: #f5f5f5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
/* 发送按钮 */
|
||||
.send-button {
|
||||
background-color: var(--primary-color);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: var(--border-radius);
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.send-button:hover {
|
||||
background-color: var(--primary-dark);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.send-button:active {
|
||||
transform: translateY(1px);
|
||||
}
|
||||
|
||||
.send-button:disabled {
|
||||
background-color: #b3d8ff;
|
||||
cursor: not-allowed;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
/* 动画效果 */
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.message-avatar {
|
||||
|
||||
@keyframes typing {
|
||||
0% { transform: scale(0); }
|
||||
40% { transform: scale(1); }
|
||||
80% { transform: scale(0); }
|
||||
100% { transform: scale(0); }
|
||||
}
|
||||
</style>
|
@ -14,7 +14,20 @@ export const mutations = {
|
||||
state.socket.onopen=function () {
|
||||
console.log("WebSocket连接成功");
|
||||
};
|
||||
// 注意:这里不再直接处理 onmessage,而是在 action 中处理
|
||||
state.socket.onmessage = function (e) {
|
||||
console.log(e,'接收到的消息')
|
||||
if (e.data.startsWith("C")) {
|
||||
state.count = e.data;
|
||||
}
|
||||
else if (e.data.startsWith("系统通知")){
|
||||
state.notices.push(e.data);
|
||||
}else if (e.data.startsWith("close")){
|
||||
console.log(e.data)
|
||||
} else {
|
||||
state.messages.push(JSON.parse(e.data));
|
||||
console.log(state.messages);
|
||||
}
|
||||
};
|
||||
state.socket.onerror= function () {
|
||||
console.log("WebSocket连接发生错误");
|
||||
};
|
||||
@ -22,77 +35,31 @@ export const mutations = {
|
||||
console.log("connection closed (" + e.code + ")");
|
||||
};
|
||||
},
|
||||
|
||||
SET_SOCKET_ONMESSAGE(state, handler) {
|
||||
// 设置 WebSocket 的消息处理函数
|
||||
if (state.socket) {
|
||||
state.socket.onmessage = handler;
|
||||
}
|
||||
},
|
||||
|
||||
WEBSOCKET_SEND(state,msg){
|
||||
if (state.socket) {
|
||||
state.socket.send(msg);
|
||||
}
|
||||
},
|
||||
|
||||
WEBSOCKET_CLOSE(state){
|
||||
if (state.socket) {
|
||||
state.socket.close();
|
||||
state.socket = null;
|
||||
}
|
||||
},
|
||||
|
||||
SET_MESSAGE(state,msg){
|
||||
state.messages = msg;
|
||||
},
|
||||
|
||||
ADD_MESSAGE(state, message) {
|
||||
// 使用展开运算符创建新数组而不是直接 push
|
||||
state.messages = [...state.messages, message];
|
||||
},
|
||||
|
||||
ADD_NOTICE(state, notice) {
|
||||
// 使用展开运算符创建新数组而不是直接 push
|
||||
state.notices = [...state.notices, notice];
|
||||
},
|
||||
|
||||
SET_COUNT(state, count) {
|
||||
state.count = count;
|
||||
state.messages = msg
|
||||
}
|
||||
}
|
||||
|
||||
export const actions = {
|
||||
websocket_init({ commit, state }, url) {
|
||||
commit('WEBSOCKET_INIT', url);
|
||||
|
||||
// 在 action 中设置 WebSocket 的 onmessage 回调
|
||||
if (state.socket) {
|
||||
state.socket.onmessage = function(e) {
|
||||
console.log(e, '接收到的消息');
|
||||
if (e.data.startsWith("C")) {
|
||||
commit('SET_COUNT', e.data);
|
||||
} else if (e.data.startsWith("系统通知")) {
|
||||
commit('ADD_NOTICE', e.data);
|
||||
} else if (e.data.startsWith("close")) {
|
||||
console.log(e.data);
|
||||
} else {
|
||||
commit('ADD_MESSAGE', JSON.parse(e.data));
|
||||
console.log(state.messages);
|
||||
}
|
||||
};
|
||||
}
|
||||
websocket_init({commit}, url) {
|
||||
commit('WEBSOCKET_INIT', url)
|
||||
},
|
||||
|
||||
websocket_send({commit}, msg) {
|
||||
commit('WEBSOCKET_SEND', msg);
|
||||
commit('WEBSOCKET_SEND', msg)
|
||||
},
|
||||
|
||||
websocket_close({commit}){
|
||||
commit('WEBSOCKET_CLOSE');
|
||||
commit('WEBSOCKET_CLOSE')
|
||||
},
|
||||
|
||||
set_message({commit},msg){
|
||||
commit('SET_MESSAGE', msg);
|
||||
commit('SET_MESSAGE',msg)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user