Commit 8d36ee61 by Sixong.Zhu

会话控制

parent 3347be3d
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<div <div
ref="top" ref="top"
class="chat-messages pos-rel flex-fill d-flex" class="chat-messages pos-rel flex-fill d-flex"
:class="{ 'is-not-chat-member': !isChatMember }" :class="{ 'is-not-chat-member': !hasInput }"
> >
<div <div
v-if="getCurrentInputingPeople.length" v-if="getCurrentInputingPeople.length"
...@@ -21,12 +21,12 @@ ...@@ -21,12 +21,12 @@
title="收缩侧边栏" title="收缩侧边栏"
ref="resize" ref="resize"
@mousedown="dragControllerDiv" @mousedown="dragControllerDiv"
v-if="isChatMember" v-if="hasInput"
></div> ></div>
<div <div
ref="bottom" ref="bottom"
class="chat-input flex-none h-100" class="chat-input flex-none h-100"
v-if="isChatMember" v-if="hasInput"
> >
<message-input @error="onError" /> <message-input @error="onError" />
</div> </div>
...@@ -36,206 +36,213 @@ ...@@ -36,206 +36,213 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { import {
Component, Component,
Prop, Prop,
Provide, Provide,
Ref, Ref,
Vue, Vue,
Watch, Watch,
} from "vue-property-decorator"; } from "vue-property-decorator";
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";
type RoomInfoTab = "customer" | "order"; type RoomInfoTab = "customer" | "order";
@Component({ components: { MessageInput, messages } }) @Component({ components: { MessageInput, messages } })
export default class ChatRoom extends Vue { export default class ChatRoom extends Vue {
@Ref("chatBox") chatBox!: Element; @Ref("chatBox") chatBox!: Element;
@Ref("top") refTop!: Element; @Ref("top") refTop!: Element;
@Ref("bottom") refBottom!: Element; @Ref("bottom") refBottom!: Element;
@Ref("resize") refResize!: Element; @Ref("resize") refResize!: Element;
@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.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;
@chatStore.Mutation(ChatStore.MUTATION_CLEAR_CURRENT_CHAT_MEMBERS) @chatStore.Mutation(ChatStore.MUTATION_CLEAR_CURRENT_CHAT_MEMBERS)
private readonly clearChatMembers!: ChatStore.MUTATION_CLEAR_CURRENT_CHAT_MEMBERS; private readonly clearChatMembers!: ChatStore.MUTATION_CLEAR_CURRENT_CHAT_MEMBERS;
@chatStore.State(ChatStore.STATE_CURRENT_CHAT_TITLE) @chatStore.State(ChatStore.STATE_CURRENT_CHAT_TITLE)
private readonly chatTitle!: ChatStore.STATE_CURRENT_CHAT_TITLE; private readonly chatTitle!: ChatStore.STATE_CURRENT_CHAT_TITLE;
@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) @chatStore.State(ChatStore.STATE_CHAT_CURRENT_CHAT_UNIPLAT_ID)
private readonly currentChatUniplatId!: ChatStore.STATE_CHAT_CURRENT_CHAT_UNIPLAT_ID; private readonly currentChatUniplatId!: ChatStore.STATE_CHAT_CURRENT_CHAT_UNIPLAT_ID;
@chatStore.State(ChatStore.STATE_MY_CHAT_ROOM_LIST) @chatStore.State(ChatStore.STATE_MY_CHAT_ROOM_LIST)
private readonly myChatList!: ChatStore.STATE_MY_CHAT_ROOM_LIST; private readonly myChatList!: ChatStore.STATE_MY_CHAT_ROOM_LIST;
@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;
private allChatList = { list: [] }; @chatStore.State(ChatStore.STATE_CHAT_CURRENT_IS_CHAT_ERROR)
private readonly chatError: ChatStore.STATE_CHAT_CURRENT_IS_CHAT_ERROR;
@Prop({ type: Function }) private get hasInput() {
private close?: () => void; return this.isChatMember && this.chatError !== this.chatId;
}
@Provide() showReadSummary = true; private allChatList = { list: [] };
@Watch("currentChatUniplatId") @Prop({ type: Function })
private whenCurrentChatIdChanged(newValue: string, oldValue: string) { private close?: () => void;
if (Number(oldValue) === Number(newValue)) return;
this.clearChatMembers();
}
private activeTab: RoomInfoTab = "customer"; @Provide() showReadSummary = true;
private get getCurrentInputingPeople() { @Watch("currentChatUniplatId")
return this.currentInputPeople private whenCurrentChatIdChanged(newValue: string, oldValue: string) {
.map(() => "" /* this.userInfo[k].name */) if (Number(oldValue) === Number(newValue)) return;
.join("、"); this.clearChatMembers();
} }
private get currentChat() { private activeTab: RoomInfoTab = "customer";
const chatId = this.chatId;
if (this.myChatList == null) return;
const result = this.myChatList.list.find((k) => k.chat_id === chatId);
return result ?? {};
}
private get customerInfoTabShow() { private get getCurrentInputingPeople() {
return this.activeTab === "customer"; return this.currentInputPeople
} .map(() => "" /* this.userInfo[k].name */)
.join("、");
}
private get orderInfoTabShow() { private get currentChat() {
return this.activeTab === "order"; const chatId = this.chatId;
} if (this.myChatList == null) return;
const result = this.myChatList.list.find((k) => k.chat_id === chatId);
return result ?? {};
}
private onError(msg: string) { private get customerInfoTabShow() {
this.$message.error(msg); return this.activeTab === "customer";
} }
private dragControllerDiv(e: MouseEvent) { private get orderInfoTabShow() {
const resize = this.refResize as any; return this.activeTab === "order";
const top = this.refTop as HTMLElement; }
const bottom = this.refBottom as HTMLElement;
const box = this.chatBox as HTMLElement;
const startY = e.clientY;
const originTop = resize.offsetTop;
document.onmousemove = function (e) {
const endY = e.clientY;
let moveLen = originTop + (endY - startY); // (endY-startY) = 移动的距离。originTop + 移动的距离 = 顶部区域最后的高度
if (moveLen < 300) moveLen = 300; // 上部区域的最小高度为300px
if (box.clientHeight - moveLen < 150) {
moveLen = box.clientHeight - 150;
}
const bottomHeight = box.clientHeight - moveLen;
resize.style.top = moveLen + "px"; // 设置左侧区域的宽度
top.style.height = moveLen + "px";
bottom.style.height = bottomHeight + "px";
};
document.onmouseup = function () {
document.onmousemove = null;
document.onmouseup = null;
resize.releaseCapture && resize.releaseCapture();
};
resize.setCapture && resize.setCapture();
return false;
}
mounted() { private onError(msg: string) {
this.refBottom && this.$message.error(msg);
((this.refBottom as HTMLElement).style.height = }
this.chatBox.clientHeight - this.refTop.clientHeight + "px");
}
}
</script>
<style lang="less" scoped> private dragControllerDiv(e: MouseEvent) {
.chat-status { const resize = this.refResize as any;
display: inline-block; const top = this.refTop as HTMLElement;
width: 46px; const bottom = this.refBottom as HTMLElement;
height: 20px; const box = this.chatBox as HTMLElement;
line-height: 20px;
background: #22bd7a; const startY = e.clientY;
font-size: 13px; const originTop = resize.offsetTop;
border-radius: 2px; document.onmousemove = function (e) {
color: #ffffff; const endY = e.clientY;
text-align: center; let moveLen = originTop + (endY - startY); // (endY-startY) = 移动的距离。originTop + 移动的距离 = 顶部区域最后的高度
margin-left: 10px; if (moveLen < 300) moveLen = 300; // 上部区域的最小高度为300px
&.chat-done { if (box.clientHeight - moveLen < 150) {
background: #c5d4e5; moveLen = box.clientHeight - 150;
} }
} const bottomHeight = box.clientHeight - moveLen;
resize.style.top = moveLen + "px"; // 设置左侧区域的宽度
top.style.height = moveLen + "px";
bottom.style.height = bottomHeight + "px";
};
document.onmouseup = function () {
document.onmousemove = null;
document.onmouseup = null;
resize.releaseCapture && resize.releaseCapture();
};
resize.setCapture && resize.setCapture();
return false;
}
.chat-panel { mounted() {
height: 100%; this.refBottom &&
.chat-area, ((this.refBottom as HTMLElement).style.height =
.chat-info { this.chatBox.clientHeight - this.refTop.clientHeight + "px");
display: inline-block; }
vertical-align: top;
}
.chat-info {
width: 349px;
border-left: 1px solid #e1e1e1;
} }
} </script>
.info-tabs {
height: 40px;
line-height: 40px;
border-bottom: 1px solid #f0f0f0;
.info-tab { <style lang="less" scoped>
.chat-status {
display: inline-block; display: inline-block;
vertical-align: top; width: 46px;
width: 50%; height: 20px;
line-height: 20px;
background: #22bd7a;
font-size: 13px;
border-radius: 2px;
color: #ffffff;
text-align: center; text-align: center;
font-size: 15px; margin-left: 10px;
color: #333; &.chat-done {
cursor: pointer; background: #c5d4e5;
}
}
&.active { .chat-panel {
font-weight: 600; height: 100%;
.chat-area,
.chat-info {
display: inline-block;
vertical-align: top;
}
.chat-info {
width: 349px;
border-left: 1px solid #e1e1e1;
} }
} }
} .info-tabs {
.chat-area { height: 40px;
position: relative; line-height: 40px;
width: 100%; border-bottom: 1px solid #f0f0f0;
overflow: hidden;
.chat-messages { .info-tab {
height: calc(100% - 130px + 1px); display: inline-block;
border-bottom: 1px solid #e1e1e1; vertical-align: top;
&.is-not-chat-member { width: 50%;
height: calc(100% - 50px); text-align: center;
border-bottom: none; font-size: 15px;
color: #333;
cursor: pointer;
&.active {
font-weight: 600;
}
} }
} }
.resize { .chat-area {
cursor: row-resize; position: relative;
position: absolute;
left: 0;
top: calc(100% - 130px + 1px);
height: 6px;
width: 100%; width: 100%;
overflow: hidden;
.chat-messages {
height: calc(100% - 130px + 1px);
border-bottom: 1px solid #e1e1e1;
&.is-not-chat-member {
height: calc(100% - 50px);
border-bottom: none;
}
}
.resize {
cursor: row-resize;
position: absolute;
left: 0;
top: calc(100% - 130px + 1px);
height: 6px;
width: 100%;
}
}
.order-info-con {
height: calc(100% - 40px);
}
.someone-inputing {
position: absolute;
left: 20px;
bottom: 20px;
z-index: 1;
color: #c2c2c2;
} }
}
.order-info-con {
height: calc(100% - 40px);
}
.someone-inputing {
position: absolute;
left: 20px;
bottom: 20px;
z-index: 1;
color: #c2c2c2;
}
</style> </style>
...@@ -21,9 +21,14 @@ ...@@ -21,9 +21,14 @@
size="small" size="small"
v-if="!isChatMember" v-if="!isChatMember"
type="primary" type="primary"
:disabled="isChatError"
>我要接待</el-button >我要接待</el-button
> >
<el-button class="button" @click="showAddMember" size="small" <el-button
class="button"
@click="showAddMember"
size="small"
:disabled="isChatError"
>添加客服</el-button >添加客服</el-button
> >
<el-button <el-button
...@@ -32,6 +37,7 @@ ...@@ -32,6 +37,7 @@
size="small" size="small"
v-if="isChatMember && operatorType > 25" v-if="isChatMember && operatorType > 25"
type="warning" type="warning"
:disabled="isChatError"
>结束接待</el-button >结束接待</el-button
> >
<el-button <el-button
...@@ -40,6 +46,7 @@ ...@@ -40,6 +46,7 @@
size="small" size="small"
v-if="isChatMember" v-if="isChatMember"
type="danger" type="danger"
:disabled="isChatError"
>退出会话</el-button >退出会话</el-button
> >
<i <i
...@@ -58,164 +65,171 @@ ...@@ -58,164 +65,171 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { Component, Prop, Vue } from "vue-property-decorator"; import { Component, Prop, Vue } from "vue-property-decorator";
import ChatCreator from "@/customer-service/components/create-chat.vue"; import ChatCreator from "@/customer-service/components/create-chat.vue";
import { ChatStore, chatStore } from "@/customer-service/store/model"; import { ChatStore, chatStore } from "@/customer-service/store/model";
import { ChatRole } from "../model"; import { ChatRole } from "../model";
import { import {
ChatChangedEvent, ChatChangedEvent,
ChatEventHandler, ChatEventHandler,
} from "./controller/chat-event-handler"; } from "./controller/chat-event-handler";
@Component({ components: { ChatCreator } }) @Component({ components: { ChatCreator } })
export default class ChatTitle extends Vue { export default class ChatTitle extends Vue {
@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.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;
@chatStore.State(ChatStore.STATE_CURRENT_CHAT_TITLE) @chatStore.State(ChatStore.STATE_CURRENT_CHAT_TITLE)
private readonly chatTitle!: ChatStore.STATE_CURRENT_CHAT_TITLE; private readonly chatTitle!: ChatStore.STATE_CURRENT_CHAT_TITLE;
@chatStore.State(ChatStore.STATE_CHAT_DIALOG_IS_SINGLE) @chatStore.State(ChatStore.STATE_CHAT_DIALOG_IS_SINGLE)
private readonly isSingleChat: ChatStore.STATE_CHAT_DIALOG_IS_SINGLE; private readonly isSingleChat: ChatStore.STATE_CHAT_DIALOG_IS_SINGLE;
@chatStore.Action(ChatStore.ACTION_CHAT_ADD_CS) @chatStore.State(ChatStore.STATE_CHAT_CURRENT_IS_CHAT_ERROR)
private readonly _addCS!: ChatStore.ACTION_CHAT_ADD_CS; private readonly chatError: ChatStore.STATE_CHAT_CURRENT_IS_CHAT_ERROR;
@chatStore.Action(ChatStore.ACTION_CHAT_START_RECEPTION) @chatStore.Action(ChatStore.ACTION_CHAT_ADD_CS)
private readonly _startReception!: ChatStore.ACTION_CHAT_START_RECEPTION; private readonly _addCS!: ChatStore.ACTION_CHAT_ADD_CS;
@chatStore.Action(ChatStore.ACTION_CHAT_FINISH_RECEPTION) @chatStore.Action(ChatStore.ACTION_CHAT_START_RECEPTION)
private readonly _finishReception!: ChatStore.ACTION_CHAT_FINISH_RECEPTION; private readonly _startReception!: ChatStore.ACTION_CHAT_START_RECEPTION;
@chatStore.Action(ChatStore.ACTION_CHAT_USER_EXIT) @chatStore.Action(ChatStore.ACTION_CHAT_FINISH_RECEPTION)
private readonly _userExitChat!: ChatStore.ACTION_CHAT_USER_EXIT; private readonly _finishReception!: ChatStore.ACTION_CHAT_FINISH_RECEPTION;
@chatStore.Action(ChatStore.ACTION_CHAT_CS_EXIT) @chatStore.Action(ChatStore.ACTION_CHAT_USER_EXIT)
private readonly _csExitChat!: ChatStore.ACTION_CHAT_CS_EXIT; private readonly _userExitChat!: ChatStore.ACTION_CHAT_USER_EXIT;
@chatStore.State(ChatStore.STATE_CHAT_CURRENT_IS_CHAT_MEMBER) @chatStore.Action(ChatStore.ACTION_CHAT_CS_EXIT)
private readonly isChatMember!: ChatStore.STATE_CHAT_CURRENT_IS_CHAT_MEMBER; private readonly _csExitChat!: ChatStore.ACTION_CHAT_CS_EXIT;
@chatStore.State(ChatStore.STATE_CHAT_CURRENT_USER_UID) @chatStore.State(ChatStore.STATE_CHAT_CURRENT_IS_CHAT_MEMBER)
private readonly operatorUid!: ChatStore.STATE_CHAT_CURRENT_USER_UID; private readonly isChatMember!: ChatStore.STATE_CHAT_CURRENT_IS_CHAT_MEMBER;
@chatStore.State(ChatStore.STATE_CHAT_CURRENT_USER_TYPE) @chatStore.State(ChatStore.STATE_CHAT_CURRENT_USER_UID)
private readonly operatorType!: ChatStore.STATE_CHAT_CURRENT_USER_TYPE; private readonly operatorUid!: ChatStore.STATE_CHAT_CURRENT_USER_UID;
@chatStore.Mutation(ChatStore.MUTATION_HIDE_CHAT) @chatStore.State(ChatStore.STATE_CHAT_CURRENT_USER_TYPE)
private readonly hideChat: ChatStore.MUTATION_HIDE_CHAT; private readonly operatorType!: ChatStore.STATE_CHAT_CURRENT_USER_TYPE;
private get chatMembersId() { @chatStore.Mutation(ChatStore.MUTATION_HIDE_CHAT)
return this.chatMembers.map((k) => +k.eid); private readonly hideChat: ChatStore.MUTATION_HIDE_CHAT;
}
private visible = false; private get isChatError() {
return this.chatError === this.chatId;
}
private get notOnlyCheck(): boolean { private get chatMembersId() {
return true; return this.chatMembers.map((k) => +k.eid);
} }
@Prop({ type: Function }) private visible = false;
private close?: () => void;
private showAddMember() { private get notOnlyCheck(): boolean {
this.visible = true; return true;
} }
private hideAddMember() { @Prop({ type: Function })
this.visible = false; private close?: () => void;
}
private async addMember(users: string[], done: () => void) { private showAddMember() {
try { this.visible = true;
await this._addCS(users);
this.hideAddMember();
} catch (error) {
console.error(error);
} finally {
done();
} }
}
private noop() { private hideAddMember() {
return 1; this.visible = false;
} }
private async exitChat() { private async addMember(users: string[], done: () => void) {
this.$confirm("确认要退出此会话?") try {
.then(async () => { await this._addCS(users);
try { this.hideAddMember();
if (+this.operatorType === ChatRole.Default) { } catch (error) {
await this._userExitChat(); console.error(error);
} else if (+this.operatorType > ChatRole.Default) { } finally {
await this._csExitChat(); done();
} }
this.hideChat(); }
} catch (error) {
console.error(error);
}
})
.catch(this.noop);
}
private async startReception() { private noop() {
try { return 1;
await this._startReception().then(() => }
ChatEventHandler.raiseChatChanged(
ChatChangedEvent.Start, private async exitChat() {
this.chatId this.$confirm("确认要退出此会话?")
) .then(async () => {
); try {
this.$emit("updateActive", "my_receiving"); if (+this.operatorType === ChatRole.Default) {
} catch (error) { await this._userExitChat();
console.error(error); } else if (+this.operatorType > ChatRole.Default) {
await this._csExitChat();
}
this.hideChat();
} catch (error) {
console.error(error);
}
})
.catch(this.noop);
} }
}
private async finishReception() { private async startReception() {
await this.$confirm( try {
"确定要结束接待吗?结束接待将会终止客服会话", await this._startReception().then(() =>
"提示", ChatEventHandler.raiseChatChanged(
{ ChatChangedEvent.Start,
confirmButtonText: "确定", this.chatId
cancelButtonText: "取消", )
type: "warning", );
this.$emit("updateActive", "my_receiving");
} catch (error) {
console.error(error);
} }
); }
await this._finishReception().then(() =>
ChatEventHandler.raiseChatChanged(ChatChangedEvent.End, this.chatId) private async finishReception() {
); await this.$confirm(
this.hideChat(); "确定要结束接待吗?结束接待将会终止客服会话",
"提示",
{
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}
);
await this._finishReception().then(() =>
ChatEventHandler.raiseChatChanged(ChatChangedEvent.End, this.chatId)
);
this.hideChat();
}
} }
}
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.room-title { .room-title {
font-size: 16px; font-size: 16px;
padding: 0 20px; padding: 0 20px;
height: 60px; height: 60px;
min-height: 60px; min-height: 60px;
border-bottom: 1px solid #e1e1e1; border-bottom: 1px solid #e1e1e1;
.title { .title {
cursor: pointer; cursor: pointer;
} }
.members-count { .members-count {
color: #666666; color: #666666;
} }
.title-right-arrow { .title-right-arrow {
font-size: 10px; font-size: 10px;
margin-left: 10px; margin-left: 10px;
vertical-align: middle; vertical-align: middle;
color: #666; color: #666;
} }
.title-close { .title-close {
color: #8d959d; color: #8d959d;
cursor: pointer; cursor: pointer;
margin-left: 30px; margin-left: 30px;
}
} }
}
</style> </style>
...@@ -128,7 +128,7 @@ ...@@ -128,7 +128,7 @@
}; };
img.remove(); img.remove();
} }
uploadFile(file) return uploadFile(file)
.then((r) => { .then((r) => {
if (r) { if (r) {
const msg = { const msg = {
...@@ -150,6 +150,7 @@ ...@@ -150,6 +150,7 @@
}); });
this.removeSendingMessages(index); this.removeSendingMessages(index);
URL.revokeObjectURL(src.url); URL.revokeObjectURL(src.url);
return index;
} else { } else {
this.setMsg2Failed(index); this.setMsg2Failed(index);
} }
......
...@@ -196,6 +196,7 @@ export const MAX_IMAGE_SIZE = 5 * 1024 * 1024; ...@@ -196,6 +196,7 @@ export const MAX_IMAGE_SIZE = 5 * 1024 * 1024;
export const MAX_IMAGE_SIZE_STRING = "5MB"; export const MAX_IMAGE_SIZE_STRING = "5MB";
export const MESSAGE_IMAGE_TOO_LARGE = `您发送的图片大小超过 ${MAX_IMAGE_SIZE_STRING}。`; export const MESSAGE_IMAGE_TOO_LARGE = `您发送的图片大小超过 ${MAX_IMAGE_SIZE_STRING}。`;
export const MESSAGE_FILE_EMPTY = "不能发送空文件。"; export const MESSAGE_FILE_EMPTY = "不能发送空文件。";
export const ERROR_IMAGE = "发送的不是图片";
/** /**
* 最大文件大小 * 最大文件大小
......
...@@ -69,9 +69,6 @@ ...@@ -69,9 +69,6 @@
@chatStore.Action(ChatStore.ACTION_GET_CHAT_MESSAGES_AFTER_SPECIFIC_ID) @chatStore.Action(ChatStore.ACTION_GET_CHAT_MESSAGES_AFTER_SPECIFIC_ID)
private readonly getNextPageMsg!: ChatStore.ACTION_GET_CHAT_MESSAGES_AFTER_SPECIFIC_ID; private readonly getNextPageMsg!: ChatStore.ACTION_GET_CHAT_MESSAGES_AFTER_SPECIFIC_ID;
@chatStore.Action(ChatStore.ACTION_CLEAR_CURRENT_CHAT_DATA)
private readonly clearChatId!: ChatStore.ACTION_CLEAR_CURRENT_CHAT_DATA;
@chatStore.Mutation(ChatStore.MUTATION_SAVE_FUNC_SCROLL_TO_BOTTOM) @chatStore.Mutation(ChatStore.MUTATION_SAVE_FUNC_SCROLL_TO_BOTTOM)
private readonly saveScrollToBottomFunc!: ChatStore.MUTATION_SAVE_FUNC_SCROLL_TO_BOTTOM; private readonly saveScrollToBottomFunc!: ChatStore.MUTATION_SAVE_FUNC_SCROLL_TO_BOTTOM;
...@@ -87,6 +84,9 @@ ...@@ -87,6 +84,9 @@
@chatStore.Mutation(ChatStore.MUTATION_WITHDRAW) @chatStore.Mutation(ChatStore.MUTATION_WITHDRAW)
private readonly executeWithDraw!: ChatStore.MUTATION_WITHDRAW; private readonly executeWithDraw!: ChatStore.MUTATION_WITHDRAW;
@chatStore.Action(ChatStore.ACTION_SET_CHAT_ERROR)
private readonly setError!: ChatStore.ACTION_SET_CHAT_ERROR;
@Prop({ default: "circle" }) @Prop({ default: "circle" })
private shape!: string; private shape!: string;
...@@ -148,6 +148,14 @@ ...@@ -148,6 +148,14 @@
} }
} }
@Watch("chatId")
private onChatChanged(o: number, n: number) {
o && n && this.messages.length
? this.fetchNewMsg()
: setTimeout(() => this.fetchNewMsg(), 300);
this.scroll2End(this.messages.length ? 0 : 100);
}
private raiseFileOpen(value: boolean) { private raiseFileOpen(value: boolean) {
this.$emit("file-open", value); this.$emit("file-open", value);
} }
...@@ -204,7 +212,6 @@ ...@@ -204,7 +212,6 @@
this.scollWrapper.removeEventListener("scroll", this.handleScroll); this.scollWrapper.removeEventListener("scroll", this.handleScroll);
this.clearScrollToBottomFunc(); this.clearScrollToBottomFunc();
this.clearNewMessage(); this.clearNewMessage();
// this.clearChatId();
} }
public scroll2End(delay?: number) { public scroll2End(delay?: number) {
...@@ -325,13 +332,25 @@ ...@@ -325,13 +332,25 @@
if (msg.length === 0) return; if (msg.length === 0) return;
this.startLoadingNew(); this.startLoadingNew();
const msgId = getLastMessageId(msg); const msgId = getLastMessageId(msg);
const data = await this.getNextPageMsg(msgId); return this.getNextPageMsg(msgId)
if (data.length === 0) { .then((data) => {
// eslint-disable-next-line no-console if (data.length === 0) {
console.log("没有更多新消息了"); // eslint-disable-next-line no-console
} console.log("没有更多新消息了");
this.$emit("next-page", msgId); }
this.endLoadingNew(); this.$emit("next-page", msgId);
this.endLoadingNew();
})
.catch((e) => {
if (
e &&
e.message &&
(e.message as string).includes("sql: no rows in result set")
) {
this.setError(this.chatId);
}
})
.finally(() => this.endLoadingNew());
} }
private format2Time(time: number) { private format2Time(time: number) {
......
...@@ -18,9 +18,17 @@ ...@@ -18,9 +18,17 @@
src="@/customer-service/imgs/pic.png" src="@/customer-service/imgs/pic.png"
/> />
</label> </label>
<!-- <label for="chat-upload-file" :title="tip4File" @click="allowLoadFile"> <label
<img class="tool-bar-icon" src="@/customer-service/imgs/file.png" /> for="chat-upload-file"
</label> --> :title="tip4File"
@click="allowLoadFile"
v-if="enableFileSelection"
>
<img
class="tool-bar-icon"
src="@/customer-service/imgs/file.png"
/>
</label>
<input <input
@change="onChange" @change="onChange"
...@@ -63,6 +71,7 @@ ...@@ -63,6 +71,7 @@
import { Component, Ref, Vue, Watch } from "vue-property-decorator"; import { Component, Ref, Vue, Watch } from "vue-property-decorator";
import { namespace } from "vuex-class"; import { namespace } from "vuex-class";
import { import {
ERROR_IMAGE,
getFileType, getFileType,
getSvg, getSvg,
MAX_FILE_SIZE, MAX_FILE_SIZE,
...@@ -130,6 +139,8 @@ ...@@ -130,6 +139,8 @@
private tip4Image = `发送图片(最大${MAX_IMAGE_SIZE_STRING})`; private tip4Image = `发送图片(最大${MAX_IMAGE_SIZE_STRING})`;
private tip4File = `发送文件(最大${MAX_FILE_SIZE_STRING})`; private tip4File = `发送文件(最大${MAX_FILE_SIZE_STRING})`;
private enableFileSelection = false;
private emoji: EmojiItem[] = []; private emoji: EmojiItem[] = [];
@Watch("chatId") @Watch("chatId")
...@@ -489,6 +500,15 @@ ...@@ -489,6 +500,15 @@
this.$emit("error", MESSAGE_FILE_EMPTY); this.$emit("error", MESSAGE_FILE_EMPTY);
return; return;
} }
if (
this.enableFileSelection &&
file.size >= MAX_FILE_SIZE
) {
this.$emit("error", MESSAGE_FILE_TOO_LARGE);
return;
}
if (this.isImage(file)) { if (this.isImage(file)) {
if (file.size >= MAX_IMAGE_SIZE) { if (file.size >= MAX_IMAGE_SIZE) {
this.$emit("error", MESSAGE_IMAGE_TOO_LARGE); this.$emit("error", MESSAGE_IMAGE_TOO_LARGE);
...@@ -496,11 +516,11 @@ ...@@ -496,11 +516,11 @@
} }
html += this.buildImageHtml(file); html += this.buildImageHtml(file);
} else { } else {
if (file.size >= MAX_FILE_SIZE) { if (this.enableFileSelection) {
this.$emit("error", MESSAGE_FILE_TOO_LARGE); html += this.buildFileHtml(file);
return; } else {
return this.$emit("error", ERROR_IMAGE);
} }
html += this.buildFileHtml(file);
} }
} }
......
...@@ -31,7 +31,7 @@ function uniqueMessages( ...@@ -31,7 +31,7 @@ function uniqueMessages(
messages: NonNullable<ChatStore.STATE_CHAT_MSG_HISTORY> messages: NonNullable<ChatStore.STATE_CHAT_MSG_HISTORY>
) { ) {
const arr = [...messages]; const arr = [...messages];
return unique(arr, function(item, all) { return unique(arr, function (item, all) {
return all.findIndex((k) => k.id === item.id); return all.findIndex((k) => k.id === item.id);
}); });
} }
...@@ -119,6 +119,7 @@ export default { ...@@ -119,6 +119,7 @@ export default {
[ChatStore.STATE_CHAT_DIALOG_VISIBLE]: false, [ChatStore.STATE_CHAT_DIALOG_VISIBLE]: false,
[ChatStore.STATE_CHAT_DIALOG_IS_SINGLE]: false, [ChatStore.STATE_CHAT_DIALOG_IS_SINGLE]: false,
[ChatStore.STATE_CHAT_CURRENT_IS_CHAT_MEMBER]: false, [ChatStore.STATE_CHAT_CURRENT_IS_CHAT_MEMBER]: false,
[ChatStore.STATE_CHAT_CURRENT_IS_CHAT_ERROR]: null,
[ChatStore.STATE_CHAT_CURRENT_CHAT_UNIPLAT_ID]: null, [ChatStore.STATE_CHAT_CURRENT_CHAT_UNIPLAT_ID]: null,
[ChatStore.STATE_CHAT_CURRENT_USER_UID]: null, [ChatStore.STATE_CHAT_CURRENT_USER_UID]: null,
[ChatStore.STATE_CHAT_MSG_HISTORY]: null, [ChatStore.STATE_CHAT_MSG_HISTORY]: null,
...@@ -326,7 +327,7 @@ export default { ...@@ -326,7 +327,7 @@ export default {
state[ChatStore.STATE_CHAT_SENDING_MESSAGES] = [...current]; state[ChatStore.STATE_CHAT_SENDING_MESSAGES] = [...current];
} }
}, },
[ChatStore.MUTATION_SAVE_CURRENT_CHAT_INPUTING]: (function() { [ChatStore.MUTATION_SAVE_CURRENT_CHAT_INPUTING]: (function () {
const setTimeoutId: { [key: string]: number } = {}; const setTimeoutId: { [key: string]: number } = {};
return ( return (
state: ChatStoreState, state: ChatStoreState,
...@@ -683,13 +684,15 @@ export default { ...@@ -683,13 +684,15 @@ export default {
); );
commit(ChatStore.MUTATION_INITING_CHAT_DONE); commit(ChatStore.MUTATION_INITING_CHAT_DONE);
commit(ChatStore.MUTATION_SCROLL_TO_BOTTOM); commit(ChatStore.MUTATION_SCROLL_TO_BOTTOM);
state[ChatStore.STATE_CHAT_CURRENT_IS_CHAT_ERROR] = null;
}, },
async [ChatStore.ACTION_CLEAR_CURRENT_CHAT_DATA]({ commit }) { async [ChatStore.ACTION_CLEAR_CURRENT_CHAT_DATA]({ commit, state }) {
commit(ChatStore.MUTATION_CLEAR_CURRENT_CHAT_ID); commit(ChatStore.MUTATION_CLEAR_CURRENT_CHAT_ID);
commit(ChatStore.MUTATION_CLEAR_MYSELF_ID); commit(ChatStore.MUTATION_CLEAR_MYSELF_ID);
commit(ChatStore.MUTATION_CLEAR_CHAT_MSG_HISTORY); commit(ChatStore.MUTATION_CLEAR_CHAT_MSG_HISTORY);
commit(ChatStore.MUTATION_CLEAR_CHAT_TITLE); commit(ChatStore.MUTATION_CLEAR_CHAT_TITLE);
commit(ChatStore.MUTATION_CLEAR_CURRENT_CHAT_MEMBERS); commit(ChatStore.MUTATION_CLEAR_CURRENT_CHAT_MEMBERS);
state[ChatStore.STATE_CHAT_CURRENT_IS_CHAT_ERROR] = null;
}, },
async [ChatStore.ACTION_GET_CHAT_MEMBERS]({ commit, state }) { async [ChatStore.ACTION_GET_CHAT_MEMBERS]({ commit, state }) {
const chatId = state[ChatStore.STATE_CHAT_CURRENT_CHAT_ID]; const chatId = state[ChatStore.STATE_CHAT_CURRENT_CHAT_ID];
...@@ -729,7 +732,7 @@ export default { ...@@ -729,7 +732,7 @@ export default {
} }
commit( commit(
ChatStore.MUTATION_SAVE_CURRENT_CHAT_MEMBERS, ChatStore.MUTATION_SAVE_CURRENT_CHAT_MEMBERS,
unique(newChatMembers, function(item, all) { unique(newChatMembers, function (item, all) {
return all.findIndex((k) => k.eid === item.eid); return all.findIndex((k) => k.eid === item.eid);
}) })
); );
...@@ -916,6 +919,9 @@ export default { ...@@ -916,6 +919,9 @@ export default {
.updateChat(p) .updateChat(p)
.finally(() => dispatch(ChatStore.ACTION_GET_MY_CHAT_LIST)); .finally(() => dispatch(ChatStore.ACTION_GET_MY_CHAT_LIST));
}, },
[ChatStore.ACTION_SET_CHAT_ERROR]: ({ state }, chat: number) => {
state[ChatStore.STATE_CHAT_CURRENT_IS_CHAT_ERROR] = chat;
},
}, },
getters: { getters: {
[ChatStore.STATE_CHAT_MSG_HISTORY](state) { [ChatStore.STATE_CHAT_MSG_HISTORY](state) {
......
...@@ -44,6 +44,9 @@ export namespace ChatStore { ...@@ -44,6 +44,9 @@ export namespace ChatStore {
"当前用户类型状态,25-普通用户,92-客服"; "当前用户类型状态,25-普通用户,92-客服";
export type STATE_CHAT_CURRENT_USER_TYPE = string | null; export type STATE_CHAT_CURRENT_USER_TYPE = string | null;
export const STATE_CHAT_CURRENT_IS_CHAT_ERROR = "当前会话是否错误";
export type STATE_CHAT_CURRENT_IS_CHAT_ERROR = number | null;
export const STATE_CHAT_CURRENT_CHAT_UNIPLAT_ID = "当前chat的Uniplat id"; export const STATE_CHAT_CURRENT_CHAT_UNIPLAT_ID = "当前chat的Uniplat id";
export type STATE_CHAT_CURRENT_CHAT_UNIPLAT_ID = string | null; export type STATE_CHAT_CURRENT_CHAT_UNIPLAT_ID = string | null;
...@@ -344,6 +347,9 @@ export namespace ChatStore { ...@@ -344,6 +347,9 @@ export namespace ChatStore {
value: dto.MessageHandled; value: dto.MessageHandled;
}) => void; }) => void;
export const ACTION_SET_CHAT_ERROR = "标记会话关键性错误";
export type ACTION_SET_CHAT_ERROR = (chat: number) => void;
export interface ChatUpdateParameter { export interface ChatUpdateParameter {
chat: number; chat: number;
type?: dto.MessageType; type?: dto.MessageType;
......
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