Commit 3347be3d by Sixong.Zhu

style

parent eca55214
<template>
<div class="msg-detail file-message d-flex" @dblclick="openFile">
<div class="file-message-info">
<div
class="file-message-info"
:class="{ 'd-flex align-items-center': !messageBody.msg.size }"
>
<div
class="text-nowrap text-truncate file-message-name"
class="file-message-name"
:title="messageBody.msg.name"
:class="{ 'text-truncate': messageBody.msg.size }"
>
{{ messageBody.msg.name }}
</div>
<div class="text-hint">
<div class="text-hint" v-if="messageBody.msg.size">
{{ format(messageBody.msg.size) }}
</div>
</div>
......
......@@ -108,443 +108,447 @@
</template>
<script lang="ts">
import { Component, Inject, Prop, Vue } from "vue-property-decorator";
import * as dto from "../model";
import chat from "./../xim";
import {
isAudio,
isImage,
isVideo,
MAX_FILE_SIZE,
MAX_IMAGE_SIZE,
} from "./message-item/file-controller";
import WhoReadList from "./who-read-list.vue";
import avatar from "@/customer-service/components/avatar.vue";
import { chatStore, ChatStore } from "@/customer-service/store/model";
import ximInstance from "../xim/xim";
import { dbController } from "../database";
import ImageMessage from "./message-item/image-message.vue";
import FileMessage from "./message-item/file-message.vue";
import AudioMessage from "./message-item/audio-message.vue";
import VideoMessage from "./message-item/video-message.vue";
import TextMessage from "./message-item/text-message.vue";
import WithdrawMessage from "./message-item/withdraw-message.vue";
import xim from "./../xim";
const twoMinutes = 2 * 60 * 1000;
const messageMapping = new Map<dto.MessageType, string>([
[dto.MessageType.Image, "image-message"],
[dto.MessageType.File, "file-message"],
[dto.MessageType.Video, "video-message"],
[dto.MessageType.Voice, "audio-message"],
[dto.MessageType.Text, "text-message"],
[dto.MessageType.Withdraw, "withdraw-message"],
[dto.MessageType.GeneralOrderMsg, "text-message"],
]);
@Component({
components: {
WhoReadList,
avatar,
ImageMessage,
FileMessage,
AudioMessage,
VideoMessage,
TextMessage,
WithdrawMessage,
},
})
export default class Message extends Vue {
@chatStore.State(ChatStore.STATE_CHAT_CURRENT_USER_UID)
private readonly chatMyId!: ChatStore.STATE_CHAT_CURRENT_USER_UID;
@chatStore.Getter(ChatStore.GETTER_CURRENT_CHAT_PRESENT_MEMBERS)
private readonly chatMembers!: ChatStore.GETTER_CURRENT_CHAT_PRESENT_MEMBERS;
@chatStore.State(ChatStore.STATE_CHAT_SOURCE)
private readonly chatSource!: ChatStore.STATE_CHAT_SOURCE;
@chatStore.State(ChatStore.STATE_CHAT_CURRENT_CHAT_ID)
private readonly chatId!: ChatStore.STATE_CHAT_CURRENT_CHAT_ID;
@chatStore.Mutation(ChatStore.MUTATION_WITHDRAW)
private readonly executeWithDraw!: ChatStore.MUTATION_WITHDRAW;
@chatStore.Action(ChatStore.ACTION_SET_HANDLED)
private readonly setHandled!: ChatStore.ACTION_SET_HANDLED;
@Prop({ type: Object, default: () => Object.create(null) })
private readonly data!: dto.Message;
@Prop()
private readonly isSendingMessage!: boolean;
@Prop()
private readonly failed!: boolean;
@Prop({ default: "circle" })
private readonly shape!: string;
@Inject({ default: false }) readonly showReadSummary!: boolean;
private readonly backend = chat.isBackend();
private messageComponent = "";
private readListVisibility = false;
private org = "";
private readerListOffset = false;
private defaultMessageHandledStatus = dto.MessageHandled.Default;
private showHostAvatar: boolean = false;
private get canWithdraw() {
if (this.backend && this.data) {
return new Date().valueOf() - this.data.ts * 1000 < twoMinutes;
import { Component, Inject, Prop, Vue } from "vue-property-decorator";
import * as dto from "../model";
import chat from "./../xim";
import {
isAudio,
isImage,
isVideo,
MAX_FILE_SIZE,
MAX_IMAGE_SIZE,
} from "./message-item/file-controller";
import WhoReadList from "./who-read-list.vue";
import avatar from "@/customer-service/components/avatar.vue";
import { chatStore, ChatStore } from "@/customer-service/store/model";
import ximInstance from "../xim/xim";
import { dbController } from "../database";
import ImageMessage from "./message-item/image-message.vue";
import FileMessage from "./message-item/file-message.vue";
import AudioMessage from "./message-item/audio-message.vue";
import VideoMessage from "./message-item/video-message.vue";
import TextMessage from "./message-item/text-message.vue";
import WithdrawMessage from "./message-item/withdraw-message.vue";
import xim from "./../xim";
const twoMinutes = 2 * 60 * 1000;
const messageMapping = new Map<dto.MessageType, string>([
[dto.MessageType.Image, "image-message"],
[dto.MessageType.File, "file-message"],
[dto.MessageType.Video, "video-message"],
[dto.MessageType.Voice, "audio-message"],
[dto.MessageType.Text, "text-message"],
[dto.MessageType.Withdraw, "withdraw-message"],
[dto.MessageType.GeneralOrderMsg, "text-message"],
]);
@Component({
components: {
WhoReadList,
avatar,
ImageMessage,
FileMessage,
AudioMessage,
VideoMessage,
TextMessage,
WithdrawMessage,
},
})
export default class Message extends Vue {
@chatStore.State(ChatStore.STATE_CHAT_CURRENT_USER_UID)
private readonly chatMyId!: ChatStore.STATE_CHAT_CURRENT_USER_UID;
@chatStore.Getter(ChatStore.GETTER_CURRENT_CHAT_PRESENT_MEMBERS)
private readonly chatMembers!: ChatStore.GETTER_CURRENT_CHAT_PRESENT_MEMBERS;
@chatStore.State(ChatStore.STATE_CHAT_SOURCE)
private readonly chatSource!: ChatStore.STATE_CHAT_SOURCE;
@chatStore.State(ChatStore.STATE_CHAT_CURRENT_CHAT_ID)
private readonly chatId!: ChatStore.STATE_CHAT_CURRENT_CHAT_ID;
@chatStore.Mutation(ChatStore.MUTATION_WITHDRAW)
private readonly executeWithDraw!: ChatStore.MUTATION_WITHDRAW;
@chatStore.Action(ChatStore.ACTION_SET_HANDLED)
private readonly setHandled!: ChatStore.ACTION_SET_HANDLED;
@Prop({ type: Object, default: () => Object.create(null) })
private readonly data!: dto.Message;
@Prop()
private readonly isSendingMessage!: boolean;
@Prop()
private readonly failed!: boolean;
@Prop({ default: "circle" })
private readonly shape!: string;
@Inject({ default: false }) readonly showReadSummary!: boolean;
private readonly backend = chat.isBackend();
private messageComponent = "";
private readListVisibility = false;
private org = "";
private readerListOffset = false;
private defaultMessageHandledStatus = dto.MessageHandled.Default;
private showHostAvatar: boolean = false;
private get canWithdraw() {
if (this.backend && this.data) {
return new Date().valueOf() - this.data.ts * 1000 < twoMinutes;
}
return false;
}
return false;
}
private get isWithdrawMessage() {
return this.data.type === dto.MessageType.Withdraw;
}
private get isAllRead() {
return this.data.read_count >= this.data.total_read_count;
}
private get isWithdrawMessage() {
return this.data.type === dto.MessageType.Withdraw;
}
private get messageBody(): { eid?: string; oid?: string; msg: any } {
if (this.data) {
try {
return { ...this.data, msg: JSON.parse(this.data.msg) };
} catch {
return {
...this.data,
msg: JSON.parse(this.data.msg.replace(/\n/g, "\\n")),
};
}
private get isAllRead() {
return this.data.read_count >= this.data.total_read_count;
}
return { msg: { text: "" } };
}
private get messageBody(): { eid?: string; oid?: string; msg: any } {
if (this.data) {
try {
return { ...this.data, msg: JSON.parse(this.data.msg) };
} catch {
return {
...this.data,
msg: JSON.parse(this.data.msg.replace(/\n/g, "\\n")),
};
}
}
private get handled() {
if (this.data) {
return this.defaultMessageHandledStatus || this.data.handled;
return { msg: { text: "" } };
}
return dto.MessageHandled.Default;
}
private get isMyMessage() {
if (this.isSendingMessage) {
return true;
private get handled() {
if (this.data) {
return this.defaultMessageHandledStatus || this.data.handled;
}
return dto.MessageHandled.Default;
}
const senderEid = this.messageBody.eid;
return senderEid!.toString() === this.chatMyId!.toString();
}
created() {
this.messageComponent = messageMapping.get(this.messageType) as string;
}
private get userName() {
if (this.chatMembers) {
const t = this.chatMembers.find((i) => i.eid === this.data.eid);
if (t) {
return t.name;
private get isMyMessage() {
if (this.isSendingMessage) {
return true;
}
const senderEid = this.messageBody.eid;
return senderEid!.toString() === this.chatMyId!.toString();
}
return "";
}
private get avatar() {
const avatar = chat.getUserMapping();
created() {
this.messageComponent = messageMapping.get(this.messageType) as string;
}
if (this.isSendingMessage) {
if (Object.getOwnPropertyNames(avatar).length > 0) {
this.showHostAvatar = true;
} else {
this.showHostAvatar = false;
}
if (avatar && this.chatMyId) {
const user = avatar[this.chatMyId];
if (user && user.avatar) {
return user.avatar;
private get userName() {
if (this.chatMembers) {
const t = this.chatMembers.find((i) => i.eid === this.data.eid);
if (t) {
return t.name;
}
}
return "";
}
if (avatar && this.data) {
if (Object.getOwnPropertyNames(avatar).length > 0) {
this.showHostAvatar = true;
} else {
this.showHostAvatar = false;
private get avatar() {
const avatar = chat.getUserMapping();
if (this.isSendingMessage) {
if (Object.getOwnPropertyNames(avatar).length > 0) {
this.showHostAvatar = true;
} else {
this.showHostAvatar = false;
}
if (avatar && this.chatMyId) {
const user = avatar[this.chatMyId];
if (user && user.avatar) {
return user.avatar;
}
}
}
const value = avatar[this.data.eid];
if (value && value.avatar) {
return value.avatar;
if (avatar && this.data) {
if (Object.getOwnPropertyNames(avatar).length > 0) {
this.showHostAvatar = true;
} else {
this.showHostAvatar = false;
}
const value = avatar[this.data.eid];
if (value && value.avatar) {
return value.avatar;
}
}
}
return "";
}
return "";
}
private get messageType() {
const type = this.data?.type;
if (type === "file") {
const name = this.messageBody?.msg.name;
if (name) {
const size = this.messageBody?.msg.size;
if (size) {
const outImageSize = size > MAX_IMAGE_SIZE;
if (!outImageSize && isImage(name)) {
return dto.MessageType.Image;
}
const outSize = size > MAX_FILE_SIZE;
if (!outSize) {
if (isAudio(name)) {
return dto.MessageType.Voice;
private get messageType() {
const type = this.data?.type;
if (type === "file") {
const name = this.messageBody?.msg.name;
if (name) {
const size = this.messageBody?.msg.size;
if (size) {
const outImageSize = size > MAX_IMAGE_SIZE;
if (!outImageSize && isImage(name)) {
return dto.MessageType.Image;
}
if (isVideo(name)) {
return dto.MessageType.Video;
const outSize = size > MAX_FILE_SIZE;
if (!outSize) {
if (isAudio(name)) {
return dto.MessageType.Voice;
}
if (isVideo(name)) {
return dto.MessageType.Video;
}
}
}
}
}
return type;
}
return type;
}
private get isTextMessage() {
return this.messageType === dto.MessageType.Text;
}
private get isTextMessage() {
return this.messageType === dto.MessageType.Text;
}
private get matchKeywords() {
if (this.isTextMessage && !this.isMyMessage) {
const m = this.messageBody.msg as { text: string };
if (m && m.text) {
const keywords = xim.getMatchedTextKeywords();
return keywords.find((i) => m.text.includes(i));
private get matchKeywords() {
if (this.isTextMessage && !this.isMyMessage) {
const m = this.messageBody.msg as { text: string };
if (m && m.text) {
const keywords = xim.getMatchedTextKeywords();
return keywords.find((i) => m.text.includes(i));
}
}
return false;
}
return false;
}
private isCustomer() {
return !this.showReadSummary;
}
private openFile(url: string) {
if (this.isSendingMessage) {
return;
private isCustomer() {
return !this.showReadSummary;
}
if (this.failed) {
return;
private openFile(url: string) {
if (this.isSendingMessage) {
return;
}
if (this.failed) {
return;
}
const copy = { ...this.messageBody.msg };
copy.url = url;
this.$emit("open", { type: this.messageType, msg: copy });
}
const copy = { ...this.messageBody.msg };
copy.url = url;
this.$emit("open", { type: this.messageType, msg: copy });
}
private withdraw() {
ximInstance.withdraw(this.chatId!, this.data.id).finally(() => {
dbController
.removeMessage(this.chatId!, this.data.id)
.finally(() => {
this.executeWithDraw(this.data.id);
this.$emit("withdraw", this.data.id);
});
});
}
private withdraw() {
ximInstance.withdraw(this.chatId!, this.data.id).finally(() => {
dbController
.removeMessage(this.chatId!, this.data.id)
.finally(() => {
this.executeWithDraw(this.data.id);
this.$emit("withdraw", this.data.id);
});
});
}
private openReaderList(e: MouseEvent) {
this.readerListOffset = e.x < 450;
this.readListVisibility = true;
}
private openReaderList(e: MouseEvent) {
this.readerListOffset = e.x < 450;
this.readListVisibility = true;
}
private executeHandled() {
this.setHandled({
id: this.data.id,
value: (this.defaultMessageHandledStatus =
dto.MessageHandled.Handled),
});
this.closeKeywordPopover();
}
private executeHandled() {
this.setHandled({
id: this.data.id,
value: (this.defaultMessageHandledStatus =
dto.MessageHandled.Handled),
});
this.closeKeywordPopover();
}
private ignoredKeyword() {
this.setHandled({
id: this.data.id,
value: (this.defaultMessageHandledStatus =
dto.MessageHandled.Ignored),
});
this.closeKeywordPopover();
}
private ignoredKeyword() {
this.setHandled({
id: this.data.id,
value: (this.defaultMessageHandledStatus =
dto.MessageHandled.Ignored),
});
this.closeKeywordPopover();
}
private closeKeywordPopover() {
document.body.click();
private closeKeywordPopover() {
document.body.click();
}
}
}
</script>
<style lang="less" scoped>
.message-con {
padding-bottom: 20px;
margin-right: 15px;
position: relative;
&.my-message {
.msg-detail {
background-color: #dbf2ff;
border-radius: 8px 0 8px 8px;
}
.message-con {
padding-bottom: 20px;
margin-right: 15px;
position: relative;
&.my-message {
.msg-detail {
background-color: #dbf2ff;
border-radius: 8px 0 8px 8px;
}
.msg-read {
display: inline-block;
color: #bfe1ff;
margin-right: 15px;
user-select: none;
flex: none;
margin-top: auto;
}
.msg-read {
display: inline-block;
color: #bfe1ff;
margin-right: 15px;
user-select: none;
flex: none;
margin-top: auto;
}
.download-icon {
margin-right: 15px;
margin-left: 0;
margin-top: 0;
}
.withdraw {
color: #999;
position: absolute;
bottom: 0;
right: 0;
font-size: 12px;
display: none;
cursor: pointer;
}
&:hover {
.withdraw {
display: inline-block;
}
}
.download-icon {
margin-right: 15px;
margin-left: 0;
margin-top: 0;
/deep/ .file-message-info {
text-align: initial;
}
}
.withdraw {
color: #999;
position: absolute;
bottom: 0;
right: 0;
font-size: 12px;
display: none;
cursor: pointer;
&.offset-bottom {
margin-bottom: 30px;
}
&:hover {
.withdraw {
display: inline-block;
}
> i {
height: 16px;
font-size: 16px;
margin-right: 10px;
}
}
&.offset-bottom {
margin-bottom: 30px;
.msg-name {
font-size: 14px;
color: #888;
text-align: right;
margin-bottom: 3px;
min-height: 16px;
&.algin-left {
text-align: left;
}
}
> i {
height: 16px;
font-size: 16px;
margin-right: 10px;
}
}
.msg-name {
font-size: 14px;
color: #888;
text-align: right;
margin-bottom: 3px;
min-height: 16px;
&.algin-left {
text-align: left;
.msg-content {
text-align: right;
&.algin-left {
text-align: left;
}
}
}
.msg-content {
text-align: right;
&.algin-left {
text-align: left;
}
}
.msg-detail {
margin-top: 10px;
font-size: 14px;
line-height: 20px;
background: #f5f6fa;
border-radius: 0px 8px 8px;
padding: 10px;
word-break: break-word;
/deep/ img {
max-width: 300px;
.msg-detail {
margin-top: 10px;
font-size: 14px;
line-height: 20px;
background: #f5f6fa;
border-radius: 0px 8px 8px;
padding: 10px;
word-break: break-word;
/deep/ img {
max-width: 300px;
}
}
}
.download-icon {
cursor: pointer;
text-decoration: none;
margin-left: 15px;
margin-top: 42px;
.download-icon {
cursor: pointer;
text-decoration: none;
margin-left: 15px;
margin-top: 42px;
i {
color: #fff;
font-size: 14px;
i {
color: #fff;
font-size: 14px;
}
}
}
.no-selection {
user-select: none;
}
.pointer {
cursor: pointer;
}
.all {
color: #4389f8;
}
.match-keyword {
background-color: #fff3e0;
border-radius: 13px;
padding: 3px 8px;
color: #e87005;
position: absolute;
bottom: -10px;
left: 0;
cursor: pointer;
font-size: 12px;
&.handled {
color: #59ba7b;
background-color: #f0f0f0;
cursor: default;
.no-selection {
user-select: none;
}
&.ignored {
color: #999;
background-color: #f0f0f0;
cursor: default;
.pointer {
cursor: pointer;
}
i {
margin-right: 5px;
.all {
color: #4389f8;
}
}
.keyword-action {
list-style: none;
.match-keyword {
background-color: #fff3e0;
border-radius: 13px;
padding: 3px 8px;
color: #e87005;
position: absolute;
bottom: -10px;
left: 0;
cursor: pointer;
font-size: 12px;
&.handled {
color: #59ba7b;
background-color: #f0f0f0;
cursor: default;
}
&.ignored {
color: #999;
background-color: #f0f0f0;
cursor: default;
}
i {
margin-right: 5px;
}
}
li {
.keyword-action {
list-style: none;
padding: 8px 10px;
color: #077aec;
cursor: pointer;
&:hover {
background-color: #f5f6fa;
li {
list-style: none;
padding: 8px 10px;
color: #077aec;
cursor: pointer;
&:hover {
background-color: #f5f6fa;
}
}
}
}
</style>
<style lang="less">
.match-keyword-popover {
padding: 0;
}
.match-keyword-popover {
padding: 0;
}
</style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment