Commit 01b506b6 by zhousil

Merge branch 'master' into release

parents df68099d 87ad0f2f
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
import MessageInput from "@/customer-service/components/message-input.vue"; import MessageInput from "@/customer-service/components/message-input.vue";
import messages from "@/customer-service/components/message-list.vue"; import messages from "@/customer-service/components/message-list.vue";
import { ChatStore, chatStore } from "@/customer-service/store/model"; import { ChatStore, chatStore } from "@/customer-service/store/model";
import Chat from "@/customer-service/xim";
type RoomInfoTab = "customer" | "order"; type RoomInfoTab = "customer" | "order";
...@@ -124,7 +125,7 @@ ...@@ -124,7 +125,7 @@
} }
private onError(msg: string) { private onError(msg: string) {
this.$message.error(msg); Chat.error(msg);
} }
private dragControllerDiv(e: MouseEvent) { private dragControllerDiv(e: MouseEvent) {
......
...@@ -16,32 +16,58 @@ ...@@ -16,32 +16,58 @@
> >
{{ isQuestionAnswerMessage ? "" : userName }} {{ isQuestionAnswerMessage ? "" : userName }}
</div> </div>
<div <div class="d-flex">
class="content-avatar d-flex align-items-start" <template
:class="{ v-if="backend && showReadSummary && !isWithdrawMessage"
'justify-content-end': isMyMessage, >
'cs-flex-direction': !isMyMessage, <div v-if="isMyMessage" class="msg-read pos-rel">
}" <span
> @click="openReaderList"
<component class="pointer"
:is="messageComponent" :class="{ all: isAllRead }"
:user-name="userName" >
<template v-if="isAllRead">全部已读</template>
<template v-else-if="data.read_count > 0"
>{{ data.read_count }}人已读</template
>
<template v-else>未读</template>
</span>
<who-read-list
v-if="readListVisibility"
@blur="readListVisibility = false"
:msgId="data.id"
:class="{ offset: readerListOffset }"
/>
</div>
</template>
<div
class="content-avatar d-flex align-items-start"
:class="{ :class="{
'my-message': isMyMessage, 'justify-content-end': isMyMessage,
'cs-flex-direction': !isMyMessage,
}" }"
v-if="messageComponent" >
v-model="data" <component
@open="openFile" :is="messageComponent"
/> :user-name="userName"
<avatar :class="{
v-if="!isQuestionAnswerMessage && !isWithdrawMessage" 'my-message': isMyMessage,
:src=" }"
chatRole === 'admin' || chatRole === 'customer-service' v-if="messageComponent"
? defaultAvatar v-model="data"
: avatar @open="openFile"
" />
shape="circle" <avatar
/> v-if="!isQuestionAnswerMessage && !isWithdrawMessage"
:src="
chatRole === 'admin' ||
chatRole === 'customer-service'
? defaultAvatar
: avatar
"
shape="circle"
/>
</div>
</div> </div>
</div> </div>
...@@ -52,36 +78,17 @@ ...@@ -52,36 +78,17 @@
></i> ></i>
<i class="el-icon-loading" v-else-if="isSendingMessage"></i> <i class="el-icon-loading" v-else-if="isSendingMessage"></i>
<template v-if="backend && showReadSummary && !isWithdrawMessage">
<div v-if="isMyMessage" class="msg-read pos-rel">
<span
@click="openReaderList"
class="pointer"
:class="{ all: isAllRead }"
>
<template v-if="isAllRead">全部已读</template>
<template v-else-if="data.read_count > 0"
>{{ data.read_count }}人已读</template
>
<template v-else>未读</template>
</span>
<who-read-list
v-if="readListVisibility"
@blur="readListVisibility = false"
:msgId="data.id"
:class="{ offset: readerListOffset }"
/>
</div>
</template>
<span <span
class="withdraw" class="withdraw"
v-if=" v-if="
isMyMessage && isMyMessage &&
canWithdraw && canWithdraw &&
isWithdraw &&
!isWithdrawMessage && !isWithdrawMessage &&
!isQuestionAnswerMessage !isQuestionAnswerMessage &&
isChatMember
" "
@mouseenter="hoverWithdraw"
@click="withdraw" @click="withdraw"
>撤回此消息</span >撤回此消息</span
> >
...@@ -147,6 +154,7 @@ ...@@ -147,6 +154,7 @@
import xim from "./../xim"; import xim from "./../xim";
import { ChatRole } from "@/customer-service/model"; import { ChatRole } from "@/customer-service/model";
import { getUserMapping } from "../utils/user-info"; import { getUserMapping } from "../utils/user-info";
import Xim from "@/customer-service/xim";
const twoMinutes = 2 * 60 * 1000; const twoMinutes = 2 * 60 * 1000;
...@@ -202,6 +210,9 @@ ...@@ -202,6 +210,9 @@
@chatStore.Getter(ChatStore.GETTER_CURRENT_CURRENT_CHAT) @chatStore.Getter(ChatStore.GETTER_CURRENT_CURRENT_CHAT)
private readonly currentChat!: ChatStore.GETTER_CURRENT_CURRENT_CHAT; private readonly currentChat!: ChatStore.GETTER_CURRENT_CURRENT_CHAT;
@chatStore.State(ChatStore.STATE_CHAT_CURRENT_IS_CHAT_MEMBER)
private readonly isChatMember!: ChatStore.STATE_CHAT_CURRENT_IS_CHAT_MEMBER;
@Prop({ type: Object, default: () => Object.create(null) }) @Prop({ type: Object, default: () => Object.create(null) })
private readonly data!: dto.Message; private readonly data!: dto.Message;
...@@ -227,6 +238,8 @@ ...@@ -227,6 +238,8 @@
private readerListOffset = false; private readerListOffset = false;
private defaultMessageHandledStatus = dto.MessageHandled.Default; private defaultMessageHandledStatus = dto.MessageHandled.Default;
private isWithdraw = true;
private get canWithdraw() { private get canWithdraw() {
if (this.backend && this.data) { if (this.backend && this.data) {
return new Date().valueOf() - this.data.ts * 1000 < twoMinutes; return new Date().valueOf() - this.data.ts * 1000 < twoMinutes;
...@@ -297,7 +310,8 @@ ...@@ -297,7 +310,8 @@
private getFilterUsername(name: string) { private getFilterUsername(name: string) {
if ( if (
this.currentChat && this.currentChat.catalog === "福利宝" && this.currentChat &&
this.currentChat.catalog === "福利宝" &&
this.chatRole === "customer-service" this.chatRole === "customer-service"
) { ) {
return `采购顾问 ${name}`; return `采购顾问 ${name}`;
...@@ -398,6 +412,10 @@ ...@@ -398,6 +412,10 @@
} }
private withdraw() { private withdraw() {
if (new Date().valueOf() - this.data.ts * 1000 > twoMinutes) {
Xim.error("超过两分钟的消息不能撤回");
return;
}
ximInstance.withdraw(this.chatId!, this.data.id).finally(() => { ximInstance.withdraw(this.chatId!, this.data.id).finally(() => {
dbController dbController
.removeMessage(this.chatId!, this.data.id) .removeMessage(this.chatId!, this.data.id)
...@@ -408,6 +426,11 @@ ...@@ -408,6 +426,11 @@
}); });
} }
private hoverWithdraw() {
this.isWithdraw =
new Date().valueOf() - this.data.ts * 1000 < twoMinutes;
}
private openReaderList(e: MouseEvent) { private openReaderList(e: MouseEvent) {
this.readerListOffset = e.x < 450; this.readerListOffset = e.x < 450;
this.readListVisibility = true; this.readListVisibility = true;
......
...@@ -349,9 +349,10 @@ export default { ...@@ -349,9 +349,10 @@ export default {
} else { } else {
arr.push(eid); arr.push(eid);
} }
setTimeoutId[eid] = setTimeout(() => { setTimeoutId[eid] = setTimeout(
arr.splice(arr.indexOf(eid), 1); () => arr.splice(arr.indexOf(eid), 1),
}, 4000); 4000
);
}; };
})(), })(),
[ChatStore.MUTATION_CLEAR_CURRENT_CHAT_INPUTING]: (state) => { [ChatStore.MUTATION_CLEAR_CURRENT_CHAT_INPUTING]: (state) => {
...@@ -477,21 +478,31 @@ export default { ...@@ -477,21 +478,31 @@ export default {
items.forEach((i) => (sum += i.unread_msg_count)); items.forEach((i) => (sum += i.unread_msg_count));
state[ChatStore.STATE_CURRENT_UNREAD_MESSAGE_COUNT] = sum; state[ChatStore.STATE_CURRENT_UNREAD_MESSAGE_COUNT] = sum;
}, },
async [ChatStore.ACTION_GET_CHAT_MESSAGES]({ state, commit }) { async [ChatStore.ACTION_GET_CHAT_MESSAGES]({ state, commit, getters }) {
const chatId = state[ChatStore.STATE_CHAT_CURRENT_CHAT_ID]; const chatId = state[ChatStore.STATE_CHAT_CURRENT_CHAT_ID];
const chat = getters[ChatStore.GETTER_CURRENT_CURRENT_CHAT];
const isMember = state[ChatStore.STATE_CHAT_CURRENT_IS_CHAT_MEMBER];
if (chatId == null) return; if (chatId == null) return;
let data: Message[] = []; let data: Message[] = [];
const cache = await dbController.getChatMessages(chatId); const getMessages = async () => {
if (cache && cache.length) { const o = {
data = cache; model: chat.model_name,
obj: chat.obj_id,
isMember,
};
data = await xim.queryLastPageMsg(chatType, chatId, 20, o);
};
if (isMember) {
const cache = await dbController.getChatMessages(chatId);
if (cache && cache.length) {
data = cache;
} else {
await getMessages();
}
} else { } else {
data = await xim.queryLastPageMsg( await getMessages();
chatType,
chatId,
20,
!state[ChatStore.STATE_CHAT_CURRENT_IS_CHAT_MEMBER]
);
} }
try { try {
commit(ChatStore.MUTATION_PUSH_CHAT_MSG_HISTORY, data); commit(ChatStore.MUTATION_PUSH_CHAT_MSG_HISTORY, data);
dbController.saveChatMessages(chatId, data); dbController.saveChatMessages(chatId, data);
...@@ -504,34 +515,46 @@ export default { ...@@ -504,34 +515,46 @@ export default {
} }
}, },
async [ChatStore.ACTION_GET_CHAT_MESSAGES_BEFORE_SPECIFIC_ID]( async [ChatStore.ACTION_GET_CHAT_MESSAGES_BEFORE_SPECIFIC_ID](
{ state, commit }, { state, commit, getters },
msgId: Parameters<ChatStore.ACTION_GET_CHAT_MESSAGES_BEFORE_SPECIFIC_ID>[0] msgId: Parameters<ChatStore.ACTION_GET_CHAT_MESSAGES_BEFORE_SPECIFIC_ID>[0]
) { ) {
const chatId = state[ChatStore.STATE_CHAT_CURRENT_CHAT_ID]; const chatId = state[ChatStore.STATE_CHAT_CURRENT_CHAT_ID];
if (chatId == null) return; if (chatId == null) return;
const chat = getters[ChatStore.GETTER_CURRENT_CURRENT_CHAT];
const o = {
model: chat.model_name,
obj: chat.obj_id,
isMember: state[ChatStore.STATE_CHAT_CURRENT_IS_CHAT_MEMBER],
};
const data = await xim.queryPrevPageMsg( const data = await xim.queryPrevPageMsg(
chatType, chatType,
chatId, chatId,
msgId, msgId,
10, 10,
!state[ChatStore.STATE_CHAT_CURRENT_IS_CHAT_MEMBER] o
); );
commit(ChatStore.MUTATION_UNSHIFT_CHAT_MSG_HISTORY, data); commit(ChatStore.MUTATION_UNSHIFT_CHAT_MSG_HISTORY, data);
dbController.appendMessages(chatId, data); dbController.appendMessages(chatId, data);
return data; return data;
}, },
async [ChatStore.ACTION_GET_CHAT_MESSAGES_AFTER_SPECIFIC_ID]( async [ChatStore.ACTION_GET_CHAT_MESSAGES_AFTER_SPECIFIC_ID](
{ state, commit }, { state, commit, getters },
msgId: Parameters<ChatStore.ACTION_GET_CHAT_MESSAGES_AFTER_SPECIFIC_ID>[0] msgId: Parameters<ChatStore.ACTION_GET_CHAT_MESSAGES_AFTER_SPECIFIC_ID>[0]
) { ) {
const chatId = state[ChatStore.STATE_CHAT_CURRENT_CHAT_ID]; const chatId = state[ChatStore.STATE_CHAT_CURRENT_CHAT_ID];
if (chatId == null) return; if (chatId == null) return;
const chat = getters[ChatStore.GETTER_CURRENT_CURRENT_CHAT];
const o = {
model: chat.model_name,
obj: chat.obj_id,
isMember: state[ChatStore.STATE_CHAT_CURRENT_IS_CHAT_MEMBER],
};
const data = await xim.queryNextPageMsg( const data = await xim.queryNextPageMsg(
chatType, chatType,
chatId, chatId,
msgId, msgId,
10, 10,
!state[ChatStore.STATE_CHAT_CURRENT_IS_CHAT_MEMBER] o
); );
commit(ChatStore.MUTATION_PUSH_CHAT_MSG_HISTORY, data); commit(ChatStore.MUTATION_PUSH_CHAT_MSG_HISTORY, data);
dbController.appendMessages(chatId, data); dbController.appendMessages(chatId, data);
...@@ -618,7 +641,12 @@ export default { ...@@ -618,7 +641,12 @@ export default {
dispatch(ChatStore.ACTION_GET_MY_CHAT_LIST); dispatch(ChatStore.ACTION_GET_MY_CHAT_LIST);
return chatId; return chatId;
}, },
async [ChatStore.ACTION_REGISTER_EVENT]({ dispatch, commit, state }) { async [ChatStore.ACTION_REGISTER_EVENT]({
dispatch,
commit,
state,
getters,
}) {
const chatId = state[ChatStore.STATE_CHAT_CURRENT_CHAT_ID]; const chatId = state[ChatStore.STATE_CHAT_CURRENT_CHAT_ID];
const onNewMsg = (e: Message) => { const onNewMsg = (e: Message) => {
if (e.chat_id === chatId) { if (e.chat_id === chatId) {
...@@ -637,11 +665,21 @@ export default { ...@@ -637,11 +665,21 @@ export default {
if (msgs == null) return; if (msgs == null) return;
const oldestMsgId = msgs[0].id - 1; const oldestMsgId = msgs[0].id - 1;
const lastMsgId = msgs[msgs.length - 1].id + 1; const lastMsgId = msgs[msgs.length - 1].id + 1;
const chat = getters[ChatStore.GETTER_CURRENT_CURRENT_CHAT];
const o = {
model: chat.model_name,
obj: chat.obj_id,
isMember:
state[ChatStore.STATE_CHAT_CURRENT_IS_CHAT_MEMBER],
};
const freshMsgs = await xim.queryMsgs( const freshMsgs = await xim.queryMsgs(
chatType, chatType,
chatId, chatId,
oldestMsgId < 1 ? 1 : oldestMsgId, oldestMsgId < 1 ? 1 : oldestMsgId,
lastMsgId lastMsgId,
20,
true,
o
); );
commit(ChatStore.MUTATION_CLEAR_CHAT_MSG_HISTORY); commit(ChatStore.MUTATION_CLEAR_CHAT_MSG_HISTORY);
commit( commit(
......
...@@ -165,12 +165,16 @@ export class Xim { ...@@ -165,12 +165,16 @@ export class Xim {
lid = 0, lid = 0,
rid = 0, rid = 0,
limit = DefaultMsgPageSize, limit = DefaultMsgPageSize,
desc = true desc: boolean,
p: { isMember: boolean; model: string; obj: string }
): Promise<Message[]> { ): Promise<Message[]> {
this.checkConnected(); this.checkConnected();
if (this.client == null) { if (this.client == null) {
throw new Error("client shouldn't undefined"); throw new Error("client shouldn't undefined");
} }
if (!p.isMember && p.model && p.obj) {
return this.queryMessageWhenIsNotMember(p, limit, lid, rid, desc);
}
const res = await this.client.fetchChatMsgs(chatType, chatId, { const res = await this.client.fetchChatMsgs(chatType, chatId, {
lid, lid,
rid, rid,
...@@ -180,6 +184,25 @@ export class Xim { ...@@ -180,6 +184,25 @@ export class Xim {
return res.args[0]; return res.args[0];
} }
private queryMessageWhenIsNotMember(
p: { isMember: boolean; model: string; obj: string },
limit: number,
lid: number,
rid: number,
desc: boolean
) {
return chat
.getSdk()
.getAxios()
.get(
`/general/xim/model/${p.model}/${
p.obj
}/msgs?lid=${lid}&rid=${rid}&limit=${limit}&desc=${
desc ? 0 : 1
}`
);
}
private setMessagesRead(chatId: number, msg: Message[]) { private setMessagesRead(chatId: number, msg: Message[]) {
if (msg.length === 0) return; if (msg.length === 0) return;
return this.setRead(chatId, msg[0].id, msg[msg.length - 1].id); return this.setRead(chatId, msg[0].id, msg[msg.length - 1].id);
...@@ -190,10 +213,18 @@ export class Xim { ...@@ -190,10 +213,18 @@ export class Xim {
chatType: string, chatType: string,
chatId: number, chatId: number,
limit: number, limit: number,
notToRead?: boolean p: { isMember: boolean; model: string; obj: string }
) { ) {
const data = await this.queryMsgs(chatType, chatId, 0, 0, limit, true); const data = await this.queryMsgs(
if (!notToRead) { chatType,
chatId,
0,
0,
limit,
true,
p
);
if (p && p.isMember) {
this.setMessagesRead(chatId, data); this.setMessagesRead(chatId, data);
} }
return data; return data;
...@@ -205,7 +236,7 @@ export class Xim { ...@@ -205,7 +236,7 @@ export class Xim {
chatId: number, chatId: number,
msgId: number, msgId: number,
limit: number, limit: number,
notToRead?: boolean p: { isMember: boolean; model: string; obj: string }
) { ) {
const data = await this.queryMsgs( const data = await this.queryMsgs(
chatType, chatType,
...@@ -213,9 +244,10 @@ export class Xim { ...@@ -213,9 +244,10 @@ export class Xim {
0, 0,
msgId, msgId,
limit, limit,
true true,
p
); );
if (!notToRead) { if (p && p.isMember) {
this.setMessagesRead(chatId, data); this.setMessagesRead(chatId, data);
} }
return data; return data;
...@@ -227,7 +259,7 @@ export class Xim { ...@@ -227,7 +259,7 @@ export class Xim {
chatId: number, chatId: number,
msgId: number, msgId: number,
limit: number, limit: number,
notToRead?: boolean p: { isMember: boolean; model: string; obj: string }
) { ) {
const data = await this.queryMsgs( const data = await this.queryMsgs(
chatType, chatType,
...@@ -235,9 +267,10 @@ export class Xim { ...@@ -235,9 +267,10 @@ export class Xim {
msgId, msgId,
0, 0,
limit, limit,
false false,
p
); );
if (!notToRead) { if (p && p.isMember) {
this.setMessagesRead(chatId, data); this.setMessagesRead(chatId, data);
} }
return data; return data;
......
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