mirror of
https://github.com/kuaifan/dootask.git
synced 2026-03-06 17:37:06 +00:00
perf: 优化消息列表
This commit is contained in:
parent
1d4602db0b
commit
a13bc3f0bd
@ -53,6 +53,7 @@
|
||||
"vue-resize-observer": "^2.0.16",
|
||||
"vue-router": "^3.5.3",
|
||||
"vue-template-compiler": "^2.6.14",
|
||||
"vue-virtual-scroller-hi": "^1.0.10-1",
|
||||
"vuedraggable": "^2.24.3",
|
||||
"vuex": "^3.6.2",
|
||||
"webpack": "^5.69.1",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="dialogData && dialogData.id"
|
||||
v-if="isReady"
|
||||
class="dialog-wrapper"
|
||||
@drop.prevent="chatPasteDrag($event, 'drag')"
|
||||
@dragover.prevent="chatDragOver(true, $event)"
|
||||
@ -51,42 +51,38 @@
|
||||
</ETooltip>
|
||||
</div>
|
||||
</slot>
|
||||
<ScrollerY
|
||||
<DynamicScroller
|
||||
ref="scroller"
|
||||
class="dialog-scroller overlay-y"
|
||||
:style="{opacity: visible ? 1 : 0}"
|
||||
:auto-bottom="isAutoBottom"
|
||||
@on-scroll="chatScroll"
|
||||
static>
|
||||
<div ref="manageList" class="dialog-list">
|
||||
<ul>
|
||||
<li v-if="dialogData.hasMorePages" class="history" @click="loadNextPage">{{$L('加载历史消息')}}</li>
|
||||
<li v-else-if="dialogData.loading > 0 && dialogMsgList.length === 0" class="loading"><Loading/></li>
|
||||
<li v-else-if="dialogMsgList.length === 0" class="nothing">{{$L('暂无消息')}}</li>
|
||||
<li
|
||||
v-for="item in dialogMsgList"
|
||||
:id="'view_' + item.id"
|
||||
:key="item.id"
|
||||
:class="{self:item.userid == userId, 'history-tip': topId == item.id}">
|
||||
<em v-if="topId == item.id" class="history-text">{{$L('历史消息')}}</em>
|
||||
<div class="dialog-avatar">
|
||||
<UserAvatar :userid="item.userid" :tooltipDisabled="item.userid == userId" :size="30"/>
|
||||
</div>
|
||||
<DialogView :msg-data="item" :dialog-type="dialogData.type"/>
|
||||
</li>
|
||||
<li
|
||||
v-for="item in tempMsgList"
|
||||
:id="'tmp_' + item.id"
|
||||
:key="'tmp_' + item.id"
|
||||
:class="{self:item.userid == userId}">
|
||||
<div class="dialog-avatar">
|
||||
<UserAvatar :userid="item.userid" :tooltipDisabled="item.userid == userId" :size="30"/>
|
||||
</div>
|
||||
<DialogView :msg-data="item" :dialog-type="dialogData.type"/>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</ScrollerY>
|
||||
:items="allMsgs"
|
||||
:min-item-size="58"
|
||||
@onScroll="onScroll"
|
||||
class="dialog-scroller overlay-y">
|
||||
<template #before>
|
||||
<div v-if="dialogData.hasMorePages" class="dialog-item history" @click="loadNextPage">{{$L('加载历史消息')}}</div>
|
||||
<div v-else-if="dialogData.loading > 0 && dialogMsgList.length === 0" class="dialog-item loading"><Loading/></div>
|
||||
<div v-else-if="dialogMsgList.length === 0" class="dialog-item nothing">{{$L('暂无消息')}}</div>
|
||||
</template>
|
||||
<template v-slot="{ item, index, active }">
|
||||
<DynamicScrollerItem
|
||||
:item="item"
|
||||
:active="active"
|
||||
:size-dependencies="[item.msg]"
|
||||
:data-index="index"
|
||||
:data-active="active"
|
||||
:class="{
|
||||
'dialog-item': true,
|
||||
'self': item.userid == userId,
|
||||
'history-tip': topId == item.id
|
||||
}"
|
||||
@click.native="">
|
||||
<em v-if="topId == item.id" class="history-text">{{$L('历史消息')}}</em>
|
||||
<div class="dialog-avatar">
|
||||
<UserAvatar :userid="item.userid" :tooltipDisabled="item.userid == userId" :size="30"/>
|
||||
</div>
|
||||
<DialogView :msg-data="item" :dialog-type="dialogData.type"/>
|
||||
</DynamicScrollerItem>
|
||||
</template>
|
||||
</DynamicScroller>
|
||||
<div :class="['dialog-footer', msgNew > 0 && dialogMsgList.length > 0 ? 'newmsg' : '']" @click="onActive">
|
||||
<div class="dialog-newmsg" @click="onToBottom">{{$L('有' + msgNew + '条新消息')}}</div>
|
||||
<div class="dialog-input">
|
||||
@ -161,19 +157,30 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ScrollerY from "../../../components/ScrollerY";
|
||||
import {mapState} from "vuex";
|
||||
import DialogView from "./DialogView";
|
||||
import DialogUpload from "./DialogUpload";
|
||||
import {Store} from "le5le-store";
|
||||
import UserInput from "../../../components/UserInput";
|
||||
import DrawerOverlay from "../../../components/DrawerOverlay";
|
||||
import DialogGroupInfo from "./DialogGroupInfo";
|
||||
import ChatInput from "./ChatInput";
|
||||
|
||||
import { DynamicScroller, DynamicScrollerItem } from 'vue-virtual-scroller-hi'
|
||||
import 'vue-virtual-scroller-hi/dist/vue-virtual-scroller.css'
|
||||
|
||||
export default {
|
||||
name: "DialogWrapper",
|
||||
components: {ChatInput, DialogGroupInfo, DrawerOverlay, UserInput, DialogUpload, DialogView, ScrollerY},
|
||||
components: {
|
||||
DynamicScroller,
|
||||
DynamicScrollerItem,
|
||||
ChatInput,
|
||||
DialogGroupInfo,
|
||||
DrawerOverlay,
|
||||
UserInput,
|
||||
DialogUpload,
|
||||
DialogView
|
||||
},
|
||||
|
||||
props: {
|
||||
dialogId: {
|
||||
type: Number,
|
||||
@ -183,21 +190,13 @@ export default {
|
||||
|
||||
data() {
|
||||
return {
|
||||
visible: true,
|
||||
autoBottom: true,
|
||||
autoInterval: null,
|
||||
|
||||
dialogDrag: false,
|
||||
inputFocus: false,
|
||||
|
||||
msgText: '',
|
||||
msgNew: 0,
|
||||
topId: 0,
|
||||
|
||||
allMsgs: [],
|
||||
tempMsgs: [],
|
||||
|
||||
dialogMsgSubscribe: null,
|
||||
|
||||
pasteShow: false,
|
||||
pasteFile: [],
|
||||
pasteItem: [],
|
||||
@ -206,19 +205,17 @@ export default {
|
||||
createGroupData: {},
|
||||
createGroupLoad: 0,
|
||||
|
||||
dialogDrag: false,
|
||||
groupInfoShow: false,
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.dialogMsgSubscribe = Store.subscribe('dialogMsgPush', this.addDialogMsg);
|
||||
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
if (this.dialogMsgSubscribe) {
|
||||
this.dialogMsgSubscribe.unsubscribe();
|
||||
this.dialogMsgSubscribe = null;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
computed: {
|
||||
@ -230,12 +227,16 @@ export default {
|
||||
'wsOpenNum',
|
||||
]),
|
||||
|
||||
isReady() {
|
||||
return this.dialogId > 0 && this.dialogData.id > 0
|
||||
},
|
||||
|
||||
dialogData() {
|
||||
return this.cacheDialogs.find(({id}) => id == this.dialogId) || {};
|
||||
},
|
||||
|
||||
dialogMsgList() {
|
||||
if (!this.dialogId) {
|
||||
if (!this.isReady) {
|
||||
return [];
|
||||
}
|
||||
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() {
|
||||
if (!this.dialogId) {
|
||||
if (!this.isReady) {
|
||||
return [];
|
||||
}
|
||||
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() {
|
||||
return this.dialogData.type === 'group' ? $A.runNum(this.dialogData.people) : 0;
|
||||
},
|
||||
@ -313,20 +315,7 @@ export default {
|
||||
if (id) {
|
||||
this.msgNew = 0;
|
||||
this.topId = -1;
|
||||
this.visible = false;
|
||||
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)));
|
||||
});
|
||||
this.$store.dispatch("getDialogMsgs", id).then(this.onToBottom).catch(_ => {});
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
@ -335,7 +324,21 @@ export default {
|
||||
wsOpenNum(num) {
|
||||
if (num <= 1) return
|
||||
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: {
|
||||
@ -353,6 +356,12 @@ export default {
|
||||
}
|
||||
msgText = msgText.replace(/<\/span> <\/p>$/, "</span></p>")
|
||||
//
|
||||
if (!this.isDesktop) {
|
||||
this.$refs.input.blur();
|
||||
}
|
||||
this.onToBottom();
|
||||
this.onActive();
|
||||
//
|
||||
let tempId = $A.randomString(16);
|
||||
this.tempMsgs.push({
|
||||
id: tempId,
|
||||
@ -363,11 +372,6 @@ export default {
|
||||
text: msgText,
|
||||
},
|
||||
});
|
||||
if (!this.isDesktop) {
|
||||
this.$refs.input.blur();
|
||||
}
|
||||
this.onToBottom();
|
||||
this.onActive();
|
||||
//
|
||||
this.$store.dispatch("call", {
|
||||
url: 'dialog/msg/sendtext',
|
||||
@ -441,6 +445,12 @@ export default {
|
||||
chatFile(type, file) {
|
||||
switch (type) {
|
||||
case 'progress':
|
||||
if (!this.isDesktop) {
|
||||
this.$refs.input.blur();
|
||||
}
|
||||
this.onToBottom();
|
||||
this.onActive();
|
||||
//
|
||||
this.tempMsgs.push({
|
||||
id: file.tempId,
|
||||
dialog_id: this.dialogData.id,
|
||||
@ -448,11 +458,6 @@ export default {
|
||||
userid: this.userId,
|
||||
msg: { },
|
||||
});
|
||||
if (!this.isDesktop) {
|
||||
this.$refs.input.blur();
|
||||
}
|
||||
this.onToBottom();
|
||||
this.onActive();
|
||||
break;
|
||||
|
||||
case 'error':
|
||||
@ -479,31 +484,11 @@ export default {
|
||||
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) {
|
||||
this.inputFocus = true;
|
||||
this.$emit("on-focus", e)
|
||||
},
|
||||
|
||||
onEventBlur(e) {
|
||||
this.inputFocus = false;
|
||||
this.$emit("on-blur", e)
|
||||
},
|
||||
|
||||
@ -518,8 +503,10 @@ export default {
|
||||
},
|
||||
|
||||
onToBottom() {
|
||||
this.autoBottom = true;
|
||||
this.$refs.scroller && this.$refs.scroller.autoToBottom();
|
||||
this.msgNew = 0;
|
||||
if (this.isReady) {
|
||||
this.$refs.scroller.scrollToBottom();
|
||||
}
|
||||
},
|
||||
|
||||
openProject() {
|
||||
@ -537,30 +524,18 @@ export default {
|
||||
},
|
||||
|
||||
loadNextPage() {
|
||||
let topId = this.dialogMsgList[0].id;
|
||||
let tmpId = this.allMsgs[0].id;
|
||||
this.$store.dispatch('getDialogMoreMsgs', this.dialogId).then(() => {
|
||||
this.$nextTick(() => {
|
||||
this.topId = topId;
|
||||
$A.scrollToView(document.getElementById("view_" + topId), {
|
||||
behavior: 'instant',
|
||||
inline: 'start',
|
||||
})
|
||||
this.topId = tmpId;
|
||||
const index = this.allMsgs.findIndex(({id}) => id == tmpId);
|
||||
if (index > -1) {
|
||||
this.$refs.scroller.scrollToItem(index);
|
||||
}
|
||||
});
|
||||
}).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() {
|
||||
this.createGroupData = {
|
||||
userids: this.dialogData.dialog_user ? [this.userId, this.dialogData.dialog_user.userid] : [this.userId],
|
||||
@ -586,6 +561,36 @@ export default {
|
||||
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>
|
||||
|
||||
48
resources/assets/sass/dark.scss
vendored
48
resources/assets/sass/dark.scss
vendored
@ -179,37 +179,33 @@ body.dark-mode-reverse {
|
||||
}
|
||||
}
|
||||
.dialog-scroller {
|
||||
.dialog-list {
|
||||
> ul {
|
||||
> li {
|
||||
.dialog-view {
|
||||
.dialog-head {
|
||||
.dialog-content {
|
||||
background-color: #e1e1e1;
|
||||
.content-text {
|
||||
color: #ffffff;
|
||||
.content-text {
|
||||
> pre {
|
||||
.mention {
|
||||
color: #000000;
|
||||
}
|
||||
}
|
||||
.dialog-item {
|
||||
.dialog-view {
|
||||
.dialog-head {
|
||||
.dialog-content {
|
||||
background-color: #e1e1e1;
|
||||
.content-text {
|
||||
color: #ffffff;
|
||||
.content-text {
|
||||
> pre {
|
||||
.mention {
|
||||
color: #000000;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
&.self {
|
||||
.dialog-view {
|
||||
.dialog-head {
|
||||
.dialog-content {
|
||||
background-color: #8bcf70;
|
||||
.content-text {
|
||||
> pre {
|
||||
.mention {
|
||||
color: #000000;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
&.self {
|
||||
.dialog-view {
|
||||
.dialog-head {
|
||||
.dialog-content {
|
||||
background-color: #8bcf70;
|
||||
.content-text {
|
||||
> pre {
|
||||
.mention {
|
||||
color: #000000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,478 +180,469 @@
|
||||
}
|
||||
|
||||
.dialog-scroller {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
padding: 0 32px;
|
||||
overflow: auto;
|
||||
position: relative;
|
||||
padding: 16px 32px 0;
|
||||
|
||||
.dialog-list {
|
||||
> ul {
|
||||
> li {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
list-style: none;
|
||||
margin-bottom: 16px;
|
||||
.dialog-item {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
list-style: none;
|
||||
padding-bottom: 16px;
|
||||
|
||||
&:first-child {
|
||||
margin-top: 16px;
|
||||
}
|
||||
.dialog-avatar {
|
||||
position: relative;
|
||||
margin-bottom: 20px;
|
||||
flex-shrink: 0;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.dialog-avatar {
|
||||
position: relative;
|
||||
margin-bottom: 20px;
|
||||
flex-shrink: 0;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
.dialog-view {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
margin: 0 0 0 8px;
|
||||
position: relative;
|
||||
|
||||
.dialog-view {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
margin: 0 0 0 8px;
|
||||
position: relative;
|
||||
&.text {
|
||||
max-width: 70%;
|
||||
}
|
||||
|
||||
&.text {
|
||||
max-width: 70%;
|
||||
}
|
||||
|
||||
&: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 {
|
||||
&:hover {
|
||||
.dialog-head {
|
||||
.dialog-menu {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.history-tip {
|
||||
position: relative;
|
||||
padding-top: 60px;
|
||||
.dialog-username {
|
||||
margin-bottom: 6px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.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%);
|
||||
.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;
|
||||
}
|
||||
}
|
||||
|
||||
&.loading {
|
||||
padding: 12px 0;
|
||||
justify-content: center;
|
||||
|
||||
.common-loading {
|
||||
margin: 0;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
&.an-emoji {
|
||||
.content-text {
|
||||
> pre {
|
||||
font-size: 72px;
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.nothing {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
color: #999999;
|
||||
}
|
||||
&.two-emoji {
|
||||
.content-text {
|
||||
> pre {
|
||||
font-size: 52px;
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.bottom {
|
||||
height: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
&.three-emoji {
|
||||
.content-text {
|
||||
> pre {
|
||||
font-size: 32px;
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.self {
|
||||
flex-direction: row-reverse;
|
||||
.content-text {
|
||||
color: #333333;
|
||||
|
||||
.dialog-view {
|
||||
align-items: flex-end;
|
||||
margin: 0 8px 0 0;
|
||||
> 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;
|
||||
|
||||
.dialog-head {
|
||||
flex-direction: row-reverse;
|
||||
ol,
|
||||
ul {
|
||||
li {
|
||||
list-style-type: none;
|
||||
|
||||
.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;
|
||||
}
|
||||
}
|
||||
&::before {
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
width: 1.2em;
|
||||
color: #0088ff;
|
||||
text-align: left;
|
||||
margin-right: 0.2em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content-file {
|
||||
&.file {
|
||||
background-color: #F4F5F7;
|
||||
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;
|
||||
}
|
||||
|
||||
&.img {
|
||||
border-radius: 6px;
|
||||
.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;
|
||||
}
|
||||
}
|
||||
|
||||
&.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dialog-menu {
|
||||
margin-left: 0;
|
||||
margin-right: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.dialog-foot {
|
||||
.done {
|
||||
display: inline-block;
|
||||
.content-file {
|
||||
&.file {
|
||||
background-color: #F4F5F7;
|
||||
}
|
||||
|
||||
.percent {
|
||||
display: flex;
|
||||
&.img {
|
||||
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 {
|
||||
padding: 0 14px;
|
||||
padding-right: 14px;
|
||||
padding-left: 14px;
|
||||
}
|
||||
.dialog-footer {
|
||||
background-color: #f8f8f8;
|
||||
|
||||
@ -81,9 +81,6 @@
|
||||
padding: 0 12px;
|
||||
height: 64px;
|
||||
}
|
||||
.dialog-scroller {
|
||||
padding: 0 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -637,7 +637,8 @@
|
||||
}
|
||||
.dialog-wrapper {
|
||||
.dialog-scroller {
|
||||
padding: 0 16px 0 32px
|
||||
padding-right: 16px;
|
||||
padding-left: 32px;
|
||||
}
|
||||
.dialog-footer {
|
||||
padding: 0 14px 0 28px;
|
||||
@ -672,7 +673,7 @@
|
||||
min-width: 320px;
|
||||
max-width: 450px;
|
||||
border-left: 1px solid #f4f5f5;
|
||||
|
||||
|
||||
.head {
|
||||
&:before {
|
||||
left: 18px;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user