import {Message} from "element-ui";
import {lStorage} from "../../utils/storage";
import request from "@/utils/request.js";
import {getSimpleData} from "@/views/chat/chatdata.js";


const chatClient = {
    state: {
        sender: null,
        ws: null,
        currentActor: null,
        currentChatId: null,
        chats: {"unread": 0},
        chatOpen: false,
        chatState: "",
        chatEnter: false,
        onOpen: null,
        onTips: null,
        onActor: null,
        onChat: null,
        onChatOpen: null,
        dataCache: {},
    },
    mutations: {
        setSender(state, sender) {
            if (state.ws && state.ws.readyState == WebSocket.OPEN && state.sender && state.sender.id != sender.id) {
                state.ws.close();
                state.ws = null;
            }
            state.sender = sender;
            let cacheChats = getCacheChats();
            if (cacheChats) {
                state.chats = cacheChats;
            }
        },
        setCurrentActor(state, actor) {
            state.currentActor = actor;
        },
        setCurrentChatId(state, chatId) {
            state.currentChatId = chatId;
            if (chatId) {
                if (state.chats[chatId] && state.chats[chatId].unread) {
                    state.chats.unread = state.chats.unread - state.chats[chatId].unread;
                    state.chats[chatId].unread = 0;
                    setCacheChats(state.chats);
                }
                if (state.onChatOpen) {
                    state.onChatOpen(chatId);
                }
            }
        },
        openChat(state) {
            state.chatOpen = true;
        },
        setOnOpen(state, onOpen) {
            state.onOpen = onOpen;
        },
        setOnTips(state, onTips) {
            state.onTips = onTips;
        },
        setOnActor(state, onActor) {
            state.onActor = onActor;
        },
        setOnChat(state, onChat) {
            state.onChat = onChat;
        },
        setOnChatOpen(state, onChatOpen) {
            state.onChatOpen = onChatOpen
        },
        handleHistoryMessages(state, obj) {
            let {chatId, messages} = obj;
            if (messages && messages.length) {
                let initChat = false;
                if (!state.chats[chatId]) {
                    state.chats[chatId] = emptyChat(chatId);
                    initChat = true;
                }
                if (state.chats[chatId].messages.length === 0) {
                    for (let i = 0; i < messages.length; i++) {
                        this.commit("handleMessage", JSON.parse(messages[i]));
                    }
                    if (initChat && state.onChat) {
                        state.onChat(chatId);
                    }
                }
            }
        },
        handleMessage(state, mesObj) {
            const messageChatId = mesObj.chatId;
            const messageCommand = mesObj.command;
            const messageSenderId = mesObj.senderId;
            const messageSenderName = mesObj.senderName;
            if (messageCommand && messageChatId) {

                if (isMessageType(messageCommand)) {
                    if (messageCommand === commands.data) {
                        mesObj.message = JSON.parse(mesObj.message);
                        state.chats[messageChatId].data = mesObj.message;
                    } else if (messageCommand === commands.tips && state.onTips) {
                        state.onTips(mesObj);
                    } else if (messageCommand === commands.image) {
                        if (!state.chats[messageChatId].images) {
                            state.chats[messageChatId].images = []
                        }
                        state.chats[messageChatId].images.push(mesObj.message);
                    }

                    state.chats[messageChatId].messages.push(mesObj);

                    let needCache = false;
                    if (messageCommand !== commands.data && messageSenderName && messageSenderName.indexOf("[") !== -1) {
                        needCache = true;
                    }
                    if (state.chatOpen && messageChatId == state.currentChatId) {
                        if (state.chats[messageChatId].unread > 0) {
                            state.chats.unread = state.chats.unread - state.chats[messageChatId].unread;
                            needCache = true;
                        }
                        state.chats[messageChatId].unread = 0;
                        state.chats[messageChatId].lastMessageTime = mesObj.createTime;
                    } else if (needCache && mesObj.createTime > state.chats[messageChatId].lastMessageTime) {
                        state.chats[messageChatId].lastMessageTime = mesObj.createTime;
                        state.chats.unread++;
                        state.chats[messageChatId].unread++;
                    }

                    if (needCache) {
                        setCacheChats(state.chats);
                    }

                } else if (messageCommand === commands.actor) {
                    mesObj.message = JSON.parse(mesObj.message);
                    state.chats[messageChatId].actors[messageSenderId] = mesObj.message;
                    if (state.onActor) {
                        state.onActor(mesObj);
                    }
                } else if (messageCommand === commands.actors) {
                    mesObj.message = JSON.parse(mesObj.message);
                    let actors = mesObj.message;
                    if (actors && Object.keys(actors).length) {
                        for (let senderId in actors) {
                            state.chats[messageChatId].actors[senderId] = actors[senderId];
                        }
                    }
                } else if (messageCommand === commands.actor_status) {
                    if (state.chats[messageChatId].actors && state.chats[messageChatId].actors[messageSenderId]) {
                        state.chats[messageChatId].actors[messageSenderId].status = mesObj.message;
                    }
                } else {
                    console.warn("群聊消息指令未解释:" + JSON.stringify(mesObj));
                }
            } else {
                console.warn("群聊消息格式错误:" + JSON.stringify(mesObj));
            }
        },
        connect(state) {
            if (state.ws && state.ws.readyState == WebSocket.OPEN) {
                return;
            }
            if (!state.sender) {
                console.info("Not found the sender config [setSender]");
                return;
            }
            if (!state.currentActor) {
                console.info("Not found the currentActor [setCurrentActor]");
                return;
            }


            let sender = state.sender;

            let query = "id=" + sender.id;

            const wsProtocol = sender.ssl ? "wss://" : "ws://";

            let url = wsProtocol + sender.server + sender.path + "?" + query;

            state.ws = new WebSocket(url);
            state.ws.onmessage = async (event) => {
                state.chatState = "message";
                state.chatEnter = true;
                const mesObj = JSON.parse(event.data);
                if (mesObj && mesObj.chatId) {
                    let mesChatId = mesObj.chatId;
                    if (!state.chats[mesChatId]) {
                        state.chats[mesChatId] = emptyChat(mesChatId);
                        let lines = await getChatMessages(mesChatId);
                        if (lines && lines.length) {
                            for (let i = 0; i < lines.length; i++) {
                                this.commit("handleMessage", JSON.parse(lines[i]));
                            }
                        }
                        if (state.onChat) {
                            state.onChat(mesChatId);
                        }
                    }
                    this.commit("handleMessage", mesObj);
                }
            }
            state.ws.onopen = (event) => {
                state.chatState = "open";
                state.chatEnter = true;
                if (state.onOpen) {
                    state.onOpen();
                }
                Message({message: "群聊服务已连接", duration: 2000, type: "success"});
            }
            state.ws.onerror = (event) => {
                state.chatState = "error";
                state.chatEnter = false;
            }
            state.ws.onclose = (event) => {
                state.chatState = "close";
                state.chatEnter = false;
                Message({message: "群聊服务连接断开", duration: 1000, type: "error"});
            }
        },
        closeChatOpen(state) {
            state.chatOpen = false;
            state.currentChatId = null;
        },
        setChatState(state, chatState) {
            state.chatState = chatState;
        },
        setChatEnter(state, chatEnter) {
            state.chatEnter = chatEnter;
        },
        send(state, messageObj) {
            if (!state.ws) {
                console.error("Null Websocket")
                return false;
            }
            if (messageObj.needChat === undefined) {
                messageObj.needChat = true;
            }
            if (messageObj.needChat && !messageObj["chatId"] && state.currentChatId) {
                messageObj["chatId"] = state.currentChatId;
            }
            messageObj["senderId"] = state.sender.id;
            messageObj["senderName"] = state.sender.name;
            if (state.ws.readyState === WebSocket.OPEN) {
                state.chatState = "message";
                state.chatEnter = false;

                state.ws.send(JSON.stringify(messageObj));

                state.chatEnter = true;
                return true;
            } else if (state.ws.readyState == WebSocket.CONNECTING) {
                state.chatEnter = false;
                Message({message: "连接中", duration: 1000});
                return false;
            } else if (state.ws.readyState == WebSocket.CLOSING || state.ws.readyState == WebSocket.CLOSED) {
                Message("连接断开,重连中");
                state.chatEnter = false;
                state.chatState = "close";
                return false;
            }
        },
        readAll(state) {
            if (state.chats && Object.keys(state.chats).length > 0) {
                for (let key in state.chats) {
                    if (key != "unread") {
                        let len = state.chats[key].unread;
                        state.chats[key].unread = 0;
                        if (len > 0) {
                            state.chats.unread = state.chats.unread - state.chats[key].unread;
                        }
                    }
                }
                state.chats.unread = 0;
                setCacheChats(state.chats);
            }
        },
        setDataCache(state, data) {
            if (data && data.id) {
                state.dataCache[data.id] = data;
            }
        },
        close(state) {
            if (state.ws) {
                state.ws.close();
                state.ws = null;
            }
        }
    },
    actions: {
        setSender(context, sender) {
            return context.commit("setSender", sender);
        },
        setCurrentActor(context, actor) {
            return context.commit("setCurrentActor", actor);
        },
        setCurrentChatId(context, chatId) {
            return new Promise((resolve) => {
                if (!context.state.chats[chatId] || context.state.chats[chatId].messages.length === 0) {
                    getChatMessages(chatId).then((lines) => {
                        context.commit("handleHistoryMessages", {"chatId": chatId, "messages": lines});
                        context.commit("setCurrentChatId", chatId);
                        resolve(chatId);
                    });
                } else {
                    context.commit("setCurrentChatId", chatId);
                    resolve(chatId);
                }
            });
        },
        setChatOpen(context, chatId) {
            return new Promise((resolve) => {
                if (chatId) {
                    context.dispatch("setCurrentChatId", chatId).then(res => {
                        context.commit("openChat");
                        resolve(res);
                    });
                } else {
                    context.commit("openChat");
                    resolve(chatId);
                }
            })
        },
        setOnOpen(context, onOpen) {
            return context.commit("setOnOpen", onOpen);
        },
        setOnTips(context, onTips) {
            return context.commit("setOnTips", onTips);
        },
        setOnActor(context, onActor) {
            return context.commit("setOnActor", onActor);
        },
        setOnChat(context, onChat) {
            return context.commit("setOnChat", onChat);
        },
        setOnChatOpen(context, onChatOpen) {
            return context.commit("setOnChatOpen", onChatOpen);
        },
        connect(context) {
            return context.commit('connect');
        },
        closeChatOpen(context) {
            return context.commit('closeChatOpen');
        },
        send(context, messageObj) {
            messageObj.needChat = true;
            return context.commit("send", messageObj);
        },
        sendMessage(context, message) {
            return context.commit("send", {"message": message, "command": commands.message, "needChat": true})
        },
        sendImage(context, image) {
            return context.commit("send", {"message": image, "command": commands.image, "needChat": true})
        },
        sendFile(context, file) {
            return context.commit("send", {"message": file, "command": commands.file, "needChat": true})
        },
        sendData(context, data) {
            return context.commit("send", {"message": data, "command": commands.data, "needChat": true})
        },
        sendTips(context, tips) {
            return context.commit("send", {"message": tips, "command": commands.tips, "needChat": true})
        },
        sendActor(context, chatId) {
            return context.commit("send", {
                "message": context.state.currentActor,
                "command": commands.actor,
                "chatId": chatId,
                "needChat": false
            })
        },
        sendActors(context, obj) {
            return context.commit("send", {
                "message": obj.actorIds,
                "command": commands.actors,
                "chatId": obj.chatId,
                "needChat": false
            })
        },
        sendChatRole(context, chatRole) {
            return context.commit("send", {"message": chatRole, "command": commands.chat_role, "needChat": true});
        },
        sendChatClass(context, chatRole) {
            return context.commit("send", {"message": chatRole, "command": commands.chat_class, "needChat": true});
        },
        sendActorStatus(context, status) {
            return context.commit("send", {"message": status, "command": commands.actor_status, "needChat": false});
        },
        initChatHistory(context, chatId) {
            return new Promise((resolve) => {
                getChatMessages(chatId).then((lines) => {
                    context.commit("handleHistoryMessages", {"chatId": chatId, "messages": lines});
                    resolve(chatId);
                });
            });
        },
        initSenderHistory(context, senderId) {
            Message({message: "【群聊】加载历史消息中", duration: 2000, type: "info"});
            return new Promise((resolve) => {
                getListChats(senderId).then(async (chatIds) => {
                    if (chatIds && chatIds.length) {
                        for (let i = 0; i < chatIds.length; i++) {
                            await context.dispatch("initChatHistory", chatIds[i]);
                        }
                    }
                    Message({message: "【群聊】加载历史消息完成", duration: 2000, type: "success"});
                    resolve(senderId);
                });
            });
        },
        readAll(context) {
            return context.commit("readAll");
        },
        getChatData(context, chatId) {
            let data;
            if (context.state.chats[chatId] && context.state.chats[chatId].data) {
                data = context.state.chats[chatId].data;
            } else if (context.state.dataCache[chatId]) {
                data = context.state.dataCache[chatId];
            }
            return new Promise((resolve) => {
                if (!data) {
                    getSimpleData(chatId).then((dataRes) => {
                        if (dataRes.data) {
                            context.commit("setDataCache", dataRes.data);
                            data = dataRes.data;
                        }
                        resolve(data);
                    });
                } else {
                    resolve(data);
                }
            })
        },
        closeChatClient(context) {
            context.commit("close");
        }
    }
}

export function checkChat(senderId) {
    return new Promise((resolve) => {
        request({
            url: "/chat/check/" + senderId,
            method: "get"
        }).then((res) => {
            let result;
            if (res.data) {
                result = res.data;
            } else {
                result = res;
            }
            if ("exists" === result) {
                resolve(false);
            } else {
                resolve(true);
            }
        })
    });
}

export function getListChats(senderId) {
    return new Promise((resolve) => {
        request({
            url: '/chat/get/list/' + senderId,
            method: 'get'
        }).then((chatRes) => {
            let chatIds;
            if (Array.isArray(chatRes)) {
                chatIds = chatRes;
            } else if (chatRes.data) {
                chatIds = JSON.parse(chatRes.data);
            }
            resolve(chatIds);
        });
    });
}

export function getChatMessages(chatId) {
    return new Promise((resolve) => {
        request({
            url: '/chat/get/messages/' + chatId,
            method: 'get'
        }).then((messRes) => {
            let lines;
            if (Array.isArray(messRes)) {
                lines = messRes;
            } else if (messRes.data) {
                lines = JSON.parse(messRes.data);
            }
            resolve(lines);
        });
    });
}

export function isMessageType(command) {
    return !command.startsWith("_");
}


export const getCacheChats = () => {
    return lStorage.get("chat_kf_cache_chats");
}


export const setCacheChats = (chats) => {
    if (chats && Object.keys(chats).length > 0) {
        let cacheChats = {}
        for (let key in chats) {
            if (key === "unread") {
                cacheChats[key] = chats[key]
            } else {
                cacheChats[key] = {...chats[key]};
                cacheChats[key]["messages"] = [];
                cacheChats[key]["actors"] = {};
                cacheChats[key]["images"] = [];
                if (chats[key].data) {
                    let data = chats[key].data;
                    cacheChats[key]["data"] = {
                        "id": data.id,
                        "gameId": data.gameId,
                        "sellAccount": data.sellAccount,
                        "fullName": data.fullName,
                        "subarea": data.subarea,
                        "subregion": data.subregion
                    };
                }
            }
        }
        lStorage.set("chat_kf_cache_chats", cacheChats);
    }
}

export const emptyChat = (chatId) => {
    return {
        "id": chatId,
        "name": null,
        "kfId": null,
        "adminId": null,
        "status": null,
        "messages": [],
        "actors": {},
        "data": null,
        "images": [],
        "unread": 0,
        "lastMessageTime": 0,
        "createTime": Date.now(),
    };
}

export const commands = {
    message: "message",
    image: "image",
    file: "file",
    data: "data",
    tips: "tips",
    actor: "_actor",
    actors: "_actors",
    actor_quit: "_actor_quit",
    actor_status: "_actor_status",
    chat_role: "_chat_role",
    chat_class: "_chat_class"
}

export default chatClient;

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐