添加 mock 数据,添加客服聊天

This commit is contained in:
icssoa 2021-03-17 18:34:35 +08:00
parent cdc38f2a01
commit 9c96709e1e
11 changed files with 173 additions and 70 deletions

View File

@ -1,6 +1,6 @@
{
"name": "cool-admin-vue",
"version": "3.0.2",
"version": "3.1.0",
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
@ -10,8 +10,8 @@
},
"dependencies": {
"axios": "^0.21.1",
"cl-admin": "^1.3.4",
"cl-admin-crud": "^1.6.0",
"cl-admin": "^1.4.0",
"cl-admin-crud": "^1.6.2",
"cl-admin-theme": "^0.0.4",
"clipboard": "^2.0.7",
"codemirror": "^5.59.4",
@ -20,6 +20,7 @@
"echarts": "^4.5.0",
"element-ui": "^2.15.1",
"js-beautify": "^1.13.5",
"mockjs": "^1.1.0",
"nprogress": "^0.2.0",
"qs": "^6.9.1",
"quill": "^1.3.7",

View File

@ -25,6 +25,7 @@ export default {
}
}
},
"chat",
"task",
"copy",
"distpicker",

View File

@ -66,7 +66,7 @@ export default {
},
computed: {
...mapGetters(["conf", "menuGroup"]),
...mapGetters(["menuGroup"]),
lastName() {
return _.last(this.list).name;

View File

@ -1,11 +1,11 @@
<template>
<div class="chat-wrap">
<div class="cl-chat__wrap">
<!-- 聊天窗口 -->
<cl-dialog :visible.sync="visible" v-bind="conf">
<div class="chat-box">
<div class="cl-chat">
<!-- 会话区域 -->
<div class="chat-box__session">
<div class="chat-box__session-search">
<div class="cl-chat__session">
<div class="cl-chat__session-search">
<el-input
v-model="session.keyWord"
placeholder="搜索"
@ -18,9 +18,9 @@
</div>
<!-- 会话列表 -->
<ul class="chat-box__session-list scroller1">
<ul class="cl-chat__session-list scroller1" v-if="sessionList.length > 0">
<li
class="chat-box__session-item"
class="cl-chat__session-item"
v-for="(item, index) in sessionList"
:key="index"
:class="{
@ -47,18 +47,23 @@
</div>
</li>
</ul>
<!-- 空态 -->
<div class="cl-chat__session-empty" v-else>
没有搜索到内容...
</div>
</div>
<!-- 会话详情 -->
<div class="chat-box__detail">
<div class="cl-chat__detail">
<template v-if="session.current">
<div
class="chat-box__detail-container scroller1"
class="cl-chat__detail-container scroller1"
ref="scroller"
v-loading="message.loading"
>
<!-- 加载更多 -->
<div class="chat-box__detail-more" v-if="message.list.length > 0">
<div class="cl-chat__detail-more" v-if="message.list.length > 0">
<el-button
round
size="mini"
@ -72,9 +77,9 @@
<message :list="message.list" />
</div>
<div class="chat-box__detail-footer">
<div class="cl-chat__detail-footer">
<!-- 工具栏 -->
<div class="chat-box__opbar">
<div class="cl-chat__opbar">
<ul>
<!-- 表情 -->
<li>
@ -93,7 +98,7 @@
</el-popover>
</li>
<!-- 图片上传 -->
<li>
<li hidden>
<cl-upload
accept="image/*"
list-type
@ -103,7 +108,7 @@
</cl-upload>
</li>
<!-- 视频上传 -->
<li>
<li hidden>
<cl-upload
accept="video/*"
list-type
@ -126,7 +131,7 @@
</div>
<!-- 输入框发送按钮 -->
<div class="chat-box__input">
<div class="cl-chat__input">
<el-input
v-model="message.value"
placeholder="请描述您想咨询的问题"
@ -158,9 +163,9 @@
<script>
import dayjs from "dayjs";
import io from "socket.io-client";
import { isString, debounce } from "cl-admin/utils";
import { mapGetters } from "vuex";
import { isString, debounce } from "cl-admin/utils";
import io from "socket.io-client";
import { socketUrl } from "@/config/env";
import Emoji from "./emoji";
import Message from "./message";
@ -180,14 +185,16 @@ export default {
data() {
return {
visible: false,
socket: null,
conf: {
title: "聊天对话框",
height: "650px",
width: "1000px",
props: {
modal: true,
"custom-class": "chat-box__wrap",
customClass: "cl-chat__dialog",
"append-to-body": true,
"close-on-click-modal": false,
width: "1000px"
"close-on-click-modal": false
}
},
message: {
@ -212,8 +219,7 @@ export default {
},
emoji: {
visible: false
},
socket: null
}
};
},
@ -233,28 +239,26 @@ export default {
}
},
mounted() {
this.socket = io(`${socketUrl}?isAdmin=true&token=${this.token}`);
this.socket.on("connect", () => {
console.log("socket connect");
});
this.socket.on("admin", msg => {
this.onMessage(msg);
});
this.socket.on("error", err => {
console.log(err);
});
this.socket.on("disconnect", () => {
console.log("disconnect connect");
});
created() {
// this.socket = io(`${socketUrl}?isAdmin=true&token=${this.token}`);
// this.socket.on("connect", () => {
// console.log("socket connect");
// });
// this.socket.on("admin", msg => {
// this.onMessage(msg);
// });
// this.socket.on("error", err => {
// console.log(err);
// });
// this.socket.on("disconnect", () => {
// console.log("disconnect connect");
// });
},
destroyed() {
this.socket.close();
if (this.socket) {
this.socket.close();
}
},
methods: {
@ -342,7 +346,7 @@ export default {
order: "updateTime",
sort: "desc"
})
.then(async res => {
.then(res => {
this.session.list = res.list;
this.session.pagination = res.pagination;
@ -411,7 +415,10 @@ export default {
scrollToBottom: debounce(function() {
this.$nextTick(() => {
if (this.$refs["scroller"]) {
this.$refs["scroller"].scrollTo(0, 999999);
this.$refs["scroller"].scrollTo({
top: 99999,
behavior: "smooth"
});
}
});
}, 300),
@ -580,12 +587,14 @@ export default {
content
});
this.socket.emit(`user@${userId}`, {
contentType,
type: 0,
content: JSON.stringify(content),
sessionId: id
});
if (this.socket) {
this.socket.emit(`user@${userId}`, {
contentType,
type: 0,
content: JSON.stringify(content),
sessionId: id
});
}
},
/**
@ -642,22 +651,22 @@ export default {
</script>
<style lang="scss">
.chat-box__wrap {
height: 650px;
min-width: 1000px;
.cl-chat__dialog {
margin-bottom: 0 !important;
min-width: 1000px;
.el-dialog__body {
height: calc(100% - 46px);
padding: 0;
}
&.is-fullscreen {
.cl-dialog__container {
height: 100%;
height: calc(100vh - 46px) !important;
}
}
}
.chat-box {
.cl-chat {
display: flex;
height: 100%;
background-color: #f7f7f7;
@ -673,7 +682,7 @@ export default {
padding: 10px;
}
ul {
&-list {
height: calc(100% - 52px);
overflow: auto;
@ -684,14 +693,12 @@ export default {
border-left: 5px solid #fff;
.avatar {
height: 40px;
width: 40px;
margin-right: 12px;
img {
display: block;
height: 100%;
width: 100%;
height: 40px;
width: 40px;
border-radius: 3px;
background-color: #eee;
}
@ -741,6 +748,11 @@ export default {
}
}
}
&-empty {
text-align: center;
margin-top: 10px;
}
}
&__detail {
@ -779,6 +791,7 @@ export default {
&__opbar {
margin-bottom: 5px;
ul {
display: flex;
li {

View File

@ -1,3 +1,4 @@
import Notice from "./notice";
import Chat from "./chat";
export default { Notice };
export default { Notice, Chat };

View File

@ -12,7 +12,7 @@
<div class="main">
<div class="avatar" @tap="toUserDetail(item)">
<el-image :src="item.avatarUrl"></el-image>
<img :src="item.avatarUrl" />
</div>
<div class="det">
@ -185,11 +185,13 @@ export default {
.avatar {
flex-shrink: 0;
height: 40px;
width: 40px;
.el-image {
img {
display: block;
height: 40px;
width: 40px;
border-radius: 3px;
background-color: #fff;
}
}

View File

@ -1,6 +1,9 @@
import { BaseService, Service, Permission } from "cl-admin";
@Service("app/im/message")
@Service({
namespace: "im/message",
mock: true
})
class ImMessage extends BaseService {
@Permission("read")
read(data) {

View File

@ -1,6 +1,9 @@
import { BaseService, Service, Permission } from "cl-admin";
@Service("app/im/session")
@Service({
namespace: "im/session",
mock: true
})
class ImSession extends BaseService {
@Permission("unreadCount")
unreadCount() {

View File

@ -9,6 +9,9 @@ import router from "@/router";
// 缓存
import store from "@/store";
// mock
import "@/mock";
// 阻止显示生产模式的消息
Vue.config.productionTip = false;

75
src/mock/chat.js Normal file
View File

@ -0,0 +1,75 @@
import Mock from "mockjs";
Mock.mock("/im/session/page", "post", options => {
const { keyWord = "" } = JSON.parse(options.body);
const data = Mock.mock({
"list|20": [
{
id: "@id",
nickname: "@name",
createTime: "@datetime(yy-MM-dd HH:mm:ss)",
text: "@cparagraph(5)",
content() {
return JSON.stringify({ text: this.text });
},
"contentType|0-3": 0,
"serviceUnreadCount|0-10": 0,
headimgurl() {
return Mock.Random.image(
"40x40",
Mock.Random.color(),
"#FFF",
"png",
this.nickname[0]
);
}
}
]
});
return {
code: 1000,
data: {
list: data.list.filter(e => e.nickname.includes(keyWord)),
pagination: {}
}
};
});
Mock.mock("/im/session/unreadCount", "get", options => {
const data = Mock.mock({
"count|1-50": 1
});
return {
code: 1000,
data: data.count
};
});
Mock.mock("/im/message/page", "post", options => {
const data = Mock.mock({
"list|20": [
{
id: "@id",
nickname: "@name",
createTime: "@datetime",
text: "@cparagraph(1, 4)",
content() {
return JSON.stringify({ text: this.text });
},
contentType: 0,
"type|0-1": 1
}
]
});
return {
code: 1000,
data: {
list: data.list,
pagination: {}
}
};
});

1
src/mock/index.js Normal file
View File

@ -0,0 +1 @@
import "./chat";