├── .browserslistrc ├── .gitignore ├── README.md ├── babel.config.js ├── jsconfig.json ├── package-lock.json ├── package.json ├── public ├── favicon.ico └── index.html ├── src ├── App.vue ├── api │ ├── artists.js │ ├── dj.js │ ├── else.js │ ├── list.js │ ├── mv.js │ ├── plugins │ │ ├── mixin.js │ │ └── request.js │ ├── singer.js │ ├── song.js │ ├── user.js │ └── video.js ├── assets │ ├── area.js │ ├── css │ │ ├── common │ │ │ ├── ad_animate.css │ │ │ ├── common.less │ │ │ └── util.less │ │ └── default │ │ │ ├── app.less │ │ │ ├── dj_detail.less │ │ │ ├── explore.less │ │ │ ├── home.less │ │ │ ├── home_search.less │ │ │ ├── login.less │ │ │ ├── mv_detail.less │ │ │ ├── singer_album.less │ │ │ ├── singer_detail.less │ │ │ ├── song_detail.less │ │ │ ├── song_search.less │ │ │ ├── user_center.less │ │ │ ├── user_detail.less │ │ │ └── video_detail.less │ └── img │ │ ├── login-bg.jpg │ │ ├── m-music-banner.jpg │ │ ├── search-bg.jpg │ │ └── tx.jpg ├── components │ ├── Global │ │ ├── BotLoad.vue │ │ ├── BotLoadAudioList.vue │ │ ├── BotLoadRequest.vue │ │ ├── BreakHeader.vue │ │ ├── EmptyBox.vue │ │ ├── EmptyTextBox.vue │ │ ├── IconText.vue │ │ ├── ImgLoader.vue │ │ ├── LoadingBlock.vue │ │ ├── PullRefresh.vue │ │ └── Scroll.vue │ ├── block │ │ ├── ScrollXBlock.vue │ │ └── StrMarquee.vue │ ├── card │ │ ├── AlbumList.vue │ │ ├── AudioCoverList.vue │ │ ├── AudioItem.vue │ │ ├── AudioList.vue │ │ ├── CircleCard.vue │ │ ├── CommentlistCard.vue │ │ ├── CrowdCard.vue │ │ ├── MvLgCard.vue │ │ ├── MvListCard.vue │ │ ├── MvRmdCard.vue │ │ ├── PlaylistSmCard.vue │ │ ├── SearchVideoList.vue │ │ ├── SonglistCard.vue │ │ ├── UnfoldCard.vue │ │ ├── UsPlaylistCard.vue │ │ ├── VideoCoverCard.vue │ │ ├── VideoList.vue │ │ └── ViewsBlockCard.vue │ ├── carousel │ │ ├── AdCarousel.vue │ │ └── AdCarouselItem.vue │ ├── common │ │ ├── AAleart.vue │ │ ├── ADialog.vue │ │ ├── AdWaterfall.vue │ │ ├── Fullscreen.vue │ │ ├── FullscreenScroll.vue │ │ ├── LoadingBlock.vue │ │ ├── MovableMask.vue │ │ └── RequestLoader.vue │ ├── form │ │ ├── AreaPickerList.vue │ │ ├── AvatarList.vue │ │ ├── DatePickerList.vue │ │ ├── EditInputList.vue │ │ ├── RadioItems.vue │ │ ├── RadioList.vue │ │ ├── RadioListItems.vue │ │ ├── TabBarReply.vue │ │ ├── TextAreaBox.vue │ │ └── TextAreaList.vue │ ├── header │ │ └── AutoHeader.vue │ ├── item │ │ ├── ArtistItem.vue │ │ ├── DjradioItem.vue │ │ ├── PrivateMsgItem.vue │ │ ├── SearchAudioItem.vue │ │ ├── SearchMlogItem.vue │ │ ├── SingerRadioItem.vue │ │ ├── SonglistItem.vue │ │ ├── TrendItem.vue │ │ └── UserItem.vue │ ├── player │ │ ├── TabPlayer.vue │ │ ├── child │ │ │ ├── TpControl.vue │ │ │ ├── TpCover.vue │ │ │ ├── TpCricleProgress.vue │ │ │ ├── TpCurList.vue │ │ │ ├── TpHisList.vue │ │ │ ├── TpLists.vue │ │ │ ├── TpLyric.vue │ │ │ ├── TpOldList.vue │ │ │ ├── TpProgress.vue │ │ │ └── TpTools.vue │ │ └── tabplayer.less │ ├── popup │ │ └── SongPopup.vue │ ├── tool │ │ └── AvatarsHandler.vue │ ├── utils │ │ └── LoadingBlock.js │ └── video │ │ ├── AdVideo.vue │ │ ├── ScreenVideo.vue │ │ └── SingleVideo.vue ├── main.js ├── plugins │ ├── ADialog.js │ ├── GlobalComps.js │ └── Vant.js ├── router │ ├── index.js │ └── route │ │ ├── home.routes.js │ │ └── login.routes.js ├── store │ ├── index.js │ └── modules │ │ ├── music.js │ │ └── user.js ├── utils │ ├── AdDirect.js │ ├── Bus.js │ ├── Constellation.js │ ├── Decorator.js │ ├── Filters.js │ └── ToolFunc.js └── views │ ├── Comment │ └── SongComment.vue │ ├── Dj │ ├── DjDetail.vue │ └── child │ │ ├── DjAbout.vue │ │ ├── DjShow.vue │ │ └── DjSimilar.vue │ ├── Home │ ├── Home.vue │ ├── child │ │ ├── Explore.vue │ │ ├── HomeAside.vue │ │ ├── SkySquare.vue │ │ ├── UserCenter.vue │ │ ├── Village copy.vue │ │ ├── Village.vue │ │ └── child │ │ │ ├── ExBanner.vue │ │ │ ├── ExBoutiqueAudioList.vue │ │ │ ├── ExMvTop.vue │ │ │ ├── ExRmdRadiosStation.vue │ │ │ ├── SsRmdMv.vue │ │ │ ├── UcBanner.vue │ │ │ ├── UcMyMusic.vue │ │ │ └── UcMyPlaylist.vue │ └── routes │ │ ├── HomeSearch.vue │ │ └── child │ │ ├── HsAlbum.vue │ │ ├── HsDj.vue │ │ ├── HsMix.vue │ │ ├── HsMv.vue │ │ ├── HsSinger.vue │ │ ├── HsSong.vue │ │ ├── HsSonglist.vue │ │ ├── HsSuggest.vue │ │ ├── HsUser.vue │ │ └── HsVideo.vue │ ├── Login │ └── Login.vue │ ├── Singer │ ├── SingerDetail.vue │ ├── child │ │ ├── SdAlbum.vue │ │ ├── SdHome.vue │ │ ├── SdMv.vue │ │ └── SdSong.vue │ └── routes │ │ ├── SingerAlbum.vue │ │ └── child │ │ └── SdBanner.vue │ ├── Song │ ├── SongDetail.vue │ ├── SongSearch.vue │ └── child │ │ └── SdBanner.vue │ ├── Square │ ├── DjSquare.vue │ ├── MvSquare.vue │ ├── SonglistSquare.vue │ └── child │ │ ├── DjBanner.vue │ │ ├── DjRmdBlock.vue │ │ ├── DjRmdList.vue │ │ ├── MvChina.vue │ │ ├── MvEamerica.vue │ │ ├── MvJapan.vue │ │ ├── MvKorea.vue │ │ ├── SonglistBoutique.vue │ │ ├── SonglistHot.vue │ │ ├── SonglistPopular.vue │ │ └── SonglistRmd.vue │ ├── User │ ├── UserChatroom.vue │ ├── UserDetail.vue │ ├── UserFriend.vue │ ├── UserNews.vue │ ├── child │ │ ├── UdHome.vue │ │ ├── UdTrend.vue │ │ ├── UfAartistSub.vue │ │ ├── UfFolloweds.vue │ │ ├── UfFollows.vue │ │ ├── UnComments.vue │ │ ├── UnForwards.vue │ │ ├── UnNotices.vue │ │ └── UnPrivate.vue │ └── routes │ │ ├── UserInfo.vue │ │ ├── UserSonglist.vue │ │ ├── UsetTrendDetail.vue │ │ └── child │ │ ├── UtdChat.vue │ │ ├── UtdForward.vue │ │ └── UtdPraise.vue │ └── Video │ ├── MvDetail.vue │ ├── VideoDetail.vue │ └── child │ ├── MdComment.vue │ ├── MdRelated.vue │ └── VdPopup.vue └── vue.config.js /.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not dead 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | pnpm-debug.log* 14 | 15 | # Editor directories and files 16 | .idea 17 | .vscode 18 | *.suo 19 | *.ntvs* 20 | *.njsproj 21 | *.sln 22 | *.sw? 23 | 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Starry 移动端音乐webapp(此项目已停止维护) 2 | ![6041ef606a374.jpg](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/27df42925152420c9a74d0bb6dca1db2~tplv-k3u1fbpfcp-watermark.image) 3 | 4 | ### 前提 5 | 6 | ps:账号使用自己网易云音乐的账号,目前仅支持手机号登录 7 | 8 | ### 特点: 9 | 10 | - 页面切换过渡 11 | - 手势切换操作 12 | - 数据本地储存 13 | - 登录,歌单,专辑,歌手,电台,MV,视频,评论,搜索,用户,动态,粉丝,关注,收藏...等二十几个页面 14 | - 圆形进度条,滚动歌词 15 | - .... 16 | 17 | 18 | 19 | ### 下载 && 运行 20 | 21 | [项目地址](https://github.com/Adicwu/Starry) 22 | 23 | [线上地址](http://music.adicw.cn) 24 | 25 | > 项目当前依赖[NeteaseCloudMusicApi](https://github.com/Binaryify/NeteaseCloudMusicApi),感谢NeteaseCloudMusicApi的作者 26 | 27 | ### 运行截图实例 28 | 29 | ![首页](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/fcdaf78e00d74205846864eb14cc10a5~tplv-k3u1fbpfcp-zoom-1.image) 30 | ![播放器界面](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/24fb6d9f8f2e44c7939ef057b2a011fd~tplv-k3u1fbpfcp-zoom-1.image) 31 | ![滚动歌词](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0e61023542f145849efe4bcbcaf122d4~tplv-k3u1fbpfcp-zoom-1.image) 32 | ![用户动态](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/548b7d2e7cb04d9586f4a5f7814e337e~tplv-k3u1fbpfcp-zoom-1.image) 33 | ![发现](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9ae7fae749194ce98cdf38f7fb15c0f0~tplv-k3u1fbpfcp-zoom-1.image) 34 | ![mv详情](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/05d7b930f54344ccb5cb6e3b827ad668~tplv-k3u1fbpfcp-zoom-1.image) 35 | ![搜索](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4ebf153c9a8341b9aa8842e2d3531f34~tplv-k3u1fbpfcp-zoom-1.image) 36 | 37 | ### 技术栈 38 | 39 | #### 前端 40 | 41 | 1. vue-cli4以及其全家桶 42 | 2. Vant/FontAwesome/Animate.css/BetterScroll 43 | 3. Axios/Less 44 | 45 | #### 后端 46 | 47 | 1. NeteaseCloudMusicApi项目 48 | 49 | 2. nginx反向代理配置https以及域名 50 | 51 | 52 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // 关掉装饰器的错误提示 3 | "compilerOptions": { 4 | "experimentalDecorators": true 5 | } 6 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "m-adic-music", 3 | "version": "0.1.1", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build" 8 | }, 9 | "dependencies": { 10 | "axios": "^0.19.2", 11 | "better-scroll": "^1.15.2", 12 | "core-js": "^3.6.5", 13 | "jquery": "^3.5.1", 14 | "less": "^3.11.1", 15 | "less-loader": "^6.1.0", 16 | "vant": "^2.8.4", 17 | "vue": "^2.6.11", 18 | "vue-router": "^3.3.1", 19 | "vuex": "^3.4.0" 20 | }, 21 | "devDependencies": { 22 | "@vue/cli-plugin-babel": "~4.4.0", 23 | "@vue/cli-plugin-router": "~4.4.0", 24 | "@vue/cli-plugin-vuex": "~4.4.0", 25 | "@vue/cli-service": "~4.4.0", 26 | "compression-webpack-plugin": "^4.0.0", 27 | "style-resources-loader": "^1.3.3", 28 | "vue-cli-plugin-style-resources-loader": "^0.1.4", 29 | "vue-template-compiler": "^2.6.11" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adicwu/Starry/a9530e3901ed1e967be9feafc9bff863026dc591/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | SkySquare 11 | 12 | 13 | 18 |
19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/api/artists.js: -------------------------------------------------------------------------------- 1 | import { 2 | getax 3 | } from './plugins/request.js' 4 | 5 | //歌手信息以及单曲 6 | export function artists(id) { 7 | return getax(`artists?id=${id}`) 8 | } 9 | -------------------------------------------------------------------------------- /src/api/dj.js: -------------------------------------------------------------------------------- 1 | import { 2 | getax 3 | } from './plugins/request.js' 4 | 5 | //dj轮播 6 | export function djBanner() { 7 | return getax('dj/banner') 8 | } 9 | 10 | //分类dj 11 | export function rmdDj(type) { 12 | return getax(`dj/recommend/type?type=${type}`) 13 | } 14 | 15 | //dj分类列表 16 | export function djTypes() { 17 | return getax('dj/catelist') 18 | } 19 | 20 | //dj节目 21 | export function djProgram(id,limit=30){ 22 | return getax(`dj/program?rid=${id}&limit=${limit}`) 23 | } 24 | 25 | //dj详情 26 | export function djDetail(id){ 27 | return getax(`dj/detail?rid=${id}`) 28 | } 29 | 30 | //dj节目评论 31 | export function djComment(id){ 32 | return getax(`comment/dj?id=${id}`) 33 | } -------------------------------------------------------------------------------- /src/api/else.js: -------------------------------------------------------------------------------- 1 | import { 2 | getax 3 | } from './plugins/request.js' 4 | import { 5 | songUrl 6 | } from './song.js' 7 | export function getBanner() { 8 | return getax('banner?type=1') 9 | } 10 | export function exclusiveBroadcast() { 11 | return getax('personalized/privatecontent') 12 | } 13 | export function rmdRadiostation() { 14 | return getax('personalized/djprogram') 15 | } 16 | export function mvTop(limit) { 17 | return getax(`top/mv?limit=${limit}`) 18 | } 19 | export function hotComment(id, type, limit = 10, offset = 0) { 20 | // 0: 歌曲 1: mv 2: 歌单 3: 专辑 4: 电台 5: 视频 21 | return getax(`comment/hot?id=${id}&type=${type}&limit=${limit}&offset=${offset}`) 22 | } 23 | //相关列表(电台、歌单) 24 | export function relatedList(id) { 25 | return getax(`related/playlist?id=${id}`) 26 | } 27 | //默认搜索关键词 28 | export function dfSearchTxt() { 29 | return getax(`search/default`) 30 | } 31 | //热搜列表(简略) 32 | export function tinyHotSearch() { 33 | return getax(`search/hot`) 34 | } 35 | //热搜列表(详细) 36 | export function fullHotSearch() { 37 | return getax(`search/hot/detail`) 38 | } 39 | 40 | //混合关键字搜索 41 | //type 1: 单曲, 10: 专辑, 100: 歌手, 1000: 歌单, 1002: 用户, 1004: MV, 1006: 歌词, 1009: 电台, 1014: 视频, 1018:综合 42 | export function mixSearch(key, type = 1, limit = 40, offset = 0) { 43 | if (type === 1) { 44 | return new Promise((resolve, reject) => { 45 | getax(`search?keywords=${key}&limit=${limit}&type=${type}&offset=${offset}`).then(res => { 46 | let songs = res.data.result.songs 47 | let songCount = res.data.result.songCount 48 | let ids = songs.map(item => item.id) 49 | songUrl(ids.toString()).then(respon => { 50 | respon.data.data.forEach(rel => { 51 | let index = songs.findIndex(item => item.id === rel.id) 52 | songs[index].url = rel.url 53 | }) 54 | }) 55 | let rel = { 56 | songs, 57 | songCount 58 | } 59 | resolve(rel) 60 | }).catch(err => reject(err)) 61 | }) 62 | } else { 63 | return getax(`search?keywords=${key}&limit=${limit}&type=${type}&offset=${offset}`) 64 | } 65 | } 66 | 67 | //搜索提示 68 | export function searchSuggest(keywords) { 69 | return getax(`search/suggest?keywords= ${keywords}&type=mobile`) 70 | } -------------------------------------------------------------------------------- /src/api/list.js: -------------------------------------------------------------------------------- 1 | import { 2 | getax 3 | } from './plugins/request.js' 4 | 5 | //精品歌单 6 | export function boutiqueAudioList(cat = '',limit, before = 0) { 7 | // " 华语 "、" 古风 " 、" 欧美 "、" 流行 ", 默认为 "全部" 8 | return before === 0 ? 9 | getax(`/top/playlist/highquality?limit=${limit}&cat=${cat}`) : 10 | getax(`/top/playlist/highquality?limit=${limit}&before=${before}&cat=${cat}`) 11 | } 12 | 13 | //推荐歌单 14 | export function rmdSonglist(limit = 1) { 15 | return getax(`personalized?limit=${limit}`) 16 | } 17 | 18 | //热门歌单 19 | export function hotSonglist() { 20 | return getax('playlist/hot') 21 | } 22 | 23 | //网友精选歌单 24 | export function userHotSonglist(limit, offset = 0, order = '', cat = '') { 25 | return getax(`top/playlist?limit=${limit}&offset=${offset}&order=${order}&cat=${cat}`) 26 | } 27 | -------------------------------------------------------------------------------- /src/api/mv.js: -------------------------------------------------------------------------------- 1 | import { 2 | getax 3 | } from './plugins/request.js' 4 | 5 | //最新mv 6 | export function newMv(limit) { 7 | return getax(`/mv/first?limit=${limit}`, false) 8 | } 9 | 10 | //推荐mv 11 | export function rmdMv(limit) { 12 | return getax('/personalized/mv') 13 | } 14 | 15 | //排行mv 16 | export function rankMv(limit, area = '') { 17 | return getax(`/top/mv?limit=${limit}&area=${area}`) 18 | } 19 | 20 | //获取mv数据 21 | export function mvDetail(id) { 22 | return Promise.all([ 23 | getax(`mv/detail?mvid=${id}`), 24 | getax(`mv/url?id=${id}`), 25 | getax(`mv/detail/info?mvid=${id}`), 26 | ]) 27 | } 28 | 29 | //获取mv相关视频数据 30 | export function mvRelated(id) { 31 | return getax(`related/allvideo?id=${id}`) 32 | } 33 | 34 | //获取视频标签/分类下的视频 35 | export function mvGroup(id){ 36 | return getax(`video/group?id=${id}`) 37 | } 38 | 39 | //获取mv评论内容 40 | export function mvComment(id,limit=5) { 41 | return getax(`comment/mv?id=${id}&limit=${limit}`) 42 | } 43 | -------------------------------------------------------------------------------- /src/api/plugins/mixin.js: -------------------------------------------------------------------------------- 1 | import store from '../../store/index.js' 2 | export function getCookie(){ 3 | let { 4 | cookie 5 | } = store.state.user; 6 | return cookie; 7 | } -------------------------------------------------------------------------------- /src/api/plugins/request.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import { Toast } from 'vant' 3 | const dev = false; 4 | 5 | const baseURL = dev ? '/api' : 'https://musicapi.adicw.cn/', 6 | timeout = 6000; 7 | axios.defaults.withCredentials = true 8 | const instance = axios.create({ 9 | baseURL, 10 | timeout, 11 | }) 12 | instance.interceptors.response.use(response => { 13 | return response 14 | }, error => { 15 | let { status, data } = error.response 16 | switch (status) { 17 | case 404: { 18 | Toast(data.message || '!!!'); 19 | break; 20 | } 21 | } 22 | return Promise.reject(error) 23 | }) 24 | // instance.interceptors.request.use(config => { 25 | // if (store.state.user.token == null) { 26 | // router.push('/login') 27 | // } else { 28 | // let { cookie } = store.state.user 29 | // config.withCredentials = true 30 | // config.header.cookie = cookie 31 | // } 32 | // return config 33 | // }, err => { 34 | // console.dir(err); 35 | // return Promise.reject(err) 36 | // }) 37 | 38 | export function getax(config) { 39 | return instance(config) 40 | } 41 | 42 | export function postax(url, data = {}) { 43 | return instance.post(url, data) 44 | } 45 | 46 | export function putax(url, data = {}) { 47 | return instance.put(url, data) 48 | } -------------------------------------------------------------------------------- /src/api/singer.js: -------------------------------------------------------------------------------- 1 | import { 2 | getax 3 | } from './plugins/request.js' 4 | //歌手mv 5 | export function singerMv(id, limit = 50) { 6 | return getax(`artist/mv?id=${id}&limit=${limit}`) 7 | } 8 | //歌手专辑 9 | export function singerAlbums(id, limit = 40) { 10 | return getax(`artist/album?id=${id}&limit=${limit}`) 11 | } 12 | //专辑内容 13 | export function singerAlbum(id) { 14 | return getax(`album?id=${id}`) 15 | } 16 | //歌手描述 17 | export function singerDesc(id) { 18 | return getax(`artist/desc?id=${id}`) 19 | } 20 | //歌手热门50单曲 21 | export function singerHotArtists(id) { 22 | return getax(`artist/top/song?id=${id}`) 23 | } 24 | //歌手单曲 25 | export function singerArtists(id) { 26 | return getax(`artists?id=${id}`) 27 | } 28 | //相似歌手 29 | export function singerSimi(id) { 30 | return getax(`/simi/artist?id=${id}`) 31 | } 32 | -------------------------------------------------------------------------------- /src/api/song.js: -------------------------------------------------------------------------------- 1 | import { 2 | getax 3 | } from './plugins/request.js' 4 | 5 | //推荐新歌 6 | export function rmdNewsSong() { 7 | return getax(`personalized/newsong`) 8 | } 9 | 10 | //歌单内容 11 | export function songlistDetail(id) { 12 | return getax(`playlist/detail?id=${id}`) 13 | } 14 | 15 | //歌曲内容 16 | export function songDetail(id) { 17 | return getax(`song/detail?ids=${id}`, false) 18 | } 19 | 20 | //获取音乐url 21 | export function songUrl(id) { 22 | return getax(`song/url?id=${id}`, false) 23 | } 24 | 25 | //获取音乐歌词 26 | export function songLyric(id) { 27 | return getax(`lyric?id=${id}`, false) 28 | } 29 | 30 | //单曲是否可用 31 | export function songCheck(id) { 32 | return getax(`check/music?id=${id}`, false) 33 | } 34 | 35 | //获取歌曲评论 36 | export function songComment(id, limit = 20, offset = 0, before = 0) { 37 | return getax(`comment/music?id=${id}&limit=${limit}&offset=${offset}`) 38 | } 39 | -------------------------------------------------------------------------------- /src/api/video.js: -------------------------------------------------------------------------------- 1 | import { 2 | getax, 3 | postax 4 | } from './plugins/request.js' 5 | import { 6 | getCookie 7 | } from './plugins/mixin.js' 8 | 9 | //推荐视频 10 | export function rmdVideo(offset = 0) { 11 | return getax(`video/timeline/recommend?offset=${offset}`) 12 | } 13 | 14 | //全部视频列表 15 | export function videoLists(offset = 0) { 16 | return getax(`video/timeline/all?offset=${offset}`) 17 | } 18 | 19 | //标签/分类视频 20 | export function groupVideo(id, offset = 0) { 21 | return getax(`video/group?id=${id}offset=${offset}`) 22 | } 23 | 24 | //视频分类列表 25 | export function videoCateLists() { 26 | return getax(`video/category/list`) 27 | } 28 | 29 | //视频标签列表 30 | export function videoGroupLists() { 31 | return getax(`video/group/list`) 32 | } 33 | 34 | //视频详情 35 | export function videoDetail(id) { 36 | return getax(`video/detail?id=${id}`) 37 | } 38 | 39 | //视频相关数据 40 | export function videoInfo(id) { 41 | return getax(`video/detail/info?id=${id}`) 42 | } 43 | 44 | //视频播放地址 45 | export function videoUrl(id) { 46 | return getax(`video/url?id=${id}`) 47 | } 48 | 49 | //视频评论 50 | export function videoComment(id, limit = 5, offset = 0) { 51 | return getax(`comment/video?id=${id}&limit=${limit}&offset=${offset}`) 52 | } 53 | 54 | //云盘 55 | export function cloud(limit = 200, offset = 0) { 56 | return getax(`user/cloud?limit=${limit}&offset=${offset}`) 57 | } -------------------------------------------------------------------------------- /src/assets/css/common/ad_animate.css: -------------------------------------------------------------------------------- 1 | /* fast */ 2 | .ft-delay { 3 | animation-delay: 0.3s; 4 | } 5 | 6 | .slide-ftin-up { 7 | animation: slideltinup .5s forwards; 8 | } 9 | 10 | @keyframes slideltinup { 11 | from { 12 | transform: translate3d(0, 60px, 0); 13 | } 14 | 15 | to { 16 | transform: translate3d(0, 0, 0); 17 | } 18 | } 19 | 20 | .slide-ftin-down { 21 | animation: slideltindown .5s forwards; 22 | } 23 | 24 | @keyframes slideltindown { 25 | from { 26 | transform: translate3d(0, -60px, 0); 27 | } 28 | 29 | to { 30 | transform: translate3d(0, 0, 0); 31 | } 32 | } 33 | 34 | .slide-ftin-left { 35 | animation: slideltinleft .5s forwards; 36 | } 37 | 38 | @keyframes slideltinleft { 39 | from { 40 | transform: translate3d(-60px, 0, 0); 41 | } 42 | 43 | to { 44 | transform: translate3d(0, 0, 0); 45 | } 46 | } 47 | 48 | .slide-ftin-right { 49 | animation: slideltinright .5s forwards; 50 | } 51 | 52 | @keyframes slideltinright { 53 | from { 54 | transform: translate3d(60px, 0, 0); 55 | } 56 | 57 | to { 58 | transform: translate3d(0, 0, 0); 59 | } 60 | } 61 | 62 | .fade-ftin { 63 | animation: fadeftin .3s forwards; 64 | } 65 | 66 | @keyframes fadeftin { 67 | from { 68 | opacity: 0; 69 | } 70 | 71 | to { 72 | opacity: 1; 73 | } 74 | } 75 | 76 | .fade-scale-in{ 77 | animation: fadeScaleIn .3s forwards; 78 | } 79 | 80 | @keyframes fadeScaleIn{ 81 | 0%{ 82 | opacity: 0; 83 | transform: scale(.95); 84 | } 85 | 40%{ 86 | opacity: .8; 87 | } 88 | 100%{ 89 | opacity: 1; 90 | transform: scale(1); 91 | } 92 | } 93 | 94 | .fade-ftin-up { 95 | animation: fadeftinup .3s forwards; 96 | } 97 | 98 | @keyframes fadeftinup { 99 | from { 100 | transform: translate3d(0, 120px, 0); 101 | opacity: 0; 102 | } 103 | 104 | to { 105 | transform: translate3d(0, 0, 0); 106 | opacity: 1; 107 | } 108 | } 109 | 110 | .fade-ftout-down { 111 | animation: fadeftoutdown .3s forwards; 112 | } 113 | 114 | @keyframes fadeftoutdown { 115 | from { 116 | transform: translate3d(0, 0, 0); 117 | opacity: 1; 118 | } 119 | 120 | to { 121 | transform: translate3d(0, 120px, 0); 122 | opacity: 0; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/assets/css/common/common.less: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | -webkit-overflow-scrolling: touch; 5 | &::selection { 6 | background-color: #28c7b9; 7 | color: white; 8 | } 9 | 10 | &::-moz-selection { 11 | background-color: #28c7b9; 12 | color: white; 13 | } 14 | 15 | &::-webkit-selection { 16 | background-color: #28c7b9; 17 | color: white; 18 | } 19 | 20 | input:-webkit-autofill, 21 | textarea:-webkit-autofill, 22 | select:-webkit-autofill { 23 | -webkit-text-fill-color: #717171 !important; 24 | -webkit-box-shadow: 0 0 0px 1000px transparent inset !important; 25 | background-color: transparent; 26 | background-image: none; 27 | transition: background-color 50000s ease-in-out 0s; 28 | } 29 | 30 | img { 31 | object-fit: cover; 32 | width: 100%; 33 | height: 100%; 34 | } 35 | 36 | .img-optimization{ 37 | width: 20%; 38 | height: 20%; 39 | transform: scale(5) translate(40%,40%); 40 | } 41 | } 42 | 43 | html { 44 | height: 100%; 45 | h1 { 46 | font-size: 2rem; 47 | } 48 | h2 { 49 | font-size: 1.5rem; 50 | } 51 | h3 { 52 | font-size: 1.125rem; 53 | } 54 | h4 { 55 | font-size: 1rem; 56 | } 57 | h5 { 58 | font-size: 0.8125rem; 59 | } 60 | h6 { 61 | font-size: 0.6875rem; 62 | } 63 | body { 64 | height: 100%; 65 | -webkit-font-smoothing: antialiased; 66 | -moz-osx-font-smoothing: grayscale; 67 | 68 | img { 69 | object-fit: cover; 70 | user-select: none; 71 | pointer-event: none; 72 | } 73 | 74 | /* 取消下列标签点击背景变色 */ 75 | a, 76 | button, 77 | input, 78 | img, 79 | div { 80 | -webkit-tap-highlight-color: transparent; 81 | } 82 | 83 | .text-truncate { 84 | display: block; 85 | width: 100%; 86 | overflow: hidden; 87 | text-overflow: ellipsis; 88 | white-space: nowrap; 89 | } 90 | 91 | .paragraph-truncate { 92 | display: -webkit-box !important; 93 | -webkit-box-orient: vertical; 94 | text-overflow: ellipsis; 95 | -webkit-line-clamp: 2; 96 | overflow: hidden; 97 | white-space: pre-wrap; 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/assets/css/common/util.less: -------------------------------------------------------------------------------- 1 | .black-shadow(@x,@y,@z,@deep:0.4){ 2 | box-shadow: @x @y @z rgba(0, 0, 0, @deep); 3 | } 4 | .pale-white(@deep:0.8){ 5 | color: rgba(255, 255, 255, @deep); 6 | } 7 | .pale-black(@deep:0.8){ 8 | color: rgba(0, 0, 0, @deep); 9 | } 10 | .click-bg{ 11 | background-color: rgba(0, 0, 0, 0.1); 12 | } 13 | .mask(@index:1,@background:none){ 14 | content: ''; 15 | position: absolute; 16 | top: 0; 17 | left: 0; 18 | display: block; 19 | width: 100%; 20 | height: 100%; 21 | z-index: @index; 22 | background: @background; 23 | } 24 | .p-truncate(@line:1){ 25 | display: -webkit-box !important; 26 | width: 100%; 27 | -webkit-box-orient: vertical; 28 | text-overflow: ellipsis; 29 | -webkit-line-clamp: @line; 30 | overflow: hidden; 31 | white-space: pre-wrap; 32 | } -------------------------------------------------------------------------------- /src/assets/css/default/app.less: -------------------------------------------------------------------------------- 1 | #app { 2 | position: relative; 3 | width: 100vw; 4 | height: 100%; 5 | 6 | .app-banner { 7 | position: fixed; 8 | width: 100%; 9 | height: 100%; 10 | z-index: 9999; 11 | background: #def; 12 | img{ 13 | 14 | } 15 | span { 16 | position: absolute; 17 | bottom: 20px; 18 | right: 20px; 19 | padding: 4px 8px; 20 | border-radius: 28px; 21 | border: 1px solid #fff; 22 | opacity: .4; 23 | color: #fff; 24 | font-size: 10px; 25 | } 26 | } 27 | 28 | .flod-left-enter-active { 29 | animation: flod-left-in 0.3s; 30 | } 31 | 32 | .flod-left-leave-active { 33 | animation: flod-left-out 0.3s; 34 | } 35 | 36 | .flod-right-enter-active { 37 | animation: flod-right-in 0.3s; 38 | } 39 | 40 | .flod-right-leave-active { 41 | animation: flod-right-out 0.3s; 42 | } 43 | 44 | .child-route-in { 45 | animation: child-route-in 0.4s forwards; 46 | } 47 | 48 | .child-route-out { 49 | animation: child-route-out 0.4s forwards; 50 | } 51 | 52 | @keyframes flod-left-in { 53 | from { 54 | transform: translate3d(100%, 0, 0); 55 | } 56 | 57 | to { 58 | transform: translate3d(0, 0, 0); 59 | } 60 | } 61 | 62 | @keyframes flod-left-out { 63 | from { 64 | transform: translate3d(0, 0, 0); 65 | } 66 | 67 | to { 68 | transform: translate3d(-100%, 0, 0); 69 | } 70 | } 71 | 72 | @keyframes flod-right-in { 73 | from { 74 | transform: translate3d(-100%, 0, 0); 75 | } 76 | 77 | to { 78 | transform: translate3d(0, 0, 0); 79 | } 80 | } 81 | 82 | @keyframes flod-right-out { 83 | from { 84 | transform: translate3d(0, 0, 0); 85 | } 86 | 87 | to { 88 | transform: translate3d(100%, 0, 0); 89 | } 90 | } 91 | 92 | @keyframes child-route-in { 93 | from { 94 | transform: translate3d(0, 160px, 0); 95 | opacity: 0; 96 | } 97 | 98 | to { 99 | transform: translate3d(0, 0, 0); 100 | opacity: 1; 101 | } 102 | } 103 | 104 | @keyframes child-route-out { 105 | from { 106 | transform: translate3d(0, 0, 0); 107 | opacity: 1; 108 | } 109 | 110 | to { 111 | transform: translate3d(0, 160px, 0); 112 | opacity: 0; 113 | } 114 | } 115 | } -------------------------------------------------------------------------------- /src/assets/css/default/dj_detail.less: -------------------------------------------------------------------------------- 1 | .dj-detail { 2 | position: fixed; 3 | top: 0; 4 | width: 100%; 5 | height: 100%; 6 | background: #fff; 7 | overflow-x: hidden; 8 | overflow-y: scroll; 9 | z-index: 800; 10 | 11 | .dj-detail-cover { 12 | position: sticky; 13 | top: -60vw; 14 | width: 100%; 15 | height: 80vw; 16 | img{ 17 | position: absolute; 18 | top: 0; 19 | z-index: 1; 20 | } 21 | div{ 22 | position: absolute; 23 | width: 80%; 24 | left: 10px; 25 | bottom: 7vw; 26 | z-index: 2; 27 | b{ 28 | font-size: 14px; 29 | color: rgba(255, 255, 255, .9); 30 | } 31 | p{ 32 | margin-top: 3px; 33 | color: #999; 34 | font-size: 10px; 35 | } 36 | } 37 | &.active { 38 | z-index: 6; 39 | } 40 | } 41 | 42 | .dj-detail-contain { 43 | margin-top: -40px; 44 | margin-bottom: 120px; 45 | 46 | & /deep/ .van-tabs__wrap { 47 | z-index: 6; 48 | 49 | &::after { 50 | border: none; 51 | border-bottom: 1px solid #eee; 52 | } 53 | 54 | .van-tabs__nav { 55 | border-top-left-radius: 26px; 56 | border-top-right-radius: 26px; 57 | background: #fff !important; 58 | 59 | .van-tabs__line { 60 | width: 30px !important; 61 | } 62 | } 63 | 64 | .van-tab__text { 65 | font-size: 12px; 66 | } 67 | } 68 | } 69 | } -------------------------------------------------------------------------------- /src/assets/css/default/explore.less: -------------------------------------------------------------------------------- 1 | .explore { 2 | width: 100%; 3 | height: 100%; 4 | padding-top: 44px; 5 | box-sizing: border-box; 6 | background: #000; 7 | overflow-y: auto; 8 | /deep/.van-pull-refresh__track>:last-child{ 9 | margin-bottom: 100px; 10 | } 11 | } -------------------------------------------------------------------------------- /src/assets/css/default/home.less: -------------------------------------------------------------------------------- 1 | .home { 2 | position: absolute; 3 | top: 0; 4 | left: 0; 5 | width: 100%; 6 | height: 100%; 7 | overflow: hidden; 8 | .home-contain { 9 | position: relative; 10 | width: 100%; 11 | height: 100%; 12 | overflow: hidden; 13 | .nav-aside { 14 | width: 60px; 15 | height: 44px; 16 | color: #fff; 17 | font-size: 1.4375rem; 18 | display: flex; 19 | box-sizing: border-box; 20 | align-items: center; 21 | &:first-child { 22 | justify-content: flex-start; 23 | padding-left: 12px; 24 | } 25 | &:last-child { 26 | justify-content: flex-end; 27 | padding-right: 12px; 28 | } 29 | } 30 | /deep/.van-tabs__wrap { 31 | position: absolute; 32 | width: 100vw; 33 | z-index: 555; 34 | &.van-hairline--top-bottom::after { 35 | content: unset !important; 36 | } 37 | .van-tab { 38 | transition: all 0.3s; 39 | .van-tab__text { 40 | color: #fff !important; 41 | } 42 | } 43 | .van-tab--active { 44 | font-weight: 600 !important; 45 | font-size: 16px !important; 46 | } 47 | } 48 | /deep/.van-tabs__content { 49 | width: 100vw; 50 | height: 100%; 51 | .van-tab__pane { 52 | position: absolute; 53 | height: 100%; 54 | overflow: hidden; 55 | background: #000; 56 | & > div { 57 | animation: fade-in 0.6s forwards; 58 | } 59 | @keyframes fade-in { 60 | from { 61 | transform: translateZ(0); 62 | opacity: 0.4; 63 | } 64 | to { 65 | transform: translateZ(0); 66 | opacity: 1; 67 | } 68 | } 69 | } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/assets/css/default/login.less: -------------------------------------------------------------------------------- 1 | .login { 2 | position: relative; 3 | width: 100vw; 4 | height: 100%; 5 | background: #fff; 6 | z-index: 999; 7 | .login-banner { 8 | position: relative; 9 | width: 100%; 10 | height: 52vh; 11 | border-radius: 0 0 43px 43px; 12 | overflow: hidden; 13 | &::before { 14 | content: ''; 15 | position: absolute; 16 | bottom: 0; 17 | display: block; 18 | width: 100%; 19 | height: 50%; 20 | background: linear-gradient(to bottom, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.6)); 21 | } 22 | img { 23 | width: 100%; 24 | height: 100%; 25 | } 26 | } 27 | .login-box { 28 | position: fixed; 29 | top: 18vh; 30 | left: 0; 31 | right: 0; 32 | margin: 0 26px; 33 | height: 290px; 34 | background: #fff; 35 | padding: 16px; 36 | box-sizing: border-box; 37 | box-shadow: 0 0 24px rgba(0, 0, 0, 0.2); 38 | border-radius: 20px; 39 | animation-duration: 0.8s; 40 | & > h3 { 41 | margin-top: 8px; 42 | padding-bottom: 10px; 43 | text-align: center; 44 | color: #717171; 45 | } 46 | ._input-group { 47 | width: 100%; 48 | height: 46px; 49 | display: grid; 50 | grid-template-columns: 50px 1fr; 51 | grid-template-rows: 1fr; 52 | background: #fafafc; 53 | border-radius: 16px; 54 | overflow: hidden; 55 | margin: 20px 0; 56 | label { 57 | justify-self: center; 58 | align-self: center; 59 | color: #28c9e0; 60 | font-size: 1.125rem; 61 | } 62 | input[type='text'], 63 | input[type='password'] { 64 | display: block; 65 | border: none; 66 | outline: none; 67 | color: #717171; 68 | background: none; 69 | padding-right: 10px; 70 | box-sizing: border-box; 71 | font-size: 0.875rem; 72 | } 73 | } 74 | p { 75 | text-align: center; 76 | font-size: 0.75rem; 77 | text-decoration: underline; 78 | &:active { 79 | color: crimson; 80 | } 81 | } 82 | ._btn-login { 83 | position: absolute; 84 | left: 0; 85 | right: 0; 86 | bottom: -30px; 87 | margin: 0 auto; 88 | width: 86%; 89 | height: 52px; 90 | border: none; 91 | background: linear-gradient(to right, #28c9e0, #1cd5c6); 92 | color: #fff; 93 | border-radius: 46px; 94 | letter-spacing: 4px; 95 | box-shadow: 0 6px 10px rgba(0, 0, 0, 0.2); 96 | outline: none; 97 | font-size: 0.875rem; 98 | transition: all 0.2s; 99 | &:active { 100 | background: linear-gradient(to right, #2ce2fa, #1ff5e4); 101 | } 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/assets/css/default/mv_detail.less: -------------------------------------------------------------------------------- 1 | .mv-detail { 2 | position: fixed; 3 | top: 0; 4 | width: 100%; 5 | height: 100%; 6 | background: #fff; 7 | overflow-x: hidden; 8 | overflow-y: scroll; 9 | z-index: 800; 10 | ._player { 11 | position: sticky; 12 | top: 0; 13 | width: 100vw; 14 | height: 57vw; 15 | background: #def; 16 | z-index: 2; 17 | ._player-cover { 18 | position: absolute; 19 | top: 0; 20 | width: 100%; 21 | height: 100%; 22 | z-index: 20; 23 | } 24 | } 25 | ._info { 26 | position: relative; 27 | padding: 10px 16px; 28 | color: #313131; 29 | z-index: 1; 30 | ._info-sname, 31 | ._info-singer { 32 | width: 100%; 33 | display: flex; 34 | } 35 | ._info-sname { 36 | max-width: 90%; 37 | font-weight: 800; 38 | } 39 | ._info-singer { 40 | justify-content: flex-end; 41 | span { 42 | font-size: 12px; 43 | } 44 | } 45 | ._summary-switch{ 46 | position: absolute; 47 | right: 10px; 48 | top: 10px; 49 | padding: 6px; 50 | color: #717171; 51 | } 52 | } 53 | ._summary{ 54 | position: relative; 55 | box-sizing: border-box; 56 | padding: 16px; 57 | padding-top: 0; 58 | width: 100%; 59 | overflow: hidden; 60 | z-index: 1; 61 | ul{ 62 | li{ 63 | &:first-child{ 64 | background: none; 65 | color: #999999; 66 | font-size: 14px; 67 | margin-left: 0; 68 | padding: 4px 0; 69 | } 70 | font-size: 10px; 71 | padding: 3px 12px; 72 | display: inline-flex; 73 | color: #626262; 74 | background: #f3f3f3; 75 | border-radius: 22px; 76 | margin-right: 10px; 77 | margin-bottom: 8px; 78 | } 79 | } 80 | p{ 81 | margin-top: 4px; 82 | color: #666666; 83 | font-size: 13px; 84 | } 85 | } 86 | ._tools{ 87 | position: relative; 88 | display: grid; 89 | grid-template-columns: repeat(4,1fr); 90 | align-items: center; 91 | justify-items: center; 92 | width: 100vw; 93 | height: 20vw; 94 | border-bottom: 1px solid #e6e6e6; 95 | z-index: 1; 96 | span{ 97 | display: flex; 98 | flex-direction: column; 99 | justify-content: center; 100 | align-items: center; 101 | font-size: 0.625rem; 102 | color: #717171; 103 | &::before{ 104 | color: #000; 105 | margin-bottom: 3px; 106 | font-size: 1.6rem; 107 | } 108 | } 109 | } 110 | ._related{ 111 | 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/assets/css/default/singer_album.less: -------------------------------------------------------------------------------- 1 | .singer-album { 2 | position: fixed; 3 | top: 0; 4 | width: 100%; 5 | height: 100%; 6 | background: #fff; 7 | overflow-x: hidden; 8 | overflow-y: scroll; 9 | z-index: 800; 10 | ._shower { 11 | position: sticky; 12 | top: 46px; 13 | z-index: 10; 14 | margin-top: -80px; 15 | width: 100%; 16 | height: 92px; 17 | border-radius: 22px 22px 0 0; 18 | background: #fff; 19 | ._contain-title { 20 | display: flex; 21 | align-items: center; 22 | padding: 16px; 23 | box-sizing: border-box; 24 | font-size: 1rem; 25 | i { 26 | font-size: 1.5rem; 27 | margin-right: 10px; 28 | color: #717171; 29 | } 30 | span { 31 | color: #999; 32 | font-size: 0.875rem; 33 | } 34 | } 35 | ._contain-tips { 36 | position: relative; 37 | display: grid; 38 | grid-template-columns: 40px 1fr 40px; 39 | grid-template-rows: 1fr; 40 | margin: 0 10px; 41 | height: 36px; 42 | border-radius: 44px; 43 | align-items: center; 44 | box-shadow: 0 0 6px rgba(0, 0, 0, 0.1); 45 | i { 46 | justify-self: center; 47 | font-size: 1.125rem; 48 | &:last-child { 49 | color: #b3b3b3; 50 | } 51 | } 52 | p { 53 | box-sizing: border-box; 54 | font-size: 0.875rem; 55 | a { 56 | color: #b3b3b3; 57 | } 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/assets/css/default/song_detail.less: -------------------------------------------------------------------------------- 1 | .song-detail { 2 | position: fixed; 3 | top: 0; 4 | width: 100%; 5 | height: 100%; 6 | z-index: 800; 7 | background: #fff; 8 | .song-detail-inside{ 9 | position: relative; 10 | width: 100%; 11 | height: 100%; 12 | overflow-x: hidden; 13 | overflow-y: scroll; 14 | ._shower { 15 | position: sticky; 16 | top: 46px; 17 | z-index: 10; 18 | margin-top: -80px; 19 | width: 100%; 20 | height: 92px; 21 | border-radius: 22px 22px 0 0; 22 | background: #fff; 23 | ._contain-title { 24 | display: flex; 25 | align-items: center; 26 | padding: 16px; 27 | box-sizing: border-box; 28 | font-size: 1rem; 29 | i { 30 | font-size: 1.5rem; 31 | margin-right: 10px; 32 | color: #717171; 33 | } 34 | span { 35 | color: #999; 36 | font-size: 0.875rem; 37 | } 38 | } 39 | ._contain-tips { 40 | position: relative; 41 | display: grid; 42 | grid-template-columns: 40px 1fr 40px; 43 | grid-template-rows: 1fr; 44 | margin: 0 10px; 45 | height: 36px; 46 | border-radius: 44px; 47 | align-items: center; 48 | box-shadow: 0 0 6px rgba(0, 0, 0, 0.1); 49 | i { 50 | justify-self: center; 51 | font-size: 1.125rem; 52 | &:last-child { 53 | color: #b3b3b3; 54 | } 55 | } 56 | p { 57 | box-sizing: border-box; 58 | font-size: 0.875rem; 59 | a { 60 | color: #b3b3b3; 61 | } 62 | } 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/assets/css/default/song_search.less: -------------------------------------------------------------------------------- 1 | .song-search { 2 | position: fixed; 3 | top: 0; 4 | width: 100%; 5 | height: 100%; 6 | background: #fff; 7 | overflow-x: hidden; 8 | overflow-y: scroll; 9 | z-index: 800; 10 | overflow: hidden; 11 | ._header{ 12 | position: relative; 13 | width: 100%; 14 | height: 160px; 15 | ._header-control{ 16 | position: relative; 17 | padding-left: 20px; 18 | display: grid; 19 | grid-template-columns: 1fr 80px; 20 | height: 38px; 21 | z-index: 3; 22 | transition: all .3s; 23 | transform: translateY(24px); 24 | &._header-control-focus{ 25 | transform: translateY(16px); 26 | } 27 | ._header-control-input{ 28 | display: grid; 29 | grid-template-columns: 40px 1fr; 30 | border-radius: 12px; 31 | background: #fff; 32 | align-items: center; 33 | justify-items: center; 34 | i{ 35 | font-size: 1.125rem; 36 | color: #717171; 37 | } 38 | input[type=text]{ 39 | box-sizing: border-box; 40 | padding: 10px; 41 | padding-left: 0; 42 | width: 100%; 43 | height: 100%; 44 | background: none; 45 | border: none; 46 | font-size: 0.875rem; 47 | } 48 | } 49 | &>i{ 50 | align-self: center; 51 | justify-self: center; 52 | font-size: 1.875rem; 53 | color: #fff; 54 | } 55 | } 56 | ._header-banner{ 57 | position: absolute; 58 | top: 0; 59 | z-index: 1; 60 | width: 100%; 61 | height: 100%; 62 | background: url(../../img/search-bg.jpg) no-repeat center/cover; 63 | transform: scale(1); 64 | transition: all .3s; 65 | &._header-banner-focus{ 66 | transform: scale(1.2); 67 | } 68 | } 69 | } 70 | ._contain{ 71 | position: absolute; 72 | top: 0; 73 | box-sizing: border-box; 74 | padding-top: 20px; 75 | padding-bottom: 50px; 76 | width: 100%; 77 | height: calc(100vh - 120px); 78 | border-radius: 24px 24px 0 0; 79 | background: #fff; 80 | z-index: 3; 81 | overflow: hidden; 82 | transition: all .3s; 83 | transform: translateY(120px); 84 | &._contain-focus{ 85 | transform: translateY(70px); 86 | height: calc(100vh - 50px); 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /src/assets/css/default/user_center.less: -------------------------------------------------------------------------------- 1 | .usercenter { 2 | position: relative; 3 | width: 100%; 4 | height: 100%; 5 | background: #000; 6 | color: #fff; 7 | overflow-x: hidden; 8 | overflow-y: auto; 9 | &>:last-child{ 10 | margin-bottom: 100px; 11 | } 12 | .usercenter-contain { 13 | width: 100%; 14 | padding-bottom: 20px; 15 | ._userinfo { 16 | margin: 0 26px; 17 | margin-top: 40px; 18 | height: 80px; 19 | display: grid; 20 | grid-template-columns: repeat(3, 1fr); 21 | ._userinfo-item { 22 | display: flex; 23 | flex-direction: column; 24 | justify-content: space-evenly; 25 | align-items: center; 26 | b { 27 | font-size: 1.375rem; 28 | color: #12c770; 29 | } 30 | span { 31 | font-weight: 600; 32 | letter-spacing: 2px; 33 | color: rgba(255,255,255,.8); 34 | font-size: 0.875rem; 35 | } 36 | } 37 | } 38 | ._motto{ 39 | text-align: center; 40 | color: #fff; 41 | font-size: 0.75rem; 42 | margin-top: 20px; 43 | line-height: 18px; 44 | } 45 | 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/assets/img/login-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adicwu/Starry/a9530e3901ed1e967be9feafc9bff863026dc591/src/assets/img/login-bg.jpg -------------------------------------------------------------------------------- /src/assets/img/m-music-banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adicwu/Starry/a9530e3901ed1e967be9feafc9bff863026dc591/src/assets/img/m-music-banner.jpg -------------------------------------------------------------------------------- /src/assets/img/search-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adicwu/Starry/a9530e3901ed1e967be9feafc9bff863026dc591/src/assets/img/search-bg.jpg -------------------------------------------------------------------------------- /src/assets/img/tx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adicwu/Starry/a9530e3901ed1e967be9feafc9bff863026dc591/src/assets/img/tx.jpg -------------------------------------------------------------------------------- /src/components/Global/BreakHeader.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 38 | 39 | 60 | -------------------------------------------------------------------------------- /src/components/Global/EmptyBox.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/components/Global/EmptyTextBox.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 17 | 27 | -------------------------------------------------------------------------------- /src/components/Global/IconText.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 16 | 17 | 35 | -------------------------------------------------------------------------------- /src/components/Global/ImgLoader.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 26 | 27 | 60 | -------------------------------------------------------------------------------- /src/components/Global/LoadingBlock.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 30 | -------------------------------------------------------------------------------- /src/components/block/ScrollXBlock.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 28 | 29 | 59 | -------------------------------------------------------------------------------- /src/components/block/StrMarquee.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 31 | 32 | 62 | -------------------------------------------------------------------------------- /src/components/card/AlbumList.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 42 | -------------------------------------------------------------------------------- /src/components/card/AudioCoverList.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 63 | -------------------------------------------------------------------------------- /src/components/card/AudioItem.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 35 | 36 | 65 | -------------------------------------------------------------------------------- /src/components/card/CircleCard.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 26 | 27 | 71 | -------------------------------------------------------------------------------- /src/components/card/MvRmdCard.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 38 | 39 | 77 | -------------------------------------------------------------------------------- /src/components/card/PlaylistSmCard.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 27 | 28 | 61 | -------------------------------------------------------------------------------- /src/components/card/SonglistCard.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 34 | 35 | 89 | -------------------------------------------------------------------------------- /src/components/card/UsPlaylistCard.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 31 | 32 | 95 | -------------------------------------------------------------------------------- /src/components/card/VideoList.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 44 | -------------------------------------------------------------------------------- /src/components/card/ViewsBlockCard.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 36 | 37 | 92 | -------------------------------------------------------------------------------- /src/components/carousel/AdCarouselItem.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 28 | 29 | 61 | -------------------------------------------------------------------------------- /src/components/common/Fullscreen.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 27 | -------------------------------------------------------------------------------- /src/components/common/FullscreenScroll.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 75 | 88 | -------------------------------------------------------------------------------- /src/components/common/LoadingBlock.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 22 | -------------------------------------------------------------------------------- /src/components/common/MovableMask.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 50 | 51 | 80 | -------------------------------------------------------------------------------- /src/components/common/RequestLoader.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 26 | 27 | 77 | -------------------------------------------------------------------------------- /src/components/form/AreaPickerList.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 66 | 67 | 101 | -------------------------------------------------------------------------------- /src/components/form/AvatarList.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 25 | 58 | -------------------------------------------------------------------------------- /src/components/form/DatePickerList.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 62 | 63 | 97 | -------------------------------------------------------------------------------- /src/components/form/EditInputList.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 37 | 75 | -------------------------------------------------------------------------------- /src/components/form/RadioItems.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 23 | 24 | 32 | -------------------------------------------------------------------------------- /src/components/form/RadioList.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 57 | 58 | 92 | -------------------------------------------------------------------------------- /src/components/form/RadioListItems.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 27 | 28 | 52 | -------------------------------------------------------------------------------- /src/components/form/TabBarReply.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 49 | -------------------------------------------------------------------------------- /src/components/form/TextAreaBox.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 37 | 38 | 65 | -------------------------------------------------------------------------------- /src/components/form/TextAreaList.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 57 | 93 | -------------------------------------------------------------------------------- /src/components/header/AutoHeader.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 43 | 44 | 53 | -------------------------------------------------------------------------------- /src/components/item/ArtistItem.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 34 | -------------------------------------------------------------------------------- /src/components/item/DjradioItem.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 24 | 25 | 65 | -------------------------------------------------------------------------------- /src/components/item/SingerRadioItem.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 30 | -------------------------------------------------------------------------------- /src/components/item/SonglistItem.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 23 | 24 | 63 | -------------------------------------------------------------------------------- /src/components/player/child/TpCover.vue: -------------------------------------------------------------------------------- 1 | 15 | 46 | 98 | -------------------------------------------------------------------------------- /src/components/player/child/TpCricleProgress.vue: -------------------------------------------------------------------------------- 1 | 4 | 47 | 76 | -------------------------------------------------------------------------------- /src/components/player/child/TpCurList.vue: -------------------------------------------------------------------------------- 1 | 17 | 59 | 89 | -------------------------------------------------------------------------------- /src/components/player/child/TpHisList.vue: -------------------------------------------------------------------------------- 1 | 17 | 62 | 92 | -------------------------------------------------------------------------------- /src/components/player/child/TpOldList.vue: -------------------------------------------------------------------------------- 1 | 10 | 27 | 57 | -------------------------------------------------------------------------------- /src/components/player/child/TpProgress.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 69 | -------------------------------------------------------------------------------- /src/components/player/child/TpTools.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 61 | -------------------------------------------------------------------------------- /src/components/player/tabplayer.less: -------------------------------------------------------------------------------- 1 | .tab-player { 2 | position: fixed; 3 | bottom: 0; 4 | left: 0; 5 | width: 100vw; 6 | height: 50px; 7 | background: #fff; 8 | z-index: 888; 9 | box-shadow: 0 -1px 0 rgba(0, 0, 0, 0.05); 10 | transition: all 0.3s; 11 | animation-duration: .3s; 12 | &._active-contain { 13 | height: 100%; 14 | } 15 | ._banner { 16 | position: absolute; 17 | top: 0; 18 | left: 0; 19 | width: 100%; 20 | height: 100%; 21 | // filter: blur(10px); 22 | z-index: -1; 23 | animation-duration: 0.6s; 24 | background-size: cover; 25 | background-position: center; 26 | &::before { 27 | content: ''; 28 | position: absolute; 29 | top: 0; 30 | left: 0; 31 | display: block; 32 | width: 100%; 33 | height: 100%; 34 | background: #333; 35 | opacity: 0.8; 36 | z-index: 2; 37 | transform: scale(1.2); 38 | } 39 | & > img { 40 | transform: scale(1.4); 41 | } 42 | } 43 | 44 | ._info { 45 | display: flex; 46 | flex-direction: column; 47 | justify-content: center; 48 | width: calc(100% - 160px); 49 | height: 100%; 50 | overflow: hidden; 51 | padding: 0 16px; 52 | box-sizing: border-box; 53 | &._active-info { 54 | position: absolute; 55 | bottom: 28%; 56 | width: 100%; 57 | height: unset; 58 | overflow: hidden; 59 | align-items: center; 60 | p { 61 | max-width: 90%; 62 | text-align: center; 63 | &:first-child { 64 | font-size: 1.25rem; 65 | line-height: 1.4rem; 66 | color: #fff; 67 | font-weight: 600; 68 | } 69 | &:last-child { 70 | margin-top: 6px; 71 | font-size: 0.875rem; 72 | color: rgba(255, 255, 255, 0.8); 73 | } 74 | } 75 | } 76 | p { 77 | max-width: 100%; 78 | &:first-child { 79 | font-size: 0.875rem; 80 | color: #333; 81 | } 82 | &:last-child { 83 | font-size: 0.625rem; 84 | color: #808080; 85 | } 86 | } 87 | } 88 | ._tools{ 89 | position: absolute; 90 | bottom: 16%; 91 | padding: 0 30px; 92 | box-sizing: border-box; 93 | width: 100%; 94 | } 95 | ._num-progress { 96 | position: absolute; 97 | top: 280px; 98 | left: 0; 99 | right: 0; 100 | margin: auto; 101 | color: #fff; 102 | display: flex; 103 | justify-content: space-between; 104 | width: 204px; 105 | font-size: 14px; 106 | } 107 | 108 | 109 | } 110 | -------------------------------------------------------------------------------- /src/components/tool/AvatarsHandler.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 32 | 33 | 49 | -------------------------------------------------------------------------------- /src/components/utils/LoadingBlock.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import LoadingBlock from '../common/LoadingBlock.vue' 3 | const Mask = Vue.extend(LoadingBlock) 4 | function insertDom(parent, el, binding) { 5 | el.instance.visible = true; 6 | parent.appendChild(el.mask) 7 | } 8 | function removeDom(rootDom, el, binding) { 9 | if (!binding.value) { 10 | rootDom.removeChild(el.mask) 11 | el.instance && el.instance.$destroy(); 12 | } 13 | } 14 | const directive = () => { 15 | Vue.directive('loading', { 16 | bind(el, binding) { 17 | const mask = new Mask({ 18 | el: document.createElement('div'), 19 | data: {} 20 | }); 21 | el.instance = mask 22 | el.mask = mask.$el 23 | el.oldValue = binding.value 24 | el.isOver = false 25 | if (binding.value) { 26 | Vue.nextTick(() => { 27 | el.oldDisplay = el.style.display 28 | el.style.display = 'none'; 29 | el.rootDom = typeof binding.modifiers.child === 'undefined' ? el.parentElement : el; 30 | insertDom(el.rootDom, el, binding) 31 | }) 32 | } 33 | }, 34 | update(el, binding) { 35 | if (el.oldValue !== binding.value && !el.isOver) { 36 | el.isOver = true 37 | removeDom(el.rootDom, el, binding) 38 | el.style.display = el.oldDisplay; 39 | } 40 | }, 41 | unbind(el) { 42 | el.instance && el.instance.$destroy(); 43 | } 44 | }) 45 | }; 46 | export default directive; -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | //default 2 | import Vue from 'vue' 3 | import App from './App.vue' 4 | import router from './router' 5 | import store from './store' 6 | import axios from 'axios' 7 | 8 | //plugins 9 | import '@/plugins/Vant' 10 | import '@/plugins/GlobalComps' 11 | import '@/plugins/ADialog' 12 | import '@/utils/Filters' 13 | import ToolFunc from '@/utils/ToolFunc' 14 | import AdDirect from '@/utils/AdDirect' 15 | import LoadingBlock from '@/components/utils/LoadingBlock' 16 | import Bus from '@/utils/Bus' 17 | Vue.use(AdDirect) 18 | Vue.use(ToolFunc) 19 | Vue.use(Bus) 20 | Vue.use(LoadingBlock) 21 | 22 | 23 | //axios 24 | Vue.prototype.axios = axios 25 | axios.defaults.withCredentials = true 26 | //vuex 27 | Vue.prototype.$store = store 28 | //else 29 | Vue.prototype.baseImg = 'https://api.adicw.cn/uploads/'; 30 | Vue.prototype.squareImgSize = '?param=300y300'; 31 | Vue.prototype.rectangleImgSize = '?param=533y300'; 32 | Vue.prototype.dfImg = 'http://p1.music.126.net/Vxsf58sMyNjqnWVZa9Wbfw==/18991864347187831.jpg'; 33 | Vue.config.productionTip = false 34 | 35 | //router 36 | new Vue({ 37 | render: h => h(App), 38 | router, 39 | }).$mount('#app') -------------------------------------------------------------------------------- /src/plugins/ADialog.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Confirm from '@/components/common/ADialog' 3 | const ConfirmBox = Vue.extend(Confirm); 4 | Confirm.install = (content, options) => { 5 | options = Object.assign({ 6 | content: content, 7 | }, options); 8 | let instance = new ConfirmBox({ 9 | data: options 10 | }).$mount(); 11 | document.body.appendChild(instance.$el); 12 | return instance.confirm(); 13 | }; 14 | Vue.prototype.$aconfirm = Confirm.install; -------------------------------------------------------------------------------- /src/plugins/GlobalComps.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | const changeStr = str => str.charAt(0).toUpperCase() + str.slice(1) 4 | const requireComponent = require.context('../components/Global', false, /\.vue$/) 5 | requireComponent.keys().forEach(fileName => { 6 | const config = requireComponent(fileName) 7 | const componentName = changeStr( 8 | fileName.replace(/^\.\//, '').replace(/\.\w+$/, '') 9 | ) 10 | Vue.component(componentName, config.default || config) 11 | }) 12 | -------------------------------------------------------------------------------- /src/plugins/Vant.js: -------------------------------------------------------------------------------- 1 | import 'vant/lib/index.css'; 2 | import Vue from 'vue' 3 | const list = [ 4 | Popup, 5 | Overlay, 6 | Icon, 7 | Slider, 8 | Button, 9 | Swipe, 10 | SwipeItem, 11 | Notify, 12 | Toast, 13 | Tab, 14 | Tabs, 15 | Field, 16 | ShareSheet, 17 | ImagePreview, 18 | Loading, 19 | Empty, 20 | PullRefresh, 21 | Circle, 22 | Sticky, 23 | NoticeBar, 24 | DatetimePicker, 25 | Area, 26 | ] 27 | import { 28 | Popup, 29 | Overlay, 30 | Icon, 31 | Slider, 32 | Button, 33 | Swipe, 34 | SwipeItem, 35 | Notify, 36 | Toast, 37 | Tab, 38 | Tabs, 39 | Field, 40 | ShareSheet, 41 | ImagePreview, 42 | Loading, 43 | Empty, 44 | PullRefresh, 45 | Circle, 46 | Sticky, 47 | NoticeBar, 48 | DatetimePicker, 49 | Area, 50 | } from 'vant' 51 | list.forEach(item => { 52 | let no_list = []; 53 | !no_list.includes(item) && Vue.use(item) 54 | }) 55 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import VueRouter from 'vue-router' 2 | import Vue from 'vue' 3 | 4 | const routerList = [] 5 | function importAll(routerArr) { 6 | routerArr.keys().forEach(key => { 7 | routerList.push(routerArr(key).default) 8 | }) 9 | } 10 | importAll(require.context('./route', true, /\.routes\.js/)) 11 | Vue.use(VueRouter) 12 | 13 | const routes = [{ 14 | path: '/', 15 | component: () => import('../views/Home/Home'), 16 | meta: { 17 | title: 'Starry', 18 | } 19 | }, 20 | // { 21 | // path: '*', 22 | // component: , 23 | // meta: { 24 | // title: 'Starry' 25 | // }, 26 | // }, 27 | ...routerList 28 | ] 29 | const router = new VueRouter({ 30 | mode: 'history', 31 | // mode: 'hash', 32 | routes, 33 | }) 34 | 35 | router.beforeEach((to, from, next) => { 36 | next(); 37 | }) 38 | export default router 39 | -------------------------------------------------------------------------------- /src/router/route/login.routes.js: -------------------------------------------------------------------------------- 1 | const Login = () => import('@/views/Login/Login') 2 | export default { 3 | path: '/login', 4 | component: Login, 5 | meta: { 6 | title: '登录 - Starry' 7 | }, 8 | } 9 | -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import user from './modules/user' 4 | import music from './modules/music' 5 | 6 | Vue.use(Vuex) 7 | 8 | export default new Vuex.Store({ 9 | state: { 10 | loading: true 11 | }, 12 | mutations: {}, 13 | actions: {}, 14 | modules: { 15 | user, 16 | music 17 | } 18 | }) 19 | -------------------------------------------------------------------------------- /src/store/modules/user.js: -------------------------------------------------------------------------------- 1 | import { 2 | logout 3 | } from 'apis/user' 4 | export default { 5 | state: sessionStorage.getItem('state') ? JSON.parse(sessionStorage.getItem('state')) : { 6 | flag: false, 7 | userid: null, 8 | token: null, 9 | cookie: null, 10 | }, 11 | mutations: { 12 | setAccessToken(state, auth) { 13 | if (auth.token != state.token) { 14 | state.flag = auth.flag 15 | state.token = auth.token 16 | state.userid = auth.userid 17 | state.cookie = auth.cookie 18 | } 19 | }, 20 | clearAccessToken(state) { 21 | sessionStorage.clear() 22 | location.reload() 23 | } 24 | }, 25 | getters: { 26 | 27 | }, 28 | actions: { 29 | signOut({commit}) { 30 | return new Promise(resolve => { 31 | logout().then(res => { 32 | commit('clearAccessToken') 33 | resolve() 34 | }) 35 | }) 36 | } 37 | }, 38 | } 39 | -------------------------------------------------------------------------------- /src/utils/Bus.js: -------------------------------------------------------------------------------- 1 | const install = (Vue) => { 2 | const Bus = new Vue({ 3 | methods: { 4 | on(event, ...args) { 5 | this.$on(event, ...args); 6 | }, 7 | emit(event, callback) { 8 | this.$emit(event, callback); 9 | }, 10 | off(event, callback) { 11 | this.$off(event, callback); 12 | } 13 | } 14 | }) 15 | Vue.prototype.$bus = Bus; 16 | } 17 | export default install; 18 | -------------------------------------------------------------------------------- /src/utils/Constellation.js: -------------------------------------------------------------------------------- 1 | export const constellation = [{ 2 | date: [312, 419], 3 | text: '白羊座' 4 | }, 5 | { 6 | date: [420, 520], 7 | text: '金牛座' 8 | }, 9 | { 10 | date: [622, 722], 11 | text: '巨蟹座' 12 | }, 13 | { 14 | date: [723, 822], 15 | text: '狮子座' 16 | }, 17 | { 18 | date: [823, 922], 19 | text: '处女座' 20 | }, 21 | { 22 | date: [923, 1023], 23 | text: '天秤座' 24 | }, 25 | { 26 | date: [1024, 1122], 27 | text: '天蝎座', 28 | }, 29 | { 30 | date: [1123, 1221], 31 | text: '射手座' 32 | }, 33 | { 34 | date: [1222, 119], 35 | text: '摩羯座' 36 | }, 37 | { 38 | date: [120, 218], 39 | text: '水瓶座' 40 | }, 41 | { 42 | date: [219, 320], 43 | text: '双鱼座' 44 | } 45 | ] 46 | -------------------------------------------------------------------------------- /src/utils/Decorator.js: -------------------------------------------------------------------------------- 1 | import { 2 | throttle, 3 | debounce 4 | } from 'lodash' 5 | import Vue from 'vue' 6 | export const throttles = function (wait = 300, options = {}) { 7 | return function (target, name, descriptor) { 8 | descriptor.value = throttle(descriptor.value, wait, options) 9 | } 10 | } 11 | export const debounces = function (wait = 300, options = {}) { 12 | return function (target, name, descriptor) { 13 | descriptor.value = debounce(descriptor.value, wait, options) 14 | } 15 | } 16 | export const adConfirm = function (text) { 17 | const { 18 | $aconfirm 19 | } = Vue.prototype; 20 | return function (target, name, descriptor) { 21 | let originFn = descriptor.value; 22 | descriptor.value = function (...args) { 23 | $aconfirm(text) 24 | .then(originFn.bind(this, ...args)) 25 | .catch(() => {}); 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /src/utils/Filters.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | const filters = { 3 | numFormat(val) { 4 | val = val.toString(); 5 | return val.length > 4 ? `${val.substr(0, val.length - 4)}万` : val; 6 | }, 7 | msToYmd(val) { 8 | let date = new Date(val) 9 | return `${date.getFullYear()}.${date.getMonth() + 1}.${date.getDate()}` 10 | }, 11 | } 12 | Object.keys(filters).forEach(k => Vue.filter(k, filters[k])) 13 | -------------------------------------------------------------------------------- /src/utils/ToolFunc.js: -------------------------------------------------------------------------------- 1 | export default { 2 | install(Vue, options) { 3 | window.debouncetimer = null 4 | window.throttleflag = true 5 | Object.assign(Vue.prototype, { 6 | getPresentDate() { 7 | let date = new Date(); 8 | let year = date.getFullYear(); 9 | let month = (date.getMonth() + 1).toString().padStart(2, '0'); 10 | let day = (date.getDate()).toString().padStart(2, '0'); 11 | let fulldate = year + "-" + month + "-" + day; 12 | return fulldate; 13 | }, 14 | getFullPresentDate() { 15 | let date = new Date(); 16 | let year = date.getFullYear(); 17 | let month = (date.getMonth() + 1).toString().padStart(2, '0'); 18 | let day = date 19 | .getDate() 20 | .toString() 21 | .padStart(2, '0'); 22 | let hours = date 23 | .getHours() 24 | .toString() 25 | .padStart(2, '0'); 26 | let mins = date 27 | .getMinutes() 28 | .toString() 29 | .padStart(2, '0'); 30 | return year + '.' + month + '.' + day + ' ' + hours + ':' + mins; 31 | }, 32 | toMainPage(path, id) { 33 | if (this.$route.path === path && this.$route.query.id === id) return; 34 | typeof id != 'undefined' ? this.$router.push(`${path}?id=${id}`) : this.$router.push(path) 35 | }, 36 | debounce(fn, del = 300) { 37 | if (window.debouncetimer != null) clearTimeout(window.debouncetimer) 38 | window.debouncetimer = setTimeout(fn, del) 39 | }, 40 | throttle(fn, del = 300) { 41 | if (!window.throttleflag) return; 42 | window.throttleflag = false 43 | setTimeout(() => { 44 | fn(); 45 | window.throttleflag = true 46 | }, del) 47 | } 48 | }) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/views/Dj/child/DjSimilar.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 51 | 52 | 108 | -------------------------------------------------------------------------------- /src/views/Home/Home.vue: -------------------------------------------------------------------------------- 1 | 40 | 41 | 88 | 89 | 92 | -------------------------------------------------------------------------------- /src/views/Home/child/Explore.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 60 | 61 | 64 | -------------------------------------------------------------------------------- /src/views/Home/child/SkySquare.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 58 | 59 | 69 | -------------------------------------------------------------------------------- /src/views/Home/child/Village copy.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 52 | 53 | 63 | -------------------------------------------------------------------------------- /src/views/Home/child/Village.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 66 | 67 | 76 | -------------------------------------------------------------------------------- /src/views/Home/child/child/ExBoutiqueAudioList.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 44 | 45 | 50 | -------------------------------------------------------------------------------- /src/views/Home/child/child/ExMvTop.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 53 | 54 | 59 | -------------------------------------------------------------------------------- /src/views/Home/child/child/ExRmdRadiosStation.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 48 | 49 | 54 | -------------------------------------------------------------------------------- /src/views/Home/child/child/SsRmdMv.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 32 | 33 | 50 | -------------------------------------------------------------------------------- /src/views/Home/routes/child/HsAlbum.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 55 | -------------------------------------------------------------------------------- /src/views/Home/routes/child/HsDj.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 57 | -------------------------------------------------------------------------------- /src/views/Home/routes/child/HsMv.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 58 | -------------------------------------------------------------------------------- /src/views/Home/routes/child/HsSinger.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 37 | -------------------------------------------------------------------------------- /src/views/Home/routes/child/HsSong.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 57 | -------------------------------------------------------------------------------- /src/views/Home/routes/child/HsSonglist.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 63 | -------------------------------------------------------------------------------- /src/views/Home/routes/child/HsSuggest.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 47 | -------------------------------------------------------------------------------- /src/views/Home/routes/child/HsUser.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 35 | -------------------------------------------------------------------------------- /src/views/Home/routes/child/HsVideo.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 44 | -------------------------------------------------------------------------------- /src/views/Login/Login.vue: -------------------------------------------------------------------------------- 1 | 34 | 35 | 84 | 85 | 88 | -------------------------------------------------------------------------------- /src/views/Singer/child/SdAlbum.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 57 | -------------------------------------------------------------------------------- /src/views/Singer/child/SdMv.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 69 | -------------------------------------------------------------------------------- /src/views/Singer/child/SdSong.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 43 | -------------------------------------------------------------------------------- /src/views/Song/SongSearch.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 83 | 84 | 87 | -------------------------------------------------------------------------------- /src/views/Square/DjSquare.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 76 | 77 | 92 | -------------------------------------------------------------------------------- /src/views/Square/MvSquare.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 55 | 56 | 92 | -------------------------------------------------------------------------------- /src/views/Square/SonglistSquare.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 55 | 56 | 85 | -------------------------------------------------------------------------------- /src/views/Square/child/DjBanner.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 33 | 34 | 46 | -------------------------------------------------------------------------------- /src/views/Square/child/MvChina.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 39 | 40 | 50 | -------------------------------------------------------------------------------- /src/views/Square/child/MvEamerica.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 39 | 40 | 50 | -------------------------------------------------------------------------------- /src/views/Square/child/MvJapan.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 39 | 40 | 50 | -------------------------------------------------------------------------------- /src/views/Square/child/MvKorea.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 39 | 40 | 50 | -------------------------------------------------------------------------------- /src/views/Square/child/SonglistBoutique.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 47 | 48 | 59 | -------------------------------------------------------------------------------- /src/views/Square/child/SonglistHot.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 37 | 38 | 49 | -------------------------------------------------------------------------------- /src/views/Square/child/SonglistPopular.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 47 | 48 | 59 | -------------------------------------------------------------------------------- /src/views/Square/child/SonglistRmd.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 41 | 42 | 53 | -------------------------------------------------------------------------------- /src/views/User/UserChatroom.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 25 | -------------------------------------------------------------------------------- /src/views/User/UserFriend.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 42 | -------------------------------------------------------------------------------- /src/views/User/UserNews.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 41 | -------------------------------------------------------------------------------- /src/views/User/child/UdTrend.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 63 | 64 | 78 | -------------------------------------------------------------------------------- /src/views/User/child/UfAartistSub.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 36 | -------------------------------------------------------------------------------- /src/views/User/child/UfFolloweds.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 36 | -------------------------------------------------------------------------------- /src/views/User/child/UfFollows.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 36 | -------------------------------------------------------------------------------- /src/views/User/child/UnComments.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 36 | -------------------------------------------------------------------------------- /src/views/User/child/UnForwards.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 36 | -------------------------------------------------------------------------------- /src/views/User/child/UnNotices.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 36 | -------------------------------------------------------------------------------- /src/views/User/child/UnPrivate.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 38 | -------------------------------------------------------------------------------- /src/views/User/routes/UsetTrendDetail.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 73 | -------------------------------------------------------------------------------- /src/views/User/routes/child/UtdChat.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 68 | -------------------------------------------------------------------------------- /src/views/User/routes/child/UtdForward.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 53 | -------------------------------------------------------------------------------- /src/views/User/routes/child/UtdPraise.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 52 | -------------------------------------------------------------------------------- /src/views/Video/child/MdComment.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 67 | 68 | 83 | -------------------------------------------------------------------------------- /src/views/Video/child/MdRelated.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 37 | 38 | 51 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | const CompressionPlugin = require('compression-webpack-plugin'), 2 | productionGzipExtensions = [ 3 | "js", 4 | "css", 5 | "svg", 6 | "woff", 7 | "ttf", 8 | "json", 9 | "html" 10 | ], 11 | path = require('path'); 12 | 13 | const resolve = dir => path.join(__dirname, dir); 14 | const devConfig = { 15 | // 跨域 16 | devServer: { 17 | proxy: { 18 | '/api': { 19 | target: "https://musicapi.adicw.cn/", 20 | changeOrigin: true, 21 | ws: true, 22 | pathRewrite: { 23 | '^/api': '' 24 | } 25 | } 26 | } 27 | }, 28 | } 29 | const commonConfig = { 30 | pluginOptions: { 31 | 'style-resources-loader': { 32 | preProcessor: 'less', 33 | patterns: [ 34 | // 全局变量路径,不能使用路径别名 35 | path.resolve(__dirname, 'src/assets/css/common/util.less') 36 | ] 37 | } 38 | }, 39 | //别名配置 40 | //图片转base64 41 | chainWebpack: config => { 42 | config.resolve.alias 43 | .set('styles', resolve('./src/assets/css')) 44 | .set('apis', resolve('./src/api')) 45 | .set('static', resolve('./src/assets')) 46 | .set('comps', resolve('./src/components')); 47 | config.module 48 | .rule('images') 49 | .use('url-loader') 50 | .loader('url-loader') 51 | .tap(options => Object.assign(options, { 52 | limit: 20000 53 | })) 54 | }, 55 | } 56 | const defaultConfig = { 57 | configureWebpack: { 58 | plugins: [ 59 | // Gzip 60 | new CompressionPlugin({ 61 | filename: "[path].gz[query]", 62 | test: new RegExp("\\.(" + productionGzipExtensions.join("|") + ")$"), 63 | threshold: 1024, 64 | minRatio: 0.8, //压缩率大于0.8的才压缩 65 | deleteOriginalAssets: false //是否删除原文件 66 | }) 67 | ], 68 | }, 69 | productionSourceMap: false, //不输出map文件 70 | // devServer: {}, 71 | 72 | 73 | // 跨域 74 | // devServer: { 75 | // proxy: { 76 | // '/api': { 77 | // target: "https://s1.hdslb.com/", 78 | // changeOrigin: true, 79 | // ws: true, 80 | // pathRewrite:{ 81 | // '^/api': '' 82 | // } 83 | // } 84 | // } 85 | // }, 86 | 87 | // 部署应用时的基本 URL 88 | // publicPath: process.env.NODE_ENV === 'production' ? './' : '/', 89 | } 90 | const appConfig = { 91 | runtimeCompiler: true, 92 | publicPath: './', 93 | } 94 | module.exports = { 95 | ...devConfig, 96 | ...commonConfig, 97 | ...defaultConfig 98 | } 99 | --------------------------------------------------------------------------------