Commit 8d36ee61 by Sixong.Zhu

会话控制

parent 3347be3d
......@@ -5,7 +5,7 @@
<div
ref="top"
class="chat-messages pos-rel flex-fill d-flex"
:class="{ 'is-not-chat-member': !isChatMember }"
:class="{ 'is-not-chat-member': !hasInput }"
>
<div
v-if="getCurrentInputingPeople.length"
......@@ -21,12 +21,12 @@
title="收缩侧边栏"
ref="resize"
@mousedown="dragControllerDiv"
v-if="isChatMember"
v-if="hasInput"
></div>
<div
ref="bottom"
class="chat-input flex-none h-100"
v-if="isChatMember"
v-if="hasInput"
>
<message-input @error="onError" />
</div>
......@@ -36,22 +36,22 @@
</template>
<script lang="ts">
import {
import {
Component,
Prop,
Provide,
Ref,
Vue,
Watch,
} from "vue-property-decorator";
import MessageInput from "@/customer-service/components/message-input.vue";
import messages from "@/customer-service/components/message-list.vue";
import { ChatStore, chatStore } from "@/customer-service/store/model";
} from "vue-property-decorator";
import MessageInput from "@/customer-service/components/message-input.vue";
import messages from "@/customer-service/components/message-list.vue";
import { ChatStore, chatStore } from "@/customer-service/store/model";
type RoomInfoTab = "customer" | "order";
type RoomInfoTab = "customer" | "order";
@Component({ components: { MessageInput, messages } })
export default class ChatRoom extends Vue {
@Component({ components: { MessageInput, messages } })
export default class ChatRoom extends Vue {
@Ref("chatBox") chatBox!: Element;
@Ref("top") refTop!: Element;
@Ref("bottom") refBottom!: Element;
......@@ -81,6 +81,13 @@ export default class ChatRoom extends Vue {
@chatStore.State(ChatStore.STATE_CHAT_CURRENT_IS_CHAT_MEMBER)
private readonly isChatMember!: ChatStore.STATE_CHAT_CURRENT_IS_CHAT_MEMBER;
@chatStore.State(ChatStore.STATE_CHAT_CURRENT_IS_CHAT_ERROR)
private readonly chatError: ChatStore.STATE_CHAT_CURRENT_IS_CHAT_ERROR;
private get hasInput() {
return this.isChatMember && this.chatError !== this.chatId;
}
private allChatList = { list: [] };
@Prop({ type: Function })
......@@ -156,11 +163,11 @@ export default class ChatRoom extends Vue {
((this.refBottom as HTMLElement).style.height =
this.chatBox.clientHeight - this.refTop.clientHeight + "px");
}
}
}
</script>
<style lang="less" scoped>
.chat-status {
.chat-status {
display: inline-block;
width: 46px;
height: 20px;
......@@ -174,9 +181,9 @@ export default class ChatRoom extends Vue {
&.chat-done {
background: #c5d4e5;
}
}
}
.chat-panel {
.chat-panel {
height: 100%;
.chat-area,
.chat-info {
......@@ -187,8 +194,8 @@ export default class ChatRoom extends Vue {
width: 349px;
border-left: 1px solid #e1e1e1;
}
}
.info-tabs {
}
.info-tabs {
height: 40px;
line-height: 40px;
border-bottom: 1px solid #f0f0f0;
......@@ -206,8 +213,8 @@ export default class ChatRoom extends Vue {
font-weight: 600;
}
}
}
.chat-area {
}
.chat-area {
position: relative;
width: 100%;
overflow: hidden;
......@@ -227,15 +234,15 @@ export default class ChatRoom extends Vue {
height: 6px;
width: 100%;
}
}
.order-info-con {
}
.order-info-con {
height: calc(100% - 40px);
}
.someone-inputing {
}
.someone-inputing {
position: absolute;
left: 20px;
bottom: 20px;
z-index: 1;
color: #c2c2c2;
}
}
</style>
......@@ -21,9 +21,14 @@
size="small"
v-if="!isChatMember"
type="primary"
:disabled="isChatError"
>我要接待</el-button
>
<el-button class="button" @click="showAddMember" size="small"
<el-button
class="button"
@click="showAddMember"
size="small"
:disabled="isChatError"
>添加客服</el-button
>
<el-button
......@@ -32,6 +37,7 @@
size="small"
v-if="isChatMember && operatorType > 25"
type="warning"
:disabled="isChatError"
>结束接待</el-button
>
<el-button
......@@ -40,6 +46,7 @@
size="small"
v-if="isChatMember"
type="danger"
:disabled="isChatError"
>退出会话</el-button
>
<i
......@@ -58,17 +65,17 @@
</template>
<script lang="ts">
import { Component, Prop, Vue } from "vue-property-decorator";
import ChatCreator from "@/customer-service/components/create-chat.vue";
import { ChatStore, chatStore } from "@/customer-service/store/model";
import { ChatRole } from "../model";
import {
import { Component, Prop, Vue } from "vue-property-decorator";
import ChatCreator from "@/customer-service/components/create-chat.vue";
import { ChatStore, chatStore } from "@/customer-service/store/model";
import { ChatRole } from "../model";
import {
ChatChangedEvent,
ChatEventHandler,
} from "./controller/chat-event-handler";
} from "./controller/chat-event-handler";
@Component({ components: { ChatCreator } })
export default class ChatTitle extends Vue {
@Component({ components: { ChatCreator } })
export default class ChatTitle extends Vue {
@chatStore.State(ChatStore.STATE_CHAT_CURRENT_CHAT_ID)
private readonly chatId!: ChatStore.STATE_CHAT_CURRENT_CHAT_ID;
......@@ -81,6 +88,9 @@ export default class ChatTitle extends Vue {
@chatStore.State(ChatStore.STATE_CHAT_DIALOG_IS_SINGLE)
private readonly isSingleChat: ChatStore.STATE_CHAT_DIALOG_IS_SINGLE;
@chatStore.State(ChatStore.STATE_CHAT_CURRENT_IS_CHAT_ERROR)
private readonly chatError: ChatStore.STATE_CHAT_CURRENT_IS_CHAT_ERROR;
@chatStore.Action(ChatStore.ACTION_CHAT_ADD_CS)
private readonly _addCS!: ChatStore.ACTION_CHAT_ADD_CS;
......@@ -108,6 +118,10 @@ export default class ChatTitle extends Vue {
@chatStore.Mutation(ChatStore.MUTATION_HIDE_CHAT)
private readonly hideChat: ChatStore.MUTATION_HIDE_CHAT;
private get isChatError() {
return this.chatError === this.chatId;
}
private get chatMembersId() {
return this.chatMembers.map((k) => +k.eid);
}
......@@ -190,11 +204,11 @@ export default class ChatTitle extends Vue {
);
this.hideChat();
}
}
}
</script>
<style lang="less" scoped>
.room-title {
.room-title {
font-size: 16px;
padding: 0 20px;
height: 60px;
......@@ -217,5 +231,5 @@ export default class ChatTitle extends Vue {
cursor: pointer;
margin-left: 30px;
}
}
}
</style>
......@@ -128,7 +128,7 @@
};
img.remove();
}
uploadFile(file)
return uploadFile(file)
.then((r) => {
if (r) {
const msg = {
......@@ -150,6 +150,7 @@
});
this.removeSendingMessages(index);
URL.revokeObjectURL(src.url);
return index;
} else {
this.setMsg2Failed(index);
}
......
......@@ -196,6 +196,7 @@ export const MAX_IMAGE_SIZE = 5 * 1024 * 1024;
export const MAX_IMAGE_SIZE_STRING = "5MB";
export const MESSAGE_IMAGE_TOO_LARGE = `您发送的图片大小超过 ${MAX_IMAGE_SIZE_STRING}。`;
export const MESSAGE_FILE_EMPTY = "不能发送空文件。";
export const ERROR_IMAGE = "发送的不是图片";
/**
* 最大文件大小
......
......@@ -69,9 +69,6 @@
@chatStore.Action(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)
private readonly saveScrollToBottomFunc!: ChatStore.MUTATION_SAVE_FUNC_SCROLL_TO_BOTTOM;
......@@ -87,6 +84,9 @@
@chatStore.Mutation(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" })
private shape!: string;
......@@ -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) {
this.$emit("file-open", value);
}
......@@ -204,7 +212,6 @@
this.scollWrapper.removeEventListener("scroll", this.handleScroll);
this.clearScrollToBottomFunc();
this.clearNewMessage();
// this.clearChatId();
}
public scroll2End(delay?: number) {
......@@ -325,13 +332,25 @@
if (msg.length === 0) return;
this.startLoadingNew();
const msgId = getLastMessageId(msg);
const data = await this.getNextPageMsg(msgId);
return this.getNextPageMsg(msgId)
.then((data) => {
if (data.length === 0) {
// eslint-disable-next-line no-console
console.log("没有更多新消息了");
}
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) {
......
......@@ -18,9 +18,17 @@
src="@/customer-service/imgs/pic.png"
/>
</label>
<!-- <label for="chat-upload-file" :title="tip4File" @click="allowLoadFile">
<img class="tool-bar-icon" src="@/customer-service/imgs/file.png" />
</label> -->
<label
for="chat-upload-file"
:title="tip4File"
@click="allowLoadFile"
v-if="enableFileSelection"
>
<img
class="tool-bar-icon"
src="@/customer-service/imgs/file.png"
/>
</label>
<input
@change="onChange"
......@@ -63,6 +71,7 @@
import { Component, Ref, Vue, Watch } from "vue-property-decorator";
import { namespace } from "vuex-class";
import {
ERROR_IMAGE,
getFileType,
getSvg,
MAX_FILE_SIZE,
......@@ -130,6 +139,8 @@
private tip4Image = `发送图片(最大${MAX_IMAGE_SIZE_STRING})`;
private tip4File = `发送文件(最大${MAX_FILE_SIZE_STRING})`;
private enableFileSelection = false;
private emoji: EmojiItem[] = [];
@Watch("chatId")
......@@ -489,6 +500,15 @@
this.$emit("error", MESSAGE_FILE_EMPTY);
return;
}
if (
this.enableFileSelection &&
file.size >= MAX_FILE_SIZE
) {
this.$emit("error", MESSAGE_FILE_TOO_LARGE);
return;
}
if (this.isImage(file)) {
if (file.size >= MAX_IMAGE_SIZE) {
this.$emit("error", MESSAGE_IMAGE_TOO_LARGE);
......@@ -496,11 +516,11 @@
}
html += this.buildImageHtml(file);
} else {
if (file.size >= MAX_FILE_SIZE) {
this.$emit("error", MESSAGE_FILE_TOO_LARGE);
return;
}
if (this.enableFileSelection) {
html += this.buildFileHtml(file);
} else {
return this.$emit("error", ERROR_IMAGE);
}
}
}
......
......@@ -31,7 +31,7 @@ function uniqueMessages(
messages: NonNullable<ChatStore.STATE_CHAT_MSG_HISTORY>
) {
const arr = [...messages];
return unique(arr, function(item, all) {
return unique(arr, function (item, all) {
return all.findIndex((k) => k.id === item.id);
});
}
......@@ -119,6 +119,7 @@ export default {
[ChatStore.STATE_CHAT_DIALOG_VISIBLE]: false,
[ChatStore.STATE_CHAT_DIALOG_IS_SINGLE]: 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_USER_UID]: null,
[ChatStore.STATE_CHAT_MSG_HISTORY]: null,
......@@ -326,7 +327,7 @@ export default {
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 } = {};
return (
state: ChatStoreState,
......@@ -683,13 +684,15 @@ export default {
);
commit(ChatStore.MUTATION_INITING_CHAT_DONE);
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_MYSELF_ID);
commit(ChatStore.MUTATION_CLEAR_CHAT_MSG_HISTORY);
commit(ChatStore.MUTATION_CLEAR_CHAT_TITLE);
commit(ChatStore.MUTATION_CLEAR_CURRENT_CHAT_MEMBERS);
state[ChatStore.STATE_CHAT_CURRENT_IS_CHAT_ERROR] = null;
},
async [ChatStore.ACTION_GET_CHAT_MEMBERS]({ commit, state }) {
const chatId = state[ChatStore.STATE_CHAT_CURRENT_CHAT_ID];
......@@ -729,7 +732,7 @@ export default {
}
commit(
ChatStore.MUTATION_SAVE_CURRENT_CHAT_MEMBERS,
unique(newChatMembers, function(item, all) {
unique(newChatMembers, function (item, all) {
return all.findIndex((k) => k.eid === item.eid);
})
);
......@@ -916,6 +919,9 @@ export default {
.updateChat(p)
.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: {
[ChatStore.STATE_CHAT_MSG_HISTORY](state) {
......
......@@ -44,6 +44,9 @@ export namespace ChatStore {
"当前用户类型状态,25-普通用户,92-客服";
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 type STATE_CHAT_CURRENT_CHAT_UNIPLAT_ID = string | null;
......@@ -344,6 +347,9 @@ export namespace ChatStore {
value: dto.MessageHandled;
}) => void;
export const ACTION_SET_CHAT_ERROR = "标记会话关键性错误";
export type ACTION_SET_CHAT_ERROR = (chat: number) => void;
export interface ChatUpdateParameter {
chat: number;
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