|
@@ -1,747 +0,0 @@
|
|
|
-<template>
|
|
|
- <div
|
|
|
- class="message-bubble"
|
|
|
- :class="[message.flow === 'in' ? '' : 'reverse']"
|
|
|
- ref="htmlRefHook"
|
|
|
- >
|
|
|
- <img
|
|
|
- class="avatar"
|
|
|
- :src="
|
|
|
- message?.avatar ||
|
|
|
- 'https://news-info.ks3-cn-beijing.ksyuncs.com/07/1690787574969.png'
|
|
|
- "
|
|
|
- onerror="this.src='https://news-info.ks3-cn-beijing.ksyuncs.com/07/1690787574969.png'"
|
|
|
- />
|
|
|
- <main class="message-area">
|
|
|
- <label
|
|
|
- class="name"
|
|
|
- v-if="message.flow === 'in' && message.conversationType === 'GROUP'"
|
|
|
- >
|
|
|
- {{ message.nameCard || message.nick || message.from }}
|
|
|
- </label>
|
|
|
- <div
|
|
|
- :class="handleImageOrVideoBubbleStyle(message)"
|
|
|
- @click.prevent.right="toggleDialog"
|
|
|
- >
|
|
|
- <div
|
|
|
- class="message-replie-area"
|
|
|
- :class="[
|
|
|
- message?.flow === 'in' ? '' : 'message-replies-area-reverse'
|
|
|
- ]"
|
|
|
- v-if="
|
|
|
- message?.cloudCustomData &&
|
|
|
- referenceMessage &&
|
|
|
- referenceMessage?.messageRootID
|
|
|
- "
|
|
|
- @click="showRepliesDialog(message, false)"
|
|
|
- >
|
|
|
- <MessageReference
|
|
|
- :message="message"
|
|
|
- :referenceMessage="referenceMessage"
|
|
|
- :referenceForShow="referenceForShow"
|
|
|
- :url="url"
|
|
|
- :face="face"
|
|
|
- :allMessageID="allMessageID"
|
|
|
- type="reply"
|
|
|
- />
|
|
|
- </div>
|
|
|
- <slot />
|
|
|
- <div v-if="dropdown" ref="dropdownRef" class="dropdown-inner">
|
|
|
- <div
|
|
|
- class="dialog"
|
|
|
- :class="[message.flow === 'in' ? '' : 'dialog-right']"
|
|
|
- @click="dropdown = false"
|
|
|
- >
|
|
|
- <slot name="dialog" />
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <MessageEmojiReact
|
|
|
- :message="message"
|
|
|
- type="content"
|
|
|
- v-if="needEmojiReact && isEmojiReactionInMessage(message)"
|
|
|
- />
|
|
|
- </div>
|
|
|
- </main>
|
|
|
- <label
|
|
|
- class="message-label fail"
|
|
|
- v-if="message.status === 'fail'"
|
|
|
- @click="resendMessage(message)"
|
|
|
- >
|
|
|
- !
|
|
|
- </label>
|
|
|
- <label
|
|
|
- class="message-label"
|
|
|
- :class="readReceiptStyle(message)"
|
|
|
- v-if="showReadReceiptTag(message)"
|
|
|
- @click="showReadReceiptDialog(message)"
|
|
|
- >
|
|
|
- <span>{{ readReceiptCont(message) }}</span>
|
|
|
- </label>
|
|
|
- </div>
|
|
|
- <div
|
|
|
- class="message-reference-area"
|
|
|
- :class="[message.flow === 'in' ? '' : 'message-reference-area-reverse']"
|
|
|
- v-if="
|
|
|
- message?.cloudCustomData &&
|
|
|
- referenceMessage &&
|
|
|
- !referenceMessage?.messageRootID
|
|
|
- "
|
|
|
- @click="jumpToAim(referenceMessage)"
|
|
|
- >
|
|
|
- <MessageReference
|
|
|
- :message="message"
|
|
|
- :referenceMessage="referenceMessage"
|
|
|
- :referenceForShow="referenceForShow"
|
|
|
- :url="url"
|
|
|
- :face="face"
|
|
|
- :allMessageID="allMessageID"
|
|
|
- type="reference"
|
|
|
- />
|
|
|
- </div>
|
|
|
- <label
|
|
|
- class="message-replies"
|
|
|
- :class="[message.flow === 'in' ? '' : 'message-replies-reverse']"
|
|
|
- v-if="replies?.length"
|
|
|
- @click="showRepliesDialog(message, true)"
|
|
|
- >
|
|
|
- <i class="icon icon-msg-replies"></i>
|
|
|
- <span>{{ replies?.length + $t('TUIChat.条回复') }}</span>
|
|
|
- </label>
|
|
|
-</template>
|
|
|
-
|
|
|
-<script lang="ts">
|
|
|
-import { decodeText } from '../utils/decodeText';
|
|
|
-import constant from '../../constant';
|
|
|
-import {
|
|
|
- defineComponent,
|
|
|
- watchEffect,
|
|
|
- reactive,
|
|
|
- toRefs,
|
|
|
- ref,
|
|
|
- nextTick,
|
|
|
- watch
|
|
|
-} from 'vue';
|
|
|
-import { onClickOutside, onLongPress, useElementBounding } from '@vueuse/core';
|
|
|
-import { deepCopy, JSONToObject } from '../utils/utils';
|
|
|
-import { handleErrorPrompts } from '../../utils';
|
|
|
-import TUIChat from '../index.vue';
|
|
|
-import MessageReference from './message-reference.vue';
|
|
|
-import { Message } from '../interface';
|
|
|
-import { TUIEnv } from '../../../../TUIPlugin';
|
|
|
-import MessageEmojiReact from './message-emoji-react.vue';
|
|
|
-import TIM from '../../../../TUICore/tim/index';
|
|
|
-
|
|
|
-const messageBubble = defineComponent({
|
|
|
- props: {
|
|
|
- data: {
|
|
|
- type: Object,
|
|
|
- default: () => ({})
|
|
|
- },
|
|
|
- messagesList: {
|
|
|
- type: Array,
|
|
|
- default: () => []
|
|
|
- },
|
|
|
- isH5: {
|
|
|
- type: Boolean,
|
|
|
- default: false
|
|
|
- },
|
|
|
- needGroupReceipt: {
|
|
|
- type: Boolean,
|
|
|
- default: false
|
|
|
- },
|
|
|
- needReplies: {
|
|
|
- type: Boolean,
|
|
|
- default: true
|
|
|
- },
|
|
|
- flow: {
|
|
|
- type: String,
|
|
|
- default: ''
|
|
|
- },
|
|
|
- needEmojiReact: {
|
|
|
- type: Boolean,
|
|
|
- default: false
|
|
|
- }
|
|
|
- },
|
|
|
- emits: [
|
|
|
- 'jumpID',
|
|
|
- 'resendMessage',
|
|
|
- 'showReadReceiptDialog',
|
|
|
- 'showRepliesDialog',
|
|
|
- 'dropDownOpen'
|
|
|
- ],
|
|
|
- components: {
|
|
|
- MessageReference,
|
|
|
- MessageEmojiReact
|
|
|
- },
|
|
|
- setup(props: any, ctx: any) {
|
|
|
- const { t } = (window as any).TUIKitTUICore.config.i18n.useI18n();
|
|
|
- const { TUIServer } = TUIChat;
|
|
|
- const data = reactive({
|
|
|
- env: TUIEnv(),
|
|
|
- message: {} as Message,
|
|
|
- messagesList: [],
|
|
|
- show: false,
|
|
|
- type: {},
|
|
|
- referenceMessage: {},
|
|
|
- referenceForShow: {},
|
|
|
- allMessageID: '',
|
|
|
- needGroupReceipt: false,
|
|
|
- needReplies: true,
|
|
|
- replies: [],
|
|
|
- face: [],
|
|
|
- url: '',
|
|
|
- needEmojiReact: false
|
|
|
- });
|
|
|
-
|
|
|
- watchEffect(() => {
|
|
|
- data.type = constant;
|
|
|
- data.messagesList = props.messagesList;
|
|
|
- data.needEmojiReact = props.needEmojiReact;
|
|
|
- data.message = deepCopy(
|
|
|
- data.messagesList?.find(
|
|
|
- (item: any) => (item as any)?.ID === props.message?.ID
|
|
|
- ) || props.data
|
|
|
- );
|
|
|
- data.needGroupReceipt = props.needGroupReceipt;
|
|
|
- data.needReplies = props.needReplies;
|
|
|
- if ((data.message as any).cloudCustomData) {
|
|
|
- const messageIDList: any[] = [];
|
|
|
- const cloudCustomData = JSONToObject(
|
|
|
- (data.message as any).cloudCustomData
|
|
|
- );
|
|
|
- data.replies = cloudCustomData?.messageReplies?.replies || [];
|
|
|
- data.referenceMessage = cloudCustomData.messageReply
|
|
|
- ? cloudCustomData.messageReply
|
|
|
- : '';
|
|
|
- for (
|
|
|
- let index = 0;
|
|
|
- index < (data.messagesList as any).length;
|
|
|
- index++
|
|
|
- ) {
|
|
|
- // To determine whether the referenced message is still in the message list, the corresponding field of the referenced message is displayed if it is in the message list. Otherwise, messageabstract/messagesender is displayed
|
|
|
- messageIDList.push((data.messagesList as any)[index].ID);
|
|
|
- (data as any).allMessageID = JSON.stringify(messageIDList);
|
|
|
- if (
|
|
|
- (data.messagesList as any)[index].ID ===
|
|
|
- (data.referenceMessage as any)?.messageID
|
|
|
- ) {
|
|
|
- data.referenceForShow = (data.messagesList as any)[index];
|
|
|
- if (
|
|
|
- (data.referenceMessage as any).messageType === constant.typeText
|
|
|
- ) {
|
|
|
- (data as any).face = decodeText(
|
|
|
- (data.referenceForShow as any).payload
|
|
|
- );
|
|
|
- }
|
|
|
- if (
|
|
|
- (data.referenceMessage as any).messageType === constant.typeFace
|
|
|
- ) {
|
|
|
- (
|
|
|
- data as any
|
|
|
- ).url = `https://web.sdk.qcloud.com/im/assets/face-elem/${
|
|
|
- (data.referenceForShow as any).payload.data
|
|
|
- }@2x.png`;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- } else {
|
|
|
- data.replies = [];
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- const htmlRefHook = ref<HTMLElement | null>(null);
|
|
|
- const dropdown = ref(false);
|
|
|
- const dropdownRef = ref(null);
|
|
|
-
|
|
|
- const toggleDialog = (e: any) => {
|
|
|
- dropdown.value = !dropdown.value;
|
|
|
- if (dropdown.value) {
|
|
|
- ctx.emit('dropDownOpen', dropdownRef);
|
|
|
- nextTick(() => {
|
|
|
- const dialogDom = (dropdownRef as any)?.value?.children[0];
|
|
|
- const dialogElement = document.getElementsByClassName(
|
|
|
- 'dialog-item'
|
|
|
- )[0] as HTMLElement;
|
|
|
- const parentDom = (dropdownRef as any)?.value?.offsetParent;
|
|
|
- const parentBound = useElementBounding(parentDom);
|
|
|
- const messageListDom = document.getElementById(
|
|
|
- 'messageEle'
|
|
|
- ) as HTMLElement;
|
|
|
- const messageListBound = useElementBounding(messageListDom);
|
|
|
- const leftRange = messageListBound?.left?.value;
|
|
|
- const rightRange =
|
|
|
- messageListBound?.left?.value +
|
|
|
- (messageListDom as any).clientWidth -
|
|
|
- dialogDom.clientWidth +
|
|
|
- 76;
|
|
|
- const topRange = messageListBound?.top?.value;
|
|
|
- const bottomRange =
|
|
|
- messageListBound?.top?.value +
|
|
|
- (messageListDom as any).clientHeight -
|
|
|
- dialogDom.clientHeight;
|
|
|
- const { clientX, clientY } = e;
|
|
|
- if (data?.env?.isH5) {
|
|
|
- if (parentBound?.top?.value <= dialogElement?.clientHeight) {
|
|
|
- dialogDom.style.bottom = `-${dialogElement?.clientHeight}Px`;
|
|
|
- } else {
|
|
|
- if (data?.message?.flow === 'in') {
|
|
|
- dialogDom.style.top = `-${dialogElement?.clientHeight - 20}Px`;
|
|
|
- } else {
|
|
|
- dialogDom.style.top = `-${dialogElement?.clientHeight}Px`;
|
|
|
- }
|
|
|
- }
|
|
|
- const centerWidth =
|
|
|
- parentBound?.left?.value + parentBound?.width?.value / 2;
|
|
|
- if (
|
|
|
- centerWidth > dialogElement.clientWidth / 2 &&
|
|
|
- centerWidth <
|
|
|
- messageListDom?.clientWidth - dialogElement.clientWidth / 2
|
|
|
- ) {
|
|
|
- dialogDom.style.left = 'calc(50% - 135Px)';
|
|
|
- } else if (centerWidth <= dialogElement.clientWidth / 2) {
|
|
|
- dialogDom.style.left = '-20Px';
|
|
|
- } else {
|
|
|
- dialogDom.style.left = `-${dialogElement.clientWidth / 2 + 10}Px`;
|
|
|
- }
|
|
|
- return;
|
|
|
- }
|
|
|
- switch (true) {
|
|
|
- case clientX > leftRange && clientX < rightRange:
|
|
|
- dialogDom.style.left = `${Math.max(
|
|
|
- e.clientX - parentBound?.left?.value - 76,
|
|
|
- -40
|
|
|
- )}Px`;
|
|
|
- break;
|
|
|
- case clientX <= leftRange:
|
|
|
- dialogDom.style.left = '20Px';
|
|
|
- break;
|
|
|
- case clientX >= rightRange:
|
|
|
- dialogDom.style.right = `${Math.max(
|
|
|
- parentBound?.left?.value +
|
|
|
- parentDom?.clientWidth -
|
|
|
- e.clientX -
|
|
|
- 256,
|
|
|
- -10
|
|
|
- )}Px`;
|
|
|
- break;
|
|
|
- }
|
|
|
- switch (true) {
|
|
|
- case clientY > topRange && clientY < bottomRange:
|
|
|
- dialogDom.style.top = `${e.clientY - parentBound?.top?.value}Px`;
|
|
|
- dialogDom.style.cssText = dialogDom.style.cssText.replace(
|
|
|
- 'align-items:end;',
|
|
|
- ''
|
|
|
- );
|
|
|
- break;
|
|
|
- case clientY <= topRange:
|
|
|
- dialogDom.style.top = '0Px';
|
|
|
- dialogDom.style.cssText = dialogDom.style.cssText.replace(
|
|
|
- 'align-items:end;',
|
|
|
- ''
|
|
|
- );
|
|
|
- break;
|
|
|
- case clientY >= bottomRange:
|
|
|
- dialogDom.style.bottom = `${
|
|
|
- parentBound?.top?.value + parentDom?.clientHeight - e.clientY
|
|
|
- }Px`;
|
|
|
- dialogDom.style.cssText += 'align-items:end;';
|
|
|
- break;
|
|
|
- }
|
|
|
- });
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- const jumpToAim = (message: any) => {
|
|
|
- if (
|
|
|
- (data.referenceMessage as any)?.messageID &&
|
|
|
- data.allMessageID.includes((data.referenceMessage as any)?.messageID)
|
|
|
- ) {
|
|
|
- ctx.emit('jumpID', (data.referenceMessage as any).messageID);
|
|
|
- } else {
|
|
|
- const message = t('TUIChat.无法定位到原消息');
|
|
|
- handleErrorPrompts(message, props);
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- onClickOutside(dropdownRef, () => {
|
|
|
- dropdown.value = false;
|
|
|
- });
|
|
|
-
|
|
|
- const toggleDialogH5 = (e: any) => {
|
|
|
- if (data?.env?.isH5) toggleDialog(e);
|
|
|
- return;
|
|
|
- };
|
|
|
-
|
|
|
- onLongPress(htmlRefHook, toggleDialogH5);
|
|
|
-
|
|
|
- const resendMessage = (message: any) => {
|
|
|
- ctx.emit('resendMessage', message);
|
|
|
- };
|
|
|
-
|
|
|
- const showReadReceiptTag = (message: any) => {
|
|
|
- if (
|
|
|
- message.flow === 'out' &&
|
|
|
- message.status === 'success' &&
|
|
|
- message.needReadReceipt
|
|
|
- ) {
|
|
|
- return true;
|
|
|
- }
|
|
|
- return false;
|
|
|
- };
|
|
|
-
|
|
|
- const readReceiptStyle = (message: any) => {
|
|
|
- if (
|
|
|
- message?.readReceiptInfo?.isPeerRead ||
|
|
|
- (message?.readReceiptInfo?.isPeerRead === undefined &&
|
|
|
- message?.isPeerRead) ||
|
|
|
- message?.readReceiptInfo?.unreadCount === 0
|
|
|
- ) {
|
|
|
- return '';
|
|
|
- }
|
|
|
- return 'unRead';
|
|
|
- };
|
|
|
-
|
|
|
- const readReceiptCont = (message: any) => {
|
|
|
- switch (message.conversationType) {
|
|
|
- case TUIServer.TUICore.TIM.TYPES.CONV_C2C:
|
|
|
- if (
|
|
|
- message?.readReceiptInfo?.isPeerRead ||
|
|
|
- (message?.readReceiptInfo?.isPeerRead === undefined &&
|
|
|
- message?.isPeerRead)
|
|
|
- ) {
|
|
|
- return t('TUIChat.已读');
|
|
|
- }
|
|
|
- return t('TUIChat.未读');
|
|
|
- case TUIServer.TUICore.TIM.TYPES.CONV_GROUP:
|
|
|
- if (message.readReceiptInfo.unreadCount === 0) {
|
|
|
- return t('TUIChat.全部已读');
|
|
|
- }
|
|
|
- if (
|
|
|
- message.readReceiptInfo.readCount === 0 ||
|
|
|
- (message.readReceiptInfo.unreadCount === undefined &&
|
|
|
- message.readReceiptInfo.readCount === undefined)
|
|
|
- ) {
|
|
|
- return t('TUIChat.未读');
|
|
|
- }
|
|
|
- return `${message.readReceiptInfo.readCount + t('TUIChat.人已读')}`;
|
|
|
- default:
|
|
|
- return '';
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- const showReadReceiptDialog = (message: any) => {
|
|
|
- ctx.emit('showReadReceiptDialog', message, 'receipt');
|
|
|
- };
|
|
|
-
|
|
|
- const showRepliesDialog = (message: any, isRoot: boolean) => {
|
|
|
- if (isRoot) {
|
|
|
- ctx.emit('showRepliesDialog', message, 'replies');
|
|
|
- return;
|
|
|
- }
|
|
|
- if ((data.referenceMessage as any)?.messageRootID) {
|
|
|
- const message = data.messagesList?.find(
|
|
|
- (item: Message) =>
|
|
|
- item.ID === (data.referenceMessage as any)?.messageRootID
|
|
|
- );
|
|
|
- if (message) {
|
|
|
- ctx.emit('showRepliesDialog', message, 'replies');
|
|
|
- return;
|
|
|
- } else {
|
|
|
- const message = t('TUIChat.无法定位到原消息');
|
|
|
- handleErrorPrompts(message, props);
|
|
|
- }
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- const handleImageOrVideoBubbleStyle = (message: Message) => {
|
|
|
- const classNameList = ['content'];
|
|
|
- if (!message) return classNameList;
|
|
|
- classNameList.push(`content-${data.message.flow}`);
|
|
|
- if (
|
|
|
- data.message.type === TIM.TYPES.MSG_IMAGE &&
|
|
|
- !isEmojiReactionInMessage(message)
|
|
|
- ) {
|
|
|
- classNameList.push('content-image');
|
|
|
- }
|
|
|
- if (
|
|
|
- data.message.type === TIM.TYPES.MSG_VIDEO &&
|
|
|
- !isEmojiReactionInMessage(message)
|
|
|
- ) {
|
|
|
- classNameList.push('content-video');
|
|
|
- }
|
|
|
- return classNameList;
|
|
|
- };
|
|
|
-
|
|
|
- const isEmojiReactionInMessage = (message: Message) => {
|
|
|
- try {
|
|
|
- if (!message?.cloudCustomData) return;
|
|
|
- const reactList = JSONToObject(message?.cloudCustomData)?.messageReact
|
|
|
- ?.reacts;
|
|
|
- if (!reactList || Object.keys(reactList).length === 0) return false;
|
|
|
- return true;
|
|
|
- } catch (err) {
|
|
|
- console.warn(err);
|
|
|
- return false;
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- return {
|
|
|
- ...toRefs(data),
|
|
|
- toggleDialog,
|
|
|
- htmlRefHook,
|
|
|
- jumpToAim,
|
|
|
- dropdown,
|
|
|
- dropdownRef,
|
|
|
- resendMessage,
|
|
|
- showReadReceiptTag,
|
|
|
- readReceiptStyle,
|
|
|
- readReceiptCont,
|
|
|
- showReadReceiptDialog,
|
|
|
- showRepliesDialog,
|
|
|
- handleImageOrVideoBubbleStyle,
|
|
|
- isEmojiReactionInMessage,
|
|
|
- TIM
|
|
|
- };
|
|
|
- }
|
|
|
-});
|
|
|
-export default messageBubble;
|
|
|
-</script>
|
|
|
-<style lang="scss" scoped>
|
|
|
-@import url('../../../styles/common.scss');
|
|
|
-@import url('../../../styles/icon.scss');
|
|
|
-.reverse {
|
|
|
- flex-direction: row-reverse;
|
|
|
- justify-content: flex-start;
|
|
|
-}
|
|
|
-.avatar {
|
|
|
- width: 36Px;
|
|
|
- height: 36Px;
|
|
|
- border-radius: 5Px;
|
|
|
-}
|
|
|
-.message-bubble {
|
|
|
- width: 100%;
|
|
|
- display: flex;
|
|
|
- padding-bottom: 5Px;
|
|
|
-}
|
|
|
-.line-left {
|
|
|
- border: 1Px solid rgba(0, 110, 255, 0.5);
|
|
|
-}
|
|
|
-.message-reference-area {
|
|
|
- display: flex;
|
|
|
- background: #f2f2f2;
|
|
|
- border-radius: 0.5rem;
|
|
|
- border-radius: 0.63rem;
|
|
|
- align-self: start;
|
|
|
- margin-left: 44Px;
|
|
|
- margin-right: 8Px;
|
|
|
- &-show {
|
|
|
- width: 100%;
|
|
|
- display: flex;
|
|
|
- flex-direction: inherit;
|
|
|
- justify-content: center;
|
|
|
- padding: 6Px;
|
|
|
- p {
|
|
|
- font-family: PingFangSC-Regular;
|
|
|
- font-weight: 400;
|
|
|
- font-size: 0.88rem;
|
|
|
- color: #999999;
|
|
|
- letter-spacing: 0;
|
|
|
- word-break: keep-all;
|
|
|
- padding-right: 5Px;
|
|
|
- }
|
|
|
- span {
|
|
|
- height: 1.25rem;
|
|
|
- font-family: PingFangSC-Regular;
|
|
|
- font-weight: 400;
|
|
|
- font-size: 0.88rem;
|
|
|
- color: #999999;
|
|
|
- letter-spacing: 0;
|
|
|
- display: inline-block;
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-.message-replies {
|
|
|
- display: flex;
|
|
|
- align-self: start;
|
|
|
- margin-left: 44Px;
|
|
|
- margin-right: 8Px;
|
|
|
- padding: 2Px;
|
|
|
- color: #999999;
|
|
|
- font-size: 10Px;
|
|
|
- i {
|
|
|
- margin: 4Px;
|
|
|
- }
|
|
|
- span {
|
|
|
- line-height: 20Px;
|
|
|
- }
|
|
|
-}
|
|
|
-.message-reference-area-reverse,
|
|
|
-.message-replies-reverse {
|
|
|
- align-self: end;
|
|
|
- margin-right: 44Px;
|
|
|
- margin-left: 8Px;
|
|
|
-}
|
|
|
-.message-img {
|
|
|
- max-width: min(calc(100vw - 180Px), 300Px);
|
|
|
- max-height: min(calc(100vw - 180Px), 300Px);
|
|
|
-}
|
|
|
-.message-video-cover {
|
|
|
- display: inline-block;
|
|
|
- position: relative;
|
|
|
- &::before {
|
|
|
- position: absolute;
|
|
|
- z-index: 1;
|
|
|
- content: '';
|
|
|
- width: 0Px;
|
|
|
- height: 0Px;
|
|
|
- border: 15Px solid transparent;
|
|
|
- border-left: 20Px solid #ffffff;
|
|
|
- top: 0;
|
|
|
- left: 0;
|
|
|
- bottom: 0;
|
|
|
- right: 0;
|
|
|
- margin: auto;
|
|
|
- }
|
|
|
-}
|
|
|
-.message-videoimg {
|
|
|
- max-width: min(calc(100vw - 160Px), 300Px);
|
|
|
- max-height: min(calc(100vw - 160Px), 300Px);
|
|
|
-}
|
|
|
-.face-box {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
-}
|
|
|
-.text-img {
|
|
|
- width: 20Px;
|
|
|
- height: 20Px;
|
|
|
-}
|
|
|
-.message-audio {
|
|
|
- padding-left: 10Px;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- position: relative;
|
|
|
- .icon {
|
|
|
- margin: 0 4Px;
|
|
|
- }
|
|
|
- audio {
|
|
|
- width: 0;
|
|
|
- height: 0;
|
|
|
- }
|
|
|
-}
|
|
|
-.reserve {
|
|
|
- flex-direction: row-reverse;
|
|
|
-}
|
|
|
-.message-area {
|
|
|
- max-width: calc(100% - 54Px);
|
|
|
- position: relative;
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- padding: 0 8Px;
|
|
|
- .name {
|
|
|
- padding-bottom: 4Px;
|
|
|
- font-weight: 400;
|
|
|
- font-size: 0.8rem;
|
|
|
- color: #999999;
|
|
|
- letter-spacing: 0;
|
|
|
- }
|
|
|
- .reference-content {
|
|
|
- padding: 12Px;
|
|
|
- font-weight: 400;
|
|
|
- font-size: 14Px;
|
|
|
- color: burlywood;
|
|
|
- letter-spacing: 0;
|
|
|
- word-wrap: break-word;
|
|
|
- word-break: break-all;
|
|
|
- animation: reference 800ms;
|
|
|
- }
|
|
|
- @-webkit-keyframes reference {
|
|
|
- from {
|
|
|
- opacity: 1;
|
|
|
- }
|
|
|
- 50% {
|
|
|
- background-color: #ff9c19;
|
|
|
- }
|
|
|
- to {
|
|
|
- opacity: 1;
|
|
|
- }
|
|
|
- }
|
|
|
- @keyframes reference {
|
|
|
- from {
|
|
|
- opacity: 1;
|
|
|
- }
|
|
|
- 50% {
|
|
|
- background-color: #ff9c19;
|
|
|
- }
|
|
|
- to {
|
|
|
- opacity: 1;
|
|
|
- }
|
|
|
- }
|
|
|
- .content {
|
|
|
- padding: 12Px;
|
|
|
- font-weight: 400;
|
|
|
- font-size: 14Px;
|
|
|
- color: #000000;
|
|
|
- letter-spacing: 0;
|
|
|
- word-wrap: break-word;
|
|
|
- word-break: break-all;
|
|
|
- width: fit-content;
|
|
|
- &-in {
|
|
|
- background: #fbfbfb;
|
|
|
- border-radius: 0Px 10Px 10Px 10Px;
|
|
|
- }
|
|
|
- &-out {
|
|
|
- background: #dceafd;
|
|
|
- border-radius: 10Px 0Px 10Px 10Px;
|
|
|
- }
|
|
|
- &-image {
|
|
|
- padding: 0Px;
|
|
|
- height: fit-content;
|
|
|
- border-radius: 10Px 0Px 10Px 10Px;
|
|
|
- }
|
|
|
- &-video {
|
|
|
- padding: 0Px;
|
|
|
- height: fit-content;
|
|
|
- background: transparent;
|
|
|
- border-radius: 10Px;
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-.message-label {
|
|
|
- align-self: flex-end;
|
|
|
- font-family: PingFangSC-Regular;
|
|
|
- font-weight: 400;
|
|
|
- font-size: 12Px;
|
|
|
- color: #b6b8ba;
|
|
|
- word-break: keep-all;
|
|
|
-}
|
|
|
-.fail {
|
|
|
- width: 15Px;
|
|
|
- height: 15Px;
|
|
|
- border-radius: 15Px;
|
|
|
- background: red;
|
|
|
- color: #ffffff;
|
|
|
- display: flex;
|
|
|
- justify-content: center;
|
|
|
- align-items: center;
|
|
|
-}
|
|
|
-.unRead {
|
|
|
- color: #679ce1;
|
|
|
-}
|
|
|
-.dropdown-inner {
|
|
|
- position: absolute;
|
|
|
- width: 100%;
|
|
|
- height: 100%;
|
|
|
- left: 0;
|
|
|
- top: 0;
|
|
|
-}
|
|
|
-.dialog {
|
|
|
- position: absolute;
|
|
|
- z-index: 1;
|
|
|
- display: flex;
|
|
|
- flex-direction: row;
|
|
|
- width: fit-content;
|
|
|
- &-right {
|
|
|
- right: 0;
|
|
|
- }
|
|
|
-}
|
|
|
-</style>
|