Commit d5f94077 by 吴云建

会话优化

parent 4fd2e1d8
<template>
<div class="chat-container" :class="{'is-in-page': isInPage}">
<div class="search-wrap" v-if="!modelName">
<el-input
class="keyword-input"
......@@ -12,8 +13,8 @@
></el-input>
<i v-if="!isInPage" class="close-btn el-icon-close" @click="$emit('close')"></i>
</div>
<chat-list v-if="!modelName" ref="chatListComp" />
<chat-list-model v-if="modelName" @update-page-info="$emit('update-page-info', $event)" ref="chatListModel"/>
<chat-list v-if="!modelName" ref="chatListComp" @list-count-update="$emit('list-count-update', $event)" />
<chat-list-model v-if="modelName" @list-count-update="$emit('list-count-update', $event)" ref="chatListModel" :modelName="modelName" :listName="listName" />
<div class="chat-content-wrap" v-if="chatVisible && onShow" >
<chat :modelName="modelName"/>
</div>
......@@ -39,9 +40,10 @@ import buttonThrottle from "../utils/button-throttle";
export default class ChatContainer extends Vue {
@Prop(Boolean) isInPage: boolean;
@Prop(String) modelName: string;
@Prop(String) listName: string;
@Prop(Boolean) isActive: boolean;
private onShow = false;
private orginPath = "";
@chatStore.State(ChatStore.STATE_CHAT_DIALOG_VISIBLE)
private readonly chatVisible!: ChatStore.STATE_CHAT_DIALOG_VISIBLE;
......@@ -58,23 +60,16 @@ export default class ChatContainer extends Vue {
this.chatListComp.search(this.searchKeyword)
}
@Watch("$route") routeUpdate() {
if (this.$route.fullPath !== this.orginPath) {
this.onShow = false;
@Watch("isActive", {immediate: true}) isActiveUpdate() {
this.onShow = this.isActive;
if (!this.onShow) {
this.chatListModel && this.chatListModel.clearActiveId();
} else {
this.onShow = true
}
}
private onChatDrawerClose(){
this.hideChat()
}
created() {
this.orginPath = this.$route.fullPath;
this.onShow = true
}
}
</script>
......@@ -82,7 +77,7 @@ export default class ChatContainer extends Vue {
.chat-container {
height: 70vh;
&.is-in-page {
height: calc(100% - 45px);
height: 100%;
}
}
.keyword-input {
......@@ -104,7 +99,7 @@ export default class ChatContainer extends Vue {
}
.search-wrap {
height: 59px;
border-bottom: 1px solid #ccc;
border-bottom: 1px solid #ddd;
}
.close-btn {
float: right;
......
......@@ -3,7 +3,6 @@
<div class="chat-list h-100">
<div class="chat-list-scroll">
<el-scrollbar ref="scrollbar" class="list-scroll no-bottom-scrollbar">
<div v-if="needUpdate" class="need-update-tip" @click="refreshFirstPage">数据有更新,请刷新</div>
<div
v-for="item in chatRooms"
:key="'room_' + item.id"
......@@ -108,16 +107,20 @@ export default class ModelChatList extends Vue {
@Prop({ type: Number, default: -1 })
private selected!: number;
@Prop({ type: String })
private modelName!: string;
@Prop({ type: String })
private listName!: string;
@Ref("scrollbar")
private scrollbar: Vue & { update: () => void };
private modelName = "";
private listName = "";
private activeId = "";
private pageSize = 10;
private total = 0;
private currentPage = 1;
private needUpdate = false;
private sseTs = 0;
private get chatRooms() {
......@@ -129,10 +132,19 @@ export default class ModelChatList extends Vue {
}
private async getList() {
const result = await this.sdk.model(this.modelName).list(this.listName || undefined).query({
let result = await this.sdk.model(this.modelName).list(this.listName || undefined).query({
pageIndex: this.currentPage,
item_size: this.pageSize
})
if (result.pageData.rows.length === 0 && this.currentPage !== 1) {
this.currentPage = 1;
if (result.pageData.record_count > 0) {
result = await this.sdk.model(this.modelName).list(this.listName || undefined).query({
pageIndex: this.currentPage,
item_size: this.pageSize
})
}
}
this.chatList = result.pageData.rows.map(it => {
return {
id: it.id.value,
......@@ -145,23 +157,14 @@ export default class ModelChatList extends Vue {
last_msg_content: it.LastMsgContent.value,
last_msg_ts: it.LastMsgTime.value,
last_msg_type: it.LastMsgType.value,
title: it.title.value
title: it.Title.value
} as ChatType
})
this.needUpdate = false;
this.hideChat();
this.total = result.pageData.record_count;
this.$emit("update-page-info", {title: result.pageData.title})
}
private async refreshFirstPage() {
this.currentPage = 1;
await this.getList();
this.$emit("list-count-update", this.total);
}
async created() {
this.modelName = this.$route.params.modelName;
this.listName = this.$route.params.listName;
await this.getList();
this.setSource(ChatStore.StateChatSourceDirection.Server);
this.scrollbar.update();
......@@ -171,10 +174,20 @@ export default class ModelChatList extends Vue {
}
onTransportMessage(e: any) {
let index = e.dataUpdates.findIndex(it => it.action === "startChat" || it.action === "csExitChat");
let index = e.dataUpdates.findIndex(it => it.action === "startChat" || it.action === "csExitChat" || it.action === "finishChat");
if (index > -1) {
this.needUpdate = true;
}
this.refreshListDebounce();
}
}
private refreshListDebounce() {
if (this.sseTs) {
return
}
setTimeout(() => {
this.sseTs = 0;
this.getList();
}, 1000)
}
mounted() {
......@@ -224,7 +237,7 @@ export default class ModelChatList extends Vue {
width: 25%;
box-sizing: border-box;
height: 100%;
border-right: 1px solid #ccc;
border-right: 1px solid #ddd;
.title {
padding-left: 20px;
line-height: 59px;
......
......@@ -57,6 +57,7 @@ import avatar from "@/customer-service/components/avatar.vue";
import { chatStore, ChatStore } from "@/customer-service/store/model";
import { formatTime, TimeFormatRule } from "@/customer-service/utils/time";
import { Chat as ChatType } from "@/customer-service/xim/models/chat";
import { EVENTS } from "@/EventConsts"
export function parserMessage(type: string, rawMsg: string) {
if (!type) return "";
......@@ -110,10 +111,14 @@ export default class ChatList extends Vue {
@Ref("scrollbar")
private scrollbar: Vue & { update: () => void };
private sseTs = 0;
private unReadMsgCount = 0;
private get chatRooms() {
return this.chatList?.list.filter(chat => chat.title.indexOf(this.searchKeyword) > -1) || [];
const list = this.chatList?.list.filter(chat => chat.title.indexOf(this.searchKeyword) > -1) || [];
this.unReadMsgCount = list.filter(chat => chat.unread_msg_count > 0).length;
this.$emit("list-count-update", this.unReadMsgCount);
this.$eventHub.$emit(EVENTS.NewMsg, this.unReadMsgCount);
return list;
}
private isSelected(item: ChatType) {
......@@ -126,39 +131,11 @@ export default class ChatList extends Vue {
async created() {
await this.getMyChatList();
this.setSource(ChatStore.StateChatSourceDirection.Server);
await this.selectFirstChat();
this.scrollbar.update();
this.$onBeforeDestroy(
await this.sdk.model("UniplatChat").registerOnChange(this.onTransportMessage)
)
}
mounted() {
this.saveMyId();
this.goToOnlyRoom();
}
onTransportMessage() {
const ts = new Date().getTime();
if (ts - this.sseTs > 100) {
this.getMyChatList()
// this.hideChat()
this.sseTs = ts;
}
}
private goToOnlyRoom() {
if (this.chatRooms.length === 1) {
const wantedChat = this.chatRooms[0];
this.goToChatRoom(wantedChat);
}
}
private async selectFirstChat() {
if (this.chatId != null) return;
if (!this.chatRooms.length) return;
const { chat_id } = this.chatRooms[0];
this.saveChatId(chat_id);
}
public async search(searchKeyword: string) {
......@@ -174,6 +151,10 @@ export default class ChatList extends Vue {
this.showChat();
this.close();
if (data.unread_msg_count > 0) {
data.unread_msg_count = 0;
}
}
private raiseChatIdChanged() {
......@@ -208,7 +189,7 @@ export default class ChatList extends Vue {
width: 25%;
box-sizing: border-box;
height: calc(100% - 59px);
border-right: 1px solid #ccc;
border-right: 1px solid #ddd;
.title {
padding-left: 20px;
line-height: 59px;
......
......@@ -17,7 +17,7 @@
<div class="title-buttons">
<el-button class="button" @click="startReception" round v-if="!isChatMember"
>开始接待</el-button
>我要接待</el-button
>
<el-button class="button" @click="exitChat" round v-if="isChatMember"
>退出会话</el-button
......@@ -81,6 +81,9 @@ export default class ChatTitle extends Vue {
@chatStore.State(ChatStore.STATE_CHAT_CURRENT_USER_TYPE)
private readonly operatorType!: ChatStore.STATE_CHAT_CURRENT_USER_TYPE;
@chatStore.Mutation(ChatStore.MUTATION_HIDE_CHAT)
private readonly hideChat: ChatStore.MUTATION_HIDE_CHAT;
private get chatMembersId() {
return this.chatMembers.map((k) => +k.eid);
}
......@@ -120,6 +123,7 @@ export default class ChatTitle extends Vue {
} else if (+this.operatorType > 25){
await this._csExitChat();
}
this.hideChat();
} catch (error) {
console.error(error);
}
......@@ -139,7 +143,8 @@ export default class ChatTitle extends Vue {
cancelButtonText: "取消",
type: "warning",
})
await this._finishReception();
await this._finishReception();
this.hideChat();
}
}
</script>
......
......@@ -193,11 +193,11 @@ export default class MessageList extends Vue {
if (wrap) {
if (delay) {
setTimeout(() => {
wrap.scrollTop = 10000;
wrap.scrollTop = 100000;
}, delay);
return;
}
wrap.scrollTop = 10000;
wrap.scrollTop = 100000;
}
});
}
......
......@@ -9,7 +9,7 @@ import { decode } from "../utils/jwt";
import { getUserInfo } from "../utils/user-info";
import Chat from "../xim";
import chatType from "../xim/chat-type";
import { Chat as ChatType } from "../xim/models/chat";
import { Chat as ChatType, Message } from "../xim/models/chat";
import xim, { ChatNotifyListener } from "../xim/xim";
import { ChatStatus, ChatStore, ChatStoreState } from "./model";
......@@ -85,6 +85,7 @@ export default {
[ChatStore.STATE_CURRENT_CHAT_MEMBERS]: null,
[ChatStore.STATE_CURRENT_CHAT_TITLE]: "",
[ChatStore.STATE_FUNC_SCROLL_TO_BOTTOM]: () => true,
[ChatStore.STATE_FUNC_ON_NEW_MSG]: () => true,
[ChatStore.STATE_CURRENT_CHAT_INPUTING]: [],
[ChatStore.STATE_CURRENT_CHAT_INITING]: false,
[ChatStore.STATE_CHAT_CURRENT_USER_TYPE]: null,
......@@ -214,6 +215,15 @@ export default {
[ChatStore.MUTATION_CLEAR_FUNC_SCROLL_TO_BOTTOM](state) {
state[ChatStore.STATE_FUNC_SCROLL_TO_BOTTOM] = () => true;
},
[ChatStore.MUTATION_SAVE_FUNC_ON_NEW_MSG](
state,
data: ChatStore.STATE_FUNC_ON_NEW_MSG
) {
state[ChatStore.STATE_FUNC_ON_NEW_MSG] = data;
},
[ChatStore.MUTATION_CLEAR_FUNC_ON_NEW_MSG](state) {
state[ChatStore.STATE_FUNC_ON_NEW_MSG] = () => true;
},
[ChatStore.MUTATION_APPEND_SENDING_MESSAGE]: (
state,
payload: ChatStore.STATE_CHAT_SENDING_MESSAGE
......@@ -449,11 +459,18 @@ export default {
await dispatch(ChatStore.ACTION_SAVE_CURRENT_CHAT_ID_VERSION, chatId);
},
async [ChatStore.ACTION_REGISTER_EVENT]({ dispatch, commit, state }) {
const chatId = state[ChatStore.STATE_CHAT_CURRENT_CHAT_ID];
if (chatId == null) return;
const onNewMsg = () => {
dispatch(ChatStore.ACTION_GET_FRESH_MESSAGE);
const onNewMsg = (e: Message) => {
if (e.chat_id === chatId) {
dispatch(ChatStore.ACTION_GET_FRESH_MESSAGE);
}
state[ChatStore.STATE_FUNC_ON_NEW_MSG](e);
};
const chatId = state[ChatStore.STATE_CHAT_CURRENT_CHAT_ID];
if (chatId == null) {
xim.off("msg", onNewMsg);
xim.on("msg", onNewMsg);
return;
}
const onMsgRead: ChatNotifyListener = async (e) => {
if (
process.env.VUE_APP_API_CLIENT_ID !==
......@@ -491,11 +508,11 @@ export default {
commit(ChatStore.MUTATION_SAVE_CURRENT_CHAT_INPUTING, e);
};
removeRegisterChatEvents.push(() => {
xim.off("msg", chatId, onNewMsg);
xim.off("msg", onNewMsg);
xim.off("chat_notify", "read", onMsgRead);
xim.off("chat_notify", "user.input", onInputing);
});
xim.on("msg", chatId, onNewMsg);
xim.on("msg", onNewMsg);
xim.on("chat_notify", "read", onMsgRead);
xim.on("chat_notify", "user.input", onInputing);
},
......
......@@ -82,6 +82,9 @@ export namespace ChatStore {
export const STATE_FUNC_SCROLL_TO_BOTTOM = "收到消息后滚动到底部的方法";
export type STATE_FUNC_SCROLL_TO_BOTTOM = () => void
export const STATE_FUNC_ON_NEW_MSG = "收到消息回调方法";
export type STATE_FUNC_ON_NEW_MSG = (e: chatDto.Message) => void
/* getter */
export const GETTER_CURRENT_CHAT_PRESENT_MEMBERS = "当前会话未退出的参与者";
export type GETTER_CURRENT_CHAT_PRESENT_MEMBERS = dto.ChatMembers | null
......@@ -189,11 +192,15 @@ export namespace ChatStore {
export const MUTATION_SAVE_FUNC_SCROLL_TO_BOTTOM =
"保存收到新消息后滚动到底部的方法";
export type MUTATION_SAVE_FUNC_SCROLL_TO_BOTTOM = (func: () => void) => void
export const MUTATION_CLEAR_FUNC_SCROLL_TO_BOTTOM =
"删除收到新消息后滚动到底部的方法";
export type MUTATION_CLEAR_FUNC_SCROLL_TO_BOTTOM = () => void
export const MUTATION_SAVE_FUNC_ON_NEW_MSG = "保存收到新消息后的方法";
export type MUTATION_SAVE_FUNC_ON_NEW_MSG = (func: (e: dto.Message) => void) => void
export const MUTATION_CLEAR_FUNC_ON_NEW_MSG = "删除收到新消息后的方法";
export type MUTATION_CLEAR_FUNC_ON_NEW_MSG = () => void
export const MUTATION_APPEND_SENDING_MESSAGE = "appendSendingMessage";
export type MUTATION_APPEND_SENDING_MESSAGE = (payload: dto.Message) => void
......@@ -320,6 +327,7 @@ export interface ChatStoreState {
[ChatStore.STATE_CURRENT_CHAT_MEMBERS]: ChatStore.STATE_CURRENT_CHAT_MEMBERS;
[ChatStore.STATE_CURRENT_CHAT_TITLE]: ChatStore.STATE_CURRENT_CHAT_TITLE;
[ChatStore.STATE_FUNC_SCROLL_TO_BOTTOM]: ChatStore.STATE_FUNC_SCROLL_TO_BOTTOM;
[ChatStore.STATE_FUNC_ON_NEW_MSG]: ChatStore.STATE_FUNC_ON_NEW_MSG;
[ChatStore.STATE_CURRENT_CHAT_INPUTING]: ChatStore.STATE_CURRENT_CHAT_INPUTING;
[ChatStore.STATE_CURRENT_CHAT_INITING]: ChatStore.STATE_CURRENT_CHAT_INITING;
[ChatStore.STATE_MY_CHAT_ROOM_LIST]: ChatStore.STATE_MY_CHAT_ROOM_LIST;
......
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