Commit b779691b by 杨铁龙

Merge branch 'master' into wx_master

parents 142ecbe7 fbedbee7
<template> <template>
<div class="chat-room-con h-100 pos-rel"> <div class="chat-room-con pos-rel">
<div class="chat-panel"> <div class="chat-panel">
<div class="chat-area h-100 d-flex flex-column" ref="chatBox"> <div class="chat-area h-100 d-flex flex-column" ref="chatBox">
<div <div
...@@ -43,25 +43,22 @@ ...@@ -43,25 +43,22 @@
import Chat from "@/customer-service/xim"; import Chat from "@/customer-service/xim";
import { CustomerServiceEvent } from "../event"; import { CustomerServiceEvent } from "../event";
const chatResizeKey1 = "chat-resize-1";
const chatResizeKey2 = "chat-resize-2";
@Component({ components: { MessageInput, messages } }) @Component({ components: { MessageInput, messages } })
export default class ChatRoom extends Vue { export default class ChatRoom extends Vue {
@Ref("chatBox") private readonly chatBox!: Element; @Ref("chatBox") private readonly chatBox!: HTMLElement;
@Ref("top") private readonly refTop!: Element; @Ref("top") private readonly refTop!: HTMLElement;
@Ref("bottom") private readonly refBottom!: Element; @Ref("bottom") private readonly refBottom!: HTMLElement;
@Ref("resize") private readonly refResize!: Element; @Ref("resize") private readonly refResize!: HTMLElement;
@chatStore.State(ChatStore.STATE_CHAT_CURRENT_CHAT_ID) @chatStore.State(ChatStore.STATE_CHAT_CURRENT_CHAT_ID)
private readonly chatId!: ChatStore.STATE_CHAT_CURRENT_CHAT_ID; private readonly chatId!: ChatStore.STATE_CHAT_CURRENT_CHAT_ID;
@chatStore.Mutation(ChatStore.MUTATION_CLEAR_CURRENT_CHAT_MEMBERS)
private readonly clearChatMembers!: ChatStore.MUTATION_CLEAR_CURRENT_CHAT_MEMBERS;
@chatStore.State(ChatStore.STATE_CURRENT_CHAT_INPUTING) @chatStore.State(ChatStore.STATE_CURRENT_CHAT_INPUTING)
private readonly currentInputPeople!: ChatStore.STATE_CURRENT_CHAT_INPUTING; private readonly currentInputPeople!: ChatStore.STATE_CURRENT_CHAT_INPUTING;
@chatStore.State(ChatStore.STATE_CHAT_CURRENT_CHAT_UNIPLAT_ID)
private readonly currentChatUniplatId!: ChatStore.STATE_CHAT_CURRENT_CHAT_UNIPLAT_ID;
@chatStore.State(ChatStore.STATE_CHAT_CURRENT_IS_CHAT_MEMBER) @chatStore.State(ChatStore.STATE_CHAT_CURRENT_IS_CHAT_MEMBER)
private readonly isChatMember!: ChatStore.STATE_CHAT_CURRENT_IS_CHAT_MEMBER; private readonly isChatMember!: ChatStore.STATE_CHAT_CURRENT_IS_CHAT_MEMBER;
...@@ -79,12 +76,6 @@ ...@@ -79,12 +76,6 @@
@Provide() showReadSummary = true; @Provide() showReadSummary = true;
@Watch("currentChatUniplatId")
private whenCurrentChatIdChanged(newValue: string, oldValue: string) {
if (Number(oldValue) === Number(newValue)) return;
this.clearChatMembers();
}
private get getCurrentInputingPeople() { private get getCurrentInputingPeople() {
return this.currentInputPeople return this.currentInputPeople
.map(() => "" /* this.userInfo[k].name */) .map(() => "" /* this.userInfo[k].name */)
...@@ -97,9 +88,9 @@ ...@@ -97,9 +88,9 @@
private dragControllerDiv(e: MouseEvent) { private dragControllerDiv(e: MouseEvent) {
const resize = this.refResize as any; const resize = this.refResize as any;
const top = this.refTop as HTMLElement; const top = this.refTop;
const bottom = this.refBottom as HTMLElement; const bottom = this.refBottom;
const box = this.chatBox as HTMLElement; const box = this.chatBox;
const startY = e.clientY; const startY = e.clientY;
const originTop = resize.offsetTop; const originTop = resize.offsetTop;
...@@ -115,6 +106,9 @@ ...@@ -115,6 +106,9 @@
resize.style.top = moveLen + "px"; // 设置左侧区域的宽度 resize.style.top = moveLen + "px"; // 设置左侧区域的宽度
top.style.height = moveLen + "px"; top.style.height = moveLen + "px";
bottom.style.height = bottomHeight + "px"; bottom.style.height = bottomHeight + "px";
localStorage.setItem(chatResizeKey1, moveLen);
localStorage.setItem(chatResizeKey2, bottomHeight + "");
}; };
document.onmouseup = function () { document.onmouseup = function () {
document.onmousemove = null; document.onmousemove = null;
...@@ -126,9 +120,29 @@ ...@@ -126,9 +120,29 @@
} }
mounted() { mounted() {
this.adjust();
}
private adjust() {
setTimeout(() => {
if (
localStorage.getItem(chatResizeKey1) &&
localStorage.getItem(chatResizeKey2) &&
this.hasInput
) {
const s1 = localStorage.getItem(chatResizeKey1) + "px";
const s2 = localStorage.getItem(chatResizeKey2) + "px";
this.refTop && (this.refTop.style.height = s1);
this.refResize && (this.refResize.style.top = s1);
this.refBottom && (this.refBottom.style.height = s2);
} else {
this.refBottom && this.refBottom &&
((this.refBottom as HTMLElement).style.height = ((this.refBottom as HTMLElement).style.height =
this.chatBox.clientHeight - this.refTop.clientHeight + "px"); this.chatBox.clientHeight -
this.refTop.clientHeight +
"px");
}
}, 800);
} }
private openMessage(o: any) { private openMessage(o: any) {
...@@ -148,6 +162,7 @@ ...@@ -148,6 +162,7 @@
), ),
300 300
); );
this.$emit("send");
} }
} }
</script> </script>
...@@ -158,7 +173,7 @@ ...@@ -158,7 +173,7 @@
width: 46px; width: 46px;
height: 20px; height: 20px;
line-height: 20px; line-height: 20px;
background: #22bd7a; background-color: #22bd7a;
font-size: 13px; font-size: 13px;
border-radius: 2px; border-radius: 2px;
color: #ffffff; color: #ffffff;
...@@ -223,6 +238,10 @@ ...@@ -223,6 +238,10 @@
top: calc(100% - 130px + 1px); top: calc(100% - 130px + 1px);
height: 6px; height: 6px;
width: 100%; width: 100%;
&:hover {
background-color: #eee;
}
} }
} }
.order-info-con { .order-info-con {
......
...@@ -7,6 +7,8 @@ import { ChatUserInfoService } from "@/customer-service/utils/user-info"; ...@@ -7,6 +7,8 @@ import { ChatUserInfoService } from "@/customer-service/utils/user-info";
@Component({ components: {} }) @Component({ components: {} })
export default class ChatList extends Vue { export default class ChatList extends Vue {
private nextTimer = 0;
@chatStore.Action(ChatStore.ACTION_GET_MY_CHAT_LIST) @chatStore.Action(ChatStore.ACTION_GET_MY_CHAT_LIST)
protected readonly getMyChatList!: ChatStore.ACTION_GET_MY_CHAT_LIST; protected readonly getMyChatList!: ChatStore.ACTION_GET_MY_CHAT_LIST;
...@@ -91,4 +93,18 @@ export default class ChatList extends Vue { ...@@ -91,4 +93,18 @@ export default class ChatList extends Vue {
} }
return this.parseMesage(item); return this.parseMesage(item);
} }
/**
* 一分钟更新一次会话列表
*/
protected enableAutoRefresh() {
this.nextTimer = setTimeout(
() => this.getMyChatList().finally(() => this.enableAutoRefresh()),
60 * 1000
);
}
beforeDestroy() {
clearTimeout(this.nextTimer);
}
} }
...@@ -3,21 +3,17 @@ ...@@ -3,21 +3,17 @@
:modal="false" :modal="false"
:before-close="close" :before-close="close"
:visible="value" :visible="value"
custom-class="hide-header show-close padding-0 width-auto" :show-close="false"
custom-class="transparent"
width="90%"
> >
<div class="d-flex flex-column"> <div class="d-flex flex-column">
<div class="preview-title text-center">图片预览</div> <div class="d-flex justify-content-center align-items-start">
<img v-if="file" :src="file.url" />
<div class="d-flex justify-content-center" style="min-width: 300px"> <i class="el-icon-close" @click="close"></i>
<img v-if="file" :src="file.url" :style="style" />
</div> </div>
<div class="d-flex justify-content-center actions"> <div class="d-flex justify-content-center actions">
<span
class="d-flex align-items-center justify-content-center"
@click="set2Default"
>1:1</span
>
<a <a
class="d-flex align-items-center justify-content-center" class="d-flex align-items-center justify-content-center"
:href="file.url" :href="file.url"
...@@ -31,60 +27,55 @@ ...@@ -31,60 +27,55 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { Component, Model, Prop, Vue } from "vue-property-decorator"; import { Component, Model, Prop, Vue } from "vue-property-decorator";
@Component({ components: {} }) @Component({ components: {} })
export default class ImagePreview extends Vue { export default class ImagePreview extends Vue {
@Model("update") @Model("update")
private value!: boolean; private value!: boolean;
@Prop() @Prop()
private file!: { name: string; url: string }; private file!: { name: string; url: string };
private style: {
"max-height": number | string;
"max-width": number | string;
} = {
"max-height": "300px",
"max-width": "600px",
};
private close() { private close() {
setTimeout(
() =>
(this.style = { "max-height": "300px", "max-width": "600px" }),
300
);
this.$emit("update", false); this.$emit("update", false);
} }
private set2Default() {
this.style = { "max-height": "1600px", "max-width": "1600px" };
}
private get getAttachment() { private get getAttachment() {
if (this.file) { if (this.file) {
return this.file.name; return this.file.name;
} }
return "文件下载"; return "文件下载";
} }
} }
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.preview-title { img {
font-size: 18px; max-width: 100%;
color: #333; max-height: 100%;
margin-bottom: 15px;
}
.actions { & + i {
top: -25px;
right: 20px;
background-color: rgba(0, 0, 0, 0.5);
border-radius: 50%;
padding: 5px;
font-size: 40px;
color: #fff;
display: table;
position: relative;
z-index: 1;
cursor: pointer;
}
}
.actions {
margin: 15px 0; margin: 15px 0;
> span,
a { a {
width: 30px; width: 50px;
height: 30px; height: 50px;
background-color: #7a7b7d; background-color: #7a7b7d;
color: #fff; color: #fff;
border-radius: 50%; border-radius: 50%;
...@@ -92,16 +83,12 @@ export default class ImagePreview extends Vue { ...@@ -92,16 +83,12 @@ export default class ImagePreview extends Vue {
i { i {
color: #fff; color: #fff;
font-size: 20px; font-size: 30px;
} }
& + span { & + span {
margin-left: 15px; margin-left: 15px;
} }
} }
> a {
margin-left: 15px;
} }
}
</style> </style>
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
<script lang="ts"> <script lang="ts">
import { Component, Ref, Vue, Watch } from "vue-property-decorator"; import { Component, Ref, Vue, Watch } from "vue-property-decorator";
import ChatInput, { import ChatInput, {
FILE_INFO_CLASS, isFileElement,
isImageOrFile, isImageOrFile,
} from "../hybrid-input/index.vue"; } from "../hybrid-input/index.vue";
import { Message, MessageType } from "../model"; import { Message, MessageType } from "../model";
...@@ -51,6 +51,8 @@ ...@@ -51,6 +51,8 @@
@Ref("chat-input") @Ref("chat-input")
private readonly chatInput!: ChatInput; private readonly chatInput!: ChatInput;
private sending = false;
@Watch("chatRoomVisible") @Watch("chatRoomVisible")
private whenChatRoomShow() { private whenChatRoomShow() {
if (!this.chatRoomVisible) return; if (!this.chatRoomVisible) return;
...@@ -58,27 +60,39 @@ ...@@ -58,27 +60,39 @@
} }
private async sendMessage(msg: ChildNode[]) { private async sendMessage(msg: ChildNode[]) {
if (this.chatIniting) { if (this.chatIniting || this.sending) {
return; return;
} }
const count = msg.length;
let finished = 0;
this.sending = true;
const onFinishedChanged = () => {
finished++;
if (finished === count) {
this.sending = false;
}
};
setTimeout(() => (this.sending = false), 3000);
for (const item of msg) { for (const item of msg) {
if (isImageOrFile(item)) { if (isImageOrFile(item)) {
if ((item as Element).classList.contains(FILE_INFO_CLASS)) { if (isFileElement(item)) {
await this.sendFile(item, MessageType.File).catch((e) => await this.sendFile(item, MessageType.File)
this.onError(e) .catch((e) => this.onError(e))
); .finally(onFinishedChanged);
} else { } else {
await this.sendFile(item, MessageType.Image).catch((e) => await this.sendFile(item, MessageType.Image)
this.onError(e) .catch((e) => this.onError(e))
); .finally(onFinishedChanged);
} }
continue; continue;
} }
if (item.textContent) { if (item.textContent) {
await this.sendText(item.textContent).catch((e) => await this.sendText(item.textContent)
this.onError(e) .catch((e) => this.onError(e))
); .finally(onFinishedChanged);
} else {
onFinishedChanged();
} }
} }
this.$emit("sent"); this.$emit("sent");
...@@ -166,7 +180,8 @@ ...@@ -166,7 +180,8 @@
console.error(e); console.error(e);
this.setMsg2Failed(index); this.setMsg2Failed(index);
this.chatInput && this.chatInput.updateUploadProgress(0); this.chatInput &&
this.chatInput.updateUploadProgress(0);
}); });
} }
} }
......
<template> <template>
<div>
<div <div
class="msg-detail voice-message d-flex align-items-center" class="msg-detail voice-message d-flex align-items-center"
:class="{ playing: playing, 'can-play': messageRealUrl }" :class="{ playing: playing, 'can-play': messageRealUrl }"
...@@ -20,7 +21,7 @@ ...@@ -20,7 +21,7 @@
v-else-if="fileFailed2Load" v-else-if="fileFailed2Load"
title="[语音加载失败]" title="[语音加载失败]"
></i> ></i>
</div>
<text-message v-model="value" v-if="backend" /> <text-message v-model="value" v-if="backend" />
</div> </div>
</template> </template>
...@@ -92,6 +93,9 @@ ...@@ -92,6 +93,9 @@
<style lang="less" scoped> <style lang="less" scoped>
.voice-message { .voice-message {
width: 200px; width: 200px;
background-color: #eee;
border-radius: 6px;
padding: 8px 10px;
&.can-play { &.can-play {
cursor: pointer; cursor: pointer;
...@@ -102,12 +106,6 @@ ...@@ -102,12 +106,6 @@
} }
} }
.inline-text {
position: absolute;
bottom: 0;
left: 40px;
}
.my-message { .my-message {
.voice-message { .voice-message {
> div { > div {
......
<template> <template>
<div class="position-message" @click="openPosition"> <div class="position-message" @click="openPosition">
<div class="d-flex justify-content-between align-items-center"> <div class="d-flex justify-content-between align-items-center">
<span class="d-flex align-items-center"> <span class="d-flex align-items-center flex-fill">
<span class="title">{{ title }}</span> <span class="title flex-fill">{{ title }}</span>
<span <span
v-for="item in tags" v-for="item in tags"
:key="item.title" :key="item.title"
...@@ -46,7 +46,43 @@ ...@@ -46,7 +46,43 @@
} }
private get salary() { private get salary() {
return this.positionData.salary; const max = this.positionData.max_salary;
const min = this.positionData.min_salary;
const formatSalary = (v: number, type?: "Y" | "K") => {
if (type === "K") {
return {
v: parseFloat((v / 1000).toFixed(2)),
unit: "K",
};
}
if (+v < 1000) {
return {
v,
unit: "",
};
} else {
return {
v: parseFloat((v / 1000).toFixed(2)),
unit: "K",
};
}
};
if (!max && !min) {
return "面议";
}
if (+min >= +max) {
const v = formatSalary(min);
return `${v.v}${v.unit}`;
}
const formatMin = formatSalary(min);
const formatMax = formatSalary(max);
if (formatMin.unit === formatMax.unit) {
return `${formatMin.v}-${formatMax.v} ${formatMax.unit}`;
} else {
const formatMin = formatSalary(min, "K");
const formatMax = formatSalary(max, "K");
return `${formatMin.v}-${formatMax.v} K`;
}
} }
private get positionBody() { private get positionBody() {
...@@ -64,7 +100,9 @@ ...@@ -64,7 +100,9 @@
private get tail() { private get tail() {
return [ return [
this.positionData.company_name, this.positionData.company_name,
this.positionData.business_scope, this.positionData.business_scope !== '0'
? this.positionData.business_scope
: "",
]; ];
} }
......
...@@ -50,7 +50,6 @@ ...@@ -50,7 +50,6 @@
import { dbController } from "../database"; import { dbController } from "../database";
import { getLastMessageId } from "../store"; import { getLastMessageId } from "../store";
import { CustomerServiceEvent } from "../event"; import { CustomerServiceEvent } from "../event";
import xim from "../xim/xim";
@Component({ components: { message, ImagePreview, VideoPreview } }) @Component({ components: { message, ImagePreview, VideoPreview } })
export default class MessageList extends Vue { export default class MessageList extends Vue {
...@@ -95,7 +94,7 @@ ...@@ -95,7 +94,7 @@
private get messages() { private get messages() {
if (this.historyMessage) { if (this.historyMessage) {
if (this.sendingMessages) { if (this.sendingMessages && this.sendingMessages.length) {
return [...this.historyMessage, ...this.sendingMessages].filter( return [...this.historyMessage, ...this.sendingMessages].filter(
(i) => i.chat_id === this.chatId && i.id > 0 (i) => i.chat_id === this.chatId && i.id > 0
); );
...@@ -103,7 +102,7 @@ ...@@ -103,7 +102,7 @@
return this.historyMessage; return this.historyMessage;
} }
if (this.sendingMessages) { if (this.sendingMessages && this.sendingMessages.length) {
return this.sendingMessages.filter( return this.sendingMessages.filter(
(i) => i.chat_id === this.chatId && i.id > 0 (i) => i.chat_id === this.chatId && i.id > 0
); );
...@@ -190,15 +189,6 @@ ...@@ -190,15 +189,6 @@
public created() { public created() {
this.handleScrollWrapper(); this.handleScrollWrapper();
this.onNewMessage((e) => {
if (e.type === MessageType.Withdraw) {
const ids = xim.withDrawMsgHandle(e);
this.executeWithDraw(ids);
dbController
.removeMessage(e.chat_id, ids)
.finally(() => this.refresh());
}
});
} }
public mounted() { public mounted() {
......
...@@ -33,10 +33,17 @@ ...@@ -33,10 +33,17 @@
<div v-if="isMyMessage" class="msg-read pos-rel"> <div v-if="isMyMessage" class="msg-read pos-rel">
<span <span
@click="openReaderList" @click="openReaderList"
class="pointer" :class="[
:class="{ all: isAllRead }" isAllRead ? 'all' : 'not-all',
{ pointer: isChatMember },
]"
> >
<template v-if="isAllRead">全部已读</template> <template v-if="isAllRead">
<i
class="el-icon-circle-check"
title="全部已读"
></i>
</template>
<template <template
v-else-if="manualReaded || data.read_count" v-else-if="manualReaded || data.read_count"
>{{ >{{
...@@ -73,12 +80,7 @@ ...@@ -73,12 +80,7 @@
/> />
<avatar <avatar
v-if="!isQuestionAnswerMessage && !isWithdrawMessage" v-if="!isQuestionAnswerMessage && !isWithdrawMessage"
:src=" :src="avatar || defaultAvatar"
chatRole === 'admin' ||
chatRole === 'customer-service'
? defaultAvatar
: avatar
"
shape="circle" shape="circle"
/> />
</div> </div>
...@@ -153,7 +155,6 @@ ...@@ -153,7 +155,6 @@
import avatar from "@/customer-service/components/avatar.vue"; import avatar from "@/customer-service/components/avatar.vue";
import { chatStore, ChatStore } from "@/customer-service/store/model"; import { chatStore, ChatStore } from "@/customer-service/store/model";
import ximInstance from "../xim/xim"; import ximInstance from "../xim/xim";
import { dbController } from "../database";
import ImageMessage from "./message-item/image-message.vue"; import ImageMessage from "./message-item/image-message.vue";
import FileMessage from "./message-item/file-message.vue"; import FileMessage from "./message-item/file-message.vue";
import AudioMessage from "./message-item/audio-message.vue"; import AudioMessage from "./message-item/audio-message.vue";
...@@ -168,12 +169,12 @@ ...@@ -168,12 +169,12 @@
import PayMessage from "./message-item/pay-message.vue"; import PayMessage from "./message-item/pay-message.vue";
import NotifyMessage from "./message-item/notify-message.vue"; import NotifyMessage from "./message-item/notify-message.vue";
import { ChatRole } from "@/customer-service/model"; import { ChatRole } from "@/customer-service/model";
import { getUserMapping } from "../utils/user-info"; import { ChatUserInfoService, getUserMapping } from "../utils/user-info";
import Xim from "@/customer-service/xim"; import Xim from "@/customer-service/xim";
import { CustomerServiceEvent, MessageEvent } from "../event"; import { CustomerServiceEvent, MessageEvent } from "../event";
import { PayMessageBody } from "../xim/models/chat"; import { PayMessageBody } from "../xim/models/chat";
const twoMinutes = 2 * 60 * 1000; const oneDay = 24 * 60 * 60 * 1000;
const messageMapping = new Map<dto.MessageType, string>([ const messageMapping = new Map<dto.MessageType, string>([
[dto.MessageType.Image, "image-message"], [dto.MessageType.Image, "image-message"],
...@@ -219,8 +220,8 @@ ...@@ -219,8 +220,8 @@
@chatStore.State(ChatStore.STATE_CHAT_CURRENT_USER_UID) @chatStore.State(ChatStore.STATE_CHAT_CURRENT_USER_UID)
private readonly chatMyId!: ChatStore.STATE_CHAT_CURRENT_USER_UID; private readonly chatMyId!: ChatStore.STATE_CHAT_CURRENT_USER_UID;
@chatStore.Getter(ChatStore.STATE_CURRENT_CHAT_MEMBERS) @chatStore.State(ChatStore.STATE_ALL_HISTORY_CHAT_MEMBERS)
private readonly allChatMembers!: ChatStore.STATE_CURRENT_CHAT_MEMBERS; private readonly allChatMembers!: ChatStore.STATE_ALL_HISTORY_CHAT_MEMBERS;
@chatStore.Getter(ChatStore.GETTER_CURRENT_CHAT_PRESENT_MEMBERS) @chatStore.Getter(ChatStore.GETTER_CURRENT_CHAT_PRESENT_MEMBERS)
private readonly chatMembers!: ChatStore.GETTER_CURRENT_CHAT_PRESENT_MEMBERS; private readonly chatMembers!: ChatStore.GETTER_CURRENT_CHAT_PRESENT_MEMBERS;
...@@ -228,9 +229,6 @@ ...@@ -228,9 +229,6 @@
@chatStore.State(ChatStore.STATE_CHAT_CURRENT_CHAT_ID) @chatStore.State(ChatStore.STATE_CHAT_CURRENT_CHAT_ID)
private readonly chatId!: 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) @chatStore.Action(ChatStore.ACTION_SET_HANDLED)
private readonly setHandled!: ChatStore.ACTION_SET_HANDLED; private readonly setHandled!: ChatStore.ACTION_SET_HANDLED;
...@@ -266,12 +264,22 @@ ...@@ -266,12 +264,22 @@
private org = ""; private org = "";
private manualAllRead = false; private manualAllRead = false;
private manualReaded = 0; private manualReaded = 0;
private refetchUsername = "";
private refetchUserIcon = "";
private readerListOffset = false; private readerListOffset = false;
private defaultMessageHandledStatus = dto.MessageHandled.Default; private defaultMessageHandledStatus = dto.MessageHandled.Default;
private isWithdraw = true; private isWithdraw = true;
private get isSystemMessage() {
return (
this.messageBody &&
this.messageBody.eid &&
+this.messageBody.eid === 0
);
}
private get isPayMessage() { private get isPayMessage() {
return dto.MessageTypeController.isPayMessage(this.data.type); return dto.MessageTypeController.isPayMessage(this.data.type);
} }
...@@ -281,14 +289,17 @@ ...@@ -281,14 +289,17 @@
if (this.isPayMessage) { if (this.isPayMessage) {
return true; return true;
} }
if (this.needReadTip) { if (this.needReadTip && this.isMyMessage) {
return new Date().valueOf() - this.data.ts * 1000 < twoMinutes; return new Date().valueOf() - this.data.ts * 1000 < oneDay;
} }
} }
return false; return false;
} }
private get needReadTip() { private get needReadTip() {
if (this.isSystemMessage) {
return false;
}
return ( return (
this.data.type !== dto.MessageType.Pay && this.data.type !== dto.MessageType.Pay &&
this.data.type !== dto.MessageType.Refund && this.data.type !== dto.MessageType.Refund &&
...@@ -344,6 +355,15 @@ ...@@ -344,6 +355,15 @@
return true; return true;
} }
// 系统推送的消息或老用户(一般是客服,eid为负数),默认为客服发送
if (
this.messageBody &&
this.messageBody.eid &&
+this.messageBody.eid <= 0
) {
return true;
}
if ( if (
this.backend && this.backend &&
this.messageBody && this.messageBody &&
...@@ -370,24 +390,37 @@ ...@@ -370,24 +390,37 @@
} }
private get userName() { private get userName() {
if (this.refetchUsername) {
return this.refetchUsername;
}
if (this.chatMembers) { if (this.chatMembers) {
const t = this.chatMembers.find((i) => i.eid === this.data.eid); const t = this.chatMembers.find((i) => i.eid === this.data.eid);
if (t) { if (t) {
return this.getFilterUsername(t.alias_name || t.name); const name = this.getFilterUsername(
t.alias_name as string,
t.name
);
if (name) {
return name;
} }
} }
return ""; }
this.refetchUsername4Message();
return this.refetchUsername;
} }
private getFilterUsername(name: string) { private getFilterUsername(name1: string, name2: string) {
const backend = Xim.isBackend();
if ( if (
this.currentChat && this.currentChat &&
this.currentChat.catalog === "福利宝" && this.currentChat.catalog === "福利宝" &&
this.chatRole === "customer-service" this.chatRole === "customer-service"
) { ) {
return `采购顾问 ${name}`; return backend && name1
? `采购顾问 ${name1}(${name2})`
: `采购顾问 ${name1 || name2}`;
} }
return name; return backend && name1 ? `${name1}(${name2})` : name1 || name2;
} }
private get avatar() { private get avatar() {
...@@ -400,7 +433,7 @@ ...@@ -400,7 +433,7 @@
} }
} }
return ""; return this.refetchUserIcon;
} }
private get defaultAvatar() { private get defaultAvatar() {
...@@ -525,14 +558,7 @@ ...@@ -525,14 +558,7 @@
}, },
}); });
} }
ximInstance.withdraw(this.chatId, this.data.id).finally(() => { ximInstance.withdraw(this.chatId, this.data.id);
dbController
.removeMessage(this.chatId, [this.data.id])
.finally(() => {
this.executeWithDraw([this.data.id]);
this.$emit("withdraw", this.data.id);
});
});
} }
private hoverWithdraw() { private hoverWithdraw() {
...@@ -543,13 +569,15 @@ ...@@ -543,13 +569,15 @@
return false; return false;
} }
return (this.isWithdraw = return (this.isWithdraw =
new Date().valueOf() - this.data.ts * 1000 < twoMinutes); new Date().valueOf() - this.data.ts * 1000 < oneDay);
} }
private openReaderList(e: MouseEvent) { private openReaderList(e: MouseEvent) {
if (this.isChatMember) {
this.readerListOffset = e.x < 450; this.readerListOffset = e.x < 450;
this.readListVisibility = true; this.readListVisibility = true;
} }
}
private executeHandled() { private executeHandled() {
this.setHandled({ this.setHandled({
...@@ -576,6 +604,24 @@ ...@@ -576,6 +604,24 @@
private openMessage(o: any) { private openMessage(o: any) {
CustomerServiceEvent.emit(this, o); CustomerServiceEvent.emit(this, o);
} }
private refetchUsername4Message() {
if (this.data && this.data.eid) {
ChatUserInfoService.getUserInfo(this.data.eid).then((r) => {
if (r) {
if (Xim.isBackend() && r.alias_name) {
this.refetchUsername = `${r.alias_name}(${
r.name || r.phone
})`;
} else {
this.refetchUsername =
r.alias_name || r.name || r.phone;
}
r.icon && (this.refetchUserIcon = r.icon);
}
});
}
}
} }
</script> </script>
...@@ -694,7 +740,12 @@ ...@@ -694,7 +740,12 @@
} }
.all { .all {
color: #4389f8; color: #ccc;
opacity: 0.7;
}
.not-all {
color: #077aec;
} }
.match-keyword { .match-keyword {
......
...@@ -79,6 +79,61 @@ class DevAppTools { ...@@ -79,6 +79,61 @@ class DevAppTools {
}); });
}); });
} }
public getDataByKey(key: string) {
return new Promise<any>((resolve) => {
this.onReady().finally(() => {
if (!this.db) {
return resolve(false);
}
setTimeout(() => {
const store = this.buildStore(this.table);
const r = store.get(key);
r.onsuccess = ((o) => {
const result = (o.target as any).result;
if (result) {
resolve(result.content)
} else {
resolve(result)
}
});
r.onerror = () => resolve(false);
}, 300);
});
});
}
public addData(data: any, key: string) {
return new Promise<boolean>((resolve) => {
this.onReady().finally(() => {
if (!this.db) {
return resolve(false);
}
setTimeout(() => {
const store = this.buildStore(this.table);
const r = store.add({ value: key, content: data });
r.onsuccess = () => resolve(true);
r.onerror = () => resolve(false);
}, 300);
});
});
}
public deleteData(key: string) {
return new Promise<boolean>((resolve) => {
this.onReady().finally(() => {
if (!this.db) {
return resolve(false);
}
setTimeout(() => {
const store = this.buildStore(this.table);
const r = store.delete(key);
r.onsuccess = () => resolve(true);
r.onerror = () => resolve(false);
}, 300);
});
});
}
} }
export const devAppTools = new DevAppTools(); export const devAppTools = new DevAppTools();
...@@ -152,9 +152,13 @@ class ChatCacheDatabaseController { ...@@ -152,9 +152,13 @@ class ChatCacheDatabaseController {
public saveChatList(items: Chat[]) { public saveChatList(items: Chat[]) {
if (this.db) { if (this.db) {
const store = this.buildStore(this.chatListKey); const store = this.buildStore(this.chatListKey);
if (items && items.length) {
for (const item of items) { for (const item of items) {
store.add(item, item.id); store.add(item, item.id);
} }
} else {
store.clear();
}
} }
} }
...@@ -375,7 +379,7 @@ class ChatCacheDatabaseController { ...@@ -375,7 +379,7 @@ class ChatCacheDatabaseController {
public appendMessages(chat: number, items: Message[]) { public appendMessages(chat: number, items: Message[]) {
return new Promise<void>(resolve => { return new Promise<void>(resolve => {
if (!this.db || !items.length) { if (!this.db || !items || !items.length) {
return resolve(); return resolve();
} }
const store = this.buildChatMessageStore(chat); const store = this.buildChatMessageStore(chat);
...@@ -459,49 +463,6 @@ class ChatCacheDatabaseController { ...@@ -459,49 +463,6 @@ class ChatCacheDatabaseController {
}); });
}); });
} }
public syncChats(chats: number[]) {
return new Promise<void>(resolve => {
if (this.db) {
this.getChatList().then(r => {
const set = new Set<number>(chats);
let finished = 0;
let removing = [];
for (const item of r) {
if (!set.has(item.id)) {
removing.push(item.id);
}
}
for (const item of removing) {
this.removeChatAndMessages(item).finally(() => {
finished++;
if (finished === removing.length) {
resolve();
}
});
}
!removing.length && resolve();
});
} else {
resolve();
}
});
}
private removeChatAndMessages(chat: number) {
this.setupChatMessageDatabase(chat).finally(() => {
const store = this.buildChatMessageStore(chat);
const r = store.clear();
r.onsuccess = () => {
indexedDB.deleteDatabase(this.buildChatMessageKey(chat));
};
});
return this.removeChatFromList(chat);
}
} }
export const dbController = new ChatCacheDatabaseController(); export const dbController = new ChatCacheDatabaseController();
...@@ -125,6 +125,10 @@ ...@@ -125,6 +125,10 @@
); );
} }
export function isFileElement(node: ChildNode) {
return (node as Element).classList.contains(FILE_INFO_CLASS);
}
const limitedFileExtension = [ const limitedFileExtension = [
"ppt", "ppt",
"pptx", "pptx",
...@@ -149,9 +153,6 @@ ...@@ -149,9 +153,6 @@
@chatStore.State(ChatStore.STATE_CHAT_CURRENT_CHAT_ID) @chatStore.State(ChatStore.STATE_CHAT_CURRENT_CHAT_ID)
private readonly chatId!: ChatStore.STATE_CHAT_CURRENT_CHAT_ID; private readonly chatId!: ChatStore.STATE_CHAT_CURRENT_CHAT_ID;
@chatStore.Action(ChatStore.ACTION_GET_MY_CHAT_LIST)
protected readonly getMyChatList!: ChatStore.ACTION_GET_MY_CHAT_LIST;
@Ref("input") @Ref("input")
private readonly messageInputBox!: HTMLDivElement; private readonly messageInputBox!: HTMLDivElement;
...@@ -339,16 +340,18 @@ ...@@ -339,16 +340,18 @@
if (e.shiftKey || e.ctrlKey || e.altKey) { if (e.shiftKey || e.ctrlKey || e.altKey) {
return; return;
} }
// 避免按一下enter键多次触发发送
if (this.reloadTimer) {
clearTimeout(this.reloadTimer);
}
this.reloadTimer = setTimeout(() => {
const data = this.getNodeListFromInputBox(); const data = this.getNodeListFromInputBox();
this.$emit("send", data); this.$emit("send", data);
this.clearInput(); this.clearInput();
if (this.chatId) { if (this.chatId) {
chatCache[this.chatId] = []; chatCache[this.chatId] = [];
} }
if (this.reloadTimer) { }, 120);
clearTimeout(this.reloadTimer);
}
this.reloadTimer = setTimeout(() => this.getMyChatList(), 120);
} }
/** /**
...@@ -366,31 +369,18 @@ ...@@ -366,31 +369,18 @@
*/ */
private combine(nodes: ChildNode[]) { private combine(nodes: ChildNode[]) {
const sendingNodes: ChildNode[] = []; const sendingNodes: ChildNode[] = [];
let needCreateNewNode = false;
let text = "";
for (const item of nodes) { for (const item of nodes) {
if (!isImageOrFile(item) && item.textContent) { if (isImageOrFile(item)) {
if (needCreateNewNode) {
text = "";
needCreateNewNode = false;
}
text += item.textContent;
} else {
needCreateNewNode = true;
if (text) {
this.checkTextLength(text);
const node = document.createTextNode(text);
sendingNodes.push(node);
}
sendingNodes.push(item); sendingNodes.push(item);
continue;
} }
} if (item.textContent) {
const text = item.textContent;
if (text) {
this.checkTextLength(text); this.checkTextLength(text);
const node = document.createTextNode(text); const node = document.createTextNode(text);
sendingNodes.push(node); sendingNodes.push(node);
} }
}
return sendingNodes; return sendingNodes;
} }
......
...@@ -174,15 +174,15 @@ export const imItems = [ ...@@ -174,15 +174,15 @@ export const imItems = [
// 亲亲小保 // 亲亲小保
{ {
type: IMDomainType.社保客服, type: IMDomainType.社保客服,
title: "社保客服", title: "在线咨询",
}, },
{ {
type: IMDomainType.pc网站咨询, type: IMDomainType.pc网站咨询,
title: "pc网站咨询", title: "在线咨询",
}, },
{ {
type: IMDomainType.手机官网咨询, type: IMDomainType.手机官网咨询,
title: "手机官网咨询", title: "在线咨询",
}, },
{ {
type: IMDomainType.问答动态提醒, type: IMDomainType.问答动态提醒,
......
...@@ -115,8 +115,21 @@ class WebMonitor { ...@@ -115,8 +115,21 @@ class WebMonitor {
options.userAgent && options.userAgent &&
msg.push(`UserAgent: ${window.navigator.userAgent}`); msg.push(`UserAgent: ${window.navigator.userAgent}`);
r.config && r.config &&
r.config.data && r.config.params &&
msg.push(`Payload: ${JSON.stringify(r.config.data)}`); msg.push(`Params: ${JSON.stringify(r.config.params)}`);
if (r.config && r.config.data) {
const form = r.config.data as FormData;
if (form.getAll) {
const p = form.getAll("parameters");
for (const item of p) {
msg.push(`Payload: ${item}`);
}
} else {
msg.push(
`Payload: ${JSON.stringify(r.config.data)}`
);
}
}
msg.push( msg.push(
`Exception: ${( `Exception: ${(
......
...@@ -138,16 +138,19 @@ class OrderService { ...@@ -138,16 +138,19 @@ class OrderService {
r.pageData.rows, r.pageData.rows,
orderPayItemPredict orderPayItemPredict
); );
if (!withActions) {
items = items.filter( items = items.filter(
(i) => (i) =>
i.status !== PayStatus.Deleted && i.status !== PayStatus.Deleted &&
i.status !== PayStatus.Cancel i.status !== PayStatus.Cancel
); );
}
if (withActions) { if (withActions) {
for (let i = 0; i < r.pageData.rows.length; i++) { for (let i = 0; i < r.pageData.rows.length; i++) {
r.pageData && r.pageData &&
r.pageData.rows && r.pageData.rows &&
r.pageData.rows[i] && r.pageData.rows[i] &&
items[i] &&
(items[i].actions = r.pageData.rows[i].actions); (items[i].actions = r.pageData.rows[i].actions);
} }
} }
......
...@@ -73,6 +73,11 @@ export namespace ChatStore { ...@@ -73,6 +73,11 @@ export namespace ChatStore {
| readonly (dto.ChatMember & dto.ChatMemberExtraInfo)[] | readonly (dto.ChatMember & dto.ChatMemberExtraInfo)[]
| null; | null;
export const STATE_ALL_HISTORY_CHAT_MEMBERS = "当前会话历史所有参与者";
export type STATE_ALL_HISTORY_CHAT_MEMBERS =
| readonly (dto.ChatMember & dto.ChatMemberExtraInfo)[]
| null;
export const STATE_CURRENT_CHAT_TITLE = "会话标题"; export const STATE_CURRENT_CHAT_TITLE = "会话标题";
export type STATE_CURRENT_CHAT_TITLE = string; export type STATE_CURRENT_CHAT_TITLE = string;
...@@ -247,12 +252,6 @@ export namespace ChatStore { ...@@ -247,12 +252,6 @@ export namespace ChatStore {
keyword?: string keyword?: string
) => Promise<ChatType[]>; ) => Promise<ChatType[]>;
export const ACTION_SYNC_MY_CHAT_LIST = "同步我的会话列表";
export type ACTION_SYNC_MY_CHAT_LIST = () => void;
export const ACTION_FORCE_RELOAD_CHAT_LIST = "重新获取我的会话列表";
export type ACTION_FORCE_RELOAD_CHAT_LIST = () => Promise<ChatType[]>;
export const ACTION_REBUILD_UNREAD_MESSAGE_COUNT = "重新计算未读消息数"; export const ACTION_REBUILD_UNREAD_MESSAGE_COUNT = "重新计算未读消息数";
export type ACTION_REBUILD_UNREAD_MESSAGE_COUNT = () => void; export type ACTION_REBUILD_UNREAD_MESSAGE_COUNT = () => void;
......
import Chat from "../xim"; import Chat from "../xim";
import { orderService } from '../service/order'; import { orderService } from "../service/order";
export type ChatInfo = { export type ChatInfo = {
[eid: string]: any; [eid: string]: any;
...@@ -10,7 +10,8 @@ const chatInfo: ChatInfo = {}; ...@@ -10,7 +10,8 @@ const chatInfo: ChatInfo = {};
export const getChatModel = () => chatInfo; export const getChatModel = () => chatInfo;
const loadingKeys = new Set<string>(); const loadingKeys = new Set<string>();
let waitingAction: { key: string; resolve: (d: ChatModelInfoData) => void }[] = []; let waitingAction: { key: string; resolve: (d: ChatModelInfoData) => void }[] =
[];
export interface ChatModelInfoData { export interface ChatModelInfoData {
uniplatId: string | number; uniplatId: string | number;
...@@ -25,7 +26,10 @@ function buildCache() { ...@@ -25,7 +26,10 @@ function buildCache() {
if (!model2DetailNameMapping.size) { if (!model2DetailNameMapping.size) {
// 用户端默认不使用chat内置的detailName(这个专属于服务端),所以这里加一层内置转换 // 用户端默认不使用chat内置的detailName(这个专属于服务端),所以这里加一层内置转换
if (!Chat.isBackend()) { if (!Chat.isBackend()) {
model2DetailNameMapping.set(orderService.generalOrder, orderService.generalOrderDefaultDetailName); model2DetailNameMapping.set(
orderService.generalOrder,
orderService.generalOrderDefaultDetailName
);
} }
} }
} }
...@@ -57,12 +61,6 @@ export async function getChatModelInfo( ...@@ -57,12 +61,6 @@ export async function getChatModelInfo(
data: d, data: d,
} as ChatModelInfoData); } as ChatModelInfoData);
} }
return Promise.resolve({
uniplatId: 0,
chat_id: 0,
uniplat_version: 0,
data: d,
});
} }
loadingKeys.add(key); loadingKeys.add(key);
...@@ -71,7 +69,7 @@ export async function getChatModelInfo( ...@@ -71,7 +69,7 @@ export async function getChatModelInfo(
.detail(id + "", detail) .detail(id + "", detail)
.query(); .query();
const data = info; const data = info;
chatInfo[key] = data; info && info.row.UniplatChatId && (chatInfo[key] = data);
loadingKeys.delete(key); loadingKeys.delete(key);
const o = ( const o = (
...@@ -90,7 +88,7 @@ export async function getChatModelInfo( ...@@ -90,7 +88,7 @@ export async function getChatModelInfo(
} }
) as ChatModelInfoData; ) as ChatModelInfoData;
let removing = []; const removing = [];
for (const item of waitingAction) { for (const item of waitingAction) {
if (item.key === key) { if (item.key === key) {
item.resolve(o); item.resolve(o);
......
...@@ -56,6 +56,17 @@ export function uuid() { ...@@ -56,6 +56,17 @@ export function uuid() {
return s.join("") return s.join("")
} }
export function copyTextToClipboard(text: string) {
const input = document.createElement("input");
input.setAttribute("readonly", "readonly");
input.setAttribute("value", text);
document.body.appendChild(input);
input.select();
const ret = document.execCommand("copy");
document.body.removeChild(input);
return ret;
}
const URL_REGEX = const URL_REGEX =
/((?:(?:https?|ftp|file):\/\/|www\.|ftp\.)(?:\([-A-Z0-9+&@#\/%=~_|$?!:,.]*\)|[-A-Z0-9+&@#\/%=~_|$?!:,.])*(?:\([-A-Z0-9+&@#\/%=~_|$?!:,.]*\)|[A-Z0-9+&@#\/%=~_|$]))/gim /((?:(?:https?|ftp|file):\/\/|www\.|ftp\.)(?:\([-A-Z0-9+&@#\/%=~_|$?!:,.]*\)|[-A-Z0-9+&@#\/%=~_|$?!:,.])*(?:\([-A-Z0-9+&@#\/%=~_|$?!:,.]*\)|[A-Z0-9+&@#\/%=~_|$]))/gim
......
import { UniplatSdk } from "uniplat-sdk"; import { UniplatSdk } from "uniplat-sdk";
import Chat from "../xim"; import Chat from "../xim";
export type UserMapping = { export interface ChatUserSummaryInfo {
[eid: string]: {
name: string; name: string;
phone: string; phone: string;
icon: string; icon: string;
alias_name: string; alias_name: string;
}; }
};
export type UserMapping = { [eid: string]: ChatUserSummaryInfo };
const userMapping: UserMapping = {}; const userMapping: UserMapping = {};
...@@ -25,6 +25,12 @@ interface UserInfo { ...@@ -25,6 +25,12 @@ interface UserInfo {
export const getUserMapping = () => userMapping; export const getUserMapping = () => userMapping;
const loadingKeys = new Set<string>();
let waitingAction: {
key: string;
resolve: (d: ChatUserSummaryInfo) => void;
}[] = [];
export class ChatUserInfoService { export class ChatUserInfoService {
public static async getUserInfo(eid: string, sdk?: UniplatSdk) { public static async getUserInfo(eid: string, sdk?: UniplatSdk) {
if (userMapping[eid]) { if (userMapping[eid]) {
...@@ -33,6 +39,15 @@ export class ChatUserInfoService { ...@@ -33,6 +39,15 @@ export class ChatUserInfoService {
if (!+eid || +eid < 0) { if (!+eid || +eid < 0) {
return { name: "", phone: "", icon: "", alias_name: "" }; return { name: "", phone: "", icon: "", alias_name: "" };
} }
if (loadingKeys.has(eid)) {
return new Promise<ChatUserSummaryInfo>((resolve) =>
waitingAction.push({ key: eid, resolve })
);
}
loadingKeys.add(eid);
const info = await (sdk || Chat.getSdk()) const info = await (sdk || Chat.getSdk())
.domainService( .domainService(
"passport", "passport",
...@@ -47,6 +62,21 @@ export class ChatUserInfoService { ...@@ -47,6 +62,21 @@ export class ChatUserInfoService {
alias_name: info.alias_name, alias_name: info.alias_name,
}; };
userMapping[eid] = data; userMapping[eid] = data;
const removing = [];
for (const item of waitingAction) {
if (item.key === eid) {
item.resolve(data);
removing.push(item.key);
}
}
for (const item of removing) {
waitingAction = waitingAction.filter((i) => i.key !== item);
}
loadingKeys.delete(eid);
return data; return data;
} }
......
...@@ -154,7 +154,7 @@ class Chat { ...@@ -154,7 +154,7 @@ class Chat {
.finally(() => { .finally(() => {
this.registerXimEvent(); this.registerXimEvent();
if (xim.isConnected()) { if (xim.isConnected()) {
resolve(); setTimeout(resolve, 200);
} else { } else {
reject(new Error(`xim is not connected`)); reject(new Error(`xim is not connected`));
} }
......
...@@ -55,6 +55,7 @@ export interface Chat { ...@@ -55,6 +55,7 @@ export interface Chat {
biz_type_code: string; biz_type_code: string;
business_data?: string; business_data?: string;
detail_name?: string; detail_name?: string;
keyword?: string;
} }
export interface Message { export interface Message {
...@@ -230,6 +231,8 @@ export interface PositionMessage { ...@@ -230,6 +231,8 @@ export interface PositionMessage {
company_name: string; company_name: string;
business_scope: string; business_scope: string;
post_id: number; post_id: number;
max_salary: number;
min_salary: number;
} }
export interface CsUser { export interface CsUser {
......
...@@ -165,6 +165,7 @@ export class Xim { ...@@ -165,6 +165,7 @@ export class Xim {
lid = 0, lid = 0,
rid = 0, rid = 0,
limit = DefaultMsgPageSize, limit = DefaultMsgPageSize,
// = 0 正序(最新的消息在最下面),=1 倒序(最新的消息在最上面)
desc: boolean, desc: boolean,
p?: { isMember: boolean; model: string; obj: string } p?: { isMember: boolean; model: string; obj: string }
): Promise<Message[]> { ): Promise<Message[]> {
...@@ -195,8 +196,12 @@ export class Xim { ...@@ -195,8 +196,12 @@ export class Xim {
.getSdk() .getSdk()
.getAxios() .getAxios()
.get<any, Message[]>( .get<any, Message[]>(
`/general/xim/model/${p.model}/${p.obj}/msgs?lid=${lid}&rid=${rid}&limit=${limit}&desc=${desc ? 0 : 1}` `/general/xim/model/${p.model}/${
) p.obj
}/msgs?lid=${lid}&rid=${rid}&limit=${limit}&desc=${
desc ? 1 : 0
}`
);
} }
private setMessagesRead(chatId: number, msg: Message[]) { private setMessagesRead(chatId: number, msg: Message[]) {
...@@ -431,9 +436,12 @@ export class Xim { ...@@ -431,9 +436,12 @@ export class Xim {
vue.$once("hook:beforeDestroy", () => this.off("msg", action)); vue.$once("hook:beforeDestroy", () => this.off("msg", action));
} }
public withDrawMsgHandle(e: Message) { public withDrawMsgHandle(e: Message): number[] {
const ids = e.ref_id ? [e.ref_id] : e.msg.startsWith("[") ? JSON.parse(e.msg) : [+e.msg]; return e.ref_id
return ids; ? [e.ref_id]
: e.msg.startsWith("[")
? JSON.parse(e.msg)
: [+e.msg];
} }
} }
......
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