perf: 优化消息列表

This commit is contained in:
kuaifan 2022-05-12 15:10:21 +08:00
parent 1d4602db0b
commit a13bc3f0bd
6 changed files with 587 additions and 595 deletions

View File

@ -53,6 +53,7 @@
"vue-resize-observer": "^2.0.16", "vue-resize-observer": "^2.0.16",
"vue-router": "^3.5.3", "vue-router": "^3.5.3",
"vue-template-compiler": "^2.6.14", "vue-template-compiler": "^2.6.14",
"vue-virtual-scroller-hi": "^1.0.10-1",
"vuedraggable": "^2.24.3", "vuedraggable": "^2.24.3",
"vuex": "^3.6.2", "vuex": "^3.6.2",
"webpack": "^5.69.1", "webpack": "^5.69.1",

View File

@ -1,6 +1,6 @@
<template> <template>
<div <div
v-if="dialogData && dialogData.id" v-if="isReady"
class="dialog-wrapper" class="dialog-wrapper"
@drop.prevent="chatPasteDrag($event, 'drag')" @drop.prevent="chatPasteDrag($event, 'drag')"
@dragover.prevent="chatDragOver(true, $event)" @dragover.prevent="chatDragOver(true, $event)"
@ -51,42 +51,38 @@
</ETooltip> </ETooltip>
</div> </div>
</slot> </slot>
<ScrollerY <DynamicScroller
ref="scroller" ref="scroller"
class="dialog-scroller overlay-y" :items="allMsgs"
:style="{opacity: visible ? 1 : 0}" :min-item-size="58"
:auto-bottom="isAutoBottom" @onScroll="onScroll"
@on-scroll="chatScroll" class="dialog-scroller overlay-y">
static> <template #before>
<div ref="manageList" class="dialog-list"> <div v-if="dialogData.hasMorePages" class="dialog-item history" @click="loadNextPage">{{$L('加载历史消息')}}</div>
<ul> <div v-else-if="dialogData.loading > 0 && dialogMsgList.length === 0" class="dialog-item loading"><Loading/></div>
<li v-if="dialogData.hasMorePages" class="history" @click="loadNextPage">{{$L('加载历史消息')}}</li> <div v-else-if="dialogMsgList.length === 0" class="dialog-item nothing">{{$L('暂无消息')}}</div>
<li v-else-if="dialogData.loading > 0 && dialogMsgList.length === 0" class="loading"><Loading/></li> </template>
<li v-else-if="dialogMsgList.length === 0" class="nothing">{{$L('暂无消息')}}</li> <template v-slot="{ item, index, active }">
<li <DynamicScrollerItem
v-for="item in dialogMsgList" :item="item"
:id="'view_' + item.id" :active="active"
:key="item.id" :size-dependencies="[item.msg]"
:class="{self:item.userid == userId, 'history-tip': topId == item.id}"> :data-index="index"
<em v-if="topId == item.id" class="history-text">{{$L('历史消息')}}</em> :data-active="active"
<div class="dialog-avatar"> :class="{
<UserAvatar :userid="item.userid" :tooltipDisabled="item.userid == userId" :size="30"/> 'dialog-item': true,
</div> 'self': item.userid == userId,
<DialogView :msg-data="item" :dialog-type="dialogData.type"/> 'history-tip': topId == item.id
</li> }"
<li @click.native="">
v-for="item in tempMsgList" <em v-if="topId == item.id" class="history-text">{{$L('历史消息')}}</em>
:id="'tmp_' + item.id" <div class="dialog-avatar">
:key="'tmp_' + item.id" <UserAvatar :userid="item.userid" :tooltipDisabled="item.userid == userId" :size="30"/>
:class="{self:item.userid == userId}"> </div>
<div class="dialog-avatar"> <DialogView :msg-data="item" :dialog-type="dialogData.type"/>
<UserAvatar :userid="item.userid" :tooltipDisabled="item.userid == userId" :size="30"/> </DynamicScrollerItem>
</div> </template>
<DialogView :msg-data="item" :dialog-type="dialogData.type"/> </DynamicScroller>
</li>
</ul>
</div>
</ScrollerY>
<div :class="['dialog-footer', msgNew > 0 && dialogMsgList.length > 0 ? 'newmsg' : '']" @click="onActive"> <div :class="['dialog-footer', msgNew > 0 && dialogMsgList.length > 0 ? 'newmsg' : '']" @click="onActive">
<div class="dialog-newmsg" @click="onToBottom">{{$L('' + msgNew + '条新消息')}}</div> <div class="dialog-newmsg" @click="onToBottom">{{$L('' + msgNew + '条新消息')}}</div>
<div class="dialog-input"> <div class="dialog-input">
@ -161,19 +157,30 @@
</template> </template>
<script> <script>
import ScrollerY from "../../../components/ScrollerY";
import {mapState} from "vuex"; import {mapState} from "vuex";
import DialogView from "./DialogView"; import DialogView from "./DialogView";
import DialogUpload from "./DialogUpload"; import DialogUpload from "./DialogUpload";
import {Store} from "le5le-store";
import UserInput from "../../../components/UserInput"; import UserInput from "../../../components/UserInput";
import DrawerOverlay from "../../../components/DrawerOverlay"; import DrawerOverlay from "../../../components/DrawerOverlay";
import DialogGroupInfo from "./DialogGroupInfo"; import DialogGroupInfo from "./DialogGroupInfo";
import ChatInput from "./ChatInput"; import ChatInput from "./ChatInput";
import { DynamicScroller, DynamicScrollerItem } from 'vue-virtual-scroller-hi'
import 'vue-virtual-scroller-hi/dist/vue-virtual-scroller.css'
export default { export default {
name: "DialogWrapper", name: "DialogWrapper",
components: {ChatInput, DialogGroupInfo, DrawerOverlay, UserInput, DialogUpload, DialogView, ScrollerY}, components: {
DynamicScroller,
DynamicScrollerItem,
ChatInput,
DialogGroupInfo,
DrawerOverlay,
UserInput,
DialogUpload,
DialogView
},
props: { props: {
dialogId: { dialogId: {
type: Number, type: Number,
@ -183,21 +190,13 @@ export default {
data() { data() {
return { return {
visible: true,
autoBottom: true,
autoInterval: null,
dialogDrag: false,
inputFocus: false,
msgText: '', msgText: '',
msgNew: 0, msgNew: 0,
topId: 0, topId: 0,
allMsgs: [],
tempMsgs: [], tempMsgs: [],
dialogMsgSubscribe: null,
pasteShow: false, pasteShow: false,
pasteFile: [], pasteFile: [],
pasteItem: [], pasteItem: [],
@ -206,19 +205,17 @@ export default {
createGroupData: {}, createGroupData: {},
createGroupLoad: 0, createGroupLoad: 0,
dialogDrag: false,
groupInfoShow: false, groupInfoShow: false,
} }
}, },
mounted() { mounted() {
this.dialogMsgSubscribe = Store.subscribe('dialogMsgPush', this.addDialogMsg);
}, },
beforeDestroy() { beforeDestroy() {
if (this.dialogMsgSubscribe) {
this.dialogMsgSubscribe.unsubscribe();
this.dialogMsgSubscribe = null;
}
}, },
computed: { computed: {
@ -230,12 +227,16 @@ export default {
'wsOpenNum', 'wsOpenNum',
]), ]),
isReady() {
return this.dialogId > 0 && this.dialogData.id > 0
},
dialogData() { dialogData() {
return this.cacheDialogs.find(({id}) => id == this.dialogId) || {}; return this.cacheDialogs.find(({id}) => id == this.dialogId) || {};
}, },
dialogMsgList() { dialogMsgList() {
if (!this.dialogId) { if (!this.isReady) {
return []; return [];
} }
return $A.cloneJSON(this.dialogMsgs.filter(({dialog_id}) => { return $A.cloneJSON(this.dialogMsgs.filter(({dialog_id}) => {
@ -245,15 +246,8 @@ export default {
}); });
}, },
isAutoBottom() {
if (this.inputFocus && !this.isDesktop) {
return false;
}
return this.autoBottom
},
tempMsgList() { tempMsgList() {
if (!this.dialogId) { if (!this.isReady) {
return []; return [];
} }
return $A.cloneJSON(this.tempMsgs.filter(({dialog_id}) => { return $A.cloneJSON(this.tempMsgs.filter(({dialog_id}) => {
@ -261,6 +255,14 @@ export default {
})); }));
}, },
allMsgList() {
const {dialogMsgList, tempMsgList} = this;
if (tempMsgList.length > 0) {
dialogMsgList.push(...tempMsgList);
}
return dialogMsgList;
},
peopleNum() { peopleNum() {
return this.dialogData.type === 'group' ? $A.runNum(this.dialogData.people) : 0; return this.dialogData.type === 'group' ? $A.runNum(this.dialogData.people) : 0;
}, },
@ -313,20 +315,7 @@ export default {
if (id) { if (id) {
this.msgNew = 0; this.msgNew = 0;
this.topId = -1; this.topId = -1;
this.visible = false; this.$store.dispatch("getDialogMsgs", id).then(this.onToBottom).catch(_ => {});
if (this.dialogMsgList.length > 0) {
setTimeout(_ => {
this.onToBottom();
this.visible = true;
}, 10);
}
let startTime = new Date().getTime();
this.$store.dispatch("getDialogMsgs", id).then(_ => {
setTimeout(_ => {
this.onToBottom();
this.visible = true;
}, Math.max(0, 100 - (new Date().getTime() - startTime)));
});
} }
}, },
immediate: true immediate: true
@ -335,7 +324,21 @@ export default {
wsOpenNum(num) { wsOpenNum(num) {
if (num <= 1) return if (num <= 1) return
this.$store.dispatch("getDialogMsgs", this.dialogId).catch(_ => {}); this.$store.dispatch("getDialogMsgs", this.dialogId).catch(_ => {});
} },
allMsgList(newList, oldList) {
const {scrollE} = this.scrollInfo();
this.allMsgs = newList;
this.$nextTick(_ => {
if (scrollE > 10 && oldList.length > 0) {
const lastId = oldList[oldList.length - 1].id
const tmpList = newList.filter(item => item.id && item.id > lastId)
this.msgNew += tmpList.length
} else {
this.onToBottom();
}
})
},
}, },
methods: { methods: {
@ -353,6 +356,12 @@ export default {
} }
msgText = msgText.replace(/<\/span> <\/p>$/, "</span></p>") msgText = msgText.replace(/<\/span> <\/p>$/, "</span></p>")
// //
if (!this.isDesktop) {
this.$refs.input.blur();
}
this.onToBottom();
this.onActive();
//
let tempId = $A.randomString(16); let tempId = $A.randomString(16);
this.tempMsgs.push({ this.tempMsgs.push({
id: tempId, id: tempId,
@ -363,11 +372,6 @@ export default {
text: msgText, text: msgText,
}, },
}); });
if (!this.isDesktop) {
this.$refs.input.blur();
}
this.onToBottom();
this.onActive();
// //
this.$store.dispatch("call", { this.$store.dispatch("call", {
url: 'dialog/msg/sendtext', url: 'dialog/msg/sendtext',
@ -441,6 +445,12 @@ export default {
chatFile(type, file) { chatFile(type, file) {
switch (type) { switch (type) {
case 'progress': case 'progress':
if (!this.isDesktop) {
this.$refs.input.blur();
}
this.onToBottom();
this.onActive();
//
this.tempMsgs.push({ this.tempMsgs.push({
id: file.tempId, id: file.tempId,
dialog_id: this.dialogData.id, dialog_id: this.dialogData.id,
@ -448,11 +458,6 @@ export default {
userid: this.userId, userid: this.userId,
msg: { }, msg: { },
}); });
if (!this.isDesktop) {
this.$refs.input.blur();
}
this.onToBottom();
this.onActive();
break; break;
case 'error': case 'error':
@ -479,31 +484,11 @@ export default {
this.onActive(); this.onActive();
}, },
chatScroll(res) {
switch (res.directionreal) {
case 'up':
if (res.scrollE < 10) {
this.msgNew = 0;
this.autoBottom = true;
}
break;
case 'down':
this.autoBottom = false;
break;
}
if (res.scale >= 1) {
this.msgNew = 0;
this.autoBottom = true;
}
},
onEventFocus(e) { onEventFocus(e) {
this.inputFocus = true;
this.$emit("on-focus", e) this.$emit("on-focus", e)
}, },
onEventBlur(e) { onEventBlur(e) {
this.inputFocus = false;
this.$emit("on-blur", e) this.$emit("on-blur", e)
}, },
@ -518,8 +503,10 @@ export default {
}, },
onToBottom() { onToBottom() {
this.autoBottom = true; this.msgNew = 0;
this.$refs.scroller && this.$refs.scroller.autoToBottom(); if (this.isReady) {
this.$refs.scroller.scrollToBottom();
}
}, },
openProject() { openProject() {
@ -537,30 +524,18 @@ export default {
}, },
loadNextPage() { loadNextPage() {
let topId = this.dialogMsgList[0].id; let tmpId = this.allMsgs[0].id;
this.$store.dispatch('getDialogMoreMsgs', this.dialogId).then(() => { this.$store.dispatch('getDialogMoreMsgs', this.dialogId).then(() => {
this.$nextTick(() => { this.$nextTick(() => {
this.topId = topId; this.topId = tmpId;
$A.scrollToView(document.getElementById("view_" + topId), { const index = this.allMsgs.findIndex(({id}) => id == tmpId);
behavior: 'instant', if (index > -1) {
inline: 'start', this.$refs.scroller.scrollToItem(index);
}) }
}); });
}).catch(() => {}) }).catch(() => {})
}, },
addDialogMsg() {
if (this.isAutoBottom) {
this.$nextTick(this.onToBottom);
} else {
this.$nextTick(() => {
if (this.$refs.scroller && this.$refs.scroller.scrollInfo().scrollE > 10) {
this.msgNew++;
}
})
}
},
openCreateGroup() { openCreateGroup() {
this.createGroupData = { this.createGroupData = {
userids: this.dialogData.dialog_user ? [this.userId, this.dialogData.dialog_user.userid] : [this.userId], userids: this.dialogData.dialog_user ? [this.userId, this.dialogData.dialog_user.userid] : [this.userId],
@ -586,6 +561,36 @@ export default {
this.createGroupLoad--; this.createGroupLoad--;
}); });
}, },
scrollInfo() {
if (!this.isReady) {
return {
scale: 0, //
scrollY: 0, //
scrollE: 0, //
}
}
const scrollerView = this.$refs.scroller.$el;
let wInnerH = scrollerView.clientHeight;
let wScrollY = scrollerView.scrollTop;
let bScrollH = scrollerView.scrollHeight;
this.scrollY = wScrollY;
return {
scale: wScrollY / (bScrollH - wInnerH),
scrollY: wScrollY,
scrollE: bScrollH - wInnerH - wScrollY,
}
},
onScroll() {
this.__onScroll && clearTimeout(this.__onScroll);
this.__onScroll = setTimeout(_ => {
const {scrollE} = this.scrollInfo();
if (scrollE <= 10) {
this.msgNew = 0;
}
}, 100)
},
} }
} }
</script> </script>

View File

@ -179,37 +179,33 @@ body.dark-mode-reverse {
} }
} }
.dialog-scroller { .dialog-scroller {
.dialog-list { .dialog-item {
> ul { .dialog-view {
> li { .dialog-head {
.dialog-view { .dialog-content {
.dialog-head { background-color: #e1e1e1;
.dialog-content { .content-text {
background-color: #e1e1e1; color: #ffffff;
.content-text { .content-text {
color: #ffffff; > pre {
.content-text { .mention {
> pre { color: #000000;
.mention {
color: #000000;
}
}
} }
} }
} }
} }
} }
&.self { }
.dialog-view { }
.dialog-head { &.self {
.dialog-content { .dialog-view {
background-color: #8bcf70; .dialog-head {
.content-text { .dialog-content {
> pre { background-color: #8bcf70;
.mention { .content-text {
color: #000000; > pre {
} .mention {
} color: #000000;
} }
} }
} }

View File

@ -180,478 +180,469 @@
} }
.dialog-scroller { .dialog-scroller {
position: relative;
flex: 1; flex: 1;
padding: 0 32px; position: relative;
overflow: auto; padding: 16px 32px 0;
.dialog-list { .dialog-item {
> ul { display: flex;
> li { flex-direction: row;
display: flex; align-items: flex-start;
flex-direction: row; list-style: none;
align-items: flex-start; padding-bottom: 16px;
list-style: none;
margin-bottom: 16px;
&:first-child { .dialog-avatar {
margin-top: 16px; position: relative;
} margin-bottom: 20px;
flex-shrink: 0;
width: 30px;
height: 30px;
}
.dialog-avatar { .dialog-view {
position: relative; display: flex;
margin-bottom: 20px; flex-direction: column;
flex-shrink: 0; align-items: flex-start;
width: 30px; margin: 0 0 0 8px;
height: 30px; position: relative;
}
.dialog-view { &.text {
display: flex; max-width: 70%;
flex-direction: column; }
align-items: flex-start;
margin: 0 0 0 8px;
position: relative;
&.text { &:hover {
max-width: 70%; .dialog-head {
} .dialog-menu {
&:hover {
.dialog-head {
.dialog-menu {
opacity: 1;
}
}
}
.dialog-username {
margin-bottom: 6px;
opacity: 0.8;
}
.dialog-head {
display: flex;
align-items: flex-start;
.dialog-content {
background-color: #F4F5F7;
padding: 8px;
min-width: 32px;
border-radius: 0 6px 6px 6px;
display: flex;
align-items: flex-start;
&.an-emoticon,
&.an-emoji,
&.two-emoji,
&.three-emoji {
background-color: transparent !important;
}
&.an-emoji {
.content-text {
> pre {
font-size: 72px;
line-height: 1;
}
}
}
&.two-emoji {
.content-text {
> pre {
font-size: 52px;
line-height: 1;
}
}
}
&.three-emoji {
.content-text {
> pre {
font-size: 32px;
line-height: 1;
}
}
}
.content-text {
color: #333333;
> pre {
display: block;
margin: 0;
padding: 0;
line-height: 1.5;
white-space: pre-wrap;
word-wrap: break-word;
word-break: break-word;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
font-size: 14px;
ol,
ul {
li {
list-style-type: none;
&::before {
display: inline-block;
white-space: nowrap;
width: 1.2em;
color: #0088ff;
text-align: left;
margin-right: 0.2em;
}
}
}
ul {
li {
&::before {
content: '\2022';
font-weight: 900;
}
}
}
ol {
li {
counter-reset: list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
counter-increment: list-0;
&:before {
content: counter(list-0, decimal) '. ';
}
}
}
blockquote {
border-left: 4px solid #ccc;
margin-bottom: 5px;
margin-top: 5px;
padding-left: 16px;
}
pre {
white-space: pre-wrap;
margin: 5px 0;
padding: 5px 10px;
border-radius: 3px;
background-color: #23241f;
color: #f8f8f2;
overflow: visible;
}
img {
cursor: pointer;
max-width: 220px;
max-height: 220px;
vertical-align: bottom;
&.emoticon {
max-width: 150px;
max-height: 150px;
}
}
.mention {
color: $flow-status-end-color;
background-color: transparent;
user-select: auto;
padding: 0;
margin: 0;
> span {
margin: 0;
}
&.task {
cursor: pointer;
}
&.me {
font-size: 13px;
font-weight: 600;
padding: 3px 4px;
color: #ffffff;
background-color: $primary-color;
}
}
}
}
.content-file {
&.file {
display: inline-block;
.file-box {
background-color: #ffffff;
display: flex;
align-items: center;
padding: 10px 14px;
border-radius: 3px;
width: 220px;
.file-thumb {
width: 36px;
}
.file-info {
margin-left: 12px;
display: flex;
flex-direction: column;
justify-content: center;
.file-name {
color: #333333;
font-size: 14px;
line-height: 18px;
word-break: break-all;
text-overflow: ellipsis;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.file-size {
padding-top: 4px;
color: #666666;
font-size: 14px;
}
}
}
}
&.img {
padding: 0;
display: flex;
max-width: 220px;
max-height: 220px;
border-radius: 6px;
background-color: transparent;
overflow: hidden;
.file-img {
display: flex;
cursor: pointer;
}
}
}
.content-loading {
display: flex;
.common-loading {
width: 20px;
height: 20px;
margin: 4px;
}
}
.content-unknown {
text-decoration: underline;
}
}
.dialog-menu {
opacity: 0;
margin-left: 6px;
transition: all 0.3s;
.menu-icon {
display: flex;
align-items: center;
border-radius: 4px;
border: 1px solid #ddd;
background-color: #ffffff;
> i {
flex: 1;
display: inline-block;
padding: 4px 6px;
color: #999;
font-size: 13px;
cursor: pointer;
& + i {
border-left: 1px solid #ddd;
}
&:hover {
color: #777;
}
}
}
}
}
.dialog-foot {
display: flex;
align-items: center;
padding-top: 4px;
height: 21px;
line-height: 1;
.common-loading {
margin: 0 2px;
width: 10px;
height: 10px;
}
.time {
color: #bbbbbb;
font-size: 12px;
}
.done {
display: none;
margin-left: 4px;
transform: scale(0.9);
font-size: 12px;
color: $primary-color;
}
.percent {
display: none;
margin-left: 4px;
align-items: center;
cursor: pointer;
}
}
}
.dialog-action {
align-self: flex-start;
display: flex;
align-items: flex-start;
height: 100%;
> * {
margin: 0 5px;
}
}
&.history {
cursor: pointer;
justify-content: center;
font-size: 13px;
padding: 3px 0;
margin: 12px 0;
opacity: 0.6;
transition: opacity 0.2s;
&:hover {
opacity: 1; opacity: 1;
} }
} }
}
&.history-tip { .dialog-username {
position: relative; margin-bottom: 6px;
padding-top: 60px; opacity: 0.8;
}
.history-text { .dialog-head {
font-style: normal; display: flex;
position: absolute; align-items: flex-start;
top: 10px;
left: 50%; .dialog-content {
height: 22px; background-color: #F4F5F7;
line-height: 22px; padding: 8px;
padding: 0 48px; min-width: 32px;
text-align: center; border-radius: 0 6px 6px 6px;
font-size: 12px; display: flex;
border-radius: 2px; align-items: flex-start;
background: #f5f5f5;
transform: translateX(-50%); &.an-emoticon,
&.an-emoji,
&.two-emoji,
&.three-emoji {
background-color: transparent !important;
} }
}
&.loading { &.an-emoji {
padding: 12px 0; .content-text {
justify-content: center; > pre {
font-size: 72px;
.common-loading { line-height: 1;
margin: 0; }
width: 18px; }
height: 18px;
} }
}
&.nothing { &.two-emoji {
position: absolute; .content-text {
top: 50%; > pre {
left: 50%; font-size: 52px;
transform: translate(-50%, -50%); line-height: 1;
color: #999999; }
} }
}
&.bottom { &.three-emoji {
height: 0; .content-text {
margin: 0; > pre {
padding: 0; font-size: 32px;
} line-height: 1;
}
}
}
&.self { .content-text {
flex-direction: row-reverse; color: #333333;
.dialog-view { > pre {
align-items: flex-end; display: block;
margin: 0 8px 0 0; margin: 0;
padding: 0;
line-height: 1.5;
white-space: pre-wrap;
word-wrap: break-word;
word-break: break-word;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
font-size: 14px;
.dialog-head { ol,
flex-direction: row-reverse; ul {
li {
list-style-type: none;
.dialog-content { &::before {
background-color: $primary-color; display: inline-block;
border-radius: 6px 0 6px 6px; white-space: nowrap;
width: 1.2em;
.content-text { color: #0088ff;
color: #ffffff; text-align: left;
margin-right: 0.2em;
> pre {
.mention {
color: #333333;
&.me {
font-size: 14px;
font-weight: normal;
padding: 3px 0;
background-color: transparent;
}
}
} }
} }
}
.content-file { ul {
&.file { li {
background-color: #F4F5F7; &::before {
content: '\2022';
font-weight: 900;
}
}
}
ol {
li {
counter-reset: list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
counter-increment: list-0;
&:before {
content: counter(list-0, decimal) '. ';
}
}
}
blockquote {
border-left: 4px solid #ccc;
margin-bottom: 5px;
margin-top: 5px;
padding-left: 16px;
}
pre {
white-space: pre-wrap;
margin: 5px 0;
padding: 5px 10px;
border-radius: 3px;
background-color: #23241f;
color: #f8f8f2;
overflow: visible;
}
img {
cursor: pointer;
max-width: 220px;
max-height: 220px;
vertical-align: bottom;
&.emoticon {
max-width: 150px;
max-height: 150px;
}
}
.mention {
color: $flow-status-end-color;
background-color: transparent;
user-select: auto;
padding: 0;
margin: 0;
> span {
margin: 0;
}
&.task {
cursor: pointer;
}
&.me {
font-size: 13px;
font-weight: 600;
padding: 3px 4px;
color: #ffffff;
background-color: $primary-color;
}
}
}
}
.content-file {
&.file {
display: inline-block;
.file-box {
background-color: #ffffff;
display: flex;
align-items: center;
padding: 10px 14px;
border-radius: 3px;
width: 220px;
.file-thumb {
width: 36px;
}
.file-info {
margin-left: 12px;
display: flex;
flex-direction: column;
justify-content: center;
.file-name {
color: #333333;
font-size: 14px;
line-height: 18px;
word-break: break-all;
text-overflow: ellipsis;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
} }
&.img { .file-size {
border-radius: 6px; padding-top: 4px;
color: #666666;
font-size: 14px;
}
}
}
}
&.img {
padding: 0;
display: flex;
max-width: 220px;
max-height: 220px;
border-radius: 6px;
background-color: transparent;
overflow: hidden;
.file-img {
display: flex;
cursor: pointer;
}
}
}
.content-loading {
display: flex;
.common-loading {
width: 20px;
height: 20px;
margin: 4px;
}
}
.content-unknown {
text-decoration: underline;
}
}
.dialog-menu {
opacity: 0;
margin-left: 6px;
transition: all 0.3s;
.menu-icon {
display: flex;
align-items: center;
border-radius: 4px;
border: 1px solid #ddd;
background-color: #ffffff;
> i {
flex: 1;
display: inline-block;
padding: 4px 6px;
color: #999;
font-size: 13px;
cursor: pointer;
& + i {
border-left: 1px solid #ddd;
}
&:hover {
color: #777;
}
}
}
}
}
.dialog-foot {
display: flex;
align-items: center;
padding-top: 4px;
height: 21px;
line-height: 1;
.common-loading {
margin: 0 2px;
width: 10px;
height: 10px;
}
.time {
color: #bbbbbb;
font-size: 12px;
}
.done {
display: none;
margin-left: 4px;
transform: scale(0.9);
font-size: 12px;
color: $primary-color;
}
.percent {
display: none;
margin-left: 4px;
align-items: center;
cursor: pointer;
}
}
}
.dialog-action {
align-self: flex-start;
display: flex;
align-items: flex-start;
height: 100%;
> * {
margin: 0 5px;
}
}
&.history {
cursor: pointer;
justify-content: center;
font-size: 13px;
padding: 3px 0;
margin: 12px 0;
opacity: 0.6;
transition: opacity 0.2s;
&:hover {
opacity: 1;
}
}
&.history-tip {
position: relative;
padding-top: 60px;
.history-text {
font-style: normal;
position: absolute;
top: 10px;
left: 50%;
height: 22px;
line-height: 22px;
padding: 0 48px;
text-align: center;
font-size: 12px;
border-radius: 2px;
background: #f5f5f5;
transform: translateX(-50%);
}
}
&.loading {
padding: 12px 0;
justify-content: center;
.common-loading {
margin: 0;
width: 18px;
height: 18px;
}
}
&.nothing {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: #999999;
}
&.bottom {
height: 0;
margin: 0;
padding: 0;
}
&.self {
flex-direction: row-reverse;
.dialog-view {
align-items: flex-end;
margin: 0 8px 0 0;
.dialog-head {
flex-direction: row-reverse;
.dialog-content {
background-color: $primary-color;
border-radius: 6px 0 6px 6px;
.content-text {
color: #ffffff;
> pre {
.mention {
color: #333333;
&.me {
font-size: 14px;
font-weight: normal;
padding: 3px 0;
background-color: transparent; background-color: transparent;
} }
} }
} }
.dialog-menu {
margin-left: 0;
margin-right: 6px;
}
} }
.dialog-foot { .content-file {
.done { &.file {
display: inline-block; background-color: #F4F5F7;
} }
.percent { &.img {
display: flex; border-radius: 6px;
background-color: transparent;
} }
} }
} }
.dialog-menu {
margin-left: 0;
margin-right: 6px;
}
}
.dialog-foot {
.done {
display: inline-block;
}
.percent {
display: flex;
}
} }
} }
} }
@ -877,7 +868,8 @@
} }
} }
.dialog-scroller { .dialog-scroller {
padding: 0 14px; padding-right: 14px;
padding-left: 14px;
} }
.dialog-footer { .dialog-footer {
background-color: #f8f8f8; background-color: #f8f8f8;

View File

@ -81,9 +81,6 @@
padding: 0 12px; padding: 0 12px;
height: 64px; height: 64px;
} }
.dialog-scroller {
padding: 0 14px;
}
} }
} }
} }

View File

@ -637,7 +637,8 @@
} }
.dialog-wrapper { .dialog-wrapper {
.dialog-scroller { .dialog-scroller {
padding: 0 16px 0 32px padding-right: 16px;
padding-left: 32px;
} }
.dialog-footer { .dialog-footer {
padding: 0 14px 0 28px; padding: 0 14px 0 28px;