├── .env.development ├── .env.production ├── .eslintignore ├── .eslintrc.cjs ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_report.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── deploy.yml ├── .gitignore ├── .husky ├── commit-msg ├── common.sh ├── lintstagedrc.js └── pre-commit ├── .npmrc ├── .prettierignore ├── .prettierrc.json ├── .stylelintrc.cjs ├── .vscode ├── extensions.json ├── launch.json ├── settings.json └── tasks.json ├── LICENSE ├── README.md ├── commitlint.config.js ├── config ├── plugin │ ├── compress.ts │ ├── imagemin.ts │ └── visualizer.ts ├── vite.config.base.ts ├── vite.config.dev.ts └── vite.config.prod.ts ├── index.html ├── package.json ├── pnpm-lock.yaml ├── public └── favicon.ico ├── src ├── App.vue ├── assets │ ├── iconfont │ │ ├── index-color.css │ │ └── index.css │ ├── login_bg.jpg │ ├── login_bg.webp │ ├── logo.jpeg │ └── qrcode.jpeg ├── auto-imports.d.ts ├── components.d.ts ├── components │ ├── AddFriendModal │ │ ├── index.vue │ │ └── styles.scss │ ├── Avatar │ │ ├── index.vue │ │ └── styles.scss │ ├── CreateGroupModal │ │ ├── SelectUser.vue │ │ ├── index.vue │ │ └── styles.scss │ ├── Icon │ │ └── index.vue │ ├── LoginBox │ │ ├── index.vue │ │ └── styles.scss │ ├── MsgReadModal │ │ ├── UserItem.vue │ │ ├── index.vue │ │ └── styles.scss │ ├── RenderMessage │ │ ├── emoji.vue │ │ ├── file.vue │ │ ├── image.vue │ │ ├── index.vue │ │ ├── text.vue │ │ ├── video.vue │ │ └── voice.vue │ ├── UserSettingBox │ │ ├── index.vue │ │ └── styles.scss │ ├── VideoPlayer │ │ └── index.vue │ ├── VirtualList │ │ ├── index.tsx │ │ ├── item.tsx │ │ └── virtual.ts │ └── avatar │ │ ├── index.vue │ │ └── styles.scss ├── constant │ ├── group.ts │ └── message.ts ├── directives │ ├── v-friends.ts │ ├── v-login-show.ts │ └── v-login.ts ├── enums │ ├── group.ts │ └── index.ts ├── env.d.ts ├── hooks │ ├── useCached.ts │ ├── useDownload.ts │ ├── useEmojiUpload.ts │ ├── useLikeToggle.ts │ ├── useMockMessage.ts │ ├── useRecording.ts │ └── useUpload.ts ├── main.ts ├── router │ ├── guard │ │ ├── index.ts │ │ └── permissionGuard.ts │ └── index.ts ├── services │ ├── apis.ts │ ├── request.ts │ ├── types.ts │ └── urls.ts ├── stores │ ├── cached.ts │ ├── chat.ts │ ├── contacts.ts │ ├── downloadQuenu.ts │ ├── emoji.ts │ ├── global.ts │ ├── group.ts │ ├── preview.ts │ ├── user.ts │ └── ws.ts ├── styles │ ├── base.css │ └── main.css ├── utils │ ├── computedTime.ts │ ├── copy.ts │ ├── detectDevice.ts │ ├── eventBus.ts │ ├── index.ts │ ├── initWorker.ts │ ├── notification.ts │ ├── readCountQueue.ts │ ├── renderReplyContent.ts │ ├── shakeTitle.ts │ ├── unique.ts │ ├── websocket.ts │ ├── worker.ts │ └── wsType.ts └── views │ └── Home │ ├── Chat │ ├── components │ │ ├── ChatBox │ │ │ ├── MsgInput │ │ │ │ ├── index.vue │ │ │ │ ├── item.vue │ │ │ │ ├── styles.scss │ │ │ │ ├── types.ts │ │ │ │ └── utils.ts │ │ │ ├── PasteImageDialog │ │ │ │ ├── index.vue │ │ │ │ └── styles.scss │ │ │ ├── SendBar │ │ │ │ ├── index.vue │ │ │ │ └── styles.scss │ │ │ ├── constant.ts │ │ │ ├── index.vue │ │ │ └── styles.scss │ │ ├── ChatList │ │ │ ├── ContextMenu │ │ │ │ ├── index.vue │ │ │ │ └── styles.scss │ │ │ ├── MsgItem │ │ │ │ ├── components │ │ │ │ │ └── UserCard │ │ │ │ │ │ ├── UserCard.vue │ │ │ │ │ │ └── styles.scss │ │ │ │ ├── index.vue │ │ │ │ └── styles.scss │ │ │ ├── MsgOption │ │ │ │ ├── index.vue │ │ │ │ └── styles.scss │ │ │ ├── RoomName │ │ │ │ ├── components │ │ │ │ │ └── SettingBox │ │ │ │ │ │ ├── SettingBox.vue │ │ │ │ │ │ └── components │ │ │ │ │ │ ├── AdvancedSetting │ │ │ │ │ │ ├── AdvancedSetting.vue │ │ │ │ │ │ └── styles.scss │ │ │ │ │ │ └── DeadZoneSetting │ │ │ │ │ │ ├── DeadZoneSetting.vue │ │ │ │ │ │ └── styles.scss │ │ │ │ ├── index.vue │ │ │ │ └── styles.scss │ │ │ ├── UserContextMenu │ │ │ │ ├── index.vue │ │ │ │ └── styles.scss │ │ │ ├── index.vue │ │ │ └── styles.scss │ │ ├── SideBar │ │ │ ├── index.vue │ │ │ └── styles.scss │ │ └── UserList │ │ │ ├── ContextMenu │ │ │ ├── index.vue │ │ │ └── styles.scss │ │ │ ├── UserItem │ │ │ ├── index.vue │ │ │ └── styles.scss │ │ │ ├── index.vue │ │ │ └── styles.scss │ └── index.vue │ ├── Contacts │ ├── components │ │ └── ContactList │ │ │ ├── Content │ │ │ ├── index.vue │ │ │ └── styles.scss │ │ │ ├── Side │ │ │ ├── ContactItem.vue │ │ │ ├── NewFriendItem.vue │ │ │ ├── index.vue │ │ │ └── styles.scss │ │ │ ├── index.vue │ │ │ └── styles.scss │ └── index.vue │ ├── components │ ├── PostCard │ │ ├── PostCard.vue │ │ └── styles.scss │ └── ToolBar │ │ ├── index.vue │ │ └── styles.scss │ ├── index.vue │ └── styles.scss ├── tsconfig.json └── tsconfig.node.json /.env.development: -------------------------------------------------------------------------------- 1 | VITE_API_PREFIX=https://api.mallchat.cn 2 | VITE_WS_URL=wss://api.mallchat.cn/websocket -------------------------------------------------------------------------------- /.env.production: -------------------------------------------------------------------------------- 1 | VITE_API_PREFIX=https://api.mallchat.cn 2 | VITE_WS_URL=wss://api.mallchat.cn/websocket -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Coverage directory used by tools like istanbul 11 | coverage 12 | .eslintcache 13 | 14 | # Dependency directory 15 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 16 | node_modules 17 | 18 | # OSX 19 | .DS_Store 20 | 21 | .gitignore 22 | .idea 23 | npm-debug.log.* 24 | .pnpm-debug.log* 25 | *.css.d.ts 26 | *.sass.d.ts 27 | *.scss.d.ts 28 | 29 | /build/ 30 | /dist/ 31 | /out/ 32 | /recipes/ 33 | 34 | # package files 35 | package.json 36 | package-lock.json 37 | 38 | # Json 39 | *.json 40 | 41 | # Build 42 | build 43 | out 44 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | require('@rushstack/eslint-patch/modern-module-resolution') 2 | 3 | module.exports = { 4 | root: true, 5 | env: { 6 | browser: true, 7 | es2021: true, 8 | node: true, 9 | }, 10 | extends: [ 11 | 'plugin:vue/vue3-essential', 12 | 'eslint:recommended', 13 | '@vue/eslint-config-typescript', 14 | '@vue/eslint-config-prettier/skip-formatting', 15 | ], 16 | parserOptions: { 17 | ecmaVersion: 'latest', 18 | }, 19 | rules: { 20 | 'vue/multi-word-component-names': [0], 21 | 'vue/require-default-prop': 0, // 不强制要求props默认值 22 | 'vue/require-direct-export': 1, // 要求导出组件 23 | 'vue/no-v-text': 1, // 禁止使用v-text 24 | 'vue/padding-line-between-blocks': 1, // 在vue组件中,要求在