mirror of
https://github.com/algerkong/AlgerMusicPlayer.git
synced 2026-04-30 03:47:22 +08:00
首页 歌手推荐 歌单分类 最热音乐没写完
This commit is contained in:
+7
-1
@@ -6,7 +6,13 @@
|
|||||||
<link rel="icon" href="/favicon.ico" />
|
<link rel="icon" href="/favicon.ico" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Vite App</title>
|
<title>Vite App</title>
|
||||||
<link rel="stylesheet" href="//at.alicdn.com/t/font_2685283_d0nzj20hrzk.css">
|
<link rel="stylesheet" href="//at.alicdn.com/t/font_2685283_m5ii4umo6k8.css">
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" />
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--animate-delay: 0.5s;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
Generated
+13
@@ -465,6 +465,14 @@
|
|||||||
"postcss-value-parser": "^4.1.0"
|
"postcss-value-parser": "^4.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"axios": {
|
||||||
|
"version": "0.21.1",
|
||||||
|
"resolved": "https://registry.npm.taobao.org/axios/download/axios-0.21.1.tgz",
|
||||||
|
"integrity": "sha1-IlY0gZYvTWvemnbVFu8OXTwJsrg=",
|
||||||
|
"requires": {
|
||||||
|
"follow-redirects": "^1.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"balanced-match": {
|
"balanced-match": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npm.taobao.org/balanced-match/download/balanced-match-1.0.2.tgz",
|
"resolved": "https://registry.npm.taobao.org/balanced-match/download/balanced-match-1.0.2.tgz",
|
||||||
@@ -866,6 +874,11 @@
|
|||||||
"to-regex-range": "^5.0.1"
|
"to-regex-range": "^5.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"follow-redirects": {
|
||||||
|
"version": "1.14.1",
|
||||||
|
"resolved": "https://registry.nlark.com/follow-redirects/download/follow-redirects-1.14.1.tgz?cache=0&sync_timestamp=1620555300559&other_urls=https%3A%2F%2Fregistry.nlark.com%2Ffollow-redirects%2Fdownload%2Ffollow-redirects-1.14.1.tgz",
|
||||||
|
"integrity": "sha1-2RFN7Qoc/dM04WTmZirQK/2R/0M="
|
||||||
|
},
|
||||||
"fs-extra": {
|
"fs-extra": {
|
||||||
"version": "10.0.0",
|
"version": "10.0.0",
|
||||||
"resolved": "https://registry.nlark.com/fs-extra/download/fs-extra-10.0.0.tgz",
|
"resolved": "https://registry.nlark.com/fs-extra/download/fs-extra-10.0.0.tgz",
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tailwindcss/postcss7-compat": "^2.2.4",
|
"@tailwindcss/postcss7-compat": "^2.2.4",
|
||||||
"autoprefixer": "^9.8.6",
|
"autoprefixer": "^9.8.6",
|
||||||
|
"axios": "^0.21.1",
|
||||||
"postcss": "^7.0.36",
|
"postcss": "^7.0.36",
|
||||||
"sass": "^1.35.2",
|
"sass": "^1.35.2",
|
||||||
"tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.2.4",
|
"tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.2.4",
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import request from "@/utils/request";
|
||||||
|
import { IHotSinger } from "@/type/singer";
|
||||||
|
import { ISearchKeyword } from "@/type/search";
|
||||||
|
import { IPlayListSort } from "@/type/playlist";
|
||||||
|
import { IRecommendMusic } from "@/type/music";
|
||||||
|
|
||||||
|
interface IHotSingerParams {
|
||||||
|
offset: number;
|
||||||
|
limit: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IRecommendMusicParams {
|
||||||
|
limit: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取热门歌手
|
||||||
|
export const getHotSinger = (params: IHotSingerParams) => {
|
||||||
|
return request.get<IHotSinger>("/top/artists", { params });
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取搜索推荐词
|
||||||
|
export const getSearchKeyword = () => {
|
||||||
|
return request.get<ISearchKeyword>("/search/default");
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取歌单分类
|
||||||
|
export const getPlaylistCategory = () => {
|
||||||
|
return request.get<IPlayListSort>("/playlist/catlist");
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取推荐音乐
|
||||||
|
export const getRecommendMusic = (params: IRecommendMusicParams) => {
|
||||||
|
return request.get<IRecommendMusic>("/personalized/newsong", { params });
|
||||||
|
};
|
||||||
+72
-16
@@ -2,31 +2,80 @@
|
|||||||
<div class="layout-page">
|
<div class="layout-page">
|
||||||
<div class="layout-main">
|
<div class="layout-main">
|
||||||
<app-menu class="menu" :menus="menus" />
|
<app-menu class="menu" :menus="menus" />
|
||||||
<router-view class="main"></router-view>
|
<div class="main">
|
||||||
|
<div class="search-box flex">
|
||||||
|
<div class="search-box-input flex-1">
|
||||||
|
<n-input
|
||||||
|
size="large"
|
||||||
|
round
|
||||||
|
:placeholder="searchKeyword"
|
||||||
|
class="border border-gray-600"
|
||||||
|
>
|
||||||
|
<template #prefix>
|
||||||
|
<i class="iconfont icon-search"></i>
|
||||||
|
</template>
|
||||||
|
</n-input>
|
||||||
|
</div>
|
||||||
|
<div class="user-box">
|
||||||
|
<n-popselect
|
||||||
|
v-model:value="value"
|
||||||
|
:options="options"
|
||||||
|
trigger="click"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
<i class="iconfont icon-xiasanjiaoxing"></i>
|
||||||
|
</n-popselect>
|
||||||
|
<n-avatar
|
||||||
|
class="ml-2"
|
||||||
|
circle
|
||||||
|
size="large"
|
||||||
|
src="https://picsum.photos/200/300?random=1"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<router-view></router-view>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from '@vue/reactivity';
|
import { useStore } from 'vuex';
|
||||||
import { AppMenu } from './components';
|
import { AppMenu } from './components';
|
||||||
let menus = ref([
|
import { getSearchKeyword } from '@/api/home';
|
||||||
|
import { ref, onMounted } from 'vue';
|
||||||
|
|
||||||
|
const store = useStore();
|
||||||
|
const menus = store.state.menus;
|
||||||
|
|
||||||
|
|
||||||
|
const value = 'Drive My Car'
|
||||||
|
const options = [
|
||||||
{
|
{
|
||||||
href: '/',
|
label: 'Girl',
|
||||||
icon: "icon-homefill",
|
value: 'Girl'
|
||||||
text: "hello"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
href: '/main',
|
label: 'In My Life',
|
||||||
icon: "icon-peoplefill",
|
value: 'In My Life'
|
||||||
text: "hello"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
href: '/',
|
label: 'Wait',
|
||||||
icon: "icon-videofill",
|
value: 'Wait'
|
||||||
text: "hello"
|
}
|
||||||
},
|
]
|
||||||
])
|
|
||||||
|
const searchKeyword = ref<String>("搜索点什么吧...")
|
||||||
|
|
||||||
|
const loadSearchKeyword = async () => {
|
||||||
|
const { data } = await getSearchKeyword();
|
||||||
|
searchKeyword.value = data.data.showKeyword
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
loadSearchKeyword()
|
||||||
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@@ -38,8 +87,10 @@ let menus = ref([
|
|||||||
|
|
||||||
.layout-main {
|
.layout-main {
|
||||||
@apply bg-black rounded-lg mb-10 text-white shadow-xl flex;
|
@apply bg-black rounded-lg mb-10 text-white shadow-xl flex;
|
||||||
height: 800px;
|
height: 900px;
|
||||||
width: 1400px;
|
width: 1500px;
|
||||||
|
overflow: hidden;
|
||||||
|
min-width: 1500px;
|
||||||
.menu {
|
.menu {
|
||||||
width: 90px;
|
width: 90px;
|
||||||
}
|
}
|
||||||
@@ -47,5 +98,10 @@ let menus = ref([
|
|||||||
@apply pt-6 pr-6 pb-6;
|
@apply pt-6 pr-6 pb-6;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.user-box {
|
||||||
|
@apply ml-6 flex text-lg justify-center items-center rounded-full pl-3 border border-gray-600;
|
||||||
|
background: #1a1a1a;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -4,12 +4,12 @@
|
|||||||
<div class="app-menu">
|
<div class="app-menu">
|
||||||
<div class="app-menu-header">
|
<div class="app-menu-header">
|
||||||
<div class="app-menu-logo">
|
<div class="app-menu-logo">
|
||||||
<img src="@/assets/logo.png" class="w-10 h-10" alt="logo" />
|
<img src="@/assets/logo.png" class="w-9 h-9 mt-2" alt="logo" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="app-menu-list">
|
<div class="app-menu-list">
|
||||||
<div class="app-menu-item" v-for="(item,index) in menus" :key="index">
|
<div class="app-menu-item" v-for="(item,index) in menus" :key="index">
|
||||||
<router-link class="app-menu-item-link mb-4 mt-4" :to="item.href">
|
<router-link class="app-menu-item-link" :to="item.href">
|
||||||
<i class="iconfont app-menu-item-icon" :style="iconStyle" :class="item.icon"></i>
|
<i class="iconfont app-menu-item-icon" :style="iconStyle" :class="item.icon"></i>
|
||||||
<span v-if="isText" class="app-menu-item-text ml-3">{{ item.text }}</span>
|
<span v-if="isText" class="app-menu-item-text ml-3">{{ item.text }}</span>
|
||||||
</router-link>
|
</router-link>
|
||||||
@@ -29,15 +29,15 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
size: {
|
size: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '30px'
|
default: '26px'
|
||||||
},
|
},
|
||||||
color: {
|
color: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '#fff'
|
default: '#aaa'
|
||||||
},
|
},
|
||||||
menus: {
|
menus: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => []
|
default: []
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -61,7 +61,13 @@ onMounted(() => {
|
|||||||
@apply flex items-center justify-center;
|
@apply flex items-center justify-center;
|
||||||
}
|
}
|
||||||
|
|
||||||
img {
|
.app-menu-item-link {
|
||||||
color: #fff;
|
@apply mb-6 mt-6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-menu-item-icon:hover {
|
||||||
|
color: #fff !important;
|
||||||
|
transform: scale(1.05);
|
||||||
|
transition: 0.2s ease-in-out;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -10,7 +10,10 @@ import "./index.css";
|
|||||||
|
|
||||||
import router from "@/router";
|
import router from "@/router";
|
||||||
|
|
||||||
|
import store from "@/store";
|
||||||
|
|
||||||
const app = createApp(App);
|
const app = createApp(App);
|
||||||
app.use(router);
|
app.use(router);
|
||||||
|
app.use(store);
|
||||||
app.use(naive);
|
app.use(naive);
|
||||||
app.mount("#app");
|
app.mount("#app");
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { createStore } from "vuex";
|
||||||
|
|
||||||
|
let state = {
|
||||||
|
menus: [
|
||||||
|
{
|
||||||
|
href: "/",
|
||||||
|
icon: "icon-homefill",
|
||||||
|
text: "hello",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
href: "/main",
|
||||||
|
icon: "icon-peoplefill",
|
||||||
|
text: "hello",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
href: "/",
|
||||||
|
icon: "icon-videofill",
|
||||||
|
text: "hello",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
let mutations = {};
|
||||||
|
|
||||||
|
const store = createStore({
|
||||||
|
state: state,
|
||||||
|
mutations: mutations,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default store;
|
||||||
@@ -0,0 +1,156 @@
|
|||||||
|
export interface IRecommendMusic {
|
||||||
|
code: number;
|
||||||
|
category: number;
|
||||||
|
result: Result[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Result {
|
||||||
|
id: number;
|
||||||
|
type: number;
|
||||||
|
name: string;
|
||||||
|
copywriter?: any;
|
||||||
|
picUrl: string;
|
||||||
|
canDislike: boolean;
|
||||||
|
trackNumberUpdateTime?: any;
|
||||||
|
song: Song;
|
||||||
|
alg: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Song {
|
||||||
|
name: string;
|
||||||
|
id: number;
|
||||||
|
position: number;
|
||||||
|
alias: string[];
|
||||||
|
status: number;
|
||||||
|
fee: number;
|
||||||
|
copyrightId: number;
|
||||||
|
disc: string;
|
||||||
|
no: number;
|
||||||
|
artists: Artist[];
|
||||||
|
album: Album;
|
||||||
|
starred: boolean;
|
||||||
|
popularity: number;
|
||||||
|
score: number;
|
||||||
|
starredNum: number;
|
||||||
|
duration: number;
|
||||||
|
playedNum: number;
|
||||||
|
dayPlays: number;
|
||||||
|
hearTime: number;
|
||||||
|
ringtone: string;
|
||||||
|
crbt?: any;
|
||||||
|
audition?: any;
|
||||||
|
copyFrom: string;
|
||||||
|
commentThreadId: string;
|
||||||
|
rtUrl?: any;
|
||||||
|
ftype: number;
|
||||||
|
rtUrls: any[];
|
||||||
|
copyright: number;
|
||||||
|
transName?: any;
|
||||||
|
sign?: any;
|
||||||
|
mark: number;
|
||||||
|
originCoverType: number;
|
||||||
|
originSongSimpleData?: any;
|
||||||
|
single: number;
|
||||||
|
noCopyrightRcmd?: any;
|
||||||
|
rtype: number;
|
||||||
|
rurl?: any;
|
||||||
|
mvid: number;
|
||||||
|
bMusic: BMusic;
|
||||||
|
mp3Url?: any;
|
||||||
|
hMusic: BMusic;
|
||||||
|
mMusic: BMusic;
|
||||||
|
lMusic: BMusic;
|
||||||
|
exclusive: boolean;
|
||||||
|
privilege: Privilege;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Privilege {
|
||||||
|
id: number;
|
||||||
|
fee: number;
|
||||||
|
payed: number;
|
||||||
|
st: number;
|
||||||
|
pl: number;
|
||||||
|
dl: number;
|
||||||
|
sp: number;
|
||||||
|
cp: number;
|
||||||
|
subp: number;
|
||||||
|
cs: boolean;
|
||||||
|
maxbr: number;
|
||||||
|
fl: number;
|
||||||
|
toast: boolean;
|
||||||
|
flag: number;
|
||||||
|
preSell: boolean;
|
||||||
|
playMaxbr: number;
|
||||||
|
downloadMaxbr: number;
|
||||||
|
rscl?: any;
|
||||||
|
freeTrialPrivilege: FreeTrialPrivilege;
|
||||||
|
chargeInfoList: ChargeInfoList[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ChargeInfoList {
|
||||||
|
rate: number;
|
||||||
|
chargeUrl?: any;
|
||||||
|
chargeMessage?: any;
|
||||||
|
chargeType: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FreeTrialPrivilege {
|
||||||
|
resConsumable: boolean;
|
||||||
|
userConsumable: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface BMusic {
|
||||||
|
name?: any;
|
||||||
|
id: number;
|
||||||
|
size: number;
|
||||||
|
extension: string;
|
||||||
|
sr: number;
|
||||||
|
dfsId: number;
|
||||||
|
bitrate: number;
|
||||||
|
playTime: number;
|
||||||
|
volumeDelta: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Album {
|
||||||
|
name: string;
|
||||||
|
id: number;
|
||||||
|
type: string;
|
||||||
|
size: number;
|
||||||
|
picId: number;
|
||||||
|
blurPicUrl: string;
|
||||||
|
companyId: number;
|
||||||
|
pic: number;
|
||||||
|
picUrl: string;
|
||||||
|
publishTime: number;
|
||||||
|
description: string;
|
||||||
|
tags: string;
|
||||||
|
company: string;
|
||||||
|
briefDesc: string;
|
||||||
|
artist: Artist;
|
||||||
|
songs: any[];
|
||||||
|
alias: string[];
|
||||||
|
status: number;
|
||||||
|
copyrightId: number;
|
||||||
|
commentThreadId: string;
|
||||||
|
artists: Artist[];
|
||||||
|
subType: string;
|
||||||
|
transName?: any;
|
||||||
|
onSale: boolean;
|
||||||
|
mark: number;
|
||||||
|
picId_str: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Artist {
|
||||||
|
name: string;
|
||||||
|
id: number;
|
||||||
|
picId: number;
|
||||||
|
img1v1Id: number;
|
||||||
|
briefDesc: string;
|
||||||
|
picUrl: string;
|
||||||
|
img1v1Url: string;
|
||||||
|
albumSize: number;
|
||||||
|
alias: any[];
|
||||||
|
trans: string;
|
||||||
|
musicSize: number;
|
||||||
|
topicPerson: number;
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
export interface IPlayListSort {
|
||||||
|
code: number;
|
||||||
|
all: SortAll;
|
||||||
|
sub: SortAll[];
|
||||||
|
categories: SortCategories;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SortCategories {
|
||||||
|
"0": string;
|
||||||
|
"1": string;
|
||||||
|
"2": string;
|
||||||
|
"3": string;
|
||||||
|
"4": string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SortAll {
|
||||||
|
name: string;
|
||||||
|
resourceCount: number;
|
||||||
|
imgId: number;
|
||||||
|
imgUrl?: any;
|
||||||
|
type: number;
|
||||||
|
category: number;
|
||||||
|
resourceType: number;
|
||||||
|
hot: boolean;
|
||||||
|
activity: boolean;
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
export interface ISearchKeyword {
|
||||||
|
code: number;
|
||||||
|
message?: any;
|
||||||
|
data: SearchKeywordData;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SearchKeywordData {
|
||||||
|
showKeyword: string;
|
||||||
|
realkeyword: string;
|
||||||
|
searchType: number;
|
||||||
|
action: number;
|
||||||
|
alg: string;
|
||||||
|
gap: number;
|
||||||
|
source?: any;
|
||||||
|
bizQueryInfo: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
export interface IHotSinger {
|
||||||
|
code: number;
|
||||||
|
more: boolean;
|
||||||
|
artists: Artist[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Artist {
|
||||||
|
name: string;
|
||||||
|
id: number;
|
||||||
|
picId: number;
|
||||||
|
img1v1Id: number;
|
||||||
|
briefDesc: string;
|
||||||
|
picUrl: string;
|
||||||
|
img1v1Url: string;
|
||||||
|
albumSize: number;
|
||||||
|
alias: string[];
|
||||||
|
trans: string;
|
||||||
|
musicSize: number;
|
||||||
|
topicPerson: number;
|
||||||
|
showPrivateMsg?: any;
|
||||||
|
isSubed?: any;
|
||||||
|
accountId?: number;
|
||||||
|
picId_str?: string;
|
||||||
|
img1v1Id_str: string;
|
||||||
|
transNames?: string[];
|
||||||
|
followed: boolean;
|
||||||
|
mvSize?: any;
|
||||||
|
publishTime?: any;
|
||||||
|
identifyTag?: any;
|
||||||
|
alg?: any;
|
||||||
|
fansCount?: any;
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
const request = axios.create({
|
||||||
|
baseURL: "http://123.56.226.179:3000",
|
||||||
|
timeout: 10000,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default request;
|
||||||
+142
-8
@@ -1,22 +1,156 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<n-layout class="h-full bg-black" :native-scrollbar="false">
|
||||||
<div class="main-page">
|
<div class="main-page">
|
||||||
<!--音乐搜索框 -->
|
<!-- 推荐歌手 -->
|
||||||
<div class="search-box">
|
<div class="recommend-singer">
|
||||||
<div class="search-box-input">
|
<div class="recommend-singer-list">
|
||||||
<n-input size="large" round placeholder="搜索歌曲或歌手...">
|
<div
|
||||||
<template #prefix>
|
class="recommend-singer-item relative"
|
||||||
<i class="iconfont icon-search"></i>
|
v-for="(item,index) in hotSingerData?.artists"
|
||||||
</template>
|
:key="item.id"
|
||||||
</n-input>
|
>
|
||||||
|
<div :style="getStyle(item)" class="recommend-singer-item-bg"></div>
|
||||||
|
<div
|
||||||
|
class="recommend-singer-item-count p-2 text-base text-gray-200 z-10"
|
||||||
|
>{{ item.musicSize }}首</div>
|
||||||
|
<div class="recommend-singer-item-info z-10">
|
||||||
|
<div class="recommend-singer-item-info-play">
|
||||||
|
<i class="iconfont icon-playfill text-xl"></i>
|
||||||
|
</div>
|
||||||
|
<div class="ml-4">
|
||||||
|
<div class="recommend-singer-item-info-name">{{ item.name }}</div>
|
||||||
|
<div class="recommend-singer-item-info-name">{{ item.name }}</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="main-content">
|
||||||
|
<!-- 歌单分类列表 -->
|
||||||
|
<div class="play-list-type">
|
||||||
|
<div class="title">歌单分类</div>
|
||||||
|
<n-layout class="bg-black">
|
||||||
|
<template v-for="(item,index) in playlistCategory?.sub" :key="item.name">
|
||||||
|
<span
|
||||||
|
class="play-list-type-item animate__animated animate__bounceIn animate__repeat-1"
|
||||||
|
:style="getPlaylistTypeStyle(index <= 8 ? index : index - 8)"
|
||||||
|
v-if="isShowAllPlaylistCategory || index <= 8"
|
||||||
|
>{{ item.name }}</span>
|
||||||
|
</template>
|
||||||
|
<div
|
||||||
|
class="play-list-type-showall animate__animated animate__bounceIn animate__repeat-1"
|
||||||
|
:style="getPlaylistTypeStyle(!isShowAllPlaylistCategory ? 25 : playlistCategory?.sub.length + 30)"
|
||||||
|
@click="isShowAllPlaylistCategory = !isShowAllPlaylistCategory"
|
||||||
|
>{{ !isShowAllPlaylistCategory ? '显示全部' : '隐藏一些' }}</div>
|
||||||
|
</n-layout>
|
||||||
|
</div>
|
||||||
|
<div class="recommend-music">
|
||||||
|
<div class="title">本周最热音乐</div>
|
||||||
|
<n-layout class="bg-black">
|
||||||
|
<img v-for="item in recommendMusic?.result" :src="item.picUrl" width="100" height="100" />
|
||||||
|
</n-layout>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</n-layout>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { onMounted, ref } from "vue";
|
||||||
|
import { getHotSinger, getPlaylistCategory, getRecommendMusic } from "@/api/home"
|
||||||
|
import type { IHotSinger } from "@/type/singer";
|
||||||
|
import type { IPlayListSort } from "@/type/playlist";
|
||||||
|
import type { IRecommendMusic } from "@/type/music";
|
||||||
|
|
||||||
|
// 歌手信息
|
||||||
|
const hotSingerData = ref<IHotSinger>()
|
||||||
|
// 歌单分类
|
||||||
|
const playlistCategory = ref<IPlayListSort>()
|
||||||
|
// 是否显示全部歌单分类
|
||||||
|
const isShowAllPlaylistCategory = ref<boolean>(false)
|
||||||
|
// 推荐歌曲
|
||||||
|
const recommendMusic = ref<IRecommendMusic>()
|
||||||
|
|
||||||
|
|
||||||
|
// 设置歌手背景图片
|
||||||
|
const getStyle = (item: any) => {
|
||||||
|
return {
|
||||||
|
"background-image": "url(" + item.picUrl + ")"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 设置歌单分类样式
|
||||||
|
const getPlaylistTypeStyle = (index: number) => {
|
||||||
|
return {
|
||||||
|
"animation-delay": index * 25 + "ms"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//加载推荐歌手
|
||||||
|
const loadSingerList = async () => {
|
||||||
|
const { data } = await getHotSinger({ offset: 0, limit: 5 })
|
||||||
|
hotSingerData.value = data
|
||||||
|
}
|
||||||
|
// 加载歌单分类
|
||||||
|
const loadPlaylistCategory = async () => {
|
||||||
|
const { data } = await getPlaylistCategory()
|
||||||
|
playlistCategory.value = data
|
||||||
|
}
|
||||||
|
// 加载推荐歌曲
|
||||||
|
const loadRecommendMusic = async () => {
|
||||||
|
const { data } = await getRecommendMusic({ limit: 6 })
|
||||||
|
recommendMusic.value = data
|
||||||
|
}
|
||||||
|
|
||||||
|
// 页面初始化
|
||||||
|
onMounted(() => {
|
||||||
|
loadSingerList()
|
||||||
|
loadPlaylistCategory()
|
||||||
|
loadRecommendMusic()
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
.recommend-singer {
|
||||||
|
&-list {
|
||||||
|
@apply flex mt-5;
|
||||||
|
height: 350px;
|
||||||
|
}
|
||||||
|
&-item {
|
||||||
|
@apply flex-1 h-full rounded-3xl p-5 mr-5 flex flex-col justify-between;
|
||||||
|
&-bg {
|
||||||
|
@apply bg-gray-900 bg-no-repeat bg-cover bg-center rounded-3xl absolute w-full h-full top-0 left-0 z-0;
|
||||||
|
filter: brightness(80%);
|
||||||
|
}
|
||||||
|
&-info {
|
||||||
|
@apply flex items-center p-2;
|
||||||
|
&-play {
|
||||||
|
@apply w-12 h-12 bg-green-500 rounded-full flex justify-center items-center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-content {
|
||||||
|
@apply mt-6 flex;
|
||||||
|
.title {
|
||||||
|
@apply text-lg font-bold mb-4;
|
||||||
|
}
|
||||||
|
.play-list-type {
|
||||||
|
width: 250px;
|
||||||
|
@apply mr-6;
|
||||||
|
&-item,
|
||||||
|
&-showall {
|
||||||
|
@apply py-2 px-3 mr-3 mb-3 inline-block border border-gray-700 rounded-xl cursor-pointer hover:bg-green-600 transition;
|
||||||
|
background-color: #1a1a1a;
|
||||||
|
}
|
||||||
|
&-showall {
|
||||||
|
@apply block text-center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.recommend-music {
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
Reference in New Issue
Block a user