Files
dvcp_v2_webapp/packages/xbot/AppSessionArchiveXbot/components/Detail.vue
2024-01-22 17:12:32 +08:00

1089 lines
31 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.

<template>
<ai-list v-loading="isLoading" class="detail">
<template slot="title">
<ai-title
title="会话存档详情"
isShowBack
isShowBottomBorder
@onBackClick="cancel(false)"
></ai-title>
</template>
<template #left>
<div class="addressBook-left">
<div class="addressBook-left__title">
<h2
:class="[tabIndex == 1 ? 'tab-active' : '']"
@click="typeClick(1)"
>
群聊会话
</h2>
<!-- <h2
:class="[tabIndex == 0 ? 'tab-active' : '']"
@click="typeClick(0)"
>
私聊会话
</h2> -->
</div>
<div class="addressBook-left__list--title">
<el-input
size="mini"
:placeholder="tabIndex == 1 ? '请输入群名称' : '请输入昵称'"
v-model="searchName"
clearable
@clear="(current = 1), (searchName = ''), getListInit()"
v-throttle="
() => {
(current = 1), getListInit();
}
"
suffix-icon="iconfont iconSearch"
>
</el-input>
</div>
<div class="addressBook-left__list--wrapper">
<div
class="addressBook-left__list--item"
v-for="(item, index) in list"
:key="index"
:class="leftActiveIndex == index ? 'active' : ''"
@click="leftClick(index)"
>
<div v-if="tabIndex == 1" class="flex-left">
<img :src="item.roomAvatar ? item.roomAvatar : 'https://cdn.cunwuyun.cn/dvcp/group-img.png'" alt="">
<p>{{ item.roomName }}</p>
</div>
<div v-else class="flex-left">
<img :src="item.toUserAvatar" alt="" />
<p>{{ item.toUserName }}</p>
</div>
<div
class="flex-right"
:class="`type` + item.roomType"
v-if="tabIndex == 1 && item.roomType > 0"
>
{{ item.roomType == 1 ? "内部" : "外部" }}
</div>
<div
class="flex-right"
:class="`type` + item.toUserType"
v-if="tabIndex != 1 && item.toUserType > 0"
>
{{ item.toUserType == 1 ? "内部" : "外部" }}
</div>
</div>
<AiEmpty v-if="!list.length"></AiEmpty>
</div>
<el-pagination
class="pagination"
layout="prev, pager, next"
:total="total"
@current-change="currentChange"
:current-page="current"
:page-size="20"
>
</el-pagination>
</div>
</template>
<template slot="content">
<div class="content-right-title">
<div class="tab-content">
<h2
v-for="(item, index) in msgTypeList"
:key="index"
:class="msgType == index ? 'tab-active' : ''"
@click="msgTypeClick(index)"
>
{{ item.name }}
</h2>
</div>
<div class="search-content">
<el-date-picker
v-model="time"
size="small"
type="daterange"
value-format="yyyy-MM-dd"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
@change="onChange"
>
</el-date-picker>
<el-input
size="small"
placeholder="输入搜索内容"
v-model="searchMsg"
clearable
@clear="(msgCurrent = 1), (searchMsg = ''), getMsgListInit()"
suffix-icon="iconfont iconSearch"
v-throttle="
() => {
(msgCurrent = 1), getMsgListInit();
}
"
/>
<!-- <ai-download :instance="instance" url="/app/appconvenientaddressbook/export" :params="search" fileName="会话存档"
:disabled="msgList.length == 0">
<el-button icon="iconfont iconExported" :disabled="msgList.length == 0">导出</el-button>
</ai-download> -->
<el-button
icon="iconfont iconExported"
:disabled="msgList.length == 0"
style="margin-left: 8px"
@click="handleExport"
>导出</el-button
>
</div>
</div>
<div class="content-right-info" @scroll="msgScroll">
<div ref="pdf">
<div v-for="(item, index) in msgList" :key="index">
<div
class="item"
:class="item.userId == id ? 'item-right' : 'item-left'"
>
<!-- <p class="time" v-if="index == 0">{{item.msgSendTime}}</p> -->
<p class="user-name">
{{ item.userName }}<span>{{ item.msgSendTime }}</span>
</p>
<div class="item-content-flex">
<!-- <i class="el-icon-warning" v-if="item.userId == id"></i> -->
<img
:src="item.userAvatar"
alt=""
class="user-img"
v-if="item.userId != id && item.userAvatar"
/>
<img
src="./img/user-img.png"
alt=""
class="user-img"
v-if="item.userId != id && !item.userAvatar"
/>
<div class="content" v-if="item.msgType == 'text'">
<span></span>
<p>{{ item.content }}</p>
</div>
<div class="img-list" v-if="item.msgType == 'image'">
<img :src="item.sdkFileUrl" alt="" v-viewer />
</div>
<div class="voice-info" v-if="item.msgType == 'voice'">
<ai-audio :src="item.sdkFileUrl" skin="flat" />
</div>
<video
style="width: 300px; object-fit: fill"
controls
:src="item.sdkFileUrl"
v-if="item.msgType == 'video'"
></video>
<ai-file-list
v-if="item.msgType == 'file'"
:fileList="item.files"
:fileOps="{ name: 'name', size: 'fileSizeStr' }"
></ai-file-list>
<div class="revoke-text" v-if="item.msgType == 'revoke'">
{{ item.userName
}}撤回了一条消息
</div>
<div class="revoke-text" v-if="item.msgType == 'disagree'">
对方不同意会话存档内容,你将无法继续提供服务
</div>
<div class="revoke-text" v-if="item.msgType == 'agree'">
对方同意会话存档内容,你可以继续提供服务
</div>
<div class="card-info" v-if="item.msgType == 'card'">
<div class="top">
<div class="card-left">
<h3>{{ item.cardCorpName }}</h3>
<p>{{ item.cardUserName }}</p>
<!-- <div>{{item.cardUserId}}</div> -->
</div>
<div class="card-right">
<img
:src="item.cardUserAvatar"
alt=""
v-if="item.cardUserAvatar"
/>
<img src="./img/user-img.png" alt="" v-else />
</div>
</div>
<div class="bottom">个人名片</div>
</div>
<img
:src="item.sdkFileUrl"
alt=""
v-if="item.msgType == 'emotion'"
:style="[
{ width: item.width / 2 + 'px' },
{ height: item.height / 2 + 'px' },
]"
/>
<div class="map-info" v-if="item.msgType == 'location'">
<div :id="item.mapId" class="map-content"></div>
<div class="address-text">
<p>{{ item.title }}</p>
<p>{{ item.address }}</p>
</div>
</div>
<div class="card-info" v-if="item.msgType == 'weapp'">
<div class="top">
<div class="card-left">
<h3>{{item.displayName}}</h3>
<p>{{item.title}}</p>
</div>
<div class="card-right">
<img src="./img/app-icon.png" alt="" >
</div>
</div>
<div class="bottom"><img src="./img/app-mini-icon.png" alt="" >小程序</div>
</div>
<div
class="card-info pointer"
v-if="item.msgType == 'link'"
@click="openLink(item)"
>
<div class="top">
<div class="card-left">
<p>{{ item.title }}</p>
<div>{{ item.username }}</div>
</div>
<div class="card-right" v-if="item.imageUrl">
<img :src="item.imageUrl" alt="" />
</div>
</div>
<div class="bottom">分享链接</div>
</div>
<img
:src="item.userAvatar"
alt=""
class="user-img"
v-if="item.userId == id"
/>
<!-- <i class="el-icon-warning" v-if="item.userId != id"></i> -->
</div>
</div>
</div>
</div>
<AiEmpty v-if="!msgList.length"></AiEmpty>
</div>
<!-- <el-pagination class="msg-list-pagination"
layout="prev, pager, next"
:total="msgTotal" @current-change="msgCurrentChange" :current-page="msgCurrent" :page-size="20">
</el-pagination> -->
</template>
</ai-list>
</template>
<script>
import { mapState } from "vuex";
import AMapLoader from "@amap/amap-jsapi-loader";
import html2canvas from "html2canvas";
import jsPDF from "jspdf";
import { Loading } from "element-ui";
const PdfLoader = (ele, pdfFileName) => {
let loadingInstance = Loading.service({ fullscreen: true, text: '正在导出(请勿刷新/关闭页面)' });
ele.style.fontFamily = "宋体";
ele.style.fontSize = "16px";
ele.style.padding = "0 20px";
// 预留一定的时间给dom页面渲染完成 如果你能保证dom已经渲染完成了包括图片 才去进行下面转化操作那就可以不用这个延迟器)
setTimeout(() => {
html2canvas(ele, {
// dpi: 300, // 清晰度
scale: 1, // 将Canvas放大倍数 可以获得更具清晰的图片内容
// !!!注意如果你生成的元素内容非常多是一个非常长列表 建议scale不要写太高或者删除这个属性 因为html2canvas会吧内容转成
// base64 会有一定的内容上限 最终返回没有base64编码目前我尝试过生成55页的PDF估计上限在70-100页
useCORS: true, //是否允许跨域
allowTaint: false,
height: ele.offsetHeight,
width: ele.offsetWidth,
windowWidth: document.body.scrollWidth,
windowHeight: document.body.scrollHeight,
}).then((canvas) => {
//未生成pdf的html页面高度
var leftHeight = canvas.height;
var a4Width = 595.28;
var a4Height = 841.89;
//一页pdf显示html页面生成的canvas高度;
var a4HeightRef = Math.floor((canvas.width / a4Width) * a4Height);
//pdf页面偏移
var position = 0;
var pageData = canvas.toDataURL("image/jpeg", 1.0); // 生成的base64 如果你只是要图片 到这里就可以拿到base64图片编码可以查一下base64转二进制 使用new FormData对象传给后端到服务器
var pdf = new jsPDF("x", "pt", "a4"); //生成A4内容大小的pdf每页 更多参数配置可以看看下面的网站
// https://blog.csdn.net/weixin_42333548/article/details/107630706
var index = 1,
canvas1 = document.createElement("canvas"),
height;
pdf.setDisplayMode("fullwidth", "continuous", "FullScreen");
// 处理 pdf 上一页 与 下一页内容之间交叉不好看的断点样式
// 并且把内容转成二进制 生成pdf文件
function createImpl(canvas) {
if (leftHeight > 0) {
index++;
var checkCount = 0;
if (leftHeight > a4HeightRef) {
var i = position + a4HeightRef;
for (i = position + a4HeightRef; i >= position; i--) {
var isWrite = true;
for (var j = 0; j < canvas.width; j++) {
var c = canvas.getContext("2d").getImageData(j, i, 1, 1).data;
if (c[0] != 0xff || c[1] != 0xff || c[2] != 0xff) {
isWrite = false;
break;
}
}
if (isWrite) {
checkCount++;
if (checkCount >= 10) {
break;
}
} else {
checkCount = 0;
}
}
height =
Math.round(i - position) || Math.min(leftHeight, a4HeightRef);
if (height <= 0) {
height = a4HeightRef;
}
} else {
height = leftHeight;
}
canvas1.width = canvas.width;
canvas1.height = height;
var ctx = canvas1.getContext("2d");
ctx.drawImage(
canvas,
0,
position,
canvas.width,
height,
0,
0,
canvas.width,
height
);
if (position != 0) {
pdf.addPage();
}
pdf.addImage(
canvas1.toDataURL("image/jpeg", 1.0),
"JPEG",
0,
0,
a4Width,
(a4Width / canvas1.width) * height
);
leftHeight -= height;
position += height;
if (leftHeight > 0) {
//给pdf文件 添加全屏水印
// const base64 = ''; // 吧你要添加的水印内容搞成一张小图片 然后手动去转成base64编码 放在这里就可以了
// for (let i = 0; i < 6; i++) {
// for (let j = 0; j < 5; j++) {
// const left = (j * 120) + 20;
// pdf.addImage(base64, 'JPEG', left, i * 150, 20, 30);
// };
// };
pdf.addImage(pageData, "JPEG", 0, i * 150, 20, 30);
setTimeout(createImpl, 500, canvas);
} else {
pdfSave();
}
}
}
//当内容未超过pdf一页显示的范围无需分页
if (leftHeight < a4HeightRef) {
pdf.addImage(
pageData,
"JPEG",
0,
0,
a4Width,
(a4Width / canvas.width) * leftHeight
);
pdfSave();
} else {
try {
pdf.deletePage(0);
setTimeout(createImpl, 500, canvas);
} catch (err) {
console.log(err);
}
}
function pdfSave() {
// pdf文件生成完毕 自动下载到客户本地
pdf.save(pdfFileName + ".pdf");
loadingInstance.close();
}
});
}, 500);
};
export default {
name: "Detail",
props: {
instance: Function,
dict: Object,
params: Object,
},
data() {
return {
isLoading: false,
tabIndex: 1,
searchName: "",
time: [],
search: {
name: "",
},
current: 1,
total: 0,
list: [],
leftActiveIndex: 0,
msgCurrent: 1,
msgTotal: 0,
msgPages: 2,
msgList: [],
msgType: 0,
msgTypeList: [
{ name: "全部", value: "" },
{ name: "图片/视频", value: "imagevideo" },
{ name: "语音", value: "voice" },
{ name: "文件", value: "file" },
],
searchMsg: "",
id: "", //YangFei
};
},
computed: {
...mapState(["user"]),
},
created() {
this.isLoading = true;
if (this.params && this.params.id) {
this.id = this.params.id;
this.getList();
}
},
methods: {
msgScroll(e) {
if (e.target.scrollTop == 0) {
if (this.msgCurrent > this.msgPages) {
return this.$message("已加载完成,没有更多数据");
} else {
this.msgCurrent++;
this.isLoading = true;
this.getMsgList();
}
}
},
getListInit() {
this.isLoading = true;
this.current = 1;
this.leftActiveIndex = 0;
this.getList();
},
getList() {
this.instance
.post(`/app/appsessionarchiveindex/listForXbot`, null, {
params: {
userId: this.id,
type: this.tabIndex,
size: 20,
current: this.current,
toUserName: this.tabIndex == 1 ? "" : this.searchName,
roomName: this.tabIndex == 1 ? this.searchName : "",
},
})
.then((res) => {
if (res.code === 0) {
this.list = res.data.records;
this.total = res.data.total || 0;
this.getMsgListInit();
}
this.isLoading = false;
})
.catch(() => {
this.isLoading = false;
});
},
getMsgListInit() {
this.isLoading = true;
this.msgCurrent = 1;
this.msgPages = 2;
this.getMsgList();
},
getMsgList() {
var preveHeight = document.querySelector(
".content-right-info"
).scrollHeight;
this.instance
.post(`/app/appsessionarchiveinfo/listForXbot`, null, {
params: {
userId: this.id,
type: this.tabIndex,
size: 8,
current: this.msgCurrent,
msgType: this.msgTypeList[this.msgType].value,
// msgType: 'weapp',
toUserId:
this.list[this.leftActiveIndex].type == 1
? ""
: this.list[this.leftActiveIndex].toUserId,
roomId:
this.list[this.leftActiveIndex].type == 1
? this.list[this.leftActiveIndex].roomId
: "",
content: this.searchMsg,
startTime: this.time ? this.time[0] : "",
endTime: this.time ? this.time[1] : "",
},
})
.then((res) => {
if (res.code === 0) {
res.data.records.map((item, index) => {
if (item.msgType == "file") {
item.files = [
{
url: item.sdkFileUrl,
accessUrl: item.sdkFileUrl,
name: item.sdkFileName,
fileSizeStr: item.fileSizeStr,
},
];
}
if (item.msgType == "image") {
var image = new Image();
image.crossOrigin = '';
image.src = item.sdkFileUrl
image.onload = ()=>{
this.$set(this.msgList[index], 'src', this.getBase64Image(image))
// item.src = this.getBase64Image(image);
// console.log(this.getBase64Image(image))
}
}
});
this.msgList =
this.msgCurrent > 1
? [...res.data.records, ...this.msgList]
: res.data.records;
this.msgList.map((item, index) => {
if (item.msgType == "location") {
item.mapId = `map${index}`
this.initMap(item.lng, item.lat, item.zoom, item.mapId);
}
})
this.msgPages = res.data.pages || 2;
this.$nextTick(() => {
if (this.msgCurrent == 1) {
document
.querySelector(".content-right-info")
.scrollTo(0, 999999999);
} else {
var height =
document.querySelector(".content-right-info").scrollHeight -
preveHeight;
document.querySelector(".content-right-info").scrollTop =
height;
}
});
}
this.$forceUpdate()
this.isLoading = false;
})
.catch(() => {
this.isLoading = false;
});
},
getBase64Image(img) {
var canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, img.width, img.height);
var ext = img.src.substring(img.src.lastIndexOf(".")+1).toLowerCase();
var dataURL = canvas.toDataURL("image/"+ext);
return dataURL;
},
initMap(lng, lat, zoom, mapId) {
AMapLoader.load({
key: "54a02a43d9828a8f9cd4f26fe281e74e",
version: "2.0",
}).then((AMap) => {
this.map = new AMap.Map(mapId, {
resizeEnable: true,
zooms: [6, 20],
center: [lng, lat],
zoom: zoom,
scrollWheel: false,
});
});
},
typeClick(index) {
this.tabIndex = index;
this.msgType = 0;
this.getListInit();
},
onChange() {
this.getMsgListInit();
},
currentChange(e) {
this.current = e;
this.getList();
},
msgCurrentChange(e) {
this.msgCurrent = e;
this.getMsgList();
},
leftClick(index) {
this.leftActiveIndex = index;
this.msgType = 0;
this.getMsgListInit();
},
msgTypeClick(index) {
this.msgType = index;
this.getMsgListInit();
},
openLink(row) {
document.write('<a href="" target="new"></a>');
window.open(row.linkUrl, "new");
},
handleExport() {
var fileName =
this.tabIndex == 1
? this.list[this.leftActiveIndex].roomName
: this.list[this.leftActiveIndex].toUserName;
PdfLoader(this.$refs.pdf, fileName);
},
cancel() {
this.$emit("change", {
type: "List",
isRefresh: true,
});
},
},
};
</script>
<style scoped lang="scss">
.detail {
.addressBook-left {
width: 300px;
height: auto;
background: #fafafb;
position: relative;
.addressBook-left__title {
display: flex;
align-items: center;
width: 100%;
height: 40px;
background: #ffffff;
h2 {
flex: 1;
height: 100%;
line-height: 40px;
color: #222;
font-size: 14px;
text-align: center;
cursor: pointer;
border-bottom: 2px solid transparent;
&.tab-active {
color: #2266ff;
border-bottom: 2px solid #2266ff;
}
}
}
.addressBook-left__list--wrapper {
height: calc(100% - 110px);
padding: 8px;
width: 100%;
box-sizing: border-box;
overflow-y: scroll;
.addressBook-left__list--item {
width: 100%;
line-height: 44px;
font-size: 16px;
color: #333;
margin-bottom: 8px;
padding: 8px;
display: flex;
justify-content: space-between;
cursor: pointer;
img {
width: 44px;
height: 44px;
border-radius: 50%;
margin-right: 8px;
vertical-align: top;
}
.flex-left {
padding-right: 8px;
box-sizing: border-box;
width: calc(100% - 56px);
p {
display: inline-block;
width: calc(100% - 52px);
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
.flex-right {
font-size: 12px;
margin-top: 8px;
border-radius: 4px;
width: 56px;
height: 28px;
line-height: 28px;
text-align: center;
border-radius: 4px;
}
.type1 {
background-color: #eaf4ff;
color: #267ef0;
}
.type2 {
background-color: #fdeee1;
color: #fb7d29;
}
}
.addressBook-left__list--item:hover {
background-color: #e8efff;
}
.active {
background-color: #e8efff;
color: #26f;
}
}
.addressBook-left__list--title {
display: flex;
align-items: center;
margin: 8px 8px 0;
.addressBook-left__list--search {
flex: 1;
:deep(input) {
width: 100%;
}
}
.el-button {
width: 84px;
flex-shrink: 1;
margin-right: 8px;
}
}
.pagination {
position: absolute;
bottom: 0;
width: 100%;
text-align: center;
background-color: #fff;
}
}
:deep(.ai-list__content--right) {
flex: 1;
min-width: 0;
margin-left: 1px;
box-shadow: none;
.ai-list__content--right-wrapper {
width: 100%;
position: relative;
padding: 0 !important;
height: 100%;
}
}
.content-right-title {
height: 40px;
border-bottom: 1px solid #ddd;
display: flex;
justify-content: space-between;
box-sizing: content-box;
.tab-content {
display: flex;
align-items: center;
width: 300px;
height: 40px;
background: #ffffff;
h2 {
flex: 1;
height: 100%;
line-height: 40px;
color: #222;
font-size: 14px;
text-align: center;
cursor: pointer;
border-bottom: 2px solid transparent;
&.tab-active {
color: #2266ff;
border-bottom: 2px solid #2266ff;
}
}
}
.search-content {
display: flex;
padding: 4px 8px 4px 0;
.ai-download,
.el-input {
margin-left: 8px;
}
.el-input {
width: 240px;
}
.el-date-editor--daterange {
width: 240px;
}
:deep .el-date-editor .el-range-separator {
width: 30px;
}
}
}
.content-right-info {
padding: 24px 16px;
height: calc(100% - 80px);
overflow-y: scroll;
.item {
margin-bottom: 48px;
.user-name {
color: #666;
font-size: 12px;
line-height: 20px;
padding: 0 0 0 64px;
span {
display: inline-block;
margin: 0 12px;
color: #999;
}
}
.item-content-flex {
display: flex;
.user-img {
width: 44px;
height: 44px;
border-radius: 50%;
margin-right: 8px;
}
.content {
max-width: calc(100% - 144px);
position: relative;
background-color: #f3f6f9;
span {
width: 0px;
height: 0px;
border: 10px solid transparent;
position: absolute;
top: 50%;
margin-top: -10px;
}
p {
display: inline-block;
padding: 8px;
line-height: 28px;
font-family: PingFangSC-Regular;
font-size: 16px;
color: #333;
word-break: break-all;
}
}
.img-list {
img {
max-width: 400px;
}
}
.voice-info {
.ai-audio {
margin-top: 8px;
}
}
.el-icon-warning {
font-size: 32px;
color: #f46;
margin-top: 8px;
}
.revoke-text {
line-height: 44px;
padding: 0 6px;
border-radius: 4px;
background-color: #eee;
color: #999;
margin-top: 4px;
}
.card-info {
width: 300px;
position: relative;
border-radius: 8px;
background-color: #fff;
border: 1px solid #eee;
.top {
display: flex;
padding: 16px;
.card-left {
width: calc(100% - 60px);
h3 {
line-height: 60px;
font-size: 22px;
color: #333;
margin-bottom: 10px;
}
p {
color: #000;
line-height: 24px;
font-size: 16px;
}
div {
color: #666;
font-size: 14px;
line-height: 24px;
}
}
.card-right {
img {
width: 50px;
height: 50px;
border-radius: 4px;
}
}
}
.bottom {
padding-left: 16px;
line-height: 44px;
font-size: 16px;
color: #666;
border-top: 1px solid #eee;
img {
width: 16px;
height: 16px;
margin-right: 8px;
}
}
}
.pointer {
cursor: pointer;
}
.map-info {
width: 600px;
height: 400px;
position: relative;
.map-content {
width: 600px;
height: 400px;
}
.address-text {
position: absolute;
bottom: 0;
left: 0;
z-index: 9999;
width: 600px;
background-color: rgba(0, 0, 0, 0.7);
p {
color: #fff;
line-height: 34px;
font-size: 16px;
padding-left: 16px;
word-break: break-all;
}
}
}
}
}
.item-left {
.item-content-flex {
.user-img {
margin: 0 20px 0 0;
}
.content {
span {
left: -18px;
border-right-color: #f3f6f9;
}
}
.el-icon-warning {
margin-left: 16px;
}
}
}
.item-right {
width: 100%;
justify-content: right;
.user-name {
text-align: right;
padding: 0 52px 0 0;
}
.item-content-flex {
justify-content: end;
.user-img {
margin: 0 0 0 20px;
}
.content {
background-color: #90e287;
span {
border-left-color: #90e287;
right: -18px;
}
}
.el-icon-warning {
margin-right: 16px;
}
.voice-info {
text-align: right;
}
}
}
}
.addressBook-left__list--wrapper::-webkit-scrollbar,
.content-right-info::-webkit-scrollbar {
width: 4px;
}
.addressBook-left__list--wrapper::-webkit-scrollbar-thumb,
.content-right-info::-webkit-scrollbar-thumb {
border-radius: 10px;
background: rgba(0, 0, 0, 0.2);
}
.addressBook-left__list--wrapper::-webkit-scrollbar-track
.content-right-info::-webkit-scrollbar-track {
border-radius: 0;
background: rgba(0, 0, 0, 0.1);
}
.msg-list-pagination {
position: absolute;
bottom: 0;
width: calc(100% - 32px);
text-align: center;
}
}
</style>