feat: 聊天交互

feature/task1.0.0__0514__ch
向文可 2 years ago
parent 76eb6645e0
commit 4c92155014

@ -1,11 +1,30 @@
<template>
<div class="chat-container">
<div class="header">当前客服小爱</div>
<div class="chat-container" @click="emojiVisible = false">
<div class="header">
<p>当前客服小爱</p>
<el-button type="text" @click="summaryVisible = !summaryVisible">
{{ summaryVisible ? '收起' : '统计数据' }}
</el-button>
</div>
<div class="summary">
<el-table v-show="summaryVisible" border :data="[summary]">
<el-table-column align="center" header-align="center" label="今日接待次数" prop="todayTimes" />
<el-table-column align="center" header-align="center" label="今日接待人数" prop="todayCount" />
<el-table-column align="center" header-align="center" label="历史接待次数" prop="historyTimes" />
<el-table-column align="center" header-align="center" label="历史接待人数" prop="historyCount" />
</el-table>
</div>
<div class="body">
<div class="aside">
<div class="aside-header">近期会话</div>
<el-scrollbar class="session-list" tag="ul">
<li v-for="(item, index) in sessionList" :key="index" class="session-item">
<li
v-for="(item, index) in sessionList"
:key="index"
class="session-item"
:class="{ active: state.currentIndex === index }"
@click="handleChangeSession(index)"
>
<el-badge class="session-count" :hidden="item.count === 0" :max="99" :value="item.count">
<el-avatar circle :src="item.avatar" />
</el-badge>
@ -29,34 +48,54 @@
</div>
</div>
<div class="content-header-right">
<el-button>个人订单</el-button>
<el-button>转移会话</el-button>
<el-button>
<el-icon name="clipboard" />
个人订单
</el-button>
<el-button>
<el-icon name="chat-forward" />
转移会话
</el-button>
</div>
</div>
<el-scrollbar class="message-list">
<el-scrollbar ref="refsMessageList" class="message-list">
<message-item v-for="(item, index) in sessionMessageList" :key="index" :message="item" />
</el-scrollbar>
<div class="operation-bar">
<el-button type="text" @click.stop="emojiVisible = !emojiVisible">
<el-icon name="chat-smile-3-fill" size="20" />
</el-button>
<el-button type="text" @click="handlePickImage">
<el-icon name="image-fill" size="20" />
</el-button>
<el-button type="text" @click="handlePickVideo">
<el-icon name="movie-fill" size="20" />
</el-button>
<el-scrollbar v-show="emojiVisible" class="emoji-panel" tag="ul">
<li v-for="(item, index) in emojiList" :key="index" @click="handleAddEmoji(item)">
{{ entitiestoUtf16(item) }}
</li>
</el-scrollbar>
<el-button type="text" @click="emojiVisible = !emojiVisible">
<el-icon name="chat-smile-3-fill" size="24" />
</el-button>
<el-button type="text">
<el-icon name="image-fill" size="24" />
</el-button>
<el-button type="text">
<el-icon name="movie-fill" size="24" />
</el-button>
<input
ref="refsImage"
accept="image/*"
style="display: none"
type="file"
@change="handleSendImage"
/>
<input
ref="refsVideo"
accept="video/*"
style="display: none"
type="file"
@change="handleSendVideo"
/>
</div>
<div class="input">
<el-input v-model="state.message" type="textarea" />
<el-input v-model="state.message" placeholder="请输入要发送的内容" type="textarea" />
</div>
<div class="send">
<el-button type="primary">发送</el-button>
<el-button type="primary" @click="handleSendMessage"></el-button>
</div>
</div>
</div>
@ -66,6 +105,22 @@
<script setup>
import { emojiData, entitiestoUtf16 } from '@/utils/emoji.js';
import MessageItem from './message.vue';
const { proxy } = getCurrentInstance();
//
const summaryVisible = ref(true);
const summary = ref({
historyTimes: 96,
historyCount: 88,
todayTimes: 10,
todayCount: 8,
});
//
const state = reactive({
currentIndex: 0,
message: '',
});
const sessionList = reactive([
{
name: '小可爱',
@ -89,10 +144,6 @@
content: '你好,请问这个能有优惠吗?',
},
]);
const state = reactive({
currentIndex: 0,
message: '',
});
const currentSession = computed(() => {
return sessionList[state.currentIndex];
});
@ -172,13 +223,80 @@
name: '小可爱',
},
]);
const handleChangeSession = (index) => {
state.currentIndex = index;
};
//
const emojiVisible = ref(false);
const emojiList = computed(() => emojiData.map((item) => item.list).flat());
const handleAddEmoji = (data) => {
let str = ' ' + entitiestoUtf16(data) + ' ';
state.message += str;
emojiVisible.value = false;
};
//
const refsImage = ref(null);
const handlePickImage = () => {
refsImage.value.click();
};
const handleSendImage = (e) => {
const file = e.target.files[0];
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = (e) => {
const data = e.target.result;
const message = {
type: 'image',
content: data,
};
handleSendMessage(message);
};
};
//
const refsVideo = ref(null);
const handlePickVideo = () => {
refsVideo.value.click();
};
const handleSendVideo = (e) => {
const file = e.target.files[0];
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = (e) => {
const data = e.target.result;
const message = {
type: 'video',
content: data,
};
handleSendMessage(message);
};
};
//
const refsMessageList = ref(null);
const handleSendMessage = (data) => {
const message = data || {
type: 'text',
content: state.message,
};
if (message.content) {
Object.assign(message, {
time: dayjs(new Date()).format('YYYY-MM-DD HH:mm:ss'),
from: 'employee',
avatar: 'https://placem.at/people',
name: '小爱',
});
sessionMessageList.push(message);
if (!data) {
state.message = '';
}
nextTick(() => {
refsMessageList.value.setScrollTop(refsMessageList.value.scrollbar$.scrollHeight);
});
} else {
proxy.$message.warning('发送消息不能为空');
}
};
</script>
@ -188,22 +306,30 @@
flex-direction: column;
overflow: hidden;
.header {
display: flex;
align-items: center;
padding: @layout-space 0;
.el-button {
margin-left: @layout-space-super;
}
}
.summary {
margin-bottom: @layout-space;
}
.body {
width: 100%;
flex: 1;
overflow: hidden;
display: flex;
border: 1px solid #eee;
border: 1px solid #ebeef5;
.aside {
border-right: 1px solid #eee;
border-right: 1px solid #ebeef5;
.aside-header {
height: 60px;
display: flex;
align-items: center;
padding: @layout-space;
border-bottom: 1px solid #eee;
border-bottom: 1px solid #ebeef5;
font-size: @layout-h3;
font-weight: bolder;
}
@ -218,6 +344,9 @@
&:hover {
background-color: #f5f5f5;
}
&.active {
background-color: #eee;
}
.session-count {
margin-right: @layout-space;
:deep(.el-badge__content) {
@ -246,7 +375,7 @@
}
}
+ .session-item {
border-top: 1px solid #eee;
border-top: 1px solid #ebeef5;
}
}
}
@ -261,7 +390,7 @@
align-items: center;
justify-content: space-between;
padding: @layout-space;
border-bottom: 1px solid #eee;
border-bottom: 1px solid #ebeef5;
.content-header-left {
display: flex;
align-items: center;
@ -291,9 +420,9 @@
.operation-bar {
display: flex;
align-items: center;
padding: @layout-space;
border-top: 1px solid #eee;
border-bottom: 1px solid #eee;
padding: 0 @layout-space;
border-top: 1px solid #ebeef5;
border-bottom: 1px solid #ebeef5;
position: relative;
.emoji-panel {
position: absolute;
@ -319,7 +448,7 @@
}
}
.input {
height: 100px;
height: 64px;
.el-textarea {
height: 100%;
:deep(textarea) {

Loading…
Cancel
Save