video_ca/src/views/Chat.vue

385 lines
14 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<el-container class="layout-container-demo" style="height: 700px;width: 1000px;">
<el-aside width="200px">
<el-scrollbar>
<el-menu :default-openeds="['1', '3']">
<el-sub-menu index="1">
<template #title>
<el-icon>
<message />
</el-icon>
</template>
<el-scrollbar height="300px">
<el-menu-item-group v-for="user in userList" :key="user.id">
<el-menu-item :index="String(user.id)" @click="handleGetMessage(user.id)" style="height: 40px;">
{{ user.email }}
</el-menu-item>
</el-menu-item-group>
</el-scrollbar>
</el-sub-menu>
<el-sub-menu index="2">
<template #title>
<el-icon><icon-menu /></el-icon>
群组
</template>
<el-scrollbar height="200px">
<el-menu-item-group v-for="item in groupList" :key="item.id">
<!-- <template #title>Group 1</template> -->
<el-menu-item :index="String(item.group_name)" @click="handleSelectGroup">{{ item.group_name
}}</el-menu-item>
<!-- <el-menu-item index="2-2">Option 2</el-menu-item> -->
</el-menu-item-group>
</el-scrollbar>
</el-sub-menu>
</el-menu>
</el-scrollbar>
</el-aside>
<el-container width="800px">
<el-header style="text-align: right; font-size: 12px">
<div class="toolbar">
<el-text class="mx-1" type="primary" style="margin-right: 10px;">{{ message }}</el-text>
<!-- 重新连接websocket按钮 -->
<ElButton type="primary" style="margin-right: 10px;" @click="reconnect()">重新连接</ElButton>
<el-dropdown>
<el-icon style="margin-right: 10px; margin-top: 1px" size="25px">
<setting />
</el-icon>
</el-dropdown>
<span @click="updateUser()" style=" margin-left: 30px; color: #12B7F5; text-decoration: underline; cursor: pointer;
">修改用户名</span>
<input type="text" v-if="isUpdate" v-model="newUserName" />
<span v-if="isUpdate" @click="makeSure">确定</span>
<div>
<span style=" margin-right: 10px;margin-left: 10px;">{{ username }}</span>
<el-avatar size="default" fit="fit"> {{ username }} </el-avatar>
</div>
</div>
</el-header>
<el-main style="margin-top: 1px;">
<el-scrollbar class="chat-room" id="chat-room" ref="chatRoom" height="600px" style="margin-top: 1px" always>
<div v-for="item in MsgList" :key="item.ID"
style="margin-top: 10px;margin-bottom: 20px;">
<!-- 左边 -->
<div v-if="uid == item.ToUserID && item.FromUserID == cur_user_id" style="margin-left: 10px;margin-bottom: 8px;">
<el-row class="row-bg" type="flex" align="middle">
<el-avatar size="default" fit="fit">{{ cur_user_name }}</el-avatar>
<span style="margin-left: 10px">{{ formatTime(item.CreatedAt) }}</span>
</el-row>
<el-row>
<el-col :span="1000" :offset="1" class="msg" >
{{ item.Msg }}
</el-col>
</el-row>
</div>
<!-- 右边 -->
<div v-if="uid == item.FromUserID && item.ToUserID == cur_user_id" style="margin-right: 10px;margin-bottom: 8px;">
<el-row class="row-bg" type="flex" justify="end" align="middle">
<span style="margin-right: 10px">{{ formatTime(item.CreatedAt)}}</span>
<el-avatar size="default" fit="fit"> {{ item.username }} </el-avatar>
</el-row>
<el-row justify="end">
<el-col :span="1000" class="msg2" style="margin-right: 20px;">
{{ item.Msg }}
</el-col>
</el-row>
</div>
</div>
</el-scrollbar>
</el-main>
<el-row class="row-bg" type="flex" justify="space-around" align="middle">
<el-col :span="20">
<el-input type="text" style="width: 100%" autofocus @keyup.enter="handleSendBtnClick"
placeholder="请输入消息按Enter发送" v-model="currentMsg"></el-input>
</el-col>
<el-col :span="2">
<el-button class="sendBtn" @click="handleSendBtnClick" type="primary" size="default">
发送
</el-button>
</el-col>
</el-row>
</el-container>
</el-container>
</template>
<script>
import axios from "axios";
import { inject } from "vue";
import { getFriendListService } from "@/api/chat.js";
import { getMessageService} from "@/api/chat.js";
import {sendMessageService} from "@/api/chat.js";
import { ElAvatar, ElDropdown, ElDropdownItem, ElDropdownMenu, ElIcon, ElMenu, ElMenuItem, ElMenuItemGroup, ElScrollbar, ElRow, ElCol, ElButton } from 'element-plus'
import { Menu as IconMenu, Message, Setting } from '@element-plus/icons-vue'
import router from "@/router/index.js";
import {ElMessage} from "element-plus";
export default {
data() {
return {
ip: "",
tableData: [],
tokenData: {
token: localStorage.getItem("token"),
ip: localStorage.getItem("ip"),
userId: localStorage.getItem("userId"),
username: localStorage.getItem("username"),
},
username: localStorage.getItem("username"),
userList: [],
to_user_id:0,
cur_user_id:0,
cur_user_name: "",
eventSource: null, // 事件源
uid: localStorage.getItem("userId"),
currentMsg:"",
MsgList: [],
groupList: [],
};
},
// methods 是一些用来更改状态与触发更新的函数
// 它们可以在模板中作为事件处理器绑定
methods: {
async handleSelectUser(){
let result = {};
try {
result = await getFriendListService(this.tokenData);
} catch (e) {
console.log(e);
}
let data = result.data;
this.userList=data.friends;
this.groupList=data.groups;
},
async handleGetMessage(id){
let result = {};
this.to_user_id=id;
this.cur_user_id=id;
console.log("uid:",this.uid,"\tcur_user_id:",this.cur_user_id)
try {
let req={
token: localStorage.getItem("token"),
ip: localStorage.getItem("ip"),
userId: localStorage.getItem("userId"),
username: localStorage.getItem("username"),
from_user_id:id,
to_user_id:localStorage.getItem("userId"),
index:2,
type:1,
}
result = await getMessageService(req);
} catch (e) {
console.log(e);
}
let data = result.data;
if(data === undefined){
ElMessage({
message: "消息获取失败!",
type: "error",
})
return;
}
//data sort by created time
for (let i = 0; i < data.length; i++) {
for (let j = i + 1; j < data.length; j++) {
if (data[i].CreatedAt > data[j].CreatedAt) {
let temp = data[i];
data[i] = data[j];
data[j] = temp;
}
}
}
this.MsgList=data;
this.scrollToBottom();
},
formatTime(time){
let date = new Date(time);
let year = date.getFullYear();
let month = date.getMonth() + 1;
let day = date.getDate();
let hour = date.getHours();
let minute = date.getMinutes();
let second = date.getSeconds();
return year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second;
},
connectSSE(){
if (!!window.EventSource) {
this.eventSource = new EventSource("https://gep.ljsea.xyz/im/sse_msg?token="+this.tokenData.token);
let this_=this
this.eventSource.onmessage = function(event) {
console.log(event.data);
let msg = JSON.parse(event.data);
if(msg.type !=="check"){
alert(msg);
this_.MsgList.push(msg);
}
};
this.eventSource.onerror = (error) => {
if (this.eventSource.readyState === EventSource.CLOSED) {
//console.log('Connection was closed by the server.');
ElMessage({
message: "连接已关闭!",
type: "error",
})
// Optionally, try to reconnect
} else {
//console.error('EventSource failed:', error);
ElMessage({
message: "连接失败!服务器无法实时推送消息!",
type: "error",
})
// Handle error
}
};
}else{
ElMessage({
message: "您的浏览器不支持SSE",
type: "error",
})
}
},
scrollToBottom() {
this.$nextTick(() => {
const scrollbar = this.$refs.chatRoom.$el.querySelector('.el-scrollbar__wrap');
if (scrollbar) {
scrollbar.scrollTop = scrollbar.scrollHeight;
}
});
},
async handleSendBtnClick(){
let result = {};
try {
let req={
token: localStorage.getItem("token"),
ip: localStorage.getItem("ip"),
userId: localStorage.getItem("userId"),
username: localStorage.getItem("username"),
from_user_id:localStorage.getItem("userId"),
to_user_id:this.to_user_id,
msg:this.currentMsg,
type:1,
}
result = await sendMessageService(req);
if(result.code !==0){
ElMessage({
message: "消息发送失败!",
type: "error",
})
}
let msg={
ID:result.Data,
FromUserID:localStorage.getItem("userId"),
ToUserID:this.to_user_id,
Msg:this.currentMsg,
CreatedAt:new Date(),
}
this.MsgList.push(msg);
this.scrollToBottom();
} catch (e) {
console.log(e);
}
this.currentMsg="";
},
async getIpClient() {
try {
const response = await axios.get("https://ipinfo.io/json");
this.ip = response.data.ip;
localStorage.setItem("ip", this.ip);
//console.log(response);
} catch (error) {
console.error(error);
}
},
handleMenuSelect(val) {
router.push(val);
},
toVideoList() {
router.push("/videoList");
},
// 修改条纹颜色
tableRowClassName({ row, rowIndex }) {
if (row.human === 1) {
return {
background: "#488aff",
};
} else {
return "";
}
},
},
// 生命周期钩子会在组件生命周期的各个不同阶段被调用
// 例如这个函数就会在组件挂载完成后被调用
async mounted() {
let now = new Date();
if (localStorage.getItem("token") === null) {
router.push("/login");
}
// console.log("mounted");
await this.getIpClient();
await this.handleSelectUser();
//this.connectSSE();
this.handleGetMessage(this.userList[0].id);
},
};
</script>
<style scoped>
.layout-container-demo .el-header {
position: relative;
/* background-color: var(--el-color-primary-light-7); */
color: var(--el-text-color-primary);
}
.layout-container-demo .el-aside {
color: var(--el-text-color-primary);
/* background: var(--el-color-primary-light-8); */
}
.layout-container-demo .el-menu {
border-right: none;
}
.layout-container-demo .el-main {
padding: 0;
}
.layout-container-demo .toolbar {
display: inline-flex;
align-items: center;
justify-content: center;
height: 100%;
right: 5px;
}
.msg {
background-color: #73d1f3;
/* box-shadow: rgba(18, 23, 45, 0.6) 0px 8px 24px; */
border-radius: 4px;
padding: 10px;
font-size: 18px;
line-height: 16px;
/* width: auto; */
/* max-width: 330px; */
margin-top: 20px;
color: white;
}
.msg2 {
background-color: #12B7F5;
/* box-shadow: rgba(18, 23, 45, 0.6) 0px 8px 24px; */
border-radius: 4px;
padding: 10px;
font-size: 18px;
line-height: 16px;
/* width: auto; */
/* max-width: 330px; */
margin-top: 20px;
color: white;
}
</style>