feat: 完善聊天模块

This commit is contained in:
橙子
2024-04-06 18:28:32 +08:00
parent 43b4032bbb
commit 6aedff75f1
17 changed files with 507 additions and 110 deletions

View File

@@ -0,0 +1,18 @@
import request from "@/config/axios/service";
export function sendPersonalMessage(data) {
return request({
url: "/chat-message/personal",
method: "post",
data
});
}
export function sendGroupMessage(data) {
return request({
url: "/chat-message/group",
method: "post",
data
});
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

View File

@@ -13,7 +13,7 @@ const receiveMsg = (connection) => {
});
//接受其他用户消息
connection.on("receiveMsg", (type, content) => {
chatStore.addMsg(content);
});
//用户状态-正在输入中,无
connection.on("userStatus", (type) => {

View File

@@ -1,25 +1,28 @@
import { defineStore } from "pinia";
const chatStore = defineStore("chat", {
state: () => ({
userList: [],
msgList: []
}),
// getters: {
// userListData: (state) => state.userList,
// },
actions: {
// 设置在线总数
getters: {
allMsgContext: (state) => state.msgList.filter(x=>x.messageType=="All"),
personalMsgContext: (state) => state.msgList.filter(x=>x.messageType=="Personal"),
},
actions:
{
setMsgList(value) {
this.msgList = value;
},
addMsg(msg) {
this.msgList.push(msg);
},
setUserList(value) {
this.userList = value;
},
addUser(user)
{
addUser(user) {
this.userList.push(user);
},
delUser(userId)
{
delUser(userId) {
this.userList = this.userList.filter(obj => obj.userId != userId);
}
},

View File

@@ -1,18 +1,162 @@
<script setup>
import { onMounted, ref,computed } from 'vue';
import {storeToRefs} from 'pinia'
import {getList as getChatUserList} from '@/apis/chatUserApi'
import { onMounted, ref, computed } from 'vue';
import { storeToRefs } from 'pinia'
import { getList as getChatUserList } from '@/apis/chatUserApi'
import { sendPersonalMessage,sendGroupMessage } from '@/apis/chatMessageApi'
import useChatStore from "@/stores/chat";
const chatStore=useChatStore();
const {userList} =storeToRefs(chatStore);
import useUserStore from "@/stores/user";
onMounted(async()=>{
//聊天存储
const chatStore = useChatStore();
const { userList } = storeToRefs(chatStore);
//用户信息
const userStore = useUserStore();
//发送消息是否为空
const msgIsNullShow=ref(false)
//当前选择用户
const currentSelectUser = ref(null);
//当前输入框的值
const currentInputValue = ref("");
//临时存储的输入框根据用户id及组name、all组为keydata为value
const inputListDataStore = ref([{ key: "all", value: "" }]);
//当前聊天框显示的消息
const currentMsgContext = computed(() => {
if (selectIsAll()) {
return chatStore.allMsgContext;
}
else {
return chatStore.personalMsgContext.filter(x => {
//两个条件
//接收用户者id为对面id我发给他
//或者发送用户id为对面他发给我
return (x.receiveId == currentSelectUser.value.userId && x.sendUserId == userStore.id)||
(x.sendUserId == currentSelectUser.value.userId && x.receiveId == userStore.id);
});
}
});
//当前聊天框显示的名称
const currentHeaderName = computed(() => {
return currentSelectUser.value == null ? "官方学习交流群" : currentSelectUser.value.userName;
});
const currentUserItem = computed(() => {
return userList.value.filter(x=>x.userId!=useUserStore().id)
});
//初始化
onMounted(async () => {
chatStore.setUserList((await getChatUserList()).data);
})
/*-----方法-----*/
//当前选择的是否为全部
const selectIsAll = () => {
return currentSelectUser.value == null;
};
//输入框的值被更改
const changeInputValue = (inputValue) => {
currentInputValue.value = inputValue;
let index = -1;
let findKey = currentSelectUser.value?.userId
if (selectIsAll()) {
findKey = 'all'
}
index = inputListDataStore.value.findIndex(obj => obj.key == findKey);
inputListDataStore.value[index].value = currentInputValue.value;
}
//绑定的input改变事件
const updateInputValue = (event) => {
changeInputValue(event.target.value);
}
//获取输入框的值
const getCurrentInputValue = () => {
if (selectIsAll()) {
return inputListDataStore.value.filter(x => x.key == "all")[0].value;
} else {
//如果不存在初始存储值
if (!inputListDataStore.value.some(x => x.key == currentSelectUser.value.userId)) {
inputListDataStore.value.push({ key: currentSelectUser.value.userId, value: "" });
return "";
}
return inputListDataStore.value.filter(x => x.key == currentSelectUser.value.userId)[0].value;
}
};
//点击用户列表,
const onclickUserItem = (userInfo, isAllItem) => {
if (isAllItem) {
currentSelectUser.value = null;
}
else {
currentSelectUser.value = userInfo;
}
//填充临时存储的输入框
var value = getCurrentInputValue();
//更新当前的输入框
changeInputValue(value);
}
//点击发送按钮
const onclickSendMsg = () => {
console.log(currentInputValue.value ,"currentInputValue.value");
if(currentInputValue.value=="")
{
msgIsNullShow.value=true;
setTimeout(() => {
// 这里写上你想要3秒后执行的代码
msgIsNullShow.value=false;
}, 3000);
return;
}
if (selectIsAll()) {
onclickSendGroupMsg("all", currentInputValue.value);
}
else {
onclickSendPersonalMsg(currentSelectUser.value.userId, currentInputValue.value);
}
changeInputValue("");
}
//点击发送个人消息
const onclickSendPersonalMsg = (receiveId, msg) => {
//添加到本地存储
chatStore.addMsg({
messageType: "Personal",
sendUserId: userStore.id,
content: msg,
receiveId: receiveId
});
sendPersonalMessage({userId:receiveId,content:msg});
//调用接口发送消息
}
//点击发送群组消息按钮
const onclickSendGroupMsg = (groupName, msg) => {
//组还需区分是否给全部成员组
if (selectIsAll) {
//添加到本地存储,不需要,因为广播自己能够接收
// chatStore.addMsg({
// messageType: "All",
// sendUserId: userStore.id,
// content: msg
// });
//调用接口发送消息
sendGroupMessage({content:msg});
}
else {
alert("暂未实现");
}
}
</script>
<template>
<div class="body">
<div class="left">
<div class="icon">
@@ -47,9 +191,10 @@ onMounted(async()=>{
</div>
</div>
<div class="user-list">
<div class="user-div" style="background-color: #C8C8CA;">
<div class="user-div" @click="onclickUserItem(null, true)"
:class="{ 'select-user-item': currentSelectUser == null }">
<div class="user-div-left">
<img src="@/assets/chat_images/friendicon.jpg" />
<img src="@/assets/chat_images/yilogo.png" />
<div class="user-name-msg">
<p class="font-name">官方学习交流群</p>
<p class="font-msg">冲冲冲</p>
@@ -62,11 +207,12 @@ onMounted(async()=>{
</div>
<div v-for="(item,i) in userList" :key="i" class="user-div">
<div v-for="(item, i) in currentUserItem" :key="i" @click="onclickUserItem(item, false)" class="user-div"
:class="{ 'select-user-item': currentSelectUser?.userId == item.userId }">
<div class="user-div-left">
<img src="@/assets/chat_images/friendicon.jpg" />
<div class="user-name-msg">
<p class="font-name">{{item.userName}}</p>
<p class="font-name">{{ item.userName }}</p>
<p class="font-msg">现在感觉怎么样</p>
</div>
</div>
@@ -79,7 +225,7 @@ onMounted(async()=>{
<div class="right">
<div class="header">
<div class="header-left">橙子</div>
<div class="header-left">{{ currentHeaderName }}</div>
<div class="header-right">
<div>
<ul>
@@ -96,48 +242,53 @@ onMounted(async()=>{
</div>
<div class="content">
<div v-for="i in 100" :key="i">
<div class="content-others content-common">
<img src="@/assets/chat_images/friendicon.jpg" />
<div class="content-others-msg content-msg-common ">感觉还可以</div>
</div>
<div class="content-myself content-common">
<div class="content-myself-msg content-msg-common ">现在感觉怎么样</div>
<div v-for="(item, i) in currentMsgContext" :key="i">
<div class="content-myself content-common" v-if="item.sendUserId == userStore.id">
<div class="content-myself-msg content-msg-common ">{{ item.content }}</div>
<img src="@/assets/chat_images/icon.jpg" />
</div>
<div class="content-others content-common" v-else>
<img src="@/assets/chat_images/friendicon.jpg" />
<div class="content-others-msg content-msg-common ">{{ item.content }}</div>
</div>
</div>
</div>
<div class="bottom">
<div class="bottom-tool">
<ul class="ul-left">
<li><img src="@/assets/chat_images/emoji.png" /></li>
<li><img src="@/assets/chat_images/sendFile.png" /></li>
<li><img src="@/assets/chat_images/screenshot.png" /></li>
<li><img src="@/assets/chat_images/chatHistory.png" /></li>
</ul>
<ul class="ul-left">
<li><img src="@/assets/chat_images/emoji.png" /></li>
<li><img src="@/assets/chat_images/sendFile.png" /></li>
<li><img src="@/assets/chat_images/screenshot.png" /></li>
<li><img src="@/assets/chat_images/chatHistory.png" /></li>
</ul>
<ul class="ul-right">
<li><img src="@/assets/chat_images/landline.png" /></li>
<li><img src="@/assets/chat_images/videoChat.png" /></li>
</ul>
</div>
<div class="bottom-input" contenteditable="true">
<ul class="ul-right">
<li><img src="@/assets/chat_images/landline.png" /></li>
<li><img src="@/assets/chat_images/videoChat.png" /></li>
</ul>
</div>
</div>
<!-- <div class="bottom-input" contenteditable="true" @input="updateInputValue"> -->
<!-- <div class="bottom-input" contenteditable="true" @input="updateInputValue">
<div class="bottom-send">
<button>
发送(S)
</button>
</div> -->
<textarea class="bottom-input" v-model="currentInputValue" @input="updateInputValue" @keyup.enter="onclickSendMsg()">
</textarea>
<div class="bottom-send">
<div class="msg-null" v-show="msgIsNullShow">不能发送空白信息</div>
<button @click="onclickSendMsg()">
发送(S)
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<style scoped lang="scss">
.body {
@@ -148,6 +299,10 @@ onMounted(async()=>{
box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.2);
}
.select-user-item {
background-color: #C8C8CA !important;
}
.left {
background-color: #2a2a2a;
width: 70px;
@@ -344,46 +499,52 @@ onMounted(async()=>{
&-tool {
display: flex;
justify-content: space-between;
justify-content: space-between;
height: 22px;
.ul-left {
display: flex;
display: flex;
li {
width: 22px;
height: 22px;
margin-right: 20px;
}
img {
width: 100%;
height: 100%;
}
li {
width: 22px;
height: 22px;
margin-right: 20px;
}
.ul-right {
display: flex;
li {
width: 22px;
height: 22px;
margin-right: 20px;
}
img {
width: 100%;
height: 100%;
}
img {
width: 100%;
height: 100%;
}
}
.ul-right {
display: flex;
li {
width: 22px;
height: 22px;
margin-right: 20px;
}
img {
width: 100%;
height: 100%;
}
}
}
&-input {
font-family: "Microsoft YaHei", sans-serif;
height: 70px;
width: 100%;
overflow-y: auto;
padding: 10px 0;
font-size: 18px;
background: #F7F7F7;
border: none;
resize: none;
outline: none;
}
&-send {
@@ -445,6 +606,7 @@ onMounted(async()=>{
.content-common {
display: flex;
margin-bottom: 18px;
img {
height: 45px;
@@ -526,5 +688,34 @@ onMounted(async()=>{
border-bottom: 10px solid transparent;
border-right: 10px solid #FFFFFF;
}
.msg-null{
width: 140px;
height: 41px;
background-color: #FFFFFF;
position: relative;
left: 132px;
bottom: 60px;
border-radius: 5px;
// border: 2px solid #E5E5E5;
display: flex;
align-content: center;
justify-content: center;
flex-wrap: wrap;
font-size: 14px;
}
.msg-null:after {
/* 箭头靠下边 */
content: "";
position: absolute;
width: 0;
height: 0;
top: 40px;
left: 80px;
border-top: 10px solid #FFFFFF;
border-bottom: 10px solid transparent;
border-right: 10px solid transparent;
border-left: 10px solid transparent;
}
</style>