├── .browserslistrc ├── .env.development ├── .env.production ├── .eslintrc.js ├── .gitignore ├── .prettierrc.js ├── .vscode └── settings.json ├── README.md ├── babel.config.js ├── gitImgs ├── 001.jpg ├── 002.png ├── 003.jpg └── 004.jpg ├── jsconfig.json ├── package-lock.json ├── package.json ├── pnpm-lock.yaml ├── public ├── favicon.ico └── index.html ├── src ├── App.vue ├── api │ ├── chat.js │ ├── emoticon.js │ ├── music.js │ └── user.js ├── assets │ ├── background.gif │ ├── css │ │ ├── common.less │ │ ├── font.less │ │ ├── index.less │ │ ├── reset.less │ │ ├── transition.css │ │ ├── variables.less │ │ └── visible.less │ ├── js │ │ ├── link.js │ │ └── tools.js │ ├── logo.gif │ └── logo.png ├── components │ ├── Barrage │ │ └── index.vue │ ├── ChatPopup │ │ └── index.vue │ ├── Emotion │ │ ├── Emotion.vue │ │ ├── emotion.js │ │ └── emotionImgs │ │ │ ├── 0.gif │ │ │ ├── 1.gif │ │ │ ├── 10.gif │ │ │ ├── 100.gif │ │ │ ├── 101.gif │ │ │ ├── 102.gif │ │ │ ├── 103.gif │ │ │ ├── 104.gif │ │ │ ├── 11.gif │ │ │ ├── 12.gif │ │ │ ├── 13.gif │ │ │ ├── 14.gif │ │ │ ├── 15.gif │ │ │ ├── 16.gif │ │ │ ├── 17.gif │ │ │ ├── 18.gif │ │ │ ├── 19.gif │ │ │ ├── 2.gif │ │ │ ├── 20.gif │ │ │ ├── 21.gif │ │ │ ├── 22.gif │ │ │ ├── 23.gif │ │ │ ├── 24.gif │ │ │ ├── 25.gif │ │ │ ├── 26.gif │ │ │ ├── 27.gif │ │ │ ├── 28.gif │ │ │ ├── 29.gif │ │ │ ├── 3.gif │ │ │ ├── 30.gif │ │ │ ├── 31.gif │ │ │ ├── 32.gif │ │ │ ├── 33.gif │ │ │ ├── 34.gif │ │ │ ├── 35.gif │ │ │ ├── 36.gif │ │ │ ├── 37.gif │ │ │ ├── 38.gif │ │ │ ├── 39.gif │ │ │ ├── 4.gif │ │ │ ├── 40.gif │ │ │ ├── 41.gif │ │ │ ├── 42.gif │ │ │ ├── 43.gif │ │ │ ├── 44.gif │ │ │ ├── 45.gif │ │ │ ├── 46.gif │ │ │ ├── 47.gif │ │ │ ├── 48.gif │ │ │ ├── 49.gif │ │ │ ├── 5.gif │ │ │ ├── 50.gif │ │ │ ├── 51.gif │ │ │ ├── 52.gif │ │ │ ├── 53.gif │ │ │ ├── 54.gif │ │ │ ├── 55.gif │ │ │ ├── 56.gif │ │ │ ├── 57.gif │ │ │ ├── 58.gif │ │ │ ├── 59.gif │ │ │ ├── 6.gif │ │ │ ├── 60.gif │ │ │ ├── 61.gif │ │ │ ├── 62.gif │ │ │ ├── 63.gif │ │ │ ├── 64.gif │ │ │ ├── 65.gif │ │ │ ├── 66.gif │ │ │ ├── 67.gif │ │ │ ├── 68.gif │ │ │ ├── 69.gif │ │ │ ├── 7.gif │ │ │ ├── 70.gif │ │ │ ├── 71.gif │ │ │ ├── 72.gif │ │ │ ├── 73.gif │ │ │ ├── 74.gif │ │ │ ├── 75.gif │ │ │ ├── 76.gif │ │ │ ├── 77.gif │ │ │ ├── 78.gif │ │ │ ├── 79.gif │ │ │ ├── 8.gif │ │ │ ├── 80.gif │ │ │ ├── 81.gif │ │ │ ├── 82.gif │ │ │ ├── 83.gif │ │ │ ├── 84.gif │ │ │ ├── 85.gif │ │ │ ├── 86.gif │ │ │ ├── 87.gif │ │ │ ├── 88.gif │ │ │ ├── 89.gif │ │ │ ├── 9.gif │ │ │ ├── 90.gif │ │ │ ├── 91.gif │ │ │ ├── 92.gif │ │ │ ├── 93.gif │ │ │ ├── 94.gif │ │ │ ├── 95.gif │ │ │ ├── 96.gif │ │ │ ├── 97.gif │ │ │ ├── 98.gif │ │ │ └── 99.gif │ ├── GlobalConfig │ │ └── index.vue │ ├── SvgIcon │ │ └── index.vue │ ├── bulletChat │ │ └── index.vue │ ├── chat │ │ ├── ChatHeader │ │ │ ├── components │ │ │ │ ├── OnLineList.vue │ │ │ │ ├── PersionInfo.vue │ │ │ │ ├── RoomList.vue │ │ │ │ └── RoomSetting.vue │ │ │ └── index.vue │ │ ├── ChatLrc │ │ │ └── index.vue │ │ ├── ChatMessageFrame │ │ │ └── index.vue │ │ ├── ChatProgress │ │ │ └── index.vue │ │ ├── ChatTips │ │ │ └── index.vue │ │ ├── ChatToolbar │ │ │ ├── components │ │ │ │ ├── ToolbarChooseMusic.vue │ │ │ │ ├── ToolbarCollect.vue │ │ │ │ ├── ToolbarEmotion.vue │ │ │ │ ├── ToolbarQueueMusic.vue │ │ │ │ └── WxPre.vue │ │ │ └── index.vue │ │ ├── MessagePanel │ │ │ └── index.vue │ │ └── MusicPlayer │ │ │ └── index.vue │ └── preImg │ │ └── index.vue ├── config │ └── index.js ├── icons │ ├── index.js │ └── svg │ │ ├── btn-loading.svg │ │ ├── char-frame-del.svg │ │ ├── chat-frame-unknow-file.svg │ │ ├── chat-go.svg │ │ ├── chat-header-setting.svg │ │ ├── chat-mine.svg │ │ ├── chat-online.svg │ │ ├── chat-panel-link.svg │ │ ├── chat-pre-close.svg │ │ ├── chat-pre-download.svg │ │ ├── chat-pre-recovert.svg │ │ ├── chat-room-info-lock.svg │ │ ├── chat-room-info-select.svg │ │ ├── chat-room-locked.svg │ │ ├── chat-room.svg │ │ ├── chat-share.svg │ │ ├── choose-music-empty.svg │ │ ├── choose-music-love.svg │ │ ├── choose-music-play.svg │ │ ├── close.svg │ │ ├── github.svg │ │ ├── icon-error.svg │ │ ├── icon-message.svg │ │ ├── icon-success.svg │ │ ├── icon-warning.svg │ │ ├── music.svg │ │ ├── progress-collect.svg │ │ ├── progress-music.svg │ │ ├── progress-switch.svg │ │ ├── queue-music-del.svg │ │ ├── queue-music-zan.svg │ │ ├── toolbar-hook.svg │ │ ├── toolbar-love.svg │ │ ├── toolbar-music.svg │ │ ├── toolbar-pic.svg │ │ ├── toolbar-search.svg │ │ └── toolbar-wx.svg ├── main.js ├── permission.js ├── router │ └── index.js ├── socket-io │ └── index.js ├── store │ ├── actions.js │ ├── default.js │ ├── getters.js │ ├── index.js │ ├── mutations.js │ └── state.js ├── theme │ ├── global.less │ ├── index.js │ └── modules │ │ ├── black.js │ │ ├── default.js │ │ └── transparent.js ├── utils │ ├── auth.js │ ├── axios.js │ ├── chat.js │ ├── request.js │ ├── tools.js │ ├── validate.js │ └── vue.prototype.js └── views │ ├── Chat │ └── index.vue │ ├── login.vue │ └── register.vue └── vue.config.js /.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not dead 4 | -------------------------------------------------------------------------------- /.env.development: -------------------------------------------------------------------------------- 1 | ENV = 'development' 2 | VUE_APP_BASE_API = 'http://localhost:3000/api' 3 | VUE_APP_WS_API = 'http://localhost:3000' 4 | -------------------------------------------------------------------------------- /.env.production: -------------------------------------------------------------------------------- 1 | ENV = 'production' 2 | VUE_APP_BASE_API = '/api' 3 | VUE_APP_WS_API = '/' 4 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: true, 4 | es2021: true, 5 | node: true 6 | }, 7 | extends: ['plugin:vue/recommended', 'airbnb-base', 'eslint-config-prettier'], 8 | plugins: ['import', 'eslint-plugin-prettier'], 9 | parserOptions: { 10 | ecmaVersion: 'latest', 11 | sourceType: 'module' 12 | }, 13 | rules: { 14 | 'prettier/prettier': 2, 15 | 'global-require': 0, 16 | 'import/extensions': 0, 17 | 'import/no-unresolved': 0, 18 | 'no-console': 2, 19 | 'func-names': 0, 20 | 'no-param-reassign': 0, 21 | 'import/no-extraneous-dependencies': 0, 22 | 'import/prefer-default-export': 0, 23 | 'vue/no-v-html': 0, 24 | 'import/no-cycle': 0, 25 | 'consistent-return': 0, 26 | 'no-return-assign': 0, 27 | 'no-shadow': 0, 28 | 'prefer-rest-params': 0, 29 | 'no-plusplus': 0, 30 | 'no-useless-escape': 0, 31 | radix: 0, 32 | camelcase: 0, 33 | 'vue/multi-word-component-names': 0, 34 | 'no-restricted-syntax': 0, 35 | 'vue/no-template-shadow': 0, 36 | 'no-unused-expressions': [ 37 | 2, 38 | { 39 | allowShortCircuit: true, 40 | allowTernary: true 41 | } 42 | ], 43 | 'no-tabs': [ 44 | 2, 45 | { 46 | allowIndentationTabs: true 47 | } 48 | ] 49 | }, 50 | globals: { 51 | log: true 52 | } 53 | }; 54 | -------------------------------------------------------------------------------- /.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 | *.suo 19 | *.ntvs* 20 | *.njsproj 21 | *.sln 22 | *.sw? 23 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | printWidth: 200, 3 | tabWidth: 2, 4 | useTabs: true, 5 | semi: true, 6 | singleQuote: true, 7 | trailingComma: "none", 8 | bracketSpacing: true, 9 | arrowParens: "avoid", 10 | eslintIntegration: false, 11 | vueIndentScriptAndStyle: false, 12 | embeddedLanguageFormatting: 'off', 13 | }; 14 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "eslint.validate": ["html", "vue", "javascript", "jsx"], 3 | "emmet.syntaxProfiles": { 4 | "vue-html": "html", 5 | "vue": "html" 6 | }, 7 | "eslint.alwaysShowStatus": true, 8 | "eslint.quiet": true, 9 | "editor.codeActionsOnSave": { 10 | "source.fixAll.eslint": "explicit", 11 | "source.fixAll": "explicit" 12 | }, 13 | "cSpell.words": [ 14 | "typeorm" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### 2.x版本已经更新 2 | 3 | ![](./gitImgs/002.png)![项目图片]( 4 | 5 | ### 项目地址 6 | 7 | * github *后端项目地址:[项目地址](https://github.com/longyanjiang/Nine-chat-backend.git)* 前端模块地址: [项目地址](https://github.com/longyanjiang/Nine-chat-frontend.git) 8 | * 项目 [线上体验地址](https://music-chat.mmmss.com/#/http://chat.jiangly.com/#) 9 | 10 | ## 项目迁移 11 | 12 | * 一台云服务器 13 | * 一个mysql服务器即可 14 | * 一个私有文件远程存储的接口 15 | 项目已经提供了测试数据,拉下项目可直接运行,**typeorm**可自动化建表,无需额外操作,修改数据库地址即可快速迁移完成。 16 | 17 | ### 项目启动 18 | 19 | * 项目采用了 orm 操作数据库、所以只需要在`.env 配置文件`中配置上自己的数据库、就会初始化成功、orm会自动创建所需要的数据库 20 | * 如果不想自己建表填入带有root权限的数据库账号密码可以自动化建库,也可以填写场景好的数据库账号密码即可 21 | * 项目提供了一个测试数据库、可以直接使用、账号密码都有配置、可以自行操作即可 22 | * 前端部分 `pnpm install` `pnpm dev` 23 | * 后端部分 `pnpm install` `pnpm dev` 启动后初次会自动创建 超级管理员( super 123456 ),自动创建888官方房间, 首次默认会自动往曲库添加部分歌曲,如果想要添加到聊天室,super账号搜索歌曲,收藏就会加入官方聊天室,也可以通过接口`getAlbumList`传入专辑id添加歌曲,也可以在开发环境添加,也可以搜索添加。 24 | * 项目为`DEMO项目`,未配置与验证邮箱,也没有详细配置权限装饰器,仅有基础权限。 25 | 26 | ### 图片文件上传说明 27 | 28 | * 默认文件会上传到public下的files目录,默认basic目录下会有基础图片,所以本地开发环境不会显示图片,使用的是相对路径图片,或者自己拼接, 29 | * 将前端项目打包后的dist文件内容放入public下面,即可只启动后端项目 3000端口即可同时访问前后端,图片即可正常 30 | 31 | ### 免责声明 32 | 33 | 平台音乐数据来源于第三方网站,仅供学习交流使用,请勿用于商业用途。 34 | 35 | ### 更新历史 36 | 37 | ```html 38 | 1.x: 39 | 1、普通文字聊天、粘贴图片发送、在线搜索表情包发送等聊天功能 40 | 2、在线搜索歌曲、点歌、切割、收藏歌曲 41 | 3、歌曲实时播放,所有人共享一个实时歌单、一起听歌 42 | 4、实时修改个人信息资料 43 | 5、支持自定义专属背景 44 | 6、快捷键等待你的探索 45 | 46 | 2.x: 2022051 47 | 1.新增个人私有房间,支持用户创建自己独立的房间了 48 | 2.新增图片或文件发送,可直接粘贴到输入框即可 49 | 3.支持消息引用,点击引用的消息会自动滚动到指定位置 50 | 4.上拉平滑加载更多[修复1.0]上拉抖动问题 51 | 5.新增消息两分钟内可撤回 52 | 6.划分三级权限 超级管理员>房主>普通用户 支持加密房间 53 | 7.新增夜间主题和透明主题,支持部分快捷操作 54 | 8.新增部分快捷键 55 | 56 | 更多功能等你来提... 57 | ``` 58 | 59 | ## 项目部分截图 60 | 61 | ![](./gitImgs/001.jpg) 62 | 63 | ![](./gitImgs/003.jpg) 64 | 65 | ![](./gitImgs/004.jpg) 66 | 67 | ### 基础技术栈 68 | 69 | * 前端采用 vue + socker-io 未使用ui框架 70 | * 后端采用 nestjs + typeorm + mysql + socket.io 71 | 72 | > 佛系更新 有需要请 `issues`提 看到有需要就更新、没有就GG 73 | 74 | ### 关于更新 75 | 76 | 详情功能看预览地址,有bug就留言,基础模型功能都有,可以自己二次开发。 77 | 78 | 有时间也会更新部分功能上去、尽量做到简洁、方便各位移植和部署。 79 | 80 | 有创意或想法可以提issues,采纳会回复更新。 81 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['@vue/cli-plugin-babel/preset'] 3 | }; 4 | -------------------------------------------------------------------------------- /gitImgs/001.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/gitImgs/001.jpg -------------------------------------------------------------------------------- /gitImgs/002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/gitImgs/002.png -------------------------------------------------------------------------------- /gitImgs/003.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/gitImgs/003.jpg -------------------------------------------------------------------------------- /gitImgs/004.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/gitImgs/004.jpg -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "./", 4 | "paths": { 5 | "@/*": ["src/*"] 6 | } 7 | }, 8 | "exclude": ["node_modules", "dist"] 9 | } 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "snine-chat-frontend", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "vue-cli-service serve --mode development", 7 | "dev:pro": "vue-cli-service serve --mode production", 8 | "build": "vue-cli-service build", 9 | "lint": "eslint --ext .js,.vue src", 10 | "lint:fix": "eslint --fix --ext .js,.vue src" 11 | }, 12 | "dependencies": { 13 | "core-js": "^3.6.5", 14 | "element-ui": "^2.15.7", 15 | "vue": "^2.6.11", 16 | "vue-router": "^3.2.0", 17 | "vuex": "^3.4.0" 18 | }, 19 | "devDependencies": { 20 | "@vue/cli-plugin-babel": "~4.5.0", 21 | "@vue/cli-plugin-router": "~4.5.0", 22 | "@vue/cli-plugin-vuex": "~4.5.0", 23 | "@vue/cli-service": "~4.5.0", 24 | "@vue/eslint-config-prettier": "^6.0.0", 25 | "axios": "^0.24.0", 26 | "babel-eslint": "^10.1.0", 27 | "clipboard": "^2.0.8", 28 | "eslint": "^8.10.0", 29 | "eslint-config-airbnb-base": "^15.0.0", 30 | "eslint-config-prettier": "^8.4.0", 31 | "eslint-plugin-import": "^2.25.4", 32 | "eslint-plugin-prettier": "^4.0.0", 33 | "eslint-plugin-vue": "^8.5.0", 34 | "less": "^3.0.4", 35 | "less-loader": "^5.0.0", 36 | "nprogress": "^0.2.0", 37 | "prettier": "^2.2.1", 38 | "socket.io-client": "^4.3.2", 39 | "style-resources-loader": "^1.5.0", 40 | "svg-sprite-loader": "^6.0.11", 41 | "vue-cli-plugin-style-resources-loader": "^0.1.5", 42 | "vue-custom-barrage": "^0.0.6", 43 | "vue-socket.io-extended": "^4.2.0", 44 | "vue-template-compiler": "^2.6.11", 45 | "xml-loader": "^1.2.1" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | <%= htmlWebpackPlugin.options.title %> 12 | 13 | 14 | <% if (process.env.NODE_ENV==='production' ) { %> 15 | 18 | <% } %> 19 | 20 | 21 | 22 | 26 |
27 | 28 | 29 | <% if (process.env.NODE_ENV==='production' ) { %> 30 | 39 | <% } %> 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 59 | 60 | 66 | -------------------------------------------------------------------------------- /src/api/chat.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request'; 2 | 3 | export const history = data => request('post', '/chat/history', data); 4 | 5 | export const createRoom = data => request('post', '/chat/createRoom', data); 6 | 7 | export const queryRoomInfo = data => request('get', '/chat/roomInfo', data); 8 | 9 | export const updateRoomInfo = data => request('post', '/chat/updateRoomInfo', data); 10 | -------------------------------------------------------------------------------- /src/api/emoticon.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request'; 2 | 3 | export const queryEmo = data => request('get', '/chat/emoticon', data); 4 | -------------------------------------------------------------------------------- /src/api/music.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request'; 2 | 3 | export const search = data => request('get', '/music/search', data); 4 | 5 | export const collectMusic = data => request('post', '/music/collectMusic', data); 6 | 7 | export const collectList = data => request('get', '/music/collectList', data); 8 | 9 | export const hot = data => request('get', '/music/hot', data); 10 | 11 | export const removeCollect = data => request('post', '/music/removeCollect', data); 12 | -------------------------------------------------------------------------------- /src/api/user.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request'; 2 | 3 | export const register = data => request('post', '/user/register', data); 4 | 5 | export const login = data => request('post', '/user/login', data); 6 | 7 | export const getInfo = data => request('get', '/user/getInfo', data); 8 | 9 | export const updateUserInfo = data => request('post', '/user/update', data); 10 | -------------------------------------------------------------------------------- /src/assets/background.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/assets/background.gif -------------------------------------------------------------------------------- /src/assets/css/common.less: -------------------------------------------------------------------------------- 1 | .flex_center { 2 | display: flex; 3 | justify-content: center; 4 | align-items: center; 5 | } 6 | 7 | .flex_between { 8 | display: flex; 9 | justify-content: space-between; 10 | align-items: center; 11 | } 12 | 13 | .flex_start { 14 | display: flex; 15 | align-items: center; 16 | justify-content: flex-start; 17 | } 18 | 19 | .flex_end { 20 | display: flex; 21 | align-items: center; 22 | justify-content: flex-end; 23 | } 24 | 25 | 26 | body { 27 | font-family: "webfont" !important; 28 | cursor: url(https://file.jiangly.com/images/34113113.png),default; 29 | } 30 | 31 | ::selection { 32 | color: #fff; 33 | background: @colorSuccess; 34 | text-shadow: none; 35 | } 36 | 37 | input.common-input { 38 | width: 100%; 39 | outline: none; 40 | margin: 5px 0; 41 | padding: 0 10px; 42 | line-height: 40px; 43 | height: 40px; 44 | font-size: 14px; 45 | background-color: @colorBgBody; 46 | border: 1px solid transparent; 47 | border-radius: 5px; 48 | } 49 | 50 | input.common-input:hover { 51 | background-color: lighten(@colorBgBody, 2%); 52 | } 53 | 54 | input.common-input:focus { 55 | border-color: @colorInfo; 56 | } 57 | 58 | textarea.common-textarea { 59 | width: 100%; 60 | outline: none; 61 | margin: 5px 0; 62 | padding: 10px; 63 | font-size: 14px; 64 | background-color: @colorBgBody; 65 | border: 1px solid transparent; 66 | border-radius: 5px; 67 | min-height: 40px; 68 | min-height: 100px; 69 | } 70 | 71 | textarea.common-textarea:hover { 72 | background-color: lighten(@colorBgBody, 2%); 73 | } 74 | 75 | textarea.common-textarea:focus { 76 | border-color: @colorInfo; 77 | } 78 | 79 | ::-webkit-scrollbar { 80 | display: none; 81 | } 82 | 83 | .s-1-line{ 84 | text-overflow: ellipsis; 85 | white-space: nowrap; 86 | overflow: hidden; 87 | } 88 | 89 | .m_l5{ 90 | margin-left: 5px; 91 | } 92 | 93 | .m_l10{ 94 | margin-left: 10px; 95 | } 96 | 97 | .m_l15{ 98 | margin-left: 15px; 99 | } 100 | 101 | .m_l20{ 102 | margin-left: 20px; 103 | } 104 | 105 | .m_l30{ 106 | margin-left: 30px; 107 | } 108 | 109 | .m_r5{ 110 | margin-right: 5px; 111 | } 112 | 113 | .m_r10{ 114 | margin-right: 10px; 115 | } 116 | 117 | .m_r15{ 118 | margin-right: 15px; 119 | } 120 | 121 | .m_r20{ 122 | margin-right: 20px; 123 | } 124 | 125 | .m_r30{ 126 | margin-top: 30px; 127 | } 128 | 129 | .m_t5{ 130 | margin-top: 5px; 131 | } 132 | 133 | .m_t10{ 134 | margin-top: 10px; 135 | } 136 | 137 | .m_t15{ 138 | margin-top: 15px; 139 | } 140 | 141 | .m_t20{ 142 | margin-top: 20px; 143 | } 144 | 145 | .m_t30{ 146 | margin-top: 30px; 147 | } 148 | 149 | .m_b5{ 150 | margin-bottom: 5px; 151 | } 152 | 153 | .m_b10{ 154 | margin-bottom: 10px; 155 | } 156 | 157 | .m_b15{ 158 | margin-bottom: 15px; 159 | } 160 | 161 | .m_b20{ 162 | margin-bottom: 20px; 163 | } 164 | 165 | .m_b30{ 166 | margin-bottom: 30px; 167 | } 168 | 169 | /* element 全局样式修改 */ 170 | 171 | /* 抽屉颜色 */ 172 | .el-drawer, .el-dialog, .el-message-box{ 173 | background-color: @message-drawer-bg-color !important; 174 | } 175 | 176 | .el-message-box{ 177 | border: 1px solid @message-drawer-bg-color !important; 178 | } 179 | 180 | .el-drawer__open .el-drawer.rtl{ 181 | background-color: rgba(@message-drawer-bg-color, .8); 182 | } 183 | 184 | .el-form-item__label, .el-radio, .el-drawer__header, .el-dialog__title, .el-message-box__content, .el-message-box__title, .el-popover__title{ 185 | color: @message-main-text-color !important; 186 | } 187 | .el-popover__title{ 188 | font-weight: 600 !important; 189 | } 190 | 191 | /* wxPre */ 192 | .el-popover{ 193 | background: @message-popup-bg-color !important; 194 | border-color: @message-popup-bg-color !important; 195 | } 196 | .el-popper .popper__arrow{ 197 | border-width: 0 !important; 198 | } 199 | .el-popper .popper__arrow::after{ 200 | border-width: 0 !important; 201 | } 202 | 203 | /* 弹窗 */ 204 | .el-dialog__body{ 205 | padding: 10px 20px !important; 206 | } 207 | 208 | /* 去掉dropdown的三角 */ 209 | .popper__arrow{ 210 | top: 0 !important; 211 | } 212 | 213 | /* 改变dropdown位置 */ 214 | .el-popper[x-placement^=bottom]{ 215 | margin-top: -15px !important; 216 | } -------------------------------------------------------------------------------- /src/assets/css/font.less: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'webfont'; 3 | font-display: swap; 4 | src: url('//at.alicdn.com/t/webfont_9pbijjfbiud.eot'); /* IE9*/ 5 | src: url('//at.alicdn.com/t/webfont_9pbijjfbiud.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ 6 | url('//at.alicdn.com/t/webfont_9pbijjfbiud.woff2') format('woff2'), 7 | url('//at.alicdn.com/t/webfont_9pbijjfbiud.woff') format('woff'), /* chrome、firefox */ 8 | url('//at.alicdn.com/t/webfont_9pbijjfbiud.ttf') format('truetype'), /* chrome、firefox、opera、Safari, Android, iOS 4.2+*/ 9 | url('//at.alicdn.com/t/webfont_9pbijjfbiud.svg#NotoSansHans-DemiLight') format('svg'); /* iOS 4.1- */ 10 | } -------------------------------------------------------------------------------- /src/assets/css/index.less: -------------------------------------------------------------------------------- 1 | @import './variables.less'; 2 | @import './common.less'; 3 | @import './transition.css'; 4 | @import './visible.less'; 5 | 6 | @import './reset.less'; 7 | -------------------------------------------------------------------------------- /src/assets/css/reset.less: -------------------------------------------------------------------------------- 1 | /* 参考 http://linxz.github.io/tianyizone/css_reset.html */ 2 | 3 | /* 清除默认的margin的属性值 */ 4 | body, 5 | blockquote, 6 | dd, 7 | dl, 8 | figure, 9 | form, 10 | p, 11 | pre, 12 | h1, 13 | h2, 14 | h3, 15 | h4, 16 | h5, 17 | h6 { 18 | margin: 0; 19 | } 20 | 21 | /* 统一设置列表的margin和padding,以及列表表形式 */ 22 | menu, 23 | ul, 24 | ol { 25 | list-style: none; 26 | margin: 0; 27 | padding: 0; 28 | } 29 | 30 | /* 全局定义字体以及页面背景 */ 31 | body { 32 | font: 14px/1.5 'Helvetica Neue', Helvetica, Arial, 'Microsoft Yahei', 33 | 'Hiragino Sans GB', 'Heiti SC', 'WenQuanYi Micro Hei', sans-serif; 34 | background-color: @colorBgBody; 35 | word-spacing: 1px; 36 | -webkit-font-smoothing: antialiased; 37 | } 38 | 39 | h1, 40 | h2, 41 | h3, 42 | h4, 43 | h5, 44 | h6, 45 | input, 46 | button, 47 | select, 48 | textarea { 49 | font-size: 18px; 50 | } 51 | 52 | /* 设置字体大小 */ 53 | input[type='button'], 54 | input[type='submit'], 55 | input[type='reset'] { 56 | font-size: 16px; 57 | } 58 | 59 | /* 设置字体大小,这部分跟前面写在一起,IE6中会无效 */ 60 | 61 | /* 字体控制 */ 62 | body, 63 | input, 64 | button, 65 | select, 66 | optgroup, 67 | option, 68 | textarea, 69 | pre { 70 | font-family: 'Helvetica Neue', Helvetica, Arial, 'Microsoft Yahei', 71 | 'Hiragino Sans GB', 'Heiti SC', 'WenQuanYi Micro Hei', sans-serif; 72 | } 73 | 74 | /* 设置iframe的背景色以及去除个别浏览器iframe底部的几个像素 */ 75 | iframe { 76 | background-color: #fff; 77 | vertical-align: middle; 78 | } 79 | 80 | /* 设置文本链接样式 */ 81 | a { 82 | color: inherit; 83 | text-decoration: none; 84 | } 85 | 86 | a:hover { 87 | text-decoration: none; 88 | } 89 | 90 | /* 去除个别浏览器图片底部的几个像素,以及设置图片形式链接无边框 */ 91 | img { 92 | vertical-align: middle; 93 | } 94 | 95 | a img { 96 | border: 0 none; 97 | } 98 | 99 | /* 设置表单元素的样式 */ 100 | fieldset { 101 | margin: 0; 102 | padding: 0; 103 | } 104 | 105 | legend { 106 | color: windowtext; 107 | } 108 | 109 | 110 | /* 尽量统一按钮的大小,鉴于IE6不支持【属性选择符】,所以使用一个类名来控制 */ 111 | input[type='submit'], 112 | input[type='reset'] { 113 | overflow: visible; 114 | padding: 0.1em 0.25em; 115 | cursor: pointer; 116 | } 117 | 118 | /* 尽量统一按钮的大小,如果采用input方式做的按钮 */ 119 | select, 120 | textarea { 121 | background-color: #fff; 122 | } 123 | 124 | /* 统一文本输入框、下拉、文本框的背景色,避免被用户设置系统颜色而破坏页面色彩 */ 125 | select { 126 | border: 1px inset; 127 | } 128 | 129 | /* 统一下拉的边框 */ 130 | textarea { 131 | overflow: auto; 132 | vertical-align: text-bottom; 133 | *vertical-align: auto; 134 | border: 1px solid; 135 | resize: vertical; 136 | } 137 | 138 | /* 滚动条为auto,与周边的元素对齐方式,其中hack部分是IE6&7中vertical-align影响范围清除,resize为上下可拉动,避免左右拉动破坏页面布局,如有需要可以设置为none */ 139 | 140 | /* 设置表格元素的样式 */ 141 | table { 142 | border-spacing: 0; 143 | } 144 | 145 | /* 合并表格的间隙,去掉单元格之间的间距,如有需要合并单元格为细线表格,可增加 border-collapse:collapse; */ 146 | td, 147 | th, 148 | caption { 149 | padding: 0; 150 | } 151 | 152 | /* 去除单元格以及caption表头的padding值 */ 153 | -------------------------------------------------------------------------------- /src/assets/css/transition.css: -------------------------------------------------------------------------------- 1 | .page-enter-active, 2 | .page-leave-active { 3 | transition: opacity 0.3s ease; 4 | } 5 | .page-enter, 6 | .page-leave-active { 7 | opacity: 0; 8 | } 9 | 10 | .fade-enter, 11 | .fade-leave-to { 12 | opacity: 0; 13 | } 14 | .fade-enter-active, 15 | .fade-leave-active { 16 | transition: all 0.3s ease; 17 | } 18 | 19 | /* 弹框面板 */ 20 | .popup-box-enter, 21 | .popup-box-leave-to { 22 | opacity: 0; 23 | transform: scale(.8); 24 | } 25 | .popup-box-enter-active, 26 | .popup-box-leave-active { 27 | transition: all 0.3s ease; 28 | } 29 | 30 | 31 | /* 聊天面板 */ 32 | .message-panel-enter, 33 | .message-panel-leave-to { 34 | opacity: 0; 35 | transform: translateY(100%); 36 | } 37 | .message-panel-enter-active, 38 | .message-panel-leave-active { 39 | transition: all 0.3s ease; 40 | } 41 | 42 | .transform-enter, 43 | .transform-leave-to { 44 | transform: translateY(20px); 45 | opacity: 0; 46 | } 47 | .transform-enter-active, 48 | .transform-leave-active { 49 | transition: all 0.4s ease; 50 | } 51 | 52 | .z-load-loop { 53 | -webkit-animation: ani-load-loop 1s linear infinite; 54 | animation: ani-load-loop 1s linear infinite; 55 | } 56 | 57 | @keyframes ani-load-loop { 58 | 0% { 59 | -webkit-transform: rotate(0); 60 | transform: rotate(0); 61 | } 62 | 63 | 50% { 64 | -webkit-transform: rotate(180deg); 65 | transform: rotate(180deg); 66 | } 67 | 68 | to { 69 | -webkit-transform: rotate(1turn); 70 | transform: rotate(1turn); 71 | } 72 | } 73 | 74 | .msg-tips-enter, 75 | .msg-tips-leave-to { 76 | transform: translateY(20px); 77 | opacity: 0; 78 | } 79 | 80 | .msg-tips-enter-active, 81 | .msg-tips-leave-active { 82 | transition: all 0.5s ease; 83 | } 84 | 85 | .msg-tips-enter, 86 | .msg-tips-leave-to { 87 | transform: translateY(20px); 88 | opacity: 0; 89 | } 90 | .msg-tips-enter-active, 91 | .msg-tips-leave-active { 92 | transition: all 0.5s ease; 93 | } -------------------------------------------------------------------------------- /src/assets/css/variables.less: -------------------------------------------------------------------------------- 1 | /* ===== 主题色配置 ===== */ 2 | @colorPrimary: #6bc30d; 3 | @colorPrimaryLight: lighten(@colorPrimary, 8%); 4 | @colorPrimaryDark: darken(@colorPrimary, 8%); 5 | @colorPrimaryFade: fade(@colorPrimary, 8%); 6 | 7 | @colorAssist: #2db7f5; 8 | @colorAssistLight: lighten(@colorAssist, 8%); 9 | @colorAssistDark: darken(@colorAssist, 8%); 10 | @colorAssistFade: fade(@colorAssist, 8%); 11 | 12 | @colorSuccess: #67c23a; 13 | @colorSuccessLight: lighten(@colorSuccess, 8%); 14 | @colorSuccessDark: darken(@colorSuccess, 8%); 15 | @colorSuccessFade: fade(@colorSuccess, 8%); 16 | 17 | @colorWarning: #e6a23c; 18 | @colorWarningLight: lighten(@colorWarning, 8%); 19 | @colorWarningDark: darken(@colorWarning, 8%); 20 | @colorWarningFade: fade(@colorWarning, 8%); 21 | 22 | @colorError: #f56c6c; 23 | @colorErrorLight: lighten(@colorError, 8%); 24 | @colorErrorDark: darken(@colorError, 8%); 25 | @colorErrorFade: fade(@colorError, 8%); 26 | 27 | @colorInfo: #909399; 28 | @colorInfoLight: lighten(@colorInfo, 8%); 29 | @colorInfoDark: darken(@colorInfo, 8%); 30 | @colorInfoFade: fade(@colorInfo, 8%); 31 | 32 | @color: linear-gradient(90deg, @colorAssist, @colorPrimary); 33 | @colorReverse: linear-gradient(270deg, @colorAssist, @colorPrimary); 34 | @colorCol: linear-gradient(@colorAssist, @colorPrimary); 35 | @colorActive: { 36 | background-image: @color; 37 | background-clip: text; 38 | -webkit-background-clip: text; 39 | -webkit-text-fill-color: transparent; 40 | box-decoration-break: clone; 41 | 42 | @media screen and (max-width: @breakpoints-sm) { 43 | max-width: @containerMaxWidth-sm; 44 | color: #fff; 45 | background-clip: none; 46 | -webkit-text-fill-color: @colorPrimary; 47 | } 48 | 49 | } 50 | 51 | 52 | /* ===== 字体颜色配置 ===== */ 53 | @colorTextTitle: #282828; 54 | @colorTextContent: #414240; 55 | @colorTextSub: #808695; 56 | @colorTextLight: #aeaeae; 57 | @colorTextDisable: #c5c8ce; 58 | @colorTextSilver: #f1f1f1; 59 | @colorTextWhite: #ffffff; 60 | @colorFooterText: #60606d; 61 | 62 | /* ===== 边框颜色配置 ===== */ 63 | @colorBorder: #eaeaea; 64 | @colorBorderLight: fade(@colorBorder, 50%); 65 | 66 | /* ===== 背景颜色配置 ===== */ 67 | @colorBgBody: #efefee; 68 | @colorBg: #ffffff; 69 | 70 | @colorBgSideMenu: #363D4D; 71 | @colorBgSideMenuItemActive: #474C5E; 72 | 73 | /* ===== 各种高度配置 ===== */ 74 | @heightHeader: 60px; 75 | @heightFooter: 230px; 76 | 77 | /* ===== 响应式相关变量 ===== */ 78 | // 前缀名称 79 | @prefix: s; 80 | // 容器名 81 | @container: container; 82 | // 行名 83 | @row-name: row; 84 | // 列名 85 | @columns-name: col; 86 | // 列边距 87 | @columns-padding: 8px; 88 | // 栅格数 89 | @grid-count: 60; 90 | 91 | // 断点配置 92 | @breakpoints-xs: 0; 93 | // 0 - 576 Small screen / phone 94 | @breakpoints-sm: 576px; 95 | // 576 - 768 Medium screen / tablet 96 | @breakpoints-md: 768px; 97 | // 768 - 992 Large screen / desktop 98 | @breakpoints-lg: 992px; 99 | // 992 - 1200 Extra large screen / wide desktop 100 | @breakpoints-xl: 1200px; 101 | 102 | // 容器宽度配置 103 | @containerMaxWidth-xs: 0; 104 | @containerMaxWidth-sm: 640px; 105 | @containerMaxWidth-md: 767px; 106 | @containerMaxWidth-lg: 970px; 107 | @containerMaxWidth-xl: 1280px; 108 | -------------------------------------------------------------------------------- /src/assets/css/visible.less: -------------------------------------------------------------------------------- 1 | /* ===== 定义元素显示的方式 ===== */ 2 | .responsive-visibility() { 3 | display: block !important; 4 | table& { display: table !important; } 5 | tr& { display: table-row !important; } 6 | th&, 7 | td& { display: table-cell !important; } 8 | } 9 | 10 | /* ===== 定义元素隐藏的方式 ===== */ 11 | .responsive-invisibility() { 12 | display: none !important; 13 | } 14 | 15 | /* ===== 默认影藏 ===== */ 16 | .visible-xs, 17 | .visible-xs-block, 18 | .visible-xs-inline, 19 | .visible-xs-inline-block, 20 | .visible-sm, 21 | .visible-sm-block, 22 | .visible-sm-inline, 23 | .visible-sm-inline-block, 24 | .visible-md, 25 | .visible-md-block, 26 | .visible-md-inline, 27 | .visible-md-inline-block, 28 | .visible-lg, 29 | .visible-lg-block, 30 | .visible-lg-inline, 31 | .visible-lg-inline-block, 32 | .visible-xl, 33 | .visible-xl-block, 34 | .visible-xl-inline, 35 | .visible-xl-inline-block { 36 | display: none !important; 37 | } 38 | 39 | .visible-xs { 40 | @media (min-width: @breakpoints-xs) and (max-width: @breakpoints-sm) { 41 | .responsive-visibility(); 42 | } 43 | } 44 | .visible-xs-block { 45 | @media (min-width: @breakpoints-xs) and (max-width: @breakpoints-sm) { 46 | display: block !important; 47 | } 48 | } 49 | .visible-xs-inline { 50 | @media (min-width: @breakpoints-xs) and (max-width: @breakpoints-sm) { 51 | display: inline !important; 52 | } 53 | } 54 | .visible-xs-inline-block { 55 | @media (min-width: @breakpoints-xs) and (max-width: @breakpoints-sm) { 56 | display: inline-block !important; 57 | } 58 | } 59 | 60 | .visible-sm { 61 | @media (min-width: @breakpoints-sm) and (max-width: @breakpoints-md) { 62 | .responsive-visibility(); 63 | } 64 | } 65 | 66 | .visible-sm-block { 67 | @media (min-width: @breakpoints-sm) and (max-width: @breakpoints-md) { 68 | display: block !important; 69 | } 70 | } 71 | 72 | .visible-sm-inline { 73 | @media (min-width: @breakpoints-sm) and (max-width: @breakpoints-md) { 74 | display: inline !important; 75 | } 76 | } 77 | 78 | .visible-sm-inline-block { 79 | @media (min-width: @breakpoints-sm) and (max-width: @breakpoints-md) { 80 | display: inline-block !important; 81 | } 82 | } 83 | 84 | .visible-md { 85 | @media (min-width: @breakpoints-md) and (max-width: @breakpoints-lg) { 86 | .responsive-visibility(); 87 | } 88 | } 89 | 90 | .visible-md-block { 91 | @media (min-width: @breakpoints-md) and (max-width: @breakpoints-lg) { 92 | display: block !important; 93 | } 94 | } 95 | 96 | .visible-md-inline { 97 | @media (min-width: @breakpoints-md) and (max-width: @breakpoints-lg) { 98 | display: inline !important; 99 | } 100 | } 101 | .visible-md-inline-block { 102 | @media (min-width: @breakpoints-md) and (max-width: @breakpoints-lg) { 103 | display: inline-block !important; 104 | } 105 | } 106 | 107 | .visible-lg { 108 | @media (min-width: @breakpoints-lg) and (max-width: @breakpoints-xl) { 109 | .responsive-visibility(); 110 | } 111 | } 112 | .visible-lg-block { 113 | @media (min-width: @breakpoints-lg) and (max-width: @breakpoints-xl) { 114 | display: block !important; 115 | } 116 | } 117 | .visible-lg-inline { 118 | @media (min-width: @breakpoints-lg) and (max-width: @breakpoints-xl) { 119 | display: inline !important; 120 | } 121 | } 122 | .visible-lg-inline-block { 123 | @media (min-width: @breakpoints-lg) and (max-width: @breakpoints-xl) { 124 | display: inline-block !important; 125 | } 126 | } 127 | 128 | .visible-xl { 129 | @media (min-width: @breakpoints-xl) { 130 | .responsive-visibility(); 131 | } 132 | } 133 | .visible-xl-block { 134 | @media (min-width: @breakpoints-xl) { 135 | display: block !important; 136 | } 137 | } 138 | .visible-xl-inline { 139 | @media (min-width: @breakpoints-xl) { 140 | display: inline !important; 141 | } 142 | } 143 | .visible-xl-inline-block { 144 | @media (min-width: @breakpoints-xl) { 145 | display: inline-block !important; 146 | } 147 | } 148 | 149 | 150 | .hidden-xs { 151 | @media (min-width: @breakpoints-xs) and (max-width: @breakpoints-sm) { 152 | .responsive-invisibility(); 153 | } 154 | } 155 | .hidden-sm { 156 | @media (min-width: @breakpoints-sm) and (max-width: @breakpoints-md) { 157 | .responsive-invisibility(); 158 | } 159 | } 160 | .hidden-md { 161 | @media (min-width: @breakpoints-md) and (max-width: @breakpoints-lg) { 162 | .responsive-invisibility(); 163 | } 164 | } 165 | .hidden-lg { 166 | @media (min-width: @breakpoints-lg) and (max-width: @breakpoints-xl) { 167 | .responsive-invisibility(); 168 | } 169 | } 170 | .hidden-xl { 171 | @media (min-width: @breakpoints-xl) { 172 | .responsive-invisibility(); 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /src/assets/js/link.js: -------------------------------------------------------------------------------- 1 | import { oneOf } from '@/assets/js/tools'; 2 | 3 | export default { 4 | props: { 5 | to: { 6 | type: [Object, String] 7 | }, 8 | replace: { 9 | type: Boolean, 10 | default: false 11 | }, 12 | target: { 13 | type: String, 14 | validator(value) { 15 | return oneOf(value, ['_blank', '_self', '_parent', '_top']); 16 | }, 17 | default: '_self' 18 | }, 19 | append: { 20 | type: Boolean, 21 | required: false, 22 | default: false 23 | } 24 | }, 25 | computed: { 26 | linkUrl() { 27 | const type = typeof this.to; 28 | if (type !== 'string') { 29 | return null; 30 | } 31 | if (this.to.includes('//')) { 32 | /* Absolute URL, we do not need to route this */ 33 | return this.to; 34 | } 35 | const router = this.$router; 36 | if (router) { 37 | const current = this.$route; 38 | const route = router.resolve(this.to, current, this.append); 39 | return route ? route.href : this.to; 40 | } 41 | return this.to; 42 | } 43 | }, 44 | methods: { 45 | handleClick(newWindow = false) { 46 | const router = this.$router; 47 | 48 | if (newWindow) { 49 | let { to } = this; 50 | if (router) { 51 | const current = this.$route; 52 | const route = router.resolve(this.to, current, this.append); 53 | to = route ? route.href : this.to; 54 | } 55 | window.open(to); 56 | } else if (router) { 57 | this.replace ? this.$router.replace(this.to) : this.$router.push(this.to); 58 | } else { 59 | window.location.href = this.to; 60 | } 61 | }, 62 | handleCheckClick(event, newWindow = false) { 63 | if (this.to) { 64 | if (this.target === '_blank') { 65 | return false; 66 | } 67 | event.preventDefault(); 68 | this.handleClick(newWindow); 69 | } 70 | } 71 | } 72 | }; 73 | -------------------------------------------------------------------------------- /src/assets/js/tools.js: -------------------------------------------------------------------------------- 1 | // https://www.cnblogs.com/momo798/p/9177767.html 2 | 3 | /** 4 | * @desc 防抖 如 input。核心:在给定的时间间隔内 只触发一次 取消上一次。连续的操作 只触发一次。 5 | */ 6 | export const debounce = (fn, wait = 500) => { 7 | let timer = null; 8 | 9 | return function () { 10 | clearTimeout(timer); 11 | timer = setTimeout(() => { 12 | fn.apply(this, arguments); 13 | }, wait); 14 | // timer = setTimeout(fn, wait); 15 | }; 16 | }; 17 | 18 | /** 19 | * @desc 节流 对高频事件的优化 如 scroll。 20 | * 与防抖区别:防抖在连续的操作过程中只触发一次,而节流可能触发多次,但是频率变低了。 21 | */ 22 | export const throttle = (fn, interval = 300) => { 23 | let timer = null; 24 | let timeStart = new Date(); 25 | 26 | return function () { 27 | const now = new Date(); 28 | const space = now - timeStart; 29 | if (space > interval) { 30 | fn.apply(this, arguments); 31 | timeStart = now; 32 | } else { 33 | clearTimeout(timer); 34 | timer = setTimeout(() => { 35 | // 这个 时候 currentTarget 为 null 36 | fn.apply(this, arguments); 37 | }, interval); 38 | } 39 | }; 40 | }; 41 | 42 | /** 43 | * @desc 节流(定时器方案) 对高频事件的优化 如 scroll。核心:间隔时间内 打开可执行标志。 44 | * 优点:确保最终结果,因为是延迟执行。 45 | * 缺点:不能马上触发 (方向键操作试下) 46 | */ 47 | export const throttle1 = (fn, interval = 1000) => { 48 | let timer = null; 49 | return function () { 50 | if (!timer) { 51 | timer = setTimeout(() => { 52 | fn.apply(this, arguments); 53 | clearTimeout(timer); 54 | timer = null; 55 | }, interval); 56 | } 57 | }; 58 | }; 59 | 60 | /** 61 | * @desc 节流(时间戳方案) 对高频事件的优化 如 scroll。 核心: 每隔给定时间,触发一次。 62 | * 优点:立即触发 63 | * 缺点:如果上一次停止操作的时间 跟下次操作时间没有超过给定的时间 将不会触发。(时间设置大一点 方向键操作试下) 64 | */ 65 | export const throttle2 = (fn, interval = 2000) => { 66 | let timeStart = new Date(); 67 | return function () { 68 | const now = new Date(); 69 | if (now - timeStart > interval) { 70 | fn.apply(this, arguments); 71 | timeStart = now; 72 | } 73 | }; 74 | }; 75 | 76 | /** 77 | * @desc 检测是不是空对象 78 | */ 79 | export const isEmptyObject = obj => obj && Object.keys(obj).length === 0; 80 | 81 | /** 82 | * @desc url 上获取参数 83 | */ 84 | export const getQueryString = name => { 85 | const reg = new RegExp(`(^|&)${name}=([^&]*)(&|$)`, 'i'); 86 | const regRewrite = new RegExp(`(^|/)${name}/([^/]*)(/|$)`, 'i'); 87 | const r = window.location.search.substr(1).match(reg); 88 | const q = window.location.pathname.substr(1).match(regRewrite); 89 | if (r != null) { 90 | return unescape(r[2]); 91 | } 92 | if (q != null) { 93 | return unescape(q[2]); 94 | } 95 | return null; 96 | }; 97 | 98 | /** 99 | * @desc 检测 value 是否在 validList 中 100 | * @param value 需要检测的值 101 | * @param validList 检测列表 102 | */ 103 | export function oneOf(value, validList) { 104 | for (let i = 0; i < validList.length; i++) { 105 | if (value === validList[i]) { 106 | return true; 107 | } 108 | } 109 | return false; 110 | } 111 | -------------------------------------------------------------------------------- /src/assets/logo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/assets/logo.gif -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/assets/logo.png -------------------------------------------------------------------------------- /src/components/Barrage/index.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 84 | 110 | -------------------------------------------------------------------------------- /src/components/ChatPopup/index.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 84 | 129 | -------------------------------------------------------------------------------- /src/components/Emotion/Emotion.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 49 | 50 | 88 | -------------------------------------------------------------------------------- /src/components/Emotion/emotion.js: -------------------------------------------------------------------------------- 1 | export const emotionData = [ 2 | { id: 0, text: '微笑' }, 3 | { id: 1, text: '撇嘴' }, 4 | { id: 2, text: '色' }, 5 | { id: 3, text: '发呆' }, 6 | { id: 4, text: '得意' }, 7 | { id: 5, text: '流泪' }, 8 | { id: 6, text: '害羞' }, 9 | { id: 7, text: '闭嘴' }, 10 | { id: 8, text: '睡' }, 11 | { id: 9, text: '大哭' }, 12 | { id: 10, text: '尴尬' }, 13 | { id: 11, text: '发怒' }, 14 | { id: 12, text: '调皮' }, 15 | { id: 13, text: '呲牙' }, 16 | { id: 14, text: '惊讶' }, 17 | { id: 15, text: '难过' }, 18 | { id: 16, text: '酷' }, 19 | { id: 17, text: '冷汗' }, 20 | { id: 18, text: '抓狂' }, 21 | { id: 19, text: '吐' }, 22 | { id: 20, text: '偷笑' }, 23 | { id: 21, text: '可爱' }, 24 | { id: 22, text: '白眼' }, 25 | { id: 23, text: '傲慢' }, 26 | { id: 24, text: '饥饿' }, 27 | { id: 25, text: '困' }, 28 | { id: 26, text: '惊恐' }, 29 | { id: 27, text: '流汗' }, 30 | { id: 28, text: '憨笑' }, 31 | { id: 29, text: '大兵' }, 32 | { id: 30, text: '奋斗' }, 33 | { id: 31, text: '咒骂' }, 34 | { id: 32, text: '疑问' }, 35 | { id: 33, text: '嘘' }, 36 | { id: 34, text: '晕' }, 37 | { id: 35, text: '折磨' }, 38 | { id: 36, text: '衰' }, 39 | { id: 37, text: '骷髅' }, 40 | { id: 38, text: '敲打' }, 41 | { id: 39, text: '再见' }, 42 | { id: 40, text: '擦汗' }, 43 | { id: 41, text: '抠鼻' }, 44 | { id: 42, text: '鼓掌' }, 45 | { id: 43, text: '糗大了' }, 46 | { id: 44, text: '坏笑' }, 47 | { id: 45, text: '左哼哼' }, 48 | { id: 46, text: '右哼哼' }, 49 | { id: 47, text: '哈欠' }, 50 | { id: 48, text: '鄙视' }, 51 | { id: 49, text: '委屈' }, 52 | { id: 50, text: '快哭了' }, 53 | { id: 51, text: '阴险' }, 54 | { id: 52, text: '亲亲' }, 55 | { id: 53, text: '吓' }, 56 | { id: 54, text: '可怜' }, 57 | { id: 55, text: '菜刀' }, 58 | { id: 56, text: '西瓜' }, 59 | { id: 57, text: '啤酒' }, 60 | { id: 58, text: '篮球' }, 61 | { id: 59, text: '乒乓' }, 62 | { id: 60, text: '咖啡' }, 63 | { id: 61, text: '饭' }, 64 | { id: 62, text: '猪头' }, 65 | { id: 63, text: '玫瑰' }, 66 | { id: 64, text: '凋谢' }, 67 | { id: 65, text: '示爱' }, 68 | { id: 66, text: '爱心' }, 69 | { id: 67, text: '心碎' }, 70 | { id: 68, text: '蛋糕' }, 71 | { id: 69, text: '闪电' }, 72 | { id: 70, text: '炸弹' }, 73 | { id: 71, text: '刀' }, 74 | { id: 72, text: '足球' }, 75 | { id: 73, text: '瓢虫' }, 76 | { id: 74, text: '便便' }, 77 | { id: 75, text: '月亮' }, 78 | { id: 76, text: '太阳' }, 79 | { id: 77, text: '礼物' }, 80 | { id: 78, text: '拥抱' }, 81 | { id: 79, text: '强' }, 82 | { id: 80, text: '弱' }, 83 | { id: 81, text: '握手' }, 84 | { id: 82, text: '胜利' }, 85 | { id: 83, text: '抱拳' }, 86 | { id: 84, text: '勾引' }, 87 | { id: 85, text: '拳头' }, 88 | { id: 86, text: '差劲' }, 89 | { id: 87, text: '爱你' }, 90 | { id: 88, text: 'NO' }, 91 | { id: 89, text: 'OK' }, 92 | { id: 90, text: '爱情' }, 93 | { id: 91, text: '飞吻' }, 94 | { id: 92, text: '跳跳' }, 95 | { id: 93, text: '发抖' }, 96 | { id: 94, text: '怄火' }, 97 | { id: 95, text: '转圈' }, 98 | { id: 96, text: '磕头' }, 99 | { id: 97, text: '回头' }, 100 | { id: 98, text: '跳绳' }, 101 | { id: 99, text: '挥手' }, 102 | { id: 100, text: '激动' }, 103 | { id: 101, text: '街舞' }, 104 | { id: 102, text: '献吻' }, 105 | { id: 103, text: '左太极' }, 106 | { id: 104, text: '右太极' } 107 | ]; 108 | 109 | export function getImgUrl(id) { 110 | // eslint-disable-next-line import/no-dynamic-require 111 | return require(`@/components/Emotion/emotionImgs/${id}.gif`); 112 | } 113 | 114 | export function emotion(res) { 115 | const word = res.replace(/\[|\]/gi, ''); 116 | let index = -1; 117 | emotionData.forEach(item => { 118 | if (item.text === word) { 119 | index = item.id; 120 | } 121 | }); 122 | if (index >= 0) { 123 | const url = getImgUrl(index); 124 | return ``; 125 | } 126 | } 127 | 128 | export function replaceEmotionText(content) { 129 | if(!content) return '' 130 | return content.replace(/<\/?.+?>/g, '').replace(/\[[\u4E00-\u9FA5]{1,3}\]/gi, emotion); 131 | } 132 | 133 | // export { emotionData, getImgUrl, replaceEmotionText } 134 | -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/0.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/0.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/1.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/10.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/10.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/100.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/100.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/101.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/101.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/102.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/102.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/103.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/103.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/104.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/104.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/11.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/11.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/12.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/12.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/13.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/13.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/14.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/14.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/15.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/15.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/16.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/16.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/17.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/17.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/18.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/18.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/19.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/19.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/2.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/20.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/20.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/21.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/21.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/22.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/22.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/23.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/23.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/24.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/24.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/25.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/25.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/26.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/26.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/27.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/27.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/28.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/28.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/29.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/29.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/3.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/30.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/30.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/31.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/31.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/32.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/32.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/33.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/33.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/34.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/34.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/35.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/35.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/36.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/36.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/37.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/37.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/38.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/38.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/39.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/39.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/4.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/40.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/40.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/41.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/41.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/42.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/42.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/43.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/43.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/44.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/44.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/45.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/45.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/46.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/46.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/47.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/47.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/48.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/48.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/49.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/49.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/5.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/50.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/50.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/51.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/51.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/52.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/52.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/53.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/53.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/54.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/54.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/55.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/55.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/56.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/56.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/57.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/57.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/58.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/58.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/59.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/59.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/6.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/6.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/60.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/60.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/61.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/61.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/62.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/62.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/63.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/63.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/64.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/64.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/65.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/65.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/66.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/66.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/67.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/67.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/68.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/68.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/69.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/69.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/7.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/7.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/70.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/70.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/71.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/71.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/72.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/72.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/73.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/73.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/74.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/74.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/75.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/75.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/76.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/76.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/77.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/77.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/78.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/78.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/79.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/79.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/8.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/8.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/80.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/80.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/81.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/81.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/82.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/82.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/83.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/83.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/84.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/84.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/85.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/85.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/86.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/86.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/87.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/87.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/88.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/88.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/89.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/89.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/9.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/9.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/90.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/90.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/91.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/91.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/92.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/92.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/93.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/93.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/94.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/94.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/95.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/95.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/96.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/96.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/97.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/97.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/98.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/98.gif -------------------------------------------------------------------------------- /src/components/Emotion/emotionImgs/99.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CooperJiang/Nine-chat-frontend/d90ee3263dc59db7e0fc6df1fef78e7c40be1ad5/src/components/Emotion/emotionImgs/99.gif -------------------------------------------------------------------------------- /src/components/GlobalConfig/index.vue: -------------------------------------------------------------------------------- 1 | 48 | 49 | 152 | 159 | -------------------------------------------------------------------------------- /src/components/SvgIcon/index.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 53 | 54 | 69 | -------------------------------------------------------------------------------- /src/components/bulletChat/index.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 26 | 41 | -------------------------------------------------------------------------------- /src/components/chat/ChatHeader/components/OnLineList.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 45 | 46 | 107 | -------------------------------------------------------------------------------- /src/components/chat/ChatHeader/components/PersionInfo.vue: -------------------------------------------------------------------------------- 1 | 38 | 39 | 165 | 215 | -------------------------------------------------------------------------------- /src/components/chat/ChatLrc/index.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 38 | 39 | 63 | -------------------------------------------------------------------------------- /src/components/chat/ChatProgress/index.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 41 | 94 | -------------------------------------------------------------------------------- /src/components/chat/ChatTips/index.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 50 | 87 | -------------------------------------------------------------------------------- /src/components/chat/ChatToolbar/components/ToolbarChooseMusic.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 94 | 208 | -------------------------------------------------------------------------------- /src/components/chat/ChatToolbar/components/ToolbarCollect.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 57 | 126 | -------------------------------------------------------------------------------- /src/components/chat/ChatToolbar/components/ToolbarEmotion.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 80 | 155 | -------------------------------------------------------------------------------- /src/components/chat/ChatToolbar/components/ToolbarQueueMusic.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 41 | 104 | -------------------------------------------------------------------------------- /src/components/chat/ChatToolbar/components/WxPre.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 18 | 19 | 33 | -------------------------------------------------------------------------------- /src/components/chat/ChatToolbar/index.vue: -------------------------------------------------------------------------------- 1 | 43 | 44 | 85 | 122 | -------------------------------------------------------------------------------- /src/components/chat/MusicPlayer/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 64 | -------------------------------------------------------------------------------- /src/components/preImg/index.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 169 | 170 | 261 | -------------------------------------------------------------------------------- /src/config/index.js: -------------------------------------------------------------------------------- 1 | const config = { 2 | default_room_bg: '', // 默认房间背景 3 | wx_avatar: '/basic/wx.png' // 微信联系方式 4 | }; 5 | 6 | export default config; 7 | -------------------------------------------------------------------------------- /src/icons/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import SvgIcon from '@/components/SvgIcon'; // svg component 3 | 4 | // register globally 5 | Vue.component('Icon', SvgIcon); 6 | 7 | const req = require.context('./svg', false, /\.svg$/); 8 | const requireAll = requireContext => requireContext.keys().map(requireContext); 9 | requireAll(req); 10 | -------------------------------------------------------------------------------- /src/icons/svg/btn-loading.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/char-frame-del.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/chat-frame-unknow-file.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/chat-go.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/chat-header-setting.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/chat-mine.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/chat-online.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/chat-panel-link.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/chat-pre-close.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/chat-pre-download.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/chat-pre-recovert.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/chat-room-info-select.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/icons/svg/chat-room-locked.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/chat-room.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/chat-share.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/choose-music-love.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/icons/svg/choose-music-play.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/icons/svg/close.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/github.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/icon-error.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/icon-message.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/icon-success.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/icon-warning.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/music.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/progress-collect.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/progress-music.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/progress-switch.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/queue-music-del.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/icons/svg/queue-music-zan.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/icons/svg/toolbar-hook.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/toolbar-love.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/toolbar-music.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/icons/svg/toolbar-pic.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/icons/svg/toolbar-search.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/toolbar-wx.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import ElementUI from 'element-ui'; 2 | import Vue from 'vue'; 3 | import Barrage from 'vue-custom-barrage'; 4 | import App from './App.vue'; 5 | import router from './router'; 6 | import store from './store'; 7 | import './assets/css/index.less'; 8 | import './socket-io/index.js'; 9 | import './utils/vue.prototype'; 10 | import './icons/index'; 11 | import './permission'; 12 | import './theme/global.less'; 13 | 14 | import 'element-ui/lib/theme-chalk/index.css'; 15 | 16 | Vue.use(ElementUI); 17 | Vue.use(Barrage); 18 | 19 | Vue.config.productionTip = false; 20 | 21 | new Vue({ 22 | router, 23 | store, 24 | render: h => h(App) 25 | }).$mount('#app'); 26 | -------------------------------------------------------------------------------- /src/permission.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-underscore-dangle */ 2 | import NProgress from 'nprogress'; 3 | import router from './router'; 4 | import store from './store'; 5 | import 'nprogress/nprogress.css'; 6 | import { getToken } from '@/utils/auth'; 7 | 8 | NProgress.configure({ showSpinner: false }); 9 | const whiteList = ['/login', '/register']; 10 | 11 | router.beforeEach(async (to, from, next) => { 12 | NProgress.start(); 13 | document.title = '小九的聊天室'; 14 | if (to.path) { 15 | if (window._hmt) { 16 | window._hmt.push(['_trackPageview', `/#${to.fullPath}`]); 17 | } 18 | } 19 | const hasToken = getToken(); 20 | if (hasToken) { 21 | !store.state.user_info && (await store.dispatch('getUserInfo')); 22 | next(); 23 | } else if (whiteList.indexOf(to.path) !== -1) { 24 | next(); 25 | } else { 26 | next(`/login`); 27 | NProgress.done(); 28 | } 29 | }); 30 | 31 | router.afterEach(() => { 32 | NProgress.done(); 33 | }); 34 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import VueRouter from 'vue-router'; 3 | 4 | Vue.use(VueRouter); 5 | 6 | const routes = [ 7 | { 8 | path: '/', 9 | name: 'Home', 10 | component: () => import('../views/Chat') 11 | }, 12 | { 13 | path: '/login', 14 | name: 'Login', 15 | component: () => import('../views/login.vue') 16 | }, 17 | { 18 | path: '/register', 19 | name: 'Register', 20 | component: () => import('../views/register.vue') 21 | }, 22 | { 23 | path: '*', 24 | redirect: '/' 25 | } 26 | ]; 27 | 28 | const router = new VueRouter({ 29 | routes 30 | }); 31 | 32 | export default router; 33 | -------------------------------------------------------------------------------- /src/socket-io/index.js: -------------------------------------------------------------------------------- 1 | import SocketIO from 'socket.io-client'; 2 | import VueSocketIoExtended from 'vue-socket.io-extended'; 3 | import Vue from 'vue'; 4 | 5 | const url = process.env.VUE_APP_WS_API; 6 | const socket = SocketIO(url, { 7 | transports: ['websocket'], 8 | path: '/chat', 9 | reconnection: true, 10 | reconnectionAttempts: Infinity, 11 | autoConnect: false 12 | }); 13 | Vue.use(VueSocketIoExtended, socket); 14 | -------------------------------------------------------------------------------- /src/store/actions.js: -------------------------------------------------------------------------------- 1 | import { getInfo } from '@/api/user'; 2 | import { queryRoomInfo } from '@/api/chat'; 3 | import router from '../router/index'; 4 | 5 | export default { 6 | /* 获取用户信息 */ 7 | async getUserInfo({ commit }) { 8 | return new Promise(resolve => { 9 | getInfo().then(res => { 10 | const { user_info } = res.data; 11 | commit('setUserInfo', user_info); 12 | resolve(true); 13 | }); 14 | }); 15 | }, 16 | 17 | /* 获取当前房间信息 */ 18 | async getRoomInfo({ commit, state }) { 19 | return new Promise(resolve => { 20 | queryRoomInfo({ room_id: state.room_id }).then(res => { 21 | commit('setRoomInfo', res.data); 22 | resolve(true); 23 | }); 24 | }); 25 | }, 26 | 27 | /* 退出登录 */ 28 | async logout({ commit }) { 29 | return new Promise(resolve => { 30 | localStorage.removeItem('chat_token'); 31 | commit('setToken', null); 32 | commit('resetStore'); 33 | router.push('/login'); 34 | resolve(); 35 | }); 36 | } 37 | }; 38 | -------------------------------------------------------------------------------- /src/store/default.js: -------------------------------------------------------------------------------- 1 | export default function getDefaultValue() { 2 | return { 3 | token: null, 4 | user_info: null, 5 | room_list: [], 6 | room_id: 888, 7 | on_line_user_list: [], 8 | messageList: [], 9 | music_info: null, 10 | music_lrc: null, 11 | music_src: null, 12 | music_start_time: null, 13 | current_music_time: null, 14 | music_queue_list: [], 15 | room_admin_info: {}, 16 | un_read_msg_num: 0, // 未读消息数 17 | pre_img: null, 18 | room_info: null, // 此处的信息来自于初始化阶段,后续不会变更,页面使用的数据 以getters的room_info为准 来自ws实时更新的数据 19 | 20 | show_all_tips: true, 21 | showTipsJoinRoom: true, 22 | showTipsQuitRoom: true, 23 | showTipsSwitchMusic: true, 24 | showTipsPlayMusic: true, 25 | showTipsNotice: true, 26 | showHistoryBarrageInfo: true, 27 | showBarrageImg: false, 28 | showBarrageAvatar: true, 29 | theme: 'black', 30 | is_screen: false 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /src/store/getters.js: -------------------------------------------------------------------------------- 1 | export default { 2 | room_admin_info: state => state.room_admin_info, 3 | room_admin_id: state => state.room_admin_info.id, 4 | room_list: state => state.room_list, 5 | room_id: state => state.room_id, 6 | mine_room_bg: state => state.user_info && state.user_info.user_room_bg, 7 | mine_room_id: state => state.user_info && state.user_info.user_room_id, 8 | mine_id: state => state.user_info && state.user_info.user_id, 9 | on_line_user_list: state => state.on_line_user_list, 10 | onLineUserNum: state => state.on_line_user_list.length, 11 | onLineRoomNum: state => state.room_list.length, 12 | user_info: state => state.user_info, 13 | room_info: state => state.room_list.find(t => t.room_id === state.room_id) 14 | }; 15 | -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Vuex from 'vuex'; 3 | import state from './state'; 4 | import mutations from './mutations'; 5 | import actions from './actions'; 6 | import getters from './getters'; 7 | 8 | Vue.use(Vuex); 9 | 10 | export default new Vuex.Store({ 11 | state, 12 | mutations, 13 | actions, 14 | getters 15 | }); 16 | -------------------------------------------------------------------------------- /src/store/mutations.js: -------------------------------------------------------------------------------- 1 | import getDefaultValue from './default'; 2 | import { setTheme } from '@/theme'; 3 | 4 | export default { 5 | setSignInPopup(state, isShow) { 6 | state.showSignInPopup = isShow; 7 | }, 8 | 9 | setSignUpPopup(state, isShow) { 10 | state.showSignUpPopup = isShow; 11 | }, 12 | 13 | setToken(state, token) { 14 | state.token = token; 15 | }, 16 | 17 | setTheme(state, theme) { 18 | state.theme = theme; 19 | }, 20 | 21 | setUserInfo(state, user_info) { 22 | state.user_info = user_info; 23 | }, 24 | 25 | /* 设置房间当前所在的房间room_id */ 26 | setRoomId(state, room_id) { 27 | state.room_id = Number(room_id); 28 | }, 29 | 30 | /* 房间列表信息 */ 31 | setRoomList(state, room_list) { 32 | state.room_list = room_list; 33 | }, 34 | 35 | /* 房间在线用户列表 */ 36 | setOnlineUserList(state, on_line_user_list) { 37 | state.on_line_user_list = on_line_user_list; 38 | }, 39 | 40 | /* 房间房主信息 */ 41 | setRoomAdminInfo(state, room_admin_info) { 42 | state.room_admin_info = room_admin_info; 43 | }, 44 | 45 | /** 46 | * @desc 变更消息列表 47 | * @param {*} state 48 | * @param {*} messageInfo [] || {} 数组表示第一次获取了历史信息或者上拉加载更多 {} 表示一条新消息, 直接存入即可 49 | */ 50 | setMessageDataList(state, messageInfo) { 51 | const isArray = Array.isArray(messageInfo); 52 | let result = []; 53 | isArray && (result = [...messageInfo, ...state.messageList]); 54 | !isArray && (result = [...state.messageList, ...[messageInfo]]); 55 | state.messageList = state.show_all_tips ? result : result.filter(t => t.message_type !== 'info'); 56 | }, 57 | 58 | /* 清除所有公告信息 */ 59 | clearTipsInfo(state) { 60 | state.messageList = state.messageList.filter(t => t.message_type !== 'info'); 61 | }, 62 | 63 | /* 清除公告信息 */ 64 | clearNoticeInfo(state) { 65 | state.messageList = state.messageList.filter(t => t.message_type !== 'notice'); 66 | }, 67 | 68 | /* 撤回消息修改列表信息 */ 69 | updateMessageList(state, { id, msg }) { 70 | const messageIndex = state.messageList.findIndex(t => t.id === id); 71 | messageIndex !== -1 && (state.messageList[messageIndex].message_content = msg); 72 | messageIndex !== -1 && (state.messageList[messageIndex].message_type = 'info'); 73 | state.messageList.forEach(item => { 74 | if (item?.quote_info?.quote_message_id === id) { 75 | item.quote_info.quote_message_status = -1; 76 | } 77 | }); 78 | }, 79 | 80 | setCurrentMusicInfo(state, currentMusicInfo) { 81 | const { music_info, music_lrc, music_src } = currentMusicInfo; 82 | state.music_info = music_info; 83 | state.music_lrc = music_lrc; 84 | state.music_src = music_src; 85 | }, 86 | 87 | setCurrentMusicStartTime(state, music_start_time) { 88 | state.music_start_time = music_start_time; 89 | }, 90 | 91 | setCurrenMusicTime(state, current_music_time) { 92 | state.current_music_time = current_music_time; 93 | }, 94 | 95 | setQueueMusicList(state, music_queue_list) { 96 | state.music_queue_list = music_queue_list; 97 | }, 98 | 99 | setUnReadMsgNum(state, un_read_msg_num) { 100 | state.un_read_msg_num = un_read_msg_num; 101 | }, 102 | 103 | emptyMessageDataList(state) { 104 | state.messageList = []; 105 | }, 106 | 107 | resetStore(state) { 108 | Object.assign(state, getDefaultValue()); 109 | }, 110 | 111 | /* 设置预览图片 */ 112 | setPreImg(state, pre_img) { 113 | state.pre_img = pre_img; 114 | }, 115 | 116 | /* 设置当前房间信息 */ 117 | setRoomInfo(state, room_info) { 118 | state.room_info = room_info; 119 | }, 120 | 121 | /* 设置全局配置信息 */ 122 | setGlobalRoomConfig(state, { key, value }) { 123 | state[key] = value; 124 | localStorage.setItem(key, typeof value === 'boolean' ? JSON.stringify(value) : value); 125 | if (key === 'theme') { 126 | setTheme(value); 127 | } 128 | } 129 | }; 130 | -------------------------------------------------------------------------------- /src/store/state.js: -------------------------------------------------------------------------------- 1 | import getDefaultValue from './default'; 2 | 3 | const state = getDefaultValue(); 4 | 5 | export default state; 6 | -------------------------------------------------------------------------------- /src/theme/global.less: -------------------------------------------------------------------------------- 1 | /* 聊天面板背景色 */ 2 | @message-panel-bg-color: var(--message-panel-bg-color, #fff); 3 | /* 主要文字颜色 */ 4 | @message-main-text-color: var(--message-main-text-color, #333); 5 | /* 聊天面板阴影 */ 6 | @message-panel-box-shadow: var(--message-panel-box-shadow, 0 0 15px #f2f2f2); 7 | /* 聊天面板公告背景 提示框背景 */ 8 | @message-panel-tips-bg-color: var(--message-panel-tips-bg-color, #eee); 9 | /* 边框颜色 */ 10 | @message-border-color: var(--message-border-color, #eee); 11 | /* 弹窗的背景色 */ 12 | @message-popup-bg-color: var(--message-popup-bg-color, #ffffffb3); 13 | /* hover背景色 */ 14 | @message-hover-bg-color: var(--message-hover-bg-color, #e0dede); 15 | /* 右侧抽屉背景色 */ 16 | @message-drawer-bg-color: var(--message-drawer-bg-color, #fff); 17 | 18 | :export { 19 | name: "less"; 20 | message-panel-bg-color: @message-panel-bg-color; 21 | message-main-text-color: @message-main-text-color; 22 | message-panel-box-shadow: @message-panel-box-shadow; 23 | message-panel-tips-bg-color: @message-panel-tips-bg-color; 24 | message-border-color: @message-border-color; 25 | message-popup-bg-color: @message-popup-bg-color; 26 | message-hover-bg-color: @message-hover-bg-color; 27 | 28 | 29 | drawer-bg-color: @message-drawer-bg-color; 30 | } 31 | -------------------------------------------------------------------------------- /src/theme/index.js: -------------------------------------------------------------------------------- 1 | import store from '@/store'; 2 | 3 | const themes = {}; 4 | 5 | const themeFiles = require.context('./modules', true, /\.js$/); 6 | themeFiles.keys().forEach(modulePath => { 7 | const themeName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1'); 8 | themes[themeName] = themeFiles(modulePath).default; 9 | return themes; 10 | }); 11 | 12 | const changeStyle = obj => { 13 | if (!obj) return; 14 | Object.keys(obj).forEach(key => { 15 | document.getElementsByTagName('body')[0].style.setProperty(`--${key}`, obj[key]); 16 | }); 17 | }; 18 | 19 | export const setTheme = themeName => { 20 | localStorage.setItem('theme', themeName); 21 | store.commit('setTheme', themeName); 22 | const isHasTheme = Object.keys(themes).includes(themeName); 23 | if (isHasTheme) { 24 | const themeConfig = themes[themeName]; 25 | Object.keys(themeConfig).forEach(key => localStorage.setItem(key, themeConfig[key])); 26 | changeStyle(themeConfig); 27 | } else { 28 | const themeConfig = {}; 29 | const keys = ['sidebarBgColor', 'sidebarTextColor', 'mainBgColor', 'mainTextColor', 'borderColor', 'primaryTextColor']; 30 | keys.forEach(key => { 31 | localStorage[key] && (themeConfig[key] = localStorage[key]); 32 | }); 33 | changeStyle(themeConfig); 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /src/theme/modules/black.js: -------------------------------------------------------------------------------- 1 | export default { 2 | 'message-panel-bg-color': `#1b1f2ee6`, 3 | 'message-main-text-color': `#fff`, 4 | 'message-panel-box-shadow': 'none', 5 | 'message-panel-tips-bg-color': '#2e2e2e', 6 | 'message-border-color': '#494949', 7 | 'message-popup-bg-color': '#292f45e6', 8 | 'message-hover-bg-color': '#292f45e6', 9 | 10 | 'message-drawer-bg-color': `#2a283dcf` 11 | }; 12 | -------------------------------------------------------------------------------- /src/theme/modules/default.js: -------------------------------------------------------------------------------- 1 | export default { 2 | 'message-panel-bg-color': `#fff`, 3 | 'message-main-text-color': `#333`, 4 | 'message-panel-box-shadow': `0 0 15px #f2f2f2`, 5 | 'message-panel-tips-bg-color': '#eee', 6 | 'message-border-color': '#eee', 7 | 'message-popup-bg-color': '#ffffffb3', 8 | 'message-hover-bg-color': '#e0dede', 9 | 10 | 'message-drawer-bg-color': `#fff` 11 | }; 12 | -------------------------------------------------------------------------------- /src/theme/modules/transparent.js: -------------------------------------------------------------------------------- 1 | export default { 2 | 'message-panel-bg-color': `transparent`, 3 | 'message-main-text-color': `#fff`, 4 | 'message-panel-box-shadow': `0 0 5px #f2f2f2`, 5 | 'message-panel-tips-bg-color': '#2e2e2e', 6 | 'message-border-color': '#494949', 7 | 'message-popup-bg-color': '#37374199', 8 | 'message-hover-bg-color': '#37374199', 9 | 10 | 'message-drawer-bg-color': `#2a283db3` 11 | }; 12 | -------------------------------------------------------------------------------- /src/utils/auth.js: -------------------------------------------------------------------------------- 1 | const TokenKey = 'chat_token'; 2 | 3 | export function getToken() { 4 | return localStorage.getItem(TokenKey); 5 | } 6 | 7 | export function setToken(token) { 8 | return localStorage.setItem(TokenKey, token); 9 | } 10 | 11 | export function removeToken() { 12 | localStorage.clear(); 13 | } 14 | -------------------------------------------------------------------------------- /src/utils/axios.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import { Message } from 'element-ui'; 3 | import store from '../store/index'; 4 | import { getToken } from '@/utils/auth'; 5 | 6 | const service = axios.create({ 7 | baseURL: process.env.VUE_APP_BASE_API, 8 | timeout: 5000 9 | }); 10 | service.interceptors.request.use( 11 | config => { 12 | if (getToken()) { 13 | config.headers.Authorization = getToken(); 14 | } 15 | return config; 16 | }, 17 | error => Promise.reject(error) 18 | ); 19 | 20 | service.interceptors.response.use( 21 | response => { 22 | const res = response.data; 23 | if (![200, 201].includes(response.status)) { 24 | return Promise.reject(new Error(res.message || 'Error')); 25 | } 26 | return res; 27 | }, 28 | error => { 29 | if (error.message === 'timeout of 5000ms exceeded') { 30 | Message.error('请求超时,请检查您的网络状态或重新请求!'); 31 | } 32 | const { status, data } = error.response; 33 | const { code, message } = data; 34 | if (status === 500) { 35 | store.commit('resetStore'); 36 | store.dispatch('logout'); 37 | return; 38 | } 39 | if (code === 401) { 40 | Message.error(`身份信息校验失败、请重新登录`); 41 | store.dispatch('logout'); 42 | } else { 43 | Message.error(message); 44 | } 45 | return Promise.reject(error); 46 | } 47 | ); 48 | 49 | export default service; 50 | -------------------------------------------------------------------------------- /src/utils/chat.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @desc 返回的在线列表是对象,转化为数组,并且把有管理员的话把管理员放到首位 3 | * @param {*} userList 在线用户列表 //TODO 交给服务端处理 4 | */ 5 | export const compilerOnlineUser = userList => { 6 | const keys = Object.keys(userList); 7 | if (!keys.length) return []; 8 | let userInfo = Object.values(userList); 9 | let homeowner = null; 10 | const homeownerIndex = userInfo.findIndex(k => k.role === 'admin'); 11 | homeownerIndex !== -1 && (homeowner = userInfo.splice(homeownerIndex, 1)); 12 | homeownerIndex !== -1 && (userInfo = [...homeowner, ...userInfo]); 13 | return userInfo; 14 | }; 15 | -------------------------------------------------------------------------------- /src/utils/request.js: -------------------------------------------------------------------------------- 1 | import service from './axios'; 2 | 3 | export default function request(method, url, data = {}, headers = {}) { 4 | const dataType = method.toLocaleLowerCase() === 'get' ? 'params' : 'data'; 5 | const options = { 6 | method, 7 | url, 8 | [dataType]: data, 9 | headers: { 10 | 'Content-Type': 'application/json; charset=utf-8', 11 | ...headers 12 | } 13 | }; 14 | return service(options); 15 | } 16 | -------------------------------------------------------------------------------- /src/utils/tools.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @desc 防抖 如 input。核心:在给定的时间间隔内 只触发一次 取消上一次。连续的操作 只触发一次。 3 | */ 4 | export const debounce = (fn, wait = 500) => { 5 | let timer = null; 6 | 7 | return function () { 8 | clearTimeout(timer); 9 | timer = setTimeout(() => { 10 | fn.apply(this, arguments); 11 | }, wait); 12 | // timer = setTimeout(fn, wait); 13 | }; 14 | }; 15 | 16 | /** 17 | * @desc 节流 对高频事件的优化 如 scroll。 18 | * 与防抖区别:防抖在连续的操作过程中只触发一次,而节流可能触发多次,但是频率变低了。 19 | */ 20 | export const throttle = (fn, interval = 300) => { 21 | let timer = null; 22 | let timeStart = new Date(); 23 | 24 | return function () { 25 | const now = new Date(); 26 | const space = now - timeStart; 27 | if (space > interval) { 28 | fn.apply(this, arguments); 29 | timeStart = now; 30 | } else { 31 | clearTimeout(timer); 32 | timer = setTimeout(() => { 33 | // 这个 时候 currentTarget 为 null 34 | fn.apply(this, arguments); 35 | }, interval); 36 | } 37 | }; 38 | }; 39 | 40 | /** 41 | * @desc 节流(定时器方案) 对高频事件的优化 如 scroll。核心:间隔时间内 打开可执行标志。 42 | * 优点:确保最终结果,因为是延迟执行。 43 | * 缺点:不能马上触发 (方向键操作试下) 44 | */ 45 | export const throttle1 = (fn, interval = 1000) => { 46 | let timer = null; 47 | return function () { 48 | if (!timer) { 49 | timer = setTimeout(() => { 50 | fn.apply(this, arguments); 51 | clearTimeout(timer); 52 | timer = null; 53 | }, interval); 54 | } 55 | }; 56 | }; 57 | 58 | /** 59 | * @desc 节流(时间戳方案) 对高频事件的优化 如 scroll。 核心: 每隔给定时间,触发一次。 60 | * 优点:立即触发 61 | * 缺点:如果上一次停止操作的时间 跟下次操作时间没有超过给定的时间 将不会触发。(时间设置大一点 方向键操作试下) 62 | */ 63 | export const throttle2 = (fn, interval = 2000) => { 64 | let timeStart = new Date(); 65 | return function () { 66 | const now = new Date(); 67 | if (now - timeStart > interval) { 68 | fn.apply(this, arguments); 69 | timeStart = now; 70 | } 71 | }; 72 | }; 73 | 74 | /** 75 | * @desc 检测是不是空对象 76 | */ 77 | export const isEmptyObject = obj => obj && Object.keys(obj).length === 0; 78 | 79 | /** 80 | * @desc url 上获取参数 81 | */ 82 | export const getQueryString = name => { 83 | const reg = new RegExp(`(^|&)${name}=([^&]*)(&|$)`, 'i'); 84 | const regRewrite = new RegExp(`(^|/)${name}/([^/]*)(/|$)`, 'i'); 85 | const r = window.location.search.substr(1).match(reg); 86 | const q = window.location.pathname.substr(1).match(regRewrite); 87 | if (r != null) { 88 | return unescape(r[2]); 89 | } 90 | if (q != null) { 91 | return unescape(q[2]); 92 | } 93 | return null; 94 | }; 95 | 96 | /** 97 | * @desc 检测 value 是否在 validList 中 98 | * @param value 需要检测的值 99 | * @param validList 检测列表 100 | */ 101 | export function oneOf(value, validList) { 102 | for (let i = 0; i < validList.length; i++) { 103 | if (value === validList[i]) { 104 | return true; 105 | } 106 | } 107 | return false; 108 | } 109 | 110 | /** 111 | * @desc 格式化聊天时间记录 112 | * @param {*} timeSpace 113 | */ 114 | export const formatChatTime = date => { 115 | date = new Date(date).getTime(); 116 | const autoZero = n => (String(n).length === 1 ? '0' : '') + n; 117 | const oriSecond = date / 1000; 118 | const curSecond = parseInt(new Date().getTime() / 1000); 119 | const diffSecond = curSecond - oriSecond; 120 | const curDate = new Date(curSecond * 1000); 121 | const oriDate = new Date(oriSecond * 1000); 122 | const Y = oriDate.getFullYear(); 123 | const m = oriDate.getMonth() + 1; 124 | const d = oriDate.getDate(); 125 | const H = oriDate.getHours(); 126 | const i = oriDate.getMinutes(); 127 | // just 128 | if (diffSecond < 60) { 129 | // within a minute 130 | return '刚刚'; 131 | } 132 | if (diffSecond < 3600) { 133 | // within an hour 134 | return `${Math.floor(diffSecond / 60)}分钟前`; 135 | } 136 | if (curDate.getFullYear() === Y && curDate.getMonth() + 1 === m && curDate.getDate() === d) { 137 | return `今天${autoZero(H)}:${autoZero(i)}`; 138 | } 139 | // yesterday 140 | const mewDate = new Date((curSecond - 86400) * 1000); 141 | if (mewDate.getFullYear() === Y && mewDate.getMonth() + 1 === m && mewDate.getDate() === d) { 142 | return `昨天${autoZero(H)}:${autoZero(i)}`; 143 | } 144 | if (curDate.getFullYear() === Y) { 145 | return `${autoZero(m)}月${autoZero(d)}日`; 146 | } 147 | return `${Y}年${autoZero(m)}月${autoZero(d)}日`; 148 | }; 149 | 150 | /** 151 | * 图片宽高比适应 152 | * @param {*} w 容器宽 153 | * @param {*} h 容器高 154 | * @param {*} r 图片宽高比 155 | */ 156 | export const aspectRatioToWH = (w, h, r, iw, ih) => { 157 | const o_l = w / h; 158 | if (iw < w && ih < h) { 159 | return { w: iw, h: ih }; 160 | } 161 | // 容器宽度比 大=于 内容 宽高比 以高度为基准 162 | if (o_l > r) { 163 | return { 164 | w: h * r, 165 | h 166 | }; 167 | } 168 | if (o_l < r) { 169 | return { 170 | w, 171 | h: w / r 172 | }; 173 | } 174 | return { 175 | w, 176 | h 177 | }; 178 | }; 179 | 180 | /** 181 | * 获取图片数据 182 | * @param {*} url 文件地址 183 | * @param {*} timeout 超时时间 184 | */ 185 | export const getImgBlod = (url, timeout = 60000) => 186 | new Promise((resolve, reject) => { 187 | const xhr = new XMLHttpRequest(); 188 | xhr.open('GET', url); 189 | xhr.responseType = 'blob'; 190 | 191 | let timedout = false; 192 | const timer = setTimeout(() => { 193 | timedout = true; 194 | xhr.abort(); 195 | }, timeout); 196 | 197 | xhr.onreadystatechange = function () { 198 | if (xhr.readyState !== 4) return; 199 | if (timedout) { 200 | return; 201 | } 202 | clearTimeout(timer); 203 | if (xhr.status === 200 || xhr.status === 304) { 204 | try { 205 | const blob = this.response; 206 | resolve(window.URL.createObjectURL(blob)); 207 | } catch (error) { 208 | reject(xhr.responseText); 209 | } 210 | } else { 211 | reject(new Error(xhr.responseText)); 212 | } 213 | }; 214 | xhr.send(); 215 | }); 216 | -------------------------------------------------------------------------------- /src/utils/validate.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @description 常规正则校验表达式 3 | */ 4 | export const validatorsExp = { 5 | number: /^[0-9]*$/, 6 | nameLength: (n, m) => new RegExp(`^[\\u4E00-\\u9FA5]{${n},${m}}$`), 7 | idCard: /^(\d{6})(\d{4})(\d{2})(\d{2})(\d{3})([0-9]|X)$/, 8 | backCard: /^([1-9]{1})(\d{15}|\d{18})$/, 9 | phone: /^1[23456789]\d{9}$/, 10 | email: /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/ 11 | }; 12 | 13 | /** 14 | * @description 常规正则校验方法 15 | */ 16 | export const validatorsFun = { 17 | number: val => validatorsExp.number.test(val), 18 | idCard: val => validatorsExp.idCard.test(val), 19 | backCard: val => validatorsExp.backCard.test(val) 20 | }; 21 | 22 | /** 23 | * @description 表单校验 24 | */ 25 | export const validatorsFrom = { 26 | // 验证自然数 27 | naturalNumber: /^(([0-9]*[1-9][0-9]*)|(0+))$/, 28 | naturalNumberMsg: '请输入自然数', 29 | // 英文 30 | english: /^.[A-Za-z]+$/, 31 | englishMsg: '请输入英文字符', 32 | // 座机 33 | telephone: /^\d{3}-\d{7,8}|\d{4}-\d{7,8}$/, 34 | telephoneMsg: '请输入正确的座机号', 35 | // 银行卡号码 36 | bankCard: /^[1-9]\d{9,19}$/, 37 | bankCardMsg: '请输入正确的银行卡号码', 38 | // 证件号码 39 | IDNumber: /^[a-z0-9A-Z]{0,50}$/, 40 | IDNumberMsg: '请输入正确的证件号码', 41 | // 身份证号码,包括15位和18位的 42 | IDCard: /(^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$)|(^[1-9]\d{7}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}$)/, 43 | IDCardMsg: '请输入正确的身份证号码', 44 | // QQ号码 45 | qq: /^[1-9]\d{4,11}$/, 46 | qqMsg: '请输入正确的QQ号码', 47 | // 网址, 仅支持http和https开头的 48 | url: /^(http|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-.,@?^=%&:/~+#]*[\w\-@?^=%&/~+#])?$/, 49 | urlMsg: '请输入以http和https开头的网址', 50 | // 0到20位的英文字符和数字 51 | enNum0to20: /^[a-z0-9A-Z]{0,20}$/, 52 | enNum0to20Msg: '请输入20位以内的英文字符和数字', 53 | // 2到100位的中英文字符和空格 54 | cnEnSpace2to100: /^[a-zA-Z\u4E00-\u9FA5\s*]{2,100}$/, 55 | cnEnSpace2to100Msg: '请输入2到100位的中英文字符和空格', 56 | // 数字和换行符 57 | numLinefeed: /^[0-9\n*]+$/, 58 | numLinefeedMsg: '请输入数字和换行符', 59 | // 255位以内的字符 60 | char0to255: /^.{0,255}$/, 61 | char0to255Msg: '请输入255位以内的字符' 62 | }; 63 | 64 | /** 65 | * @param {string} path 66 | * @returns {Boolean} 67 | */ 68 | export function isExternal(path) { 69 | return /^(https?:|mailto:|tel:)/.test(path); 70 | } 71 | 72 | /** 73 | * @param {string} str 74 | * @returns {Boolean} 75 | */ 76 | export function validUsername(str) { 77 | const valid_map = ['admin', 'editor']; 78 | return valid_map.indexOf(str.trim()) >= 0; 79 | } 80 | -------------------------------------------------------------------------------- /src/utils/vue.prototype.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | 3 | /** 4 | * @desc 让节点滚动到可视区域 聊天面板发送消息后回到底部 5 | * @param {} el dom 6 | */ 7 | export function $scorllToBottom(options = { id: 'panelEnd', animation: false }) { 8 | const { id = 'panelEnd', animation = false } = options; 9 | const el = document.getElementById(id); 10 | const params = {}; 11 | animation && (params.behavior = 'smooth'); 12 | el.scrollIntoView(params); 13 | } 14 | 15 | Vue.prototype.$scorllToBottom = $scorllToBottom; 16 | -------------------------------------------------------------------------------- /src/views/login.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 93 | 142 | -------------------------------------------------------------------------------- /src/views/register.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 95 | 144 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | function resolve(dir) { 4 | return path.join(__dirname, dir); 5 | } 6 | const port = 8080; 7 | 8 | module.exports = { 9 | publicPath: '/', 10 | pluginOptions: { 11 | 'style-resources-loader': { 12 | preProcessor: 'less', 13 | patterns: [path.resolve(__dirname, './src/theme/global.less')] 14 | } 15 | }, 16 | outputDir: 'dist', 17 | assetsDir: 'static', 18 | lintOnSave: process.env.NODE_ENV === 'development', 19 | productionSourceMap: false, 20 | devServer: { 21 | port: port, 22 | open: true, 23 | overlay: { 24 | warnings: false, 25 | errors: true 26 | } 27 | }, 28 | configureWebpack: { 29 | resolve: { 30 | alias: { 31 | '@': resolve('src') 32 | } 33 | } 34 | }, 35 | 36 | chainWebpack(config) { 37 | config.module.rule('svg').exclude.add(resolve('src/icons')).end(); 38 | config.module 39 | .rule('icons') 40 | .test(/\.svg$/) 41 | .include.add(resolve('src/icons')) 42 | .end() 43 | .use('svg-sprite-loader') 44 | .loader('svg-sprite-loader') 45 | .options({ 46 | symbolId: 'icon-[name]' 47 | }) 48 | .end(); 49 | } 50 | }; 51 | --------------------------------------------------------------------------------