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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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