Commit 452addc8 by Sixong.Zhu

eslint

parent a5b8ff29
<template> <template>
<div class="chat-container" :class="{'is-in-page': isInPage}"> <div class="chat-container" :class="{ 'is-in-page': isInPage }">
<div class="search-wrap" v-if="!modelName">
<div class="search-wrap" v-if="!modelName"> <el-input
<el-input class="keyword-input"
class="keyword-input" placeholder="会话标题"
placeholder="会话标题" prefix-icon="el-icon-search"
prefix-icon="el-icon-search" v-model="searchKeyword"
v-model="searchKeyword" v-on:keyup.enter.native="search"
v-on:keyup.enter.native="search" clearable
clearable @clear="search"
@clear="search" ></el-input>
></el-input> <i
<i v-if="!isInPage" class="close-btn el-icon-close" @click="$emit('close')"></i> v-if="!isInPage"
class="close-btn el-icon-close"
@click="$emit('close')"
></i>
</div>
<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"
@updateActive="$emit('updateActive', $event)"
/>
</div>
</div> </div>
<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" @updateActive="$emit('updateActive', $event)" />
</div>
</div>
</template> </template>
<script lang="ts"> <script lang="ts">
...@@ -29,91 +45,94 @@ import chat from "@/customer-service/chat.vue"; ...@@ -29,91 +45,94 @@ import chat from "@/customer-service/chat.vue";
import { ChatStore, chatStore } from "@/customer-service/store/model"; import { ChatStore, chatStore } from "@/customer-service/store/model";
@Component({ @Component({
name: "ChatContainer", name: "ChatContainer",
components: { components: {
chat, chat,
ChatList, ChatList,
ChatListModel ChatListModel,
} },
}) })
export default class ChatContainer extends Vue { export default class ChatContainer extends Vue {
@Prop(Boolean) isInPage: boolean; @Prop(Boolean) isInPage: boolean;
@Prop(String) modelName: string; @Prop(String) modelName: string;
@Prop(String) listName: string; @Prop(String) listName: string;
@Prop(String) activeName: string; @Prop(String) activeName: string;
@Prop(Boolean) isActive: boolean; @Prop(Boolean) isActive: boolean;
private onShow = false; private onShow = false;
@chatStore.State(ChatStore.STATE_CHAT_DIALOG_VISIBLE) @chatStore.State(ChatStore.STATE_CHAT_DIALOG_VISIBLE)
private readonly chatVisible!: ChatStore.STATE_CHAT_DIALOG_VISIBLE; private readonly chatVisible!: ChatStore.STATE_CHAT_DIALOG_VISIBLE;
@chatStore.Mutation(ChatStore.MUTATION_HIDE_CHAT) @chatStore.Mutation(ChatStore.MUTATION_HIDE_CHAT)
private readonly hideChat: ChatStore.MUTATION_HIDE_CHAT private readonly hideChat: ChatStore.MUTATION_HIDE_CHAT;
@Ref("chatListComp") chatListComp: ChatList; @Ref("chatListComp") chatListComp: ChatList;
private searchKeyword = ""; private searchKeyword = "";
@Ref("chatListModel") chatListModel: ChatListModel; @Ref("chatListModel") chatListModel: ChatListModel;
private search() { private search() {
this.chatListComp.search(this.searchKeyword) this.chatListComp.search(this.searchKeyword);
} }
@Watch("isActive", {immediate: true}) isActiveUpdate() { @Watch("isActive", { immediate: true }) isActiveUpdate() {
this.onShow = this.isActive; this.onShow = this.isActive;
if (!this.onShow && this.activeName !== "my_receiving" || this.onShow && this.listName) { if (
this.chatListModel && this.chatListModel.clearActiveId(); (!this.onShow && this.activeName !== "my_receiving") ||
(this.onShow && this.listName)
) {
this.chatListModel && this.chatListModel.clearActiveId();
}
} }
}
private onChatDrawerClose(){ private onChatDrawerClose() {
this.hideChat() this.hideChat();
} }
} }
</script> </script>
<style lang="less"> <style lang="less">
.chat-container { .chat-container {
height: 70vh; height: 70vh;
&.is-in-page { &.is-in-page {
height: 100%; height: 100%;
} }
} }
.keyword-input { .keyword-input {
width: 300px; width: 300px;
margin: 15px 0 14px 20px; margin: 15px 0 14px 20px;
/deep/ .el-input__inner { /deep/ .el-input__inner {
font-size: 13px; font-size: 13px;
height: 30px; height: 30px;
line-height: 28px; line-height: 28px;
border-radius: 15px; border-radius: 15px;
padding-right: 15px; padding-right: 15px;
} }
/deep/ .el-icon-time { /deep/ .el-icon-time {
background: transparent; background: transparent;
} }
/deep/ .el-input__icon { /deep/ .el-input__icon {
line-height: 32px; line-height: 32px;
} }
} }
.search-wrap { .search-wrap {
height: 59px; height: 59px;
border-bottom: 1px solid #ddd; border-bottom: 1px solid #ddd;
} }
.close-btn { .close-btn {
float: right; float: right;
font-size: 20px; font-size: 20px;
color: #aaa; color: #aaa;
padding: 5px; padding: 5px;
cursor: pointer; cursor: pointer;
margin: 15px 10px 0; margin: 15px 10px 0;
} }
.chat-content-wrap { .chat-content-wrap {
display: inline-block; display: inline-block;
width: 75%; width: 75%;
height: calc(100% - 60px); height: calc(100% - 60px);
box-sizing: border-box; box-sizing: border-box;
vertical-align: top; vertical-align: top;
} }
</style> </style>
\ No newline at end of file
...@@ -2,7 +2,10 @@ ...@@ -2,7 +2,10 @@
<div class="chat-list-con"> <div class="chat-list-con">
<div class="chat-list h-100"> <div class="chat-list h-100">
<div class="chat-list-scroll"> <div class="chat-list-scroll">
<el-scrollbar ref="scrollbar" class="list-scroll no-bottom-scrollbar"> <el-scrollbar
ref="scrollbar"
class="list-scroll no-bottom-scrollbar"
>
<div <div
v-for="item in chatRooms" v-for="item in chatRooms"
:key="'room_' + item.id" :key="'room_' + item.id"
...@@ -11,8 +14,14 @@ ...@@ -11,8 +14,14 @@
@click="goToChatRoom(item)" @click="goToChatRoom(item)"
> >
<div class="chat-info"> <div class="chat-info">
<div class="checkbox-wrap" @click.stop v-if="showItemCheckbox"> <div
<el-checkbox v-model="item.checked"></el-checkbox> class="checkbox-wrap"
@click.stop
v-if="showItemCheckbox"
>
<el-checkbox
v-model="item.checked"
></el-checkbox>
</div> </div>
<div class="w-100"> <div class="w-100">
<div <div
...@@ -24,16 +33,28 @@ ...@@ -24,16 +33,28 @@
" "
> >
<div <div
class="chat-name flex-fill text-dot-dot-dot" class="
chat-name
flex-fill
text-dot-dot-dot
"
> >
<span>{{ item.title }}</span> <span>{{ item.title }}</span>
</div> </div>
<div v-if="item.last_msg_ts" class="chat-time"> <div
v-if="item.last_msg_ts"
class="chat-time"
>
{{ formatTimestamp(item.last_msg_ts) }} {{ formatTimestamp(item.last_msg_ts) }}
</div> </div>
</div> </div>
<div class="chat-msg text-dot-dot-dot"> <div class="chat-msg text-dot-dot-dot">
{{userNames[item.last_msg_sender] ? userNames[item.last_msg_sender] + ": " : ""}}{{ parseMesage(item) }} {{
userNames[item.last_msg_sender]
? userNames[item.last_msg_sender] +
": "
: ""
}}{{ parseMesage(item) }}
</div> </div>
</div> </div>
</div> </div>
...@@ -60,9 +81,21 @@ ...@@ -60,9 +81,21 @@
></el-pagination> ></el-pagination>
<div class="action-row"> <div class="action-row">
<el-button @click="getList">刷新</el-button> <el-button @click="getList">刷新</el-button>
<el-button v-if="!showItemCheckbox" @click="showItemCheckbox = true">批量接待</el-button> <el-button
<el-button v-if="showItemCheckbox" @click="batchStartReception">确定接待</el-button> v-if="!showItemCheckbox"
<el-button v-if="showItemCheckbox" @click="showItemCheckbox = false">取消</el-button> @click="showItemCheckbox = true"
>批量接待</el-button
>
<el-button
v-if="showItemCheckbox"
@click="batchStartReception"
>确定接待</el-button
>
<el-button
v-if="showItemCheckbox"
@click="showItemCheckbox = false"
>取消</el-button
>
</div> </div>
</div> </div>
</div> </div>
...@@ -74,22 +107,8 @@ import { Component, Prop, Ref, Vue } from "vue-property-decorator"; ...@@ -74,22 +107,8 @@ import { Component, Prop, Ref, Vue } from "vue-property-decorator";
import { chatStore, ChatStore } from "@/customer-service/store/model"; import { chatStore, ChatStore } from "@/customer-service/store/model";
import { formatTime, TimeFormatRule } from "@/customer-service/utils/time"; import { formatTime, TimeFormatRule } from "@/customer-service/utils/time";
import { Chat as ChatType } from "@/customer-service/xim/models/chat"; import { Chat as ChatType } from "@/customer-service/xim/models/chat";
import { EVENTS } from "@/EventConsts" import { EVENTS } from "@/EventConsts";
import { parserMessage } from "./controller";
export function parserMessage(type: string, rawMsg: string) {
if (!type) return "[空]";
if (!rawMsg) return "[空]";
const msg = JSON.parse(rawMsg);
if (type === "text") {
return msg.text;
} else if (type === "image") {
return `[图片]`;
} else if (type === "file") {
return `[文件]`;
} else {
return `[系统自动回复]`;
}
}
interface SelectChatType extends ChatType { interface SelectChatType extends ChatType {
checked?: boolean; checked?: boolean;
...@@ -97,7 +116,6 @@ interface SelectChatType extends ChatType { ...@@ -97,7 +116,6 @@ interface SelectChatType extends ChatType {
@Component({ components: {} }) @Component({ components: {} })
export default class ModelChatList extends Vue { export default class ModelChatList extends Vue {
@chatStore.Action(ChatStore.ACTION_CREATE_NEW_CHAT_BY_SERVICE_MAN) @chatStore.Action(ChatStore.ACTION_CREATE_NEW_CHAT_BY_SERVICE_MAN)
private readonly _createChat!: ChatStore.ACTION_CREATE_NEW_CHAT_BY_SERVICE_MAN; private readonly _createChat!: ChatStore.ACTION_CREATE_NEW_CHAT_BY_SERVICE_MAN;
...@@ -146,20 +164,26 @@ export default class ModelChatList extends Vue { ...@@ -146,20 +164,26 @@ export default class ModelChatList extends Vue {
} }
private async getList() { private async getList() {
let result = await this.sdk.model(this.modelName).list(this.listName || undefined).query({ let result = await this.sdk
pageIndex: this.currentPage, .model(this.modelName)
item_size: this.pageSize .list(this.listName || undefined)
}) .query({
pageIndex: this.currentPage,
item_size: this.pageSize,
});
if (result.pageData.rows.length === 0 && this.currentPage !== 1) { if (result.pageData.rows.length === 0 && this.currentPage !== 1) {
this.currentPage = 1; this.currentPage = 1;
if (result.pageData.record_count > 0) { if (result.pageData.record_count > 0) {
result = await this.sdk.model(this.modelName).list(this.listName || undefined).query({ result = await this.sdk
pageIndex: this.currentPage, .model(this.modelName)
item_size: this.pageSize .list(this.listName || undefined)
}) .query({
pageIndex: this.currentPage,
item_size: this.pageSize,
});
} }
} }
this.chatList = result.pageData.rows.map(it => { this.chatList = result.pageData.rows.map((it) => {
return { return {
id: it.id.value, id: it.id.value,
chat_id: it.ImChatId.value, chat_id: it.ImChatId.value,
...@@ -172,9 +196,9 @@ export default class ModelChatList extends Vue { ...@@ -172,9 +196,9 @@ export default class ModelChatList extends Vue {
last_msg_content: it.LastMsgContent.value, last_msg_content: it.LastMsgContent.value,
last_msg_ts: it.LastMsgTime.value, last_msg_ts: it.LastMsgTime.value,
last_msg_type: it.LastMsgType.value, last_msg_type: it.LastMsgType.value,
title: it.Title.value title: it.Title.value,
} as ChatType } as ChatType;
}) });
this.total = result.pageData.record_count; this.total = result.pageData.record_count;
this.$emit("list-count-update", this.total); this.$emit("list-count-update", this.total);
} }
...@@ -183,24 +207,40 @@ export default class ModelChatList extends Vue { ...@@ -183,24 +207,40 @@ export default class ModelChatList extends Vue {
await this.getList(); await this.getList();
this.setSource(ChatStore.StateChatSourceDirection.Server); this.setSource(ChatStore.StateChatSourceDirection.Server);
this.scrollbar.update(); this.scrollbar.update();
await this.sdk.model("UniplatChat").registerOnChange(this.onTransportMessage); await this.sdk
await this.sdk.model("general_order").registerOnChange(this.onTransportMessage); .model("UniplatChat")
if (this.listName === "group_receiving" || this.listName === "group_wait") { .registerOnChange(this.onTransportMessage);
await this.sdk
.model("general_order")
.registerOnChange(this.onTransportMessage);
if (
this.listName === "group_receiving" ||
this.listName === "group_wait"
) {
this.$eventHub.$on(EVENTS.ChatUpdate, this.refreshListDebounce); this.$eventHub.$on(EVENTS.ChatUpdate, this.refreshListDebounce);
} }
} }
onTransportMessage(e: any) { onTransportMessage(e: any) {
let index = e.dataUpdates.findIndex(it => it.action === "startChat" || let index = e.dataUpdates.findIndex(
it.action === "createChat" || (it) =>
it.action === "csExitChat" || it.action === "startChat" ||
it.action === "finishChat" || it.action === "createChat" ||
it.action === "delete" && it.model === "general_order" || it.action === "csExitChat" ||
it.action === "sendMsg" && this.listName === "group_before_handle" && this.chatList.findIndex(chat => chat.id == it.selectedList[0]) > -1 it.action === "finishChat" ||
(it.action === "delete" && it.model === "general_order") ||
(it.action === "sendMsg" &&
this.listName === "group_before_handle" &&
this.chatList.findIndex(
(chat) => chat.id == it.selectedList[0]
) > -1)
); );
if (index > -1) { if (index > -1) {
if (this.listName === "group_before_handle" && e.dataUpdates.findIndex(it => it.action === "sendMsg") > -1) { if (
this.$eventHub.$emit(EVENTS.ChatUpdate) this.listName === "group_before_handle" &&
e.dataUpdates.findIndex((it) => it.action === "sendMsg") > -1
) {
this.$eventHub.$emit(EVENTS.ChatUpdate);
} }
this.refreshListDebounce(); this.refreshListDebounce();
} }
...@@ -208,13 +248,13 @@ export default class ModelChatList extends Vue { ...@@ -208,13 +248,13 @@ export default class ModelChatList extends Vue {
private refreshListDebounce() { private refreshListDebounce() {
if (this.sseTs) { if (this.sseTs) {
return return;
} }
this.sseTs = new Date().getTime(); this.sseTs = new Date().getTime();
setTimeout(() => { setTimeout(() => {
this.sseTs = 0; this.sseTs = 0;
this.getList(); this.getList();
}, 1000) }, 1000);
} }
mounted() { mounted() {
...@@ -222,16 +262,16 @@ export default class ModelChatList extends Vue { ...@@ -222,16 +262,16 @@ export default class ModelChatList extends Vue {
} }
private handleSizeChange(newPageSize) { private handleSizeChange(newPageSize) {
this.pageSize = newPageSize this.pageSize = newPageSize;
this.getList() this.getList();
} }
private async goToChatRoom(data: ChatType) { private async goToChatRoom(data: ChatType) {
const chatInfo = await this._createChat({ const chatInfo = await this._createChat({
modelName: data.business_data.model_name, modelName: data.business_data.model_name,
selectedListId: data.business_data.obj_id, selectedListId: data.business_data.obj_id,
uids:[], uids: [],
showByPage: true showByPage: true,
}); });
this.activeId = data.chat_id.toString(); this.activeId = data.chat_id.toString();
} }
...@@ -243,10 +283,17 @@ export default class ModelChatList extends Vue { ...@@ -243,10 +283,17 @@ export default class ModelChatList extends Vue {
private parseMesage(data: ChatType) { private parseMesage(data: ChatType) {
if (data.last_msg_sender && data.last_msg_sender != "0") { if (data.last_msg_sender && data.last_msg_sender != "0") {
if (this.userNames[data.last_msg_sender] === undefined) { if (this.userNames[data.last_msg_sender] === undefined) {
this.updateUserName({id: data.last_msg_sender, name: ""}); this.updateUserName({ id: data.last_msg_sender, name: "" });
this.sdk.model("user").detail(data.last_msg_sender).query().then(userInfo => { this.sdk
this.updateUserName({id: data.last_msg_sender, name: userInfo.row.first_name.display as string}); .model("user")
}) .detail(data.last_msg_sender)
.query()
.then((userInfo) => {
this.updateUserName({
id: data.last_msg_sender,
name: userInfo.row.first_name.display as string,
});
});
} }
} }
if (data.last_msg_content === "") return "[暂无消息]"; if (data.last_msg_content === "") return "[暂无消息]";
...@@ -264,19 +311,19 @@ export default class ModelChatList extends Vue { ...@@ -264,19 +311,19 @@ export default class ModelChatList extends Vue {
} }
private batchStartReception() { private batchStartReception() {
let chats = this.chatRooms.filter(chat => chat.checked); let chats = this.chatRooms.filter((chat) => chat.checked);
if (chats.length === 0) { if (chats.length === 0) {
this.$message.warning("请先勾选要接待的会话") this.$message.warning("请先勾选要接待的会话");
return return;
} }
chats.forEach(chat => { chats.forEach((chat) => {
const { model_name, obj_id } = chat.business_data; const { model_name, obj_id } = chat.business_data;
this.sdk this.sdk
.model(model_name) .model(model_name)
.chat(+obj_id, this.global.org.id.toString()) .chat(+obj_id, this.global.org.id.toString())
.startChat(); .startChat();
chat.checked = false; chat.checked = false;
}) });
this.showItemCheckbox = false; this.showItemCheckbox = false;
this.clearActiveId(); this.clearActiveId();
} }
......
...@@ -26,14 +26,16 @@ ...@@ -26,14 +26,16 @@
:title="item.customer_name" :title="item.customer_name"
class="chat-name flex-fill text-dot-dot-dot" class="chat-name flex-fill text-dot-dot-dot"
> >
<span>{{ item.title || item.chat_id }}</span> <span>{{
item.title || item.chat_id
}}</span>
</div> </div>
<div v-if="item.last_msg_ts" class="chat-time"> <div v-if="item.last_msg_ts" class="chat-time">
{{ formatTimestamp(item.last_msg_ts) }} {{ formatTimestamp(item.last_msg_ts) }}
</div> </div>
</div> </div>
<div class="chat-msg text-dot-dot-dot"> <div class="chat-msg text-dot-dot-dot">
{{userNames[item.last_msg_sender] ? userNames[item.last_msg_sender] + ": " : ""}}{{ parseMesage(item) }} {{ buildLastMessage(item) }}
</div> </div>
</div> </div>
</div> </div>
...@@ -52,63 +54,15 @@ ...@@ -52,63 +54,15 @@
<script lang="ts"> <script lang="ts">
import { Component, Prop, Ref, Vue } from "vue-property-decorator"; import { Component, Prop, Ref, Vue } from "vue-property-decorator";
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 } from "@/customer-service/store/model";
import { formatTime, TimeFormatRule } from "@/customer-service/utils/time";
import { Chat as ChatType } from "@/customer-service/xim/models/chat"; import { Chat as ChatType } from "@/customer-service/xim/models/chat";
import { EVENTS } from "@/EventConsts" import { EVENTS } from "@/EventConsts";
import Controller from "./controller/chat-list";
export function parserMessage(type: string, rawMsg: string) {
if (!type) return "";
if (!rawMsg) return "";
const msg = JSON.parse(rawMsg);
if (type === "text") {
return msg.text;
} else if (type === "image") {
return `[图片]`;
} else if (type === "file") {
return `[文件]`;
} else {
return `[系统自动回复]`;
}
}
@Component({ components: { avatar } }) @Component({ components: { avatar } })
export default class ChatList extends Vue { export default class ChatList extends Controller {
private searchKeyword = ""; private searchKeyword = "";
@chatStore.Action(ChatStore.ACTION_GET_MY_CHAT_LIST)
private readonly getMyChatList!: ChatStore.ACTION_GET_MY_CHAT_LIST;
@chatStore.State(ChatStore.STATE_CHAT_CURRENT_CHAT_ID)
private readonly chatId!: ChatStore.STATE_CHAT_CURRENT_CHAT_ID;
@chatStore.State(ChatStore.STATE_MY_CHAT_ROOM_LIST)
private readonly chatList!: ChatStore.STATE_MY_CHAT_ROOM_LIST;
@chatStore.State(ChatStore.STATE_CHAT_USERNAME)
private readonly userNames!: ChatStore.STATE_CHAT_USERNAME;
@chatStore.Action(ChatStore.ACTION_SAVE_CURRENT_CHAT_ID_VERSION)
private readonly saveChatId!: ChatStore.ACTION_SAVE_CURRENT_CHAT_ID_VERSION;
@chatStore.Mutation(ChatStore.MUTATION_SAVE_MYSELF_ID)
private readonly saveMyId!: ChatStore.MUTATION_SAVE_MYSELF_ID;
@chatStore.Mutation(ChatStore.MUTATION_SAVE_USERNAME)
private readonly updateUserName!: ChatStore.MUTATION_SAVE_USERNAME;
@chatStore.Mutation(ChatStore.MUTATION_SET_CHAT_SOURCE)
private readonly setSource!: ChatStore.MUTATION_SET_CHAT_SOURCE;
@chatStore.Mutation(ChatStore.MUTATION_SAVE_CHAT_TITLE)
private readonly saveChatTitle!: ChatStore.MUTATION_SAVE_CHAT_TITLE;
@chatStore.Mutation(ChatStore.MUTATION_SHOW_CHAT)
private readonly showChat: ChatStore.MUTATION_SHOW_CHAT;
@chatStore.Mutation(ChatStore.MUTATION_HIDE_CHAT)
private readonly hideChat: ChatStore.MUTATION_HIDE_CHAT;
@Prop({ type: Number, default: -1 }) @Prop({ type: Number, default: -1 })
private selected!: number; private selected!: number;
...@@ -118,11 +72,14 @@ export default class ChatList extends Vue { ...@@ -118,11 +72,14 @@ export default class ChatList extends Vue {
private unReadMsgCount = 0; private unReadMsgCount = 0;
private get chatRooms() { private get chatRooms() {
const list = this.chatList?.list.filter(chat => chat.title.indexOf(this.searchKeyword) > -1) || []; const list =
this.chatList?.list.filter(
(chat) => chat.title.indexOf(this.searchKeyword) > -1
) || [];
let unReadMsgCount = 0; let unReadMsgCount = 0;
list.filter(chat => chat.unread_msg_count > 0).forEach(chat => { list.filter((chat) => chat.unread_msg_count > 0).forEach((chat) => {
unReadMsgCount += chat.unread_msg_count unReadMsgCount += chat.unread_msg_count;
}) });
this.unReadMsgCount = unReadMsgCount; this.unReadMsgCount = unReadMsgCount;
this.$emit("list-count-update", this.unReadMsgCount); this.$emit("list-count-update", this.unReadMsgCount);
this.$eventHub.$emit(EVENTS.NewMsg, this.unReadMsgCount); this.$eventHub.$emit(EVENTS.NewMsg, this.unReadMsgCount);
...@@ -159,7 +116,7 @@ export default class ChatList extends Vue { ...@@ -159,7 +116,7 @@ export default class ChatList extends Vue {
this.showChat(); this.showChat();
this.close(); this.close();
if (data.unread_msg_count > 0) { if (data.unread_msg_count > 0) {
data.unread_msg_count = 0; data.unread_msg_count = 0;
} }
...@@ -169,23 +126,6 @@ export default class ChatList extends Vue { ...@@ -169,23 +126,6 @@ export default class ChatList extends Vue {
this.$emit("change"); this.$emit("change");
} }
private parseMesage(data: ChatType) {
if (data.last_msg_sender && data.last_msg_sender != "0") {
if (this.userNames[data.last_msg_sender] === undefined) {
this.updateUserName({id: data.last_msg_sender, name: ""});
this.sdk.model("user").detail(data.last_msg_sender).query().then(userInfo => {
this.updateUserName({id: data.last_msg_sender, name: userInfo.row.first_name.display as string});
})
}
}
if (data.last_msg_content === "") return "[暂无消息]";
return parserMessage(data.last_msg_type, data.last_msg_content);
}
private formatTimestamp(v: number) {
return formatTime(v, { short: true, rule: TimeFormatRule.Hour12 });
}
private close() { private close() {
this.$emit("close"); this.$emit("close");
} }
......
<template> <template>
<div class="chat-room-con h-100 pos-rel"> <div class="chat-room-con h-100 pos-rel">
<div class="chat-panel"> <div class="chat-panel">
<div class="chat-area h-100" ref="chatBox"> <div class="chat-area h-100 d-flex flex-column" ref="chatBox">
<div ref="top" class="chat-messages pos-rel" :class="{'is-not-chat-member': !isChatMember}"> <div
ref="top"
class="chat-messages pos-rel flex-fill"
:class="{ 'is-not-chat-member': !isChatMember }"
>
<div <div
v-if="getCurrentInputingPeople.length" v-if="getCurrentInputingPeople.length"
class="someone-inputing" class="someone-inputing"
...@@ -11,7 +15,13 @@ ...@@ -11,7 +15,13 @@
</div> </div>
<messages /> <messages />
</div> </div>
<div class="resize" title="收缩侧边栏" ref="resize" @mousedown="dragControllerDiv" v-if="isChatMember"></div> <div
class="resize"
title="收缩侧边栏"
ref="resize"
@mousedown="dragControllerDiv"
v-if="isChatMember"
></div>
<div ref="bottom" class="chat-input" v-if="isChatMember"> <div ref="bottom" class="chat-input" v-if="isChatMember">
<message-input @error="onError" /> <message-input @error="onError" />
</div> </div>
...@@ -20,7 +30,14 @@ ...@@ -20,7 +30,14 @@
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { Component, Prop, Provide, Vue, Watch, Ref } from "vue-property-decorator"; import {
Component,
Prop,
Provide,
Vue,
Watch,
Ref,
} 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";
...@@ -106,7 +123,7 @@ export default class ChatRoom extends Vue { ...@@ -106,7 +123,7 @@ export default class ChatRoom extends Vue {
this.$message.error(msg); this.$message.error(msg);
} }
private dragControllerDiv(e:MouseEvent) { private dragControllerDiv(e: MouseEvent) {
let resize = this.refResize as any; let resize = this.refResize as any;
let top = this.refTop as HTMLElement; let top = this.refTop as HTMLElement;
let bottom = this.refBottom as HTMLElement; let bottom = this.refBottom as HTMLElement;
...@@ -126,9 +143,9 @@ export default class ChatRoom extends Vue { ...@@ -126,9 +143,9 @@ export default class ChatRoom extends Vue {
} }
let bottomHeight = box.clientHeight - moveLen; let bottomHeight = box.clientHeight - moveLen;
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";
}; };
// 鼠标松开事件 // 鼠标松开事件
document.onmouseup = function (evt) { document.onmouseup = function (evt) {
......
...@@ -14,21 +14,36 @@ ...@@ -14,21 +14,36 @@
<div v-else class="chat-status">接待中</div> <div v-else class="chat-status">接待中</div>
</template> </template>
</div> </div>
<div class="title-buttons"> <div class="title-buttons d-flex align-items-center">
<el-button
<el-button class="button" @click="startReception" round v-if="!isChatMember" class="button"
@click="startReception"
round
v-if="!isChatMember"
>我要接待</el-button >我要接待</el-button
> >
<el-button class="button" @click="exitChat" round v-if="isChatMember" <el-button
class="button"
@click="exitChat"
round
v-if="isChatMember"
>退出会话</el-button >退出会话</el-button
> >
<el-button class="button" @click="finishReception" round v-if="isChatMember && operatorType > 25" <el-button
class="button"
@click="finishReception"
round
v-if="isChatMember && operatorType > 25"
>结束接待</el-button >结束接待</el-button
> >
<el-button class="button" @click="showAddMember" round <el-button class="button" @click="showAddMember" round
>添加客服</el-button >添加客服</el-button
> >
<i v-if="close && isSingleChat" @click="close" class="title-close el-icon-close" /> <i
v-if="close && isSingleChat"
@click="close"
class="title-close el-icon-close"
/>
</div> </div>
<ChatCreator <ChatCreator
v-if="visible" v-if="visible"
...@@ -115,9 +130,9 @@ export default class ChatTitle extends Vue { ...@@ -115,9 +130,9 @@ export default class ChatTitle extends Vue {
private async exitChat() { private async exitChat() {
try { try {
if (this.operatorType == '25') { if (this.operatorType == "25") {
await this._userExitChat(); await this._userExitChat();
} else if (+this.operatorType > 25){ } else if (+this.operatorType > 25) {
await this._csExitChat(); await this._csExitChat();
} }
this.hideChat(); this.hideChat();
...@@ -129,18 +144,22 @@ export default class ChatTitle extends Vue { ...@@ -129,18 +144,22 @@ export default class ChatTitle extends Vue {
private async startReception() { private async startReception() {
try { try {
await this._startReception(); await this._startReception();
this.$emit("updateActive", "my_receiving") this.$emit("updateActive", "my_receiving");
} catch (error) { } catch (error) {
console.error(error); console.error(error);
} }
} }
private async finishReception() { private async finishReception() {
await this.$confirm("确定要结束接待吗?结束接待将会终止客服会话", "提示", { await this.$confirm(
confirmButtonText: "确定", "确定要结束接待吗?结束接待将会终止客服会话",
cancelButtonText: "取消", "提示",
type: "warning", {
}) confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}
);
await this._finishReception(); await this._finishReception();
this.hideChat(); this.hideChat();
} }
...@@ -167,7 +186,7 @@ export default class ChatTitle extends Vue { ...@@ -167,7 +186,7 @@ export default class ChatTitle extends Vue {
.title-close { .title-close {
color: #8d959d; color: #8d959d;
cursor: pointer; cursor: pointer;
margin-left:30px; margin-left: 30px;
} }
} }
</style> </style>
import { Component, Vue } from "vue-property-decorator";
import { chatStore, ChatStore } from "@/customer-service/store/model";
import { parserMessage } from ".";
import { Chat as ChatItem } from "@/customer-service/xim/models/chat";
import { formatTime, TimeFormatRule } from "@/customer-service/utils/time";
@Component({ components: {} })
export default class ChatList extends Vue {
@chatStore.Action(ChatStore.ACTION_GET_MY_CHAT_LIST)
protected readonly getMyChatList!: ChatStore.ACTION_GET_MY_CHAT_LIST;
@chatStore.State(ChatStore.STATE_CHAT_CURRENT_CHAT_ID)
protected readonly chatId!: ChatStore.STATE_CHAT_CURRENT_CHAT_ID;
@chatStore.State(ChatStore.STATE_MY_CHAT_ROOM_LIST)
protected readonly chatList!: ChatStore.STATE_MY_CHAT_ROOM_LIST;
@chatStore.State(ChatStore.STATE_CHAT_USERNAME)
protected readonly userNames!: ChatStore.STATE_CHAT_USERNAME;
@chatStore.Action(ChatStore.ACTION_SAVE_CURRENT_CHAT_ID_VERSION)
protected readonly saveChatId!: ChatStore.ACTION_SAVE_CURRENT_CHAT_ID_VERSION;
@chatStore.Mutation(ChatStore.MUTATION_SAVE_MYSELF_ID)
protected readonly saveMyId!: ChatStore.MUTATION_SAVE_MYSELF_ID;
@chatStore.Mutation(ChatStore.MUTATION_SAVE_USERNAME)
protected readonly updateUserName!: ChatStore.MUTATION_SAVE_USERNAME;
@chatStore.Mutation(ChatStore.MUTATION_SET_CHAT_SOURCE)
protected readonly setSource!: ChatStore.MUTATION_SET_CHAT_SOURCE;
@chatStore.Mutation(ChatStore.MUTATION_SAVE_CHAT_TITLE)
protected readonly saveChatTitle!: ChatStore.MUTATION_SAVE_CHAT_TITLE;
@chatStore.Mutation(ChatStore.MUTATION_SHOW_CHAT)
protected readonly showChat: ChatStore.MUTATION_SHOW_CHAT;
@chatStore.Mutation(ChatStore.MUTATION_HIDE_CHAT)
protected readonly hideChat: ChatStore.MUTATION_HIDE_CHAT;
protected parseMesage(data: ChatItem) {
if (data.last_msg_sender && data.last_msg_sender != "0") {
if (this.userNames[data.last_msg_sender] === undefined) {
this.updateUserName({ id: data.last_msg_sender, name: "" });
this.sdk
.model("user")
.detail(data.last_msg_sender)
.query()
.then((userInfo) => {
this.updateUserName({
id: data.last_msg_sender,
name: userInfo.row.first_name.display as string,
});
});
}
}
if (data.last_msg_content === "") {
return "[暂无消息]";
}
return parserMessage(data.last_msg_type, data.last_msg_content);
}
protected formatTimestamp(v: number) {
return formatTime(v, { short: true, rule: TimeFormatRule.Hour12 });
}
protected buildLastMessage(item: ChatItem) {
const sender = this.userNames[item.last_msg_sender];
if (sender) {
return `${sender}: ${this.parseMesage(item)}`;
}
return this.parseMesage(item);
}
}
export function parserMessage(type: string, rawMsg: string) {
if (!type) return "";
if (!rawMsg) return "";
const msg = JSON.parse(rawMsg);
if (type === "text") {
return msg.text;
} else if (type === "image") {
return `[图片]`;
} else if (type === "file") {
return `[文件]`;
} else {
return `[系统自动回复]`;
}
}
<template> <template>
<div class="h-100"> <div class="h-100">
<chat-input <chat-input
ref="chat-input" ref="chat-input"
@input="onInput" @input="onInput"
@send="sendMessage" @send="sendMessage"
@error="onError" @error="onError"
/> />
</div> </div>
</template> </template>
<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, FILE_INFO_CLASS,
isImageOrFile, isImageOrFile,
} from "../hybrid-input/index.vue"; } from "../hybrid-input/index.vue";
import { Message } from "../model"; import { Message } from "../model";
import { uploadFile } from "../service/upload"; import { uploadFile } from "../service/upload";
...@@ -26,167 +26,169 @@ let sendingMessageIndex = 1; ...@@ -26,167 +26,169 @@ let sendingMessageIndex = 1;
@Component({ components: { ChatInput } }) @Component({ components: { ChatInput } })
export default class MessageInput extends Vue { export default class MessageInput extends Vue {
@chatStore.State(ChatStore.STATE_CHAT_DIALOG_VISIBLE) @chatStore.State(ChatStore.STATE_CHAT_DIALOG_VISIBLE)
private readonly chatRoomVisible!: ChatStore.STATE_CHAT_DIALOG_VISIBLE; private readonly chatRoomVisible!: ChatStore.STATE_CHAT_DIALOG_VISIBLE;
@chatStore.Action(ChatStore.ACTION_SEND_MESSAGE) @chatStore.Action(ChatStore.ACTION_SEND_MESSAGE)
private readonly sendMsg!: ChatStore.ACTION_SEND_MESSAGE; private readonly sendMsg!: ChatStore.ACTION_SEND_MESSAGE;
@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.State(ChatStore.STATE_CHAT_MY_ID) @chatStore.State(ChatStore.STATE_CHAT_MY_ID)
private readonly chatMyId!: ChatStore.STATE_CHAT_MY_ID; private readonly chatMyId!: ChatStore.STATE_CHAT_MY_ID;
@chatStore.State(ChatStore.STATE_CURRENT_CHAT_INITING) @chatStore.State(ChatStore.STATE_CURRENT_CHAT_INITING)
private readonly chatIniting!: ChatStore.STATE_CURRENT_CHAT_INITING; private readonly chatIniting!: ChatStore.STATE_CURRENT_CHAT_INITING;
@chatStore.Getter(ChatStore.STATE_CHAT_SOURCE) @chatStore.Getter(ChatStore.STATE_CHAT_SOURCE)
private readonly source!: ChatStore.STATE_CHAT_SOURCE; private readonly source!: ChatStore.STATE_CHAT_SOURCE;
@chatStore.Mutation(ChatStore.MUTATION_APPEND_SENDING_MESSAGE) @chatStore.Mutation(ChatStore.MUTATION_APPEND_SENDING_MESSAGE)
private readonly appendSendingMessages!: ChatStore.MUTATION_APPEND_SENDING_MESSAGE; private readonly appendSendingMessages!: ChatStore.MUTATION_APPEND_SENDING_MESSAGE;
@chatStore.Mutation(ChatStore.MUTATION_FAILED_SENDING_MESSAGE) @chatStore.Mutation(ChatStore.MUTATION_FAILED_SENDING_MESSAGE)
private readonly failedSendingMessage!: ChatStore.MUTATION_FAILED_SENDING_MESSAGE; private readonly failedSendingMessage!: ChatStore.MUTATION_FAILED_SENDING_MESSAGE;
@chatStore.Mutation(ChatStore.MUTATION_REMOVE_SENDING_MESSAGE) @chatStore.Mutation(ChatStore.MUTATION_REMOVE_SENDING_MESSAGE)
private readonly removeSendingMessages!: ChatStore.MUTATION_REMOVE_SENDING_MESSAGE; private readonly removeSendingMessages!: ChatStore.MUTATION_REMOVE_SENDING_MESSAGE;
@Ref("chat-input") @Ref("chat-input")
private readonly chatInput!: ChatInput; private readonly chatInput!: ChatInput;
@Watch("chatRoomVisible") @Watch("chatRoomVisible")
private whenChatRoomShow() { private whenChatRoomShow() {
if (!this.chatRoomVisible) return; if (!this.chatRoomVisible) return;
this.chatInput.focus(); this.chatInput.focus();
}
private async sendMessage(msg: ChildNode[], done: () => void) {
if (this.chatIniting) {
return;
} }
for (const item of msg) {
if (isImageOrFile(item)) { private async sendMessage(msg: ChildNode[], done: () => void) {
if ((item as Element).classList.contains(FILE_INFO_CLASS)) { if (this.chatIniting) {
this.sendFile(item, "file"); return;
} else {
this.sendFile(item, "image");
} }
continue; for (const item of msg) {
} if (isImageOrFile(item)) {
if ((item as Element).classList.contains(FILE_INFO_CLASS)) {
this.sendFile(item, "file");
} else {
this.sendFile(item, "image");
}
continue;
}
if (item.textContent) { if (item.textContent) {
this.sendText(item.textContent); this.sendText(item.textContent);
} }
}
ChatLoggerService.logger?.debug("all messages sent");
done();
this.$emit("sent");
} }
ChatLoggerService.logger?.debug("all messages sent");
done(); private async onInput() {
this.$emit("sent"); if (this.chatId == null) return;
} await xim.inputing(this.chatId);
private async onInput() {
if (this.chatId == null) return;
await xim.inputing(this.chatId);
}
private sendText(text: string) {
if (text && text.trim()) {
const msg = { text: text.trim() };
if (this.source) {
Object.assign(msg, { source: this.source });
}
this.sendMsg({ msgType: "text", msg: JSON.stringify(msg) });
} }
}
private async sendFile(file: any, type: "image" | "file") {
const src = JSON.parse(file.attributes[`data-${type}`]?.value || "") as {
url: string;
name: string;
size: number;
};
if (src) {
const index = this.sendSendingMessage(type, src);
const file = await this.readBlobUrl2Base64(src.url, src.name);
if (file) {
let w = 0;
let h = 0;
if (type === "image") {
const img = new Image();
img.src = src.url;
img.onload = function() {
w = img.naturalWidth;
h = img.naturalHeight;
};
img.remove();
}
uploadFile(file)
.then((r) => {
if (r) {
const msg = {
url: r,
name: file.name,
size: file.size,
};
if (this.source) {
Object.assign(msg, { source: this.source });
}
if (w && h) { private sendText(text: string) {
Object.assign(msg, { w, h }); if (text && text.trim()) {
} const msg = { text: text.trim() };
if (this.source) {
Object.assign(msg, { source: this.source });
}
this.sendMsg({ msgType: "text", msg: JSON.stringify(msg) });
}
}
this.sendMsg({ private async sendFile(file: any, type: "image" | "file") {
msgType: type, const src = JSON.parse(
msg: JSON.stringify(msg), file.attributes[`data-${type}`]?.value || ""
}); ) as {
this.removeSendingMessages(index); url: string;
URL.revokeObjectURL(src.url); name: string;
} else { size: number;
this.setMsg2Failed(index); };
if (src) {
const index = this.sendSendingMessage(type, src);
const file = await this.readBlobUrl2Base64(src.url, src.name);
if (file) {
let w = 0;
let h = 0;
if (type === "image") {
const img = new Image();
img.src = src.url;
img.onload = function () {
w = img.naturalWidth;
h = img.naturalHeight;
};
img.remove();
}
uploadFile(file)
.then((r) => {
if (r) {
const msg = {
url: r,
name: file.name,
size: file.size,
};
if (this.source) {
Object.assign(msg, { source: this.source });
}
if (w && h) {
Object.assign(msg, { w, h });
}
this.sendMsg({
msgType: type,
msg: JSON.stringify(msg),
});
this.removeSendingMessages(index);
URL.revokeObjectURL(src.url);
} else {
this.setMsg2Failed(index);
}
})
.catch((e) => {
// eslint-disable-next-line no-console
console.error(e);
this.setMsg2Failed(index);
});
} }
}) }
.catch((e) => { }
// eslint-disable-next-line no-console
console.error(e); private setMsg2Failed(index: number) {
this.failedSendingMessage(index);
this.setMsg2Failed(index);
});
}
} }
}
private setMsg2Failed(index: number) { private sendSendingMessage(type: string, msg: any) {
this.failedSendingMessage(index); const index = sendingMessageIndex++;
} if (this.source) {
Object.assign(msg, { source: this.source, eid: this.chatMyId });
}
if (this.chatId) {
this.appendSendingMessages({
id: -index,
chat_id: this.chatId,
ts: Date.now(),
type,
msg: JSON.stringify(msg),
} as Message);
return -index;
}
return 0;
}
private sendSendingMessage(type: string, msg: any) { private readBlobUrl2Base64(url: string, name: string) {
const index = sendingMessageIndex++; return fetch(url)
if (this.source) { .then((r) => r.blob())
Object.assign(msg, { source: this.source, eid: this.chatMyId }); .then((blob) => new File([blob], name));
} }
if (this.chatId) {
this.appendSendingMessages({ private onError(e: any) {
id: -index, this.$emit("error", e.message || e);
chat_id: this.chatId,
ts: Date.now(),
type,
msg: JSON.stringify(msg),
} as Message);
return -index;
} }
return 0;
}
private readBlobUrl2Base64(url: string, name: string) {
return fetch(url)
.then((r) => r.blob())
.then((blob) => new File([blob], name));
}
private onError(e: any) {
this.$emit("error", e.message || e);
}
} }
</script> </script>
<template> <template>
<div class="input-wrap h-100"> <div class="input-wrap h-100">
<div class="tool-bar"> <div class="tool-bar">
<img <img
class="tool-bar-icon" class="tool-bar-icon"
title="发送表情" title="发送表情"
@click.stop="toggleEmoji" @click.stop="toggleEmoji"
src="@/customer-service/imgs/emoji.png" src="@/customer-service/imgs/emoji.png"
/> />
<label <label
for="chat-upload-file" for="chat-upload-file"
:title="tip4Image" :title="tip4Image"
@click="allowLoadImg" @click="allowLoadImg"
class="offset" class="offset"
> >
<img class="tool-bar-icon" src="@/customer-service/imgs/pic.png" /> <img
</label> class="tool-bar-icon"
<!-- <label for="chat-upload-file" :title="tip4File" @click="allowLoadFile"> 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" /> <img class="tool-bar-icon" src="@/customer-service/imgs/file.png" />
</label> --> </label> -->
<input <input
@change="onChange" @change="onChange"
:value="file" :value="file"
id="chat-upload-file" id="chat-upload-file"
type="file" type="file"
:accept="acceptType" :accept="acceptType"
multiple multiple
/> />
</div>
<el-scrollbar class="input-el-scrollbar">
<div
class="input-container"
ref="input"
id="chat-input-box"
contenteditable="true"
@input="$emit('input')"
@keypress.enter="handleSendMsg"
@keyup.enter="handleReturn"
></div>
</el-scrollbar>
<div class="emoji-picker" v-show="emojiPanelVisibility">
<el-scrollbar class="overflow-x-hidden">
<span
class="emoji-item"
v-for="item in emoji"
:key="item.code"
:title="item.name"
@click.stop="selectEmoji(item)"
>{{ item.emoji_chars }}</span
>
</el-scrollbar>
</div>
</div> </div>
<el-scrollbar class="input-el-scrollbar">
<div
class="input-container"
ref="input"
id="chat-input-box"
contenteditable="true"
@input="$emit('input')"
@keypress.enter="handleSendMsg"
@keyup.enter="handleReturn"
></div>
</el-scrollbar>
<div class="emoji-picker" v-show="emojiPanelVisibility">
<el-scrollbar class="overflow-x-hidden">
<span
class="emoji-item"
v-for="item in emoji"
:key="item.code"
:title="item.name"
@click.stop="selectEmoji(item)"
>{{ item.emoji_chars }}</span
>
</el-scrollbar>
</div>
</div>
</template> </template>
<script lang="ts"> <script lang="ts">
...@@ -61,37 +64,37 @@ import { Component, Ref, Vue, Watch } from "vue-property-decorator"; ...@@ -61,37 +64,37 @@ import { Component, Ref, Vue, Watch } from "vue-property-decorator";
import { namespace } from "vuex-class"; import { namespace } from "vuex-class";
import { import {
getFileType, getFileType,
getSvg, getSvg,
MAX_FILE_SIZE, MAX_FILE_SIZE,
MAX_FILE_SIZE_STRING, MAX_FILE_SIZE_STRING,
MAX_IMAGE_SIZE, MAX_IMAGE_SIZE,
MAX_IMAGE_SIZE_STRING, MAX_IMAGE_SIZE_STRING,
MESSAGE_FILE_EMPTY, MESSAGE_FILE_EMPTY,
MESSAGE_FILE_TOO_LARGE, MESSAGE_FILE_TOO_LARGE,
MESSAGE_IMAGE_TOO_LARGE, MESSAGE_IMAGE_TOO_LARGE,
} from "../components/file-controller"; } from "../components/file-controller";
import { EmojiService } from "../service/emoji"; import { EmojiService } from "../service/emoji";
import { ChatStore } from "../store/model"; import { ChatStore } from "../store/model";
import { formatFileSize } from "../utils"; import { formatFileSize } from "../utils";
export const enum InputMessageType { export const enum InputMessageType {
Text = "text", Text = "text",
Image = "image", Image = "image",
File = "file", File = "file",
} }
export interface InputMessageBody { export interface InputMessageBody {
text?: string; text?: string;
url?: string; url?: string;
name?: string; name?: string;
size?: number; size?: number;
} }
export interface InputMessage { export interface InputMessage {
type: InputMessageType; type: InputMessageType;
body: InputMessageBody; body: InputMessageBody;
file?: File | null; file?: File | null;
} }
const chatStoreNamespace = namespace("chatStore"); const chatStoreNamespace = namespace("chatStore");
...@@ -102,560 +105,566 @@ export const IMAGE_INFO_CLASS = "img-info"; ...@@ -102,560 +105,566 @@ export const IMAGE_INFO_CLASS = "img-info";
export const FILE_INFO_CLASS = "file-info"; export const FILE_INFO_CLASS = "file-info";
export function isImageOrFile(node: ChildNode) { export function isImageOrFile(node: ChildNode) {
const e = node as HTMLElement; const e = node as HTMLElement;
return ( return (
e.classList && e.classList &&
(e.classList.contains(IMAGE_INFO_CLASS) || (e.classList.contains(IMAGE_INFO_CLASS) ||
e.classList.contains(FILE_INFO_CLASS)) e.classList.contains(FILE_INFO_CLASS))
); );
} }
@Component({ components: {} }) @Component({ components: {} })
export default class Input extends Vue { export default class Input extends Vue {
@chatStoreNamespace.State(ChatStore.STATE_CHAT_CURRENT_CHAT_ID) @chatStoreNamespace.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;
@Ref("input")
private readonly messageInputBox!: HTMLDivElement;
private file = "";
private acceptType = "image/*";
private emojiPanelVisibility = false;
@Ref("input") private tip4Image = `发送图片(最大${MAX_IMAGE_SIZE_STRING})`;
private readonly messageInputBox!: HTMLDivElement; private tip4File = `发送文件(最大${MAX_FILE_SIZE_STRING})`;
private file = ""; private emoji: { name: string; emoji_chars: string; code: string }[] = [];
private acceptType = "image/*";
private emojiPanelVisibility = false; @Watch("chatId")
private onChatIdChanged(v: number, old: number) {
if (old) {
const current = this.getNodeListFromInputBox();
if (current && current.length) {
chatCache[old] = current;
}
}
private tip4Image = `发送图片(最大${MAX_IMAGE_SIZE_STRING})`; this.clearInput();
private tip4File = `发送文件(最大${MAX_FILE_SIZE_STRING})`;
if (v) {
const cache = chatCache[v];
if (cache) {
const e = document.querySelector(
"#chat-input-box"
) as HTMLElement;
if (e) {
for (const node of cache as ChildNode[]) {
e.appendChild(node);
}
}
}
}
}
private emoji: { name: string; emoji_chars: string; code: string }[] = []; public mounted() {
this.messageInputBox.addEventListener("paste", this.handlePasteEvent);
document.addEventListener("click", this.hideEmoji);
document.addEventListener("selectionchange", this.handleSaveRange);
this.setupEmoji();
this.focus();
}
@Watch("chatId") public beforeDestroy() {
private onChatIdChanged(v: number, old: number) { document.removeEventListener("click", this.hideEmoji);
if (old) { document.removeEventListener("selectionchange", this.handleSaveRange);
const current = this.getNodeListFromInputBox();
if (current && current.length) {
chatCache[old] = current;
}
} }
this.clearInput(); public focus() {
this.messageInputBox.focus();
}
if (v) { private clearInput() {
const cache = chatCache[v]; this.messageInputBox.innerHTML = "";
if (cache) { const input = document.getElementById(
const e = document.querySelector("#chat-input-box") as HTMLElement; "chat-upload-file"
if (e) { ) as HTMLInputElement;
for (const node of cache as ChildNode[]) { if (input) {
e.appendChild(node); input.value = "";
}
} }
}
} }
}
private allowLoadImg() {
public mounted() { this.acceptType = "image/*";
this.messageInputBox.addEventListener("paste", this.handlePasteEvent);
document.addEventListener("click", this.hideEmoji);
document.addEventListener("selectionchange", this.handleSaveRange);
this.setupEmoji();
this.focus();
}
public beforeDestroy() {
document.removeEventListener("click", this.hideEmoji);
document.removeEventListener("selectionchange", this.handleSaveRange);
}
public focus() {
this.messageInputBox.focus();
}
private clearInput() {
this.messageInputBox.innerHTML = "";
const input = document.getElementById(
"chat-upload-file"
) as HTMLInputElement;
if (input) {
input.value = "";
} }
}
private allowLoadFile() {
private allowLoadImg() { this.acceptType = "*";
this.acceptType = "image/*"; }
}
private async handlePasteEvent(event: ClipboardEvent) {
private allowLoadFile() { /*
this.acceptType = "*"; * 组织默认行为原因
} * 1、浏览器自带复制粘贴图片到输入框的功能,与js加工后的图片重复了,
* 2、默认复制粘贴功能会粘贴dom结构
private async handlePasteEvent(event: ClipboardEvent) { * */
/* event.preventDefault();
* 组织默认行为原因 const items = event.clipboardData && event.clipboardData.items;
* 1、浏览器自带复制粘贴图片到输入框的功能,与js加工后的图片重复了, let html = "";
* 2、默认复制粘贴功能会粘贴dom结构 const promiseArr = [];
* */ if (items && items.length) {
event.preventDefault(); // 检索剪切板items中类型带有image的
const items = event.clipboardData && event.clipboardData.items; for (let i = 0; i < items.length; i++) {
let html = ""; if (items[i].kind === "file") {
const promiseArr = []; const file = items[i].getAsFile();
if (items && items.length) { if (file) {
// 检索剪切板items中类型带有image的 if (file.size <= 0) {
for (let i = 0; i < items.length; i++) { this.$emit("error", MESSAGE_FILE_EMPTY);
if (items[i].kind === "file") { return;
const file = items[i].getAsFile(); }
if (file) { if (this.isImage(file)) {
if (file.size <= 0) { if (file.size >= MAX_IMAGE_SIZE) {
this.$emit("error", MESSAGE_FILE_EMPTY); this.$emit("error", MESSAGE_IMAGE_TOO_LARGE);
return; return;
} }
if (this.isImage(file)) { html += this.buildImageHtml(file);
if (file.size >= MAX_IMAGE_SIZE) { } else {
this.$emit("error", MESSAGE_IMAGE_TOO_LARGE); if (file.size >= MAX_FILE_SIZE) {
return; this.$emit("error", MESSAGE_FILE_TOO_LARGE);
} return;
html += this.buildImageHtml(file); }
} else { html += this.buildFileHtml(file);
if (file.size >= MAX_FILE_SIZE) {
this.$emit("error", MESSAGE_FILE_TOO_LARGE);
return;
}
html += this.buildFileHtml(file);
}
break;
}
} else {
promiseArr.push(
new Promise<void>((resolve) => {
const contentType = items[i].type;
items[i].getAsString((k) => {
/*
* items第一项是文本
* 第二项是带有dom结构的文本(包含格式)
* 第三项写明了数据是从哪里复制来的
*/
if (i === 0) {
if (contentType === "text/plain") {
html += k;
}
} else if (i === 1) {
const srcRegex = /<img[^>]+src="([^">]+)"\s+title="([^">]+)"/g;
let result;
do {
result = srcRegex.exec(k);
if (result) {
const [, src, name] = result;
html += `<img tabindex="-1" src="${src}" data-image='${JSON.stringify(
{
url: src,
name,
} }
)}'>`; break;
html = html.replace(name, "");
} }
} while (result); } else {
promiseArr.push(
new Promise<void>((resolve) => {
const contentType = items[i].type;
items[i].getAsString((k) => {
/*
* items第一项是文本
* 第二项是带有dom结构的文本(包含格式)
* 第三项写明了数据是从哪里复制来的
*/
if (i === 0) {
if (contentType === "text/plain") {
html += k;
}
} else if (i === 1) {
const srcRegex =
/<img[^>]+src="([^">]+)"\s+title="([^">]+)"/g;
let result;
do {
result = srcRegex.exec(k);
if (result) {
const [, src, name] = result;
html += `<img tabindex="-1" src="${src}" data-image='${JSON.stringify(
{
url: src,
name,
}
)}'>`;
html = html.replace(name, "");
}
} while (result);
}
resolve();
});
})
);
} }
resolve(); }
}); }
}) await Promise.all(promiseArr);
); if (html) {
this.insertHtmlAtCaret(html);
} }
}
}
await Promise.all(promiseArr);
if (html) {
this.insertHtmlAtCaret(html);
} }
}
private handleReturn(e: KeyboardEvent) {
private handleReturn(e: KeyboardEvent) { if (e.altKey || e.ctrlKey) {
if (e.altKey || e.ctrlKey) { let el = this.messageInputBox;
let el = this.messageInputBox let range = document.createRange();
let range = document.createRange() let sel = window.getSelection();
let sel = window.getSelection() let offset = sel.focusOffset;
let offset = sel.focusOffset let content = el.innerHTML;
let content = el.innerHTML el.innerHTML =
el.innerHTML = content.slice(0, offset) + '\n' + (content.slice(offset) || '\n') content.slice(0, offset) +
range.setStart(el.childNodes[0], offset + 1) "\n" +
range.collapse(true) (content.slice(offset) || "\n");
sel.removeAllRanges() range.setStart(el.childNodes[0], offset + 1);
sel.addRange(range) range.collapse(true);
return sel.removeAllRanges();
sel.addRange(range);
return;
}
if (e.shiftKey) {
e.preventDefault();
return;
}
} }
if (e.shiftKey) {
e.preventDefault(); private async handleSendMsg(e: KeyboardEvent) {
return e.preventDefault();
if (e.shiftKey || e.ctrlKey || e.altKey) {
return;
}
return new Promise((resolve, reject) => {
try {
const data = this.getNodeListFromInputBox();
this.$emit("send", data, resolve);
} catch (e) {
this.$emit("error", e);
reject(e);
}
}).then(() => {
this.clearInput();
if (this.chatId) {
chatCache[this.chatId] = [];
}
});
} }
}
private async handleSendMsg(e: KeyboardEvent) { /**
e.preventDefault(); * 获取输入框中的内容
if (e.shiftKey || e.ctrlKey || e.altKey) { * @returns 返回的是节点数组
return */
private getNodeListFromInputBox() {
this.messageInputBox.normalize();
const nodes = Array.from(this.messageInputBox.childNodes);
return this.combine(nodes);
} }
return new Promise((resolve, reject) => {
try { /**
const data = this.getNodeListFromInputBox(); * 文本,链接等需要合并成纯文本发送
this.$emit("send", data, resolve); */
} catch (e) { private combine(nodes: ChildNode[]) {
this.$emit("error", e); const sendingNodes: ChildNode[] = [];
reject(e); let needCreateNewNode = false;
} let text = "";
}).then(() => { for (const item of nodes) {
this.clearInput(); if (!isImageOrFile(item) && item.textContent) {
if (this.chatId) { if (needCreateNewNode) {
chatCache[this.chatId] = []; text = "";
} needCreateNewNode = false;
}); }
} text += item.textContent;
} else {
/** needCreateNewNode = true;
* 获取输入框中的内容 if (text) {
* @returns 返回的是节点数组 this.checkTextLength(text);
*/ const node = document.createTextNode(text);
private getNodeListFromInputBox() { sendingNodes.push(node);
this.messageInputBox.normalize(); }
const nodes = Array.from(this.messageInputBox.childNodes); sendingNodes.push(item);
return this.combine(nodes); }
}
/**
* 文本,链接等需要合并成纯文本发送
*/
private combine(nodes: ChildNode[]) {
const sendingNodes: ChildNode[] = [];
let needCreateNewNode = false;
let text = "";
for (const item of nodes) {
if (!isImageOrFile(item) && item.textContent) {
if (needCreateNewNode) {
text = "";
needCreateNewNode = false;
} }
text += item.textContent;
} else {
needCreateNewNode = true;
if (text) { if (text) {
this.checkTextLength(text); this.checkTextLength(text);
const node = document.createTextNode(text); const node = document.createTextNode(text);
sendingNodes.push(node); sendingNodes.push(node);
} }
sendingNodes.push(item);
} return sendingNodes;
} }
if (text) { private checkTextLength(text: string) {
this.checkTextLength(text); if (text.length >= 4000) {
const node = document.createTextNode(text); throw new Error("消息不能超过4000个字");
sendingNodes.push(node); }
} }
return sendingNodes; private handleSaveRange() {
} const sel = window.getSelection();
if (sel && sel.rangeCount) {
const range = sel.getRangeAt(0);
const oldRange = this.getRange && this.getRange();
if (
this.messageInputBox &&
this.messageInputBox.contains(range.endContainer)
) {
if (
oldRange &&
range.collapsed &&
range.endContainer === oldRange.endContainer &&
range.endOffset === oldRange.endOffset
) {
return;
}
private checkTextLength(text: string) { this.saveRange && this.saveRange(range);
if (text.length >= 4000) { }
throw new Error("消息不能超过4000个字");
}
}
private handleSaveRange() {
const sel = window.getSelection();
if (sel && sel.rangeCount) {
const range = sel.getRangeAt(0);
const oldRange = this.getRange && this.getRange();
if (
this.messageInputBox &&
this.messageInputBox.contains(range.endContainer)
) {
if (
oldRange &&
range.collapsed &&
range.endContainer === oldRange.endContainer &&
range.endOffset === oldRange.endOffset
) {
return;
} }
this.saveRange && this.saveRange(range);
}
} }
}
private saveRange?: (param: Range) => void;
private saveRange?: (param: Range) => void; private getRange?: () => Range | null;
private getRange?: () => Range | null;
/**
/** * 在光标处插入元素
* 在光标处插入元素 */
*/ public insertHtmlAtCaret = (function () {
public insertHtmlAtCaret = (function() { let range: Range | null = null;
let range: Range | null = null; return function (this: Input, html: string) {
return function(this: Input, html: string) { if (this.saveRange == null) {
if (this.saveRange == null) { this.saveRange = (alternate) => (range = alternate);
this.saveRange = (alternate) => (range = alternate);
}
if (this.getRange == null) {
this.getRange = () => range;
}
const sel = window.getSelection();
if (sel) {
if (range) {
range.deleteContents();
sel.removeAllRanges();
sel.addRange(range);
} else {
this.focus();
range = sel.getRangeAt(0);
document.execCommand("selectAll");
window.getSelection()?.collapseToEnd();
}
}
const el = document.createElement("div");
el.innerHTML = html;
const frag = document.createDocumentFragment();
let node = null;
let lastNode = null;
while ((node = el.firstChild)) {
lastNode = frag.appendChild(node);
}
range?.insertNode(frag);
// Preserve the selection
if (lastNode) {
if (range) {
range = range.cloneRange();
range.setStartAfter(lastNode);
range.collapse(true);
sel?.removeAllRanges();
sel?.addRange(range);
}
}
};
})();
private selectEmoji(emoji: any) {
this.insertHtmlAtCaret(emoji.emoji_chars);
this.hideEmoji();
}
private isImage(file: File) {
return file.type.startsWith("image");
}
private buildImageHtml(file: File) {
const url = URL.createObjectURL(file);
return `<img class="${IMAGE_INFO_CLASS}" tabindex="-1" src="${url}" data-image='${JSON.stringify(
{
url,
name: file.name,
size: file.size,
}
)}'>`;
}
private buildFileHtml(file: File) {
const extension = file.name.split(".");
const type = getFileType(file.name);
return `<div class="${FILE_INFO_CLASS}" tabindex="-1" title="${
extension[extension.length - 1]
}" data-file='${JSON.stringify({
url: URL.createObjectURL(file),
name: file.name,
size: file.size,
})}'><div style="display: inline-block"><div class="file-name text-truncate text-nowrap">${
file.name
}</div><div class="file-size">${formatFileSize(
file.size
)}</div></div><span class="file-icon" title="${type}">${getSvg(
type
)}</span></div> `; // 注意</div>最后面有个空
}
private onChange(e: Event) {
const target = e.target as HTMLElement;
if (target) {
const input = document.getElementById(
target.id as string
) as HTMLInputElement;
if (input) {
const files = input.files;
if (files && files.length) {
let html = "";
for (let index = 0; index < files.length; index++) {
const file = files[index];
if (file.size <= 0) {
this.$emit("error", MESSAGE_FILE_EMPTY);
return;
} }
if (this.isImage(file)) { if (this.getRange == null) {
if (file.size >= MAX_IMAGE_SIZE) { this.getRange = () => range;
this.$emit("error", MESSAGE_IMAGE_TOO_LARGE); }
return; const sel = window.getSelection();
} if (sel) {
html += this.buildImageHtml(file); if (range) {
} else { range.deleteContents();
if (file.size >= MAX_FILE_SIZE) { sel.removeAllRanges();
this.$emit("error", MESSAGE_FILE_TOO_LARGE); sel.addRange(range);
return; } else {
} this.focus();
html += this.buildFileHtml(file); range = sel.getRangeAt(0);
document.execCommand("selectAll");
window.getSelection()?.collapseToEnd();
}
} }
}
this.insertHtmlAtCaret(html); const el = document.createElement("div");
el.innerHTML = html;
const frag = document.createDocumentFragment();
let node = null;
let lastNode = null;
while ((node = el.firstChild)) {
lastNode = frag.appendChild(node);
}
range?.insertNode(frag);
// Preserve the selection
if (lastNode) {
if (range) {
range = range.cloneRange();
range.setStartAfter(lastNode);
range.collapse(true);
sel?.removeAllRanges();
sel?.addRange(range);
}
}
};
})();
private selectEmoji(emoji: any) {
this.insertHtmlAtCaret(emoji.emoji_chars);
this.hideEmoji();
}
private isImage(file: File) {
return file.type.startsWith("image");
}
private buildImageHtml(file: File) {
const url = URL.createObjectURL(file);
return `<img class="${IMAGE_INFO_CLASS}" tabindex="-1" src="${url}" data-image='${JSON.stringify(
{
url,
name: file.name,
size: file.size,
}
)}'>`;
}
private buildFileHtml(file: File) {
const extension = file.name.split(".");
const type = getFileType(file.name);
return `<div class="${FILE_INFO_CLASS}" tabindex="-1" title="${
extension[extension.length - 1]
}" data-file='${JSON.stringify({
url: URL.createObjectURL(file),
name: file.name,
size: file.size,
})}'><div style="display: inline-block"><div class="file-name text-truncate text-nowrap">${
file.name
}</div><div class="file-size">${formatFileSize(
file.size
)}</div></div><span class="file-icon" title="${type}">${getSvg(
type
)}</span></div> `; // 注意</div>最后面有个空
}
private onChange(e: Event) {
const target = e.target as HTMLElement;
if (target) {
const input = document.getElementById(
target.id as string
) as HTMLInputElement;
if (input) {
const files = input.files;
if (files && files.length) {
let html = "";
for (let index = 0; index < files.length; index++) {
const file = files[index];
if (file.size <= 0) {
this.$emit("error", MESSAGE_FILE_EMPTY);
return;
}
if (this.isImage(file)) {
if (file.size >= MAX_IMAGE_SIZE) {
this.$emit("error", MESSAGE_IMAGE_TOO_LARGE);
return;
}
html += this.buildImageHtml(file);
} else {
if (file.size >= MAX_FILE_SIZE) {
this.$emit("error", MESSAGE_FILE_TOO_LARGE);
return;
}
html += this.buildFileHtml(file);
}
}
this.insertHtmlAtCaret(html);
}
}
} }
}
} }
}
private toggleEmoji() {
private toggleEmoji() { this.emojiPanelVisibility = !this.emojiPanelVisibility;
this.emojiPanelVisibility = !this.emojiPanelVisibility;
}
private hideEmoji(e?: Event) {
if (e && e.target) {
const target = e.target as HTMLElement;
if (target.closest(".emoji-picker")) {
return;
}
} }
this.emojiPanelVisibility = false;
} private hideEmoji(e?: Event) {
if (e && e.target) {
private setupEmoji() { const target = e.target as HTMLElement;
EmojiService.onReady(() => { if (target.closest(".emoji-picker")) {
const service = new EmojiService(); return;
service.getEmoji().then((r) => { }
if (r) {
this.emoji = r.list;
} }
}); this.emojiPanelVisibility = false;
}); }
}
private setupEmoji() {
EmojiService.onReady(() => {
const service = new EmojiService();
service.getEmoji().then((r) => {
if (r) {
this.emoji = r.list;
}
});
});
}
} }
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.input-wrap { .input-wrap {
position: relative; position: relative;
padding-left: 20px; padding-left: 20px;
/deep/.input-el-scrollbar.el-scrollbar { /deep/.input-el-scrollbar.el-scrollbar {
height: calc(100% - 35px); height: calc(100% - 35px);
> .el-scrollbar__wrap { > .el-scrollbar__wrap {
overflow-x: hidden; overflow-x: hidden;
} }
> .el-scrollbar__wrap > .el-scrollbar__view {
min-height: 100%;
display: flex;
// 输入框 > .el-scrollbar__wrap > .el-scrollbar__view {
> .input-container { min-height: 100%;
width: 100%; display: flex;
font-size: 14px;
padding: 10px 20px 10px 0; // 输入框
outline: 0; > .input-container {
white-space: pre-wrap; width: 100%;
user-select: text; font-size: 14px;
padding: 10px 20px 10px 0;
outline: 0;
white-space: pre-wrap;
user-select: text;
&::selection {
background-color: #cce6fc;
}
&::selection { img {
background-color: #cce6fc; max-width: 300px;
} font-size: 50px;
vertical-align: bottom;
border: 1px solid transparent;
img { &:focus {
max-width: 300px; border-color: var(--main-color);
font-size: 50px; }
vertical-align: bottom;
border: 1px solid transparent;
&:focus { &::selection {
border-color: var(--main-color); background-color: #cce6fc;
} }
}
&::selection { .file-info {
background-color: #cce6fc; padding: 10px;
} border: 1px solid #c5d4e5;
} border-radius: 4px;
display: inline-block;
margin-right: 10px;
-webkit-user-modify: read-only;
user-select: none;
.file-name {
color: #000;
font-size: 14px;
max-width: 130px;
}
.file-info { .file-size {
padding: 10px; margin-top: 10px;
border: 1px solid #c5d4e5; }
border-radius: 4px; }
display: inline-block; }
margin-right: 10px;
-webkit-user-modify: read-only;
user-select: none;
.file-name {
color: #000;
font-size: 14px;
max-width: 130px;
}
.file-size {
margin-top: 10px;
}
} }
}
} }
}
.input-emoji { .input-emoji {
position: absolute; position: absolute;
left: 0; left: 0;
top: -225px; top: -225px;
outline: 0; outline: 0;
} }
} }
.tool-bar { .tool-bar {
padding-top: 10px; padding-top: 10px;
user-select: none; user-select: none;
.tool-bar-icon { .tool-bar-icon {
height: 16px; height: 16px;
width: 16px; width: 16px;
cursor: pointer; cursor: pointer;
} }
.offset { .offset {
margin: 0 22px; margin: 0 22px;
} }
} }
.emoji-picker { .emoji-picker {
position: absolute; position: absolute;
z-index: 2; z-index: 2;
bottom: 99px; bottom: 99px;
left: -1px; left: -1px;
background-color: #fff; background-color: #fff;
padding: 20px; padding: 20px;
padding-right: 0; padding-right: 0;
padding-bottom: 10px; padding-bottom: 10px;
border: 1px solid #f0f0f0; border: 1px solid #f0f0f0;
right: 45px; right: 45px;
overflow: hidden; overflow: hidden;
.el-scrollbar { .el-scrollbar {
height: 200px; height: 200px;
} }
.emoji-item { .emoji-item {
display: inline-flex; display: inline-flex;
cursor: pointer; cursor: pointer;
min-width: 35px; min-width: 35px;
min-height: 25px; min-height: 25px;
font-size: 20px; font-size: 20px;
vertical-align: top; vertical-align: top;
margin-top: 5px; margin-top: 5px;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
} }
} }
#chat-upload-file { #chat-upload-file {
visibility: hidden; visibility: hidden;
position: absolute; position: absolute;
} }
</style> </style>
...@@ -15,56 +15,57 @@ export namespace ChatStore { ...@@ -15,56 +15,57 @@ export namespace ChatStore {
export const ns = "chatStore"; export const ns = "chatStore";
/* state */ /* state */
export const STATE_CHAT_DIALOG_VISIBLE = "会话模块弹窗显示状态"; export const STATE_CHAT_DIALOG_VISIBLE = "会话模块弹窗显示状态";
export type STATE_CHAT_DIALOG_VISIBLE = boolean export type STATE_CHAT_DIALOG_VISIBLE = boolean;
export const STATE_CHAT_DIALOG_IS_SINGLE = "会话模块是否是单个弹窗"; export const STATE_CHAT_DIALOG_IS_SINGLE = "会话模块是否是单个弹窗";
export type STATE_CHAT_DIALOG_IS_SINGLE = boolean export type STATE_CHAT_DIALOG_IS_SINGLE = boolean;
export const STATE_MY_CHAT_ROOM_LIST = "我的会话列表"; export const STATE_MY_CHAT_ROOM_LIST = "我的会话列表";
export type STATE_MY_CHAT_ROOM_LIST = { export type STATE_MY_CHAT_ROOM_LIST = {
list: ChatType[]; list: ChatType[];
total: number; total: number;
} | null } | null;
export const STATE_SINGLE_CHAT = "单独的会话"; export const STATE_SINGLE_CHAT = "单独的会话";
export type STATE_SINGLE_CHAT = ChatType | null export type STATE_SINGLE_CHAT = ChatType | null;
export const STATE_CHAT_MSG_HISTORY = "某个会话聊天记录"; export const STATE_CHAT_MSG_HISTORY = "某个会话聊天记录";
export type STATE_CHAT_MSG_HISTORY = dto.MessageRequestResult | null export type STATE_CHAT_MSG_HISTORY = dto.MessageRequestResult | null;
export const STATE_CHAT_SENDING_MESSAGES = "sendingMessages"; export const STATE_CHAT_SENDING_MESSAGES = "sendingMessages";
export type STATE_CHAT_SENDING_MESSAGES = dto.MessageRequestResult | null export type STATE_CHAT_SENDING_MESSAGES = dto.MessageRequestResult | null;
export type STATE_CHAT_SENDING_MESSAGE = dto.Message export type STATE_CHAT_SENDING_MESSAGE = dto.Message;
export const STATE_CHAT_CURRENT_CHAT_ID = "当前chat-id"; export const STATE_CHAT_CURRENT_CHAT_ID = "当前chat-id";
export type STATE_CHAT_CURRENT_CHAT_ID = number | null export type STATE_CHAT_CURRENT_CHAT_ID = number | null;
export const STATE_CHAT_CURRENT_CHAT_VERSION = "当前chat的Uniplat version"; export const STATE_CHAT_CURRENT_CHAT_VERSION = "当前chat的Uniplat version";
export type STATE_CHAT_CURRENT_CHAT_VERSION = number | null export type STATE_CHAT_CURRENT_CHAT_VERSION = number | null;
export const STATE_CHAT_CURRENT_IS_CHAT_MEMBER = "是否是当前chat的成员"; export const STATE_CHAT_CURRENT_IS_CHAT_MEMBER = "是否是当前chat的成员";
export type STATE_CHAT_CURRENT_IS_CHAT_MEMBER = boolean export type STATE_CHAT_CURRENT_IS_CHAT_MEMBER = boolean;
export const STATE_CHAT_CURRENT_USER_UID = "用户的UiplatId"; export const STATE_CHAT_CURRENT_USER_UID = "用户的UiplatId";
export type STATE_CHAT_CURRENT_USER_UID = number | null export type STATE_CHAT_CURRENT_USER_UID = number | null;
export const STATE_CHAT_CURRENT_USER_TYPE = "当前用户类型状态,25-普通用户,92-客服"; export const STATE_CHAT_CURRENT_USER_TYPE =
export type STATE_CHAT_CURRENT_USER_TYPE = string | null "当前用户类型状态,25-普通用户,92-客服";
export type STATE_CHAT_CURRENT_USER_TYPE = string | 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;
export const STATE_CHAT_USERNAME = "会话用户id-name"; export const STATE_CHAT_USERNAME = "会话用户id-name";
export type STATE_CHAT_USERNAME = {[key: string]: string} | {} export type STATE_CHAT_USERNAME = { [key: string]: string } | {};
export const STATE_CHAT_MY_ID = "聊天窗口显示在右边那个人的id"; export const STATE_CHAT_MY_ID = "聊天窗口显示在右边那个人的id";
export type STATE_CHAT_MY_ID = string | null export type STATE_CHAT_MY_ID = string | null;
export const STATE_CHAT_MY_UID = "聊天窗口显示在右边那个人的uid"; export const STATE_CHAT_MY_UID = "聊天窗口显示在右边那个人的uid";
export type STATE_CHAT_MY_UID = string | null export type STATE_CHAT_MY_UID = string | null;
export const STATE_CHAT_SOURCE = "stateChatSource"; export const STATE_CHAT_SOURCE = "stateChatSource";
export type STATE_CHAT_SOURCE = StateChatSourceDirection export type STATE_CHAT_SOURCE = StateChatSourceDirection;
export const STATE_CURRENT_CHAT_INPUTING = "当前会话正在输入的人"; export const STATE_CURRENT_CHAT_INPUTING = "当前会话正在输入的人";
export type STATE_CURRENT_CHAT_INPUTING = string[] export type STATE_CURRENT_CHAT_INPUTING = string[];
export const STATE_CURRENT_CHAT_INITING = "当前会是否正在初始化"; export const STATE_CURRENT_CHAT_INITING = "当前会是否正在初始化";
export type STATE_CURRENT_CHAT_INITING = boolean export type STATE_CURRENT_CHAT_INITING = boolean;
export const STATE_CHAT_SEND_FAIL_MESSAGE = "最新一条发送失败消息"; export const STATE_CHAT_SEND_FAIL_MESSAGE = "最新一条发送失败消息";
export type STATE_CHAT_SEND_FAIL_MESSAGE = string | null export type STATE_CHAT_SEND_FAIL_MESSAGE = string | null;
/** /**
* 消息来源,是来自客服端(Server),还是来自于顾客端(Client) * 消息来源,是来自客服端(Server),还是来自于顾客端(Client)
...@@ -77,184 +78,198 @@ export namespace ChatStore { ...@@ -77,184 +78,198 @@ export namespace ChatStore {
export const STATE_CURRENT_CHAT_MEMBERS = "当前会话参与者"; export const STATE_CURRENT_CHAT_MEMBERS = "当前会话参与者";
export type STATE_CURRENT_CHAT_MEMBERS = export type STATE_CURRENT_CHAT_MEMBERS =
| readonly (dto.ChatMember & dto.ChatMemberExtraInfo)[] | readonly (dto.ChatMember & dto.ChatMemberExtraInfo)[]
| null | 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;
export const STATE_FUNC_SCROLL_TO_BOTTOM = "收到消息后滚动到底部的方法"; export const STATE_FUNC_SCROLL_TO_BOTTOM = "收到消息后滚动到底部的方法";
export type STATE_FUNC_SCROLL_TO_BOTTOM = () => void export type STATE_FUNC_SCROLL_TO_BOTTOM = () => void;
export const STATE_FUNC_ON_NEW_MSG = "收到消息回调方法"; export const STATE_FUNC_ON_NEW_MSG = "收到消息回调方法";
export type STATE_FUNC_ON_NEW_MSG = (e: chatDto.Message) => void export type STATE_FUNC_ON_NEW_MSG = (e: chatDto.Message) => void;
/* getter */ /* getter */
export const GETTER_CURRENT_CHAT_PRESENT_MEMBERS = "当前会话未退出的参与者"; export const GETTER_CURRENT_CHAT_PRESENT_MEMBERS = "当前会话未退出的参与者";
export type GETTER_CURRENT_CHAT_PRESENT_MEMBERS = dto.ChatMembers | null export type GETTER_CURRENT_CHAT_PRESENT_MEMBERS = dto.ChatMembers | null;
export const GETTER_CURRENT_CURRENT_CHAT = "当前打开的会话"; export const GETTER_CURRENT_CURRENT_CHAT = "当前打开的会话";
export type GETTER_CURRENT_CURRENT_CHAT = ChatType | null export type GETTER_CURRENT_CURRENT_CHAT = ChatType | null;
/* mutation */ /* mutation */
export const MUTATION_SHOW_CHAT = "打开会话弹窗"; export const MUTATION_SHOW_CHAT = "打开会话弹窗";
export type MUTATION_SHOW_CHAT = () => void export type MUTATION_SHOW_CHAT = () => void;
export const MUTATION_HIDE_CHAT = "关闭会话弹窗"; export const MUTATION_HIDE_CHAT = "关闭会话弹窗";
export type MUTATION_HIDE_CHAT = () => void export type MUTATION_HIDE_CHAT = () => void;
export const MUTATION_SAVE_CHAT_LIST = "保存我的会话列表"; export const MUTATION_SAVE_CHAT_LIST = "保存我的会话列表";
export type MUTATION_SAVE_CHAT_LIST = ( export type MUTATION_SAVE_CHAT_LIST = (
list: STATE_MY_CHAT_ROOM_LIST list: STATE_MY_CHAT_ROOM_LIST
) => void ) => void;
export const MUTATION_PUSH_CHAT_MSG_HISTORY = "新增下一页聊天记录"; export const MUTATION_PUSH_CHAT_MSG_HISTORY = "新增下一页聊天记录";
export type MUTATION_PUSH_CHAT_MSG_HISTORY = ( export type MUTATION_PUSH_CHAT_MSG_HISTORY = (
list: ChatStore.STATE_CHAT_MSG_HISTORY list: ChatStore.STATE_CHAT_MSG_HISTORY
) => void ) => void;
export const MUTATION_INITING_CHAT = "当前会话正在初始化"; export const MUTATION_INITING_CHAT = "当前会话正在初始化";
export type MUTATION_INITING_CHAT = () => void export type MUTATION_INITING_CHAT = () => void;
export const MUTATION_INITING_CHAT_DONE = "当前会话初始完成"; export const MUTATION_INITING_CHAT_DONE = "当前会话初始完成";
export type MUTATION_INITING_CHAT_DONE = () => void export type MUTATION_INITING_CHAT_DONE = () => void;
export const MUTATION_UNSHIFT_CHAT_MSG_HISTORY = "新增上一页聊天记录"; export const MUTATION_UNSHIFT_CHAT_MSG_HISTORY = "新增上一页聊天记录";
export type MUTATION_UNSHIFT_CHAT_MSG_HISTORY = ( export type MUTATION_UNSHIFT_CHAT_MSG_HISTORY = (
list: ChatStore.STATE_CHAT_MSG_HISTORY list: ChatStore.STATE_CHAT_MSG_HISTORY
) => void ) => void;
export const MUTATION_CLEAR_CHAT_MSG_HISTORY = "清空聊天记录"; export const MUTATION_CLEAR_CHAT_MSG_HISTORY = "清空聊天记录";
export type MUTATION_CLEAR_CHAT_MSG_HISTORY = () => void export type MUTATION_CLEAR_CHAT_MSG_HISTORY = () => void;
export const MUTATION_SAVE_SINGLE_CHAT = "设置单独的会话"; export const MUTATION_SAVE_SINGLE_CHAT = "设置单独的会话";
export type MUTATION_SAVE_SINGLE_CHAT = (v: ChatType) => void export type MUTATION_SAVE_SINGLE_CHAT = (v: ChatType) => void;
export const MUTATION_CLEAR_SINGLE_CHAT = "清空单独的会话"; export const MUTATION_CLEAR_SINGLE_CHAT = "清空单独的会话";
export type MUTATION_CLEAR_SINGLE_CHAT = () => void export type MUTATION_CLEAR_SINGLE_CHAT = () => void;
export const MUTATION_SAVE_SEND_FAIL_MESSAGE = "更新最新一条发送失败消息"; export const MUTATION_SAVE_SEND_FAIL_MESSAGE = "更新最新一条发送失败消息";
export type MUTATION_SAVE_SEND_FAIL_MESSAGE = (param: {msg: string, ts: number}) => void export type MUTATION_SAVE_SEND_FAIL_MESSAGE = (param: {
msg: string;
ts: number;
}) => void;
export const MUTATION_SAVE_USERNAME = "更新用户id-name"; export const MUTATION_SAVE_USERNAME = "更新用户id-name";
export type MUTATION_SAVE_USERNAME = (param: {id: string, name: string}) => void export type MUTATION_SAVE_USERNAME = (param: {
id: string;
name: string;
}) => void;
export const MUTATION_SAVE_CURRENT_CHAT_ID = "保存当前chat-id"; export const MUTATION_SAVE_CURRENT_CHAT_ID = "保存当前chat-id";
export type MUTATION_SAVE_CURRENT_CHAT_ID = ( export type MUTATION_SAVE_CURRENT_CHAT_ID = (
chatId: ChatStore.STATE_CHAT_CURRENT_CHAT_ID chatId: ChatStore.STATE_CHAT_CURRENT_CHAT_ID
) => void ) => void;
export const MUTATION_CLEAR_CURRENT_CHAT_ID = "清空chat-id"; export const MUTATION_CLEAR_CURRENT_CHAT_ID = "清空chat-id";
export type MUTATION_CLEAR_CURRENT_CHAT_ID = () => void export type MUTATION_CLEAR_CURRENT_CHAT_ID = () => void;
export const MUTATION_SET_CURRENT_USER_UID = "设置当前用户UniplatId"; export const MUTATION_SET_CURRENT_USER_UID = "设置当前用户UniplatId";
export type MUTATION_SET_CURRENT_USER_UID = (v: number) => void export type MUTATION_SET_CURRENT_USER_UID = (v: number) => void;
export const MUTATION_SAVE_CURRENT_CHAT_VERSION = export const MUTATION_SAVE_CURRENT_CHAT_VERSION =
"保存当前chat uniplat version"; "保存当前chat uniplat version";
export type MUTATION_SAVE_CURRENT_CHAT_VERSION = ( export type MUTATION_SAVE_CURRENT_CHAT_VERSION = (
v: ChatStore.STATE_CHAT_CURRENT_CHAT_VERSION v: ChatStore.STATE_CHAT_CURRENT_CHAT_VERSION
) => void ) => void;
export const MUTATION_CLEAR_CURRENT_CHAT_VERSION = export const MUTATION_CLEAR_CURRENT_CHAT_VERSION =
"清空chat uniplat version"; "清空chat uniplat version";
export type MUTATION_CLEAR_CURRENT_CHAT_VERSION = () => void export type MUTATION_CLEAR_CURRENT_CHAT_VERSION = () => void;
export const MUTATION_SAVE_CURRENT_CHAT_UNIPLAT_ID = export const MUTATION_SAVE_CURRENT_CHAT_UNIPLAT_ID =
"保存当前chat uniplat id"; "保存当前chat uniplat id";
export type MUTATION_SAVE_CURRENT_CHAT_UNIPLAT_ID = ( export type MUTATION_SAVE_CURRENT_CHAT_UNIPLAT_ID = (
v: ChatStore.STATE_CHAT_CURRENT_CHAT_UNIPLAT_ID v: ChatStore.STATE_CHAT_CURRENT_CHAT_UNIPLAT_ID
) => void ) => void;
export const MUTATION_CLEAR_CURRENT_CHAT_UNIPLAT_ID = "清空chat uniplat id"; export const MUTATION_CLEAR_CURRENT_CHAT_UNIPLAT_ID = "清空chat uniplat id";
export type MUTATION_CLEAR_CURRENT_CHAT_UNIPLAT_ID = () => void export type MUTATION_CLEAR_CURRENT_CHAT_UNIPLAT_ID = () => void;
export const MUTATION_SAVE_MYSELF_ID = export const MUTATION_SAVE_MYSELF_ID =
"保存我的id:聊天窗口显示在右边那个人的id"; "保存我的id:聊天窗口显示在右边那个人的id";
export type MUTATION_SAVE_MYSELF_ID = () => void export type MUTATION_SAVE_MYSELF_ID = () => void;
export const MUTATION_CLEAR_MYSELF_ID = export const MUTATION_CLEAR_MYSELF_ID =
"清空我的id:聊天窗口显示在右边那个人的id"; "清空我的id:聊天窗口显示在右边那个人的id";
export type MUTATION_CLEAR_MYSELF_ID = () => void export type MUTATION_CLEAR_MYSELF_ID = () => void;
export const MUTATION_SET_CHAT_SOURCE = "setChatSource"; export const MUTATION_SET_CHAT_SOURCE = "setChatSource";
export type MUTATION_SET_CHAT_SOURCE = ( export type MUTATION_SET_CHAT_SOURCE = (
payload: StateChatSourceDirection payload: StateChatSourceDirection
) => void ) => void;
export const MUTATION_SAVE_CURRENT_CHAT_MEMBERS = "保存当前会话参与者"; export const MUTATION_SAVE_CURRENT_CHAT_MEMBERS = "保存当前会话参与者";
export type MUTATION_SAVE_CURRENT_CHAT_MEMBERS = ( export type MUTATION_SAVE_CURRENT_CHAT_MEMBERS = (
params: ChatStore.STATE_CURRENT_CHAT_MEMBERS params: ChatStore.STATE_CURRENT_CHAT_MEMBERS
) => void ) => void;
export const MUTATION_CLEAR_CURRENT_CHAT_MEMBERS = "清空当前会话参与者"; export const MUTATION_CLEAR_CURRENT_CHAT_MEMBERS = "清空当前会话参与者";
export type MUTATION_CLEAR_CURRENT_CHAT_MEMBERS = () => void export type MUTATION_CLEAR_CURRENT_CHAT_MEMBERS = () => void;
export const MUTATION_SAVE_CHAT_TITLE = "保存会话标题"; export const MUTATION_SAVE_CHAT_TITLE = "保存会话标题";
export type MUTATION_SAVE_CHAT_TITLE = ( export type MUTATION_SAVE_CHAT_TITLE = (
title: ChatStore.STATE_CURRENT_CHAT_TITLE title: ChatStore.STATE_CURRENT_CHAT_TITLE
) => void ) => void;
export const MUTATION_CLEAR_CHAT_TITLE = "清空会话标题"; export const MUTATION_CLEAR_CHAT_TITLE = "清空会话标题";
export type MUTATION_CLEAR_CHAT_TITLE = () => void export type MUTATION_CLEAR_CHAT_TITLE = () => void;
export const MUTATION_SCROLL_TO_BOTTOM = "收到新消息后滚动到底部"; export const MUTATION_SCROLL_TO_BOTTOM = "收到新消息后滚动到底部";
export type MUTATION_SCROLL_TO_BOTTOM = () => void export type MUTATION_SCROLL_TO_BOTTOM = () => void;
export const MUTATION_SAVE_FUNC_SCROLL_TO_BOTTOM = export const MUTATION_SAVE_FUNC_SCROLL_TO_BOTTOM =
"保存收到新消息后滚动到底部的方法"; "保存收到新消息后滚动到底部的方法";
export type MUTATION_SAVE_FUNC_SCROLL_TO_BOTTOM = (func: () => void) => void export type MUTATION_SAVE_FUNC_SCROLL_TO_BOTTOM = (
func: () => void
) => void;
export const MUTATION_CLEAR_FUNC_SCROLL_TO_BOTTOM = export const MUTATION_CLEAR_FUNC_SCROLL_TO_BOTTOM =
"删除收到新消息后滚动到底部的方法"; "删除收到新消息后滚动到底部的方法";
export type MUTATION_CLEAR_FUNC_SCROLL_TO_BOTTOM = () => void export type MUTATION_CLEAR_FUNC_SCROLL_TO_BOTTOM = () => void;
export const MUTATION_SAVE_FUNC_ON_NEW_MSG = "保存收到新消息后的方法"; export const MUTATION_SAVE_FUNC_ON_NEW_MSG = "保存收到新消息后的方法";
export type MUTATION_SAVE_FUNC_ON_NEW_MSG = (func: (e: dto.Message) => void) => void export type MUTATION_SAVE_FUNC_ON_NEW_MSG = (
func: (e: dto.Message) => void
) => void;
export const MUTATION_CLEAR_FUNC_ON_NEW_MSG = "删除收到新消息后的方法"; export const MUTATION_CLEAR_FUNC_ON_NEW_MSG = "删除收到新消息后的方法";
export type MUTATION_CLEAR_FUNC_ON_NEW_MSG = () => void export type MUTATION_CLEAR_FUNC_ON_NEW_MSG = () => void;
export const MUTATION_APPEND_SENDING_MESSAGE = "appendSendingMessage"; export const MUTATION_APPEND_SENDING_MESSAGE = "appendSendingMessage";
export type MUTATION_APPEND_SENDING_MESSAGE = (payload: dto.Message) => void export type MUTATION_APPEND_SENDING_MESSAGE = (
payload: dto.Message
) => void;
export const MUTATION_REMOVE_SENDING_MESSAGE = "removeSendingMessage"; export const MUTATION_REMOVE_SENDING_MESSAGE = "removeSendingMessage";
export type MUTATION_REMOVE_SENDING_MESSAGE = (id: number) => void export type MUTATION_REMOVE_SENDING_MESSAGE = (id: number) => void;
export const MUTATION_FAILED_SENDING_MESSAGE = "failedSendingMessage"; export const MUTATION_FAILED_SENDING_MESSAGE = "failedSendingMessage";
export type MUTATION_FAILED_SENDING_MESSAGE = (id: number) => void export type MUTATION_FAILED_SENDING_MESSAGE = (id: number) => void;
export const MUTATION_SAVE_CURRENT_CHAT_INPUTING = "保存正在输入"; export const MUTATION_SAVE_CURRENT_CHAT_INPUTING = "保存正在输入";
export type MUTATION_SAVE_CURRENT_CHAT_INPUTING = ( export type MUTATION_SAVE_CURRENT_CHAT_INPUTING = (
params: chatDto.NotifyMessage params: chatDto.NotifyMessage
) => void ) => void;
export const MUTATION_CLEAR_CURRENT_CHAT_INPUTING = "清空正在输入"; export const MUTATION_CLEAR_CURRENT_CHAT_INPUTING = "清空正在输入";
export type MUTATION_CLEAR_CURRENT_CHAT_INPUTING = () => void export type MUTATION_CLEAR_CURRENT_CHAT_INPUTING = () => void;
export const MUTATION_CHAT_UPDATE_IS_MEMBER = "更新是否是当前成员"; export const MUTATION_CHAT_UPDATE_IS_MEMBER = "更新是否是当前成员";
export type MUTATION_CHAT_UPDATE_IS_MEMBER = (v: boolean) => Promise<void> export type MUTATION_CHAT_UPDATE_IS_MEMBER = (v: boolean) => Promise<void>;
export const MUTATION_CHAT_UPDATE_USER_TYPE = "更新当前用户的类型"; export const MUTATION_CHAT_UPDATE_USER_TYPE = "更新当前用户的类型";
export type MUTATION_CHAT_UPDATE_USER_TYPE = (v: string) => Promise<void> export type MUTATION_CHAT_UPDATE_USER_TYPE = (v: string) => Promise<void>;
/* action */ /* action */
export const ACTION_GET_MY_CHAT_LIST = "获取我的会话列表"; export const ACTION_GET_MY_CHAT_LIST = "获取我的会话列表";
export type ACTION_GET_MY_CHAT_LIST = (keyword?: string) => void export type ACTION_GET_MY_CHAT_LIST = (
keyword?: string
) => Promise<ChatStore.STATE_MY_CHAT_ROOM_LIST>;
export const ACTION_JOIN_CHAT = "加入某个会话"; export const ACTION_JOIN_CHAT = "加入某个会话";
export type ACTION_JOIN_CHAT = (chatId: number) => void export type ACTION_JOIN_CHAT = (chatId: number) => void;
export const ACTION_GET_CHAT_MESSAGES = "打开某个会话时获取他的聊天记录"; export const ACTION_GET_CHAT_MESSAGES = "打开某个会话时获取他的聊天记录";
export type ACTION_GET_CHAT_MESSAGES = export type ACTION_GET_CHAT_MESSAGES =
() => Promise<dto.MessageRequestResult> () => Promise<dto.MessageRequestResult>;
export const ACTION_GET_CHAT_MESSAGES_BEFORE_SPECIFIC_ID = export const ACTION_GET_CHAT_MESSAGES_BEFORE_SPECIFIC_ID =
"获取某个消息之前的10条消息"; "获取某个消息之前的10条消息";
export type ACTION_GET_CHAT_MESSAGES_BEFORE_SPECIFIC_ID = ( export type ACTION_GET_CHAT_MESSAGES_BEFORE_SPECIFIC_ID = (
msgId: number msgId: number
) => Promise<dto.MessageRequestResult> ) => Promise<dto.MessageRequestResult>;
export const ACTION_GET_CHAT_MESSAGES_AFTER_SPECIFIC_ID = export const ACTION_GET_CHAT_MESSAGES_AFTER_SPECIFIC_ID =
"获取某个消息之后的10条消息"; "获取某个消息之后的10条消息";
export type ACTION_GET_CHAT_MESSAGES_AFTER_SPECIFIC_ID = ( export type ACTION_GET_CHAT_MESSAGES_AFTER_SPECIFIC_ID = (
msgId: number msgId: number
) => Promise<dto.MessageRequestResult> ) => Promise<dto.MessageRequestResult>;
export const ACTION_GET_FRESH_MESSAGE = "获取最新的消息"; export const ACTION_GET_FRESH_MESSAGE = "获取最新的消息";
export type ACTION_GET_FRESH_MESSAGE = export type ACTION_GET_FRESH_MESSAGE =
() => Promise<dto.MessageRequestResult> () => Promise<dto.MessageRequestResult>;
export const ACTION_CREATE_NEW_CHAT_BY_SERVICE_MAN = "客服向顾客发起新会话"; export const ACTION_CREATE_NEW_CHAT_BY_SERVICE_MAN = "客服向顾客发起新会话";
export type ACTION_CREATE_NEW_CHAT_BY_SERVICE_MAN = (params: { export type ACTION_CREATE_NEW_CHAT_BY_SERVICE_MAN = (params: {
...@@ -262,63 +277,65 @@ export namespace ChatStore { ...@@ -262,63 +277,65 @@ export namespace ChatStore {
selectedListId: string; selectedListId: string;
uids: string[]; uids: string[];
showByPage?: boolean; showByPage?: boolean;
}) => Promise<void> }) => Promise<void>;
export const ACTION_CREATE_NEW_CHAT_BY_CLIENT = "顾客向客服发起新会话"; export const ACTION_CREATE_NEW_CHAT_BY_CLIENT = "顾客向客服发起新会话";
export type ACTION_CREATE_NEW_CHAT_BY_CLIENT = (params: { export type ACTION_CREATE_NEW_CHAT_BY_CLIENT = (params: {
modelName: string; modelName: string;
selectedListId: string; selectedListId: string;
uids: string[]; uids: string[];
}) => Promise<void> }) => Promise<void>;
export const ACTION_CREATE_NEW_CHAT_BY_CLIENT_SIDE = export const ACTION_CREATE_NEW_CHAT_BY_CLIENT_SIDE =
"startNewConversationByCustomerSide"; "startNewConversationByCustomerSide";
export type ACTION_CREATE_NEW_CHAT_BY_CLIENT_SIDE = (option: { export type ACTION_CREATE_NEW_CHAT_BY_CLIENT_SIDE = (option: {
customerServiceId?: number | string; customerServiceId?: number | string;
customerServiceGroupId?: number | string; customerServiceGroupId?: number | string;
}) => Promise<number> }) => Promise<number>;
export const ACTION_SAVE_CURRENT_CHAT_ID_VERSION = "action:保存当前chat-id"; export const ACTION_SAVE_CURRENT_CHAT_ID_VERSION = "action:保存当前chat-id";
export type ACTION_SAVE_CURRENT_CHAT_ID_VERSION = (chatId: ChatStore.STATE_CHAT_CURRENT_CHAT_ID) => Promise<void> export type ACTION_SAVE_CURRENT_CHAT_ID_VERSION = (
chatId: ChatStore.STATE_CHAT_CURRENT_CHAT_ID
) => Promise<void>;
export const ACTION_CLEAR_CURRENT_CHAT_DATA = "action:清空当前会话数据"; export const ACTION_CLEAR_CURRENT_CHAT_DATA = "action:清空当前会话数据";
export type ACTION_CLEAR_CURRENT_CHAT_DATA = () => Promise<void> export type ACTION_CLEAR_CURRENT_CHAT_DATA = () => Promise<void>;
export const ACTION_REGISTER_EVENT = "给当前会话注册事件通知"; export const ACTION_REGISTER_EVENT = "给当前会话注册事件通知";
export type ACTION_REGISTER_EVENT = () => Promise<void> export type ACTION_REGISTER_EVENT = () => Promise<void>;
export const ACTION_GET_CHAT_MEMBERS = "获取会话成员列表"; export const ACTION_GET_CHAT_MEMBERS = "获取会话成员列表";
export type ACTION_GET_CHAT_MEMBERS = () => Promise<void> export type ACTION_GET_CHAT_MEMBERS = () => Promise<void>;
export const ACTION_SEND_MESSAGE = "发送消息"; export const ACTION_SEND_MESSAGE = "发送消息";
export type ACTION_SEND_MESSAGE = (params: { export type ACTION_SEND_MESSAGE = (params: {
msgType: "text" | "image" | "file" | "voice" | "video"; msgType: "text" | "image" | "file" | "voice" | "video";
msg: string; msg: string;
ts?: number; ts?: number;
}) => void }) => void;
export const ACTION_TERINATE_CHAT = "结束会话"; export const ACTION_TERINATE_CHAT = "结束会话";
export type ACTION_TERINATE_CHAT = () => Promise<void> export type ACTION_TERINATE_CHAT = () => Promise<void>;
export const ACTION_CHAT_ADD_MEMBERS = "添加成员"; export const ACTION_CHAT_ADD_MEMBERS = "添加成员";
export type ACTION_CHAT_ADD_MEMBERS = (uids: string[]) => Promise<void> export type ACTION_CHAT_ADD_MEMBERS = (uids: string[]) => Promise<void>;
export const ACTION_CHAT_REMOVE_MEMBER = "移除成员"; export const ACTION_CHAT_REMOVE_MEMBER = "移除成员";
export type ACTION_CHAT_REMOVE_MEMBER = (uids: string[]) => Promise<void> export type ACTION_CHAT_REMOVE_MEMBER = (uids: string[]) => Promise<void>;
export const ACTION_CHAT_ADD_CS = "添加客服"; export const ACTION_CHAT_ADD_CS = "添加客服";
export type ACTION_CHAT_ADD_CS = (uids: string[]) => Promise<void> export type ACTION_CHAT_ADD_CS = (uids: string[]) => Promise<void>;
export const ACTION_CHAT_START_RECEPTION = "开始接待"; export const ACTION_CHAT_START_RECEPTION = "开始接待";
export type ACTION_CHAT_START_RECEPTION = () => Promise<void> export type ACTION_CHAT_START_RECEPTION = () => Promise<void>;
export const ACTION_CHAT_FINISH_RECEPTION = "结束接待"; export const ACTION_CHAT_FINISH_RECEPTION = "结束接待";
export type ACTION_CHAT_FINISH_RECEPTION = () => Promise<void> export type ACTION_CHAT_FINISH_RECEPTION = () => Promise<void>;
export const ACTION_CHAT_REMOVE_CS = "移除客服"; export const ACTION_CHAT_REMOVE_CS = "移除客服";
export type ACTION_CHAT_REMOVE_CS = (uids: string[]) => Promise<void> export type ACTION_CHAT_REMOVE_CS = (uids: string[]) => Promise<void>;
export const ACTION_CHAT_USER_EXIT = "普通用户退出"; export const ACTION_CHAT_USER_EXIT = "普通用户退出";
export type ACTION_CHAT_USER_EXIT = () => Promise<void> export type ACTION_CHAT_USER_EXIT = () => Promise<void>;
export const ACTION_CHAT_CS_EXIT = "客服退出"; export const ACTION_CHAT_CS_EXIT = "客服退出";
export type ACTION_CHAT_CS_EXIT = () => Promise<void> export type ACTION_CHAT_CS_EXIT = () => Promise<void>;
} }
export interface ChatStoreState { export interface ChatStoreState {
...@@ -338,13 +355,13 @@ export interface ChatStoreState { ...@@ -338,13 +355,13 @@ export interface ChatStoreState {
[ChatStore.STATE_CURRENT_CHAT_INITING]: ChatStore.STATE_CURRENT_CHAT_INITING; [ChatStore.STATE_CURRENT_CHAT_INITING]: ChatStore.STATE_CURRENT_CHAT_INITING;
[ChatStore.STATE_MY_CHAT_ROOM_LIST]: ChatStore.STATE_MY_CHAT_ROOM_LIST; [ChatStore.STATE_MY_CHAT_ROOM_LIST]: ChatStore.STATE_MY_CHAT_ROOM_LIST;
[ChatStore.STATE_CHAT_DIALOG_VISIBLE]: ChatStore.STATE_CHAT_DIALOG_VISIBLE; [ChatStore.STATE_CHAT_DIALOG_VISIBLE]: ChatStore.STATE_CHAT_DIALOG_VISIBLE;
[ChatStore.STATE_CHAT_DIALOG_IS_SINGLE]: ChatStore.STATE_CHAT_DIALOG_IS_SINGLE [ChatStore.STATE_CHAT_DIALOG_IS_SINGLE]: ChatStore.STATE_CHAT_DIALOG_IS_SINGLE;
[ChatStore.STATE_SINGLE_CHAT]: ChatStore.STATE_SINGLE_CHAT [ChatStore.STATE_SINGLE_CHAT]: ChatStore.STATE_SINGLE_CHAT;
[ChatStore.STATE_CHAT_CURRENT_IS_CHAT_MEMBER]: ChatStore.STATE_CHAT_CURRENT_IS_CHAT_MEMBER [ChatStore.STATE_CHAT_CURRENT_IS_CHAT_MEMBER]: ChatStore.STATE_CHAT_CURRENT_IS_CHAT_MEMBER;
[ChatStore.STATE_CHAT_CURRENT_USER_UID]: ChatStore.STATE_CHAT_CURRENT_USER_UID [ChatStore.STATE_CHAT_CURRENT_USER_UID]: ChatStore.STATE_CHAT_CURRENT_USER_UID;
[ChatStore.STATE_CHAT_CURRENT_USER_TYPE]: ChatStore.STATE_CHAT_CURRENT_USER_TYPE [ChatStore.STATE_CHAT_CURRENT_USER_TYPE]: ChatStore.STATE_CHAT_CURRENT_USER_TYPE;
[ChatStore.STATE_CHAT_SEND_FAIL_MESSAGE]: ChatStore.STATE_CHAT_SEND_FAIL_MESSAGE [ChatStore.STATE_CHAT_SEND_FAIL_MESSAGE]: ChatStore.STATE_CHAT_SEND_FAIL_MESSAGE;
[ChatStore.STATE_CHAT_USERNAME]: ChatStore.STATE_CHAT_USERNAME [ChatStore.STATE_CHAT_USERNAME]: ChatStore.STATE_CHAT_USERNAME;
} }
export const chatStore = namespace(ChatStore.ns); export const chatStore = namespace(ChatStore.ns);
...@@ -35,8 +35,8 @@ class Chat { ...@@ -35,8 +35,8 @@ class Chat {
EmojiService.raiseOnReady(this.token); EmojiService.raiseOnReady(this.token);
option.sdk().events.addTokenChanged(token => { option.sdk().events.addTokenChanged((token) => {
this.setToken(() => new Promise(resolve => resolve(token))); this.setToken(() => new Promise((resolve) => resolve(token)));
}); });
return this.initChatSdk(option.webSocketUri); return this.initChatSdk(option.webSocketUri);
...@@ -49,7 +49,7 @@ class Chat { ...@@ -49,7 +49,7 @@ class Chat {
public getSdk = () => { public getSdk = () => {
if (this._sdk == null) { if (this._sdk == null) {
throw new Error("sdk shouldn't undefined"); throw new Error("sdk shouldn't undefined");
}; }
return this._sdk(); return this._sdk();
}; };
......
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