diff --git a/package.json b/package.json index 2b9b52d39..1c4f6930c 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,6 @@ "element-plus": "2.11.1", "fast-xml-parser": "^4.3.2", "highlight.js": "^11.9.0", - "idb": "^8.0.0", "jsencrypt": "^3.3.2", "jsoneditor": "^10.1.3", "localforage": "^1.10.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c67815019..84cf5b973 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -86,9 +86,6 @@ importers: highlight.js: specifier: ^11.9.0 version: 11.10.0 - idb: - specifier: ^8.0.0 - version: 8.0.3 jsencrypt: specifier: ^3.3.2 version: 3.3.2 @@ -3504,9 +3501,6 @@ packages: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} - idb@8.0.3: - resolution: {integrity: sha512-LtwtVyVYO5BqRvcsKuB2iUMnHwPVByPCXFXOpuU96IZPPoPN6xjOGxZQ74pgSVVLQWtUOYgyeL4GE98BY5D3wg==, tarball: https://registry.npmmirror.com/idb/-/idb-8.0.3.tgz} - ids@1.0.5: resolution: {integrity: sha512-XQ0yom/4KWTL29sLG+tyuycy7UmeaM/79GRtSJq6IG9cJGIPeBz5kwDCguie3TwxaMNIc3WtPi0cTa1XYHicpw==} @@ -8903,8 +8897,6 @@ snapshots: dependencies: safer-buffer: 2.1.2 - idb@8.0.3: {} - ids@1.0.5: {} ignore@5.3.2: {} diff --git a/src/store/indexedDB.ts b/src/store/indexedDB.ts deleted file mode 100644 index 93f1ef3d8..000000000 --- a/src/store/indexedDB.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { CACHE_KEY, useCache } from '@/hooks/web/useCache' -import { ConversationModelType } from '@/views/chat/types/types' -import { openDB, DBSchema, IDBPDatabase } from 'idb' - -// Define your database schema -interface MyDB extends DBSchema { - Conversations: { - key: string - value: ConversationModelType - } -} - -let dbPromise: Promise> - -export const initDB = () => { - if (!dbPromise) { - try { - const { wsCache } = useCache() - const user = wsCache.get(CACHE_KEY.USER).user - dbPromise = openDB('yudao-im-indexeddb-' + user.id, 1, { - upgrade(db) { - db.createObjectStore('Conversations', { keyPath: 'conversationNo' }) - } - }) - } catch (error) { - console.log(error) - } - } - return dbPromise -} - -export const addConversation = async (conversation: ConversationModelType) => { - - try { - const db = await initDB() - await db.put('Conversations', conversation) - } catch (error) { - console.error(conversation) - console.error(error) - } - -} - -export const getConversation = async (conversationNo: string) => { - - try { - const db = await initDB() - return await db.get('Conversations', conversationNo) - } catch (error) { - console.error(error) - } - -} - -export const deleteConversation = async (conversationNo: string) => { - - try { - const db = await initDB() - await db.delete('Conversations', conversationNo) - } catch (error) { - console.error(error) - } - -} - -export const getAllConversations = async () => { - - try { - const db = await initDB() - return await db.getAll('Conversations') - } catch (error) { - console.log(error) - } - -} diff --git a/src/views/chat/ChatPage/Index.vue b/src/views/chat/ChatPage/Index.vue deleted file mode 100644 index 98ac2b4f0..000000000 --- a/src/views/chat/ChatPage/Index.vue +++ /dev/null @@ -1,57 +0,0 @@ - - - diff --git a/src/views/chat/api/messageApi.ts b/src/views/chat/api/messageApi.ts deleted file mode 100644 index 5a1290fa2..000000000 --- a/src/views/chat/api/messageApi.ts +++ /dev/null @@ -1,59 +0,0 @@ -/* - * @Author: dylan.may@qq.com - * @Date: 2024-10-16 11:30:31 - * @Last Modified by: dylan.may@qq.com - * @Last Modified time: 2024-10-16 16:01:25 - */ - -import request from '@/config/axios' -import { MessageModelType } from '../types/types' - -export interface SendMsg { - clientMessageId: string - receiverId: number - conversationType: number - contentType: number - content: string -} - -export interface SessionMsgReq { - sendTime: string - receiverId: number - userId: number - conversationType: number -} - -/** - * 消息接口 - */ -export default class MessageApi { - /** - * 发送消息 - * @param data SendMsg - * @returns Promise<{ id: number; sendTime: number }> - */ - static send(data: SendMsg): Promise<{ id: number; sendTime: number }> { - return request.post({ url: '/im/message/send', data }) - } - - /** - * 获取会话消息 - * @param data SessionMsgReq - * @returns Promise> - */ - static getSessionMsg(params: SessionMsgReq): Promise> { - return request.get({ url: '/im/message/list', params }) - } - - /** - * 获取所有消息 - * @param data { sequence: number; size: number } - * @returns Promise> - */ - static getMessageForAllSession(params: { - sequence: number - size: number - }): Promise> { - return request.get({ url: '/im/message/pull', params }) - } -} diff --git a/src/views/chat/api/sessionApi.ts b/src/views/chat/api/sessionApi.ts deleted file mode 100644 index 8f5fd02e7..000000000 --- a/src/views/chat/api/sessionApi.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * @Author: dylan.may@qq.com - * @Date: 2024-10-16 11:30:31 - * @Last Modified by: dylan.may@qq.com - * @Last Modified time: 2024-11-28 17:32:26 - */ - -import request from '@/config/axios' -import { ChatConversation } from '../model/ChatConversation' - -interface createConversationParam { - targetId: string, - type: number -} - -/** - * 会话接口 - */ -export default class SessionApi { - /** - * 获取会话列表 - * @returns Promise> - */ - static getSessionList(): Promise> { - return request.get({ url: '/im/conversation/list' }) - } - - - /** - * 创建会话 - * @param data createConversationParam - * @returns Promise - */ - static createConversation(data: createConversationParam):Promise { - return request.post({ - url: '/im/conversation/create', - data - }) - } -} diff --git a/src/views/chat/components/ChatHeader/Index.vue b/src/views/chat/components/ChatHeader/Index.vue deleted file mode 100644 index a1593c1f2..000000000 --- a/src/views/chat/components/ChatHeader/Index.vue +++ /dev/null @@ -1,18 +0,0 @@ - - - diff --git a/src/views/chat/components/ChatMessage/Index.vue b/src/views/chat/components/ChatMessage/Index.vue deleted file mode 100644 index b972b03f6..000000000 --- a/src/views/chat/components/ChatMessage/Index.vue +++ /dev/null @@ -1,60 +0,0 @@ - - - diff --git a/src/views/chat/components/Conversation/index.vue b/src/views/chat/components/Conversation/index.vue deleted file mode 100644 index 9bb7a2b16..000000000 --- a/src/views/chat/components/Conversation/index.vue +++ /dev/null @@ -1,37 +0,0 @@ - - - diff --git a/src/views/chat/components/ConversationItem/index.vue b/src/views/chat/components/ConversationItem/index.vue deleted file mode 100644 index afebde76a..000000000 --- a/src/views/chat/components/ConversationItem/index.vue +++ /dev/null @@ -1,85 +0,0 @@ - - - - - diff --git a/src/views/chat/components/Department/components/TreeNode.vue b/src/views/chat/components/Department/components/TreeNode.vue deleted file mode 100644 index a47d9f3fa..000000000 --- a/src/views/chat/components/Department/components/TreeNode.vue +++ /dev/null @@ -1,53 +0,0 @@ - - - - - diff --git a/src/views/chat/components/Department/components/TreeView.vue b/src/views/chat/components/Department/components/TreeView.vue deleted file mode 100644 index b1ca9eb1d..000000000 --- a/src/views/chat/components/Department/components/TreeView.vue +++ /dev/null @@ -1,28 +0,0 @@ - - - - - diff --git a/src/views/chat/components/Department/index.vue b/src/views/chat/components/Department/index.vue deleted file mode 100644 index 703a9e3ce..000000000 --- a/src/views/chat/components/Department/index.vue +++ /dev/null @@ -1,63 +0,0 @@ - - - diff --git a/src/views/chat/components/FriendDetail/Index.vue b/src/views/chat/components/FriendDetail/Index.vue deleted file mode 100644 index 766184eaa..000000000 --- a/src/views/chat/components/FriendDetail/Index.vue +++ /dev/null @@ -1,41 +0,0 @@ - - - diff --git a/src/views/chat/components/FriendItem/Index.vue b/src/views/chat/components/FriendItem/Index.vue deleted file mode 100644 index 03719b39e..000000000 --- a/src/views/chat/components/FriendItem/Index.vue +++ /dev/null @@ -1,32 +0,0 @@ - - - diff --git a/src/views/chat/components/Friends/Index.vue b/src/views/chat/components/Friends/Index.vue deleted file mode 100644 index d0514d28d..000000000 --- a/src/views/chat/components/Friends/Index.vue +++ /dev/null @@ -1,36 +0,0 @@ - - - diff --git a/src/views/chat/components/InputSection/Index.vue b/src/views/chat/components/InputSection/Index.vue deleted file mode 100644 index 03c25a8c9..000000000 --- a/src/views/chat/components/InputSection/Index.vue +++ /dev/null @@ -1,73 +0,0 @@ - - - diff --git a/src/views/chat/components/Message/BaseMsg.vue b/src/views/chat/components/Message/BaseMsg.vue deleted file mode 100644 index b08fc8170..000000000 --- a/src/views/chat/components/Message/BaseMsg.vue +++ /dev/null @@ -1,32 +0,0 @@ - - - diff --git a/src/views/chat/components/Message/ImageMsg.vue b/src/views/chat/components/Message/ImageMsg.vue deleted file mode 100644 index 487c076c4..000000000 --- a/src/views/chat/components/Message/ImageMsg.vue +++ /dev/null @@ -1,28 +0,0 @@ - - - diff --git a/src/views/chat/components/Message/TextMsg.vue b/src/views/chat/components/Message/TextMsg.vue deleted file mode 100644 index dd73998d1..000000000 --- a/src/views/chat/components/Message/TextMsg.vue +++ /dev/null @@ -1,24 +0,0 @@ - - - diff --git a/src/views/chat/components/ToolSection/Index.vue b/src/views/chat/components/ToolSection/Index.vue deleted file mode 100644 index 5eb5afcd1..000000000 --- a/src/views/chat/components/ToolSection/Index.vue +++ /dev/null @@ -1,49 +0,0 @@ - - - diff --git a/src/views/chat/model/BaseConversation.ts b/src/views/chat/model/BaseConversation.ts deleted file mode 100644 index aaf8b0616..000000000 --- a/src/views/chat/model/BaseConversation.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { ConversationType, MessageModelType } from '../types/types' - -export default class BaseConversation { - public id: string - public avatar: string - public name: string - public description: string - public createTime: number - public updateTime: number - public unreadMessagesCount: number - public msgList: Array - public type: ConversationType - public targetId: number - public senderId: number - public conversationNo: string - public lastMessageDescription: string - - constructor( - id: string, - avatar: string, - name: string, - lastMessageDescription: string, - createTime: number, - updateTime: number, - unreadMessagesCount: number, - msgList: Array, - type: ConversationType, - targetId: number, - senderId: number, - conversationNo: string - ) { - this.id = id - this.avatar = avatar - this.name = name - this.lastMessageDescription = lastMessageDescription - this.createTime = createTime - this.updateTime = updateTime - this.unreadMessagesCount = unreadMessagesCount - this.msgList = msgList - this.type = type - this.targetId = targetId - this.senderId = senderId - this.conversationNo = conversationNo - } -} diff --git a/src/views/chat/model/BaseMessage.ts b/src/views/chat/model/BaseMessage.ts deleted file mode 100644 index 0333af092..000000000 --- a/src/views/chat/model/BaseMessage.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { MessageRole, ContentType, SendStatus } from '../types/types' - -export default class BaseMessage { - id?: string - avatar?: string - nickname?: string - createTime: number - isRead: boolean - role: MessageRole - sendStatus: SendStatus - contentType: ContentType - conversationId: string - clientMessageId: string - senderId: number - receiverId: number - conversationType: number - conversationUserId: number - constructor( - id: string, - avatar: string, - nickname: string, - createTime: number, - isRead: boolean, - role: MessageRole, - sendStauts: SendStatus, - contentType: ContentType, - conversationId: string, - senderId: number, - receiverId: number, - conversationType: number, - conversationUserId: number - ) { - this.id = id - this.avatar = avatar - this.nickname = nickname - this.createTime = createTime - this.isRead = isRead - this.role = role - this.sendStatus = sendStauts - this.contentType = contentType - this.conversationId = conversationId - this.senderId = senderId - this.receiverId = receiverId - this.clientMessageId = this.generateClientMessageId() - this.conversationType = conversationType - this.conversationUserId = conversationUserId - } - - private generateClientMessageId() { - const timestamp = Date.now().toString() // 获取当前时间戳 - const randomPart = 'xxxx-xxxx-4xxx-yxxx-xxxx'.replace(/[xy]/g, function (c) { - const r = (Math.random() * 16) | 0, - v = c === 'x' ? r : (r & 0x3) | 0x8 - return v.toString(16) - }) - - return `${timestamp}-${randomPart}` - } -} diff --git a/src/views/chat/model/BaseResponse.ts b/src/views/chat/model/BaseResponse.ts deleted file mode 100644 index e49592653..000000000 --- a/src/views/chat/model/BaseResponse.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface BaseResponse { - code: number // 0表示成功其他表示失败 - message: string // 返回的信息,可以是成功或错误信息 - data: T // 泛型数据,成功时返回数据,失败时为 null -} diff --git a/src/views/chat/model/ChatConversation.ts b/src/views/chat/model/ChatConversation.ts deleted file mode 100644 index c931bdbe2..000000000 --- a/src/views/chat/model/ChatConversation.ts +++ /dev/null @@ -1,36 +0,0 @@ -import BaseConversation from './BaseConversation' -import BaseMessage from './BaseMessage' - -// TODO @dylan:这些 ts 类,是不是可以搞个 types.ts,然后放到 api/im 目录下?放在一个文件里 - -export class ChatConversation extends BaseConversation { - constructor( - id: string, - avatar: string, - name: string, - lastMessageDescription: string, - createTime: number, - updateTime: number, - unreadMessagesCount: number, - msgList: Array, - type: number, - targetId: number, - senderId: number, - conversationNo: string - ) { - super( - id, - avatar, - name, - lastMessageDescription, - createTime, - updateTime, - unreadMessagesCount, - msgList, - type, - targetId, - senderId, - conversationNo - ) - } -} diff --git a/src/views/chat/model/Friend.ts b/src/views/chat/model/Friend.ts deleted file mode 100644 index bb102a935..000000000 --- a/src/views/chat/model/Friend.ts +++ /dev/null @@ -1,19 +0,0 @@ -export default class Friend { - public id: string - public avatar: string - public name: string - public description: string - public createTime: number - public deptId: number - public deptName: string - - constructor(id, avatar, name, description, createTime, deptId, deptName) { - this.id = id - this.avatar = avatar - this.name = name - this.description = description - this.createTime = createTime - this.deptId = deptId - this.deptName = deptName - } -} diff --git a/src/views/chat/model/ImageMessage.ts b/src/views/chat/model/ImageMessage.ts deleted file mode 100644 index efe665d4f..000000000 --- a/src/views/chat/model/ImageMessage.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { MessageRole, ContentType, SendStatus } from '@/views/chat/types/types' -import BaseMessage from './BaseMessage' - -export default class ImageMessage extends BaseMessage { - content: string - - constructor( - id: string, - avatar: string, - nickname: string, - createTime: number, - isRead: boolean, - content: string, - role: MessageRole, - sendStatus: SendStatus, - conversationId: string, - receiverId: number, - conversationType: number, - conversationUserId: number - ) { - super( - id, - avatar, - nickname, - createTime, - isRead, - role, - sendStatus, - ContentType.IMAGE, - conversationId, - receiverId, - conversationType, - conversationUserId - ) - this.content = content - } -} diff --git a/src/views/chat/model/TextMessage.ts b/src/views/chat/model/TextMessage.ts deleted file mode 100644 index 2bd8d5da2..000000000 --- a/src/views/chat/model/TextMessage.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { MessageRole, ContentType, SendStatus, ImMessageContent } from '@/views/chat/types/types' -import BaseMessage from './BaseMessage' - -export default class TextMessage extends BaseMessage { - content: string - - constructor( - id: string, - avatar: string, - nickname: string, - createTime: number, - isRead: boolean, - content: string, - role: MessageRole, - sendStatus: SendStatus, - conversationId: string, - senderId: number, - receiverId: number, - conversationType: number, - conversationUserId: number - ) { - super( - id, - avatar, - nickname, - createTime, - isRead, - role, - sendStatus, - ContentType.TEXT, - conversationId, - senderId, - receiverId, - conversationType, - conversationUserId - ) - this.content = content - } - - /** - * 消息转换 - * @param websocketMessage - * @returns - */ - static fromWebsocket(websocketMessage: ImMessageContent): TextMessage { - return new TextMessage( - websocketMessage.id.toString(), // 服务端也应该返回一个clientMessageId - websocketMessage.senderAvatar, - websocketMessage.senderNickname, - new Date().getTime(), // TODO: 是否合理 - false, - websocketMessage.content, - MessageRole.OTHER, // 可以去掉在使用的时候依据逻辑判断 - SendStatus.SUCCESS, - '', // TODO: [dylan] - websocketMessage.senderId, - websocketMessage.receiverId, - websocketMessage.conversationType, - 0 - ) - } -} diff --git a/src/views/chat/store/chatstore.ts b/src/views/chat/store/chatstore.ts deleted file mode 100644 index 6dac27a7c..000000000 --- a/src/views/chat/store/chatstore.ts +++ /dev/null @@ -1,335 +0,0 @@ -import { store } from '@/store/index' -import { defineStore } from 'pinia' -import BaseConversation from '../model/BaseConversation' -import BaseMessage from '../model/BaseMessage' -import { ConversationModelType, MessageRole, ContentType, SendStatus, MENU_LIST_ENUM, CONVERSATION_TYPE } from '../types/types' -import SessionApi from '../api/sessionApi' -import MessageApi, { SendMsg } from '../api/messageApi' -import { useUserStore, useUserStoreWithOut } from '@/store/modules/user' -import { formatDate } from '@/utils/formatTime' -import { addConversation, getAllConversations } from '@/store/indexedDB' -import { ChatConversation } from '../model/ChatConversation' -import { generateConversationNo } from './websocketStore' - -// TODO @dylan:是不是 chat => im;session => conversation;这样统一一点哈。 -interface ChatStoreModel { - sessionList: Array - currentSession: ConversationModelType | null - currentSessionIndex: number - inputText: string, - bussinessType: number // conversation 1, friends 2 -} - -export const useChatStore = defineStore('chatStore', { - state: (): ChatStoreModel => ({ - sessionList: [], - currentSession: null, - currentSessionIndex: 0, - inputText: '', - bussinessType: 1, - }), - - getters: { - getSessionList(state: ChatStoreModel): Array { - return state.sessionList - }, - - getCurrentSession(state: ChatStoreModel): ConversationModelType | null { - return state.currentSession - }, - - getCurrentSessionIndex(state: ChatStoreModel): number { - return state.currentSessionIndex - } - }, - - actions: { - addSession(session: BaseConversation) { - this.sessionList.push(session) - }, - - setCurrentConversation() { - this.currentSession = this.sessionList[this.currentSessionIndex] - this.fetchSessionMsg() - }, - - setCurrentSessionIndex(index: number) { - this.currentSessionIndex = index - }, - - setInputText(content: string) { - this.inputText = content - }, - - setBussinessType(type: number) { - this.bussinessType = type - }, - - async addMessageToCurrentSession(message: T): Promise { - this.currentSession?.msgList.push(message) - - try { - const res = await MessageApi.send(message as unknown as SendMsg) - console.log(res) - if (res.id) { - // 更新发送状态 - const updateMsg = { - ...message, - id: res.id, - sendTime: res.sendTime, - sendStatus: SendStatus.SUCCESS - } - - this.updateMsgToCurrentSession(updateMsg) - } - } catch (error) { - console.log(error) - const updateMsg = { - ...message, - sendStatus: SendStatus.SUCCESS - } - - this.updateMsgToCurrentSession(updateMsg) - } finally { - this.setInputText('') - } - }, - - addMessageToSesstion(message: T): void { - // get the conversation from list - const conversationIndex = this.sessionList.findIndex((item) => { - return item.id === message.conversationId - }) - - const msgConversation = this.sessionList[conversationIndex] - - // add the message - msgConversation?.msgList.push(message) - - // replace the old Conversation - this.sessionList.splice(conversationIndex, 1, msgConversation) - }, - - /** - * 添加消息到会话 - * @param message - */ - addMessageToConversation(message: T): void { - - const converstionNo = generateConversationNo( - message.senderId, - message.receiverId, - message.conversationType - ) - - const conversationIndex = this.sessionList.findIndex( - (item) => item.conversationNo === converstionNo - ) - - if (conversationIndex < 0) { - console.log('conversation not exist, create it') - // Todo - return - } - - const msgConversation = this.sessionList[conversationIndex] - msgConversation.msgList.push(message) - - // replace the old Conversation - this.sessionList.splice(conversationIndex, 1, msgConversation) - - // 更新消息到indexeddb - addConversation(toRaw(msgConversation) as ChatConversation ) - - // 更新当前会话 - if (conversationIndex === this.currentSessionIndex) { - this.setCurrentConversation() - } - }, - - /** - * 根据消息创建会话 - * @param BaseMessage - * @param msg - */ - createConversation(BaseMessage: msg) { - - }, - - /** - * 生成会话No - * @param id1 - * @param id2 - * @param conversationType - * @returns - */ - generateConversationNo(id1: string, id2: string, conversationType: CONVERSATION_TYPE): string { - const SINGLE_PREFIX = 's_' - const GROUP_PREFIX = 'g_' - const [smallId, largeId] = id1 < id2 ? [id1, id2] : [id2, id1]; - - if (conversationType === CONVERSATION_TYPE.SINGLE) { - return SINGLE_PREFIX + smallId + "_" + largeId - } else if (conversationType === CONVERSATION_TYPE.GROUP) { - return GROUP_PREFIX + smallId + "_" + largeId - } - - return '' - }, - - /** - * 更新消息到当前会话 - * @param updatedMsg - */ - updateMsgToCurrentSession(updatedMsg: T): void { - if (this.currentSession) { - this.currentSession.msgList = this.currentSession?.msgList.map((item) => { - if (item.clientMessageId === updatedMsg.clientMessageId) { - return updatedMsg - } else { - return item - } - }) - - const rawCurrentSesstion = toRaw(this.currentSession) - rawCurrentSesstion.msgList =this.currentSession.msgList.map(item => toRaw(item)) - console.log("raw", rawCurrentSesstion) - addConversation(rawCurrentSesstion as ChatConversation) - } - }, - - async getConversationList() { - try { - // 从数据库获取数据 - const _conversationList = await getAllConversations() - - if (_conversationList) { - // 加载到内存 - // TODO:[dylan]处理排序 - this.sessionList = _conversationList - } - } catch (error) { - console.log(error) - } finally{ - - // 本地没有数据的时候才请求接口 - if (this.sessionList.length === 0) { - this.getSessionFromServer() - } - } - }, - - async getSessionFromServer() { - try { - const res = await SessionApi.getSessionList() - - this.sessionList = res.map((item) => ({ - ...item, - updateTime: item.lastReadTime, - name: item.targetId, - targetId: item.targetId, - senderId: item.userId, - conversationNo: item.no, - unreadMessagesCount: item.unreadMessagesCount, - description: item.lastMessageDescription, - msgList: [] - })) - - // 同步到数据库 - this.sessionList.forEach((item) => { - console.log(item) - addConversation(toRaw(item) as ChatConversation) - }) - } catch (error) { - return error - } - }, - - async fetchSessionMsg() { - if (!this.currentSession) { - return - } - - const userStore = useUserStoreWithOut() - - try { - const res = await MessageApi.getSessionMsg({ - receiverId: this.currentSession.targetId, - userId: this.currentSession.senderId, - // sendTime: formatDate(new Date(), 'YYYY-MM-DD HH:mm:ss') - conversationType: this.currentSession.type - }) - - this.currentSession.msgList = res.map((item) => { - return { - ...item, - role: item.senderId === userStore.user.id ? MessageRole.SELF : MessageRole.OTHER, - nickname: item.senderNickname, - avatar: item.senderAvatar - } - }) - - addConversation(toRaw(this.currentSession) as ChatConversation) - } catch (error) { - return error - } - }, - - - /** - * 创建会话 - */ - async createConversation(targetId, type, avatar, nickname) { - try { - const param = { - targetId, - type - } - const res = await SessionApi.createConversation(param) - if (res) { - - // 切换到聊天模式 - this.bussinessType = MENU_LIST_ENUM.CONVERSATION - - // 插入用户名和昵称 - res.avatar = avatar; - res.nickname = nickname; - const localConversation = this.convertCoversationFromServer(res) - // 存入到数据库 - addConversation(toRaw(localConversation) as ChatConversation) - // 从数据库同步到内存 - await this.getConversationList() - // 设置当前的会话 - const addIndex = this.sessionList.findIndex(item => item.conversationNo === localConversation.conversationNo) - this.setCurrentSessionIndex(addIndex) - this.setCurrentConversation() - - } - - } catch (error) { - console.log(error) - } - }, - - convertCoversationFromServer(item: any) { - return { - ...item, - updateTime: item.updateTime, - targetId: item.targetId, - senderId: item.userId, - conversationNo: item.no, - unreadMessagesCount: item.unreadMessagesCount, - description: item.lastMessageDescription, - avatar: item.avatar, - name: item.name, - msgList: [] - } - } - - - } -}) - -export const useChatStoreWithOut = () => { - return useChatStore(store) -} diff --git a/src/views/chat/store/friendstore.ts b/src/views/chat/store/friendstore.ts deleted file mode 100644 index 3f14fad17..000000000 --- a/src/views/chat/store/friendstore.ts +++ /dev/null @@ -1,113 +0,0 @@ -import { defineStore } from 'pinia' -import { store } from '@/store/index' -import BaseConversation from '../model/BaseConversation' -import Friend from '../model/Friend' -import { getAllUser, getDeptUser } from '@/api/system/user' -import * as DeptApi from '@/api/system/dept' - -interface FriendStoreModel { - friendList: Array - currentFriend: Friend | null, - selectedDepartmentId: number, - departmentList: DeptApi.DeptVO[] -} - -export const useFriendStore = defineStore('friendStore', { - state: (): FriendStoreModel => ({ - friendList: [], - currentFriend: null, - selectedDepartmentId: 0, - departmentList: [] - }), - - getters: { - getFriendList(state: FriendStoreModel): Array { - return state.friendList - } - }, - - actions: { - addFriend(session: BaseConversation) { - this.friendList.push(session) - }, - setCurrentFriend(friend: Friend) { - this.currentFriend = friend - }, - setCurrentDepartmentId(id: number) { - this.selectedDepartmentId = id - }, - resetFriendList() { - this.friendList = [] - this.currentFriend = null - }, - async fetchDepartment () { - try { - const result = await DeptApi.getSimpleDeptList() - this.departmentList = this.buildHierarchy(result) - } catch (e) { - console.log(e) - } - }, - - async fetchFriend() { - - try { - const res = await getAllUser() - this.friendList = res - - } catch (error) { - console.error(error) - } - }, - - async fetchDeptUser(id) { - - try { - const res = await getDeptUser(id) - if (res) { - this.friendList = res.map(item => { - return { - ...item, - name: item.nickname - } - }) - } else { - this.friendList = [] - } - - - } catch (error) { - console.error(error) - } - }, - - buildHierarchy(data: DeptApi.DeptVO[]): DeptApi.DeptVO[] { - const map = new Map(); - - // 初始化 map,确保每个 id 都有一条记录 - data.forEach(item => map.set(item.id, { ...item, children: [] })); - - const result: DeptApi.DeptVO[] = []; - - data.forEach(item => { - if (item.parentId === 0) { - // 根节点 - result.push(map.get(item.id)!); - } else { - // 子节点,放入父节点的 children 数组 - const parent = map.get(item.parentId); - if (parent) { - parent.children!.push(map.get(item.id)!); - } - } - }); - - return result; - } - } -}) - - -export const useFriendStoreWithOut = () => { - return useFriendStore(store) -} \ No newline at end of file diff --git a/src/views/chat/store/websocketStore.ts b/src/views/chat/store/websocketStore.ts deleted file mode 100644 index 09daa8a42..000000000 --- a/src/views/chat/store/websocketStore.ts +++ /dev/null @@ -1,207 +0,0 @@ -import { defineStore } from 'pinia' -import { ref, onUnmounted } from 'vue' -import { getRefreshToken } from '@/utils/auth' -import { useChatStore } from './chatstore' -import { - ContentType, - ImMessageContent, - ImMessageReceiveResponse, - WEBSOCKET_MESSAGE_TYPE_ENUM -} from '../types/types' -import TextMessage from '../model/TextMessage' -import { debug } from 'console' -import { useUserStore } from '@/store/modules/user' -import BaseConversation from '../model/BaseConversation' - -interface Message { - type: string - data: any -} - -enum ImConversationTypeEnum { - SINGLE = 1, - GROUP = 2 - // Add other conversation types if needed -} - -export function generateConversationNo( - fromUserId: number, - receiverId: number, - conversationType: number -): string | null { - if (conversationType === ImConversationTypeEnum.SINGLE) { - return `s_${fromUserId}_${receiverId}` - } else if (conversationType === ImConversationTypeEnum.GROUP) { - return `g_${receiverId}` - } - return null -} - -export const useWebSocketStore = defineStore('webSocket', () => { - const socket = ref(null) - const messages = ref([]) - const isConnected = ref(false) - let reconnectTimer: ReturnType | null = null - let heartbeatTimer: ReturnType | null = null - - // 初始化 WebSocket 连接 - function connect() { - const refreshToken = getRefreshToken() - - // 设置 WebSocket URL - if (refreshToken) { - console.log('refreshToken null') - } - - const url = `ws://localhost:48080/infra/ws?token=${refreshToken}` - socket.value = new WebSocket(url) - - socket.value.onopen = () => { - isConnected.value = true - console.log('WebSocket connected') - startHeartbeat() - } - - // {"type":"im-message-receive", - // "content": - // "{\ - // "id\":239,\ - // "conversationType\":1,\ - // "senderId\":144,\ - // "senderNickname\":\"dylan\",\ - // "senderAvatar\":\"http://192.168.0.208:48083/admin-api/infra/file/4/get/c34f9521ce6a2e21148f16b73ab652e578b5bb572dbc259a5043f754c19c8a3f.png\",\ - // "receiverId\":1,\ - // "contentType\":101,\ - // "content\":\"111\",\ - // "sendTime\":1731139168438,\ - // "sequence\":2}" - // } - socket.value.onmessage = (event) => { - - if (event.data === 'pong') { - return - } - - try { - const websoketMessage = JSON.parse(event.data) as ImMessageReceiveResponse - if (websoketMessage.type === WEBSOCKET_MESSAGE_TYPE_ENUM.IM_MESSAGE_RECEIVE.toString()) { - const socketChatMessage = JSON.parse(websoketMessage.content) as ImMessageContent - - // 暂不处理自己发送的消息 - if (socketChatMessage.senderId === useUserStore().user.id) { - return - } - - if (socketChatMessage.contentType === ContentType.TEXT) { - const chatStore = useChatStore() - const localTextMessage = TextMessage.fromWebsocket(socketChatMessage) - chatStore.addMessageToConversation(localTextMessage) - } else if (socketChatMessage.contentType === ContentType.IMAGE) { - - } else if (socketChatMessage.contentType === ContentType.AUDIO) { - - } - - } else if (websoketMessage.type === WEBSOCKET_MESSAGE_TYPE_ENUM.IM_CONVERSATION_ADD.toString()) { - const chatStore = useChatStore() - const conversation = JSON.parse(websoketMessage.content) as BaseConversation - chatStore.addSession(conversation) - // 同步到内存 - chatStore.getConversationList() - - } else { - // TODO:[dylan] - } - - console.log('Received message:', websoketMessage) - - } catch (error) { - console.info(error) - } - - // messages.value.push(message) - - } - - socket.value.onclose = () => { - isConnected.value = false - console.log('WebSocket disconnected') - reconnect() - } - - socket.value.onerror = (error) => { - console.error('WebSocket error:', error) - isConnected.value = false - reconnect() - } - } - - // 发送消息 - function sendMessage(message: Message) { - if (socket.value && isConnected.value) { - socket.value.send(JSON.stringify(message)) - } - } - - /** - * 发送心跳消息 - */ - function sendHeartBeat() { - if (socket.value && isConnected.value) { - socket.value.send('ping') - } - } - - // 断开 WebSocket 连接 - function disconnect() { - if (socket.value) { - socket.value.close() - socket.value = null - } - stopHeartbeat() - clearTimeout(reconnectTimer!) - } - - // 自动重连逻辑 - function reconnect() { - stopHeartbeat() - if (reconnectTimer) clearTimeout(reconnectTimer) - reconnectTimer = setTimeout(() => { - console.log('Reconnecting WebSocket...') - connect() - }, 3000) // 3秒后重连 - } - - // 启动心跳 - function startHeartbeat() { - if (heartbeatTimer) clearInterval(heartbeatTimer) - heartbeatTimer = setInterval(() => { - if (socket.value && isConnected.value) { - sendHeartBeat() - console.log('Heartbeat sent') - } - }, 5000) // 每5秒发送一次心跳 - } - - // 停止心跳 - function stopHeartbeat() { - if (heartbeatTimer) { - clearInterval(heartbeatTimer) - heartbeatTimer = null - } - } - - // 自动断开连接,清理资源 - onUnmounted(() => { - disconnect() - }) - - return { - connect, - disconnect, - sendMessage, - messages, - isConnected, - generateConversationNo - } -}) diff --git a/src/views/chat/types/types.ts b/src/views/chat/types/types.ts deleted file mode 100644 index 02d0dd4a6..000000000 --- a/src/views/chat/types/types.ts +++ /dev/null @@ -1,63 +0,0 @@ -import BaseConversation from '../model/BaseConversation' -import BaseMessage from '../model/BaseMessage' -import { ChatConversation } from '../model/ChatConversation' -import ImageMessage from '../model/ImageMessage' -import TextMessage from '../model/TextMessage' - -export enum MessageRole { - SELF = 1, - SYSTEM = 2, - OTHER = 3 -} - -export enum SendStatus { - FAILURE = 1, - SENDING = 2, - SUCCESS = 3 -} - -export enum ContentType { - TEXT = 101, - IMAGE = 102, - AUDIO = 103, - SYSTEM = 1400 -} - -export const enum MENU_LIST_ENUM { - CONVERSATION = 1, - FRIENDS = 2 -} - -export const enum CONVERSATION_TYPE { - SINGLE = 1, - GROUP = 3, - NOTIFICATION = 4 -} - -export enum WEBSOCKET_MESSAGE_TYPE_ENUM { - IM_MESSAGE_RECEIVE = 'im-message-receive', - IM_CONVERSATION_ADD = 'im-conversation-add' -} - - -export type MessageModelType = BaseMessage | TextMessage | ImageMessage -export type ConversationModelType = BaseConversation | ChatConversation -export type ConversationType = CONVERSATION_TYPE - -export type ImMessageReceiveResponse = { - type: WEBSOCKET_MESSAGE_TYPE_ENUM - content: string -}; - -export type ImMessageContent = { - id: number; - conversationType: number; - senderId: number; - senderNickname: string; - senderAvatar: string; - receiverId: number; - contentType: number; - content: string; - sendTime: number; // Use `Date` if you'd prefer the time to be a `Date` object - sequence: number; -}