Files
Yi.Admin/Yi.Bbs.Vue3/src/views/chathub/Index.vue
2024-04-09 23:59:26 +08:00

797 lines
18 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.
<script setup>
import { onMounted, ref, computed, onUnmounted } from 'vue';
import { storeToRefs } from 'pinia'
import useAuths from '@/hooks/useAuths.js';
import { getList as getChatUserList } from '@/apis/chatUserApi'
import { sendPersonalMessage, sendGroupMessage, getAccountList as getChatAccountMessageList } from '@/apis/chatMessageApi'
import useChatStore from "@/stores/chat";
import useUserStore from "@/stores/user";
const { isLogin } = useAuths();
import { useRouter } from 'vue-router'
import { getUrl } from '@/utils/icon'
const router = useRouter();
//聊天存储
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)
});
var timer = null;
//初始化
onMounted(async () => {
if (!isLogin.value) {
ElMessage({
message: '该功能,请登录后使用!即将自动跳转',
type: 'warning',
})
timer = setTimeout(function () {
onclickClose();
}, 3000);
}
chatStore.setMsgList((await getChatAccountMessageList()).data);
chatStore.setUserList((await getChatUserList()).data);
})
onUnmounted(() => {
if (timer != null) {
clearInterval(timer)
}
})
/*-----方法-----*/
//当前选择的是否为全部
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 = () => {
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 onclickClose = () => {
router.push({ path: "/index" })
.then(() => {
// 重新刷新页面
location.reload()
})
}
//点击发送群组消息按钮
const onclickSendGroupMsg = (groupName, msg) => {
//组还需区分是否给全部成员组
if (selectIsAll) {
//添加到本地存储,不需要,因为广播自己能够接收
// chatStore.addMsg({
// messageType: "All",
// sendUserId: userStore.id,
// content: msg
// });
//调用接口发送消息
sendGroupMessage({ content: msg });
}
else {
alert("暂未实现");
}
}
//获取当前最后一条信息
const getLastMessage = ((receiveId, isAll) => {
if (isAll) {
return chatStore.allMsgContext[chatStore.allMsgContext.length - 1]?.content;
} else {
const messageContext = chatStore.personalMsgContext.filter(x => {
//两个条件
//接收用户者id为对面id我发给他
//或者发送用户id为对面他发给我
return (x.receiveId == receiveId && x.sendUserId == userStore.id) ||
(x.sendUserId == receiveId && x.receiveId == userStore.id);
});
return messageContext[messageContext.length - 1]?.content;
}
})
</script>
<template>
<div style="position: absolute; top: 0;left: 0;">
<p>当前版本1.1.0</p>
<p>tip:官方学习交流群每次发送消息消耗 1 钱钱</p>
<p>tip:点击聊天窗口右上角X可退出</p>
<p>1.0.0上线框架基础功能</p>
<p>1.1.0结合用户领域信息</p>
</div>
<div class="body">
<div class="left">
<div class="icon">
<img src="@/assets/chat_images/icon.jpg">
</div>
<ul class="top-icon">
<li><img src="@/assets/chat_images/wechat.png" /></li>
<li><img src="@/assets/chat_images/addressBook.png" /></li>
<li><img src="@/assets/chat_images/collection.png" /></li>
<li><img src="@/assets/chat_images/file.png" /></li>
<li><img src="@/assets/chat_images/friend.png" /></li>
<li><img src="@/assets/chat_images/line.png" /></li>
<li><img src="@/assets/chat_images/look.png" /></li>
<li><img src="@/assets/chat_images/sou.png" /></li>
</ul>
<ul class="bottom-icon">
<li><img src="@/assets/chat_images/mini.png" /></li>
<li><img src="@/assets/chat_images/phone.png" /></li>
<li><img src="@/assets/chat_images/other.png" /></li>
</ul>
</div>
<div class="middle">
<div class="header">
<div class="header-div">
<div class="search">
<img src="@/assets/chat_images/search.png" />
<span>搜索</span>
</div>
<button type="button"> <img src="@/assets/chat_images/add.png" /></button>
</div>
</div>
<div class="user-list">
<div class="user-div" @click="onclickUserItem(null, true)"
:class="{ 'select-user-item': currentSelectUser == null }">
<div class="user-div-left">
<img src="@/assets/chat_images/yilogo.png" />
<div class="user-name-msg">
<p class="font-name">官方学习交流群</p>
<p class="font-msg">{{ getLastMessage(null, true) }}</p>
</div>
</div>
<div class=" user-div-right">
10:28
</div>
</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="getUrl(item.userIcon)" />
<div class="user-name-msg">
<p class="font-name">{{ item.userName }}</p>
<p class="font-msg">{{ getLastMessage(item.userId, false) }}</p>
</div>
</div>
<div class=" user-div-right">
10:28
</div>
</div>
</div>
</div>
<div class="right">
<div class="header">
<div class="header-left">{{ currentHeaderName }}</div>
<div class="header-right">
<div>
<ul>
<li><img src="@/assets/chat_images/fixed.png" /></li>
<li><img src="@/assets/chat_images/min.png" /></li>
<li><img src="@/assets/chat_images/max.png" /></li>
<li style="cursor: pointer;" @click="onclickClose"><img src="@/assets/chat_images/close.png" /></li>
</ul>
</div>
<div class="more"><img src="@/assets/chat_images/other2.png" /></div>
</div>
</div>
<div class="content">
<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="getUrl(item.sendUserInfo?.user.icon)" />
</div>
<div class="content-others content-common" v-else>
<img :src="getUrl(item.sendUserInfo?.user.icon)" />
<div>
<p v-if="selectIsAll()" class="content-others-username">{{item.sendUserInfo?.user.userName}}</p>
<div class="content-others-msg content-msg-common " :class="{'content-others-msg-group':selectIsAll()}">
{{ item.content }}
</div>
</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-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" @input="updateInputValue"> -->
<!-- <div class="bottom-input" contenteditable="true" @input="updateInputValue">
</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>
</template>
<style scoped lang="scss">
.body {
height: 790px;
width: 1400px;
display: flex;
justify-content: center;
box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.2);
}
.select-user-item {
background-color: #C8C8CA !important;
}
.left {
background-color: #2a2a2a;
width: 70px;
padding: 46px 10px 0 10px;
.icon {
background-color: burlywood;
height: 46px;
width: 46px;
img {
height: 100%;
width: 100%;
}
}
}
.middle {
background-color: #dadbdc;
width: 380px;
.header {
height: 75px;
background: #f7f7f7;
padding: 26px 0 26px 0;
.header-div {
background-color: #F7F7F7;
height: 30px;
width: 338px;
margin: auto;
display: flex;
justify-content: space-between;
.search {
width: 300px;
height: 100%;
background-color: #E2E2E2;
border-radius: 5px;
padding: 5px;
img {
height: 16px;
width: 16px;
}
span {
margin-left: 10px;
font-size: 14px;
color: #818181;
margin-bottom: 5px;
vertical-align: top;
}
}
button {
margin-left: 10px;
width: 30px;
background-color: #E2E2E2;
border-radius: 5px;
padding: 5px 3px;
img {
height: 100%;
width: 100%;
}
}
}
}
.user-list::-webkit-scrollbar-thumb {
background-color: #BEBCBA;
/* 滚动条滑块颜色 */
}
.user-list::-webkit-scrollbar {
width: 8px;
/* 滚动条宽度 */
height: 10px;
/* 滚动条高度 */
}
.user-list {
height: calc(100% - 75px);
overflow-y: auto;
/* 只启用垂直方向滚动条 */
.user-div {
display: flex;
justify-content: space-between;
height: 80px;
width: 100%;
background-color: #EAE8E7;
padding: 16px;
&-left {
height: 100%;
display: flex;
.user-name-msg {
display: flex;
flex-direction: column;
justify-content: space-between;
padding: 0 10px;
.font-name {
font-size: 20px;
}
.font-msg {
font-size: 15px;
color: #999999;
}
}
img {
height: 100%;
}
}
&-right {
font-size: 15px;
color: #999999;
}
}
.user-div:hover {
background-color: #D9D8D8;
}
}
}
.right {
background-color: #f5f5f5;
width: 950px;
.header {
height: 75px;
background: #f7f7f7;
border: 1px solid #e7e7e7;
display: flex;
justify-content: space-between;
.header-left {
padding: 25px;
font-size: 25px;
align-content: center;
}
.header-right {
ul {
display: flex;
li {
padding: 8px 12.5px 10px 12.5px;
img {
height: 15px;
width: 15px;
}
}
}
.more {
padding: 0px 12.5px;
display: flex;
justify-content: flex-end;
img {
height: 18px;
width: 18px;
}
}
}
}
.content {
overflow-y: auto;
/* 只启用垂直方向滚动条 */
height: 555px;
padding: 20px 40px;
}
.bottom {
height: calc(100% - 630px);
background: #f7f7f7;
border-top: 1.5px solid #e7e7e7;
padding: 15px 35px;
&-tool {
display: flex;
justify-content: space-between;
height: 22px;
.ul-left {
display: flex;
li {
width: 22px;
height: 22px;
margin-right: 20px;
}
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 {
display: flex;
justify-content: flex-end;
button {
width: 126px;
height: 40px;
background-color: #E9E9E9;
color: #06AE56;
border-radius: 5px;
font-size: 18px;
}
button:hover {
background-color: #D2D2D2;
}
}
}
}
.top-icon {
margin-top: 32px;
li {
cursor: pointer;
text-align: center;
margin-bottom: 24px;
img {
height: 24px;
width: 24px;
}
}
}
.bottom-icon {
margin-top: 125px;
li {
cursor: pointer;
text-align: center;
margin-bottom: 24px;
img {
height: 24px;
width: 24px;
}
}
}
.content-common {
display: flex;
margin-bottom: 18px;
img {
height: 45px;
width: 45px;
}
}
.content-msg-common {
display: flex;
align-content: center;
flex-wrap: wrap;
position: relative;
margin: 0 15px;
padding: 5px 15px;
text-align: center;
font-size: 18px;
border-radius: 5px;
}
.content-myself {
justify-content: flex-end;
}
.content-myself-msg:hover {
background-color: #89D961;
}
.content-myself-msg {
background-color: #95EC69;
}
.content-myself-msg:hover:after {
border-left: 10px solid #89D961;
}
.content-others {
justify-content: flex-start;
}
.content-others-username{
margin-left: 15px;
color: #B2B2B2;
position: relative;
top: -15px;
}
.content-others-msg-group{
position: relative;
top: -10px;
}
.content-others-msg {
background-color: #FFFFFF;
padding: 10px 15px;
}
.content-others-msg:hover {
background-color: #EBEBEB;
}
.content-others-msg:hover:after {
border-right: 10px solid #EBEBEB;
}
.content-myself-msg:after {
content: '';
position: absolute;
width: 0;
height: 0;
/* 箭头靠右边 */
top: 13px;
right: -10px;
border-top: 10px solid transparent;
border-bottom: 10px solid transparent;
border-left: 10px solid #97EC6F;
}
.content-others-msg:after {
/* 箭头靠左边 */
content: '';
position: absolute;
width: 0;
height: 0;
top: 13px;
left: -10px;
border-top: 10px solid transparent;
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>