├── .github └── workflows │ └── build.yml ├── .gitignore ├── LICENSE ├── README.md ├── img ├── image-20240108131746139.png ├── image-20240108131824788.png └── image-20240108131927175.png ├── music-client ├── .browserslistrc ├── .eslintrc.js ├── .gitignore ├── README.md ├── babel.config.js ├── package-lock.json ├── package.json ├── public │ ├── favicon.ico │ └── index.html ├── src │ ├── App.vue │ ├── api │ │ ├── index.ts │ │ └── request.ts │ ├── assets │ │ ├── css │ │ │ ├── global.scss │ │ │ ├── index.scss │ │ │ ├── sign.scss │ │ │ ├── var.scss │ │ │ ├── yin-current-play.scss │ │ │ └── yin-play-bar.scss │ │ ├── icons │ │ │ ├── iconfont.js │ │ │ ├── iconfont1.js │ │ │ ├── iconfont2.js │ │ │ ├── iconfont3.js │ │ │ ├── iconfont4.js │ │ │ └── index.js │ │ └── images │ │ │ ├── tubiao.jpg │ │ │ └── user.jpg │ ├── components │ │ ├── Comment.vue │ │ ├── PlayList.vue │ │ ├── SongList.vue │ │ └── layouts │ │ │ ├── YinAudio.vue │ │ │ ├── YinCurrentPlay.vue │ │ │ ├── YinFooter.vue │ │ │ ├── YinHeader.vue │ │ │ ├── YinHeaderNav.vue │ │ │ ├── YinIcon.vue │ │ │ ├── YinLoginLogo.vue │ │ │ ├── YinNav.vue │ │ │ ├── YinPlayBar.vue │ │ │ └── YinScrollTop.vue │ ├── enums │ │ ├── area.ts │ │ ├── icon.ts │ │ ├── index.ts │ │ ├── music-name.ts │ │ ├── nav.ts │ │ ├── router-name.ts │ │ ├── singer.ts │ │ ├── songList.ts │ │ └── validate.ts │ ├── main.ts │ ├── mixins │ │ └── mixin.ts │ ├── router │ │ └── index.ts │ ├── shims-vue.d.ts │ ├── store │ │ ├── configure.ts │ │ ├── index.ts │ │ ├── song.ts │ │ └── user.ts │ ├── utils │ │ └── index.ts │ └── views │ │ ├── FPassword.vue │ │ ├── Home.vue │ │ ├── Lyric.vue │ │ ├── SignIn.vue │ │ ├── SignUp.vue │ │ ├── YinContainer.vue │ │ ├── error │ │ └── 404.vue │ │ ├── loginByemail.vue │ │ ├── personal │ │ └── Personal.vue │ │ ├── search │ │ ├── Search.vue │ │ ├── SearchSong.vue │ │ └── SearchSongList.vue │ │ ├── setting │ │ ├── Password.vue │ │ ├── PersonalData.vue │ │ ├── Setting.vue │ │ └── Upload.vue │ │ ├── singer │ │ ├── Singer.vue │ │ └── SingerDetail.vue │ │ └── song-sheet │ │ ├── SongSheet.vue │ │ └── SongSheetDetail.vue ├── tsconfig.json └── vue.config.js ├── music-manage ├── .browserslistrc ├── .eslintrc.js ├── .gitignore ├── README.md ├── babel.config.js ├── package-lock.json ├── package.json ├── public │ ├── favicon.ico │ └── index.html ├── src │ ├── App.vue │ ├── api │ │ ├── index.ts │ │ └── request.ts │ ├── assets │ │ ├── css │ │ │ └── main.css │ │ ├── icons │ │ │ └── iconfont.js │ │ └── images │ │ │ ├── background.jpg │ │ │ └── user.jpg │ ├── components │ │ ├── dialog │ │ │ └── YinDelDialog.vue │ │ └── layouts │ │ │ ├── YinAside.vue │ │ │ ├── YinAudio.vue │ │ │ └── YinHeader.vue │ ├── enums │ │ ├── area.ts │ │ ├── icon.ts │ │ ├── index.ts │ │ ├── music-name.ts │ │ └── router-name.ts │ ├── main.ts │ ├── mixins │ │ └── mixin.ts │ ├── router │ │ └── index.ts │ ├── shims-vue.d.ts │ ├── store │ │ └── index.ts │ ├── utils │ │ ├── emitter.ts │ │ └── index.ts │ └── views │ │ ├── CollectPage.vue │ │ ├── CommentPage.vue │ │ ├── ConsumerPage.vue │ │ ├── Home.vue │ │ ├── InfoPage.vue │ │ ├── ListSongPage.vue │ │ ├── Login.vue │ │ ├── SingerPage.vue │ │ ├── SongListPage.vue │ │ └── SongPage.vue ├── tsconfig.json └── vue.config.js └── music-server ├── .gitignore ├── Dockerfile ├── docker-server ├── docker-compose.yml └── dockerfile ├── docker-vue-client └── dockerfile ├── docker-vue-manage └── dockerfile ├── mvnw ├── mvnw.cmd ├── pom.xml ├── sql └── tp_music.sql └── src ├── main ├── java │ └── com │ │ └── example │ │ └── yin │ │ ├── YinMusicApplication.java │ │ ├── common │ │ └── R.java │ │ ├── config │ │ ├── CorsInterceptor.java │ │ ├── MinioConfig.java │ │ ├── RedisConfig.java │ │ ├── WebCharacterEncodingFilter.java │ │ ├── WebMvcConfig.java │ │ └── WebPicConfig.java │ │ ├── constant │ │ └── Constants.java │ │ ├── controller │ │ ├── AdminController.java │ │ ├── BannerController.java │ │ ├── CollectController.java │ │ ├── CommentController.java │ │ ├── ConsumerController.java │ │ ├── FileDownloadController.java │ │ ├── ListSongController.java │ │ ├── MinioController.java │ │ ├── MinioUploadController.java │ │ ├── RankListController.java │ │ ├── SingerController.java │ │ ├── SongController.java │ │ ├── SongListController.java │ │ └── UserSupportController.java │ │ ├── handler │ │ └── MyMetaObjectHandler.java │ │ ├── mapper │ │ ├── AdminMapper.java │ │ ├── BannerMapper.java │ │ ├── CollectMapper.java │ │ ├── CommentMapper.java │ │ ├── ConsumerMapper.java │ │ ├── ListSongMapper.java │ │ ├── RankListMapper.java │ │ ├── SingerMapper.java │ │ ├── SongListMapper.java │ │ ├── SongMapper.java │ │ └── UserSupportMapper.java │ │ ├── model │ │ ├── domain │ │ │ ├── Admin.java │ │ │ ├── Banner.java │ │ │ ├── Collect.java │ │ │ ├── Comment.java │ │ │ ├── Consumer.java │ │ │ ├── ListSong.java │ │ │ ├── Order.java │ │ │ ├── RankList.java │ │ │ ├── ResetPasswordRequest.java │ │ │ ├── Singer.java │ │ │ ├── Song.java │ │ │ ├── SongList.java │ │ │ └── UserSupport.java │ │ └── request │ │ │ ├── AdminRequest.java │ │ │ ├── CollectRequest.java │ │ │ ├── CommentRequest.java │ │ │ ├── ConsumerRequest.java │ │ │ ├── ListSongRequest.java │ │ │ ├── RankListRequest.java │ │ │ ├── SingerRequest.java │ │ │ ├── SongListRequest.java │ │ │ ├── SongRequest.java │ │ │ └── UserSupportRequest.java │ │ ├── service │ │ ├── AdminService.java │ │ ├── BannerService.java │ │ ├── CollectService.java │ │ ├── CommentService.java │ │ ├── ConsumerService.java │ │ ├── ListSongService.java │ │ ├── OrderManager.java │ │ ├── RankListService.java │ │ ├── SingerService.java │ │ ├── SongListService.java │ │ ├── SongService.java │ │ ├── UserSupportService.java │ │ └── impl │ │ │ ├── AdminServiceImpl.java │ │ │ ├── BannerServiceImpl.java │ │ │ ├── CollectServiceImpl.java │ │ │ ├── CommentServiceImpl.java │ │ │ ├── ConsumerServiceImpl.java │ │ │ ├── ListSongServiceImpl.java │ │ │ ├── RankListServiceImpl.java │ │ │ ├── SimpleOrderManager.java │ │ │ ├── SingerServiceImpl.java │ │ │ ├── SongListServiceImpl.java │ │ │ ├── SongServiceImpl.java │ │ │ └── UserSupportServiceImpl.java │ │ └── utils │ │ ├── RandomUtils.java │ │ └── TestFileUtil.java └── resources │ ├── application-dev.properties │ ├── application-prod.properties │ ├── application.properties │ ├── application.yml │ ├── log4j.properties │ ├── mapper │ ├── AdminMapper.xml │ ├── BannerMapper.xml │ ├── CollectMapper.xml │ ├── CommentMapper.xml │ ├── ConsumerMapper.xml │ ├── ListSongMapper.xml │ ├── RankListMapper.xml │ ├── SingerMapper.xml │ ├── SongListMapper.xml │ ├── SongMapper.xml │ └── UserSupportMapper.xml │ └── mysql-connector-java-8.0.13.jar └── test └── java └── com └── example └── yin └── YinMusicApplicationTests.java /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build CI 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | build: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Checkout 11 | uses: actions/checkout@main 12 | with: 13 | fetch-depth: 0 14 | 15 | - name: Set up QEMU 16 | uses: docker/setup-qemu-action@master 17 | 18 | - name: Set up Docker Buildx 19 | uses: docker/setup-buildx-action@master 20 | 21 | - name: Login to DockerHub 22 | uses: docker/login-action@master 23 | with: 24 | username: ${{secrets.DOCKER_USERNAME}} 25 | password: ${{secrets.DOCKER_PASSWORD}} 26 | 27 | - name: Build and push 28 | uses: docker/build-push-action@master 29 | with: 30 | platforms: linux/amd64,linux/arm64 31 | push: true 32 | context: music-server 33 | tags: ${{secrets.DOCKER_USERNAME}}/music-server:latest 34 | file: music-server/Dockerfile -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea -------------------------------------------------------------------------------- /img/image-20240108131746139.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yin-Hongwei/music-website/2cccb623c437abc0b90c91948d2c559a387fd335/img/image-20240108131746139.png -------------------------------------------------------------------------------- /img/image-20240108131824788.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yin-Hongwei/music-website/2cccb623c437abc0b90c91948d2c559a387fd335/img/image-20240108131824788.png -------------------------------------------------------------------------------- /img/image-20240108131927175.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yin-Hongwei/music-website/2cccb623c437abc0b90c91948d2c559a387fd335/img/image-20240108131927175.png -------------------------------------------------------------------------------- /music-client/.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not dead 4 | not ie 11 5 | -------------------------------------------------------------------------------- /music-client/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true 5 | }, 6 | 'extends': [ 7 | 'plugin:vue/vue3-essential', 8 | 'eslint:recommended', 9 | '@vue/typescript/recommended' 10 | ], 11 | parserOptions: { 12 | ecmaVersion: 2020 13 | }, 14 | rules: { 15 | 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 16 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 17 | 'vue/multi-word-component-names': 0, 18 | "@typescript-eslint/no-unused-vars": ["off"], 19 | "@typescript-eslint/no-explicit-any": ["off"], 20 | 'no-undef': 0 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /music-client/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /music-client/README.md: -------------------------------------------------------------------------------- 1 | # music 2 | 3 | ## Project setup 4 | ``` 5 | npm install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | npm run serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | npm run build 16 | ``` 17 | 18 | ### Lints and fixes files 19 | ``` 20 | npm run lint 21 | ``` 22 | 23 | ### Customize configuration 24 | See [Configuration Reference](https://cli.vuejs.org/config/). 25 | -------------------------------------------------------------------------------- /music-client/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /music-client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "music-client", 3 | "version": "3.0.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "axios": "^0.26.0", 12 | "core-js": "^3.8.3", 13 | "element-plus": "^2.0.4", 14 | "vue": "^3.2.13", 15 | "vue-router": "^4.0.3", 16 | "vuex": "^4.0.0" 17 | }, 18 | "devDependencies": { 19 | "@element-plus/icons-vue": "^1.0.0", 20 | "@typescript-eslint/eslint-plugin": "^5.4.0", 21 | "@typescript-eslint/parser": "^5.4.0", 22 | "@vue/cli-plugin-babel": "~5.0.0", 23 | "@vue/cli-plugin-eslint": "~5.0.0", 24 | "@vue/cli-plugin-router": "~5.0.0", 25 | "@vue/cli-plugin-typescript": "~5.0.0", 26 | "@vue/cli-plugin-vuex": "~5.0.0", 27 | "@vue/cli-service": "~5.0.0", 28 | "@vue/eslint-config-typescript": "^9.1.0", 29 | "eslint": "^7.32.0", 30 | "eslint-plugin-vue": "^8.0.3", 31 | "sass": "^1.32.7", 32 | "sass-loader": "^12.0.0", 33 | "typescript": "~4.5.5" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /music-client/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yin-Hongwei/music-website/2cccb623c437abc0b90c91948d2c559a387fd335/music-client/public/favicon.ico -------------------------------------------------------------------------------- /music-client/public/index.html: -------------------------------------------------------------------------------- 1 | <!DOCTYPE html> 2 | <html lang=""> 3 | <head> 4 | <meta charset="utf-8"> 5 | <meta http-equiv="X-UA-Compatible" content="IE=edge"> 6 | <meta name="viewport" content="width=device-width,initial-scale=1.0"> 7 | <link rel="icon" href="<%= BASE_URL %>favicon.ico"> 8 | <title><%= htmlWebpackPlugin.options.title %></title> 9 | </head> 10 | <body> 11 | <noscript> 12 | <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong> 13 | </noscript> 14 | <div id="app"></div> 15 | <!-- built files will be auto injected --> 16 | </body> 17 | </html> 18 | -------------------------------------------------------------------------------- /music-client/src/App.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <router-view /> 3 | </template> 4 | -------------------------------------------------------------------------------- /music-client/src/api/request.ts: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import router from "@/router"; 3 | 4 | const BASE_URL = process.env.NODE_HOST; 5 | 6 | axios.defaults.timeout = 5000; // 超时时间设置 7 | axios.defaults.withCredentials = true; // true允许跨域 8 | axios.defaults.baseURL = BASE_URL; 9 | // Content-Type 响应头 10 | axios.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded;charset=UTF-8"; 11 | 12 | // 响应拦截器 13 | axios.interceptors.response.use( 14 | (response) => { 15 | // 如果返回的状态码为200,说明接口请求成功,可以正常拿到数据 16 | // 否则的话抛出错误 17 | if (response.status === 200) { 18 | return Promise.resolve(response); 19 | } else { 20 | return Promise.reject(response); 21 | } 22 | }, 23 | // 服务器状态码不是2开头的的情况 24 | (error) => { 25 | if (error.response.status) { 26 | switch (error.response.status) { 27 | // 401: 未登录 28 | case 401: 29 | router.replace({ 30 | path: "/", 31 | query: { 32 | // redirect: router.currentRoute.fullPath 33 | }, 34 | }); 35 | break; 36 | case 403: 37 | // console.log('管理员权限已修改请重新登录') 38 | // 跳转登录页面,并将要浏览的页面fullPath传过去,登录成功后跳转需要访问的页面 39 | setTimeout(() => { 40 | router.replace({ 41 | path: "/", 42 | query: { 43 | // redirect: router.currentRoute.fullPath 44 | }, 45 | }); 46 | }, 1000); 47 | break; 48 | 49 | // 404请求不存在 50 | case 404: 51 | // console.log('请求页面飞到火星去了') 52 | break; 53 | } 54 | return Promise.reject(error.response); 55 | } 56 | } 57 | ); 58 | 59 | export function getBaseURL() { 60 | return BASE_URL; 61 | } 62 | 63 | /** 64 | * 封装get方法 65 | * @param url 66 | * @param data 67 | * @returns {Promise} 68 | */ 69 | export function get(url, params?: object) { 70 | return new Promise((resolve, reject) => { 71 | axios.get(url, params).then( 72 | (response) => resolve(response.data), 73 | (error) => reject(error) 74 | ); 75 | }); 76 | } 77 | 78 | /** 79 | * 封装post请求 80 | * @param url 81 | * @param data 82 | * @returns {Promise} 83 | */ 84 | export function post(url, data = {}) { 85 | return new Promise((resolve, reject) => { 86 | axios.post(url, data).then( 87 | (response) => resolve(response.data), 88 | (error) => reject(error) 89 | ); 90 | }); 91 | } 92 | 93 | /** 94 | * 封装delete请求 95 | * @param url 96 | * @param data 97 | * @returns {Promise} 98 | */ 99 | export function deletes(url, data = {}) { 100 | return new Promise((resolve, reject) => { 101 | axios.delete(url, data).then( 102 | (response) => resolve(response.data), 103 | (error) => reject(error) 104 | ); 105 | }); 106 | } 107 | 108 | /** 109 | * 封装put请求 110 | * @param url 111 | * @param data 112 | * @returns {Promise} 113 | */ 114 | export function put(url, data = {}) { 115 | return new Promise((resolve, reject) => { 116 | axios.put(url, data).then( 117 | (response) => resolve(response.data), 118 | (error) => reject(error) 119 | ); 120 | }); 121 | } 122 | -------------------------------------------------------------------------------- /music-client/src/assets/css/global.scss: -------------------------------------------------------------------------------- 1 | @import "var.scss"; 2 | 3 | // 上下左右居中 4 | @mixin layout($justify-content: flex-start, $align-items: stretch, $flex-direction: row, $flex-wrap: nowrap) { 5 | display: flex; 6 | justify-content: $justify-content; 7 | align-items: $align-items; 8 | flex-direction: $flex-direction; 9 | flex-wrap: $flex-wrap; 10 | } 11 | 12 | // 图标 13 | @mixin icon($size: 1.5em, $color: $color-black) { 14 | width: $size; 15 | height: $size; 16 | font-size: $size; 17 | color: $color; 18 | fill: currentColor; 19 | overflow: hidden; 20 | position: relative; 21 | } 22 | -------------------------------------------------------------------------------- /music-client/src/assets/css/index.scss: -------------------------------------------------------------------------------- 1 | @import "./var.scss"; 2 | @import "./global.scss"; 3 | 4 | html, 5 | body, 6 | div, 7 | span, 8 | h1, 9 | h2, 10 | h3, 11 | h4, 12 | h5, 13 | h6, 14 | p, 15 | blockquote, 16 | pre, 17 | dl, 18 | dt, 19 | dd, 20 | ol, 21 | ul, 22 | li, 23 | hr, 24 | img, 25 | a, 26 | form, 27 | label, 28 | tr, 29 | th, 30 | td, 31 | article, 32 | aside, 33 | canvas, 34 | details, 35 | embed, 36 | figure, 37 | figcaption, 38 | footer, 39 | header { 40 | padding: 0; 41 | margin: 0; 42 | } 43 | 44 | html, body, #app { 45 | height: 100%; 46 | } 47 | 48 | ul, 49 | li { 50 | list-style: none; 51 | display: inline-block; 52 | } 53 | 54 | .pagination { 55 | @include layout(center); 56 | transform: translateY(15px); 57 | } 58 | 59 | @media screen and (min-width: $sm) { 60 | .play-list-container { 61 | margin: 0 8% 30px 8%; 62 | } 63 | } 64 | 65 | /*el*/ 66 | .el-select-dropdown__item { 67 | display: block !important; 68 | } 69 | -------------------------------------------------------------------------------- /music-client/src/assets/css/sign.scss: -------------------------------------------------------------------------------- 1 | @import "@/assets/css/var.scss"; 2 | @import "@/assets/css/global.scss"; 3 | 4 | @media screen and (min-width: $sm) { 5 | .sign { 6 | width: 300px; 7 | position: absolute; 8 | left: 60vw; 9 | top: $header-height + 60px; 10 | } 11 | } 12 | 13 | @media screen and (max-width: $sm) { 14 | .sign { 15 | width: 60vw; 16 | position: relative; 17 | margin: auto; 18 | margin-top: -78vh; 19 | } 20 | } 21 | 22 | .sign { 23 | padding: 30px 50px; 24 | border-radius: 10px; 25 | background-color: $color-white; 26 | 27 | .sign-head { 28 | text-align: center; 29 | margin-bottom: 10px; 30 | font-size: 20px; 31 | font-weight: 600; 32 | } 33 | 34 | .sign-btn:deep(.el-form-item__content) { 35 | @include layout(space-between); 36 | button { 37 | width: 50%; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /music-client/src/assets/css/var.scss: -------------------------------------------------------------------------------- 1 | //Colors 2 | $color-white: #ffffff; 3 | $color-light-white: #fefefe; 4 | $color-grey: #67757f; 5 | $color-light-grey: #EFEFEF; 6 | $color-black: #000000; 7 | $color-blue-shallow: #a9dbf9; 8 | $color-blue: #95d2f6; 9 | $color-blue-active: #30a4fc; 10 | $color-blue-light: #2aa3ef; 11 | $color-blue-dark: #2796dd; 12 | $color-red: rgb(245, 108, 108); 13 | 14 | // Theme Global Color 15 | $theme-color: $color-blue; 16 | $theme-background-color: #e6ecf0; 17 | $theme-header-color: $color-light-white; 18 | $theme-footer-color: $theme-background-color; 19 | $theme-play-bar-color: $color-light-white; 20 | 21 | // Fonts 22 | $font-family: Lato, Helvetica Neue For Number, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, PingFang SC, Hiragino Sans GB, Microsoft YaHei, 23 | Helvetica Neue, Helvetica, Arial, sans-serif; 24 | // $font-family: Avenir, Helvetica, Arial, sans-serif; 25 | $font-size-default: 1rem; 26 | $font-size-logo: 1.5rem; 27 | $font-size-header: 1rem; 28 | 29 | // header 30 | $header-height: 60px; 31 | $header-padding: 0 4%; 32 | $header-margin: 0; 33 | $header-logo-width: 10%; 34 | $header-logo-margin: 0 10px; 35 | $header-nav-padding: 0 0.5rem; 36 | $header-nav-margin: 0 0.5rem; 37 | $header-search-radius: 10px; 38 | $header-search-height: $header-height - 20px; 39 | $header-search-max-width: 25vw; 40 | $header-search-min-width: 200px; 41 | $header-search-btn-height: ($header-height / 2); 42 | $header-search-btn-width: 60px; 43 | $header-user-width: ($header-height / 1.7); 44 | $header-user-margin: 1rem; 45 | $header-user-radius: 50%; 46 | $header-menu-width: 150px; 47 | $header-menu-padding: 7px 0px; 48 | $header-menu-radius: 4px; 49 | 50 | // page 51 | $content-padding: 0 8% 20px 8%; 52 | $border-radius-songlist: 12px; 53 | 54 | // footer 55 | $footer-height: 100px; 56 | 57 | // current-play 58 | $current-play: 350px; 59 | 60 | // play-bar 61 | $play-bar-height: 60px; 62 | 63 | // style 64 | $box-shadow: 0 0 10px rgba(0, 0, 0, 0.4); 65 | 66 | // Media queries 67 | $sm: 668px; 68 | $bg: 1024px; 69 | $md: 1300px; 70 | $lg: 1450px; 71 | -------------------------------------------------------------------------------- /music-client/src/assets/css/yin-current-play.scss: -------------------------------------------------------------------------------- 1 | @import "var.scss"; 2 | @import "global.scss"; 3 | 4 | .aside-fade-enter-active { 5 | transition: all 0.3s ease; 6 | } 7 | 8 | .aside-fade-leave-active { 9 | transition: all 0.2s ease; 10 | } 11 | 12 | .aside-fade-enter, 13 | .aside-fade-leave-to { 14 | transform: translateX(10px); 15 | opacity: 0; 16 | } 17 | 18 | .yin-current-play { 19 | font-size: 14px; 20 | width: $current-play; 21 | position: fixed; 22 | right: 0; 23 | top: $header-height; 24 | bottom: 0; 25 | padding-bottom: $footer-height; 26 | z-index: 99; 27 | background-color: $color-white; 28 | box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.4); 29 | overflow: hidden; 30 | } 31 | 32 | .title, 33 | .control, 34 | .menus li { 35 | padding-left: 20px; 36 | box-sizing: border-box; 37 | } 38 | 39 | .title { 40 | margin: 10px 0; 41 | } 42 | 43 | .control { 44 | margin: 3px 0; 45 | color: $color-grey; 46 | } 47 | 48 | .menus { 49 | width: 100%; 50 | height: calc(100% - 19px); 51 | cursor: pointer; 52 | z-index: 100; 53 | overflow: scroll; 54 | white-space: nowrap; 55 | li { 56 | display: block; 57 | width: 100%; 58 | height: 40px; 59 | line-height: 40px; 60 | &:hover { 61 | background-color: $color-light-grey; 62 | } 63 | } 64 | } 65 | 66 | .is-play { 67 | color: $color-black; 68 | font-weight: bold; 69 | } 70 | -------------------------------------------------------------------------------- /music-client/src/assets/css/yin-play-bar.scss: -------------------------------------------------------------------------------- 1 | @import "var.scss"; 2 | @import "global.scss"; 3 | 4 | .play-bar { 5 | position: fixed; 6 | z-index: 100; 7 | bottom: 0; 8 | width: 100%; 9 | transition: all 0.5s; 10 | 11 | .fold { 12 | position: absolute; 13 | bottom: $play-bar-height + 10px; 14 | left: 20px; 15 | cursor: pointer; 16 | } 17 | 18 | .progress { 19 | position: absolute; 20 | margin-top: -10px; 21 | } 22 | 23 | .control-box { 24 | display: flex; 25 | align-items: center; 26 | justify-content: space-between; 27 | height: $play-bar-height; 28 | width: 100%; 29 | background-color: $theme-play-bar-color; 30 | 31 | .song-ctr { 32 | position: relative; 33 | margin: auto; 34 | flex-wrap: nowrap; 35 | 36 | svg { 37 | width: 5rem; 38 | cursor: pointer; 39 | } 40 | } 41 | 42 | .info-box { 43 | .song-bar-img { 44 | width: calc($play-bar-height - 15px); 45 | height: calc($play-bar-height - 15px); 46 | border-radius: 4px; 47 | margin-right: 10px; 48 | cursor: pointer; 49 | } 50 | .song-info { 51 | font-size: 14px; 52 | } 53 | .time-info { 54 | font-size: 12px; 55 | color: $color-grey; 56 | } 57 | } 58 | 59 | .song-edit { 60 | width: 30%; 61 | justify-content: flex-end; 62 | } 63 | } 64 | } 65 | 66 | .turn { 67 | transform: rotate(180deg); 68 | } 69 | 70 | .show { 71 | bottom: -($play-bar-height) + 5px; 72 | } 73 | 74 | .icon { 75 | @include icon(1.1em, $color-black); 76 | } 77 | 78 | .active.icon { 79 | color: $color-red; 80 | } 81 | 82 | @media screen and (min-width: $sm) { 83 | .info-box { 84 | width: 30%; 85 | min-width: 200px; 86 | margin-left: 30px; 87 | } 88 | .song-ctr, 89 | .info-box, 90 | .song-edit { 91 | display: flex; 92 | align-items: center; 93 | } 94 | } 95 | 96 | @media screen and (max-width: $sm) { 97 | .info-box { 98 | display: flex; 99 | flex-direction: row; 100 | width: 70%; 101 | margin-left: 10px; 102 | } 103 | 104 | .yin-play-show { 105 | display: none; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /music-client/src/assets/icons/iconfont1.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | !function(d){var t,n='<svg><symbol id="icon-liebiao" viewBox="0 0 1024 1024"><path d="M892.928 128q28.672 0 48.64 19.968t19.968 48.64l0 52.224q0 28.672-19.968 48.64t-48.64 19.968l-759.808 0q-28.672 0-48.64-19.968t-19.968-48.64l0-52.224q0-28.672 19.968-48.64t48.64-19.968l759.808 0zM892.928 448.512q28.672 0 48.64 19.968t19.968 48.64l0 52.224q0 28.672-19.968 48.64t-48.64 19.968l-759.808 0q-28.672 0-48.64-19.968t-19.968-48.64l0-52.224q0-28.672 19.968-48.64t48.64-19.968l759.808 0zM892.928 769.024q28.672 0 48.64 19.968t19.968 48.64l0 52.224q0 28.672-19.968 48.64t-48.64 19.968l-759.808 0q-28.672 0-48.64-19.968t-19.968-48.64l0-52.224q0-28.672 19.968-48.64t48.64-19.968l759.808 0z" ></path></symbol><symbol id="icon-xiazai" viewBox="0 0 1024 1024"><path d="M819.203 405.649c0-169.66-137.541-307.19-307.201-307.19s-307.195 137.53-307.195 307.19c-113.105 0-204.8 91.69-204.8 204.801s91.695 204.801 204.8 204.801h102.4V733.33h-102.4c-67.755 0-122.88-55.12-122.88-122.88 0-67.761 55.125-122.881 122.88-122.881h81.92v-81.92c0-124.22 101.055-225.28 225.275-225.28 124.221 0 225.281 101.06 225.281 225.28v81.92h81.92c67.76 0 122.871 55.12 122.871 122.881 0 67.76-55.111 122.88-122.871 122.88h-102.4v81.921h102.4c113.09 0 204.791-91.69 204.791-204.801s-91.701-204.801-204.791-204.801z" fill="#040000" ></path><path d="M511.393 925.541l221.281-238.02-64.441-60-110.79 119.22V410.22h-92.16v336.47L354.488 627.521l-64.431 60z" fill="#040000" ></path></symbol></svg>',e=(t=document.getElementsByTagName("script"))[t.length-1].getAttribute("data-injectcss");if(e&&!d.__iconfont__svg__cssinject__){d.__iconfont__svg__cssinject__=!0;try{document.write("<style>.svgfont {display: inline-block;width: 1em;height: 1em;fill: currentColor;vertical-align: -0.1em;font-size:16px;}</style>")}catch(t){console&&console.log(t)}}!function(t){if(document.addEventListener)if(~["complete","loaded","interactive"].indexOf(document.readyState))setTimeout(t,0);else{var e=function(){document.removeEventListener("DOMContentLoaded",e,!1),t()};document.addEventListener("DOMContentLoaded",e,!1)}else document.attachEvent&&(n=t,i=d.document,o=!1,l=function(){o||(o=!0,n())},(c=function(){try{i.documentElement.doScroll("left")}catch(t){return void setTimeout(c,50)}l()})(),i.onreadystatechange=function(){"complete"==i.readyState&&(i.onreadystatechange=null,l())});var n,i,o,l,c}(function(){var t,e;(t=document.createElement("div")).innerHTML=n,n=null,(e=t.getElementsByTagName("svg")[0])&&(e.setAttribute("aria-hidden","true"),e.style.position="absolute",e.style.width=0,e.style.height=0,e.style.overflow="hidden",function(t,e){e.firstChild?function(t,e){e.parentNode.insertBefore(t,e)}(t,e.firstChild):e.appendChild(t)}(e,document.body))})}(window); 3 | -------------------------------------------------------------------------------- /music-client/src/assets/icons/index.js: -------------------------------------------------------------------------------- 1 | import './iconfont.js' 2 | import './iconfont1.js' 3 | import './iconfont2.js' 4 | import './iconfont3.js' 5 | import './iconfont4.js' 6 | -------------------------------------------------------------------------------- /music-client/src/assets/images/tubiao.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yin-Hongwei/music-website/2cccb623c437abc0b90c91948d2c559a387fd335/music-client/src/assets/images/tubiao.jpg -------------------------------------------------------------------------------- /music-client/src/assets/images/user.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yin-Hongwei/music-website/2cccb623c437abc0b90c91948d2c559a387fd335/music-client/src/assets/images/user.jpg -------------------------------------------------------------------------------- /music-client/src/components/layouts/YinAudio.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <audio :src="attachImageUrl(songUrl)" controls="controls" :ref="player" preload="true" @canplay="canplay" @timeupdate="timeupdate" @ended="ended"> 3 | <!--(1)属性:controls,preload(2)事件:canplay,timeupdate,ended(3)方法:play(),pause() --> 4 | <!--controls:向用户显示音频控件(播放/暂停/进度条/音量)--> 5 | <!--preload:属性规定是否在页面加载后载入音频--> 6 | <!--canplay:当音频/视频处于加载过程中时,会发生的事件--> 7 | <!--timeupdate:当目前的播放位置已更改时--> 8 | <!--ended:当目前的播放列表已结束时--> 9 | </audio> 10 | </template> 11 | 12 | <script lang="ts"> 13 | import { defineComponent, ref, getCurrentInstance, computed, watch } from "vue"; 14 | import { useStore } from "vuex"; 15 | import { HttpManager } from "@/api"; 16 | import { onMounted } from 'vue'; 17 | 18 | export default defineComponent({ 19 | setup() { 20 | 21 | const { proxy } = getCurrentInstance(); 22 | const store = useStore(); 23 | const divRef = ref<HTMLAudioElement>(); 24 | const player = (el) => { 25 | divRef.value = el; 26 | }; 27 | 28 | const muted = ref(true); // 添加一个 reactive 的 muted 属性 29 | 30 | const audioDom = document.querySelector('audio'); 31 | if (audioDom) { 32 | // 设置为静音并尝试自动播放 33 | audioDom.muted = true; 34 | audioDom.play() 35 | .then(() => { 36 | // 自动播放成功 37 | }) 38 | .catch(error => { 39 | // 自动播放失败,可能是因为没有用户交互 40 | console.error('自动播放失败,需要用户交互。', error); 41 | }); 42 | } 43 | 44 | 45 | const songUrl = computed(() => store.getters.songUrl); // 音乐链接 46 | const isPlay = computed(() => store.getters.isPlay); // 播放状态 47 | const volume = computed(() => store.getters.volume); // 音量 48 | const changeTime = computed(() => store.getters.changeTime); // 指定播放时刻 49 | const autoNext = computed(() => store.getters.autoNext); // 用于触发自动播放下一首 50 | // 监听播放还是暂停 51 | watch(isPlay, () => togglePlay()); 52 | // 跳到指定时刻播放 53 | watch(changeTime, () => (divRef.value.currentTime = changeTime.value)); 54 | watch(volume, (value) => (divRef.value.volume = value)); 55 | 56 | // 开始 / 暂停 57 | function togglePlay() { 58 | isPlay.value ? divRef.value.play() : divRef.value.pause(); 59 | } 60 | // 获取歌曲链接后准备播放 61 | function canplay() { 62 | // 记录音乐时长 63 | proxy.$store.commit("setDuration", divRef.value.duration); 64 | // 开始播放 65 | if (muted.value) { 66 | divRef.value.muted = false; 67 | muted.value = false; 68 | } 69 | // divRef.value.play(); 70 | proxy.$store.commit("setIsPlay", true); 71 | } 72 | // 音乐播放时记录音乐的播放位置 73 | function timeupdate() { 74 | proxy.$store.commit("setCurTime", divRef.value.currentTime); 75 | } 76 | // 音乐播放结束时触发 77 | function ended() { 78 | proxy.$store.commit("setIsPlay", false); 79 | proxy.$store.commit("setCurTime", 0); 80 | proxy.$store.commit("setAutoNext", !autoNext.value); 81 | } 82 | 83 | 84 | 85 | return { 86 | songUrl, 87 | player, 88 | canplay, 89 | timeupdate, 90 | ended, 91 | muted, 92 | attachImageUrl: HttpManager.attachImageUrl, 93 | }; 94 | }, 95 | }); 96 | </script> 97 | 98 | <style scoped> 99 | audio { 100 | display: none; 101 | } 102 | </style> 103 | -------------------------------------------------------------------------------- /music-client/src/components/layouts/YinCurrentPlay.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <transition name="aside-fade"> 3 | <div class="yin-current-play" v-if="showAside"> 4 | <h2 class="title">当前播放</h2> 5 | <div class="control">共 {{ (currentPlayList && currentPlayList.length) || 0 }} 首</div> 6 | <ul class="menus"> 7 | <li 8 | v-for="(item, index) in currentPlayList" 9 | :class="{ 'is-play': songId === item.id }" 10 | :key="index" 11 | @click="playMusic({ 12 | id: item.id, 13 | url: item.url, 14 | pic: item.pic, 15 | index: index, 16 | name: item.name, 17 | lyric: item.lyric, 18 | currentSongList: currentPlayList, 19 | })"> 20 | {{ getSongTitle(item.name) }} 21 | </li> 22 | </ul> 23 | </div> 24 | </transition> 25 | </template> 26 | 27 | <script lang="ts"> 28 | import { defineComponent, getCurrentInstance, computed, onMounted } from "vue"; 29 | import { useStore } from "vuex"; 30 | import mixin from "@/mixins/mixin"; 31 | 32 | export default defineComponent({ 33 | setup() { 34 | const { proxy } = getCurrentInstance(); 35 | const store = useStore(); 36 | const { getSongTitle, playMusic } = mixin(); 37 | 38 | const songId = computed(() => store.getters.songId); // 音乐 ID 39 | const currentPlayList = computed(() => store.getters.currentPlayList); // 当前播放 40 | const showAside = computed(() => store.getters.showAside); // 是否显示侧边栏 41 | 42 | onMounted(() => { 43 | document.addEventListener('click', () => { 44 | proxy.$store.commit('setShowAside', false) 45 | }, true) 46 | }) 47 | 48 | return { 49 | songId, 50 | currentPlayList, 51 | showAside, 52 | getSongTitle, 53 | playMusic, 54 | }; 55 | }, 56 | }); 57 | </script> 58 | 59 | <style lang="scss" scoped> 60 | @import "@/assets/css/yin-current-play.scss"; 61 | </style> 62 | -------------------------------------------------------------------------------- /music-client/src/components/layouts/YinFooter.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <div class="yin-footer"> 3 | <p v-for="(item, index) in footerList" :key="index"> 4 | {{ item }} 5 | </p> 6 | </div> 7 | </template> 8 | 9 | <script lang="ts"> 10 | import { defineComponent, readonly } from "vue"; 11 | 12 | export default defineComponent({ 13 | setup() { 14 | const footerList = readonly([ 15 | "关于 | 帮助 | 条款 | 反馈", 16 | "Copyright © 2019 Yin-Hongwei", 17 | ]); 18 | 19 | return { footerList }; 20 | }, 21 | }); 22 | </script> 23 | 24 | <style lang="scss" scoped> 25 | @import "@/assets/css/var.scss"; 26 | @import "@/assets/css/global.scss"; 27 | 28 | .yin-footer { 29 | width: 100%; 30 | height: $footer-height; 31 | padding: 20px 0; 32 | box-sizing: border-box; 33 | font-size: 14px; 34 | @include layout(center, center, column); 35 | } 36 | 37 | p { 38 | height: 30px; 39 | } 40 | </style> 41 | -------------------------------------------------------------------------------- /music-client/src/components/layouts/YinHeaderNav.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <ul class="yin-header-nav"> 3 | <li :class="{ active: item.name === activeName }" v-for="item in styleList" :key="item.path" @click="handleChangeView(item)"> 4 | {{ item.name }} 5 | </li> 6 | </ul> 7 | </template> 8 | 9 | <script lang="ts"> 10 | import { defineComponent, getCurrentInstance } from "vue"; 11 | 12 | export default defineComponent({ 13 | props: { 14 | styleList: Array, 15 | activeName: String, 16 | }, 17 | emits: ["click"], 18 | setup() { 19 | const { proxy } = getCurrentInstance(); 20 | 21 | function handleChangeView(item) { 22 | proxy.$emit("click", item.path, item.name); 23 | } 24 | return { 25 | handleChangeView, 26 | }; 27 | }, 28 | }); 29 | </script> 30 | 31 | <style lang="scss" scoped> 32 | @import "@/assets/css/var.scss"; 33 | 34 | li { 35 | margin: $header-nav-margin; 36 | padding: $header-nav-padding; 37 | line-height: 3.3rem; 38 | color: $color-grey; 39 | border-bottom: none; 40 | cursor: pointer; 41 | } 42 | 43 | li.active { 44 | color: $color-black; 45 | font-weight: 600; 46 | border-bottom: 5px solid $color-black; 47 | } 48 | </style> 49 | -------------------------------------------------------------------------------- /music-client/src/components/layouts/YinIcon.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <svg class="icon" aria-hidden="true"> 3 | <use :xlink:href="icon"></use> 4 | </svg> 5 | </template> 6 | 7 | <script lang="ts"> 8 | import { defineComponent } from "vue"; 9 | 10 | export default defineComponent({ 11 | props: { 12 | icon: String, 13 | }, 14 | }); 15 | </script> 16 | -------------------------------------------------------------------------------- /music-client/src/components/layouts/YinLoginLogo.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <div class="login-logo"> 3 | <yin-icon :icon="icon"></yin-icon> 4 | </div> 5 | </template> 6 | 7 | <script lang="ts"> 8 | import { defineComponent } from "vue"; 9 | import YinIcon from "./YinIcon.vue"; 10 | import { Icon } from "@/enums"; 11 | 12 | export default defineComponent({ 13 | components: { 14 | YinIcon, 15 | }, 16 | data() { 17 | return { 18 | icon: Icon.ERJI, 19 | }; 20 | }, 21 | }); 22 | </script> 23 | 24 | <style lang="scss" scoped> 25 | @import "@/assets/css/var.scss"; 26 | @import "@/assets/css/global.scss"; 27 | 28 | .login-logo { 29 | background-color: $color-blue-light; 30 | height: calc(100vh - $header-height - $footer-height); 31 | min-width: 50vw; 32 | overflow: hidden; 33 | @include layout(center, center); 34 | .icon { 35 | @include icon(36rem, $color-blue-dark); 36 | transform: rotate(-30deg); 37 | } 38 | } 39 | 40 | @media screen and (min-width: $sm) { 41 | .login-logo { 42 | width: 50vw; 43 | } 44 | } 45 | 46 | @media screen and (max-width: $sm) { 47 | .login-logo { 48 | width: 100vw; 49 | } 50 | } 51 | </style> 52 | -------------------------------------------------------------------------------- /music-client/src/components/layouts/YinNav.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <ul class="yin-nav"> 3 | <li v-for="(item, index) in styleList" :key="index" :class="{ active: item.name == activeName }" @click="handleChangeView(item)"> 4 | {{ item.name }} 5 | </li> 6 | </ul> 7 | </template> 8 | 9 | <script lang="ts"> 10 | import { defineComponent, getCurrentInstance } from "vue"; 11 | 12 | export default defineComponent({ 13 | props: { 14 | styleList: Array, 15 | activeName: String, 16 | }, 17 | emits: ["click"], 18 | setup() { 19 | const { proxy } = getCurrentInstance(); 20 | 21 | function handleChangeView(val) { 22 | proxy.$emit("click", val); 23 | } 24 | return { 25 | handleChangeView, 26 | }; 27 | }, 28 | }); 29 | </script> 30 | 31 | <style lang="scss" scoped> 32 | @import "@/assets/css/var.scss"; 33 | 34 | .yin-nav { 35 | width: 100%; 36 | li { 37 | line-height: 2rem; 38 | font-size: 1rem; 39 | color: $color-grey; 40 | border-bottom: none; 41 | cursor: pointer; 42 | } 43 | li.active { 44 | color: $color-black; 45 | font-weight: 600; 46 | } 47 | } 48 | 49 | @media screen and (min-width: $sm) { 50 | .yin-nav { 51 | li { 52 | margin: 0.5rem 1rem; 53 | } 54 | } 55 | } 56 | 57 | @media screen and (max-width: $sm) { 58 | .yin-nav { 59 | li { 60 | margin: 0.3rem 0.4rem; 61 | } 62 | } 63 | } 64 | </style> 65 | -------------------------------------------------------------------------------- /music-client/src/components/layouts/YinScrollTop.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <div class="scroll-top" @click="returnTop"> 3 | <div class="box-in"></div> 4 | </div> 5 | </template> 6 | 7 | <script lang="ts"> 8 | import { defineComponent } from "vue"; 9 | 10 | export default defineComponent({ 11 | setup() { 12 | function returnTop() { 13 | let timer: number = null; 14 | cancelAnimationFrame(timer); 15 | const startTime = new Date(); 16 | const S = document.body.scrollTop || document.documentElement.scrollTop; 17 | const T = 500; 18 | timer = requestAnimationFrame(function func() { 19 | const diff: number = new Date().valueOf() - startTime.valueOf(); 20 | const t = T - Math.max(0, T - diff); 21 | document.documentElement.scrollTop = document.body.scrollTop = S - (t * S) / T; 22 | timer = requestAnimationFrame(func); 23 | if (t === T) cancelAnimationFrame(timer); 24 | }); 25 | } 26 | return { returnTop }; 27 | }, 28 | }); 29 | </script> 30 | 31 | <style lang="scss" scoped> 32 | @import "@/assets/css/var.scss"; 33 | @import "@/assets/css/global.scss"; 34 | 35 | .scroll-top { 36 | position: fixed; 37 | z-index: 100; 38 | width: 40px; 39 | height: 20px; 40 | right: 10px; 41 | bottom: 80px; 42 | padding-top: 20px; 43 | text-align: center; 44 | background-color: $color-white; 45 | border-radius: 20%; 46 | overflow: hidden; 47 | box-shadow: 0 0 4px 3px rgba(0, 0, 0, 0.2); 48 | cursor: pointer; 49 | &:hover:before { 50 | top: 50%; 51 | } 52 | &:hover .box-in { 53 | visibility: hidden; 54 | } 55 | &:before { 56 | content: "回到顶部"; 57 | position: absolute; 58 | font-weight: bold; 59 | font-size: small; 60 | width: 30px; 61 | top: -50%; 62 | left: 50%; 63 | transform: translate(-50%, -50%); 64 | } 65 | } 66 | 67 | .box-in { 68 | visibility: visible; 69 | display: inline-block; 70 | height: 10px; 71 | width: 10px; 72 | border: 1px solid $color-black; 73 | border-color: $color-black transparent transparent $color-black; 74 | // 按钮中间的小三角翻转 75 | transform: rotate(45deg) translate(-5px, -5px); 76 | } 77 | </style> 78 | -------------------------------------------------------------------------------- /music-client/src/enums/area.ts: -------------------------------------------------------------------------------- 1 | // 地区选择 2 | export const AREA = [ 3 | { 4 | value: "北京", 5 | label: "北京", 6 | }, 7 | { 8 | value: "天津", 9 | label: "天津", 10 | }, 11 | { 12 | value: "河北", 13 | label: "河北", 14 | }, 15 | { 16 | value: "山西", 17 | label: "山西", 18 | }, 19 | { 20 | value: "内蒙古", 21 | label: "内蒙古", 22 | }, 23 | { 24 | value: "辽宁", 25 | label: "辽宁", 26 | }, 27 | { 28 | value: "吉林", 29 | label: "吉林", 30 | }, 31 | { 32 | value: "黑龙江", 33 | label: "黑龙江", 34 | }, 35 | { 36 | value: "上海", 37 | label: "上海", 38 | }, 39 | { 40 | value: "江苏", 41 | label: "江苏", 42 | }, 43 | { 44 | value: "浙江", 45 | label: "浙江", 46 | }, 47 | { 48 | value: "安徽", 49 | label: "安徽", 50 | }, 51 | { 52 | value: "福建", 53 | label: "福建", 54 | }, 55 | { 56 | value: "江西", 57 | label: "江西", 58 | }, 59 | { 60 | value: "山东", 61 | label: "山东", 62 | }, 63 | { 64 | value: "河南", 65 | label: "河南", 66 | }, 67 | { 68 | value: "湖北", 69 | label: "湖北", 70 | }, 71 | { 72 | value: "湖南", 73 | label: "湖南", 74 | }, 75 | { 76 | value: "广东", 77 | label: "广东", 78 | }, 79 | { 80 | value: "广西", 81 | label: "广西", 82 | }, 83 | { 84 | value: "海南", 85 | label: "海南", 86 | }, 87 | { 88 | value: "重庆", 89 | label: "重庆", 90 | }, 91 | { 92 | value: "四川", 93 | label: "四川", 94 | }, 95 | { 96 | value: "贵州", 97 | label: "贵州", 98 | }, 99 | { 100 | value: "云南", 101 | label: "云南", 102 | }, 103 | { 104 | value: "西藏", 105 | label: "西藏", 106 | }, 107 | { 108 | value: "陕西", 109 | label: "陕西", 110 | }, 111 | { 112 | value: "甘肃", 113 | label: "甘肃", 114 | }, 115 | { 116 | value: "青海", 117 | label: "青海", 118 | }, 119 | { 120 | value: "宁夏", 121 | label: "宁夏", 122 | }, 123 | { 124 | value: "新疆", 125 | label: "新疆", 126 | }, 127 | { 128 | value: "香港", 129 | label: "香港", 130 | }, 131 | { 132 | value: "澳门", 133 | label: "澳门", 134 | }, 135 | { 136 | value: "台湾", 137 | label: "台湾", 138 | }, 139 | ]; 140 | -------------------------------------------------------------------------------- /music-client/src/enums/icon.ts: -------------------------------------------------------------------------------- 1 | export const enum Icon { 2 | BOFANG = "#icon-bofang", // 播放 3 | ZANTING = "#icon-zanting", // 暂停 4 | YINLIANG = "#icon-yinliang", // 音量有背景 5 | YINLIANG1 = "#icon-yinliang1", // 音量无背景 6 | ERJI = "#icon-erji", // 耳机 7 | SOUSUO = "#icon-sousuo", // 搜索 8 | XIAZAI = "#icon-xiazai", // 下载 9 | ZHEDIE = "#icon-jiantou-xia-cuxiantiao", // 折叠 10 | SHANGYISHOU = "#icon-ziyuanldpi", // 上一首 11 | XIAYISHOU = "#icon-ziyuanldpi1", // 下一首 12 | JINGYIN = "#icon-yinliangjingyinheix", // 静音 13 | LIEBIAO = "#icon-liebiao", // 列表 14 | Dislike = "#icon-xihuan1", // 未收藏 15 | Like = "#icon-xihuan", // 收藏 16 | Support = "#icon-zan", // 赞 17 | XUNHUAN = "#icon-xunhuan", // 循环 18 | LUANXU = "#icon-xunhuan1", // 乱序 19 | } 20 | -------------------------------------------------------------------------------- /music-client/src/enums/index.ts: -------------------------------------------------------------------------------- 1 | import { AREA } from "./area"; 2 | import { Icon } from "./icon"; 3 | import { MUSICNAME } from "./music-name"; 4 | import { NavName, HEADERNAVLIST, SIGNLIST, MENULIST } from "./nav"; 5 | import { singerStyle } from "./singer"; 6 | import { SONGSTYLE } from "./songList"; 7 | import { RouterName } from "./router-name"; 8 | import { validatePassword, SignInRules, SignUpRules } from "./validate"; 9 | 10 | export { 11 | AREA, 12 | Icon, 13 | MUSICNAME, 14 | NavName, 15 | HEADERNAVLIST, 16 | RouterName, 17 | SIGNLIST, 18 | MENULIST, 19 | singerStyle, 20 | SONGSTYLE, 21 | validatePassword, 22 | SignInRules, 23 | SignUpRules, 24 | }; 25 | -------------------------------------------------------------------------------- /music-client/src/enums/music-name.ts: -------------------------------------------------------------------------------- 1 | export const MUSICNAME = "Yin-music"; 2 | -------------------------------------------------------------------------------- /music-client/src/enums/nav.ts: -------------------------------------------------------------------------------- 1 | import { RouterName } from "./router-name"; 2 | 3 | export const enum NavName { 4 | Home = "首页", 5 | SongSheet = "歌单", 6 | Singer = "歌手", 7 | Personal = "个人主页", 8 | Setting = "设置", 9 | SignIn = "登录", 10 | SignUp = "注册", 11 | SignOut = "退出", 12 | } 13 | 14 | // 左侧导航栏 15 | export const HEADERNAVLIST = [ 16 | { 17 | name: NavName.Home, 18 | path: RouterName.Home, 19 | }, 20 | { 21 | name: NavName.SongSheet, 22 | path: RouterName.SongSheet, 23 | }, 24 | { 25 | name: NavName.Singer, 26 | path: RouterName.Singer, 27 | }, 28 | ]; 29 | 30 | // 右侧导航栏 31 | export const SIGNLIST = [ 32 | { 33 | name: NavName.SignIn, 34 | path: RouterName.SignIn, 35 | }, 36 | { 37 | name: NavName.SignUp, 38 | path: RouterName.SignUp, 39 | }, 40 | ]; 41 | 42 | // 用户下拉菜单项 43 | export const MENULIST = [ 44 | { 45 | name: NavName.Personal, 46 | path: RouterName.Personal, 47 | }, 48 | { 49 | name: NavName.Setting, 50 | path: RouterName.Setting, 51 | }, 52 | { 53 | name: NavName.SignOut, 54 | path: RouterName.SignOut, 55 | }, 56 | ]; 57 | -------------------------------------------------------------------------------- /music-client/src/enums/router-name.ts: -------------------------------------------------------------------------------- 1 | export const enum RouterName { 2 | Home = "/", 3 | SongSheet = "/song-sheet", 4 | SongSheetDetail = "/song-sheet-detail", 5 | Singer = "/singer", 6 | SingerDetail = "/singer-detail", 7 | Personal = "/personal", 8 | Setting = "/setting", 9 | PersonalData = "/personal-data", 10 | SignIn = "/sign-in", 11 | SignUp = "/sign-up", 12 | Search = "/search", 13 | Lyric = "/lyric", 14 | Error = "/404", 15 | SignOut = "0", 16 | ForgotPassword="/FPassword", 17 | loginByemail="/loginByemail", 18 | } 19 | -------------------------------------------------------------------------------- /music-client/src/enums/singer.ts: -------------------------------------------------------------------------------- 1 | export const singerStyle = [ 2 | { 3 | name: "全部歌手", 4 | type: "-1", 5 | }, 6 | { 7 | name: "男歌手", 8 | type: "1", 9 | }, 10 | { 11 | name: "女歌手", 12 | type: "0", 13 | }, 14 | { 15 | name: "组合歌手", 16 | type: "2", 17 | }, 18 | ]; 19 | -------------------------------------------------------------------------------- /music-client/src/enums/songList.ts: -------------------------------------------------------------------------------- 1 | export const SONGSTYLE = [ 2 | { 3 | name: "全部歌单", 4 | type: "One", 5 | }, 6 | { 7 | name: "华语", 8 | type: "Two", 9 | }, 10 | { 11 | name: "粤语", 12 | type: "Three", 13 | }, 14 | { 15 | name: "欧美", 16 | type: "Four", 17 | }, 18 | { 19 | name: "日韩", 20 | type: "Five", 21 | }, 22 | { 23 | name: "轻音乐", 24 | type: "Six", 25 | }, 26 | { 27 | name: "BGM", 28 | type: "Seven", 29 | }, 30 | { 31 | name: "乐器", 32 | type: "Eight", 33 | }, 34 | ]; 35 | -------------------------------------------------------------------------------- /music-client/src/enums/validate.ts: -------------------------------------------------------------------------------- 1 | // 登录规则 2 | const validateName = (rule, value, callback) => { 3 | if (!value) { 4 | return callback(new Error("用户名不能为空")); 5 | } else { 6 | callback(); 7 | } 8 | }; 9 | 10 | export const validatePassword = (rule, value, callback) => { 11 | if (value === "") { 12 | callback(new Error("密码不能为空")); 13 | } else { 14 | callback(); 15 | } 16 | }; 17 | 18 | export const SignInRules = { 19 | username: [{ validator: validateName, trigger: "blur", min: 3 }], 20 | password: [{ validator: validatePassword, trigger: "blur", min: 3 }], 21 | }; 22 | 23 | // 注册规则 24 | export const SignUpRules = { 25 | username: [{ required: true, trigger: "blur", min: 3 }], 26 | password: [{ required: true, trigger: "blur", min: 3 }], 27 | sex: [{ required: true, message: "请选择性别", trigger: "change" }], 28 | phoneNum: [{ essage: "请选择日期", trigger: "blur" }], 29 | email: [ 30 | { message: "请输入邮箱地址", trigger: "blur" }, 31 | { 32 | type: "email", 33 | message: "请输入正确的邮箱地址", 34 | trigger: ["blur", "change"], 35 | }, 36 | ], 37 | birth: [{ required: true, type: "date", message: "请选择日期", trigger: "change" }], 38 | introduction: [{ message: "请输入介绍", trigger: "blur" }], 39 | location: [{ message: "请输入地区", trigger: "change" }], 40 | }; 41 | -------------------------------------------------------------------------------- /music-client/src/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from "vue"; 2 | import ElementPlus from "element-plus"; 3 | import App from "./App.vue"; 4 | import router from "./router"; 5 | import store from "./store"; 6 | import "element-plus/dist/index.css"; 7 | import "./assets/css/index.scss"; 8 | import "./assets/icons/index.js"; 9 | 10 | import { ComponentCustomProperties } from "vue"; 11 | import { Store } from "vuex"; 12 | declare module "@vue/runtime-core" { 13 | interface State { 14 | count: number; 15 | } 16 | 17 | interface ComponentCustomProperties { 18 | $store: Store<State>; 19 | } 20 | } 21 | 22 | createApp(App).use(store).use(router).use(ElementPlus).mount("#app"); 23 | -------------------------------------------------------------------------------- /music-client/src/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | declare module "*.vue" { 3 | import type { DefineComponent } from "vue"; 4 | const component: DefineComponent<{}, {}, any>; 5 | export default component; 6 | } 7 | 8 | declare module "vue/types/vue" { 9 | import VueRouter, { Route } from "vue-router"; 10 | 11 | interface Vue { 12 | $router: VueRouter; 13 | $route: Route; 14 | } 15 | } 16 | 17 | interface ResponseBody { 18 | code: string; 19 | success: boolean; 20 | message: string; 21 | type: string; 22 | data?: any; 23 | } 24 | -------------------------------------------------------------------------------- /music-client/src/store/configure.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | state: { 3 | token: false, // 用户是否登录 4 | showAside: false, // 是否显示侧边栏 5 | searchWord: "", // 搜索关键词 6 | activeNavName: "", // 导航栏名称 7 | }, 8 | getters: { 9 | token: (state) => state.token, 10 | activeNavName: (state) => state.activeNavName, 11 | showAside: (state) => state.showAside, 12 | searchWord: (state) => state.searchWord, 13 | }, 14 | mutations: { 15 | setToken: (state, token) => { 16 | state.token = token; 17 | }, 18 | setActiveNavName: (state, activeNavName) => { 19 | state.activeNavName = activeNavName; 20 | }, 21 | setShowAside: (state, showAside) => { 22 | state.showAside = showAside; 23 | }, 24 | setSearchWord: (state, searchWord) => { 25 | state.searchWord = searchWord; 26 | }, 27 | }, 28 | }; 29 | -------------------------------------------------------------------------------- /music-client/src/store/index.ts: -------------------------------------------------------------------------------- 1 | import { createStore } from "vuex"; 2 | import configure from "./configure"; 3 | import user from "./user"; 4 | import song from "./song"; 5 | 6 | export default createStore({ 7 | modules: { 8 | configure, 9 | user, 10 | song, 11 | }, 12 | }); 13 | -------------------------------------------------------------------------------- /music-client/src/store/user.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | state: { 3 | userId: "", // ID 4 | username: "", // 名字 5 | userPic: "", // 图片 6 | }, 7 | getters: { 8 | userId: (state) => state.userId, 9 | username: (state) => state.username, 10 | userPic: (state) => state.userPic, 11 | }, 12 | mutations: { 13 | setUserId: (state, userId) => { 14 | state.userId = userId; 15 | }, 16 | setUsername: (state, username) => { 17 | state.username = username; 18 | }, 19 | setUserPic: (state, userPic) => { 20 | state.userPic = userPic; 21 | }, 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /music-client/src/views/FPassword.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <el-container id="appSend"> 3 | <el-header> 4 | <h1>修改密码</h1> 5 | </el-header> 6 | <el-main> 7 | <el-form @submit.prevent="handleSubmit"> 8 | <el-form-item label="邮箱:" prop="email"> 9 | <el-input id="email" v-model="email" type="email" required /> 10 | <el-button @click="sendVerificationCode">发送验证码</el-button> 11 | </el-form-item> 12 | <el-form-item label="验证码:" prop="code"> 13 | <el-input id="code" v-model="code" type="text" required /> 14 | </el-form-item> 15 | <el-form-item label="新密码:" prop="password"> 16 | <el-input id="password" v-model="password" type="password" required /> 17 | </el-form-item> 18 | <el-form-item label="确认密码:" prop="confirmPassword"> 19 | <el-input id="confirmPassword" v-model="confirmPassword" type="password" required /> 20 | </el-form-item> 21 | <el-form-item> 22 | 23 | <el-button @click="handleSubmit" type="submit">提交</el-button> 24 | 25 | </el-form-item> 26 | </el-form> 27 | </el-main> 28 | </el-container> 29 | </template> 30 | 31 | 32 | <style> 33 | #appSend { 34 | max-width: 400px; 35 | margin: 0 auto; 36 | } 37 | </style> 38 | 39 | <script> 40 | import axios from 'axios'; 41 | export default { 42 | 43 | 44 | data() { 45 | 46 | return { 47 | email: "", 48 | code: "", 49 | password: "", 50 | confirmPassword: "" 51 | }; 52 | }, 53 | methods: { 54 | async sendVerificationCode() { 55 | try { 56 | const email =document.getElementById('email').value; 57 | const response = await axios.get('http://localhost:8888/user/sendVerificationCode',({params: { 58 | email: email 59 | }})); 60 | console.log(response.data); 61 | this.$message({ 62 | message: response.data, 63 | type: 'success' 64 | }); 65 | } catch (error) { 66 | console.error('Error submitting email:'); 67 | this.$message({ 68 | message: 'response.data', 69 | type: 'error' 70 | }); 71 | } 72 | }, 73 | async handleSubmit() { 74 | try { 75 | const email =document.getElementById('email').value; 76 | const code=document.getElementById('code').value 77 | const password=document.getElementById('password').value 78 | const confirmPassword=document.getElementById('confirmPassword').value 79 | const data = { 80 | email: email, 81 | code: code, 82 | password: password, 83 | confirmPassword: confirmPassword 84 | }; 85 | const response = await axios.post('http://localhost:8888/user/resetPassword', data); 86 | console.log(response.data); 87 | this.$message({ 88 | message: response.data, 89 | type: 'success' 90 | }); 91 | } catch (error) { 92 | this.$message({ 93 | message: 'response.data', 94 | type: 'error' 95 | }); 96 | } 97 | } 98 | 99 | }, 100 | }; 101 | </script> 102 | -------------------------------------------------------------------------------- /music-client/src/views/Home.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <!--轮播图--> 3 | <el-carousel v-if="swiperList.length" class="swiper-container" type="card" height="20vw" :interval="4000"> 4 | <el-carousel-item v-for="(item, index) in swiperList" :key="index"> 5 | <img :src="HttpManager.attachImageUrl(item.pic)" /> 6 | </el-carousel-item> 7 | </el-carousel> 8 | <!--热门歌单--> 9 | <play-list class="play-list-container" title="歌单" path="song-sheet-detail" :playList="songList"></play-list> 10 | <!--热门歌手--> 11 | <play-list class="play-list-container" title="歌手" path="singer-detail" :playList="singerList"></play-list> 12 | </template> 13 | 14 | <script lang="ts" setup> 15 | import { ref, onMounted } from "vue"; 16 | 17 | import PlayList from "@/components/PlayList.vue"; 18 | import { NavName } from "@/enums"; 19 | import { HttpManager } from "@/api"; 20 | import mixin from "@/mixins/mixin"; 21 | 22 | const songList = ref([]); // 歌单列表 23 | const singerList = ref([]); // 歌手列表 24 | const swiperList = ref([]);// 轮播图 每次都在进行查询 25 | const { changeIndex } = mixin(); 26 | try { 27 | 28 | HttpManager.getBannerList().then((res) => { 29 | swiperList.value = (res as ResponseBody).data.sort(); 30 | }); 31 | 32 | HttpManager.getSongList().then((res) => { 33 | songList.value = (res as ResponseBody).data.sort().slice(0, 10); 34 | }); 35 | 36 | HttpManager.getAllSinger().then((res) => { 37 | singerList.value = (res as ResponseBody).data.sort().slice(0, 10); 38 | }); 39 | 40 | onMounted(() => { 41 | changeIndex(NavName.Home); 42 | }); 43 | } catch (error) { 44 | console.error(error); 45 | } 46 | </script> 47 | 48 | <style lang="scss" scoped> 49 | @import "@/assets/css/var.scss"; 50 | 51 | /*轮播图*/ 52 | .swiper-container { 53 | width: 90%; 54 | margin: auto; 55 | padding-top: 20px; 56 | img { 57 | width: 100%; 58 | } 59 | } 60 | 61 | .swiper-container:deep(.el-carousel__indicators.el-carousel__indicators--outside) { 62 | display: inline-block; 63 | transform: translateX(30vw); 64 | } 65 | 66 | .el-slider__runway { 67 | background-color: $color-blue; 68 | } 69 | </style> 70 | -------------------------------------------------------------------------------- /music-client/src/views/YinContainer.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <el-container> 3 | <el-header> 4 | <yin-header></yin-header> 5 | </el-header> 6 | <el-main> 7 | <router-view /> 8 | <yin-current-play></yin-current-play> 9 | <yin-play-bar></yin-play-bar> 10 | <yin-scroll-top></yin-scroll-top> 11 | <yin-audio></yin-audio> 12 | </el-main> 13 | <el-footer> 14 | <yin-footer></yin-footer> 15 | </el-footer> 16 | </el-container> 17 | </template> 18 | 19 | <script lang="ts" setup> 20 | import { getCurrentInstance } from "vue"; 21 | import YinHeader from "@/components/layouts/YinHeader.vue"; 22 | import YinCurrentPlay from "@/components/layouts/YinCurrentPlay.vue"; 23 | import YinPlayBar from "@/components/layouts/YinPlayBar.vue"; 24 | import YinScrollTop from "@/components/layouts/YinScrollTop.vue"; 25 | import YinFooter from "@/components/layouts/YinFooter.vue"; 26 | import YinAudio from "@/components/layouts/YinAudio.vue"; 27 | 28 | const { proxy } = getCurrentInstance(); 29 | 30 | if (sessionStorage.getItem("dataStore")) { 31 | proxy.$store.replaceState(Object.assign({}, proxy.$store.state, JSON.parse(sessionStorage.getItem("dataStore")))); 32 | } 33 | 34 | window.addEventListener("beforeunload", () => { 35 | sessionStorage.setItem("dataStore", JSON.stringify(proxy.$store.state)); 36 | }); 37 | </script> 38 | 39 | <style lang="scss" scoped> 40 | @import "@/assets/css/var.scss"; 41 | @import "@/assets/css/global.scss"; 42 | 43 | .el-container { 44 | min-height: calc(100% - 60px); 45 | } 46 | .el-header { 47 | padding: 0; 48 | } 49 | .el-main { 50 | padding-left: 0; 51 | padding-right: 0; 52 | } 53 | </style> 54 | -------------------------------------------------------------------------------- /music-client/src/views/error/404.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <div class="error-page"> 3 | <div class="error-code">404</div> 4 | </div> 5 | </template> 6 | 7 | <style scoped> 8 | .error-page { 9 | display: flex; 10 | justify-content: center; 11 | align-items: stretch; 12 | flex-direction: row; 13 | flex-wrap: nowrap; 14 | width: 100%; 15 | height: 100%; 16 | padding: 11rem 0; 17 | box-sizing: border-box; 18 | } 19 | 20 | .error-code { 21 | font-size: 250px; 22 | font-weight: bolder; 23 | color: #000000; 24 | } 25 | </style> 26 | -------------------------------------------------------------------------------- /music-client/src/views/loginByemail.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <yin-login-logo></yin-login-logo> 3 | <div class="sign"> 4 | <div class="sign-head"> 5 | <span>邮箱登录</span> 6 | </div> 7 | <el-form ref="signInForm" status-icon :model="registerForm" :rules="SignInRules"> 8 | <el-form-item prop="email"> 9 | <el-input placeholder="邮箱" v-model="registerForm.email"></el-input> 10 | </el-form-item> 11 | <el-form-item prop="password"> 12 | <el-input type="password" placeholder="密码" v-model="registerForm.password" @keyup.enter="handleLoginIn"></el-input> 13 | </el-form-item> 14 | <el-form-item class="sign-btn"> 15 | <el-button type="primary" @click="handleLoginIn">登录</el-button> 16 | <el-button type="primary" @click="handleLoginCancel">取消</el-button> 17 | </el-form-item> 18 | </el-form> 19 | </div> 20 | </template> 21 | 22 | <script lang="ts"> 23 | import { defineComponent, reactive, getCurrentInstance } from "vue"; 24 | import mixin from "@/mixins/mixin"; 25 | import YinLoginLogo from "@/components/layouts/YinLoginLogo.vue"; 26 | import { HttpManager } from "@/api"; 27 | import { NavName, RouterName, SignInRules } from "@/enums"; 28 | 29 | export default defineComponent({ 30 | components: { 31 | YinLoginLogo, 32 | }, 33 | setup() { 34 | const { proxy } = getCurrentInstance(); 35 | const { routerManager, changeIndex } = mixin(); 36 | 37 | // 登录 38 | const registerForm = reactive({ 39 | email: "", 40 | password: "", 41 | }); 42 | 43 | async function handleLoginCancel() { 44 | routerManager(RouterName.SignIn, { path: RouterName.SignIn }); 45 | } 46 | 47 | async function handleLoginIn() { 48 | let canRun = true; 49 | (proxy.$refs["signInForm"] as any).validate((valid) => { 50 | if (!valid) return (canRun = false); 51 | }); 52 | if (!canRun) return; 53 | 54 | 55 | try { 56 | const email = registerForm.email; 57 | const password = registerForm.password; 58 | const result = (await HttpManager.signInByemail({email,password})) as ResponseBody; 59 | (proxy as any).$message({ 60 | message: result.message, 61 | type: result.type, 62 | }); 63 | 64 | if (result.success) { 65 | proxy.$store.commit("setUserId", result.data[0].id); 66 | proxy.$store.commit("setUsername", result.data[0].username); 67 | proxy.$store.commit("setUserPic", result.data[0].avator); 68 | proxy.$store.commit("setToken", true); 69 | changeIndex(NavName.Home); 70 | routerManager(RouterName.Home, { path: RouterName.Home }); 71 | } 72 | } catch (error) { 73 | console.error(error); 74 | } 75 | } 76 | 77 | return { 78 | registerForm, 79 | SignInRules, 80 | handleLoginIn, 81 | handleLoginCancel, 82 | }; 83 | }, 84 | }); 85 | </script> 86 | 87 | <style lang="scss" scoped> 88 | @import "@/assets/css/sign.scss"; 89 | </style> 90 | -------------------------------------------------------------------------------- /music-client/src/views/search/Search.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <div class="search"> 3 | <yin-nav :styleList="searchNavList" :activeName="activeName" @click="handleChangeView"></yin-nav> 4 | <component class="search-list" :is="currentView"></component> 5 | </div> 6 | </template> 7 | 8 | <script lang="ts"> 9 | import { defineComponent } from "vue"; 10 | import YinNav from "@/components/layouts/YinNav.vue"; 11 | import SearchSong from "./SearchSong.vue"; 12 | import SearchSongList from "./SearchSongList.vue"; 13 | 14 | export default defineComponent({ 15 | components: { 16 | YinNav, 17 | SearchSong, 18 | SearchSongList, 19 | }, 20 | data() { 21 | return { 22 | searchNavList: [ 23 | { 24 | name: "歌曲", 25 | value: "SearchSong", 26 | }, 27 | { 28 | name: "歌单", 29 | value: "SearchSongList", 30 | }, 31 | ], 32 | activeName: "歌曲", 33 | currentView: "SearchSong", 34 | }; 35 | }, 36 | methods: { 37 | handleChangeView(item) { 38 | this.activeName = item.name; 39 | this.currentView = item.value; 40 | }, 41 | }, 42 | }); 43 | </script> 44 | 45 | <style lang="scss" scoped> 46 | @import "@/assets/css/var.scss"; 47 | @import "@/assets/css/global.scss"; 48 | 49 | .search { 50 | margin: auto; 51 | width: 900px; 52 | 53 | .search-list { 54 | min-height: 480px; 55 | } 56 | } 57 | </style> 58 | -------------------------------------------------------------------------------- /music-client/src/views/search/SearchSong.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <div class="search-song"> 3 | <song-list :songList="currentSongList"></song-list> 4 | </div> 5 | </template> 6 | 7 | <script lang="ts"> 8 | import { defineComponent, ref, computed, watch, onMounted, getCurrentInstance } from "vue"; 9 | import { useStore } from "vuex"; 10 | import SongList from "@/components/SongList.vue"; 11 | import { HttpManager } from "@/api"; 12 | 13 | export default defineComponent({ 14 | components: { 15 | SongList, 16 | }, 17 | setup() { 18 | const { proxy } = getCurrentInstance(); 19 | const store = useStore(); 20 | 21 | const currentSongList = ref([]); // 存放的音乐 22 | const searchWord = computed(() => store.getters.searchWord); 23 | watch(searchWord, (value) => { 24 | searchSong(value); 25 | }); 26 | 27 | // 搜索音乐 28 | async function searchSong(value) { 29 | if (!value) { 30 | currentSongList.value = []; 31 | return; 32 | } 33 | const result = (await HttpManager.getSongOfSingerName(value)) as ResponseBody; 34 | if (!result.data.length) { 35 | currentSongList.value = []; 36 | (proxy as any).$message({ 37 | message: "暂时没有相关歌曲", 38 | type: "warning", 39 | }); 40 | } else { 41 | currentSongList.value = result.data; 42 | } 43 | } 44 | 45 | onMounted(() => { 46 | searchSong(proxy.$route.query.keywords); 47 | }); 48 | 49 | return { 50 | currentSongList, 51 | }; 52 | }, 53 | }); 54 | </script> 55 | -------------------------------------------------------------------------------- /music-client/src/views/search/SearchSongList.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <div class="search-song-list"> 3 | <play-list :playList="playList" path="song-sheet-detail"></play-list> 4 | </div> 5 | </template> 6 | 7 | <script lang="ts"> 8 | import { defineComponent, ref, computed, watch, onMounted, getCurrentInstance } from "vue"; 9 | import { useStore } from "vuex"; 10 | import PlayList from "@/components/PlayList.vue"; 11 | import { HttpManager } from "@/api"; 12 | 13 | export default defineComponent({ 14 | components: { 15 | PlayList, 16 | }, 17 | setup() { 18 | const { proxy } = getCurrentInstance(); 19 | const store = useStore(); 20 | 21 | const playList = ref([]); 22 | const searchWord = computed(() => store.getters.searchWord); 23 | watch(searchWord, (value) => { 24 | getSearchList(value); 25 | }); 26 | 27 | async function getSearchList(value) { 28 | if (!value) return; 29 | const result = (await HttpManager.getSongListOfLikeTitle(value)) as ResponseBody; 30 | if (!result.data.length) { 31 | (proxy as any).$message({ 32 | message: "暂无该歌曲内容", 33 | type: "warning", 34 | }); 35 | } else { 36 | playList.value = result.data; 37 | } 38 | } 39 | 40 | onMounted(() => { 41 | getSearchList(proxy.$route.query.keywords); 42 | }); 43 | 44 | return { 45 | playList, 46 | }; 47 | }, 48 | }); 49 | </script> 50 | -------------------------------------------------------------------------------- /music-client/src/views/setting/Password.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <el-form ref="passwordForm" label-width="70px" :model="form" :rules="rules"> 3 | <el-form-item label="旧密码" prop="oldPassword"> 4 | <el-input type="password" v-model="form.oldPassword" /> 5 | </el-form-item> 6 | <el-form-item label="新密码" prop="newPassword"> 7 | <el-input type="password" v-model="form.newPassword" /> 8 | </el-form-item> 9 | <el-form-item label="密码确认" prop="confirmPassword"> 10 | <el-input type="password" v-model="form.confirmPassword" /> 11 | </el-form-item> 12 | <el-form-item> 13 | <el-button @click="clearData()">重置</el-button> 14 | <el-button type="primary" @click="confirm()">确认修改</el-button> 15 | </el-form-item> 16 | </el-form> 17 | </template> 18 | 19 | <script lang="ts"> 20 | import { defineComponent, getCurrentInstance, computed, reactive } from "vue"; 21 | import { useStore } from "vuex"; 22 | import mixin from "@/mixins/mixin"; 23 | import { HttpManager } from "@/api"; 24 | import { validatePassword } from "@/enums"; 25 | 26 | export default defineComponent({ 27 | setup() { 28 | const store = useStore(); 29 | const { proxy } = getCurrentInstance(); 30 | const { goBack } = mixin(); 31 | 32 | const form = reactive({ 33 | oldPassword: "", 34 | newPassword: "", 35 | confirmPassword: "", 36 | }); 37 | const userId = computed(() => store.getters.userId); 38 | const userName = computed(() => store.getters.username); 39 | 40 | const validateCheck = (rule: any, value: any, callback: any) => { 41 | if (value === "") { 42 | callback(new Error("密码不能为空")); 43 | } else if (value !== form.newPassword) { 44 | callback(new Error("请输入正确密码")); 45 | } else { 46 | callback(); 47 | } 48 | }; 49 | const rules = reactive({ 50 | oldPassword: [{ validator: validatePassword, trigger: "blur", min: 3 }], 51 | newPassword: [{ validator: validatePassword, trigger: "blur", min: 3 }], 52 | confirmPassword: [{ validator: validateCheck, trigger: "blur", min: 3 }], 53 | }); 54 | 55 | async function clearData() { 56 | form.oldPassword = ""; 57 | form.newPassword = ""; 58 | form.confirmPassword = ""; 59 | } 60 | 61 | async function confirm() { 62 | let canRun = true; 63 | (proxy.$refs["passwordForm"] as any).validate((valid) => { 64 | if (!valid) return (canRun = false); 65 | }); 66 | if (!canRun) return; 67 | 68 | 69 | const id = userId.value; 70 | const username = userName.value; 71 | const oldPassword = form.oldPassword; 72 | const password = form.newPassword; 73 | 74 | const result = (await HttpManager.updateUserPassword({id,username,oldPassword,password})) as ResponseBody; 75 | (proxy as any).$message({ 76 | message: result.message, 77 | type: result.type, 78 | }); 79 | if (result.success) goBack(); 80 | } 81 | 82 | return { 83 | form, 84 | clearData, 85 | confirm, 86 | rules, 87 | }; 88 | }, 89 | }); 90 | </script> 91 | 92 | <style></style> 93 | -------------------------------------------------------------------------------- /music-client/src/views/setting/Setting.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <div class="setting"> 3 | <h1>设置</h1> 4 | <el-tabs tab-position="left"> 5 | <el-tab-pane label="个人资料" class="content"> 6 | <Personal-data></Personal-data> 7 | </el-tab-pane> 8 | <el-tab-pane label="更改密码" class="content"> 9 | <Password></Password> 10 | </el-tab-pane> 11 | <el-tab-pane label="账号和安全" class="content"> 12 | <el-button type="danger" :icon="Delete" @click="cancelAccount">注销账号</el-button> 13 | </el-tab-pane> 14 | </el-tabs> 15 | </div> 16 | </template> 17 | 18 | <script lang="ts"> 19 | import { defineComponent, getCurrentInstance, computed, reactive } from "vue"; 20 | import { Delete } from "@element-plus/icons-vue"; 21 | import PersonalData from "./PersonalData.vue"; 22 | import Password from "./Password.vue"; 23 | import { HttpManager } from "@/api"; 24 | import { useStore } from "vuex"; 25 | import mixin from "@/mixins/mixin"; 26 | import { RouterName } from "@/enums"; 27 | 28 | export default defineComponent({ 29 | components: { 30 | PersonalData, 31 | Password, 32 | }, 33 | setup() { 34 | const { proxy } = getCurrentInstance(); 35 | const store = useStore(); 36 | const { routerManager } = mixin(); 37 | 38 | const userId = computed(() => store.getters.userId); 39 | 40 | async function cancelAccount() { 41 | const result = (await HttpManager.deleteUser(userId.value)) as ResponseBody; 42 | (proxy as any).$message({ 43 | message: result.message, 44 | type: result.type, 45 | }); 46 | routerManager(RouterName.SignIn, { path: RouterName.SignIn }); 47 | proxy.$store.commit("setToken", false); 48 | } 49 | 50 | return { 51 | Delete, 52 | cancelAccount, 53 | }; 54 | }, 55 | }); 56 | </script> 57 | 58 | <style lang="scss" scoped> 59 | @import "@/assets/css/var.scss"; 60 | @import "@/assets/css/global.scss"; 61 | 62 | h1 { 63 | border-bottom: 1px solid $color-grey; 64 | } 65 | 66 | .content { 67 | padding-top: 20px; 68 | text-align: center; 69 | } 70 | 71 | @media screen and (min-width: $sm) { 72 | .setting { 73 | margin: 30px 10%; 74 | margin-top: 0; 75 | padding: 20px; 76 | min-height: 60vh; 77 | } 78 | } 79 | 80 | @media screen and (max-width: $sm) { 81 | .setting { 82 | padding: 20px; 83 | } 84 | } 85 | </style> 86 | -------------------------------------------------------------------------------- /music-client/src/views/setting/Upload.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <div class="upload"> 3 | <el-upload drag :action="uploadUrl()" :show-file-list="false" :on-success="handleAvatarSuccess" :before-upload="beforeAvatarUpload"> 4 | <el-icon class="el-icon--upload"><upload-filled /></el-icon> 5 | <div class="el-upload__text">将文件拖到此处或点击上传</div> 6 | <template #tip> 7 | <p class="el-upload__tip">只能上传 {{ uploadTypes.join("、") }} 文件, 且不超过10M</p> 8 | </template> 9 | </el-upload> 10 | </div> 11 | </template> 12 | 13 | <script lang="ts"> 14 | import { defineComponent, ref, computed, getCurrentInstance } from "vue"; 15 | import { useStore } from "vuex"; 16 | import { UploadFilled } from "@element-plus/icons-vue"; 17 | import { HttpManager } from "@/api"; 18 | 19 | export default defineComponent({ 20 | components: { 21 | UploadFilled, 22 | }, 23 | setup() { 24 | const { proxy } = getCurrentInstance(); 25 | const store = useStore(); 26 | 27 | const uploadTypes = ref(["jpg", "jpeg", "png", "gif"]); 28 | const userId = computed(() => store.getters.userId); 29 | 30 | function uploadUrl() { 31 | return HttpManager.uploadUrl(userId.value); 32 | } 33 | 34 | function beforeAvatarUpload(file) { 35 | const ltCode = 2; 36 | const isLt10M = file.size / 1024 / 1024; 37 | const isExistFileType = uploadTypes.value.includes(file.type.replace(/image\//, "")); 38 | 39 | if (isLt10M > ltCode || isLt10M <= 0) { 40 | (proxy as any).$message.error(`图片大小范围是 0~${ltCode}MB!`); 41 | } 42 | if (!isExistFileType) { 43 | (proxy as any).$message.error(`图片只支持 ${uploadTypes.value.join("、")} 格式!`); 44 | } 45 | 46 | return isLt10M && isExistFileType; 47 | } 48 | 49 | function handleAvatarSuccess(response, file) { 50 | (proxy as any).$message({ 51 | message: response.message, 52 | type: response.type, 53 | }); 54 | 55 | if (response.success) proxy.$store.commit("setUserPic", response.data); 56 | } 57 | 58 | return { 59 | uploadTypes, 60 | uploadUrl, 61 | beforeAvatarUpload, 62 | handleAvatarSuccess, 63 | }; 64 | }, 65 | }); 66 | </script> 67 | 68 | <style scoped> 69 | .upload { 70 | width: 100%; 71 | height: 300px; 72 | display: flex; 73 | justify-content: center; 74 | align-items: center; 75 | } 76 | </style> 77 | -------------------------------------------------------------------------------- /music-client/src/views/singer/Singer.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <div class="play-list-container"> 3 | <yin-nav :styleList="singerStyle" :activeName="activeName" @click="handleChangeView"></yin-nav> 4 | <play-list :playList="data" path="singer-detail"></play-list> 5 | <el-pagination 6 | class="pagination" 7 | background 8 | layout="total, prev, pager, next" 9 | :current-page="currentPage" 10 | :page-size="pageSize" 11 | :total="allPlayList.length" 12 | @current-change="handleCurrentChange" 13 | > 14 | </el-pagination> 15 | </div> 16 | </template> 17 | 18 | <script lang="ts" setup> 19 | import { ref, computed } from "vue"; 20 | import YinNav from "@/components/layouts/YinNav.vue"; 21 | import PlayList from "@/components/PlayList.vue"; 22 | import { singerStyle } from "@/enums"; 23 | import { HttpManager } from "@/api"; 24 | 25 | // data 26 | const activeName = ref("全部歌手"); 27 | const pageSize = ref(15); // 页数 28 | const currentPage = ref(1); // 当前页 29 | const allPlayList = ref([]); 30 | // computed 31 | const data = computed(() => { 32 | return allPlayList.value.slice((currentPage.value - 1) * pageSize.value, currentPage.value * pageSize.value); 33 | }); 34 | 35 | // 获取所有歌手 36 | async function getAllSinger() { 37 | const result = (await HttpManager.getAllSinger()) as ResponseBody; 38 | currentPage.value = 1; 39 | allPlayList.value = result.data; 40 | } 41 | 42 | getAllSinger(); 43 | 44 | // 获取当前页 45 | function handleCurrentChange(val) { 46 | currentPage.value = val; 47 | } 48 | 49 | function handleChangeView(item) { 50 | activeName.value = item.name; 51 | allPlayList.value = []; 52 | if (item.name === "全部歌手") { 53 | getAllSinger(); 54 | } else { 55 | getSingerSex(item.type); 56 | } 57 | } 58 | 59 | // 通过性别对歌手分类 60 | async function getSingerSex(sex) { 61 | const result = (await HttpManager.getSingerOfSex(sex)) as ResponseBody; 62 | currentPage.value = 1; 63 | allPlayList.value = result.data; 64 | } 65 | </script> 66 | -------------------------------------------------------------------------------- /music-client/src/views/singer/SingerDetail.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <el-container> 3 | <el-aside class="album-slide"> 4 | <el-image class="singer-img" fit="contain" :src="attachImageUrl(songDetails.pic)" /> 5 | <div class="album-info"> 6 | <h2>基本资料</h2> 7 | <ul> 8 | <li v-if="songDetails.sex !== 2">性别:{{ getUserSex(songDetails.sex) }}</li> 9 | <li>生日:{{ getBirth(songDetails.birth) }}</li> 10 | <li>故乡:{{ songDetails.location }}</li> 11 | </ul> 12 | </div> 13 | </el-aside> 14 | <el-main class="album-main"> 15 | <h1>{{ songDetails.name }}</h1> 16 | <p>{{ songDetails.introduction }}</p> 17 | <song-list :songList="currentSongList"></song-list> 18 | </el-main> 19 | </el-container> 20 | </template> 21 | 22 | <script lang="ts"> 23 | import { defineComponent, ref, computed, onMounted } from "vue"; 24 | import { useStore } from "vuex"; 25 | import mixin from "@/mixins/mixin"; 26 | import SongList from "@/components/SongList.vue"; 27 | import { HttpManager } from "@/api"; 28 | import { getBirth } from "@/utils"; 29 | 30 | export default defineComponent({ 31 | components: { 32 | SongList, 33 | }, 34 | setup() { 35 | const store = useStore(); 36 | const { getUserSex } = mixin(); 37 | 38 | const currentSongList = ref([]); 39 | const songDetails = computed(() => store.getters.songDetails) as any; 40 | 41 | onMounted(async () => { 42 | try { 43 | const result = (await HttpManager.getSongOfSingerId(songDetails.value.id)) as ResponseBody; 44 | currentSongList.value = result.data; 45 | } catch (error) { 46 | console.error(error); 47 | } 48 | }); 49 | 50 | return { 51 | songDetails, 52 | currentSongList, 53 | attachImageUrl: HttpManager.attachImageUrl, 54 | getBirth, 55 | getUserSex, 56 | }; 57 | }, 58 | }); 59 | </script> 60 | 61 | <style lang="scss" scoped> 62 | @import "@/assets/css/var.scss"; 63 | 64 | .album-slide { 65 | display: flex; 66 | flex-direction: column; 67 | align-items: center; 68 | padding-top: 20px; 69 | 70 | .singer-img { 71 | height: 250px; 72 | width: 250px; 73 | border-radius: 10%; 74 | } 75 | 76 | .album-info { 77 | width: 60%; 78 | padding-top: 2rem; 79 | li { 80 | width: 100%; 81 | height: 30px; 82 | line-height: 30px; 83 | } 84 | } 85 | } 86 | 87 | .album-main { 88 | p { 89 | color: rgba(0, 0, 0, 0.5); 90 | margin: 10px 0 20px 0px; 91 | } 92 | } 93 | 94 | @media screen and (min-width: $sm) { 95 | .album-slide { 96 | position: fixed; 97 | width: 400px; 98 | } 99 | .album-main { 100 | min-width: 600px; 101 | padding-right: 10vw; 102 | margin-left: 400px; 103 | } 104 | } 105 | 106 | @media screen and (max-width: $sm) { 107 | .album-slide { 108 | display: none; 109 | } 110 | } 111 | </style> 112 | -------------------------------------------------------------------------------- /music-client/src/views/song-sheet/SongSheet.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <div class="play-list-container"> 3 | <yin-nav :styleList="songStyle" :activeName="activeName" @click="handleChangeView"></yin-nav> 4 | <play-list :playList="data" path="song-sheet-detail"></play-list> 5 | <el-pagination 6 | class="pagination" 7 | background 8 | layout="total, prev, pager, next" 9 | :current-page="currentPage" 10 | :page-size="pageSize" 11 | :total="allPlayList.length" 12 | @current-change="handleCurrentChange" 13 | > 14 | </el-pagination> 15 | </div> 16 | </template> 17 | 18 | <script lang="ts"> 19 | import { defineComponent, ref, computed } from "vue"; 20 | import YinNav from "@/components/layouts/YinNav.vue"; 21 | import PlayList from "@/components/PlayList.vue"; 22 | import { SONGSTYLE } from "@/enums"; 23 | import { HttpManager } from "@/api"; 24 | 25 | export default defineComponent({ 26 | components: { 27 | YinNav, 28 | PlayList, 29 | }, 30 | setup() { 31 | const activeName = ref("全部歌单"); 32 | const pageSize = ref(15); // 页数 33 | const currentPage = ref(1); // 当前页 34 | const songStyle = ref(SONGSTYLE); // 歌单导航栏类别 35 | const allPlayList = ref([]); // 歌单 36 | const data = computed(() => allPlayList.value.slice((currentPage.value - 1) * pageSize.value, currentPage.value * pageSize.value)); 37 | 38 | // 获取全部歌单 39 | async function getSongList() { 40 | allPlayList.value = ((await HttpManager.getSongList()) as ResponseBody).data; 41 | currentPage.value = 1; 42 | } 43 | // 通过类别获取歌单 44 | async function getSongListOfStyle(style) { 45 | allPlayList.value = ((await HttpManager.getSongListOfStyle(style)) as ResponseBody).data; 46 | currentPage.value = 1; 47 | } 48 | 49 | try { 50 | getSongList(); 51 | } catch (error) { 52 | console.error(error); 53 | } 54 | 55 | // 获取歌单 56 | async function handleChangeView(item) { 57 | activeName.value = item.name; 58 | allPlayList.value = []; 59 | try { 60 | if (item.name === "全部歌单") { 61 | await getSongList(); 62 | } else { 63 | await getSongListOfStyle(item.name); 64 | } 65 | } catch (error) { 66 | console.error(error); 67 | } 68 | } 69 | // 获取当前页 70 | function handleCurrentChange(val) { 71 | currentPage.value = val; 72 | } 73 | return { 74 | activeName, 75 | songStyle, 76 | pageSize, 77 | currentPage, 78 | allPlayList, 79 | data, 80 | handleChangeView, 81 | handleCurrentChange, 82 | }; 83 | }, 84 | }); 85 | </script> 86 | -------------------------------------------------------------------------------- /music-client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "module": "esnext", 5 | "strict": true, 6 | "jsx": "preserve", 7 | "moduleResolution": "node", 8 | "skipLibCheck": true, 9 | "esModuleInterop": true, 10 | "allowSyntheticDefaultImports": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "useDefineForClassFields": true, 13 | "sourceMap": true, 14 | "noImplicitAny": false, 15 | "strictNullChecks": false, 16 | "baseUrl": ".", 17 | "types": [ 18 | "webpack-env" 19 | ], 20 | "paths": { 21 | "@/*": [ 22 | "src/*" 23 | ] 24 | }, 25 | "lib": [ 26 | "esnext", 27 | "dom", 28 | "dom.iterable", 29 | "scripthost" 30 | ] 31 | }, 32 | "include": [ 33 | "src/**/*.ts", 34 | "src/**/*.tsx", 35 | "src/**/*.vue", 36 | "tests/**/*.ts", 37 | "tests/**/*.tsx" 38 | ], 39 | "exclude": [ 40 | "node_modules" 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /music-client/vue.config.js: -------------------------------------------------------------------------------- 1 | const { defineConfig } = require('@vue/cli-service') 2 | module.exports = defineConfig({ 3 | transpileDependencies: true, 4 | chainWebpack: config => { 5 | config.plugin('define').tap(definitions => { 6 | Object.assign(definitions[0]['process.env'], { 7 | NODE_HOST: '"http://localhost:8888"', 8 | }); 9 | return definitions; 10 | }); 11 | } 12 | }) 13 | -------------------------------------------------------------------------------- /music-manage/.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not dead 4 | not ie 11 5 | -------------------------------------------------------------------------------- /music-manage/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true 5 | }, 6 | 'extends': [ 7 | 'plugin:vue/vue3-essential', 8 | 'eslint:recommended', 9 | '@vue/typescript/recommended' 10 | ], 11 | parserOptions: { 12 | ecmaVersion: 2020 13 | }, 14 | rules: { 15 | 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 16 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 17 | 'vue/multi-word-component-names': 0, 18 | "@typescript-eslint/no-unused-vars": ["off"], 19 | "@typescript-eslint/no-explicit-any": ["off"], 20 | 'no-undef': 0 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /music-manage/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /music-manage/README.md: -------------------------------------------------------------------------------- 1 | # music-manage 2 | 3 | ## Project setup 4 | ``` 5 | npm install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | npm run serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | npm run build 16 | ``` 17 | 18 | ### Lints and fixes files 19 | ``` 20 | npm run lint 21 | ``` 22 | 23 | ### Customize configuration 24 | See [Configuration Reference](https://cli.vuejs.org/config/). 25 | -------------------------------------------------------------------------------- /music-manage/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /music-manage/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "music-manage", 3 | "version": "3.0.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "axios": "^0.26.1", 12 | "core-js": "^3.8.3", 13 | "echarts": "^5.3.2", 14 | "element-plus": "^2.1.8", 15 | "mitt": "^3.0.0", 16 | "vue": "^3.2.13", 17 | "vue-router": "^4.0.3", 18 | "vuex": "^4.0.0" 19 | }, 20 | "devDependencies": { 21 | "@typescript-eslint/eslint-plugin": "^5.4.0", 22 | "@typescript-eslint/parser": "^5.4.0", 23 | "@vue/cli-plugin-babel": "~5.0.0", 24 | "@vue/cli-plugin-eslint": "~5.0.0", 25 | "@vue/cli-plugin-router": "~5.0.0", 26 | "@vue/cli-plugin-typescript": "~5.0.0", 27 | "@vue/cli-plugin-vuex": "~5.0.0", 28 | "@vue/cli-service": "~5.0.0", 29 | "@vue/eslint-config-typescript": "^9.1.0", 30 | "eslint": "^7.32.0", 31 | "eslint-plugin-vue": "^8.0.3", 32 | "typescript": "~4.5.5" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /music-manage/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yin-Hongwei/music-website/2cccb623c437abc0b90c91948d2c559a387fd335/music-manage/public/favicon.ico -------------------------------------------------------------------------------- /music-manage/public/index.html: -------------------------------------------------------------------------------- 1 | <!DOCTYPE html> 2 | <html lang=""> 3 | <head> 4 | <meta charset="utf-8"> 5 | <meta http-equiv="X-UA-Compatible" content="IE=edge"> 6 | <meta name="viewport" content="width=device-width,initial-scale=1.0"> 7 | <link rel="icon" href="<%= BASE_URL %>favicon.ico"> 8 | <title><%= htmlWebpackPlugin.options.title %></title> 9 | </head> 10 | <body> 11 | <noscript> 12 | <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong> 13 | </noscript> 14 | <div id="app"></div> 15 | <!-- built files will be auto injected --> 16 | </body> 17 | </html> 18 | -------------------------------------------------------------------------------- /music-manage/src/App.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <div id="app"> 3 | <router-view></router-view> 4 | </div> 5 | </template> 6 | 7 | <script lang="ts" setup> 8 | import { getCurrentInstance } from "vue"; 9 | 10 | const { proxy } = getCurrentInstance(); 11 | 12 | if (sessionStorage.getItem("dataStore")) { 13 | proxy.$store.replaceState(Object.assign({}, proxy.$store.state, JSON.parse(sessionStorage.getItem("dataStore")))); 14 | } 15 | 16 | window.addEventListener("beforeunload", () => { 17 | sessionStorage.setItem("dataStore", JSON.stringify(proxy.$store.state)); 18 | }); 19 | </script> 20 | -------------------------------------------------------------------------------- /music-manage/src/api/request.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import router from '../router' 3 | 4 | const BASE_URL = process.env.NODE_HOST 5 | 6 | axios.defaults.timeout = 5000 // 超时时间设置 7 | axios.defaults.withCredentials = true // true允许跨域 8 | axios.defaults.baseURL = BASE_URL 9 | // Content-Type 响应头 10 | axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8' 11 | 12 | // 响应拦截器 13 | axios.interceptors.response.use( 14 | response => { 15 | // 如果返回的状态码为200,说明接口请求成功,可以正常拿到数据 16 | // 否则的话抛出错误 17 | if (response.status === 200) { 18 | return Promise.resolve(response) 19 | } else { 20 | return Promise.reject(response) 21 | } 22 | }, 23 | // 服务器状态码不是2开头的的情况 24 | error => { 25 | if (error.response.status) { 26 | switch (error.response.status) { 27 | // 401: 未登录 28 | case 401: 29 | router.replace({ 30 | path: "/", 31 | query: { 32 | // redirect: router.currentRoute.fullPath 33 | }, 34 | }); 35 | break; 36 | case 403: 37 | // console.log('管理员权限已修改请重新登录') 38 | // 跳转登录页面,并将要浏览的页面fullPath传过去,登录成功后跳转需要访问的页面 39 | setTimeout(() => { 40 | router.replace({ 41 | path: "/", 42 | query: { 43 | // redirect: router.currentRoute.fullPath 44 | }, 45 | }); 46 | }, 1000); 47 | break; 48 | 49 | // 404请求不存在 50 | case 404: 51 | // console.log('请求页面飞到火星去了') 52 | break; 53 | } 54 | return Promise.reject(error.response); 55 | } 56 | } 57 | ) 58 | 59 | export function getBaseURL() { 60 | return BASE_URL; 61 | } 62 | 63 | /** 64 | * 封装get方法 65 | * @param url 66 | * @param data 67 | * @returns {Promise} 68 | */ 69 | export function get(url, params?: object) { 70 | return new Promise((resolve, reject) => { 71 | axios.get(url, params).then( 72 | response => resolve(response.data), 73 | error => reject(error) 74 | ) 75 | }); 76 | } 77 | 78 | /** 79 | * 封装post请求 80 | * @param url 81 | * @param data 82 | * @returns {Promise} 83 | */ 84 | export function post(url, data = {}) { 85 | return new Promise((resolve, reject) => { 86 | axios.post(url, data).then( 87 | response => resolve(response.data), 88 | error => reject(error) 89 | ); 90 | }); 91 | } 92 | 93 | /** 94 | * 封装delete请求 95 | * @param url 96 | * @param data 97 | * @returns {Promise} 98 | */ 99 | export function deletes(url, data = {}) { 100 | return new Promise((resolve, reject) => { 101 | axios.delete(url, data).then( 102 | response => resolve(response.data), 103 | error => reject(error) 104 | ); 105 | }); 106 | } 107 | 108 | /** 109 | * 封装put请求 110 | * @param url 111 | * @param data 112 | * @returns {Promise} 113 | */ 114 | export function put(url, data = {}) { 115 | return new Promise((resolve, reject) => { 116 | axios.put(url, data).then( 117 | response => resolve(response.data), 118 | error => reject(error) 119 | ); 120 | }); 121 | } 122 | -------------------------------------------------------------------------------- /music-manage/src/assets/css/main.css: -------------------------------------------------------------------------------- 1 | html, body, div, span, 2 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 3 | dl, dt, dd, ol, ul, li,hr,img,a, 4 | form, label, tr, th, td, 5 | article, aside, canvas, details, embed, 6 | figure, figcaption, footer, header { 7 | padding: 0; 8 | margin: 0; 9 | } 10 | 11 | html, 12 | body, 13 | #app, 14 | .wrapper { 15 | width: 100%; 16 | height: 100%; 17 | overflow: hidden; 18 | } 19 | 20 | ul, 21 | li { 22 | list-style: none; 23 | display: inline-block; 24 | } 25 | 26 | a { 27 | text-decoration: none; 28 | } 29 | 30 | .crumbs { 31 | margin-bottom: 20px; 32 | } 33 | 34 | .pagination { 35 | display: flex; 36 | justify-content: center; 37 | margin: 20px 0; 38 | } 39 | 40 | .handle-box { 41 | margin-bottom: 20px; 42 | font-size: 12px; 43 | display: flex; 44 | width: 30%; 45 | } 46 | 47 | .handle-box input { 48 | margin: 0 10px; 49 | } 50 | -------------------------------------------------------------------------------- /music-manage/src/assets/icons/iconfont.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | !function(a){var e,n='<svg><symbol id="icon-bofanganniu" viewBox="0 0 1024 1024"><path d="M927.870095 571.688039 167.320423 1014.160886C121.562471 1041.981153 61.44 1007.279555 61.44 954.218179L61.44 68.595037C63.693916 16.802233 124.631347-17.041827 171.276012 8.961322L928.382003 451.43039C974.037627 479.202079 974.037627 543.611136 927.870095 571.688039Z" ></path></symbol><symbol id="icon-zanting" viewBox="0 0 1024 1024"><path d="M268.97201558 114.31784297c73.21218086 0 132.56071902 59.34853814 132.56071901 132.560719v530.24287606c0 73.21218086-59.34853814 132.56071902-132.56071901 132.560719s-132.56071902-59.34853814-132.56071901-132.560719V246.87856197c0-73.21218086 59.34853814-132.56071902 132.56071901-132.560719z m486.05596884 0c73.21218086 0 132.56071902 59.34853814 132.56071901 132.560719v530.24287606c0 73.21218086-59.34853814 132.56071902-132.56071901 132.560719s-132.56071902-59.34853814-132.56071901-132.560719V246.87856197c0-73.21218086 59.34853814-132.56071902 132.56071901-132.560719z" ></path></symbol></svg>',t=(e=document.getElementsByTagName("script"))[e.length-1].getAttribute("data-injectcss");if(t&&!a.__iconfont__svg__cssinject__){a.__iconfont__svg__cssinject__=!0;try{document.write("<style>.svgfont {display: inline-block;width: 1em;height: 1em;fill: currentColor;vertical-align: -0.1em;font-size:16px;}</style>")}catch(e){console&&console.log(e)}}!function(e){if(document.addEventListener)if(~["complete","loaded","interactive"].indexOf(document.readyState))setTimeout(e,0);else{var t=function(){document.removeEventListener("DOMContentLoaded",t,!1),e()};document.addEventListener("DOMContentLoaded",t,!1)}else document.attachEvent&&(o=e,i=a.document,c=!1,(d=function(){try{i.documentElement.doScroll("left")}catch(e){return void setTimeout(d,50)}n()})(),i.onreadystatechange=function(){"complete"==i.readyState&&(i.onreadystatechange=null,n())});function n(){c||(c=!0,o())}var o,i,c,d}(function(){var e,t;(e=document.createElement("div")).innerHTML=n,n=null,(t=e.getElementsByTagName("svg")[0])&&(t.setAttribute("aria-hidden","true"),t.style.position="absolute",t.style.width=0,t.style.height=0,t.style.overflow="hidden",function(e,t){t.firstChild?function(e,t){t.parentNode.insertBefore(e,t)}(e,t.firstChild):t.appendChild(e)}(t,document.body))})}(window); 3 | -------------------------------------------------------------------------------- /music-manage/src/assets/images/background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yin-Hongwei/music-website/2cccb623c437abc0b90c91948d2c559a387fd335/music-manage/src/assets/images/background.jpg -------------------------------------------------------------------------------- /music-manage/src/assets/images/user.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yin-Hongwei/music-website/2cccb623c437abc0b90c91948d2c559a387fd335/music-manage/src/assets/images/user.jpg -------------------------------------------------------------------------------- /music-manage/src/components/dialog/YinDelDialog.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <div> 3 | <!-- 删除提示框 --> 4 | <el-dialog title="提示" v-model="centerDialogVisible" width="300px" center> 5 | <div class="del-dialog-cnt" align="center">删除不可恢复,是否确定删除?</div> 6 | <template #footer> 7 | <span class="dialog-footer"> 8 | <el-button @click="cancelRow">取 消</el-button> 9 | <el-button type="primary" @click="confirm">确 定</el-button> 10 | </span> 11 | </template> 12 | </el-dialog> 13 | </div> 14 | </template> 15 | 16 | <script lang="ts"> 17 | import { defineComponent, getCurrentInstance, toRefs, watch, ref } from "vue"; 18 | 19 | export default defineComponent({ 20 | props: { 21 | delVisible: Boolean, 22 | }, 23 | emits: ["cancelRow", "confirm"], 24 | setup(props) { 25 | const { proxy } = getCurrentInstance(); 26 | 27 | const { delVisible } = toRefs(props); 28 | const centerDialogVisible = ref(delVisible.value); 29 | 30 | watch(delVisible, (value) => { 31 | centerDialogVisible.value = value; 32 | }); 33 | 34 | function cancelRow() { 35 | proxy.$emit("cancelRow", false); 36 | } 37 | function confirm() { 38 | proxy.$emit("confirm", null); 39 | } 40 | return { 41 | centerDialogVisible, 42 | cancelRow, 43 | confirm, 44 | }; 45 | }, 46 | }); 47 | </script> 48 | -------------------------------------------------------------------------------- /music-manage/src/components/layouts/YinAside.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <div class="sidebar"> 3 | <el-menu 4 | class="sidebar-el-menu" 5 | background-color="#ffffff" 6 | active-text-color="#30a4fc" 7 | default-active="2" 8 | router 9 | :collapse="collapse" 10 | > 11 | <el-menu-item index="info"> 12 | <el-icon><pie-chart /></el-icon> 13 | <span>系统首页</span> 14 | </el-menu-item> 15 | <el-menu-item index="consumer"> 16 | <el-icon><User /></el-icon> 17 | <span>用户管理</span> 18 | </el-menu-item> 19 | <el-menu-item index="singer"> 20 | <el-icon><mic /></el-icon> 21 | <span>歌手管理</span> 22 | </el-menu-item> 23 | <el-menu-item index="songList"> 24 | <el-icon><Document /></el-icon> 25 | <span>歌单管理</span> 26 | </el-menu-item> 27 | </el-menu> 28 | </div> 29 | </template> 30 | 31 | <script lang="ts" setup> 32 | import { ref } from "vue"; 33 | import { PieChart, Mic, Document, User } from "@element-plus/icons-vue"; 34 | import emitter from "@/utils/emitter"; 35 | 36 | const collapse = ref(false); 37 | emitter.on("collapse", (msg) => { 38 | collapse.value = msg as boolean; 39 | }); 40 | </script> 41 | 42 | <style scoped> 43 | .sidebar { 44 | display: block; 45 | position: absolute; 46 | left: 0; 47 | top: 60px; 48 | bottom: 0; 49 | overflow-y: scroll; 50 | } 51 | 52 | .sidebar::-webkit-scrollbar { 53 | width: 0; 54 | } 55 | 56 | .sidebar > ul { 57 | height: 100%; 58 | } 59 | 60 | .sidebar-el-menu:not(.el-menu--collapse) { 61 | width: 150px; 62 | } 63 | </style> 64 | -------------------------------------------------------------------------------- /music-manage/src/components/layouts/YinAudio.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <audio controls="controls" preload="true" v-if="url" :ref="player" :src="attachImageUrl(url)" @canplay="startPlay" @ended="ended"></audio> 3 | </template> 4 | 5 | <script lang="ts"> 6 | import { defineComponent, getCurrentInstance, computed, watch, ref } from "vue"; 7 | import { useStore } from "vuex"; 8 | import { HttpManager } from "@/api"; 9 | 10 | export default defineComponent({ 11 | setup() { 12 | const { proxy } = getCurrentInstance(); 13 | const store = useStore(); 14 | const divRef = ref<HTMLAudioElement>(); 15 | const player = (el) => { 16 | divRef.value = el; 17 | }; 18 | 19 | const url = computed(() => store.getters.url); // 音乐链接 20 | const isPlay = computed(() => store.getters.isPlay); // 播放状态 21 | // 监听播放还是暂停 22 | watch(isPlay, () => { 23 | togglePlay(); 24 | }); 25 | 26 | // 开始/暂停 27 | function togglePlay() { 28 | isPlay.value ? divRef.value.play() : divRef.value.pause(); 29 | } 30 | 31 | // 获取歌曲链接后准备播放 32 | function startPlay() { 33 | divRef.value.play(); 34 | } 35 | // 音乐播放结束时触发 36 | function ended() { 37 | proxy.$store.commit("setIsPlay", false); 38 | } 39 | return { 40 | url, 41 | isPlay, 42 | player, 43 | startPlay, 44 | ended, 45 | attachImageUrl: HttpManager.attachImageUrl, 46 | }; 47 | }, 48 | }); 49 | </script> 50 | 51 | <style> 52 | audio { 53 | display: none; 54 | } 55 | </style> 56 | -------------------------------------------------------------------------------- /music-manage/src/enums/area.ts: -------------------------------------------------------------------------------- 1 | export const AREA = [ 2 | { 3 | value: "北京", 4 | label: "北京", 5 | }, 6 | { 7 | value: "天津", 8 | label: "天津", 9 | }, 10 | { 11 | value: "河北", 12 | label: "河北", 13 | }, 14 | { 15 | value: "山西", 16 | label: "山西", 17 | }, 18 | { 19 | value: "内蒙古", 20 | label: "内蒙古", 21 | }, 22 | { 23 | value: "辽宁", 24 | label: "辽宁", 25 | }, 26 | { 27 | value: "吉林", 28 | label: "吉林", 29 | }, 30 | { 31 | value: "黑龙江", 32 | label: "黑龙江", 33 | }, 34 | { 35 | value: "上海", 36 | label: "上海", 37 | }, 38 | { 39 | value: "江苏", 40 | label: "江苏", 41 | }, 42 | { 43 | value: "浙江", 44 | label: "浙江", 45 | }, 46 | { 47 | value: "安徽", 48 | label: "安徽", 49 | }, 50 | { 51 | value: "福建", 52 | label: "福建", 53 | }, 54 | { 55 | value: "江西", 56 | label: "江西", 57 | }, 58 | { 59 | value: "山东", 60 | label: "山东", 61 | }, 62 | { 63 | value: "河南", 64 | label: "河南", 65 | }, 66 | { 67 | value: "湖北", 68 | label: "湖北", 69 | }, 70 | { 71 | value: "湖南", 72 | label: "湖南", 73 | }, 74 | { 75 | value: "广东", 76 | label: "广东", 77 | }, 78 | { 79 | value: "广西", 80 | label: "广西", 81 | }, 82 | { 83 | value: "海南", 84 | label: "海南", 85 | }, 86 | { 87 | value: "重庆", 88 | label: "重庆", 89 | }, 90 | { 91 | value: "四川", 92 | label: "四川", 93 | }, 94 | { 95 | value: "贵州", 96 | label: "贵州", 97 | }, 98 | { 99 | value: "云南", 100 | label: "云南", 101 | }, 102 | { 103 | value: "西藏", 104 | label: "西藏", 105 | }, 106 | { 107 | value: "陕西", 108 | label: "陕西", 109 | }, 110 | { 111 | value: "甘肃", 112 | label: "甘肃", 113 | }, 114 | { 115 | value: "青海", 116 | label: "青海", 117 | }, 118 | { 119 | value: "宁夏", 120 | label: "宁夏", 121 | }, 122 | { 123 | value: "新疆", 124 | label: "新疆", 125 | }, 126 | { 127 | value: "香港", 128 | label: "香港", 129 | }, 130 | { 131 | value: "澳门", 132 | label: "澳门", 133 | }, 134 | { 135 | value: "台湾", 136 | label: "台湾", 137 | }, 138 | ]; 139 | -------------------------------------------------------------------------------- /music-manage/src/enums/icon.ts: -------------------------------------------------------------------------------- 1 | export const enum Icon { 2 | BOFANG = "#icon-bofanganniu", // 播放 3 | ZANTING = "#icon-zanting", // 暂停 4 | } 5 | -------------------------------------------------------------------------------- /music-manage/src/enums/index.ts: -------------------------------------------------------------------------------- 1 | import { AREA } from "./area"; 2 | import { Icon } from "./icon"; 3 | import { MUSICNAME } from "./music-name"; 4 | import { RouterName } from "./router-name"; 5 | 6 | export { AREA, Icon, MUSICNAME, RouterName }; 7 | -------------------------------------------------------------------------------- /music-manage/src/enums/music-name.ts: -------------------------------------------------------------------------------- 1 | export const MUSICNAME = 'Yin-music 后台管理' 2 | -------------------------------------------------------------------------------- /music-manage/src/enums/router-name.ts: -------------------------------------------------------------------------------- 1 | export const enum RouterName { 2 | Home = "/home", 3 | Info = "/info", 4 | Song = "/song", 5 | Singer = "/singer", 6 | SongList = "/songList", 7 | ListSong = "/listSong", 8 | Comment = "/Comment", 9 | Consumer = "/consumer", 10 | Collect = "/collect", 11 | Error = "/404", 12 | SignIn = "/", 13 | SignOut = "0", 14 | } 15 | -------------------------------------------------------------------------------- /music-manage/src/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from "vue"; 2 | import ElementPlus from "element-plus"; 3 | import App from "./App.vue"; 4 | import router from "./router"; 5 | import store from "./store"; 6 | import "element-plus/dist/index.css"; 7 | import "./assets/css/main.css"; 8 | import "./assets/icons/iconfont.js"; 9 | 10 | import { Store } from "vuex"; 11 | declare module "@vue/runtime-core" { 12 | interface State { 13 | count: number; 14 | } 15 | 16 | interface ComponentCustomProperties { 17 | $store: Store<State>; 18 | } 19 | } 20 | 21 | createApp(App).use(store).use(router).use(ElementPlus).mount("#app"); 22 | -------------------------------------------------------------------------------- /music-manage/src/mixins/mixin.ts: -------------------------------------------------------------------------------- 1 | import { getCurrentInstance, ref } from "vue"; 2 | import { LocationQueryRaw } from "vue-router"; 3 | import { RouterName } from "@/enums"; 4 | 5 | interface routerOptions { 6 | path?: string; 7 | query?: LocationQueryRaw; 8 | } 9 | 10 | export default function () { 11 | const { proxy } = getCurrentInstance(); 12 | const uploadTypes = ref(["jpg", "jpeg", "png", "gif"]); 13 | 14 | function changeSex(value) { 15 | if (value === 0) { 16 | return "女"; 17 | } else if (value === 1) { 18 | return "男"; 19 | } else if (value === 2) { 20 | return "组合"; 21 | } else if (value === 3) { 22 | return "不明"; 23 | } else if (value === "男" || value === "女") { 24 | return value; 25 | } 26 | } 27 | 28 | function beforeImgUpload(file) { 29 | const ltCode = 2; 30 | const isLt2M = file.size / 1024 / 1024 < ltCode; 31 | const isExistFileType = uploadTypes.value.includes(file.type.replace(/image\//, "")); 32 | 33 | if (!isExistFileType) { 34 | (proxy as any).$message.error(`图片只支持 ${uploadTypes.value.join("、")} 格式!`); 35 | } 36 | if (!isLt2M) { 37 | (proxy as any).$message.error(`上传头像图片大小不能超过 ${ltCode}MB!`); 38 | } 39 | 40 | return isExistFileType && isLt2M; 41 | } 42 | 43 | function beforeSongUpload(file) { 44 | const ltCode = 10; 45 | const isLt10M = file.size / 1024 / 1024 < ltCode; 46 | const testmsg = file.name.substring(file.name.lastIndexOf(".") + 1); 47 | const extension = testmsg === "mp3"; 48 | 49 | if (!extension) { 50 | (proxy as any).$message({ 51 | message: "上传文件只能是mp3格式!", 52 | type: "error", 53 | }); 54 | } 55 | if (!isLt10M) { 56 | (proxy as any).$message.error(`上传头像图片大小不能超过 ${ltCode}MB!`); 57 | } 58 | 59 | return extension && isLt10M; 60 | } 61 | 62 | // 路由管理 63 | function routerManager(routerName: string | number, options: routerOptions) { 64 | switch (routerName) { 65 | case RouterName.Song: 66 | case RouterName.ListSong: 67 | case RouterName.Comment: 68 | case RouterName.Consumer: 69 | case RouterName.Collect: 70 | proxy.$router.push({ path: options.path, query: options.query }); 71 | break; 72 | case RouterName.Home: 73 | case RouterName.SignIn: 74 | case RouterName.SignOut: 75 | case RouterName.Info: 76 | case RouterName.Singer: 77 | case RouterName.SongList: 78 | case RouterName.Error: 79 | default: 80 | proxy.$router.push({ path: options.path }); 81 | break; 82 | } 83 | } 84 | 85 | function goBack(step = -1) { 86 | proxy.$router.go(step); 87 | } 88 | 89 | return { changeSex, routerManager, goBack, beforeImgUpload, beforeSongUpload }; 90 | } 91 | -------------------------------------------------------------------------------- /music-manage/src/router/index.ts: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router' 2 | 3 | const routes: Array<RouteRecordRaw> = [ 4 | { 5 | path: '/Home', 6 | component: () => import('@/views/Home.vue'), 7 | meta: { title: '自述文件' }, 8 | children: [ 9 | { 10 | path: '/Info', 11 | component: () => import('@/views/InfoPage.vue'), 12 | meta: { title: 'Info' } 13 | }, 14 | { 15 | path: '/song', 16 | component: () => import('@/views/SongPage.vue'), 17 | meta: { title: 'Song' } 18 | }, 19 | { 20 | path: '/singer', 21 | component: () => import('@/views/SingerPage.vue'), 22 | meta: { title: 'Singer' } 23 | }, 24 | { 25 | path: '/SongList', 26 | component: () => import('@/views/SongListPage.vue'), 27 | meta: { title: 'SongList' } 28 | }, 29 | { 30 | path: '/ListSong', 31 | component: () => import('@/views/ListSongPage.vue'), 32 | meta: { title: 'ListSong' } 33 | }, 34 | { 35 | path: '/Comment', 36 | component: () => import('@/views/CommentPage.vue'), 37 | meta: { title: 'Comment' } 38 | }, 39 | { 40 | path: '/Consumer', 41 | component: () => import('@/views/ConsumerPage.vue'), 42 | meta: { title: 'Consumer' } 43 | }, 44 | { 45 | path: '/Collect', 46 | component: () => import('@/views/CollectPage.vue'), 47 | meta: { title: 'Collect' } 48 | } 49 | ] 50 | }, 51 | { 52 | path: '/', 53 | component: () => import('@/views/Login.vue') 54 | } 55 | ] 56 | 57 | const router = createRouter({ 58 | history: createWebHistory(process.env.BASE_URL), 59 | routes 60 | }) 61 | 62 | export default router 63 | -------------------------------------------------------------------------------- /music-manage/src/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | declare module "*.vue" { 3 | import type { DefineComponent } from "vue"; 4 | const component: DefineComponent<{}, {}, any>; 5 | export default component; 6 | } 7 | 8 | declare module "vue/types/vue" { 9 | import VueRouter, { Route } from "vue-router"; 10 | 11 | interface Vue { 12 | $router: VueRouter; 13 | $route: Route; 14 | } 15 | } 16 | 17 | interface ResponseBody { 18 | code: string; 19 | success: boolean; 20 | message: string; 21 | type: string; 22 | data?: any; 23 | } 24 | -------------------------------------------------------------------------------- /music-manage/src/store/index.ts: -------------------------------------------------------------------------------- 1 | import { createStore } from 'vuex' 2 | 3 | export default createStore({ 4 | state: { 5 | userPic: "/img/avatorImages/user.jpg", 6 | isPlay: false, 7 | url: '', 8 | id: '', 9 | breadcrumbList: [] 10 | }, 11 | getters: { 12 | userPic: state => state.userPic, 13 | isPlay: state => state.isPlay, 14 | url: state => state.url, 15 | id: state => state.id, 16 | breadcrumbList: state => state.breadcrumbList 17 | }, 18 | mutations: { 19 | setUserPic: (state, userPic) => { state.userPic = userPic }, 20 | setIsPlay: (state, isPlay) => { state.isPlay = isPlay }, 21 | setUrl: (state, url) => { state.url = url }, 22 | setId: (state, id) => { state.id = id }, 23 | setBreadcrumbList: (state, breadcrumbList) => { state.breadcrumbList = breadcrumbList } 24 | } 25 | }) -------------------------------------------------------------------------------- /music-manage/src/utils/emitter.ts: -------------------------------------------------------------------------------- 1 | import mitt from "mitt"; 2 | 3 | const emitter = mitt(); 4 | 5 | export default emitter; 6 | -------------------------------------------------------------------------------- /music-manage/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | // 解析日期 2 | export function getBirth(cellValue) { 3 | if (cellValue == null || cellValue == "") return ""; 4 | const date = new Date(cellValue); 5 | const year = date.getFullYear(); 6 | const month = date.getMonth() + 1 < 10 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1; 7 | const day = date.getDate() < 10 ? "0" + date.getDate() : date.getDate(); 8 | return year + "-" + month + "-" + day; 9 | } 10 | 11 | // 解析歌词 12 | export function parseLyric(text) { 13 | const lines = text.split("\n"); 14 | const pattern = /\[\d{2}:\d{2}.(\d{3}|\d{2})\]/g; 15 | const result = []; 16 | 17 | // 对于歌词格式不对的特殊处理 18 | if (!/\[.+\]/.test(text)) { 19 | return [text]; 20 | } 21 | for (const item of lines) { 22 | if (pattern.test(item)) { 23 | const value = item.replace(pattern, ""); // 存歌词 24 | result.push(value); 25 | } 26 | } 27 | return result; 28 | } 29 | -------------------------------------------------------------------------------- /music-manage/src/views/Home.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <yin-header></yin-header> 3 | <yin-aside></yin-aside> 4 | <div class="content-box" :class="{ 'content-collapse': collapse }"> 5 | <router-view></router-view> 6 | </div> 7 | <yin-audio></yin-audio> 8 | </template> 9 | 10 | <script lang="ts" setup> 11 | import { ref } from "vue"; 12 | import YinHeader from "@/components/layouts/YinHeader.vue"; 13 | import YinAudio from "@/components/layouts/YinAudio.vue"; 14 | import YinAside from "@/components/layouts/YinAside.vue"; 15 | import emitter from "@/utils/emitter"; 16 | 17 | const collapse = ref(false); 18 | emitter.on("collapse", (msg) => { 19 | collapse.value = msg as boolean; 20 | }); 21 | </script> 22 | 23 | <style scoped> 24 | .content-box { 25 | position: absolute; 26 | left: 150px; 27 | right: 0; 28 | top: 60px; 29 | bottom: 0; 30 | overflow-y: scroll; 31 | transition: left 0.3s ease-in-out; 32 | padding: 20px; 33 | } 34 | 35 | .content-collapse { 36 | left: 65px; 37 | } 38 | </style> 39 | -------------------------------------------------------------------------------- /music-manage/src/views/Login.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <div class="login-container"> 3 | <div class="title">{{ nusicName }}</div> 4 | <div class="login"> 5 | <el-form :model="ruleForm" :rules="rules"> 6 | <el-form-item prop="username"> 7 | <el-input v-model="ruleForm.username" placeholder="username"></el-input> 8 | </el-form-item> 9 | <el-form-item prop="password"> 10 | <el-input type="password" placeholder="password" v-model="ruleForm.password" @keyup.enter="submitForm"></el-input> 11 | </el-form-item> 12 | <el-form-item> 13 | <el-button class="login-btn" type="primary" @click="submitForm">登录</el-button> 14 | </el-form-item> 15 | </el-form> 16 | </div> 17 | </div> 18 | </template> 19 | 20 | <script lang="ts"> 21 | import { defineComponent, getCurrentInstance, ref, reactive } from "vue"; 22 | import mixin from "@/mixins/mixin"; 23 | import { HttpManager } from "@/api/index"; 24 | import { RouterName, MUSICNAME } from "@/enums"; 25 | 26 | export default defineComponent({ 27 | setup() { 28 | const { proxy } = getCurrentInstance(); 29 | const { routerManager } = mixin(); 30 | 31 | const nusicName = ref(MUSICNAME); 32 | const ruleForm = reactive({ 33 | username: "admin", 34 | password: "123", 35 | }); 36 | const rules = reactive({ 37 | username: [{ required: true, message: "请输入用户名", trigger: "blur" }], 38 | password: [{ required: true, message: "请输入密码", trigger: "blur" }], 39 | }); 40 | async function submitForm() { 41 | let username = ruleForm.username; 42 | let password = ruleForm.password; 43 | const result = (await HttpManager.getLoginStatus({username,password})) as ResponseBody; 44 | (proxy as any).$message({ 45 | message: result.message, 46 | type: result.type, 47 | }); 48 | 49 | if (result.success) routerManager(RouterName.Info, { path: RouterName.Info }); 50 | } 51 | return { 52 | nusicName, 53 | ruleForm, 54 | rules, 55 | submitForm, 56 | }; 57 | }, 58 | }); 59 | </script> 60 | 61 | <style scoped> 62 | .login-container { 63 | position: relative; 64 | background: url("../assets/images/background.jpg"); 65 | background-attachment: fixed; 66 | background-position: center; 67 | background-size: cover; 68 | width: 100%; 69 | height: 100%; 70 | } 71 | 72 | .title { 73 | position: absolute; 74 | top: 50%; 75 | width: 100%; 76 | margin-top: -230px; 77 | text-align: center; 78 | font-size: 30px; 79 | font-weight: 600; 80 | color: #fff; 81 | } 82 | 83 | .login { 84 | position: absolute; 85 | left: 50%; 86 | top: 50%; 87 | width: 300px; 88 | margin: -150px 0 0 -190px; 89 | padding: 40px; 90 | border-radius: 5px; 91 | background: #fff; 92 | } 93 | 94 | .login-btn { 95 | width: 100%; 96 | } 97 | </style> 98 | -------------------------------------------------------------------------------- /music-manage/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "module": "esnext", 5 | "strict": true, 6 | "jsx": "preserve", 7 | "moduleResolution": "node", 8 | "skipLibCheck": true, 9 | "esModuleInterop": true, 10 | "allowSyntheticDefaultImports": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "useDefineForClassFields": true, 13 | "sourceMap": true, 14 | "noImplicitAny": false, 15 | "strictNullChecks": false, 16 | "baseUrl": ".", 17 | "types": [ 18 | "webpack-env" 19 | ], 20 | "paths": { 21 | "@/*": [ 22 | "src/*" 23 | ] 24 | }, 25 | "lib": [ 26 | "esnext", 27 | "dom", 28 | "dom.iterable", 29 | "scripthost" 30 | ] 31 | }, 32 | "include": [ 33 | "src/**/*.ts", 34 | "src/**/*.tsx", 35 | "src/**/*.vue", 36 | "tests/**/*.ts", 37 | "tests/**/*.tsx" 38 | ], 39 | "exclude": [ 40 | "node_modules" 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /music-manage/vue.config.js: -------------------------------------------------------------------------------- 1 | const { defineConfig } = require('@vue/cli-service') 2 | 3 | module.exports = defineConfig({ 4 | transpileDependencies: true, 5 | chainWebpack: config => { 6 | config.plugin('define').tap(definitions => { 7 | Object.assign(definitions[0]['process.env'], { 8 | NODE_HOST: '"http://localhost:8888"', 9 | }); 10 | return definitions; 11 | }); 12 | } 13 | }) 14 | -------------------------------------------------------------------------------- /music-server/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | .sts4-cache 12 | target/ 13 | .DS_Store 14 | ../img/ 15 | ../song/ 16 | img/ 17 | song/ 18 | logs/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | 26 | ### NetBeans ### 27 | /nbproject/private/ 28 | /build/ 29 | /nbbuild/ 30 | /dist/ 31 | /nbdist/ 32 | /.nb-gradle/ 33 | -------------------------------------------------------------------------------- /music-server/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM maven:3-openjdk-8-slim AS builder 2 | WORKDIR /app 3 | 4 | COPY pom.xml ./ 5 | RUN mvn dependency:resolve -DskipTests -B 6 | 7 | COPY src ./src 8 | RUN mvn clean package -DskipTests -B -T 1C 9 | 10 | FROM openjdk:8-jre-alpine 11 | WORKDIR /app 12 | COPY --from=builder /app/target/yin-0.0.1-SNAPSHOT.jar /app/yin-0.0.1-SNAPSHOT.jar 13 | ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app/yin-0.0.1-SNAPSHOT.jar","--spring.config.location=/config/application-prod.yml"] 14 | EXPOSE 8888 -------------------------------------------------------------------------------- /music-server/docker-server/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | web: 4 | build: . 5 | ports: 6 | - "8888:8888" 7 | depends_on: 8 | - db 9 | db: 10 | image: mysql:8.0 11 | environment: 12 | MYSQL_ROOT_PASSWORD: 123456 13 | MYSQL_DATABASE: tp_music 14 | MYSQL_USER: myuser 15 | MYSQL_PASSWORD: 123456 -------------------------------------------------------------------------------- /music-server/docker-server/dockerfile: -------------------------------------------------------------------------------- 1 | # 使用官方的Java基础镜像 2 | FROM openjdk:8-jdk-alpine 3 | # 将本地的jar文件复制到容器中 4 | COPY yin-0.0.1-SNAPSHOT.jar yin-0.0.1-SNAPSHOT.jar 5 | # 暴露端口 6 | EXPOSE 8888 7 | # 运行命令 8 | ENTRYPOINT ["java", "-jar", "/yin-0.0.1-SNAPSHOT.jar"] 9 | -------------------------------------------------------------------------------- /music-server/docker-vue-client/dockerfile: -------------------------------------------------------------------------------- 1 | # 使用官方的Node.js基础镜像作为基础镜像 2 | FROM node:14 3 | # 设置工作目录 4 | WORKDIR /appClient 5 | # 将package.json和package-lock.json复制到工作目录 6 | COPY package*.json ./ 7 | # 安装依赖 8 | RUN npm install 9 | # 将前端项目(通常是dist文件夹)复制到工作目录,记住要提前将vue打包成dist文件夹 10 | COPY dist /appClient/dist 11 | # 暴露端口 12 | EXPOSE 8080 13 | # 运行命令 14 | CMD ["npm", "start"] 15 | -------------------------------------------------------------------------------- /music-server/docker-vue-manage/dockerfile: -------------------------------------------------------------------------------- 1 | # 使用官方的Node.js基础镜像作为基础镜像 2 | FROM node:14 3 | # 设置工作目录 4 | WORKDIR /appManage 5 | # 将package.json和package-lock.json复制到工作目录 6 | COPY package*.json ./ 7 | # 安装依赖 8 | RUN npm install 9 | # 将前端项目(通常是dist文件夹)复制到工作目录,记住要提前将vue打包成dist文件夹 10 | COPY dist /appManage/dist 11 | # 暴露端口 12 | EXPOSE 8081 13 | # 运行命令 14 | CMD ["npm", "start"] 15 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/YinMusicApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.yin; 2 | 3 | import org.mybatis.spring.annotation.MapperScan; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | 7 | import static com.example.yin.constant.Constants.ASSETS_PATH; 8 | 9 | @SpringBootApplication 10 | @MapperScan("com.example.yin.mapper") 11 | public class YinMusicApplication { 12 | 13 | public static void main(String[] args) { 14 | SpringApplication.run(YinMusicApplication.class, args); 15 | } 16 | 17 | } 18 | 19 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/common/R.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.common; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author 祝英台炸油条 7 | * @Time : 2022/6/4 19:04 8 | **/ 9 | @Data 10 | public class R { 11 | 12 | private int code; 13 | 14 | private String message; 15 | 16 | private String type; 17 | 18 | private Boolean success; 19 | 20 | private Object data; 21 | 22 | public static R success(String message) { 23 | R r = new R(); 24 | r.setCode(200); 25 | r.setMessage(message); 26 | r.setSuccess(true); 27 | r.setType("success"); 28 | r.setData(null); 29 | return r; 30 | } 31 | 32 | public static R success(String message, Object data) { 33 | R r = success(message); 34 | r.setData(data); 35 | return r; 36 | } 37 | 38 | public static R warning(String message) { 39 | R r = error(message); 40 | r.setType("warning"); 41 | return r; 42 | } 43 | 44 | public static R error(String message) { 45 | R r = success(message); 46 | r.setSuccess(false); 47 | r.setType("error"); 48 | return r; 49 | } 50 | 51 | public static R fatal(String message) { 52 | R r = error(message); 53 | r.setCode(500); 54 | return r; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/config/CorsInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.config; 2 | 3 | import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; 4 | 5 | import javax.servlet.http.HttpServletRequest; 6 | import javax.servlet.http.HttpServletResponse; 7 | 8 | 9 | public class CorsInterceptor extends HandlerInterceptorAdapter { 10 | 11 | @Override 12 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { 13 | response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin")); 14 | response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"); 15 | response.setHeader("Access-Control-Max-Age", "3600"); 16 | response.setHeader("Access-Control-Allow-Headers", "x_requested_with,x-requested-with,Authorization,Content-Type,token"); 17 | response.setHeader("Access-Control-Allow-Credentials", "true"); 18 | return true; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/config/MinioConfig.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.config; 2 | 3 | import io.minio.MinioClient; 4 | import org.springframework.beans.factory.annotation.Value; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | 8 | @Configuration 9 | public class MinioConfig { 10 | 11 | @Value("${minio.endpoint}") 12 | private String minioEndpoint; 13 | 14 | @Value("${minio.access-key}") 15 | private String minioAccessKey; 16 | 17 | @Value("${minio.secret-key}") 18 | private String minioSecretKey; 19 | 20 | @Bean 21 | public MinioClient minioClient() { 22 | return MinioClient.builder() 23 | .endpoint(minioEndpoint) 24 | .credentials(minioAccessKey, minioSecretKey) 25 | .build(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/config/WebCharacterEncodingFilter.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.config; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.http.converter.HttpMessageConverter; 5 | import org.springframework.http.converter.StringHttpMessageConverter; 6 | import org.springframework.web.servlet.config.annotation.CorsRegistry; 7 | import org.springframework.web.servlet.config.annotation.EnableWebMvc; 8 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 9 | 10 | import java.nio.charset.StandardCharsets; 11 | import java.util.List; 12 | 13 | /** 14 | * 说明:解决以下问题 15 | * <p> 16 | * 因使用WebMvcConfigurer加载静态时 url encode编码无法解析为正常中文问题 17 | * </p> 18 | * 19 | */ 20 | 21 | @EnableWebMvc 22 | @Configuration 23 | public class WebCharacterEncodingFilter implements WebMvcConfigurer { 24 | 25 | /** 26 | * 乱码处理 27 | */ 28 | public HttpMessageConverter<String> responseBodyConverter() { 29 | final StringHttpMessageConverter converter = new StringHttpMessageConverter(StandardCharsets.UTF_8); 30 | converter.setWriteAcceptCharset(false); 31 | return converter; 32 | } 33 | 34 | @Override 35 | public void addCorsMappings(CorsRegistry registry) { 36 | registry.addMapping("/**").allowedOrigins("*").allowedMethods("*").allowedHeaders("*"); 37 | } 38 | 39 | @Override 40 | public void extendMessageConverters(List<HttpMessageConverter<?>> converters) { 41 | if (!converters.isEmpty()) { 42 | converters.add(converters.get(0)); 43 | converters.set(0, responseBodyConverter()); 44 | } else { 45 | converters.add(responseBodyConverter()); 46 | } 47 | } 48 | } 49 | 50 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/config/WebMvcConfig.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.web.servlet.config.annotation.CorsRegistry; 6 | import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 7 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 8 | 9 | /** 10 | * @Author 祝英台炸油条 11 | * @Time : 2022/6/7 17:08 12 | **/ 13 | @Configuration 14 | public class WebMvcConfig implements WebMvcConfigurer { 15 | 16 | @Bean 17 | public CorsInterceptor corsInterceptor() { 18 | return new CorsInterceptor(); 19 | } 20 | 21 | @Override 22 | public void addInterceptors(InterceptorRegistry registry) { 23 | registry.addInterceptor(corsInterceptor()) 24 | .addPathPatterns("/**"); 25 | } 26 | 27 | } -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/config/WebPicConfig.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.config; 2 | 3 | import com.example.yin.constant.Constants; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; 6 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 7 | 8 | /** 9 | * 集中一下图像的配置类吧 10 | * 11 | * @Author 祝英台炸油条 12 | * @Time : 2022/6/5 22:23 13 | **/ 14 | @Configuration 15 | public class WebPicConfig implements WebMvcConfigurer { 16 | 17 | //TODO 这个配置类的目的是什么 就是注册了一个类似于拦截器吧 看到对应的资源 会将其修改成相应的地址 18 | @Override 19 | public void addResourceHandlers(ResourceHandlerRegistry registry) { 20 | registry.addResourceHandler("/img/avatorImages/**") 21 | .addResourceLocations(Constants.AVATOR_IMAGES_PATH); 22 | registry.addResourceHandler("/img/singerPic/**") 23 | .addResourceLocations(Constants.SINGER_PIC_PATH); 24 | registry.addResourceHandler("/img/songPic/**") 25 | .addResourceLocations(Constants.SONG_PIC_PATH); 26 | registry.addResourceHandler("/song/**") 27 | .addResourceLocations(Constants.SONG_PATH); 28 | registry.addResourceHandler("/img/songListPic/**") 29 | .addResourceLocations(Constants.SONGLIST_PIC_PATH); 30 | registry.addResourceHandler("/img/swiper/**") 31 | .addResourceLocations(Constants.BANNER_PIC_PATH); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/constant/Constants.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.constant; 2 | 3 | public class Constants { 4 | /* 歌曲图片,歌手图片,歌曲文件,歌单图片等文件的存放路径 */ 5 | public static String ASSETS_PATH = System.getProperty("user.dir"); 6 | 7 | public static String AVATOR_IMAGES_PATH = "file:" + ASSETS_PATH + "/img/avatorImages/"; 8 | public static String SONGLIST_PIC_PATH = "file:" + ASSETS_PATH + "/img/songListPic/"; 9 | public static String SONG_PIC_PATH = "file:" + ASSETS_PATH + "/img/songPic/"; 10 | public static String SONG_PATH = "file:" + ASSETS_PATH + "/song/"; 11 | public static String SINGER_PIC_PATH = "file:" + ASSETS_PATH + "/img/singerPic/"; 12 | public static String BANNER_PIC_PATH = "file:" + ASSETS_PATH + "/img/swiper/"; 13 | 14 | /* 盐值加密 */ 15 | public static String SALT = "zyt"; 16 | } 17 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/controller/AdminController.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.controller; 2 | 3 | import com.example.yin.common.R; 4 | import com.example.yin.model.request.AdminRequest; 5 | import com.example.yin.service.AdminService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.web.bind.annotation.PostMapping; 8 | import org.springframework.web.bind.annotation.RequestBody; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | import javax.servlet.http.HttpSession; 12 | 13 | /** 14 | * 后台管理的相关事宜 15 | */ 16 | @RestController 17 | public class AdminController { 18 | @Autowired 19 | private AdminService adminService; 20 | 21 | // 判断是否登录成功 22 | @PostMapping("/admin/login/status") 23 | public R loginStatus(@RequestBody AdminRequest adminRequest, HttpSession session) { 24 | return adminService.verityPasswd(adminRequest, session); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/controller/BannerController.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.controller; 2 | 3 | import com.example.yin.common.R; 4 | import com.example.yin.service.BannerService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RestController; 9 | 10 | /** 11 | * @Author 祝英台炸油条 12 | * @Time : 2022/6/13 13:16 13 | **/ 14 | @RestController 15 | @RequestMapping("/banner") 16 | public class BannerController { 17 | 18 | @Autowired 19 | private BannerService bannerService; 20 | 21 | @GetMapping("/getAllBanner") 22 | public R getAllBanner(){ 23 | return R.success("成功获取轮播图与",bannerService.getAllBanner()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/controller/CollectController.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.controller; 2 | 3 | import com.example.yin.common.R; 4 | import com.example.yin.model.request.CollectRequest; 5 | import com.example.yin.service.CollectService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.web.bind.annotation.*; 8 | 9 | @RestController 10 | public class CollectController { 11 | 12 | @Autowired 13 | private CollectService collectService; 14 | 15 | 16 | // 添加收藏的歌曲 17 | //前台界面逻辑 18 | @PostMapping("/collection/add") 19 | public R addCollection(@RequestBody CollectRequest addCollectRequest) { 20 | return collectService.addCollection(addCollectRequest); 21 | } 22 | 23 | //TODO 这些其实有点偏简单的逻辑 所以就一点 所以放在外面 拿到里面 24 | // 取消收藏的歌曲 25 | @DeleteMapping("/collection/delete") 26 | public R deleteCollection(@RequestParam Integer userId, @RequestParam Integer songId) { 27 | return collectService.deleteCollect(userId, songId); 28 | } 29 | 30 | // 是否收藏歌曲 31 | @PostMapping("/collection/status") 32 | public R isCollection(@RequestBody CollectRequest isCollectRequest) { 33 | return collectService.existSongId(isCollectRequest); 34 | 35 | } 36 | 37 | // 返回的指定用户 ID 收藏的列表 38 | @GetMapping("/collection/detail") 39 | public R collectionOfUser(@RequestParam Integer userId) { 40 | return collectService.collectionOfUser(userId); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/controller/CommentController.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.controller; 2 | 3 | import com.example.yin.common.R; 4 | import com.example.yin.model.request.CommentRequest; 5 | import com.example.yin.service.CommentService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.web.bind.annotation.*; 8 | 9 | @RestController 10 | public class CommentController { 11 | @Autowired 12 | private CommentService commentService; 13 | 14 | 15 | // 提交评论 16 | @PostMapping("/comment/add") 17 | public R addComment(@RequestBody CommentRequest addCommentRequest) { 18 | return commentService.addComment(addCommentRequest); 19 | } 20 | 21 | // 删除评论 22 | @GetMapping("/comment/delete") 23 | public R deleteComment(@RequestParam Integer id) { 24 | return commentService.deleteComment(id); 25 | } 26 | 27 | // 获得指定歌曲 ID 的评论列表 28 | @GetMapping("/comment/song/detail") 29 | public R commentOfSongId(@RequestParam Integer songId) { 30 | return commentService.commentOfSongId(songId); 31 | } 32 | 33 | // 获得指定歌单 ID 的评论列表 34 | @GetMapping("/comment/songList/detail") 35 | public R commentOfSongListId(@RequestParam Integer songListId) { 36 | return commentService.commentOfSongListId(songListId); 37 | } 38 | 39 | // 点赞 40 | @PostMapping("/comment/like") 41 | public R commentOfLike(@RequestBody CommentRequest upCommentRequest) { 42 | return commentService.updateCommentMsg(upCommentRequest); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/controller/FileDownloadController.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.controller; 2 | 3 | import com.alibaba.excel.EasyExcel; 4 | import com.alibaba.excel.util.ListUtils; 5 | import com.example.yin.model.domain.SongList; 6 | import com.example.yin.service.SongListService; 7 | import com.example.yin.utils.TestFileUtil; 8 | import io.minio.GetObjectArgs; 9 | import io.minio.MinioClient; 10 | import io.minio.errors.*; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.beans.factory.annotation.Value; 13 | import org.springframework.core.io.ByteArrayResource; 14 | import org.springframework.core.io.Resource; 15 | import org.springframework.http.HttpHeaders; 16 | import org.springframework.http.MediaType; 17 | import org.springframework.http.ResponseEntity; 18 | import org.springframework.stereotype.Controller; 19 | import org.springframework.web.bind.annotation.GetMapping; 20 | import org.springframework.web.bind.annotation.PathVariable; 21 | import org.springframework.web.bind.annotation.RequestMapping; 22 | 23 | import javax.servlet.http.HttpServletRequest; 24 | import java.io.ByteArrayOutputStream; 25 | import java.io.File; 26 | import java.io.IOException; 27 | import java.io.InputStream; 28 | import java.nio.file.Files; 29 | import java.security.InvalidKeyException; 30 | import java.security.NoSuchAlgorithmException; 31 | import java.util.List; 32 | 33 | @Controller 34 | @RequestMapping("/download") 35 | public class FileDownloadController { 36 | 37 | @Autowired 38 | private MinioClient minioClient; 39 | @Value("${minio.bucket-name}") 40 | private String bucketName; 41 | 42 | @GetMapping("/{fileName}") 43 | public ResponseEntity<Resource> downloadFile(@PathVariable String fileName, HttpServletRequest request) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException { 44 | 45 | GetObjectArgs args = GetObjectArgs.builder() 46 | .bucket(bucketName) 47 | .object(fileName) 48 | .build(); 49 | InputStream inputStream = minioClient.getObject(args); 50 | 51 | ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 52 | byte[] buffer = new byte[1024]; 53 | int bytesRead; 54 | while ((bytesRead = inputStream.read(buffer)) != -1) { 55 | outputStream.write(buffer, 0, bytesRead); 56 | } 57 | byte[] musicBytes = outputStream.toByteArray(); 58 | // 创建一个ByteArrayResource对象,用于包装字节数组 59 | ByteArrayResource resource = new ByteArrayResource(musicBytes); 60 | // 构建响应头 61 | HttpHeaders headers = new HttpHeaders(); 62 | headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + fileName); 63 | // 返回一个 ResponseEntity 对象 64 | return ResponseEntity.ok() 65 | .headers(headers) 66 | .contentLength(musicBytes.length) 67 | .contentType(MediaType.APPLICATION_OCTET_STREAM) 68 | .body(resource); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/controller/ListSongController.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.controller; 2 | 3 | import com.alibaba.excel.EasyExcel; 4 | import com.example.yin.common.R; 5 | import com.example.yin.model.domain.SongList; 6 | import com.example.yin.model.request.ListSongRequest; 7 | import com.example.yin.service.ListSongService; 8 | import com.example.yin.service.SongListService; 9 | import com.example.yin.utils.TestFileUtil; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.core.io.InputStreamResource; 12 | import org.springframework.core.io.Resource; 13 | import org.springframework.http.HttpHeaders; 14 | import org.springframework.http.MediaType; 15 | import org.springframework.http.ResponseEntity; 16 | import org.springframework.web.bind.annotation.*; 17 | 18 | import javax.servlet.http.HttpServletRequest; 19 | import java.io.File; 20 | import java.io.FileInputStream; 21 | import java.io.IOException; 22 | import java.nio.file.Files; 23 | import java.util.List; 24 | 25 | @RestController 26 | public class ListSongController { 27 | 28 | @Autowired 29 | private ListSongService listSongService; 30 | @Autowired 31 | private SongListService service; 32 | // 给歌单添加歌曲 33 | @PostMapping("/listSong/add") 34 | public R addListSong(@RequestBody ListSongRequest addListSongRequest) { 35 | return listSongService.addListSong(addListSongRequest); 36 | } 37 | 38 | // 删除歌单里的歌曲 39 | @GetMapping("/listSong/delete") 40 | public R deleteListSong(@RequestParam int songId) { 41 | return listSongService.deleteListSong(songId); 42 | } 43 | 44 | // 返回歌单里指定歌单 ID 的歌曲 45 | @GetMapping("/listSong/detail") 46 | public R listSongOfSongId(@RequestParam int songListId) { 47 | return listSongService.listSongOfSongId(songListId); 48 | } 49 | 50 | // 更新歌单里面的歌曲信息 51 | @PostMapping("/listSong/update") 52 | public R updateListSongMsg(@RequestBody ListSongRequest updateListSongRequest) { 53 | return listSongService.updateListSongMsg(updateListSongRequest); 54 | } 55 | //导出歌单 56 | @GetMapping("/excle") 57 | public ResponseEntity<Resource> getExcle(HttpServletRequest request) throws IOException { 58 | String fileName = "SongList" + System.currentTimeMillis() + ".xlsx"; 59 | EasyExcel.write(fileName, SongList.class).sheet("模板").doWrite(data()); 60 | File file = new File(fileName); 61 | HttpHeaders headers = new HttpHeaders(); 62 | headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + fileName); 63 | 64 | byte[] content = Files.readAllBytes(file.toPath()); 65 | InputStreamResource resource = new InputStreamResource(new FileInputStream(file)); 66 | 67 | return ResponseEntity.ok() 68 | .headers(headers) 69 | .contentLength(content.length) 70 | .contentType(MediaType.APPLICATION_OCTET_STREAM) 71 | .body(resource); 72 | } 73 | private List<SongList> data() { 74 | List<SongList> allSong = service.findAllSong(); 75 | return allSong; 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/controller/RankListController.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.controller; 2 | 3 | import com.example.yin.common.R; 4 | import com.example.yin.model.request.RankListRequest; 5 | import com.example.yin.service.RankListService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.web.bind.annotation.*; 8 | 9 | @RestController 10 | public class RankListController { 11 | 12 | @Autowired 13 | private RankListService rankListService; 14 | 15 | 16 | // 提交评分 17 | @PostMapping("/rankList/add") 18 | public R addRank(@RequestBody RankListRequest rankListAddRequest) { 19 | return rankListService.addRank(rankListAddRequest); 20 | } 21 | 22 | // 获取指定歌单的评分 23 | @GetMapping("/rankList") 24 | public R rankOfSongListId(@RequestParam Long songListId) { 25 | return rankListService.rankOfSongListId(songListId); 26 | } 27 | 28 | // 获取指定用户的歌单评分 29 | @GetMapping("/rankList/user") 30 | public R getUserRank(@RequestParam(required = false) Long consumerId, @RequestParam Long songListId) { 31 | R userRank = rankListService.getUserRank(consumerId, songListId); 32 | return R.success("成功",userRank); 33 | } 34 | 35 | 36 | } 37 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/controller/SingerController.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.controller; 2 | 3 | import com.example.yin.common.R; 4 | import com.example.yin.model.request.SingerRequest; 5 | import com.example.yin.service.SingerService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.web.bind.annotation.*; 8 | import org.springframework.web.multipart.MultipartFile; 9 | 10 | @RestController 11 | public class SingerController { 12 | 13 | @Autowired 14 | private SingerService singerService; 15 | 16 | 17 | // 添加歌手 18 | @PostMapping("/singer/add") 19 | public R addSinger(@RequestBody SingerRequest addSingerRequest) { 20 | return singerService.addSinger(addSingerRequest); 21 | } 22 | 23 | // 删除歌手 24 | @DeleteMapping("/singer/delete") 25 | public R deleteSinger(@RequestParam int id) { 26 | return singerService.deleteSinger(id); 27 | } 28 | 29 | // 返回所有歌手 30 | @GetMapping("/singer") 31 | public R allSinger() { 32 | return singerService.allSinger(); 33 | } 34 | 35 | // 根据歌手名查找歌手 36 | @GetMapping("/singer/name/detail") 37 | public R singerOfName(@RequestParam String name) { 38 | return singerService.singerOfName(name); 39 | } 40 | 41 | // 根据歌手性别查找歌手 42 | @GetMapping("/singer/sex/detail") 43 | public R singerOfSex(@RequestParam int sex) { 44 | return singerService.singerOfSex(sex); 45 | } 46 | 47 | // 更新歌手信息 48 | @PostMapping("/singer/update") 49 | public R updateSingerMsg(@RequestBody SingerRequest updateSingerRequest) { 50 | return singerService.updateSingerMsg(updateSingerRequest); 51 | } 52 | 53 | // 更新歌手头像 54 | @PostMapping("/singer/avatar/update") 55 | public R updateSingerPic(@RequestParam("file") MultipartFile avatorFile, @RequestParam("id") int id) { 56 | return singerService.updateSingerPic(avatorFile, id); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/controller/SongListController.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.controller; 2 | 3 | import com.example.yin.common.R; 4 | import com.example.yin.model.request.SongListRequest; 5 | import com.example.yin.service.SongListService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.web.bind.annotation.*; 8 | import org.springframework.web.multipart.MultipartFile; 9 | 10 | @RestController 11 | public class SongListController { 12 | 13 | @Autowired 14 | private SongListService songListService; 15 | 16 | 17 | // 添加歌单 18 | @PostMapping("/songList/add") 19 | public R addSongList(@RequestBody SongListRequest addSongListRequest) { 20 | return songListService.addSongList(addSongListRequest); 21 | } 22 | 23 | // 删除歌单 24 | @GetMapping("/songList/delete") 25 | public R deleteSongList(@RequestParam int id) { 26 | return songListService.deleteSongList(id); 27 | } 28 | 29 | //TODO 这块就是前端显现相应的歌单list 30 | // 返回所有歌单 31 | @GetMapping("/songList") 32 | public R allSongList() { 33 | return songListService.allSongList(); 34 | } 35 | 36 | // 返回标题包含文字的歌单 37 | @GetMapping("/songList/likeTitle/detail") 38 | public R songListOfLikeTitle(@RequestParam String title) { 39 | return songListService.likeTitle('%' + title + '%'); 40 | } 41 | 42 | // 返回指定类型的歌单 43 | @GetMapping("/songList/style/detail") 44 | public R songListOfStyle(@RequestParam String style) { 45 | return songListService.likeStyle('%' + style + '%'); 46 | } 47 | 48 | // 更新歌单信息 49 | @PostMapping("/songList/update") 50 | public R updateSongListMsg(@RequestBody SongListRequest updateSongListRequest) { 51 | return songListService.updateSongListMsg(updateSongListRequest); 52 | 53 | } 54 | 55 | // 更新歌单图片 56 | @PostMapping("/songList/img/update") 57 | public R updateSongListPic(@RequestParam("file") MultipartFile avatorFile, @RequestParam("id") int id) { 58 | 59 | return songListService.updateSongListImg(avatorFile,id); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/controller/UserSupportController.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.controller; 2 | 3 | import com.example.yin.common.R; 4 | import com.example.yin.model.request.UserSupportRequest; 5 | import com.example.yin.service.UserSupportService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.web.bind.annotation.PostMapping; 8 | import org.springframework.web.bind.annotation.RequestBody; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | import org.springframework.web.bind.annotation.RestController; 11 | 12 | /** 13 | * @Author 祝英台炸油条 14 | * @Time : 2022/6/11 16:07 15 | **/ 16 | @RestController 17 | @RequestMapping("/userSupport") 18 | public class UserSupportController { 19 | 20 | @Autowired 21 | UserSupportService userSupportService; 22 | 23 | @PostMapping("/test") 24 | public R isUserSupportComment(@RequestBody UserSupportRequest userSupportRequest) { 25 | return userSupportService.isUserSupportComment(userSupportRequest); 26 | } 27 | 28 | @PostMapping("/insert") 29 | public R insertCommentSupport(@RequestBody UserSupportRequest userSupportRequest) { 30 | return userSupportService.insertCommentSupport(userSupportRequest); 31 | } 32 | 33 | @PostMapping("/delete") 34 | public R deleteCommentSupport(@RequestBody UserSupportRequest userSupportRequest) { 35 | return userSupportService.deleteCommentSupport(userSupportRequest); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/handler/MyMetaObjectHandler.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.handler; 2 | 3 | import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; 4 | import org.apache.ibatis.reflection.MetaObject; 5 | import org.springframework.stereotype.Component; 6 | 7 | import java.util.Date; 8 | 9 | @Component 10 | public class MyMetaObjectHandler implements MetaObjectHandler { 11 | @Override 12 | public void insertFill(MetaObject metaObject) { 13 | this.setFieldValByName("createTime", new Date(), metaObject); 14 | this.setFieldValByName("updateTime", new Date(), metaObject); 15 | } 16 | 17 | @Override 18 | public void updateFill(MetaObject metaObject) { 19 | this.setFieldValByName("updateTime", new Date(), metaObject); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/mapper/AdminMapper.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.example.yin.model.domain.Admin; 5 | import org.springframework.stereotype.Repository; 6 | 7 | @Repository 8 | public interface AdminMapper extends BaseMapper<Admin> { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/mapper/BannerMapper.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.example.yin.model.domain.Banner; 5 | 6 | /** 7 | * @author asus 8 | * @description 针对表【banner】的数据库操作Mapper 9 | * @createDate 2022-06-13 13:13:42 10 | * @Entity generator.domain.Banner 11 | */ 12 | public interface BannerMapper extends BaseMapper<Banner> { 13 | 14 | 15 | } 16 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/mapper/CollectMapper.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.example.yin.model.domain.Collect; 5 | import org.springframework.stereotype.Repository; 6 | 7 | @Repository 8 | public interface CollectMapper extends BaseMapper<Collect> { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/mapper/CommentMapper.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.example.yin.model.domain.Comment; 5 | import org.springframework.stereotype.Repository; 6 | 7 | @Repository 8 | public interface CommentMapper extends BaseMapper<Comment> { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/mapper/ConsumerMapper.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.example.yin.model.domain.Consumer; 5 | import org.springframework.stereotype.Repository; 6 | 7 | @Repository 8 | public interface ConsumerMapper extends BaseMapper<Consumer> { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/mapper/ListSongMapper.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.example.yin.model.domain.ListSong; 5 | import org.springframework.stereotype.Repository; 6 | 7 | @Repository 8 | public interface ListSongMapper extends BaseMapper<ListSong> { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/mapper/RankListMapper.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.example.yin.model.domain.RankList; 5 | import org.apache.ibatis.annotations.Param; 6 | import org.springframework.stereotype.Repository; 7 | 8 | @Repository 9 | public interface RankListMapper extends BaseMapper<RankList> { 10 | 11 | /** 12 | * 查总分 13 | * @param songListId 14 | * @return 15 | */ 16 | int selectScoreSum(Long songListId); 17 | 18 | /** 19 | * 查制定用户评分 20 | * @param consumerId 21 | * @param songListId 22 | * @return 23 | */ 24 | Integer selectUserRank(@Param("consumer_id") Long consumerId, @Param("song_list_id") Long songListId); 25 | } 26 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/mapper/SingerMapper.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.example.yin.model.domain.Singer; 5 | import org.springframework.stereotype.Repository; 6 | 7 | @Repository 8 | public interface SingerMapper extends BaseMapper<Singer> { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/mapper/SongListMapper.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.example.yin.model.domain.SongList; 5 | import org.springframework.stereotype.Repository; 6 | 7 | @Repository 8 | 9 | public interface SongListMapper extends BaseMapper<SongList> { 10 | 11 | 12 | } 13 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/mapper/SongMapper.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.example.yin.model.domain.Song; 5 | import org.springframework.stereotype.Repository; 6 | 7 | @Repository 8 | public interface SongMapper extends BaseMapper<Song> { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/mapper/UserSupportMapper.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.example.yin.model.domain.UserSupport; 5 | 6 | /** 7 | * @author asus 8 | * @description 针对表【user_support】的数据库操作Mapper 9 | * @createDate 2022-06-11 16:06:28 10 | * @Entity generator.domain.UserSupport 11 | */ 12 | public interface UserSupportMapper extends BaseMapper<UserSupport> { 13 | 14 | } 15 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/model/domain/Admin.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.model.domain; 2 | 3 | import com.baomidou.mybatisplus.annotation.IdType; 4 | import com.baomidou.mybatisplus.annotation.TableId; 5 | import com.baomidou.mybatisplus.annotation.TableName; 6 | import lombok.Data; 7 | import org.apache.commons.lang3.builder.ToStringBuilder; 8 | 9 | @TableName(value = "admin") 10 | @Data 11 | public class Admin { 12 | @TableId(type = IdType.AUTO) 13 | private Integer id; 14 | 15 | private String name; 16 | 17 | private String password; 18 | 19 | @Override 20 | public String toString() { 21 | return ToStringBuilder.reflectionToString(this); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/model/domain/Banner.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.model.domain; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | 7 | /** 8 | * 9 | * @TableName banner 10 | */ 11 | @Data 12 | public class Banner implements Serializable { 13 | /** 14 | * 15 | */ 16 | private Integer id; 17 | 18 | /** 19 | * 20 | */ 21 | private String pic; 22 | 23 | private static final long serialVersionUID = 1L; 24 | 25 | @Override 26 | public boolean equals(Object that) { 27 | if (this == that) { 28 | return true; 29 | } 30 | if (that == null) { 31 | return false; 32 | } 33 | if (getClass() != that.getClass()) { 34 | return false; 35 | } 36 | Banner other = (Banner) that; 37 | return (this.getId() == null ? other.getId() == null : this.getId().equals(other.getId())) 38 | && (this.getPic() == null ? other.getPic() == null : this.getPic().equals(other.getPic())); 39 | } 40 | 41 | @Override 42 | public int hashCode() { 43 | final int prime = 31; 44 | int result = 1; 45 | result = prime * result + ((getId() == null) ? 0 : getId().hashCode()); 46 | result = prime * result + ((getPic() == null) ? 0 : getPic().hashCode()); 47 | return result; 48 | } 49 | 50 | @Override 51 | public String toString() { 52 | StringBuilder sb = new StringBuilder(); 53 | sb.append(getClass().getSimpleName()); 54 | sb.append(" ["); 55 | sb.append("Hash = ").append(hashCode()); 56 | sb.append(", id=").append(id); 57 | sb.append(", pic=").append(pic); 58 | sb.append(", serialVersionUID=").append(serialVersionUID); 59 | sb.append("]"); 60 | return sb.toString(); 61 | } 62 | } -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/model/domain/Collect.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.model.domain; 2 | 3 | import com.baomidou.mybatisplus.annotation.*; 4 | import lombok.Data; 5 | import org.apache.commons.lang3.builder.ToStringBuilder; 6 | 7 | import java.util.Date; 8 | 9 | @TableName(value = "collect") 10 | @Data 11 | public class Collect { 12 | @TableId(type = IdType.AUTO) 13 | private Integer id; 14 | 15 | private Integer userId; 16 | 17 | private Byte type; 18 | 19 | private Integer songId; 20 | 21 | private Integer songListId; 22 | 23 | @TableField(fill = FieldFill.INSERT) 24 | private Date createTime; 25 | 26 | 27 | @Override 28 | public String toString() { 29 | return ToStringBuilder.reflectionToString(this); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/model/domain/Comment.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.model.domain; 2 | 3 | import com.baomidou.mybatisplus.annotation.*; 4 | import lombok.Data; 5 | import org.apache.commons.lang3.builder.ToStringBuilder; 6 | 7 | import java.util.Date; 8 | 9 | @TableName(value = "comment") 10 | @Data 11 | public class Comment { 12 | @TableId(type = IdType.AUTO) 13 | private Integer id; 14 | 15 | private Integer userId; 16 | 17 | private Integer songId; 18 | 19 | private Integer songListId; 20 | 21 | private String content; 22 | 23 | @TableField(fill = FieldFill.INSERT) 24 | private Date createTime; 25 | 26 | private Byte type; 27 | 28 | private Integer up; 29 | 30 | 31 | @Override 32 | public String toString() { 33 | return ToStringBuilder.reflectionToString(this); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/model/domain/Consumer.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.model.domain; 2 | 3 | import com.baomidou.mybatisplus.annotation.*; 4 | import lombok.Data; 5 | import org.apache.commons.lang3.builder.ToStringBuilder; 6 | 7 | import java.util.Date; 8 | 9 | @TableName(value = "consumer") 10 | @Data 11 | public class Consumer { 12 | @TableId(type = IdType.AUTO) 13 | private Integer id; 14 | 15 | private String username; 16 | 17 | private String password; 18 | 19 | private Byte sex; 20 | 21 | private String phoneNum; 22 | @TableField(value = "email") 23 | private String email; 24 | 25 | private Date birth; 26 | 27 | private String introduction; 28 | 29 | private String location; 30 | 31 | private String avator; 32 | 33 | @TableField(fill = FieldFill.INSERT) 34 | private Date createTime; 35 | 36 | @TableField(fill = FieldFill.INSERT_UPDATE) 37 | private Date updateTime; 38 | 39 | @Override 40 | public String toString() { 41 | return ToStringBuilder.reflectionToString(this); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/model/domain/ListSong.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.model.domain; 2 | 3 | import com.baomidou.mybatisplus.annotation.IdType; 4 | import com.baomidou.mybatisplus.annotation.TableId; 5 | import com.baomidou.mybatisplus.annotation.TableName; 6 | import lombok.Data; 7 | import org.apache.commons.lang3.builder.ToStringBuilder; 8 | 9 | import java.io.Serializable; 10 | 11 | @TableName(value = "list_song") 12 | @Data 13 | public class ListSong implements Serializable { 14 | 15 | @TableId(type = IdType.AUTO) 16 | private Integer id; 17 | 18 | private Integer songId; 19 | 20 | private Integer songListId; 21 | 22 | @Override 23 | public String toString() { 24 | return ToStringBuilder.reflectionToString(this); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/model/domain/Order.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.model.domain; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Data 8 | @AllArgsConstructor 9 | @NoArgsConstructor 10 | public class Order { 11 | private int id; 12 | private String name; 13 | private String password; 14 | } -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/model/domain/RankList.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.model.domain; 2 | 3 | import com.baomidou.mybatisplus.annotation.IdType; 4 | import com.baomidou.mybatisplus.annotation.TableId; 5 | import com.baomidou.mybatisplus.annotation.TableName; 6 | import lombok.Data; 7 | 8 | import java.io.Serializable; 9 | 10 | @TableName(value = "rank_list") 11 | @Data 12 | public class RankList implements Serializable { 13 | 14 | @TableId(type = IdType.AUTO) 15 | private Long id; 16 | 17 | private Long songListId; 18 | 19 | private Long consumerId; 20 | 21 | private Integer score; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/model/domain/ResetPasswordRequest.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.model.domain; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.ToString; 7 | 8 | @Data 9 | @AllArgsConstructor 10 | @NoArgsConstructor 11 | @ToString 12 | public class ResetPasswordRequest { 13 | private String email; 14 | private String code; 15 | private String password; 16 | private String confirmPassword; 17 | } 18 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/model/domain/Singer.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.model.domain; 2 | 3 | import com.baomidou.mybatisplus.annotation.IdType; 4 | import com.baomidou.mybatisplus.annotation.TableId; 5 | import com.baomidou.mybatisplus.annotation.TableName; 6 | import lombok.Data; 7 | import org.apache.commons.lang3.builder.ToStringBuilder; 8 | 9 | import java.util.Date; 10 | 11 | @TableName(value = "singer") 12 | @Data 13 | public class Singer { 14 | 15 | @TableId(type = IdType.AUTO) 16 | private Integer id; 17 | 18 | private String name; 19 | 20 | private Byte sex; 21 | 22 | private String pic; 23 | 24 | private Date birth; 25 | 26 | private String location; 27 | 28 | private String introduction; 29 | 30 | @Override 31 | public String toString() { 32 | return ToStringBuilder.reflectionToString(this); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/model/domain/Song.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.model.domain; 2 | 3 | import com.baomidou.mybatisplus.annotation.*; 4 | import lombok.Data; 5 | import org.apache.commons.lang3.builder.ToStringBuilder; 6 | 7 | import java.util.Date; 8 | 9 | @TableName(value = "song") 10 | @Data 11 | public class Song { 12 | 13 | @TableId(type = IdType.AUTO) 14 | private Integer id; 15 | 16 | private Integer singerId; 17 | 18 | private String name; 19 | 20 | private String introduction; 21 | 22 | @TableField(fill = FieldFill.INSERT) 23 | private Date createTime; 24 | 25 | @TableField(fill = FieldFill.INSERT_UPDATE) 26 | private Date updateTime; 27 | 28 | private String pic; 29 | 30 | private String lyric; 31 | 32 | private String url; 33 | 34 | @Override 35 | public String toString() { 36 | return ToStringBuilder.reflectionToString(this); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/model/domain/SongList.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.model.domain; 2 | 3 | import com.baomidou.mybatisplus.annotation.IdType; 4 | import com.baomidou.mybatisplus.annotation.TableId; 5 | import com.baomidou.mybatisplus.annotation.TableName; 6 | import lombok.Data; 7 | import org.apache.commons.lang3.builder.ToStringBuilder; 8 | 9 | @TableName(value = "song_list") 10 | @Data 11 | public class SongList { 12 | 13 | @TableId(type = IdType.AUTO) 14 | private Integer id; 15 | 16 | private String title; 17 | 18 | private String pic; 19 | 20 | private String style; 21 | 22 | private String introduction; 23 | 24 | @Override 25 | public String toString() { 26 | return ToStringBuilder.reflectionToString(this); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/model/domain/UserSupport.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.model.domain; 2 | 3 | import com.baomidou.mybatisplus.annotation.IdType; 4 | import com.baomidou.mybatisplus.annotation.TableId; 5 | import lombok.Data; 6 | 7 | import java.io.Serializable; 8 | 9 | /** 10 | * 11 | * @TableName user_support 12 | */ 13 | @Data 14 | public class UserSupport implements Serializable { 15 | /** 16 | * 17 | */ 18 | @TableId(type = IdType.AUTO) 19 | private Integer id; 20 | 21 | /** 22 | * 23 | */ 24 | private Integer commentId; 25 | 26 | /** 27 | * 28 | */ 29 | private Integer userId; 30 | 31 | private static final long serialVersionUID = 1L; 32 | 33 | @Override 34 | public boolean equals(Object that) { 35 | if (this == that) { 36 | return true; 37 | } 38 | if (that == null) { 39 | return false; 40 | } 41 | if (getClass() != that.getClass()) { 42 | return false; 43 | } 44 | UserSupport other = (UserSupport) that; 45 | return (this.getId() == null ? other.getId() == null : this.getId().equals(other.getId())) 46 | && (this.getCommentId() == null ? other.getCommentId() == null : this.getCommentId().equals(other.getCommentId())) 47 | && (this.getUserId() == null ? other.getUserId() == null : this.getUserId().equals(other.getUserId())); 48 | } 49 | 50 | @Override 51 | public int hashCode() { 52 | final int prime = 31; 53 | int result = 1; 54 | result = prime * result + ((getId() == null) ? 0 : getId().hashCode()); 55 | result = prime * result + ((getCommentId() == null) ? 0 : getCommentId().hashCode()); 56 | result = prime * result + ((getUserId() == null) ? 0 : getUserId().hashCode()); 57 | return result; 58 | } 59 | 60 | @Override 61 | public String toString() { 62 | StringBuilder sb = new StringBuilder(); 63 | sb.append(getClass().getSimpleName()); 64 | sb.append(" ["); 65 | sb.append("Hash = ").append(hashCode()); 66 | sb.append(", id=").append(id); 67 | sb.append(", commentId=").append(commentId); 68 | sb.append(", userId=").append(userId); 69 | sb.append(", serialVersionUID=").append(serialVersionUID); 70 | sb.append("]"); 71 | return sb.toString(); 72 | } 73 | } -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/model/request/AdminRequest.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.model.request; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author 祝英台炸油条 7 | * @Time : 2022/6/6 18:44 8 | **/ 9 | @Data 10 | public class AdminRequest { 11 | private Integer id; 12 | 13 | private String username; 14 | 15 | private String password; 16 | } 17 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/model/request/CollectRequest.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.model.request; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.Date; 6 | 7 | /** 8 | * @Author 祝英台炸油条 9 | * @Time : 2022/6/6 13:11 10 | **/ 11 | @Data 12 | public class CollectRequest { 13 | private Integer id; 14 | 15 | private Integer userId; 16 | 17 | private Byte type; 18 | 19 | private Integer songId; 20 | 21 | private Integer songListId; 22 | 23 | private Date createTime; 24 | } 25 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/model/request/CommentRequest.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.model.request; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.Date; 6 | 7 | /** 8 | * @Author 祝英台炸油条 9 | * @Time : 2022/6/6 14:29 10 | **/ 11 | @Data 12 | public class CommentRequest { 13 | private Integer id; 14 | 15 | private Integer userId; 16 | 17 | private Integer songId; 18 | 19 | private Integer songListId; 20 | 21 | private String content; 22 | 23 | private Date createTime; 24 | 25 | private Byte nowType; 26 | 27 | private Integer up;//点赞 28 | } 29 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/model/request/ConsumerRequest.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.model.request; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.Date; 6 | 7 | /** 8 | * @Author 祝英台炸油条 9 | * @Time : 2022/6/5 19:35 10 | * 这块 现在尝试把所有有关用户的属性都放入 11 | **/ 12 | @Data 13 | public class ConsumerRequest { 14 | private Integer id; 15 | 16 | private String username; 17 | 18 | private String oldPassword; //因为会用到用户旧密码 这无所谓的对应即可 19 | 20 | private String password; 21 | 22 | private Byte sex; 23 | 24 | private String phoneNum; 25 | 26 | private String email; 27 | 28 | private Date birth; 29 | 30 | private String introduction; 31 | 32 | private String location; 33 | 34 | private String avator; 35 | 36 | private Date createTime; 37 | } 38 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/model/request/ListSongRequest.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.model.request; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author 祝英台炸油条 7 | * @Time : 2022/6/6 20:38 8 | **/ 9 | @Data 10 | public class ListSongRequest { 11 | private Integer id; 12 | 13 | private Integer songId; 14 | 15 | private Integer songListId; 16 | } 17 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/model/request/RankListRequest.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.model.request; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author 祝英台炸油条 7 | * @Time : 2022/6/6 16:57 8 | **/ 9 | @Data 10 | public class RankListRequest { 11 | private Long id; 12 | 13 | private Long songListId; 14 | 15 | private Long consumerId; 16 | 17 | private Integer score; 18 | } 19 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/model/request/SingerRequest.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.model.request; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.Date; 6 | 7 | /** 8 | * @Author 祝英台炸油条 9 | * @Time : 2022/6/6 20:14 10 | **/ 11 | @Data 12 | public class SingerRequest { 13 | private Integer id; 14 | 15 | private String name; 16 | 17 | private Byte sex; 18 | 19 | private String pic; 20 | 21 | private Date birth; 22 | 23 | private String location; 24 | 25 | private String introduction; 26 | } 27 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/model/request/SongListRequest.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.model.request; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author 祝英台炸油条 7 | * @Time : 2022/6/6 20:38 8 | **/ 9 | @Data 10 | public class SongListRequest { 11 | private Integer id; 12 | 13 | private String title; 14 | 15 | private String pic; 16 | 17 | private String style; 18 | 19 | private String introduction; 20 | } 21 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/model/request/SongRequest.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.model.request; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.Date; 6 | 7 | /** 8 | * @Author 祝英台炸油条 9 | * @Time : 2022/6/6 19:11 10 | **/ 11 | @Data 12 | public class SongRequest { 13 | 14 | private Integer id; 15 | 16 | private Integer singerId; 17 | 18 | private String name; 19 | 20 | private String introduction; 21 | 22 | private Date createTime; 23 | 24 | private Date updateTime; 25 | 26 | private String pic; 27 | 28 | private String lyric; 29 | 30 | private String url; 31 | } 32 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/model/request/UserSupportRequest.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.model.request; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author 祝英台炸油条 7 | * @Time : 2022/6/11 16:08 8 | **/ 9 | @Data 10 | public class UserSupportRequest { 11 | Integer id; 12 | Integer commentId; 13 | Integer userId; 14 | } 15 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/service/AdminService.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.example.yin.common.R; 5 | import com.example.yin.model.domain.Admin; 6 | import com.example.yin.model.request.AdminRequest; 7 | 8 | import javax.servlet.http.HttpSession; 9 | 10 | public interface AdminService extends IService<Admin> { 11 | 12 | R verityPasswd(AdminRequest adminRequest, HttpSession session); 13 | } 14 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/service/BannerService.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.example.yin.model.domain.Banner; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * @author asus 10 | * @description 针对表【banner】的数据库操作Service 11 | * @createDate 2022-06-13 13:13:42 12 | */ 13 | public interface BannerService extends IService<Banner> { 14 | 15 | List<Banner> getAllBanner(); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/service/CollectService.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.example.yin.common.R; 5 | import com.example.yin.model.domain.Collect; 6 | import com.example.yin.model.request.CollectRequest; 7 | 8 | public interface CollectService extends IService<Collect> { 9 | 10 | R addCollection(CollectRequest addCollectRequest); 11 | 12 | R existSongId(CollectRequest isCollectRequest); 13 | 14 | R deleteCollect(Integer userId,Integer songId); 15 | 16 | R collectionOfUser(Integer userId); 17 | } 18 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/service/CommentService.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.example.yin.common.R; 5 | import com.example.yin.model.domain.Comment; 6 | import com.example.yin.model.request.CommentRequest; 7 | 8 | public interface CommentService extends IService<Comment> { 9 | 10 | R addComment(CommentRequest addCommentRequest); 11 | 12 | R updateCommentMsg(CommentRequest upCommentRequest); 13 | 14 | R deleteComment(Integer id); 15 | 16 | R commentOfSongId(Integer songId); 17 | 18 | R commentOfSongListId(Integer songListId); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/service/ConsumerService.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.example.yin.common.R; 5 | import com.example.yin.model.domain.Consumer; 6 | import com.example.yin.model.request.ConsumerRequest; 7 | import org.springframework.web.multipart.MultipartFile; 8 | 9 | import javax.servlet.http.HttpSession; 10 | 11 | public interface ConsumerService extends IService<Consumer> { 12 | 13 | R addUser(ConsumerRequest registryRequest); 14 | 15 | R updateUserMsg(ConsumerRequest updateRequest); 16 | 17 | R updateUserAvator(MultipartFile avatorFile, int id); 18 | 19 | R updatePassword(ConsumerRequest updatePasswordRequest); 20 | 21 | boolean existUser(String username); 22 | 23 | boolean verityPasswd(String username, String password); 24 | 25 | R deleteUser(Integer id); 26 | 27 | R allUser(); 28 | 29 | R userOfId(Integer id); 30 | 31 | R loginStatus(ConsumerRequest loginRequest, HttpSession session); 32 | R loginEmailStatus(ConsumerRequest loginRequest, HttpSession session); 33 | Consumer findByEmail (String email); 34 | R updatePassword01(ConsumerRequest updatePasswordRequest); 35 | } 36 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/service/ListSongService.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.example.yin.common.R; 5 | import com.example.yin.model.domain.ListSong; 6 | import com.example.yin.model.request.ListSongRequest; 7 | 8 | import java.util.List; 9 | 10 | public interface ListSongService extends IService<ListSong> { 11 | 12 | R addListSong(ListSongRequest addListSongRequest); 13 | 14 | R updateListSongMsg(ListSongRequest updateListSongRequest); 15 | 16 | R deleteListSong(Integer songId); 17 | 18 | //看看这啥 19 | List<ListSong> allListSong(); 20 | 21 | R listSongOfSongId(Integer songListId); 22 | } 23 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/service/OrderManager.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.service; 2 | 3 | import com.example.yin.model.domain.Order; 4 | public interface OrderManager { 5 | void sendPassword(Order order,String reciveAddress); 6 | void sendCode(String code,String reciveAddress); 7 | } -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/service/RankListService.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.example.yin.common.R; 5 | import com.example.yin.model.domain.RankList; 6 | import com.example.yin.model.request.RankListRequest; 7 | 8 | public interface RankListService extends IService<RankList> { 9 | 10 | R addRank(RankListRequest rankListAddRequest); 11 | 12 | R rankOfSongListId(Long songListId); 13 | 14 | R getUserRank(Long consumerId, Long songListId); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/service/SingerService.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.example.yin.common.R; 5 | import com.example.yin.model.domain.Singer; 6 | import com.example.yin.model.request.SingerRequest; 7 | import org.springframework.web.multipart.MultipartFile; 8 | 9 | public interface SingerService extends IService<Singer> { 10 | 11 | R addSinger (SingerRequest addSingerRequest); 12 | 13 | R updateSingerMsg(SingerRequest updateSingerRequest); 14 | 15 | R updateSingerPic(MultipartFile avatorFile, int id); 16 | 17 | R deleteSinger(Integer id); 18 | 19 | R allSinger(); 20 | 21 | R singerOfName(String name); 22 | 23 | R singerOfSex(Integer sex); 24 | } 25 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/service/SongListService.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.example.yin.common.R; 5 | import com.example.yin.model.domain.SongList; 6 | import com.example.yin.model.request.SongListRequest; 7 | import org.springframework.web.multipart.MultipartFile; 8 | 9 | import java.util.List; 10 | 11 | public interface SongListService extends IService<SongList> { 12 | 13 | R addSongList(SongListRequest addSongListRequest); 14 | 15 | R updateSongListMsg(SongListRequest updateSongListRequest); 16 | 17 | R updateSongListImg(MultipartFile avatorFile, int id); 18 | 19 | R deleteSongList(Integer id); 20 | 21 | R allSongList(); 22 | 23 | List<SongList> findAllSong(); 24 | 25 | R likeTitle(String title); 26 | 27 | R likeStyle(String style); 28 | } 29 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/service/SongService.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.example.yin.common.R; 5 | import com.example.yin.model.domain.Song; 6 | import com.example.yin.model.request.SongRequest; 7 | import org.springframework.web.multipart.MultipartFile; 8 | 9 | public interface SongService extends IService<Song> { 10 | 11 | R addSong (SongRequest addSongRequest,MultipartFile lrcfile, MultipartFile mpfile); 12 | 13 | R updateSongMsg(SongRequest updateSongRequest); 14 | 15 | R updateSongUrl(MultipartFile urlFile, int id); 16 | 17 | R updateSongPic(MultipartFile urlFile, int id); 18 | 19 | R deleteSong(Integer id); 20 | 21 | R allSong(); 22 | 23 | R songOfSingerId(Integer singerId); 24 | 25 | R songOfId(Integer id); 26 | 27 | R songOfSingerName(String name); 28 | 29 | R updateSongLrc(MultipartFile lrcFile, int id); 30 | } 31 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/service/UserSupportService.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.example.yin.common.R; 5 | import com.example.yin.model.domain.UserSupport; 6 | import com.example.yin.model.request.UserSupportRequest; 7 | 8 | /** 9 | * @author asus 10 | * @description 针对表【user_support】的数据库操作Service 11 | * @createDate 2022-06-11 16:06:28 12 | */ 13 | public interface UserSupportService extends IService<UserSupport> { 14 | 15 | R isUserSupportComment(UserSupportRequest userSupportRequest); 16 | 17 | R insertCommentSupport(UserSupportRequest userSupportRequest); 18 | 19 | R deleteCommentSupport(UserSupportRequest userSupportRequest); 20 | } 21 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/service/impl/AdminServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.service.impl; 2 | 3 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 4 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 5 | import com.example.yin.common.R; 6 | import com.example.yin.mapper.AdminMapper; 7 | import com.example.yin.model.domain.Admin; 8 | import com.example.yin.model.request.AdminRequest; 9 | import com.example.yin.service.AdminService; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.stereotype.Service; 12 | 13 | import javax.servlet.http.HttpSession; 14 | 15 | @Service 16 | public class AdminServiceImpl extends ServiceImpl<AdminMapper, Admin> implements AdminService { 17 | 18 | @Autowired 19 | private AdminMapper adminMapper; 20 | 21 | @Override 22 | public R verityPasswd(AdminRequest adminRequest, HttpSession session) { 23 | QueryWrapper<Admin> queryWrapper = new QueryWrapper<>(); 24 | queryWrapper.eq("name",adminRequest.getUsername()); 25 | queryWrapper.eq("password",adminRequest.getPassword()); 26 | if (adminMapper.selectCount(queryWrapper) > 0) { 27 | session.setAttribute("name", adminRequest.getUsername()); 28 | return R.success("登录成功"); 29 | } else { 30 | return R.error("用户名或密码错误"); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/service/impl/BannerServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.service.impl; 2 | 3 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 4 | import com.example.yin.mapper.BannerMapper; 5 | import com.example.yin.model.domain.Banner; 6 | import com.example.yin.service.BannerService; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.cache.annotation.Cacheable; 9 | import org.springframework.stereotype.Service; 10 | 11 | import java.util.List; 12 | 13 | /** 14 | * @author asus 15 | * @description 针对表【banner】的数据库操作Service实现 16 | * @createDate 2022-06-13 13:13:42 17 | */ 18 | @Service 19 | public class BannerServiceImpl extends ServiceImpl<BannerMapper, Banner> 20 | implements BannerService { 21 | 22 | @Autowired 23 | private BannerMapper bannerMapper; 24 | 25 | @Cacheable(value = "banner", key = "'list'") //放在缓存中 redis 是以key-value进行存储的 26 | @Override 27 | public List<Banner> getAllBanner() { 28 | System.out.println("没有走缓存"); 29 | return bannerMapper.selectList(null); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/service/impl/CollectServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.service.impl; 2 | 3 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 4 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 5 | import com.example.yin.common.R; 6 | import com.example.yin.mapper.CollectMapper; 7 | import com.example.yin.model.domain.Collect; 8 | import com.example.yin.model.request.CollectRequest; 9 | import com.example.yin.service.CollectService; 10 | import org.springframework.beans.BeanUtils; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.stereotype.Service; 13 | 14 | @Service 15 | public class CollectServiceImpl extends ServiceImpl<CollectMapper, Collect> implements CollectService { 16 | @Autowired 17 | private CollectMapper collectMapper; 18 | 19 | @Override 20 | public R addCollection(CollectRequest addCollectRequest) { 21 | //作者用type来判断收藏的是歌还是歌单 22 | Collect collect = new Collect(); 23 | BeanUtils.copyProperties(addCollectRequest, collect); 24 | if (collectMapper.insert(collect) > 0) { 25 | return R.success("收藏成功", true); 26 | } else { 27 | return R.error("收藏失败"); 28 | } 29 | } 30 | 31 | @Override 32 | public R existSongId(CollectRequest isCollectRequest) { 33 | QueryWrapper<Collect> queryWrapper = new QueryWrapper(); 34 | queryWrapper.eq("user_id",isCollectRequest.getUserId()); 35 | queryWrapper.eq("song_id",isCollectRequest.getSongId()); 36 | if (collectMapper.selectCount(queryWrapper) > 0) { 37 | return R.success("已收藏", true); 38 | } else { 39 | return R.success("未收藏", false); 40 | } 41 | } 42 | 43 | @Override 44 | public R deleteCollect(Integer userId, Integer songId) { 45 | QueryWrapper<Collect> queryWrapper = new QueryWrapper(); 46 | queryWrapper.eq("user_id",userId); 47 | queryWrapper.eq("song_id",songId); 48 | if (collectMapper.delete(queryWrapper) > 0) { 49 | return R.success("取消收藏", false); 50 | } else { 51 | return R.error("取消收藏失败"); 52 | } 53 | } 54 | 55 | @Override 56 | public R collectionOfUser(Integer userId) { 57 | QueryWrapper<Collect> queryWrapper = new QueryWrapper(); 58 | queryWrapper.eq("user_id",userId); 59 | return R.success("用户收藏", collectMapper.selectList(queryWrapper)); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/service/impl/CommentServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.service.impl; 2 | 3 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 4 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 5 | import com.example.yin.common.R; 6 | import com.example.yin.mapper.CommentMapper; 7 | import com.example.yin.model.domain.Comment; 8 | import com.example.yin.model.request.CommentRequest; 9 | import com.example.yin.service.CommentService; 10 | import org.springframework.beans.BeanUtils; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.stereotype.Service; 13 | 14 | @Service 15 | public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> implements CommentService { 16 | @Autowired 17 | private CommentMapper commentMapper; 18 | 19 | @Override 20 | public R addComment(CommentRequest addCommentRequest) { 21 | Comment comment = new Comment(); 22 | BeanUtils.copyProperties(addCommentRequest, comment); 23 | comment.setType(addCommentRequest.getNowType()); 24 | if (commentMapper.insert(comment) > 0) { 25 | return R.success("评论成功"); 26 | } else { 27 | return R.error("评论失败"); 28 | } 29 | } 30 | 31 | @Override 32 | public R updateCommentMsg(CommentRequest addCommentRequest) { 33 | Comment comment = new Comment(); 34 | BeanUtils.copyProperties(addCommentRequest, comment); 35 | if (commentMapper.updateById(comment) > 0) { 36 | return R.success("点赞成功"); 37 | } else { 38 | return R.error("点赞失败"); 39 | } 40 | } 41 | 42 | // 删除评论 43 | @Override 44 | public R deleteComment(Integer id) { 45 | if (commentMapper.deleteById(id) > 0) { 46 | return R.success("删除成功"); 47 | } else { 48 | return R.error("删除失败"); 49 | } 50 | } 51 | 52 | @Override 53 | public R commentOfSongId(Integer songId) { 54 | QueryWrapper<Comment> queryWrapper = new QueryWrapper<>(); 55 | queryWrapper.eq("song_id",songId); 56 | return R.success(null, commentMapper.selectList(queryWrapper)); 57 | } 58 | 59 | @Override 60 | public R commentOfSongListId(Integer songListId) { 61 | QueryWrapper<Comment> queryWrapper = new QueryWrapper<>(); 62 | queryWrapper.eq("song_list_id",songListId); 63 | return R.success(null, commentMapper.selectList(queryWrapper)); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/service/impl/ListSongServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.service.impl; 2 | 3 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 4 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 5 | import com.example.yin.common.R; 6 | import com.example.yin.mapper.ListSongMapper; 7 | import com.example.yin.model.domain.ListSong; 8 | import com.example.yin.model.request.ListSongRequest; 9 | import com.example.yin.service.ListSongService; 10 | import org.springframework.beans.BeanUtils; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.stereotype.Service; 13 | 14 | import java.util.List; 15 | 16 | @Service 17 | public class ListSongServiceImpl extends ServiceImpl<ListSongMapper, ListSong> implements ListSongService { 18 | 19 | @Autowired 20 | private ListSongMapper listSongMapper; 21 | 22 | @Override 23 | public List<ListSong> allListSong() { 24 | return listSongMapper.selectList(null); 25 | } 26 | 27 | @Override 28 | public R updateListSongMsg(ListSongRequest updateListSongRequest) { 29 | ListSong listSong = new ListSong(); 30 | BeanUtils.copyProperties(updateListSongRequest, listSong); 31 | if (listSongMapper.updateById(listSong) > 0) { 32 | return R.success("修改成功"); 33 | } else { 34 | return R.error("修改失败"); 35 | } 36 | } 37 | 38 | @Override 39 | public R deleteListSong(Integer songId) { 40 | QueryWrapper<ListSong> queryWrapper = new QueryWrapper<>(); 41 | queryWrapper.eq("song_id",songId); 42 | if (listSongMapper.delete(queryWrapper) > 0) { 43 | return R.success("删除成功"); 44 | } else { 45 | return R.error("删除失败"); 46 | } 47 | } 48 | 49 | @Override 50 | public R addListSong(ListSongRequest addListSongRequest) { 51 | ListSong listSong = new ListSong(); 52 | BeanUtils.copyProperties(addListSongRequest, listSong); 53 | if (listSongMapper.insert(listSong) > 0) { 54 | return R.success("添加成功"); 55 | } else { 56 | return R.error("添加失败"); 57 | } 58 | } 59 | 60 | @Override 61 | public R listSongOfSongId(Integer songListId) { 62 | QueryWrapper<ListSong> queryWrapper = new QueryWrapper<>(); 63 | queryWrapper.eq("song_list_id",songListId); 64 | return R.success("查询成功", listSongMapper.selectList(queryWrapper)); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/service/impl/RankListServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.service.impl; 2 | 3 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 4 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 5 | import com.example.yin.common.R; 6 | import com.example.yin.mapper.RankListMapper; 7 | import com.example.yin.model.domain.RankList; 8 | import com.example.yin.model.request.RankListRequest; 9 | import com.example.yin.service.RankListService; 10 | import org.springframework.beans.BeanUtils; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.stereotype.Service; 13 | 14 | /** 15 | * @author Administrator 16 | */ 17 | @Service 18 | public class RankListServiceImpl extends ServiceImpl<RankListMapper, RankList> implements RankListService { 19 | 20 | 21 | @Autowired 22 | private RankListMapper rankMapper; 23 | 24 | @Override 25 | public R addRank(RankListRequest rankListAddRequest) { 26 | RankList rankList = new RankList(); 27 | BeanUtils.copyProperties(rankListAddRequest, rankList); 28 | if (rankMapper.insert(rankList) > 0) { 29 | return R.success("评价成功"); 30 | } else { 31 | return R.error("评价失败"); 32 | } 33 | } 34 | 35 | @Override 36 | public R rankOfSongListId(Long songListId) { 37 | // 评分总人数如果为 0,则返回0;否则返回计算出的结果 38 | QueryWrapper<RankList> queryWrapper = new QueryWrapper<>(); 39 | queryWrapper.eq("song_list_id",songListId); 40 | Long rankNum = rankMapper.selectCount(queryWrapper); 41 | return R.success(null, (rankNum <= 0) ? 0 : rankMapper.selectScoreSum(songListId) / rankNum); 42 | } 43 | 44 | @Override 45 | public R getUserRank(Long consumerId, Long songListId) { 46 | Integer i = rankMapper.selectUserRank(consumerId, songListId); 47 | return R.success(null, i); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/service/impl/SimpleOrderManager.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.service.impl; 2 | 3 | import javax.mail.Message; 4 | import javax.mail.internet.InternetAddress; 5 | import javax.mail.internet.MimeMessage; 6 | import com.example.yin.model.domain.Order; 7 | import com.example.yin.service.OrderManager; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.beans.factory.annotation.Value; 11 | import org.springframework.mail.MailException; 12 | import org.springframework.mail.javamail.JavaMailSender; 13 | import org.springframework.mail.javamail.MimeMessagePreparator; 14 | import org.springframework.stereotype.Service; 15 | /** 16 | * 邮箱信息的发送 17 | */ 18 | 19 | @Service 20 | public class SimpleOrderManager implements OrderManager { 21 | 22 | @Value("${mail.address}") 23 | private String sendAddress; 24 | 25 | @Autowired 26 | private JavaMailSender mailSender; 27 | 28 | public void setMailSender(JavaMailSender mailSender) { 29 | this.mailSender = mailSender; 30 | } 31 | 32 | public void sendPassword(Order order, String reciveAddress) { 33 | MimeMessagePreparator preparator = new MimeMessagePreparator() { 34 | public void prepare(@NotNull MimeMessage mimeMessage) throws Exception { 35 | mimeMessage.setRecipient(Message.RecipientType.TO, 36 | new InternetAddress(reciveAddress)); 37 | mimeMessage.setFrom(new InternetAddress(sendAddress)); 38 | mimeMessage.setText("Dear " + order.getName() + "\n" + 39 | "Your password is :" + order.getPassword() + "."); 40 | } 41 | }; 42 | 43 | try { 44 | this.mailSender.send(preparator); 45 | } catch (MailException ex) { 46 | 47 | System.err.println(ex.getMessage()); 48 | } 49 | } 50 | 51 | public void sendCode(String code, String reciveAddress) { 52 | MimeMessagePreparator preparator = new MimeMessagePreparator() { 53 | public void prepare(@NotNull MimeMessage mimeMessage) throws Exception { 54 | mimeMessage.setRecipient(Message.RecipientType.TO, 55 | new InternetAddress(reciveAddress)); 56 | mimeMessage.setFrom(new InternetAddress(sendAddress)); 57 | mimeMessage.setText("Dear you code is " + code); 58 | } 59 | }; 60 | this.mailSender.send(preparator); 61 | } 62 | } -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/service/impl/SingerServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.service.impl; 2 | 3 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 4 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 5 | import com.example.yin.common.R; 6 | import com.example.yin.controller.MinioUploadController; 7 | import com.example.yin.mapper.SingerMapper; 8 | import com.example.yin.model.domain.Singer; 9 | import com.example.yin.model.request.SingerRequest; 10 | import com.example.yin.service.SingerService; 11 | import org.springframework.beans.BeanUtils; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.stereotype.Service; 14 | import org.springframework.web.multipart.MultipartFile; 15 | 16 | import java.io.File; 17 | import java.io.IOException; 18 | 19 | @Service 20 | public class SingerServiceImpl extends ServiceImpl<SingerMapper, Singer> implements SingerService { 21 | 22 | @Autowired 23 | private SingerMapper singerMapper; 24 | 25 | @Override 26 | public R updateSingerMsg(SingerRequest updateSingerRequest) { 27 | Singer singer = new Singer(); 28 | BeanUtils.copyProperties(updateSingerRequest, singer); 29 | if (singerMapper.updateById(singer) > 0) { 30 | return R.success("修改成功"); 31 | } else { 32 | return R.error("修改失败"); 33 | } 34 | } 35 | 36 | @Override 37 | public R updateSingerPic(MultipartFile avatorFile, int id) { 38 | String fileName = avatorFile.getOriginalFilename(); 39 | MinioUploadController.uploadImgFile(avatorFile); 40 | String imgPath = "/user01/singer/img/" + fileName; 41 | Singer singer = new Singer(); 42 | singer.setId(id); 43 | singer.setPic(imgPath); 44 | if (singerMapper.updateById(singer) > 0) { 45 | return R.success("上传成功", imgPath); 46 | } else { 47 | return R.error("上传失败"); 48 | } 49 | } 50 | 51 | @Override 52 | public R deleteSinger(Integer id) { 53 | if (singerMapper.deleteById(id) > 0) { 54 | return R.success("删除成功"); 55 | } else { 56 | return R.error("删除失败"); 57 | } 58 | } 59 | 60 | @Override 61 | public R allSinger() { 62 | return R.success(null, singerMapper.selectList(null)); 63 | } 64 | 65 | @Override 66 | public R addSinger(SingerRequest addSingerRequest) { 67 | Singer singer = new Singer(); 68 | BeanUtils.copyProperties(addSingerRequest, singer); 69 | String pic = "/img/avatorImages/user.jpg"; 70 | singer.setPic(pic); 71 | if (singerMapper.insert(singer) > 0) { 72 | return R.success("添加成功"); 73 | } else { 74 | return R.error("添加失败"); 75 | } 76 | } 77 | 78 | @Override 79 | public R singerOfName(String name) { 80 | QueryWrapper<Singer> queryWrapper = new QueryWrapper<>(); 81 | queryWrapper.like("name", name); 82 | return R.success(null, singerMapper.selectList(queryWrapper)); 83 | } 84 | 85 | @Override 86 | public R singerOfSex(Integer sex) { 87 | QueryWrapper<Singer> queryWrapper = new QueryWrapper<>(); 88 | queryWrapper.like("sex", sex); 89 | return R.success(null, singerMapper.selectList(queryWrapper)); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/service/impl/UserSupportServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.service.impl; 2 | 3 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 4 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 5 | import com.example.yin.common.R; 6 | import com.example.yin.mapper.UserSupportMapper; 7 | import com.example.yin.model.domain.UserSupport; 8 | import com.example.yin.model.request.UserSupportRequest; 9 | import com.example.yin.service.UserSupportService; 10 | import org.springframework.beans.BeanUtils; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.stereotype.Service; 13 | 14 | /** 15 | * @author asus 16 | * @description 针对表【user_support】的数据库操作Service实现 17 | * @createDate 2022-06-11 16:06:28 18 | */ 19 | @Service 20 | public class UserSupportServiceImpl extends ServiceImpl<UserSupportMapper, UserSupport> 21 | implements UserSupportService { 22 | 23 | @Autowired 24 | private UserSupportMapper userSupportMapper; 25 | 26 | @Override 27 | public R isUserSupportComment(UserSupportRequest userSupportRequest) { 28 | QueryWrapper<UserSupport> queryWrapper = new QueryWrapper<>(); 29 | queryWrapper.eq("comment_id", userSupportRequest.getCommentId()); 30 | queryWrapper.eq("user_id", userSupportRequest.getUserId()); 31 | if (userSupportMapper.selectCount(queryWrapper) > 0) { 32 | return R.success("您已取消点赞", true); 33 | } else { 34 | return R.success("您已点赞", false); 35 | } 36 | } 37 | 38 | @Override 39 | public R insertCommentSupport(UserSupportRequest userSupportRequest) { 40 | UserSupport userSupport = new UserSupport(); 41 | BeanUtils.copyProperties(userSupportRequest, userSupport); 42 | if (userSupportMapper.insert(userSupport) > 0) { 43 | return R.success("添加记录成功"); 44 | } 45 | return R.error("添加时,发生异常"); 46 | } 47 | 48 | @Override 49 | public R deleteCommentSupport(UserSupportRequest userSupportRequest) { 50 | QueryWrapper<UserSupport> queryWrapper = new QueryWrapper<>(); 51 | queryWrapper.eq("comment_id", userSupportRequest.getCommentId()); 52 | queryWrapper.eq("user_id", userSupportRequest.getUserId()); 53 | if (userSupportMapper.delete(queryWrapper) > 0) { 54 | return R.success("删除记录成功"); 55 | } 56 | return R.error("删除记录发生异常"); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/utils/RandomUtils.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.utils; 2 | 3 | import java.util.Random; 4 | 5 | public class RandomUtils { 6 | public static String code(){ 7 | String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; // 可以包含的字符集合 8 | int length = 5; // 生成的字符串长度为5个字符 9 | StringBuilder randomString = new StringBuilder(); 10 | Random random = new Random(); 11 | for (int i = 0; i < length; i++) { 12 | int randomIndex = random.nextInt(characters.length()); 13 | char randomChar = characters.charAt(randomIndex); 14 | randomString.append(randomChar); 15 | } 16 | return randomString.toString(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /music-server/src/main/java/com/example/yin/utils/TestFileUtil.java: -------------------------------------------------------------------------------- 1 | package com.example.yin.utils; 2 | 3 | import java.io.File; 4 | import java.io.InputStream; 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | import org.apache.commons.collections4.CollectionUtils; 9 | 10 | public class TestFileUtil { 11 | 12 | public static InputStream getResourcesFileInputStream(String fileName) { 13 | return Thread.currentThread().getContextClassLoader().getResourceAsStream("" + fileName); 14 | } 15 | 16 | public static String getPath() { 17 | return TestFileUtil.class.getResource("/").getPath(); 18 | } 19 | 20 | public static TestPathBuild pathBuild() { 21 | return new TestPathBuild(); 22 | } 23 | 24 | public static File createNewFile(String pathName) { 25 | File file = new File(getPath() + pathName); 26 | if (file.exists()) { 27 | file.delete(); 28 | } else { 29 | if (!file.getParentFile().exists()) { 30 | file.getParentFile().mkdirs(); 31 | } 32 | } 33 | return file; 34 | } 35 | 36 | public static File readFile(String pathName) { 37 | return new File(getPath() + pathName); 38 | } 39 | 40 | public static File readUserHomeFile(String pathName) { 41 | return new File(System.getProperty("user.home") + File.separator + pathName); 42 | } 43 | 44 | /** 45 | * build to test file path 46 | **/ 47 | public static class TestPathBuild { 48 | private TestPathBuild() { 49 | subPath = new ArrayList<>(); 50 | } 51 | 52 | private final List<String> subPath; 53 | 54 | public TestPathBuild sub(String dirOrFile) { 55 | subPath.add(dirOrFile); 56 | return this; 57 | } 58 | 59 | public String getPath() { 60 | if (CollectionUtils.isEmpty(subPath)) { 61 | return TestFileUtil.class.getResource("/").getPath(); 62 | } 63 | if (subPath.size() == 1) { 64 | return TestFileUtil.class.getResource("/").getPath() + subPath.get(0); 65 | } 66 | StringBuilder path = new StringBuilder(TestFileUtil.class.getResource("/").getPath()); 67 | path.append(subPath.get(0)); 68 | for (int i = 1; i < subPath.size(); i++) { 69 | path.append(File.separator).append(subPath.get(i)); 70 | } 71 | return path.toString(); 72 | } 73 | 74 | } 75 | 76 | } -------------------------------------------------------------------------------- /music-server/src/main/resources/application-dev.properties: -------------------------------------------------------------------------------- 1 | spring.datasource.url=jdbc:mysql://localhost:3306/tp_music?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC 2 | spring.datasource.username=root 3 | spring.datasource.password=123456 4 | spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver 5 | 6 | minio.endpoint=http://localhost:9000 7 | minio.access-key=root 8 | minio.secret-key=123456789 9 | minio.bucket-name=user01 10 | # 文件上传的大小 11 | spring.servlet.multipart.max-file-size= 50MB 12 | # 文件上传的最大请求大小 13 | spring.servlet.multipart.max-request-size= 50MB 14 | 15 | -------------------------------------------------------------------------------- /music-server/src/main/resources/application-prod.properties: -------------------------------------------------------------------------------- 1 | spring.datasource.url=jdbc:mysql://121.43.39.136:3306/tp_music?serverTimezone=GMT%2B8&useSSL=false 2 | spring.datasource.username=root 3 | spring.datasource.password=123456 4 | spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver 5 | -------------------------------------------------------------------------------- /music-server/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | mybatis.typeAliasesPackage=com.example.yin.model.domain 2 | mybatis.mapperLocations=classpath:mapper/*.xml 3 | spring.jackson.date-format=yyyy-MM-dd HH:mm:ss 4 | spring.jackson.time-zone=GMT+8 5 | server.port=8888 6 | 7 | spring.devtools.restart.enabled=false 8 | 9 | spring.devtools.restart.additional-paths=src/main/java 10 | 11 | spring.devtools.restart.exclude=WEB-INF/** 12 | 13 | logging.level.org.springframework.boot.autoconfigure=ERROR 14 | 15 | spring.redis.host=127.0.0.1 16 | spring.redis.port=6379 17 | spring.redis.database=0 18 | spring.redis.timeout=1800000 19 | spring.redis.lettuce.pool.max-active=20 20 | spring.redis.lettuce.pool.max-wait=-1 21 | 22 | spring.redis.lettuce.pool.max-idle=5 23 | spring.redis.lettuce.pool.min-idle=0 24 | spring.profiles.active=dev 25 | -------------------------------------------------------------------------------- /music-server/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | mail: 3 | host: smtp.163.com # 网站发送邮件邮箱服务 host 4 | port: 465 5 | username: # 开启那个服务的邮箱 6 | password: # 开启服务的那个认证码 7 | properties: 8 | mail: 9 | smtp: 10 | auth: true 11 | socketFactory: 12 | class: javax.net.ssl.SSLSocketFactory 13 | starttls: 14 | enable: true 15 | mail: 16 | address: # 开启那个服务的邮箱 17 | 18 | mybatis-plus: 19 | configuration: 20 | log-impl: org.apache.ibatis.logging.stdout.StdOutImpl -------------------------------------------------------------------------------- /music-server/src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | # LOG4J 2 | log4j.rootCategory=INFO, stdout,file 3 | 4 | # print to console 5 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 6 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 7 | log4j.appender.stdout.layout.ConversionPattern=%d{yy-MM-dd HH:mm:ss,SSS} %5p %c{1}:%L - %m%n 8 | 9 | # print to file 10 | log4j.appender.file=org.apache.log4j.DailyRollingFileAppender 11 | log4j.appender.file.DatePattern='-'yyyy-MM-dd'.log' 12 | log4j.appender.file.File=./logs/musicWebsite 13 | log4j.appender.file.layout=org.apache.log4j.PatternLayout 14 | log4j.appender.file.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} %p [%c]: %m%n 15 | -------------------------------------------------------------------------------- /music-server/src/main/resources/mapper/AdminMapper.xml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 3 | <mapper namespace="com.example.yin.mapper.AdminMapper"> 4 | <resultMap id="BaseResultMap" type="com.example.yin.model.domain.Admin"> 5 | <id column="id" jdbcType="INTEGER" property="id" /> 6 | <result column="name" jdbcType="VARCHAR" property="name" /> 7 | <result column="password" jdbcType="VARCHAR" property="password" /> 8 | </resultMap> 9 | <sql id="Base_Column_List"> 10 | id, name, password 11 | </sql> 12 | 13 | </mapper> 14 | -------------------------------------------------------------------------------- /music-server/src/main/resources/mapper/BannerMapper.xml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <!DOCTYPE mapper 3 | PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 4 | "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 5 | <mapper namespace="com.example.yin.mapper.BannerMapper"> 6 | 7 | <resultMap id="BaseResultMap" type="com.example.yin.model.domain.Banner"> 8 | <id property="id" column="id" jdbcType="INTEGER"/> 9 | <result property="pic" column="pic" jdbcType="VARCHAR"/> 10 | </resultMap> 11 | 12 | <sql id="Base_Column_List"> 13 | id,pic 14 | </sql> 15 | </mapper> 16 | -------------------------------------------------------------------------------- /music-server/src/main/resources/mapper/CollectMapper.xml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8" ?> 2 | <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 3 | <mapper namespace="com.example.yin.mapper.CollectMapper"> 4 | <resultMap id="BaseResultMap" type="com.example.yin.model.domain.Collect"> 5 | <id column="id" property="id" jdbcType="INTEGER" /> 6 | <result column="user_id" property="userId" jdbcType="INTEGER" /> 7 | <result column="type" property="type" jdbcType="TINYINT" /> 8 | <result column="song_id" property="songId" jdbcType="INTEGER" /> 9 | <result column="song_list_id" property="songListId" jdbcType="INTEGER" /> 10 | <result column="create_time" property="createTime" jdbcType="TIMESTAMP" /> 11 | </resultMap> 12 | <sql id="Base_Column_List"> 13 | id, user_id, type, song_id, song_list_id, create_time 14 | </sql> 15 | 16 | </mapper> 17 | -------------------------------------------------------------------------------- /music-server/src/main/resources/mapper/CommentMapper.xml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8" ?> 2 | <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 3 | <mapper namespace="com.example.yin.mapper.CommentMapper"> 4 | <resultMap id="BaseResultMap" type="com.example.yin.model.domain.Comment"> 5 | <id column="id" property="id" jdbcType="INTEGER" /> 6 | <result column="user_id" property="userId" jdbcType="INTEGER" /> 7 | <result column="song_id" property="songId" jdbcType="INTEGER" /> 8 | <result column="song_list_id" property="songListId" jdbcType="INTEGER" /> 9 | <result column="content" property="content" jdbcType="VARCHAR" /> 10 | <result column="create_time" property="createTime" jdbcType="TIMESTAMP" /> 11 | <result column="type" property="type" jdbcType="TINYINT" /> 12 | <result column="up" property="up" jdbcType="INTEGER" /> 13 | </resultMap> 14 | <sql id="Base_Column_List"> 15 | id, user_id, song_id, song_list_id, content, create_time, type, up 16 | </sql> 17 | 18 | </mapper> 19 | -------------------------------------------------------------------------------- /music-server/src/main/resources/mapper/ConsumerMapper.xml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8" ?> 2 | <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 3 | <mapper namespace="com.example.yin.mapper.ConsumerMapper"> 4 | <resultMap id="BaseResultMap" type="com.example.yin.model.domain.Consumer"> 5 | <result column="id" property="id" jdbcType="INTEGER" /> 6 | <result column="username" property="username" jdbcType="VARCHAR" /> 7 | <result column="password" property="password" jdbcType="VARCHAR" /> 8 | <result column="sex" property="sex" jdbcType="TINYINT" /> 9 | <result column="phone_num" property="phoneNum" jdbcType="CHAR" /> 10 | <result column="email" property="email" jdbcType="CHAR" /> 11 | <result column="birth" property="birth" jdbcType="TIMESTAMP" /> 12 | <result column="introduction" property="introduction" jdbcType="VARCHAR" /> 13 | <result column="location" property="location" jdbcType="VARCHAR" /> 14 | <result column="avator" property="avator" jdbcType="VARCHAR" /> 15 | <result column="create_time" property="createTime" jdbcType="TIMESTAMP" /> 16 | <result column="update_time" property="updateTime" jdbcType="TIMESTAMP" /> 17 | </resultMap> 18 | <sql id="Base_Column_List"> 19 | id, username, password, sex, phone_num, email, birth, introduction, location, avator, create_time, update_time 20 | </sql> 21 | 22 | </mapper> 23 | -------------------------------------------------------------------------------- /music-server/src/main/resources/mapper/ListSongMapper.xml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8" ?> 2 | <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 3 | <mapper namespace="com.example.yin.mapper.ListSongMapper"> 4 | <resultMap id="BaseResultMap" type="com.example.yin.model.domain.ListSong"> 5 | <id column="id" property="id" jdbcType="INTEGER" /> 6 | <result column="song_id" property="songId" jdbcType="INTEGER" /> 7 | <result column="song_list_id" property="songListId" jdbcType="INTEGER" /> 8 | </resultMap> 9 | <sql id="Base_Column_List"> 10 | id, song_id, song_list_id 11 | </sql> 12 | 13 | </mapper> 14 | -------------------------------------------------------------------------------- /music-server/src/main/resources/mapper/RankListMapper.xml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8" ?> 2 | <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 3 | <mapper namespace="com.example.yin.mapper.RankListMapper"> 4 | <resultMap id="BaseResultMap" type="com.example.yin.model.domain.RankList"> 5 | <result column="id" property="id" jdbcType="BIGINT" /> 6 | <result column="songListId" property="songListId" jdbcType="BIGINT" /> 7 | <result column="consumerId" property="consumerId" jdbcType="BIGINT" /> 8 | <result column="score" property="score" jdbcType="INTEGER" /> 9 | </resultMap> 10 | 11 | <select id="selectScoreSum" resultType="java.lang.Integer"> 12 | SELECT COALESCE(sum(score), 0) as score from rank_list where song_list_id = #{0} ; 13 | </select> 14 | 15 | <select id="selectUserRank" resultType="java.lang.Integer" parameterType="com.example.yin.model.domain.RankList"> 16 | select score 17 | from rank_list 18 | where consumer_id = #{consumer_id, jdbcType=BIGINT} and song_list_id = #{song_list_id, jdbcType=BIGINT} 19 | </select> 20 | 21 | </mapper> -------------------------------------------------------------------------------- /music-server/src/main/resources/mapper/SingerMapper.xml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8" ?> 2 | <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 3 | <mapper namespace="com.example.yin.mapper.SingerMapper"> 4 | <resultMap id="BaseResultMap" type="com.example.yin.model.domain.Singer"> 5 | <id column="id" property="id" jdbcType="INTEGER" /> 6 | <result column="name" property="name" jdbcType="VARCHAR" /> 7 | <result column="sex" property="sex" jdbcType="TINYINT" /> 8 | <result column="pic" property="pic" jdbcType="VARCHAR" /> 9 | <result column="birth" property="birth" jdbcType="TIMESTAMP" /> 10 | <result column="location" property="location" jdbcType="VARCHAR" /> 11 | <result column="introduction" property="introduction" jdbcType="VARCHAR" /> 12 | </resultMap> 13 | <sql id="Base_Column_List"> 14 | id, name, sex, pic, birth, location, introduction 15 | </sql> 16 | 17 | </mapper> 18 | -------------------------------------------------------------------------------- /music-server/src/main/resources/mapper/SongListMapper.xml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8" ?> 2 | <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 3 | <mapper namespace="com.example.yin.mapper.SongListMapper"> 4 | <resultMap id="BaseResultMap" type="com.example.yin.model.domain.SongList"> 5 | <id column="id" property="id" jdbcType="INTEGER" /> 6 | <result column="title" property="title" jdbcType="VARCHAR" /> 7 | <result column="pic" property="pic" jdbcType="VARCHAR" /> 8 | <result column="style" property="style" jdbcType="VARCHAR" /> 9 | </resultMap> 10 | <resultMap id="ResultMapWithBLOBs" type="com.example.yin.model.domain.SongList" extends="BaseResultMap"> 11 | <result column="introduction" property="introduction" jdbcType="LONGVARCHAR" /> 12 | </resultMap> 13 | <sql id="Base_Column_List"> 14 | id, title, pic, style 15 | </sql> 16 | <sql id="Blob_Column_List"> 17 | introduction 18 | </sql> 19 | 20 | </mapper> 21 | -------------------------------------------------------------------------------- /music-server/src/main/resources/mapper/SongMapper.xml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8" ?> 2 | <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 3 | <mapper namespace="com.example.yin.mapper.SongMapper"> 4 | <resultMap id="BaseResultMap" type="com.example.yin.model.domain.Song"> 5 | <id column="id" property="id" jdbcType="INTEGER" /> 6 | <result column="singer_id" property="singerId" jdbcType="INTEGER" /> 7 | <result column="name" property="name" jdbcType="VARCHAR" /> 8 | <result column="introduction" property="introduction" jdbcType="VARCHAR" /> 9 | <result column="create_time" property="createTime" jdbcType="TIMESTAMP" /> 10 | <result column="update_time" property="updateTime" jdbcType="TIMESTAMP" /> 11 | <result column="pic" property="pic" jdbcType="VARCHAR" /> 12 | <result column="url" property="url" jdbcType="VARCHAR" /> 13 | </resultMap> 14 | <resultMap id="ResultMapWithBLOBs" type="com.example.yin.model.domain.Song" extends="BaseResultMap"> 15 | <result column="lyric" property="lyric" jdbcType="LONGVARCHAR" /> 16 | </resultMap> 17 | <sql id="Base_Column_List"> 18 | id, singer_id, name, introduction, create_time, update_time, pic 19 | </sql> 20 | <sql id="Blob_Column_List"> 21 | lyric 22 | </sql> 23 | 24 | </mapper> 25 | -------------------------------------------------------------------------------- /music-server/src/main/resources/mapper/UserSupportMapper.xml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <!DOCTYPE mapper 3 | PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 4 | "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 5 | <mapper namespace="com.example.yin.mapper.UserSupportMapper"> 6 | 7 | <resultMap id="BaseResultMap" type="com.example.yin.model.domain.UserSupport"> 8 | <id property="id" column="id" jdbcType="INTEGER"/> 9 | <result property="commentId" column="comment_id" jdbcType="INTEGER"/> 10 | <result property="userId" column="user_id" jdbcType="INTEGER"/> 11 | </resultMap> 12 | 13 | <sql id="Base_Column_List"> 14 | id,comment_id,user_id 15 | </sql> 16 | </mapper> 17 | -------------------------------------------------------------------------------- /music-server/src/main/resources/mysql-connector-java-8.0.13.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yin-Hongwei/music-website/2cccb623c437abc0b90c91948d2c559a387fd335/music-server/src/main/resources/mysql-connector-java-8.0.13.jar -------------------------------------------------------------------------------- /music-server/src/test/java/com/example/yin/YinMusicApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.yin; 2 | 3 | import com.example.yin.service.impl.ConsumerServiceImpl; 4 | import org.junit.jupiter.api.Test; 5 | import org.junit.runner.RunWith; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.boot.test.context.SpringBootTest; 8 | import org.springframework.test.context.junit4.SpringRunner; 9 | 10 | @RunWith(SpringRunner.class) 11 | @SpringBootTest 12 | public class YinMusicApplicationTests { 13 | 14 | @Autowired 15 | // private SongServiceImpl songService; 16 | // private SingerServiceImpl singerService; 17 | // private SongListServiceImpl songListService; 18 | private ConsumerServiceImpl consumerService; 19 | // private RankListServiceImpl rankListService; 20 | 21 | // @Test 22 | // public void contextLoads() { 23 | // 24 | // } 25 | 26 | // @Test 27 | // public void testRank(){ 28 | // Rank rank_list = new Rank(); 29 | // rank_list.setConsumerId(2L); 30 | // rank_list.setScore(3); 31 | // rank_list.setSongListId(2L); 32 | // rankListService.insert(rank_list); 33 | // System.out.println("歌单均分为"+rankListService.selectAverScore(2L)); 34 | // } 35 | 36 | // 歌曲 37 | // @Test 38 | // public void songTest(){ 39 | // Song song = new Song(); 40 | // song.setName("Sanna Nielsen-Undo"); 41 | // song.setPic("/img/songPic/1775711278864263.jpg"); 42 | // song.setSingerId(42); 43 | // song.setCreateTime(new Date()); 44 | // song.setUpdateTime(new Date()); 45 | // song.setIntroduction("Undo"); 46 | // song.setLyric("[00:00:00]暂无歌词"); 47 | // song.setUrl("/song/Sanna Nielsen-Undo.mp3"); 48 | // songService.addSong(song); 49 | // } 50 | 51 | // //歌手 52 | // @Test 53 | // public void singerTest(){ 54 | // Singer singer = new Singer(); 55 | // singer.setName("Álvaro Soler"); 56 | // singer.setSex(new Byte("1")); 57 | // singer.setPic("/img/singerPic/soler.jpg"); 58 | // singer.setBirth(new Date()); 59 | // singer.setLocation("西班牙"); 60 | // singer.setIntroduction("全名是Álvaro Tauchert 61 | // Soler,是一位新晋西班牙歌手,流行音乐作曲家。出生于1991年,西班牙巴塞罗纳。"); 62 | // singerService.addSinger(singer); 63 | // } 64 | // @Test 65 | // public void singerTest2() 66 | // { 67 | // System.out.println(singerService.allSinger()); 68 | // } 69 | 70 | // 歌单 71 | // @Test 72 | // public void songListTest(){ 73 | // 74 | // SongList songList = new SongList(); 75 | // songList.setTitle("国风传统器乐赏~~♪"); 76 | // songList.setPic("/img/songListPic/19169985230816413.jpg"); 77 | // songList.setIntroduction(" 都是自己很喜欢的吉他指弹"); 78 | // songList.setStyle("乐器"); 79 | // songListService.addSongList(songList); 80 | // } 81 | // @Test 82 | // public void songListTest2() 83 | // { 84 | // System.out.println(songListService.allSongList()); 85 | // } 86 | 87 | // 用户 88 | 89 | @Test 90 | public void consumerTest2() 91 | { 92 | System.out.println(consumerService.allUser()); 93 | } 94 | } 95 | --------------------------------------------------------------------------------