diff --git a/.vscode/settings.json b/.vscode/settings.json index f145f386afc3d73989d21f10df7d9c8b10361608..e6bb50f4fcc4a92adf669d1f6e6709741bbf95ff 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -94,7 +94,7 @@ "i18n-ally.sortKeys": true, "i18n-ally.namespace": false, "i18n-ally.enabledParsers": ["ts"], - "i18n-ally.sourceLanguage": "en", + "i18n-ally.sourceLanguage": "zh-CN", "i18n-ally.displayLanguage": "zh-CN", "i18n-ally.enabledFrameworks": ["vue", "react"], "cSpell.words": [ diff --git a/package.json b/package.json index ba5400092e5c2fb36634b3ed6896532a14bc99b6..0a97ec64d45a058caa3c88e05c0b838357ca3fa3 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ "fast-xml-parser": "^4.3.2", "highlight.js": "^11.9.0", "jsencrypt": "^3.3.2", + "lodash": "^4.17.21", "lodash-es": "^4.17.21", "markdown-it": "^14.1.0", "markmap-common": "^0.16.0", @@ -68,6 +69,7 @@ "url": "^0.11.3", "video.js": "^7.21.5", "vue": "3.5.12", + "vue-at": "3.0.0-alpha.2", "vue-dompurify-html": "^4.1.4", "vue-i18n": "9.10.2", "vue-router": "^4.3.0", diff --git a/src/api/im/conversation/index.ts b/src/api/im/conversation/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..a60956fbc43a33f25c75e9d9e348993de6a1f441 --- /dev/null +++ b/src/api/im/conversation/index.ts @@ -0,0 +1,27 @@ +import request from '@/config/axios' + +export interface ImConversationRespVO { + id: number // 编号 + userId: number // 所属用户 + conversationType: number // 会话类型 + targetId: number // 聊天对象编号 + no: string // 会话标志 + pinned: boolean // 是否置顶 + lastReadTime: string // 最后已读时间 + createTime: string // 创建时间 +} + +// 获得用户的会话列表 +export const getConversationList = async () => { + return await request.get({ url: `/im/conversation/list` }) +} + +// 置顶会话 +export const updatePinned = async (data: any) => { + return await request.post({ url: `/im/conversation/update-pinned`, data }) +} + +// 更新最后已读时间 +export const updateLastReadTime = async (data: any) => { + return await request.post({ url: `/im/conversation/update-last-read-time`, data }) +} diff --git a/src/api/im/message/index.ts b/src/api/im/message/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..a127aa43de3352b908a4fdeb08574d1c40b41a8f --- /dev/null +++ b/src/api/im/message/index.ts @@ -0,0 +1,47 @@ +import request from '@/config/axios' + +export interface ImMessageSendReqVO { + clientMessageId: string // 客户端消息编号 + receiverId: number // 接收人编号 + conversationType: number // 会话类型 + contentType: number // 内容类型 + content: string // 内容 +} + +export interface ImMessageSendRespVO { + id: number // 编号 + sendTime: string // 发送时间 +} + +export interface ImMessageRespVO { + id: number // 编号 + conversationType: number // 会话类型 + senderId: number // 发送人编号 + senderNickname: string // 发送人昵称 + senderAvatar: string // 发送人头像 + receiverId: number // 接收人编号 + contentType: number // 内容类型 + content: string // 内容 + sendTime: string // 发送时间 + sequence: number // 序号 +} + +export interface pullParams { + sequence: number + size: number +} + +// 发送消息 +export const sendMessage = async (data: ImMessageSendReqVO): Promise => { + return await request.post({ url: `/im/message/send`, data }) +} + +// 消息列表-拉取大于 sequence 的消息列表 +export const pullMessageList = async (params: pullParams): Promise => { + return await request.get({ url: `/im/message/pull`, params }) +} + +// 消息列表-根据接收人和发送时间进行分页查询 +export const getMessageList = async (params: any): Promise => { + return await request.get({ url: `/im/message/list`, params }) +} diff --git a/src/assets/imgs/im/avatar/inform.png b/src/assets/imgs/im/avatar/inform.png new file mode 100644 index 0000000000000000000000000000000000000000..ec3166a5bf17a034cf67eb1102fbb9e8740acf2c Binary files /dev/null and b/src/assets/imgs/im/avatar/inform.png differ diff --git a/src/assets/imgs/im/avatar/jiaqun2x.png b/src/assets/imgs/im/avatar/jiaqun2x.png new file mode 100644 index 0000000000000000000000000000000000000000..ecf6f155b92243b0f2140373020ed4ad532f474c Binary files /dev/null and b/src/assets/imgs/im/avatar/jiaqun2x.png differ diff --git a/src/assets/imgs/im/avatar/theme2x.png b/src/assets/imgs/im/avatar/theme2x.png new file mode 100644 index 0000000000000000000000000000000000000000..9e3d59cc48b53d0c63efefee788402affa2a4409 Binary files /dev/null and b/src/assets/imgs/im/avatar/theme2x.png differ diff --git a/src/assets/imgs/im/tabbar/graycontacts.png b/src/assets/imgs/im/tabbar/graycontacts.png new file mode 100644 index 0000000000000000000000000000000000000000..468a5bd0e43a59c6fc39f507d26f36a77433362f Binary files /dev/null and b/src/assets/imgs/im/tabbar/graycontacts.png differ diff --git a/src/assets/imgs/im/tabbar/grayconversation.png b/src/assets/imgs/im/tabbar/grayconversation.png new file mode 100644 index 0000000000000000000000000000000000000000..649dd11398921258675388321da1036478625353 Binary files /dev/null and b/src/assets/imgs/im/tabbar/grayconversation.png differ diff --git a/src/assets/imgs/im/tabbar/highlightconversation.png b/src/assets/imgs/im/tabbar/highlightconversation.png new file mode 100644 index 0000000000000000000000000000000000000000..3cc43ec6930b8aa19543e08195b7ddceec005172 Binary files /dev/null and b/src/assets/imgs/im/tabbar/highlightconversation.png differ diff --git a/src/assets/imgs/im/tabbar/higtlightcontacts.png b/src/assets/imgs/im/tabbar/higtlightcontacts.png new file mode 100644 index 0000000000000000000000000000000000000000..bb40a9fe6c7fca5f2fb9da59d7b8e4882412bed2 Binary files /dev/null and b/src/assets/imgs/im/tabbar/higtlightcontacts.png differ diff --git a/src/assets/imgs/im/welcome/Group 78@3x.png b/src/assets/imgs/im/welcome/Group 78@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..d6f6a62179d45c20b8e2543a4669b114693da36a Binary files /dev/null and b/src/assets/imgs/im/welcome/Group 78@3x.png differ diff --git a/src/assets/imgs/im/welcome/Mask_group.png b/src/assets/imgs/im/welcome/Mask_group.png new file mode 100644 index 0000000000000000000000000000000000000000..eea084071e63c109fcd7841299289aff0b03a566 Binary files /dev/null and b/src/assets/imgs/im/welcome/Mask_group.png differ diff --git a/src/assets/imgs/im/welcome/Mask_group2.png b/src/assets/imgs/im/welcome/Mask_group2.png new file mode 100644 index 0000000000000000000000000000000000000000..d97a4823b0de5b95ef0c26dfa1c5a8c3a08c0fdb Binary files /dev/null and b/src/assets/imgs/im/welcome/Mask_group2.png differ diff --git a/src/components/Cropper/src/CropperAvatar.vue b/src/components/Cropper/src/CropperAvatar.vue index 9464c2a88c8ac9e74e2e0c783bd3f56e645d08a0..dc91bd266804c4cf92865f4308cdc6034a73863e 100644 --- a/src/components/Cropper/src/CropperAvatar.vue +++ b/src/components/Cropper/src/CropperAvatar.vue @@ -97,7 +97,7 @@ $prefix-cls: #{$namespace}--cropper-avatar; opacity: 0; transition: opacity 0.4s; - ::v-deep(svg) { + :deep(svg) { margin: auto; } } diff --git a/src/components/Im/SearchInput/index.ts b/src/components/Im/SearchInput/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..35a527fc86bcae36a418bda1c84c369b27f89327 --- /dev/null +++ b/src/components/Im/SearchInput/index.ts @@ -0,0 +1,3 @@ +import SearchInput from './src/SearchInput.vue' + +export { SearchInput } diff --git a/src/components/Im/SearchInput/src/SearchInput.vue b/src/components/Im/SearchInput/src/SearchInput.vue new file mode 100644 index 0000000000000000000000000000000000000000..a577b190d4a0478bec7cd2ad7688a90ece671a16 --- /dev/null +++ b/src/components/Im/SearchInput/src/SearchInput.vue @@ -0,0 +1,173 @@ + + + + + diff --git a/src/components/Im/UserStatus/index.ts b/src/components/Im/UserStatus/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..112ddecca9c1fa3bb5231dfc91829c8ea620f651 --- /dev/null +++ b/src/components/Im/UserStatus/index.ts @@ -0,0 +1,3 @@ +import UserStatus from './src/UserStatus.vue' + +export { UserStatus } diff --git a/src/components/Im/UserStatus/src/UserStatus.vue b/src/components/Im/UserStatus/src/UserStatus.vue new file mode 100644 index 0000000000000000000000000000000000000000..404e6f70021f706786f90196fe16ef8cabb5d8ab --- /dev/null +++ b/src/components/Im/UserStatus/src/UserStatus.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/src/components/Im/Welcome/index.ts b/src/components/Im/Welcome/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..ae7c836f200593f5779c6d8fd407ef70a107c126 --- /dev/null +++ b/src/components/Im/Welcome/index.ts @@ -0,0 +1,3 @@ +import Welcome from './src/Welcome.vue' + +export { Welcome } diff --git a/src/components/Im/Welcome/src/Welcome.vue b/src/components/Im/Welcome/src/Welcome.vue new file mode 100644 index 0000000000000000000000000000000000000000..ca7bb2feba5d3070ac5a0e570caaa4ac45e250cc --- /dev/null +++ b/src/components/Im/Welcome/src/Welcome.vue @@ -0,0 +1,73 @@ + + + + diff --git a/src/constant/im/emojis.js b/src/constant/im/emojis.js new file mode 100644 index 0000000000000000000000000000000000000000..c2e2019836101400b02ef082f60e428db9d42118 --- /dev/null +++ b/src/constant/im/emojis.js @@ -0,0 +1,322 @@ +const emojis = [ + '😀', + '😃', + '😄', + '😁', + '😆', + '😅', + '🤣', + '😂', + '🙂', + '🙃', + '😉', + '😊', + '😇', + '😍', + '🤩', + '😘', + '😗', + '😚', + '😙', + '😋', + '😛', + '😜', + '🤪', + '😝', + '🤑', + '🤗', + '🤭', + '🤫', + '🤔', + '🤐', + '🤨', + '😐', + '😑', + '😶', + '😏', + '😒', + '🙄', + '😬', + '🤥', + '😌', + '😔', + '😪', + '🤤', + '😴', + '😷', + '🤒', + '🤕', + '🤢', + '🤮', + '🤧', + '😵', + '🤯', + '🤠', + '😎', + '🤓', + '🧐', + '😕', + '😟', + '🙁', + '😮', + '😯', + '😲', + '😳', + '😦', + '😧', + '😨', + '😰', + '😥', + '😢', + '😭', + '😱', + '😖', + '😣', + '😞', + '😓', + '😩', + '😫', + '😤', + '😡', + '😠', + '🤬', + '😈', + '👿', + '💀', + '💩', + '🤡', + '👹', + '👺', + '👻', + '👽', + '👾', + '🤖', + '😺', + '😸', + '😹', + '😻', + '😼', + '😽', + '🙀', + '😿', + '😾', + '💋', + '👋', + '🤚', + '🖐', + '✋', + '🖖', + '👌', + '🤞', + '🤟', + '🤘', + '🤙', + '👈', + '👉', + '👆', + '🖕', + '👇', + '👍', + '👎', + '✊', + '👊', + '🤛', + '🤜', + '👏', + '🙌', + '👐', + '🤲', + '🤝', + '🙏', + '💅', + '🤳', + '💪', + '👂', + '👃', + '🧠', + '👀', + '👁', + '👅', + '👄', + '👶', + '🧒', + '👦', + '👧', + '🧑', + '👱', + '👨', + '🧔', + '👱‍', + '👨‍', + '👨‍', + '👩', + '👱‍', + '👩‍', + '👩‍', + '👩‍', + '👩‍', + '🧓', + '👴', + '👵', + '🙍', + '🙅', + '🙆', + '💁', + '🙋', + '🙇', + '🙇‍', + '🙇‍', + '🤦', + '🤷', + '🤷‍', + '🤷‍', + '👨‍⚕️', + '👩‍⚕️', + '👨‍🎓', + '👩‍🎓', + '👨‍🏫', + '👩‍🏫', + '👨‍⚖️', + '👩‍⚖️', + '👨‍🌾', + '👩‍🌾', + '👨‍🍳', + '👩‍🍳', + '👨‍🔧', + '👩‍🔧', + '👨‍🏭', + '👩‍🏭', + '👨‍💼', + '👩‍💼', + '👨‍🔬', + '👩‍🔬', + '👨‍💻', + '👩‍💻', + '👨‍🎤', + '👩‍🎤', + '👨‍🎨', + '👩‍🎨', + '👨‍✈️', + '👩‍✈️', + '👨‍🚀', + '👩‍🚀', + '👨‍🚒', + '👩‍🚒', + '👮', + '👮‍♂️', + '👮‍♀️', + '🕵', + '🕵️‍♂️', + '🕵️‍♀️', + '💂', + '💂‍', + '💂‍', + '👷', + '👷‍', + '👷‍', + '🤴', + '👸', + '👳', + '👳‍', + '👳‍', + '👲', + '🧕', + '🤵', + '👰', + '🤰', + '🤱', + '👼', + '🎅', + '🤶', + '🧙', + '🧚', + '🧛', + '🧜', + '🧝', + '🧞', + '🧟', + '💆', + '💇', + '🚶', + '🏃', + '💃', + '🕺', + '🕴', + '👯', + '🧖', + '🧖‍', + '🧖‍', + '🧘', + '👭', + '👫', + '👬', + '💏', + '👨‍', + '👩‍', + '💑', + '👨‍', + '👩‍', + '👪', + '👨‍👩‍👦', + '👨‍👩‍👧', + '👨‍👩‍👧‍👦', + '👨‍👩‍👦‍👦', + '👨‍👩‍👧‍👧', + '👨‍👨‍👦', + '👨‍👨‍👧', + '👨‍👨‍👧‍👦', + '👩‍👩‍👦', + '👩‍👩‍👧', + '👩‍👩‍👧‍👦', + '👩‍👩‍👦‍👦', + '👩‍👩‍👧‍👧', + '👨‍👦', + '👨‍👦‍👦', + '👨‍👧', + '👨‍👧‍👦', + '👨‍👧‍👧', + '👩‍👦', + '👩‍👦‍👦', + '👩‍👧', + '👩‍👧‍👦', + '👩‍👧‍👧', + '🗣', + '👤', + '👥', + '👣', + '🌂', + '☂', + '👓', + '🕶', + '👔', + '👕', + '👖', + '🧣', + '🧤', + '🧥', + '🧦', + '👗', + '👘', + '👙', + '👚', + '👛', + '👜', + '👝', + '🎒', + '👞', + '👟', + '👠', + '👡', + '👢', + '👑', + '👒', + '🎩', + '🎓', + '🧢', + '⛑', + '💄', + '💍', + '💼', +] + +export default emojis diff --git a/src/constant/im/errorCode.js b/src/constant/im/errorCode.js new file mode 100644 index 0000000000000000000000000000000000000000..afea9a837936e1cf0ef2fa3e8c7576df54761aaf --- /dev/null +++ b/src/constant/im/errorCode.js @@ -0,0 +1,77 @@ +// const ERROR_TYPE = { +// login: 1, +// }; + +export default { + /* 登陆相关 + */ + 0: { + 'none': '未知错误!' + }, + 1: { + 'invalid password': '密码错误!', + 'login failed': '登陆失败!', + 'user not found': '该用户不存在!', + }, + 17: { + 'duplicate_unique_property_exists': 'id已存在!', + 'resource_limited': '注册已达上限请开通企业版!', + 'unauthorized': '未开放授权注册!', + 'resource_not_found': '账号不存在!', + }, + 28: { + 'appkey or token error': '未登录!', + }, + 101: { + 'file exceeding maximum limit': '文件大小超出限制(默认10M)!', + 'none': '文件相关未知错误!' + }, + 217: { + 'the user was kicked by other device': '其他端踢出了该账号!', + }, + /* 群组相关 */ + 602: { + 'not in group or chatroom': '已不再该群组中!', + }, + 605: { + 'The chat room dose not exist.': '此群不存在!', + }, + /* 消息相关 */ + 221: { + 'not contact': '非好友关系,不可发送消息!', + }, + 400: { + 'UserId password error.': '用户密码错误!', + 'Please wait a moment while trying to send.': '验证码在有效期内,请勿重复发送!', + 'Image verification code error.': '图片验证码错误,请更换验证码或重新输入!', + 'Image code id cannot be empty.': '请填入图片验证码!', + 'Phone number cannot be empty.': '获取图片验证码请填入手机号!', + 'UserId hfp already exists.': '用户已注册!', + 'phone number illegal': '手机号不合法!', + 'Please send SMS to get mobile phone verification code.': '请发送短信获取手机验证码!', + 'SMS verification code error.': '验证码错误!' + }, + 603: { + 'blocked': '对方已将您加入黑名单!', + 'blacklist': '已在该群黑名单当中!无法加入该群。', + 'already': '已加入该群!' + }, + 504: { + 'exceed recall time limit': '消息超过可撤回时间!', + }, + 507: { + 'muted': '已被禁言!' + }, + 508: { + 'moderation': '内容审核不通过!请检查发送内容。' + } + // e.type === '603' 被拉黑 + // e.type === '605' 群组不存在 + // e.type === '602' 不在群组或聊天室中 + // e.type === '504' 撤回消息时超出撤回时间 + // e.type === '505' 未开通消息撤回 + // e.type === '506' 没有在群组或聊天室白名单 + // e.type === '501' 消息包含敏感词 + // e.type === '502' 被设置的自定义拦截捕获 + // e.type === '503' 未知错误 +} diff --git a/src/constant/im/index.js b/src/constant/im/index.js new file mode 100644 index 0000000000000000000000000000000000000000..5457b40367c2f19ab33f7f0aaaaca6206af1254e --- /dev/null +++ b/src/constant/im/index.js @@ -0,0 +1,14 @@ +import errorCode from './errorCode' +import onLineStatus from './onLineStatus' +import messageType from './messageType' +import informType from './informType' +import emojis from './emojis' +import warningText from './warningText' +export { + errorCode, + onLineStatus, + messageType, + informType, + emojis, + warningText, +} diff --git a/src/constant/im/informType.js b/src/constant/im/informType.js new file mode 100644 index 0000000000000000000000000000000000000000..a979573a85db6c1c2cef686b17714c58e88808ba --- /dev/null +++ b/src/constant/im/informType.js @@ -0,0 +1,52 @@ +const INFORM_NAME = { + FRIEND_INVITE: '好友申请', + FRIEND_BUILD: '已成为好友', + FRIEND_DELETED: '好友关系解除', + FRIEND_APPLY_REFUSE: '好友申请被拒绝', + FRIEND_APPLY_AGREE: '好友申请已通过', + GROUP_JOIN_SUCCESS: '成员入群成功', + GROUP_QUIT_SUCCESS: '成员退出群组成功', + GROUP_INVITE_JOIN: '邀请加入群组', + GROUP_REQUESTTOJOIN: '申请加入群组', + GROUP_REMOVE_MEMBER: '移出了群成员', + GROUP_DIRECT_MEMBER: '被直接拉入群组', + GROUP_UPDATE_ANNOUNCEMENT: '更新了群组公告', + GROUP_SET_ADMIN: '设定为管理员', + GROUP_REMOVE_ADMIN: '移除管理员', + GROUP_MUTE_MEMBER: '禁言成员', + GROUP_UNMUTE_MEMBER: '移除成员禁言', + GROUP_DESTORY: '解散群组', + GROUP_ACCEPTREQUEST: '同意入群申请', + GROUP_UPDATE_INFO: '更新群组信息', + GROUP_UPDATE_MEMBER_ATTRIBUTES: '群组成员属性更新' +} +const INFORM_TYPE = { + subscribe: INFORM_NAME.FRIEND_INVITE, + subscribed: INFORM_NAME.FRIEND_BUILD, + unsubscribed: INFORM_NAME.FRIEND_DELETED, + other_person_refuse: INFORM_NAME.FRIEND_APPLY_REFUSE, + other_person_agree: INFORM_NAME.FRIEND_APPLY_AGREE, + memberPresence: INFORM_NAME.GROUP_JOIN_SUCCESS, + memberAbsence: INFORM_NAME.GROUP_QUIT_SUCCESS, + inviteToJoin: INFORM_NAME.GROUP_INVITE_JOIN, + removeMember: INFORM_NAME.GROUP_REMOVE_MEMBER, + directJoined: INFORM_NAME.GROUP_DIRECT_MEMBER, + updateAnnouncement: INFORM_NAME.GROUP_UPDATE_ANNOUNCEMENT, + setAdmin: INFORM_NAME.GROUP_SET_ADMIN, + removeAdmin: INFORM_NAME.GROUP_REMOVE_ADMIN, + muteMember: INFORM_NAME.GROUP_MUTE_MEMBER, + unmuteMember: INFORM_NAME.GROUP_UNMUTE_MEMBER, + destroy: INFORM_NAME.GROUP_DESTORY, + requestToJoin: INFORM_NAME.GROUP_REQUESTTOJOIN, + acceptRequest: INFORM_NAME.GROUP_ACCEPTREQUEST, + updateInfo: INFORM_NAME.GROUP_UPDATE_INFO, + memberAttributesUpdate: INFORM_NAME.GROUP_UPDATE_MEMBER_ATTRIBUTES +} +const INFORM_FROM = { + FRIEND: 'friend', + GROUP: 'group' +} +export default { + INFORM_TYPE, + INFORM_FROM +} diff --git a/src/constant/im/messageType.js b/src/constant/im/messageType.js new file mode 100644 index 0000000000000000000000000000000000000000..593b33922edfa33dffae3113b05c0542d2b1bd1b --- /dev/null +++ b/src/constant/im/messageType.js @@ -0,0 +1,80 @@ +const SESSION_MESSAGE_TYPE = { + img: '[图片]', + file: '[文件]', + audio: '[语音]', + loc: '[位置]' +} + +const CUSTOM_TYPE = { + userCard: '个人名片' +} +// const ALL_MESSAGE_TYPE = { +// TEXT: 'txt', +// IMAGE: 'img', +// AUDIO: 'audio', +// LOCAL: 'loc', +// VIDEO: 'video', +// FILE: 'file', +// CUSTOM: 'custom', +// CMD: 'cmd', +// INFORM: 'inform' //这个类型不在环信消息类型内,属于自己定义的一种系统通知类的消息。 +// } +const ALL_MESSAGE_TYPE = { + TEXT: 101, + IMAGE: 102, + AUDIO: 103, + VIDEO: 104, + FILE: 105, + AT_TEXT: 106, + MERGE: 107, + CARD: 108, + LOCATION: 109, + CUSTOM: 110, + REVOKE_RECEIPT: 111, + C2C_RECEIPT: 112, + TYPING: 113, + QUOTE: 114, + FACE: 115, + ADVANCED_REVOKE: 118, + FRIEND_ADDED: 1201, + OA_NOTIFICATION: 1400, + GROUP_CREATED: 1501, + GROUP_INFO_CHANGED: 1502, + MEMBER_QUIT: 1504, + GROUP_OWNER_CHANGED: 1507, + MEMBER_KICKED: 1508, + MEMBER_INVITED: 1509, + MEMBER_ENTER: 1510, + GROUP_DISMISSED: 1511, + GROUP_MEMBER_MUTED: 1512, + GROUP_MEMBER_CANCEL_MUTED: 1513, + GROUP_MUTED: 1514, + GROUP_CANCEL_MUTED: 1515, + GROUP_ANNOUNCEMENT_UPDATED: 1519, + GROUP_NAME_UPDATED: 1520, + BURN_CHANGE: 1701, + REVOKE: 2101 +} +const CHAT_TYPE = { + SINGLE: 1, + GROUP: 3, + NOTIFICATION: 4 +} + +const MENTION_ALL = { + TEXT: '所有人', + VALUE: 'ALL' +} +const CHANGE_MESSAGE_BODAY_TYPE = { + RECALL: 0, + DELETE: 1, + MODIFY: 2 +} +export default { + SESSION_MESSAGE_TYPE, + CUSTOM_TYPE, + ALL_MESSAGE_TYPE, + CHAT_TYPE, + MENTION_ALL, + CHANGE_MESSAGE_BODAY_TYPE +} diff --git a/src/constant/im/onLineStatus.js b/src/constant/im/onLineStatus.js new file mode 100644 index 0000000000000000000000000000000000000000..19b5e70b7de8a448ae6390fb362be24f71be3491 --- /dev/null +++ b/src/constant/im/onLineStatus.js @@ -0,0 +1,11 @@ +const onLineStatus = { + Online: { label: '在线', style: 'background-color:#49FD1D' }, + Leave: { label: '离开', style: 'background-color:#4E4239' }, + Cloaking: { + label: '勿扰', + style: 'background-color:#F27014', + }, + Offline: { label: '离线', style: 'background-color:#BEC1BD' }, +} + +export default onLineStatus diff --git a/src/constant/im/warningText.js b/src/constant/im/warningText.js new file mode 100644 index 0000000000000000000000000000000000000000..536864c343cf3b271f8399dabf0f9f1958dcea7d --- /dev/null +++ b/src/constant/im/warningText.js @@ -0,0 +1,39 @@ +const SWINDLER_GO_DIE = [ + '时刻绷紧防范之弦,谨防新型电信诈骗。', + '号码陌⽣勿轻接,虚拟电话设陷阱。', + '飞来⼤奖莫惊喜,让您掏钱洞⽆底。', + '不存贪婪⼼,诈骗难得逞。', + '提⾼防骗意识,增强防范能⼒,构筑电信诈骗“防⽕墙。', + '骗⼈之⼼不可有,防骗之⼼不可⽆。', + '⽹上汇款需警惕,电话核实莫⼤意。', + '执法办案有规范,怎会汇款到个⼈。', + '不明电话及时挂,可疑短信不要回。', + '⽹络购物便利多,⽀付流程要仔细。', + '投资理财和股票,多是骗⼦设的套。', + '不信陌⽣短信,拒接陌⽣来电,让骗⼦⽆从下⼿。', + '⼀不贪⼆不占,诈骗再诡玩不转。', + '遇到恐吓要淡定,说你违法莫慌张,⼀旦难分真与假,警方电话110。', + '陌⽣来电要提防,多⽅确认防上当。', + '致富⼗年功,诈骗⼀场空。', + '积极加强⾃我防范意识,共同提⾼识骗防骗能⼒。', + '防范⽹络的骗术,不贪便宜要记住。', + ' 和谐⽹络你我共享,电信诈骗⼤家共防。', + '真假⽹店难分辨,购物不慎就被骗。', + '个⼈信息顶重要,密码账号保管好。', + '飞来⼤奖莫惊喜,让你掏钱洞⽆底。', + '安全账户⼦虚有,⼤额汇款要三思。', + '异地刷卡消费现,不要着急忙给钱。', + '电话通知接传票,实为骗钱设圈套。', + '刷卡消费莫离眼,防⽌盗刷盯着点。', + '⼼中⽆贪念,骗局远⾝边。', + '转账汇款须谨慎,万元以上到柜⾯。', + '陌⽣电话勿轻信,对⽅⾝份要核清。', + '电信诈骗不难防,不给不要不上当。', + '陌⽣信息不要理,以防害⼈⼜害⼰。', +] + +const EASEIM_HINT = + '【安全提示】本应用仅用于环信产品功能开发测试,请勿用于非法用途。任何涉及转账、汇款、裸聊、网恋、网购退款、投资理财等统统都是诈骗,请勿相信!' + +const WARM_TIP = '【温馨提示】该群仅供试用,72小时后将被删除!' +export default { SWINDLER_GO_DIE, EASEIM_HINT, WARM_TIP } diff --git a/src/layout/components/ImChat/index.ts b/src/layout/components/ImChat/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..a1b36bc09856a5717aa26b786ea41dd70e496e19 --- /dev/null +++ b/src/layout/components/ImChat/index.ts @@ -0,0 +1,3 @@ +import ImChat from './src/ImChat.vue' + +export { ImChat } diff --git a/src/layout/components/ImChat/src/ImChat.vue b/src/layout/components/ImChat/src/ImChat.vue new file mode 100644 index 0000000000000000000000000000000000000000..f63a2bef04228ae1f4a5d816d694fa5d3a6044ef --- /dev/null +++ b/src/layout/components/ImChat/src/ImChat.vue @@ -0,0 +1,110 @@ + + + diff --git a/src/layout/components/ToolHeader.vue b/src/layout/components/ToolHeader.vue index 0b8d00d57e586c219c725108579469a4ee9f5266..c770d5d27eec5449d1e3f329b7a8d9a8701f79ce 100644 --- a/src/layout/components/ToolHeader.vue +++ b/src/layout/components/ToolHeader.vue @@ -1,6 +1,7 @@ + + + + + + + +
+

+ + +

+ +
+
+
    + +
  • + +
    emoji
    +
    
    +
  • + +
  • + 󰈃 +
    3.1电话
    +
    󰈃
    +
  • + +
  • + +
    语音
    +
    
    +
  • + +
  • + +
    视频
    +
    
    +
  • + +
  • + +
    垃圾桶
    +
    
    +
  • + +
  • + +
    文件
    +
    
    +
  • + +
  • + +
    图库
    +
    
    +
  • + +
+
+

Unicode 引用

+
+ +

Unicode 是字体在网页端最原始的应用方式,特点是:

+
    +
  • 支持按字体的方式去动态调整图标大小,颜色等等。
  • +
  • 默认情况下不支持多色,直接添加多色图标会自动去色。
  • +
+
+

注意:新版 iconfont 支持两种方式引用多色图标:SVG symbol 引用方式和彩色字体图标模式。(使用彩色字体图标需要在「编辑项目」中开启「彩色」选项后并重新生成。)

+
+

Unicode 使用步骤如下:

+

第一步:拷贝项目下面生成的 @font-face

+
@font-face {
+  font-family: 'iconfont';
+  src: url('iconfont.ttf?t=1654496599109') format('truetype');
+}
+
+

第二步:定义使用 iconfont 的样式

+
.iconfont {
+  font-family: "iconfont" !important;
+  font-size: 16px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+

第三步:挑选相应图标并获取字体编码,应用于页面

+
+<span class="iconfont">&#x33;</span>
+
+
+

"iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。

+
+
+
+
+
    + +
  • + +
    + emoji +
    +
    .icon-emoji +
    +
  • + +
  • + +
    + 3.1电话 +
    +
    .icon-31dianhua +
    +
  • + +
  • + +
    + 语音 +
    +
    .icon-01 +
    +
  • + +
  • + +
    + 视频 +
    +
    .icon-video +
    +
  • + +
  • + +
    + 垃圾桶 +
    +
    .icon-lajitong +
    +
  • + +
  • + +
    + 文件 +
    +
    .icon-wenjian +
    +
  • + +
  • + +
    + 图库 +
    +
    .icon-tuku +
    +
  • + +
+
+

font-class 引用

+
+ +

font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。

+

与 Unicode 使用方式相比,具有如下特点:

+
    +
  • 相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。
  • +
  • 因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。
  • +
+

使用步骤如下:

+

第一步:引入项目下面生成的 fontclass 代码:

+
<link rel="stylesheet" href="./iconfont.css">
+
+

第二步:挑选相应图标并获取类名,应用于页面:

+
<span class="iconfont icon-xxx"></span>
+
+
+

" + iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。

+
+
+
+
+
    + +
  • + +
    emoji
    +
    #icon-emoji
    +
  • + +
  • + +
    3.1电话
    +
    #icon-31dianhua
    +
  • + +
  • + +
    语音
    +
    #icon-01
    +
  • + +
  • + +
    视频
    +
    #icon-video
    +
  • + +
  • + +
    垃圾桶
    +
    #icon-lajitong
    +
  • + +
  • + +
    文件
    +
    #icon-wenjian
    +
  • + +
  • + +
    图库
    +
    #icon-tuku
    +
  • + +
+
+

Symbol 引用

+
+ +

这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇文章 + 这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:

+
    +
  • 支持多色图标了,不再受单色限制。
  • +
  • 通过一些技巧,支持像字体那样,通过 font-size, color 来调整样式。
  • +
  • 兼容性较差,支持 IE9+,及现代浏览器。
  • +
  • 浏览器渲染 SVG 的性能一般,还不如 png。
  • +
+

使用步骤如下:

+

第一步:引入项目下面生成的 symbol 代码:

+
<script src="./iconfont.js"></script>
+
+

第二步:加入通用 CSS 代码(引入一次就行):

+
<style>
+.icon {
+  width: 1em;
+  height: 1em;
+  vertical-align: -0.15em;
+  fill: currentColor;
+  overflow: hidden;
+}
+</style>
+
+

第三步:挑选相应图标并获取类名,应用于页面:

+
<svg class="icon" aria-hidden="true">
+  <use xlink:href="#icon-xxx"></use>
+</svg>
+
+
+
+ +
+
+ + + diff --git a/src/styles/iconfont/iconfont.css b/src/styles/iconfont/iconfont.css new file mode 100644 index 0000000000000000000000000000000000000000..3ebf9f529d9e808bfe726d77eae55e12fd9a673a --- /dev/null +++ b/src/styles/iconfont/iconfont.css @@ -0,0 +1,41 @@ +@font-face { + font-family: "iconfont"; /* Project id */ + src: url('iconfont.ttf?t=1654496599109') format('truetype'); +} + +.iconfont { + font-family: "iconfont" !important; + font-size: 16px; + font-style: normal; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.icon-emoji:before { + content: "\e64a"; +} + +.icon-31dianhua:before { + content: "\f0203"; +} + +.icon-01:before { + content: "\e610"; +} + +.icon-video:before { + content: "\e61f"; +} + +.icon-lajitong:before { + content: "\e615"; +} + +.icon-wenjian:before { + content: "\e69f"; +} + +.icon-tuku:before { + content: "\e712"; +} + diff --git a/src/styles/iconfont/iconfont.js b/src/styles/iconfont/iconfont.js new file mode 100644 index 0000000000000000000000000000000000000000..979bc0375fa77af0d536eb2034343504a0181021 --- /dev/null +++ b/src/styles/iconfont/iconfont.js @@ -0,0 +1,73 @@ +/* eslint-disable */ +!(function (c) { + var t, + e, + l, + o, + n, + a = + '', + i = (i = document.getElementsByTagName('script'))[ + i.length - 1 + ].getAttribute('data-injectcss'), + h = function (c, t) { + t.parentNode.insertBefore(c, t) + } + if (i && !c.__iconfont__svg__cssinject__) { + c.__iconfont__svg__cssinject__ = !0 + try { + document.write( + '' + ) + } catch (c) { + console && console.log(c) + } + } + function d() { + n || ((n = !0), l()) + } + function s() { + try { + o.documentElement.doScroll('left') + } catch (c) { + return void setTimeout(s, 50) + } + d() + } + ;(t = function () { + var c, + t = document.createElement('div') + ;(t.innerHTML = a), + (a = null), + (t = t.getElementsByTagName('svg')[0]) && + (t.setAttribute('aria-hidden', 'true'), + (t.style.position = 'absolute'), + (t.style.width = 0), + (t.style.height = 0), + (t.style.overflow = 'hidden'), + (t = t), + (c = document.body).firstChild + ? h(t, c.firstChild) + : c.appendChild(t)) + }), + document.addEventListener + ? ~['complete', 'loaded', 'interactive'].indexOf( + document.readyState + ) + ? setTimeout(t, 0) + : ((e = function () { + document.removeEventListener('DOMContentLoaded', e, !1), + t() + }), + document.addEventListener('DOMContentLoaded', e, !1)) + : document.attachEvent && + ((l = t), + (o = c.document), + (n = !1), + s(), + (o.onreadystatechange = function () { + 'complete' == o.readyState && + ((o.onreadystatechange = null), d()) + })) +})(window) +/* eslint-disable */ diff --git a/src/styles/iconfont/iconfont.json b/src/styles/iconfont/iconfont.json new file mode 100644 index 0000000000000000000000000000000000000000..5ef211ee198778fe4656942e3153be8faccee1b1 --- /dev/null +++ b/src/styles/iconfont/iconfont.json @@ -0,0 +1,58 @@ +{ + "id": "", + "name": "", + "font_family": "iconfont", + "css_prefix_text": "icon-", + "description": "", + "glyphs": [ + { + "icon_id": "29929", + "name": "emoji", + "font_class": "emoji", + "unicode": "e64a", + "unicode_decimal": 58954 + }, + { + "icon_id": "201577", + "name": "3.1电话", + "font_class": "31dianhua", + "unicode": "f0203", + "unicode_decimal": 983555 + }, + { + "icon_id": "1236846", + "name": "语音", + "font_class": "01", + "unicode": "e610", + "unicode_decimal": 58896 + }, + { + "icon_id": "3878694", + "name": "视频", + "font_class": "video", + "unicode": "e61f", + "unicode_decimal": 58911 + }, + { + "icon_id": "7587956", + "name": "垃圾桶", + "font_class": "lajitong", + "unicode": "e615", + "unicode_decimal": 58901 + }, + { + "icon_id": "20710439", + "name": "文件", + "font_class": "wenjian", + "unicode": "e69f", + "unicode_decimal": 59039 + }, + { + "icon_id": "27334037", + "name": "图库", + "font_class": "tuku", + "unicode": "e712", + "unicode_decimal": 59154 + } + ] +} diff --git a/src/styles/iconfont/iconfont.ttf b/src/styles/iconfont/iconfont.ttf new file mode 100644 index 0000000000000000000000000000000000000000..76f389da60d6754d5d9c291e259a29f9165b3f8a Binary files /dev/null and b/src/styles/iconfont/iconfont.ttf differ diff --git a/src/utils/fileSizeFormat.ts b/src/utils/fileSizeFormat.ts new file mode 100644 index 0000000000000000000000000000000000000000..f52af683aa4156a027501ca8e8e1b94c61f43aeb --- /dev/null +++ b/src/utils/fileSizeFormat.ts @@ -0,0 +1,6 @@ +// fileSizeFormat.ts +export default function fileSizeFormat(value: number): string { + const s = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB'] + const e = Math.floor(Math.log(value) / Math.log(1024)) + return (value / Math.pow(1024, Math.floor(e))).toFixed(2) + ' ' + s[e] +} diff --git a/src/utils/paseLink.ts b/src/utils/paseLink.ts new file mode 100644 index 0000000000000000000000000000000000000000..d1091a544028b6e569aa4b2351db1c5a718991a3 --- /dev/null +++ b/src/utils/paseLink.ts @@ -0,0 +1,20 @@ +interface ParsedLinkResult { + isLink: boolean + msg: string +} + +const paseLink = (msg: string): ParsedLinkResult => { + let isLink = false + const reg = + /(https?\:\/\/|www\.)([a-zA-Z0-9-]+(\.[a-zA-Z0-9]+)+)(\:[0-9]{2,4})?\/?((\.[:_0-9a-zA-Z-]+)|[:_0-9a-zA-Z-]*\/?)*\??[:_#@*&%0-9a-zA-Z-/=]*/gm + + msg = msg.replace(reg, function (v: string): string { + const prefix = /^https?/gm.test(v) + isLink = prefix + return "" + v + '' + }) + + return { isLink, msg } +} + +export default paseLink diff --git a/src/views/im/Contacts/components/contactInfo.vue b/src/views/im/Contacts/components/contactInfo.vue new file mode 100644 index 0000000000000000000000000000000000000000..4a6548f0ac94c1ae72e2a521edd41432e500d4d1 --- /dev/null +++ b/src/views/im/Contacts/components/contactInfo.vue @@ -0,0 +1,150 @@ + + + + + diff --git a/src/views/im/Contacts/components/friendItem.vue b/src/views/im/Contacts/components/friendItem.vue new file mode 100644 index 0000000000000000000000000000000000000000..ef4c3a549419be091f0519acfd3d479896116b17 --- /dev/null +++ b/src/views/im/Contacts/components/friendItem.vue @@ -0,0 +1,116 @@ + + + + + diff --git a/src/views/im/Contacts/index.vue b/src/views/im/Contacts/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..62c856ce8f448280386833cf418aac24aae60cf0 --- /dev/null +++ b/src/views/im/Contacts/index.vue @@ -0,0 +1,30 @@ + + + diff --git a/src/views/im/Conversation/components/ConversationList.vue b/src/views/im/Conversation/components/ConversationList.vue new file mode 100644 index 0000000000000000000000000000000000000000..bbeb8de5de5ff44557ed8e5ab9834f77dfd63d2c --- /dev/null +++ b/src/views/im/Conversation/components/ConversationList.vue @@ -0,0 +1,285 @@ + + + + diff --git a/src/views/im/Conversation/index.vue b/src/views/im/Conversation/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..e78ef6b7a9b2d490c7e1455bd636018f3d1fd537 --- /dev/null +++ b/src/views/im/Conversation/index.vue @@ -0,0 +1,50 @@ + + + + + diff --git a/src/views/im/Message/components/inputBox/index.scss b/src/views/im/Message/components/inputBox/index.scss new file mode 100644 index 0000000000000000000000000000000000000000..9373989effea53f514151adda8676198cf2f820c --- /dev/null +++ b/src/views/im/Message/components/inputBox/index.scss @@ -0,0 +1,107 @@ +.chat_func_box { + position: relative; + display: flex; + align-items: center; + height: 42px; + width: 100%; + background-color: #f7f7f7; + border-top: 1px solid #e6e6e6; + border-bottom: 1px solid #e6e6e6; + line-height: 12px; + + .chat_func_icon { + width: 25px; + height: 25px; + } + + .emojis_box { + position: absolute; + left: 15px; + top: -180px; + width: 330px; + height: 150px; + border-radius: 5px; + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: space-between; + align-items: center; + background: #fff; + padding: 15px 5px; + + .emoji { + display: inline-block; + width: 25px; + height: 25px; + text-align: center; + line-height: 25px; + cursor: pointer; + transition: all 0.3s ease; + + &:hover { + transform: scale(1.2); + } + } + } + + .loading_box { + position: absolute; + right: 5px; + top: 0; + width: 50px; + height: 100%; + font-size: 15px; + } +} + +/* loading svg大小调整 */ +:deep(.circular) { + margin-top: 8px; + width: 25px; + height: 25px; +} + +.chat_content_editable { + font-family: 'PingFang SC'; + width: 100%; + box-sizing: border-box; + min-height: 100px; + border: none; + background: none; + letter-spacing: 0.5px; + resize: none; + padding: 10px 20px; + font-size: 14px; + line-height: 10px; +} + +.no_content_send_btn { + position: absolute; + bottom: 20px; + right: 20px; + width: 80px; + opacity: 0.5; +} + +.chat_send_btn { + position: absolute; + bottom: 20px; + right: 20px; + width: 80px; +} + +.iconfont { + margin-right: 12px; + transition: all 0.3s ease; + cursor: pointer; + + &:hover { + transform: scale(1.2); + color: #1b83f9; + } +} + +.record_box { + width: 250px; + height: 180px; +} diff --git a/src/views/im/Message/components/inputBox/index.vue b/src/views/im/Message/components/inputBox/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..470204e445745ff07b083dd840c5237ab6cbcae3 --- /dev/null +++ b/src/views/im/Message/components/inputBox/index.vue @@ -0,0 +1,474 @@ + + + + diff --git a/src/views/im/Message/components/messageList/index.scss b/src/views/im/Message/components/messageList/index.scss new file mode 100644 index 0000000000000000000000000000000000000000..da1d21024561c97c88bcc2a5eb9ff8ae6180e883 --- /dev/null +++ b/src/views/im/Message/components/messageList/index.scss @@ -0,0 +1,303 @@ +.messageList_box { + width: 100%; + + .message_box_item { + position: relative; + display: flex; + margin: 32px auto; + font-weight: 400; + font-size: 14px; + line-height: 20px; + letter-spacing: 0.4px; + color: #333333; + + .message_item_time { + position: absolute; + top: -25px; + left: 0; + right: 0; + margin: auto; + width: 74px; + height: 20px; + color: #adadad; + font-weight: 400; + font-size: 10px; + line-height: 20px; + } + + .message_item_avator { + width: 38px; + height: 38px; + } + .message_box_card { + display: flex; + flex-direction: column; + max-width: 50%; + min-height: 34px; + } + .message_box_nickname { + font-size: 14px; + line-height: 20px; + letter-spacing: 0.4px; + color: #9a9a9a; + margin: 0 10px; + } + .message_box_content { + display: flex; + align-items: center; + margin: 0 6px; + word-break: break-all; + /* 通用音频播放样式 */ + .message_box_content_audio { + display: flex; + justify-content: flex-end; + align-items: center; + max-width: 250px; + min-width: 80px; + font-size: 12px; + + .audio_length_text { + font-family: 'Avenir'; + font-style: normal; + font-weight: 400; + font-size: 12px; + } + } + + /* 对方音频播放样式 */ + .message_box_content_audio_other { + flex-direction: row; + + @keyframes other_play_icon { + 0% { + background: url('@/assets/images/playAudio/msg_recv_audio02@3x.png') + no-repeat; + + background-size: 100% 100%; + } + + 50% { + background: url('@/assets/images/playAudio/msg_recv_audio01@3x.png') + no-repeat; + + background-size: 100% 100%; + } + + 100% { + background: url('@/assets/images/playAudio/msg_recv_audio@3x.png') + no-repeat; + background-size: 100% 100%; + } + } + + .play_audio_icon_other { + width: 30px; + height: 30px; + background: url('@/assets/images/playAudio/msg_recv_audio@3x.png') + no-repeat; + margin-right: 10px; + } + + .start_play_audio { + animation: other_play_icon 2s; + animation-iteration-count: infinite; + } + } + + /* 己方音频播放样式 */ + .message_box_content_audio_mine { + flex-direction: row-reverse; + + @keyframes mine_play_icon { + 0% { + background: url('@/assets/images/playAudio/msg_send_audio02@3x.png') + no-repeat; + + background-size: 100% 100%; + } + + 50% { + background: url('@/assets/images/playAudio/msg_send_audio01@3x.png') + no-repeat; + + background-size: 100% 100%; + } + + 100% { + background: url('@/assets/images/playAudio/msg_send_audio@3x.png') + no-repeat; + background-size: 100% 100%; + } + } + + .play_audio_icon_mine { + width: 30px; + height: 30px; + background-size: 100% 100%; + background: url('@/assets/images/playAudio/msg_send_audio@3x.png') + no-repeat; + margin-left: 10px; + } + + .start_play_audio { + animation: mine_play_icon 2s; + animation-iteration-count: infinite; + } + } + + /* 文件消息样式 */ + .message_box_content_file { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + width: 200px; + min-height: 60px; + max-height: 120px; + padding: 10px; + + .file_text_box { + width: 75%; + height: 80%; + display: flex; + flex-direction: column; + justify-content: space-around; + + .file_name { + width: 120px; + white-space: wrap; + overflow: hidden; + text-overflow: ellipsis; + font-size: 15px; + font-weight: bold; + } + + .file_size { + font-size: 13px; + } + + .file_download { + width: 100%; + color: #333333; + font-size: 13px; + cursor: pointer; + transition: all 0.3s ease; + + &:hover { + transform: scale(0.9); + } + } + } + + .icon-wenjian { + font-size: 50px; + color: #8d8a8a; + } + } + + /* 自定义消息 */ + .message_box_content_custom { + display: flex; + flex-direction: column; + justify-content: space-between; + width: 200px; + min-height: 60px; + max-height: 120px; + padding: 10px; + overflow: hidden; + + .user_card_main { + display: flex; + flex-direction: row; + justify-content: flex-start; + align-items: center; + color: #333333; + font-size: 17px; + + .nickname { + display: inline-block; + // width: 100%; + margin-left: 10px; + height: 35px; + line-height: 35px; + } + } + } + + /* 个人名片 */ + } + .quote_msg_avtive { + animation: twinkle 0.4s infinite alternate; + } + .quote_msg_avtive ::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + border-radius: 5px; + background-color: rgba(247, 169, 35, 0.5); + } + @keyframes twinkle { + 0% { + opacity: 0.3; + } + 50% { + opacity: 0.6; + } + 100% { + opacity: 0.9; + } + } + .message_box_content_other { + background: #fff; + border-radius: 8px 8px 8px 0px; + } + + .message_box_content_mine { + background: #c1e3fc; + border-radius: 8px 0px 8px 8px; + } + } + + /* 撤回或者系统通知类消息 */ + .recall_style, + .inform_style { + height: 60px; + text-align: center; + color: #aaaaaa; + font-size: 10px; + margin: 5px 0; + + .reEdit { + color: #3e91fa; + margin-left: 3px; + cursor: pointer; + } + } +} +.message_quote_box { + padding: 5px 10px; + font-size: 7px; + background-color: #e7e7e7; + border-radius: 5px; + margin-top: 5px; + color: #a0a0a0; + cursor: pointer; + p { + word-break: break-all; + overflow: hidden; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + } +} +:deep(.el-input__wrapper) { + border-radius: 5px; +} + +:deep(.el-dialog__header) { + background: #f2f2f2; + margin: 0; +} diff --git a/src/views/im/Message/components/messageList/index.vue b/src/views/im/Message/components/messageList/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..09d4e014556e4bd58024039d7da324eff1aff768 --- /dev/null +++ b/src/views/im/Message/components/messageList/index.vue @@ -0,0 +1,141 @@ + + + + diff --git a/src/views/im/Message/components/suit/audio.vue b/src/views/im/Message/components/suit/audio.vue new file mode 100644 index 0000000000000000000000000000000000000000..6d4e6b7273e06784809f0ac8b2c0e503832e1b72 --- /dev/null +++ b/src/views/im/Message/components/suit/audio.vue @@ -0,0 +1,237 @@ + + + + diff --git a/src/views/im/Message/components/suit/modifyMessage.vue b/src/views/im/Message/components/suit/modifyMessage.vue new file mode 100644 index 0000000000000000000000000000000000000000..61c3b942b689872adafc2c3edfb7dfdabccf2554 --- /dev/null +++ b/src/views/im/Message/components/suit/modifyMessage.vue @@ -0,0 +1,120 @@ + + + + + diff --git a/src/views/im/Message/components/suit/msgQuote.vue b/src/views/im/Message/components/suit/msgQuote.vue new file mode 100644 index 0000000000000000000000000000000000000000..98e3a9a53d765e6145125b48e16b56662c1591d5 --- /dev/null +++ b/src/views/im/Message/components/suit/msgQuote.vue @@ -0,0 +1,155 @@ + + + + + diff --git a/src/views/im/Message/components/suit/previewSendImg.vue b/src/views/im/Message/components/suit/previewSendImg.vue new file mode 100644 index 0000000000000000000000000000000000000000..e4538c4ce87e8ec6e6b18f5288a62be5c32993e2 --- /dev/null +++ b/src/views/im/Message/components/suit/previewSendImg.vue @@ -0,0 +1,68 @@ + + + + diff --git a/src/views/im/Message/components/suit/reportMessage.vue b/src/views/im/Message/components/suit/reportMessage.vue new file mode 100644 index 0000000000000000000000000000000000000000..c4b0db70e8bb0564638341c4dd8b4af87a987f78 --- /dev/null +++ b/src/views/im/Message/components/suit/reportMessage.vue @@ -0,0 +1,145 @@ + + + + + + \ No newline at end of file diff --git a/src/views/im/Message/index.scss b/src/views/im/Message/index.scss new file mode 100644 index 0000000000000000000000000000000000000000..3a44ea39b3bc46ccd135a05bd6dbfb4d906b9e7a --- /dev/null +++ b/src/views/im/Message/index.scss @@ -0,0 +1,129 @@ +.app_container { + height: 100%; + border-left: 1px solid #e6e6e6; +} + +.chat_message_header { + position: relative; + display: flex; + align-items: center; + flex-direction: row; + justify-content: space-between; + height: 61px; + background: #f9f9f9; + border-radius: 0 3px 0 0; + border-bottom: 1px solid #e6e6e6; + + .chat_user_box { + display: flex; + flex-direction: row; + justify-content: flex-start; + align-items: center; + height: 20px; + max-width: 80%; + + .chat_user_name { + font-family: 'PingFang SC'; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + font-style: normal; + font-weight: 400; + font-size: 17px; + line-height: 20px; + letter-spacing: 0.3px; + color: #333333; + } + } + + .more { + display: flex; + width: 35px; + height: 100%; + align-items: center; + justify-content: center; + font-size: 20px; + cursor: pointer; + transition: all 0.3s; + + &:hover { + transform: scale(1.1); + } + } +} + +.easeim_safe_tips { + position: relative; + padding: 12px 20px; + background-color: #fff4e6; + color: #ff8c39; + line-height: 18px; + font-family: PingFang SC; + font-style: normal; + font-weight: 400; + text-align: justify; + font-size: 12px; + border: none; + + .easeim_close_tips { + position: absolute; + right: 10px; + top: 10px; + } +} + +.chat_message_main { + padding: 0; + background: #f9f9f9; + + .main_container { + padding: 0 20px; + height: 100%; + // overflow-y: scroll; + + .chat_message_tips { + margin-top: 5px; + width: 100%; + height: 30px; + text-align: center; + line-height: 30px; + + .load_more_msg { + width: 200px; + height: 30px; + border-radius: 20px; + margin: 0 auto; + background: rgba(114, 112, 112, 0.143); + font-size: 13px; + letter-spacing: 0.5px; + // box-shadow: 1px 1px 1px 1px rgba(128, 128, 128, 0.193); + } + } + } +} + +.chat_message_input_bar { + position: relative; + width: 100%; + height: 25%; + padding: 0; + background-color: #f9f9f9; + border-radius: 0 0 3px 0; +} + +:deep(.el-drawer) { + margin-top: 60px; + width: 150px; + height: calc(100% - 60px); + border-radius: 5px 0 0 5px; + + .el-drawer__header { + margin-bottom: 0; + padding-top: 0; + } + + .el-drawer__body { + padding: 0; + // padding-left: 16px; + } +} diff --git a/src/views/im/Message/index.vue b/src/views/im/Message/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..e9ac2e903b4d94345fe4161b72acc676d0895b5e --- /dev/null +++ b/src/views/im/Message/index.vue @@ -0,0 +1,109 @@ + + + + + diff --git a/src/views/im/NavBar/index.vue b/src/views/im/NavBar/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..e1447b40ffe1729e8eff5c068f45a193b72daa3e --- /dev/null +++ b/src/views/im/NavBar/index.vue @@ -0,0 +1,287 @@ + + + + + diff --git a/src/views/im/index.vue b/src/views/im/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..fdbdca00161b244a437cf5997ffc79410d6256d3 --- /dev/null +++ b/src/views/im/index.vue @@ -0,0 +1,61 @@ + + + diff --git a/vite.config.ts b/vite.config.ts index 3ef21f269cd0f0c430f4f58dd19a8a99b8658512..b1955b7f08d70528a0d6b6f9975133be61ee321e 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,8 +1,8 @@ -import {resolve} from 'path' -import type {ConfigEnv, UserConfig} from 'vite' -import {loadEnv} from 'vite' -import {createVitePlugins} from './build/vite' -import {exclude, include} from "./build/vite/optimize" +import { resolve } from 'path' +import { loadEnv } from 'vite' +import type { UserConfig, ConfigEnv } from 'vite' +import { createVitePlugins } from './build/vite' +import { include, exclude } from "./build/vite/optimize" // 当前执行node命令时文件夹的地址(工作目录) const root = process.cwd()