├── .gitignore ├── LICENSE ├── README.md ├── babel.config.js ├── jsconfig.json ├── package-lock.json ├── package.json ├── public ├── audio │ ├── chat.wav │ └── friend.wav ├── images │ ├── empty.svg │ ├── favicon.png │ ├── logo.svg │ ├── verify │ │ ├── image1.jpeg │ │ ├── image2.jpeg │ │ ├── image3.jpeg │ │ ├── image4.jpeg │ │ ├── image5.jpeg │ │ ├── image6.jpeg │ │ ├── image7.jpeg │ │ └── image8.jpeg │ └── wechat │ │ ├── wechat1.png │ │ ├── wechat2.png │ │ ├── wechat3.png │ │ ├── wechat4.png │ │ ├── wechat5.png │ │ └── wechat6.png └── index.html ├── src ├── App.vue ├── api │ ├── index.js │ ├── mockAxios.js │ └── request.js ├── assets │ ├── css │ │ └── index.css │ └── images │ │ └── background │ │ ├── background-1.jpeg │ │ ├── background-2.jpeg │ │ ├── background-3.jpeg │ │ ├── background-4.jpeg │ │ ├── background-5.jpeg │ │ ├── background-6.jpeg │ │ └── background-7.jpeg ├── main.js ├── mock │ ├── chatHistoryList.json │ ├── chatList.json │ ├── friendList.json │ ├── friendVerifyList.json │ └── mockServer.js ├── moment │ └── moment.js ├── pages │ ├── about │ │ └── index.vue │ ├── home │ │ ├── chat │ │ │ ├── emoticons.json │ │ │ ├── file-upload │ │ │ │ └── index.vue │ │ │ ├── img-upload │ │ │ │ └── index.vue │ │ │ └── index.vue │ │ ├── empty │ │ │ └── index.vue │ │ ├── index.vue │ │ ├── menu │ │ │ ├── calendar │ │ │ │ └── index.vue │ │ │ ├── index.vue │ │ │ ├── profile-edit │ │ │ │ ├── index.vue │ │ │ │ └── regions.json │ │ │ ├── search │ │ │ │ └── index.vue │ │ │ └── settings │ │ │ │ ├── index.vue │ │ │ │ └── password-reset │ │ │ │ └── index.vue │ │ ├── profile │ │ │ └── index.vue │ │ ├── sidebar-archived │ │ │ └── index.vue │ │ ├── sidebar-chats │ │ │ ├── chat-add │ │ │ │ └── index.vue │ │ │ └── index.vue │ │ ├── sidebar-favorites │ │ │ └── index.vue │ │ ├── sidebar-friends │ │ │ ├── friend-add │ │ │ │ └── index.vue │ │ │ ├── friend-verify │ │ │ │ └── index.vue │ │ │ ├── index.vue │ │ │ └── remark-reset │ │ │ │ └── index.vue │ │ └── sidebar-groups │ │ │ └── index.vue │ ├── login │ │ └── index.vue │ ├── password │ │ └── index.vue │ └── register │ │ └── index.vue ├── router │ └── index.js ├── store │ ├── home │ │ └── index.js │ └── index.js └── utils │ ├── cookie.js │ ├── date.js │ └── encrypt.js └── vue.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 toollong 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # easychat-client 2 | 3 | ## 介绍 4 | 5 | easychat-client 是 EasyChat 项目的前端部分,基于 Vue CLI 开发。 6 | 7 | EasyChat 是一个可以在线聊天的即时通讯平台,完全由个人设计和开发,初衷主要是觉得好玩儿,顺便学习一些新东西,所以网站有些简陋,属实是本人的能力和财力有限。网站没有任何付费内容,所有内容完全免费,欢迎大家使用体验,也期待大佬们的交流与反馈。 8 | 9 | 体验地址:[https://toollong.icu](https://toollong.icu)(网站已于 2023.08.18 下线,运行时长 382 天) 10 | 11 | > ### 功能介绍 12 | 13 | - 注册 14 | - 登录 15 | - 找回密码 16 | - 添加聊天 17 | - 删除聊天 18 | - 发送文本消息 19 | - 发送 Emoji 表情(Windows 7 可能无法正常显示) 20 | - 发送图片(批量发送) 21 | - 发送文件(同步发送,有点慢) 22 | - 新消息通知(有提示音) 23 | - 搜索用户 24 | - 修改好友备注 25 | - 好友申请 26 | - 好友验证 27 | - 好友删除(单向删除) 28 | - 验证消息通知(有提示音) 29 | - 查看资料 30 | - 编辑资料 31 | - 设置(头像、隐身、标签、修改密码) 32 | - 夜间模式 33 | - 小抽屉(搜一搜、日历) 34 | 35 | 36 | > ### 技术栈 37 | 38 | - 前端:Vue 3,Vue Router,Vuex,Element Plus,Socket.IO,Axios,VueUse... 39 | 40 | - 后端:Spring Cloud,Nacos,MyBatis-Plus,Netty-socketio,MinIO,Gson,MySQL,Redis,Docker... 41 | 42 | > ### 注意 43 | 44 | - 本网站仅供学习交流使用,由于网站的安全保障和加密措施并不完善,**请勿在网站中输入敏感信息**,避免信息泄露的风险。 45 | 46 | - 我的邮箱:toollong@163.com 47 | 48 | - 我的博客:[https://blog.csdn.net/weixin_49523761](https://blog.csdn.net/weixin_49523761) 49 | 50 | 51 | ## 安装 52 | 53 | ``` 54 | npm install 55 | ``` 56 | 57 | ## 启动 58 | 59 | 需要修改的地方: 60 | 61 | - 入口文件 main.js 中 socket.io 的 url 62 | - vue.config.js 中 devServer 的 url 63 | 64 | ``` 65 | npm run serve 66 | ``` 67 | 68 | ## 构建 69 | 70 | ``` 71 | npm run build 72 | ``` 73 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "esnext", 5 | "baseUrl": "./", 6 | "moduleResolution": "node", 7 | "paths": { 8 | "@/*": [ 9 | "src/*" 10 | ] 11 | }, 12 | "lib": [ 13 | "esnext", 14 | "dom", 15 | "dom.iterable", 16 | "scripthost" 17 | ] 18 | } 19 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "easychat-web", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "@formkit/auto-animate": "^1.0.0-beta.1", 12 | "@vueuse/core": "^8.6.0", 13 | "@wcjiang/notify": "^2.1.0", 14 | "axios": "^0.26.1", 15 | "core-js": "^3.8.3", 16 | "element-plus": "^2.2.2", 17 | "mockjs": "^1.1.0", 18 | "moment": "^2.29.3", 19 | "nprogress": "^0.2.0", 20 | "socket.io-client": "^2.4.0", 21 | "vue": "^3.2.13", 22 | "vue-particles": "^1.0.9", 23 | "vue-router": "^4.0.14", 24 | "vue3-slide-verify": "^1.1.1", 25 | "vuex": "^4.0.2" 26 | }, 27 | "devDependencies": { 28 | "@babel/core": "^7.12.16", 29 | "@babel/eslint-parser": "^7.12.16", 30 | "@iconify-json/ep": "^1.1.5", 31 | "@iconify-json/mdi": "^1.1.19", 32 | "@vue/cli-plugin-babel": "~5.0.0", 33 | "@vue/cli-plugin-eslint": "~5.0.0", 34 | "@vue/cli-service": "~5.0.0", 35 | "eslint": "^7.32.0", 36 | "eslint-plugin-vue": "^8.0.3", 37 | "unplugin-auto-import": "^0.8.5", 38 | "unplugin-icons": "^0.14.3", 39 | "unplugin-vue-components": "^0.19.6" 40 | }, 41 | "eslintConfig": { 42 | "root": true, 43 | "env": { 44 | "node": true 45 | }, 46 | "extends": [ 47 | "plugin:vue/vue3-essential", 48 | "eslint:recommended" 49 | ], 50 | "parserOptions": { 51 | "parser": "@babel/eslint-parser" 52 | }, 53 | "rules": {} 54 | }, 55 | "browserslist": [ 56 | "> 1%", 57 | "last 2 versions", 58 | "not dead", 59 | "not ie 11" 60 | ] 61 | } 62 | -------------------------------------------------------------------------------- /public/audio/chat.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toollong/easychat-client/8f6ff3d996f36dac2986917fcc26fe58487bd103/public/audio/chat.wav -------------------------------------------------------------------------------- /public/audio/friend.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toollong/easychat-client/8f6ff3d996f36dac2986917fcc26fe58487bd103/public/audio/friend.wav -------------------------------------------------------------------------------- /public/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toollong/easychat-client/8f6ff3d996f36dac2986917fcc26fe58487bd103/public/images/favicon.png -------------------------------------------------------------------------------- /public/images/logo.svg: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | 16 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /public/images/verify/image1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toollong/easychat-client/8f6ff3d996f36dac2986917fcc26fe58487bd103/public/images/verify/image1.jpeg -------------------------------------------------------------------------------- /public/images/verify/image2.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toollong/easychat-client/8f6ff3d996f36dac2986917fcc26fe58487bd103/public/images/verify/image2.jpeg -------------------------------------------------------------------------------- /public/images/verify/image3.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toollong/easychat-client/8f6ff3d996f36dac2986917fcc26fe58487bd103/public/images/verify/image3.jpeg -------------------------------------------------------------------------------- /public/images/verify/image4.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toollong/easychat-client/8f6ff3d996f36dac2986917fcc26fe58487bd103/public/images/verify/image4.jpeg -------------------------------------------------------------------------------- /public/images/verify/image5.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toollong/easychat-client/8f6ff3d996f36dac2986917fcc26fe58487bd103/public/images/verify/image5.jpeg -------------------------------------------------------------------------------- /public/images/verify/image6.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toollong/easychat-client/8f6ff3d996f36dac2986917fcc26fe58487bd103/public/images/verify/image6.jpeg -------------------------------------------------------------------------------- /public/images/verify/image7.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toollong/easychat-client/8f6ff3d996f36dac2986917fcc26fe58487bd103/public/images/verify/image7.jpeg -------------------------------------------------------------------------------- /public/images/verify/image8.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toollong/easychat-client/8f6ff3d996f36dac2986917fcc26fe58487bd103/public/images/verify/image8.jpeg -------------------------------------------------------------------------------- /public/images/wechat/wechat1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toollong/easychat-client/8f6ff3d996f36dac2986917fcc26fe58487bd103/public/images/wechat/wechat1.png -------------------------------------------------------------------------------- /public/images/wechat/wechat2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toollong/easychat-client/8f6ff3d996f36dac2986917fcc26fe58487bd103/public/images/wechat/wechat2.png -------------------------------------------------------------------------------- /public/images/wechat/wechat3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toollong/easychat-client/8f6ff3d996f36dac2986917fcc26fe58487bd103/public/images/wechat/wechat3.png -------------------------------------------------------------------------------- /public/images/wechat/wechat4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toollong/easychat-client/8f6ff3d996f36dac2986917fcc26fe58487bd103/public/images/wechat/wechat4.png -------------------------------------------------------------------------------- /public/images/wechat/wechat5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toollong/easychat-client/8f6ff3d996f36dac2986917fcc26fe58487bd103/public/images/wechat/wechat5.png -------------------------------------------------------------------------------- /public/images/wechat/wechat6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toollong/easychat-client/8f6ff3d996f36dac2986917fcc26fe58487bd103/public/images/wechat/wechat6.png -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | EasyChat - 快乐星球 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 |
19 | 20 | 21 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 28 | 29 | 31 | -------------------------------------------------------------------------------- /src/api/index.js: -------------------------------------------------------------------------------- 1 | import axios from "./request"; 2 | import mockAxios from "./mockAxios"; 3 | 4 | export const mockGetUserInfo = () => mockAxios.get('/user'); 5 | export const mockGetChatList = () => mockAxios.get('/chats'); 6 | export const mockGetFriendList = () => mockAxios.get('/friends'); 7 | export const mockGetFriendVerify = () => mockAxios.get('/friends/verify'); 8 | export const mockGetHistory = () => mockAxios.get('/chats/chat/history'); 9 | 10 | 11 | export const reqLogin = (data) => axios.post('/auth/login', data); 12 | 13 | export const reqLogout = () => axios.post('/auth/logout'); 14 | 15 | export const reqRegister = (data) => axios.post('/user/register', data); 16 | 17 | export const reqSendCode = (data) => axios.post('/user/verifyCode/send', data); 18 | 19 | export const reqValidateCode = (data) => axios.post('/user/verifyCode/validate', data); 20 | 21 | export const reqValidateUsername = (data) => axios.post('/user/username/validate', data); 22 | 23 | export const reqValidatePassword = (data) => axios.post('/user/password/validate', data); 24 | 25 | export const reqSearchUsers = (params) => axios.get('/user/search', { params: params }); 26 | 27 | export const reqGetUserInfo = (params) => axios.get('/user/user', { params: params }); 28 | 29 | export const reqEditUserInfo = (data) => axios.post('/user/user/edit', data); 30 | 31 | export const reqChangeAvatar = (data) => axios.post('/user/user/changeAvatar', data, { headers: { 'Content-Type': 'multipart/form-data' } }); 32 | 33 | export const reqChangePassword = (data) => axios.post('/user/user/changePassword', data); 34 | 35 | export const reqAddTag = (data) => axios.post('/user/user/addTag', data); 36 | 37 | export const reqRemoveTag = (data) => axios.post('/user/user/removeTag', data); 38 | 39 | export const reqGetChatList = (params) => axios.get('/chat/chats', { params: params }); 40 | 41 | export const reqGetFriendList = (params) => axios.get('/user/friends', { params: params }); 42 | 43 | export const reqGetFriendVerify = (params) => axios.get('/user/friendVerify', { params: params }); 44 | 45 | export const reqGetHistory = (params) => axios.get('/chat/chats/chatHistory', { params: params }); 46 | 47 | export const reqSavePictureMsg = (data) => axios.post('/chat/chats/savePictureMsg', data, { headers: { 'Content-Type': 'multipart/form-data' } }); 48 | 49 | export const reqSaveFileMsg = (data) => axios.post('/chat/chats/saveFileMsg', data, { headers: { 'Content-Type': 'multipart/form-data' } }); 50 | -------------------------------------------------------------------------------- /src/api/mockAxios.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import nprogress from "nprogress"; 3 | 4 | import "nprogress/nprogress.css"; 5 | 6 | const requests = axios.create({ 7 | baseURL: '/mock', 8 | timeout: 5000 9 | }) 10 | 11 | requests.interceptors.request.use((config) => { 12 | nprogress.start(); 13 | return config; 14 | }) 15 | 16 | requests.interceptors.response.use((res) => { 17 | nprogress.done(); 18 | return res.data; 19 | }, (error) => { 20 | return Promise.reject(new Error("response failed...")); 21 | }) 22 | 23 | export default requests; -------------------------------------------------------------------------------- /src/api/request.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import nprogress from "nprogress"; 3 | 4 | import "nprogress/nprogress.css"; 5 | 6 | const requests = axios.create({ 7 | baseURL: '/api', 8 | timeout: 60000 9 | }) 10 | 11 | requests.interceptors.request.use((config) => { 12 | if (config.url.includes("/auth/") 13 | || config.url.includes("/register") 14 | || config.url.includes("/verifyCode/") 15 | || config.url.includes("/validate") 16 | || config.url.includes("/changePassword")) { 17 | return config; 18 | } 19 | nprogress.start(); 20 | return config; 21 | }, (error) => { 22 | return Promise.reject(error); 23 | }) 24 | 25 | requests.interceptors.response.use((response) => { 26 | if (response.status === 200) { 27 | nprogress.done(); 28 | return response.data; 29 | } 30 | nprogress.done(); 31 | }, (error) => { 32 | return Promise.reject(error); 33 | }) 34 | 35 | export default requests; -------------------------------------------------------------------------------- /src/assets/css/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | width: 100%; 4 | min-width: 320px; 5 | min-height: 100vh; 6 | font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, 微软雅黑, Arial, sans-serif; 7 | font-size: 14px; 8 | font-weight: 400; 9 | line-height: 1.5; 10 | color: var(--text-color-primary); 11 | background-color: var(--bg-color); 12 | text-align: left; 13 | direction: ltr; 14 | } 15 | 16 | *, 17 | ::before, 18 | ::after { 19 | box-sizing: border-box; 20 | } 21 | 22 | :root { 23 | color-scheme: light; 24 | --color-white: #ffffff; 25 | --color-black: #000000; 26 | --color-primary: #0a80ff; 27 | --color-primary-light: #409eff; 28 | --color-primary-light-3: #79bbff; 29 | --color-primary-light-5: #a0cfff; 30 | --color-primary-light-7: #c6e2ff; 31 | --color-primary-light-8: #d9ecff; 32 | --color-primary-light-9: #ecf5ff; 33 | --color-primary-dark-2: #337ecc; 34 | --color-success: #0abb87; 35 | --color-success-light: #67c23a; 36 | --color-success-light-3: #95d475; 37 | --color-success-light-5: #b3e19d; 38 | --color-success-light-7: #d1edc4; 39 | --color-success-light-8: #e1f3d8; 40 | --color-success-light-9: #f0f9eb; 41 | --color-success-dark-2: #529b2e; 42 | --color-warning: #e6a23c; 43 | --color-warning-light-3: #eebe77; 44 | --color-warning-light-5: #f3d19e; 45 | --color-warning-light-7: #f8e3c5; 46 | --color-warning-light-8: #faecd8; 47 | --color-warning-light-9: #fdf6ec; 48 | --color-warning-dark-2: #b88230; 49 | --color-danger: #fd397a; 50 | --color-danger-light: #f56c6c; 51 | --color-danger-light-3: #f89898; 52 | --color-danger-light-5: #fab6b6; 53 | --color-danger-light-7: #fcd3d3; 54 | --color-danger-light-8: #fde2e2; 55 | --color-danger-light-9: #fef0f0; 56 | --color-danger-dark-2: #c45656; 57 | --color-error: #f56c6c; 58 | --color-error-light-3: #f89898; 59 | --color-error-light-5: #fab6b6; 60 | --color-error-light-7: #fcd3d3; 61 | --color-error-light-8: #fde2e2; 62 | --color-error-light-9: #fef0f0; 63 | --color-error-dark-2: #c45656; 64 | --color-info: #909399; 65 | --color-info-light-3: #b1b3b8; 66 | --color-info-light-5: #c8c9cc; 67 | --color-info-light-7: #dedfe0; 68 | --color-info-light-8: #e9e9eb; 69 | --color-info-light-9: #f4f4f5; 70 | --color-info-dark-2: #73767a; 71 | --bg-color: #ffffff; 72 | --bg-color-page: #f2f3f5; 73 | --bg-color-overlay: #ffffff; 74 | --text-color-primary: #303133; 75 | --text-color-regular: #606266; 76 | --text-color-secondary: #969696; 77 | --text-color-placeholder: #a8abb2; 78 | --text-color-disabled: #c0c4cc; 79 | --border-color: #dcdfe6; 80 | --border-color-light: #e4e7ed; 81 | --border-color-lighter: #ebeef5; 82 | --border-color-extra-light: #f2f6fc; 83 | --border-color-dark: #d4d7de; 84 | --border-color-darker: #cdd0d6; 85 | --fill-color: #f0f2f5; 86 | --fill-color-light: #f5f7fa; 87 | --fill-color-lighter: #fafafa; 88 | --fill-color-extra-light: #fafcff; 89 | --fill-color-dark: #ebedf0; 90 | --fill-color-darker: #e6e8eb; 91 | --fill-color-blank: #ffffff; 92 | --box-shadow: 0px 12px 32px 4px rgba(0, 0, 0, .04), 0px 8px 20px rgba(0, 0, 0, .08); 93 | --box-shadow-light: 0px 0px 12px rgba(0, 0, 0, .12); 94 | --box-shadow-lighter: 0px 0px 6px rgba(0, 0, 0, .12); 95 | --box-shadow-dark: 0px 16px 48px 16px rgba(0, 0, 0, .08), 0px 12px 32px rgba(0, 0, 0, .12), 0px 8px 16px -8px rgba(0, 0, 0, .16); 96 | --theme-color-light-1: #0a80ff; 97 | --theme-color-light-2: #409eff; 98 | --theme-color-light-3: #79bbff; 99 | --theme-color-light-8: #d9ecff; 100 | --theme-color-light-4: #ecf5ff; 101 | --theme-color-light-11: #7269ef; 102 | --theme-color-light-12: #626aef; 103 | --theme-box-shadow-1: 0px 0px 12px rgba(0, 47, 255, .12); 104 | --background-image-1: url(../images/background/background-1.jpeg); 105 | --background-image-2: url(../images/background/background-2.jpeg); 106 | --background-image-3: url(../images/background/background-3.jpeg); 107 | --background-image-4: url(../images/background/background-4.jpeg); 108 | --background-image-5: url(../images/background/background-5.jpeg); 109 | --background-image-6: url(../images/background/background-6.jpeg); 110 | --background-image-7: url(../images/background/background-7.jpeg); 111 | } 112 | 113 | html.dark { 114 | color-scheme: dark; 115 | --color-primary: #0a80ff; 116 | --color-primary-light: #409eff; 117 | --color-primary-light-3: #3375b9; 118 | --color-primary-light-5: #2a598a; 119 | --color-primary-light-7: #213d5b; 120 | --color-primary-light-8: #1d3043; 121 | --color-primary-light-9: #18222c; 122 | --color-primary-dark-2: #66b1ff; 123 | --color-success: #0abb87; 124 | --color-success-light: #67c23a; 125 | --color-success-light-3: #4e8e2f; 126 | --color-success-light-5: #3e6b27; 127 | --color-success-light-7: #2d481f; 128 | --color-success-light-8: #25371c; 129 | --color-success-light-9: #1c2518; 130 | --color-success-dark-2: #85ce61; 131 | --color-warning: #e6a23c; 132 | --color-warning-light-3: #a77730; 133 | --color-warning-light-5: #7d5b28; 134 | --color-warning-light-7: #533f20; 135 | --color-warning-light-8: #3e301c; 136 | --color-warning-light-9: #292218; 137 | --color-warning-dark-2: #ebb563; 138 | --color-danger: #fd397a; 139 | --color-danger-light: #f56c6c; 140 | --color-danger-light-3: #b25252; 141 | --color-danger-light-5: #854040; 142 | --color-danger-light-7: #582e2e; 143 | --color-danger-light-8: #412626; 144 | --color-danger-light-9: #2b1d1d; 145 | --color-danger-dark-2: #f78989; 146 | --color-error: #f56c6c; 147 | --color-error-light-3: #b25252; 148 | --color-error-light-5: #854040; 149 | --color-error-light-7: #582e2e; 150 | --color-error-light-8: #412626; 151 | --color-error-light-9: #2b1d1d; 152 | --color-error-dark-2: #f78989; 153 | --color-info: #909399; 154 | --color-info-light-3: #6b6d71; 155 | --color-info-light-5: #525457; 156 | --color-info-light-7: #393a3c; 157 | --color-info-light-8: #2d2d2f; 158 | --color-info-light-9: #202121; 159 | --color-info-dark-2: #a6a9ad; 160 | --bg-color-page: #0a0a0a; 161 | --bg-color: #16161a; 162 | --bg-color-overlay: #1d1e1f; 163 | --text-color-primary: #E5EAF3; 164 | --text-color-regular: #CFD3DC; 165 | --text-color-secondary: #A3A6AD; 166 | --text-color-placeholder: #8D9095; 167 | --text-color-disabled: #6C6E72; 168 | --border-color-darker: #636466; 169 | --border-color-dark: #58585B; 170 | --border-color: #4C4D4F; 171 | --border-color-light: #414243; 172 | --border-color-lighter: #363637; 173 | --border-color-extra-light: #2B2B2C; 174 | --fill-color-darker: #424243; 175 | --fill-color-dark: #39393A; 176 | --fill-color: #303030; 177 | --fill-color-light: #262727; 178 | --fill-color-lighter: #1D1D1D; 179 | --fill-color-extra-light: #191919; 180 | --fill-color-blank: transparent; 181 | --box-shadow: 0px 12px 32px 4px rgba(0, 0, 0, .36), 0px 8px 20px rgba(0, 0, 0, .72); 182 | --box-shadow-light: 0px 0px 12px rgba(0, 0, 0, .72); 183 | --box-shadow-lighter: 0px 0px 6px rgba(0, 0, 0, .72); 184 | --box-shadow-dark: 0px 16px 48px 16px rgba(0, 0, 0, .72), 0px 12px 32px #000000, 0px 8px 16px -8px #000000; 185 | --theme-color-light-1: #0a80ff; 186 | --theme-color-light-2: #409eff; 187 | --theme-color-light-3: #3375b9; 188 | --theme-color-light-8: #1d3043; 189 | --theme-color-light-4: #1f2b38; 190 | --theme-color-light-11: #7269ef; 191 | --theme-color-light-12: #626aef; 192 | --theme-box-shadow-1: 0px 0px 12px rgba(255, 255, 255, 0.158); 193 | } 194 | 195 | /* element plus */ 196 | 197 | html.dark { 198 | color-scheme: dark; 199 | --el-color-primary: #409eff; 200 | --el-color-primary-light-3: #3375b9; 201 | --el-color-primary-light-5: #2a598a; 202 | --el-color-primary-light-7: #213d5b; 203 | --el-color-primary-light-8: #1d3043; 204 | --el-color-primary-light-9: #18222c; 205 | --el-color-primary-dark-2: #66b1ff; 206 | --el-color-success: #67c23a; 207 | --el-color-success-light-3: #4e8e2f; 208 | --el-color-success-light-5: #3e6b27; 209 | --el-color-success-light-7: #2d481f; 210 | --el-color-success-light-8: #25371c; 211 | --el-color-success-light-9: #1c2518; 212 | --el-color-success-dark-2: #85ce61; 213 | --el-color-warning: #e6a23c; 214 | --el-color-warning-light-3: #a77730; 215 | --el-color-warning-light-5: #7d5b28; 216 | --el-color-warning-light-7: #533f20; 217 | --el-color-warning-light-8: #3e301c; 218 | --el-color-warning-light-9: #292218; 219 | --el-color-warning-dark-2: #ebb563; 220 | --el-color-danger: #f56c6c; 221 | --el-color-danger-light-3: #b25252; 222 | --el-color-danger-light-5: #854040; 223 | --el-color-danger-light-7: #582e2e; 224 | --el-color-danger-light-8: #412626; 225 | --el-color-danger-light-9: #2b1d1d; 226 | --el-color-danger-dark-2: #f78989; 227 | --el-color-error: #f56c6c; 228 | --el-color-error-light-3: #b25252; 229 | --el-color-error-light-5: #854040; 230 | --el-color-error-light-7: #582e2e; 231 | --el-color-error-light-8: #412626; 232 | --el-color-error-light-9: #2b1d1d; 233 | --el-color-error-dark-2: #f78989; 234 | --el-color-info: #909399; 235 | --el-color-info-light-3: #6b6d71; 236 | --el-color-info-light-5: #525457; 237 | --el-color-info-light-7: #393a3c; 238 | --el-color-info-light-8: #2d2d2f; 239 | --el-color-info-light-9: #202121; 240 | --el-color-info-dark-2: #a6a9ad; 241 | --el-box-shadow: 0px 12px 32px 4px rgba(0, 0, 0, 0.36), 0px 8px 20px rgba(0, 0, 0, 0.72); 242 | --el-box-shadow-light: 0px 0px 12px rgba(0, 0, 0, 0.72); 243 | --el-box-shadow-lighter: 0px 0px 6px rgba(0, 0, 0, 0.72); 244 | --el-box-shadow-dark: 0px 16px 48px 16px rgba(0, 0, 0, 0.72), 0px 12px 32px #000000, 0px 8px 16px -8px #000000; 245 | --el-bg-color-page: #0a0a0a; 246 | --el-bg-color: #141414; 247 | --el-bg-color-overlay: #1d1e1f; 248 | --el-text-color-primary: #E5EAF3; 249 | --el-text-color-regular: #CFD3DC; 250 | --el-text-color-secondary: #A3A6AD; 251 | --el-text-color-placeholder: #8D9095; 252 | --el-text-color-disabled: #6C6E72; 253 | --el-border-color-darker: #636466; 254 | --el-border-color-dark: #58585B; 255 | --el-border-color: #4C4D4F; 256 | --el-border-color-light: #414243; 257 | --el-border-color-lighter: #363637; 258 | --el-border-color-extra-light: #2B2B2C; 259 | --el-fill-color-darker: #424243; 260 | --el-fill-color-dark: #39393A; 261 | --el-fill-color: #303030; 262 | --el-fill-color-light: #262727; 263 | --el-fill-color-lighter: #1D1D1D; 264 | --el-fill-color-extra-light: #191919; 265 | --el-fill-color-blank: transparent; 266 | --el-mask-color: rgba(0, 0, 0, 0.8); 267 | --el-mask-color-extra-light: rgba(0, 0, 0, 0.3) 268 | } 269 | 270 | html.dark .el-button { 271 | --el-button-disabled-text-color: rgba(255, 255, 255, 0.5) 272 | } 273 | 274 | html.dark .el-popover { 275 | --el-popover-bg-color: var(--el-bg-color-overlay) 276 | } 277 | 278 | html.dark .el-card { 279 | --el-card-bg-color: var(--el-bg-color-overlay) 280 | } 281 | 282 | html.dark .el-empty { 283 | --el-empty-fill-color-0: var(--el-color-black); 284 | --el-empty-fill-color-1: #4b4b52; 285 | --el-empty-fill-color-2: #36383d; 286 | --el-empty-fill-color-3: #1e1e20; 287 | --el-empty-fill-color-4: #262629; 288 | --el-empty-fill-color-5: #202124; 289 | --el-empty-fill-color-6: #212224; 290 | --el-empty-fill-color-7: #1b1c1f; 291 | --el-empty-fill-color-8: #1c1d1f; 292 | --el-empty-fill-color-9: #18181a 293 | } 294 | 295 | .el-drawer { 296 | height: calc(100vh - 40px) !important; 297 | border-radius: 10px; 298 | margin: 20px; 299 | } 300 | 301 | .el-drawer .el-drawer__header { 302 | margin-bottom: 10px; 303 | } 304 | 305 | .el-dialog { 306 | border-radius: 10px !important; 307 | } 308 | 309 | .el-dialog .el-dialog__body { 310 | padding: 10px 20px; 311 | } 312 | 313 | .el-popover.el-popper { 314 | border-radius: 8px !important; 315 | } 316 | 317 | .el-calendar .el-calendar__header { 318 | align-items: center; 319 | } -------------------------------------------------------------------------------- /src/assets/images/background/background-1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toollong/easychat-client/8f6ff3d996f36dac2986917fcc26fe58487bd103/src/assets/images/background/background-1.jpeg -------------------------------------------------------------------------------- /src/assets/images/background/background-2.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toollong/easychat-client/8f6ff3d996f36dac2986917fcc26fe58487bd103/src/assets/images/background/background-2.jpeg -------------------------------------------------------------------------------- /src/assets/images/background/background-3.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toollong/easychat-client/8f6ff3d996f36dac2986917fcc26fe58487bd103/src/assets/images/background/background-3.jpeg -------------------------------------------------------------------------------- /src/assets/images/background/background-4.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toollong/easychat-client/8f6ff3d996f36dac2986917fcc26fe58487bd103/src/assets/images/background/background-4.jpeg -------------------------------------------------------------------------------- /src/assets/images/background/background-5.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toollong/easychat-client/8f6ff3d996f36dac2986917fcc26fe58487bd103/src/assets/images/background/background-5.jpeg -------------------------------------------------------------------------------- /src/assets/images/background/background-6.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toollong/easychat-client/8f6ff3d996f36dac2986917fcc26fe58487bd103/src/assets/images/background/background-6.jpeg -------------------------------------------------------------------------------- /src/assets/images/background/background-7.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toollong/easychat-client/8f6ff3d996f36dac2986917fcc26fe58487bd103/src/assets/images/background/background-7.jpeg -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import { ElCollapseTransition } from 'element-plus' 3 | import { autoAnimatePlugin } from '@formkit/auto-animate/vue' 4 | import io from 'socket.io-client' 5 | import VueParticles from 'vue-particles' 6 | import router from '@/router' 7 | import store from '@/store' 8 | import App from '@/App.vue' 9 | 10 | // import "@/mock/mockServer" 11 | import "@/moment/moment" 12 | 13 | import "@/assets/css/index.css" 14 | import "element-plus/theme-chalk/base.css" 15 | import "element-plus/theme-chalk/el-loading.css" 16 | import "element-plus/theme-chalk/el-message.css" 17 | import "element-plus/theme-chalk/el-message-box.css" 18 | import "element-plus/theme-chalk/el-notification.css" 19 | import "vue3-slide-verify/dist/style.css" 20 | 21 | const app = createApp(App) 22 | 23 | app.config.globalProperties.socket = io('https://toollong.icu', { transports: ['websocket'] }) 24 | app.component(ElCollapseTransition.name, ElCollapseTransition) 25 | app.use(router) 26 | app.use(store) 27 | app.use(autoAnimatePlugin) 28 | app.use(VueParticles) 29 | app.mount('#app') 30 | -------------------------------------------------------------------------------- /src/mock/chatHistoryList.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "70000000001", 4 | "senderId": "20000000001", 5 | "receiverId": "20000000002", 6 | "sessionId": "10000000001", 7 | "type": 0, 8 | "content": "听我说谢谢你,因为有你,温暖了四季...", 9 | "hasRead": 1, 10 | "showTime": 1, 11 | "createTime": "2022-05-26 09:40:25" 12 | }, 13 | { 14 | "id": "70000000002", 15 | "senderId": "20000000002", 16 | "receiverId": "20000000001", 17 | "sessionId": "10000000001", 18 | "type": 0, 19 | "content": "不用谢,沙雕...", 20 | "hasRead": 1, 21 | "showTime": 0, 22 | "createTime": "2022-05-26 09:41:25" 23 | }, 24 | { 25 | "id": "70000000003", 26 | "senderId": "20000000001", 27 | "receiverId": "20000000002", 28 | "sessionId": "10000000001", 29 | "type": 1, 30 | "content": "/images/image1.jpg", 31 | "hasRead": 1, 32 | "showTime": 1, 33 | "createTime": "2022-05-27 10:22:25" 34 | }, 35 | { 36 | "id": "70000000004", 37 | "senderId": "20000000002", 38 | "receiverId": "20000000001", 39 | "sessionId": "10000000001", 40 | "type": 0, 41 | "content": "这鞋是真的丑,兄弟...", 42 | "hasRead": 1, 43 | "showTime": 0, 44 | "createTime": "2022-05-27 10:30:25" 45 | }, 46 | { 47 | "id": "70000000005", 48 | "senderId": "20000000001", 49 | "receiverId": "20000000002", 50 | "sessionId": "10000000001", 51 | "type": 0, 52 | "content": "听我说谢谢你,因为有你,温暖了四季...", 53 | "hasRead": 1, 54 | "showTime": 1, 55 | "createTime": "2022-05-27 12:40:25" 56 | }, 57 | { 58 | "id": "70000000006", 59 | "senderId": "20000000001", 60 | "receiverId": "20000000002", 61 | "sessionId": "10000000001", 62 | "type": 0, 63 | "content": "听我说谢谢你,因为有你,温暖了四季...", 64 | "hasRead": 1, 65 | "showTime": 1, 66 | "createTime": "2022-05-27 13:40:25" 67 | }, 68 | { 69 | "id": "70000000006", 70 | "senderId": "20000000001", 71 | "receiverId": "20000000002", 72 | "sessionId": "10000000001", 73 | "type": 0, 74 | "content": "听我说谢谢你,因为有你,温暖了四季...", 75 | "hasRead": 1, 76 | "showTime": 1, 77 | "createTime": "2022-05-27 13:40:25" 78 | }, 79 | { 80 | "id": "70000000006", 81 | "senderId": "20000000001", 82 | "receiverId": "20000000002", 83 | "sessionId": "10000000001", 84 | "type": 0, 85 | "content": "听我说谢谢你,因为有你,温暖了四季...", 86 | "hasRead": 1, 87 | "showTime": 1, 88 | "createTime": "2022-05-27 13:40:25" 89 | }, 90 | { 91 | "id": "70000000006", 92 | "senderId": "20000000001", 93 | "receiverId": "20000000002", 94 | "sessionId": "10000000001", 95 | "type": 0, 96 | "content": "听我说谢谢你,因为有你,温暖了四季...", 97 | "hasRead": 1, 98 | "showTime": 1, 99 | "createTime": "2022-05-27 13:40:25" 100 | }, 101 | { 102 | "id": "70000000006", 103 | "senderId": "20000000001", 104 | "receiverId": "20000000002", 105 | "sessionId": "10000000001", 106 | "type": 0, 107 | "content": "听我说谢谢你,因为有你,温暖了四季...", 108 | "hasRead": 1, 109 | "showTime": 1, 110 | "createTime": "2022-05-27 13:40:25" 111 | } 112 | ] -------------------------------------------------------------------------------- /src/mock/chatList.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "sessionId": "10000000001", 4 | "userId": "20000000001", 5 | "friendUserId": "20000000005", 6 | "friendRemark": "老王", 7 | "friendNickName": "王五", 8 | "friendAvatar": "/images/avatar1.jpeg", 9 | "createTime": "2022-06-07 13:17:56", 10 | "latestChatHistory": { 11 | "senderId": "20000000001", 12 | "receiverId": "20000000002", 13 | "sessionId": "10000000001", 14 | "type": 0, 15 | "content": "hello world!", 16 | "hasRead": 1, 17 | "showTime": 0, 18 | "createTime": "2022-06-07 13:17:56" 19 | } 20 | }, 21 | { 22 | "sessionId": "10000000002", 23 | "userId": "20000000001", 24 | "friendUserId": "20000000003", 25 | "friendRemark": "单身狗", 26 | "friendNickName": "张三", 27 | "friendAvatar": "/images/avatar2.jpg", 28 | "createTime": "2022-05-26 13:17:56", 29 | "latestChatHistory": { 30 | "senderId": "20000000003", 31 | "receiverId": "20000000001", 32 | "sessionId": "10000000002", 33 | "type": 0, 34 | "content": "你好,世界!", 35 | "hasRead": 0, 36 | "showTime": 0, 37 | "createTime": "2022-05-26 13:17:56" 38 | } 39 | }, 40 | { 41 | "sessionId": "10000000003", 42 | "userId": "20000000001", 43 | "friendUserId": "20000000004", 44 | "friendRemark": "laoli", 45 | "friendNickName": "李四", 46 | "friendAvatar": "/images/avatar3.jpg", 47 | "createTime": "2022-06-06 13:17:56", 48 | "latestChatHistory": { 49 | "senderId": "20000000004", 50 | "receiverId": "20000000001", 51 | "sessionId": "10000000003", 52 | "type": 1, 53 | "content": "/images/image1.jpg", 54 | "hasRead": 1, 55 | "showTime": 0, 56 | "createTime": "2022-06-06 13:17:56" 57 | } 58 | }, 59 | { 60 | "sessionId": "10000000004", 61 | "userId": "20000000001", 62 | "friendUserId": "20000000002", 63 | "friendRemark": "", 64 | "friendNickName": "老六", 65 | "friendAvatar": "/images/avatar4.jpg", 66 | "createTime": "2022-06-07 13:18:56", 67 | "latestChatHistory": {} 68 | } 69 | ] -------------------------------------------------------------------------------- /src/mock/friendList.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "userId": "20000000001", 4 | "friendUserId": "20000000005", 5 | "friendRemark": "老王", 6 | "friendNickName": "王五", 7 | "friendAvatar": "/images/avatar1.jpeg", 8 | "introduction": "", 9 | "friendTags": [ 10 | "时间管理大师", 11 | "程序员", 12 | "打工仔" 13 | ], 14 | "sessionId": "10000000001", 15 | "sessionTime": "2022-06-06 13:17:56" 16 | }, 17 | { 18 | "userId": "20000000001", 19 | "friendUserId": "20000000003", 20 | "friendRemark": "单身狗", 21 | "friendNickName": "张三", 22 | "friendAvatar": "/images/avatar2.jpg", 23 | "introduction": "", 24 | "friendTags": [ 25 | "时间管理大师", 26 | "程序员", 27 | "打工仔" 28 | ], 29 | "sessionId": "10000000002", 30 | "sessionTime": "2022-06-06 13:17:56" 31 | }, 32 | { 33 | "userId": "20000000001", 34 | "friendUserId": "20000000004", 35 | "friendRemark": "laoli", 36 | "friendNickName": "李四", 37 | "friendAvatar": "/images/avatar3.jpg", 38 | "introduction": "", 39 | "friendTags": [ 40 | "时间管理大师", 41 | "程序员", 42 | "打工仔" 43 | ], 44 | "sessionId": "10000000003", 45 | "sessionTime": "2022-06-06 13:17:56" 46 | }, 47 | { 48 | "userId": "20000000001", 49 | "friendUserId": "20000000002", 50 | "friendRemark": "", 51 | "friendNickName": "老六", 52 | "friendAvatar": "/images/avatar4.jpg", 53 | "introduction": "", 54 | "friendTags": [], 55 | "sessionId": "10000000004", 56 | "sessionTime": "2022-06-06 13:17:56" 57 | }, 58 | { 59 | "userId": "20000000001", 60 | "friendUserId": "20000000006", 61 | "friendRemark": "", 62 | "friendNickName": "老八", 63 | "friendAvatar": "/images/avatar5.jpg", 64 | "introduction": "", 65 | "friendTags": [], 66 | "sessionId": "-1", 67 | "sessionTime": "2022-06-06 13:17:56" 68 | }, 69 | { 70 | "userId": "20000000001", 71 | "friendUserId": "20000000007", 72 | "friendRemark": "大佬", 73 | "friendNickName": "ohMyGod", 74 | "friendAvatar": "/images/avatar5.jpg", 75 | "introduction": "", 76 | "friendTags": [], 77 | "sessionId": "-1", 78 | "sessionTime": "2022-06-06 13:17:56" 79 | } 80 | ] -------------------------------------------------------------------------------- /src/mock/friendVerifyList.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "senderId": "20000000002", 4 | "senderNickName": "张三", 5 | "senderAvatar": "/images/avatar1.jpeg", 6 | "receiverId": "20000000001", 7 | "receiverNickName": "无敌", 8 | "receiverAvatar": "/images/avatar2.jpg", 9 | "applyReason": "加我加我加我", 10 | "remark": "老张", 11 | "status": 0, 12 | "hasRead": 0, 13 | "createTime": "2022-06-21 10:43:26" 14 | }, 15 | { 16 | "senderId": "20000000003", 17 | "senderNickName": "李四", 18 | "senderAvatar": "/images/avatar3.jpg", 19 | "receiverId": "20000000001", 20 | "receiverNickName": "无敌", 21 | "receiverAvatar": "/images/avatar2.jpg", 22 | "applyReason": "加我", 23 | "remark": "", 24 | "status": 1, 25 | "hasRead": 1, 26 | "createTime": "2022-06-15 10:43:26" 27 | }, 28 | { 29 | "senderId": "20000000001", 30 | "senderNickName": "无敌", 31 | "senderAvatar": "/images/avatar2.jpg", 32 | "receiverId": "20000000004", 33 | "receiverNickName": "王五", 34 | "receiverAvatar": "/images/avatar4.jpg", 35 | "applyReason": "加我加我", 36 | "remark": "王哥", 37 | "status": 1, 38 | "hasRead": 1, 39 | "createTime": "2022-06-02 10:43:26" 40 | }, 41 | { 42 | "senderId": "20000000001", 43 | "senderNickName": "无敌", 44 | "senderAvatar": "/images/avatar2.jpg", 45 | "receiverId": "20000000005", 46 | "receiverNickName": "大佬", 47 | "receiverAvatar": "/images/avatar5.jpg", 48 | "applyReason": "加我加我加我", 49 | "remark": "", 50 | "status": 2, 51 | "hasRead": 1, 52 | "createTime": "2022-06-20 08:43:26" 53 | }, 54 | { 55 | "senderId": "20000000006", 56 | "senderNickName": "123456", 57 | "senderAvatar": "/images/avatar1.jpeg", 58 | "receiverId": "20000000001", 59 | "receiverNickName": "无敌", 60 | "receiverAvatar": "/images/avatar2.jpg", 61 | "applyReason": "加我", 62 | "remark": "", 63 | "status": 3, 64 | "hasRead": 1, 65 | "createTime": "2022-06-11 10:43:26" 66 | } 67 | ] -------------------------------------------------------------------------------- /src/mock/mockServer.js: -------------------------------------------------------------------------------- 1 | import Mock from "mockjs" 2 | import chatList from "./chatList.json" 3 | import friendList from "./friendList.json" 4 | import friendVerifyList from "./friendVerifyList.json" 5 | import chatHistoryList from "./chatHistoryList.json" 6 | 7 | const userInfo = { 8 | code: 200, data: { 9 | id: "20000000001", 10 | username: "1234567890", 11 | avatar: "/images/avatar1.jpeg", 12 | nickName: "无敌", 13 | gender: "1", 14 | age: 20, 15 | birthday: "2000-01-01", 16 | email: "123456789@qq.com", 17 | phone: "1234567890", 18 | region: "山东省 烟台市", 19 | tags: [ 20 | "时间管理大师", 21 | "程序员", 22 | "打工仔" 23 | ], 24 | introduction: "" 25 | } 26 | } 27 | 28 | Mock.mock("/mock/user", "get", userInfo) 29 | Mock.mock("/mock/chats", "get", { code: 200, data: chatList }) 30 | Mock.mock("/mock/friends", "get", { code: 200, data: friendList }) 31 | Mock.mock("/mock/friends/verify", "get", { code: 200, data: friendVerifyList }) 32 | Mock.mock("/mock/chats/chat/history", "get", { code: 200, data: chatHistoryList }) -------------------------------------------------------------------------------- /src/moment/moment.js: -------------------------------------------------------------------------------- 1 | import moment from 'moment' 2 | 3 | moment.locale('zh-cn', { 4 | months: '一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月'.split('_'), 5 | monthsShort: '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'), 6 | weekdays: '星期日_星期一_星期二_星期三_星期四_星期五_星期六'.split('_'), 7 | weekdaysShort: '周日_周一_周二_周三_周四_周五_周六'.split('_'), 8 | weekdaysMin: '日_一_二_三_四_五_六'.split('_'), 9 | longDateFormat: { 10 | LT: 'HH:mm', 11 | LTS: 'HH:mm:ss', 12 | L: 'YYYY-MM-DD', 13 | LL: 'YYYY年MM月DD日', 14 | LLL: 'YYYY年MM月DD日Ah点mm分', 15 | LLLL: 'YYYY年MM月DD日ddddAh点mm分', 16 | l: 'YYYY-M-D', 17 | ll: 'YYYY年M月D日', 18 | lll: 'YYYY年M月D日 HH:mm', 19 | llll: 'YYYY年M月D日dddd HH:mm' 20 | }, 21 | meridiemParse: /凌晨|早上|上午|中午|下午|晚上/, 22 | meridiemHour: function (hour, meridiem) { 23 | if (hour === 12) { 24 | hour = 0; 25 | } 26 | if (meridiem === '凌晨' || meridiem === '早上' || 27 | meridiem === '上午') { 28 | return hour; 29 | } else if (meridiem === '下午' || meridiem === '晚上') { 30 | return hour + 12; 31 | } else { 32 | // '中午' 33 | return hour >= 11 ? hour : hour + 12; 34 | } 35 | }, 36 | meridiem: function (hour, minute, isLower) { 37 | const hm = hour * 100 + minute; 38 | if (hm < 600) { 39 | return '凌晨'; 40 | } else if (hm < 900) { 41 | return '早上'; 42 | } else if (hm < 1130) { 43 | return '上午'; 44 | } else if (hm < 1230) { 45 | return '中午'; 46 | } else if (hm < 1800) { 47 | return '下午'; 48 | } else { 49 | return '晚上'; 50 | } 51 | }, 52 | calendar: { 53 | sameDay: '[今天]LT', 54 | nextDay: '[明天]LT', 55 | nextWeek: '[下]ddddLT', 56 | lastDay: '[昨天]LT', 57 | lastWeek: '[上]ddddLT', 58 | sameElse: 'L' 59 | }, 60 | dayOfMonthOrdinalParse: /\d{1,2}(日|月|周)/, 61 | ordinal: function (number, period) { 62 | switch (period) { 63 | case 'd': 64 | case 'D': 65 | case 'DDD': 66 | return number + '日'; 67 | case 'M': 68 | return number + '月'; 69 | case 'w': 70 | case 'W': 71 | return number + '周'; 72 | default: 73 | return number; 74 | } 75 | }, 76 | relativeTime: { 77 | future: '%s内', 78 | past: '%s前', 79 | s: '几秒', 80 | ss: '%d秒', 81 | m: '1分钟', 82 | mm: '%d分钟', 83 | h: '1小时', 84 | hh: '%d小时', 85 | d: '1天', 86 | dd: '%d天', 87 | M: '1个月', 88 | MM: '%d个月', 89 | y: '1年', 90 | yy: '%d年' 91 | }, 92 | week: { 93 | // GB/T 7408-1994《数据元和交换格式·信息交换·日期和时间表示法》与ISO 8601:1988等效 94 | dow: 1, // Monday is the first day of the week. 95 | doy: 4 // The week that contains Jan 4th is the first week of the year. 96 | } 97 | }) -------------------------------------------------------------------------------- /src/pages/about/index.vue: -------------------------------------------------------------------------------- 1 | 157 | 158 | 174 | 175 | -------------------------------------------------------------------------------- /src/pages/home/chat/emoticons.json: -------------------------------------------------------------------------------- 1 | [ 2 | "😀", 3 | "😄", 4 | "😁", 5 | "😆", 6 | "😅", 7 | "🤣", 8 | "😂", 9 | "🙂", 10 | "🙃", 11 | "😉", 12 | "😊", 13 | "😇", 14 | "🥰", 15 | "😍", 16 | "🤩", 17 | "😘", 18 | "😗", 19 | "😚", 20 | "😙", 21 | "🥲", 22 | "😋", 23 | "😛", 24 | "😜", 25 | "🤪", 26 | "😝", 27 | "🤑", 28 | "🤗", 29 | "🤭", 30 | "🤫", 31 | "🤔", 32 | "🤐", 33 | "🤨", 34 | "😐", 35 | "😑", 36 | "😶", 37 | "😶‍🌫️", 38 | "😏", 39 | "😒", 40 | "🙄", 41 | "😬", 42 | "😮‍💨", 43 | "🤥", 44 | "😌", 45 | "😔", 46 | "😪", 47 | "🤤", 48 | "😴", 49 | "😷", 50 | "🤒", 51 | "🤕", 52 | "🤢", 53 | "🤮", 54 | "🤧", 55 | "🥵", 56 | "🥶", 57 | "🥴", 58 | "😵", 59 | "😵‍💫", 60 | "🤯", 61 | "🤠", 62 | "🥳", 63 | "🥸", 64 | "😎", 65 | "🤓", 66 | "🧐", 67 | "😕", 68 | "😟", 69 | "🙁", 70 | "☹️", 71 | "😮", 72 | "😯", 73 | "😲", 74 | "😳", 75 | "🥺", 76 | "😦", 77 | "😧", 78 | "😨", 79 | "😰", 80 | "😥", 81 | "😢", 82 | "😭", 83 | "😱", 84 | "😖", 85 | "😣", 86 | "😞", 87 | "😓", 88 | "😩", 89 | "😫", 90 | "🥱", 91 | "😤", 92 | "😡", 93 | "😠", 94 | "🤬", 95 | "😈", 96 | "👿", 97 | "💀", 98 | "☠️", 99 | "💩", 100 | "🤡", 101 | "👹", 102 | "👺", 103 | "👻", 104 | "👽", 105 | "👾", 106 | "🤖", 107 | "😺", 108 | "😸", 109 | "😹", 110 | "😻", 111 | "😼", 112 | "😽", 113 | "🙀", 114 | "😿", 115 | "😾", 116 | "🙈", 117 | "🙉", 118 | "🙊", 119 | "💋", 120 | "💌", 121 | "💘", 122 | "💝", 123 | "💖", 124 | "💗", 125 | "💓", 126 | "💞", 127 | "💕", 128 | "💟", 129 | "❣️", 130 | "💔", 131 | "❤️‍🔥", 132 | "❤️‍🩹", 133 | "❤️", 134 | "🧡", 135 | "💛", 136 | "💚", 137 | "💙", 138 | "💜", 139 | "🤎", 140 | "🖤", 141 | "🤍", 142 | "💯", 143 | "💢", 144 | "💥", 145 | "💫", 146 | "💦", 147 | "💨", 148 | "🕳️", 149 | "💣", 150 | "💬", 151 | "👁️‍🗨️", 152 | "🗨️", 153 | "🗯️", 154 | "💭", 155 | "💤", 156 | "👋", 157 | "🤚", 158 | "🖐️", 159 | "✋", 160 | "🖖", 161 | "👌", 162 | "🤌", 163 | "🤏", 164 | "✌️", 165 | "🤞", 166 | "🤟", 167 | "🤘", 168 | "🤙", 169 | "👈", 170 | "👉", 171 | "👆", 172 | "🖕", 173 | "👇", 174 | "☝️", 175 | "👍", 176 | "👎", 177 | "✊", 178 | "👊", 179 | "🤛", 180 | "🤜", 181 | "👏", 182 | "🙌", 183 | "👐", 184 | "🤲", 185 | "🤝", 186 | "🙏", 187 | "✍️", 188 | "💅", 189 | "🤳", 190 | "💪", 191 | "🦾", 192 | "🦿", 193 | "🦵", 194 | "🦶", 195 | "👂", 196 | "🦻", 197 | "👃", 198 | "🧠", 199 | "🫀", 200 | "🫁", 201 | "🦷", 202 | "🦴", 203 | "👀", 204 | "👁️", 205 | "👅", 206 | "👄" 207 | ] -------------------------------------------------------------------------------- /src/pages/home/chat/file-upload/index.vue: -------------------------------------------------------------------------------- 1 | 37 | 38 | 164 | 165 | -------------------------------------------------------------------------------- /src/pages/home/chat/img-upload/index.vue: -------------------------------------------------------------------------------- 1 | 40 | 41 | 179 | 180 | -------------------------------------------------------------------------------- /src/pages/home/empty/index.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 25 | 26 | -------------------------------------------------------------------------------- /src/pages/home/index.vue: -------------------------------------------------------------------------------- 1 | 38 | 39 | 126 | 127 | -------------------------------------------------------------------------------- /src/pages/home/menu/calendar/index.vue: -------------------------------------------------------------------------------- 1 | 75 | 76 | 114 | 115 | -------------------------------------------------------------------------------- /src/pages/home/menu/index.vue: -------------------------------------------------------------------------------- 1 | 193 | 194 | 283 | 284 | -------------------------------------------------------------------------------- /src/pages/home/menu/profile-edit/index.vue: -------------------------------------------------------------------------------- 1 | 126 | 127 | 261 | 262 | -------------------------------------------------------------------------------- /src/pages/home/menu/search/index.vue: -------------------------------------------------------------------------------- 1 | 53 | 54 | 104 | 105 | -------------------------------------------------------------------------------- /src/pages/home/menu/settings/index.vue: -------------------------------------------------------------------------------- 1 | 141 | 142 | 334 | 335 | -------------------------------------------------------------------------------- /src/pages/home/menu/settings/password-reset/index.vue: -------------------------------------------------------------------------------- 1 | 71 | 72 | 215 | 216 | -------------------------------------------------------------------------------- /src/pages/home/profile/index.vue: -------------------------------------------------------------------------------- 1 | 110 | 111 | 176 | 177 | -------------------------------------------------------------------------------- /src/pages/home/sidebar-archived/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /src/pages/home/sidebar-chats/chat-add/index.vue: -------------------------------------------------------------------------------- 1 | 48 | 49 | 99 | 100 | -------------------------------------------------------------------------------- /src/pages/home/sidebar-favorites/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /src/pages/home/sidebar-friends/friend-add/index.vue: -------------------------------------------------------------------------------- 1 | 201 | 202 | 355 | 356 | -------------------------------------------------------------------------------- /src/pages/home/sidebar-friends/friend-verify/index.vue: -------------------------------------------------------------------------------- 1 | 166 | 167 | 290 | 291 | -------------------------------------------------------------------------------- /src/pages/home/sidebar-friends/remark-reset/index.vue: -------------------------------------------------------------------------------- 1 | 62 | 63 | 176 | 177 | -------------------------------------------------------------------------------- /src/pages/home/sidebar-groups/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /src/pages/login/index.vue: -------------------------------------------------------------------------------- 1 | 133 | 134 | 239 | 240 | -------------------------------------------------------------------------------- /src/pages/register/index.vue: -------------------------------------------------------------------------------- 1 | 134 | 135 | 338 | 339 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHashHistory } from 'vue-router' 2 | import { getCookie } from '@/utils/cookie'; 3 | 4 | const routes = [ 5 | { 6 | path: '/login', 7 | component: () => import('@/pages/login'), 8 | name: 'login' 9 | }, 10 | { 11 | path: '/register', 12 | component: () => import('@/pages/register'), 13 | name: 'register' 14 | }, 15 | { 16 | path: '/home', 17 | component: () => import('@/pages/home'), 18 | name: 'home' 19 | }, 20 | { 21 | path: '/findPassword', 22 | component: () => import('@/pages/password'), 23 | name: 'findPassword' 24 | }, 25 | { 26 | path: '/about', 27 | component: () => import('@/pages/about'), 28 | name: 'about' 29 | }, 30 | { 31 | path: '/', 32 | redirect: "/home" 33 | } 34 | ] 35 | 36 | const router = createRouter({ 37 | history: createWebHashHistory(), 38 | routes 39 | }) 40 | 41 | router.beforeEach((to, from, next) => { 42 | if (to.path === "/login" || to.path === "/register" || to.path === "/findPassword" || to.path === "/about") { 43 | return next(); 44 | } 45 | const uid = getCookie("uid"); 46 | if (uid !== null && new RegExp(/\d{19}/).test(uid)) { 47 | return next(); 48 | } 49 | return next("/login"); 50 | }) 51 | 52 | export default router -------------------------------------------------------------------------------- /src/store/home/index.js: -------------------------------------------------------------------------------- 1 | import { mockGetChatList, mockGetFriendList, mockGetFriendVerify, mockGetHistory, reqGetChatList, reqGetFriendList, reqGetFriendVerify, reqGetHistory } from "@/api"; 2 | 3 | const state = { 4 | onlineUsers: [], 5 | chatList: [], 6 | friendList: [], 7 | friendVerifyList: [], 8 | chatHistories: [] 9 | }; 10 | const mutations = { 11 | ONLINEUSERS(state, onlineUsers) { 12 | state.onlineUsers = onlineUsers; 13 | }, 14 | CHATLIST(state, chatList) { 15 | state.chatList = chatList; 16 | }, 17 | FRIENDLIST(state, friendList) { 18 | state.friendList = friendList; 19 | }, 20 | FRIENDVERIFY(state, friendVerifyList) { 21 | state.friendVerifyList = friendVerifyList 22 | }, 23 | HISTORY(state, chatHistories) { 24 | state.chatHistories = chatHistories; 25 | } 26 | }; 27 | const actions = { 28 | // async getChatList({ commit }) { 29 | // let result = await mockGetChatList(); 30 | // if (result.code === 200) { 31 | // commit("CHATLIST", result.data.sort((obj1, obj2) => { 32 | // if (obj1.createTime > obj2.createTime) { 33 | // return -1; 34 | // } else if (obj1.createTime < obj2.createTime) { 35 | // return 1; 36 | // } else { 37 | // return 0; 38 | // } 39 | // })); 40 | // } 41 | // }, 42 | // async getFriendList({ commit }) { 43 | // let result = await mockGetFriendList(); 44 | // if (result.code === 200) { 45 | // commit("FRIENDLIST", result.data.sort()); 46 | // } 47 | // }, 48 | // async getFriendVerify({ commit }) { 49 | // let result = await mockGetFriendVerify(); 50 | // if (result.code === 200) { 51 | // commit("FRIENDVERIFY", result.data.sort((obj1, obj2) => { 52 | // if (obj1.createTime > obj2.createTime) { 53 | // return -1; 54 | // } else if (obj1.createTime < obj2.createTime) { 55 | // return 1; 56 | // } else { 57 | // return 0; 58 | // } 59 | // })); 60 | // } 61 | // }, 62 | // async getHistory({ commit }) { 63 | // let result = await mockGetHistory(); 64 | // if (result.code === 200) { 65 | // commit("HISTORY", result.data); 66 | // } 67 | // }, 68 | 69 | async getChatList({ commit }, userId) { 70 | let result = await reqGetChatList({ id: userId }); 71 | if (result.success) { 72 | commit("CHATLIST", result.data.sort((obj1, obj2) => { 73 | let time1 = obj1.latestChatHistory ? obj1.latestChatHistory.createTime : obj1.sessionTime; 74 | let time2 = obj2.latestChatHistory ? obj2.latestChatHistory.createTime : obj2.sessionTime; 75 | if (time1 > time2) { 76 | return -1; 77 | } else if (time1 < time2) { 78 | return 1; 79 | } else { 80 | return 0; 81 | } 82 | })); 83 | } 84 | }, 85 | async getFriendList({ commit }, userId) { 86 | let result = await reqGetFriendList({ id: userId }); 87 | if (result.success) { 88 | commit("FRIENDLIST", result.data.sort()); 89 | } 90 | }, 91 | async getFriendVerify({ commit }, userId) { 92 | let result = await reqGetFriendVerify({ id: userId }); 93 | if (result.success) { 94 | commit("FRIENDVERIFY", result.data.sort((obj1, obj2) => { 95 | if (obj1.createTime > obj2.createTime) { 96 | return -1; 97 | } else if (obj1.createTime < obj2.createTime) { 98 | return 1; 99 | } else { 100 | return 0; 101 | } 102 | })); 103 | } 104 | }, 105 | async getHistory({ commit }, params) { 106 | let result = await reqGetHistory(params); 107 | if (result.success) { 108 | if (result.data.records) { 109 | commit("HISTORY", result.data.records.sort((obj1, obj2) => { 110 | if (obj1.createTime < obj2.createTime) { 111 | return -1; 112 | } else if (obj1.createTime > obj2.createTime) { 113 | return 1; 114 | } else { 115 | return 0; 116 | } 117 | })); 118 | } else { 119 | commit("HISTORY", []); 120 | } 121 | } 122 | } 123 | }; 124 | const getters = {}; 125 | 126 | export default { 127 | namespaced: true, 128 | 129 | state, 130 | mutations, 131 | actions, 132 | getters 133 | } -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | import { createStore } from "vuex"; 2 | 3 | import home from './home'; 4 | 5 | export default createStore({ 6 | modules: { 7 | home 8 | } 9 | }) -------------------------------------------------------------------------------- /src/utils/cookie.js: -------------------------------------------------------------------------------- 1 | export function getCookie(name) { 2 | if (typeof name === 'string' && name !== '') { 3 | var arr = document.cookie.match(new RegExp("(^| )" + name + "=([^;]*)(;|$)")); 4 | if (arr != null) { 5 | return arr[2] ? decodeURIComponent(arr[2]) : null; 6 | } 7 | } 8 | return null; 9 | } 10 | 11 | export function setCookie(name, value, seconds) { 12 | var date = new Date(); 13 | date.setTime(date.getTime + seconds * 1000); 14 | var expires = "expires=" + date.toGMTString(); 15 | document.cookie = name + "=" + value + "; " + expires; 16 | } -------------------------------------------------------------------------------- /src/utils/date.js: -------------------------------------------------------------------------------- 1 | import moment from "moment"; 2 | 3 | export function compareDate(date, day = 0) { 4 | return moment(date).format("YYYY-MM-DD") === 5 | moment().subtract(day, "days").format("YYYY-MM-DD"); 6 | } 7 | 8 | export function compareYear(date) { 9 | return moment(date).format("YYYY") === moment().format("YYYY"); 10 | } 11 | 12 | export function formatDate(date, formatStr) { 13 | return moment(date).format(formatStr); 14 | } 15 | 16 | export function computeMinuteDiff(startTime, endTime) { 17 | return moment(endTime).diff(startTime) / (1000 * 60); 18 | } -------------------------------------------------------------------------------- /src/utils/encrypt.js: -------------------------------------------------------------------------------- 1 | export function encryptPhone(str) { 2 | if (null !== str && str !== undefined) { 3 | var pat = /(\d{3})\d*(\d{2})/; 4 | return str.replace(pat, '$1****$2'); 5 | } else { 6 | return ""; 7 | } 8 | } 9 | 10 | export function encryptIdNo(str) { 11 | if (null !== str && str !== undefined) { 12 | var pat = /(\d{4})\d*(\d{4})/; 13 | return str.replace(pat, '$1***********$2'); 14 | } else { 15 | return ""; 16 | } 17 | } 18 | 19 | export function encryptName(str) { 20 | if (null !== str && str !== undefined) { 21 | if (str.length <= 3) { 22 | return "*" + str.substring(1, str.length); 23 | } else if (str.length > 3 && str.length <= 6) { 24 | return "**" + str.substring(2, str.length); 25 | } else if (str.length > 6) { 26 | return str.substring(0, 2) + "****" + str.substring(6, str.length) 27 | } 28 | } else { 29 | return ""; 30 | } 31 | } 32 | 33 | export function encryptEmail(email) { 34 | let new_email = email; 35 | if (String(email).indexOf('@') > 0) { 36 | let str = email.split('@'); 37 | let _s = ''; 38 | if (str[0].length > 3) { //@前面多于3位 39 | for (let i = 3; i < str[0].length; i++) { 40 | _s += '*'; 41 | } 42 | new_email = str[0].substr(0, 3) + _s + '@' + str[1]; 43 | } else { //@前面小于等于于3位 44 | for (let i = 1; i < str[0].length; i++) { 45 | _s += '*' 46 | } 47 | new_email = str[0].substr(0, 1) + _s + '@' + str[1] 48 | } 49 | } 50 | return new_email; 51 | } -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | const { defineConfig } = require('@vue/cli-service') 2 | const AutoImport = require('unplugin-auto-import/webpack') 3 | const Components = require('unplugin-vue-components/webpack') 4 | const Icons = require('unplugin-icons/webpack') 5 | const { ElementPlusResolver } = require('unplugin-vue-components/resolvers') 6 | const IconsResolver = require('unplugin-icons/resolver') 7 | 8 | module.exports = defineConfig({ 9 | transpileDependencies: true, 10 | lintOnSave: false, 11 | configureWebpack: { 12 | plugins: [ 13 | AutoImport({ 14 | resolvers: [ 15 | ElementPlusResolver(), 16 | ], 17 | }), 18 | Components({ 19 | resolvers: [ 20 | ElementPlusResolver(), 21 | IconsResolver({ 22 | prefix: 'icon', 23 | enabledCollections: ['ep', 'mdi'], 24 | }), 25 | ], 26 | }), 27 | Icons(), 28 | ], 29 | }, 30 | devServer: { 31 | port: 8080, 32 | allowedHosts: "all", 33 | proxy: { 34 | '/api': { 35 | target: 'https://toollong.icu' 36 | } 37 | } 38 | } 39 | }) --------------------------------------------------------------------------------