parent
affc7849a1
commit
853ae0bc64
@ -0,0 +1,494 @@
|
|||||||
|
<template>
|
||||||
|
<div class="search">
|
||||||
|
<div class="search-topside">
|
||||||
|
<span
|
||||||
|
><div class="dropdown">
|
||||||
|
<font class="dropbtn"
|
||||||
|
>QQ音乐 <svg-icon icon-class="arrow-down"
|
||||||
|
/></font>
|
||||||
|
<div class="dropdown-content"> </div>
|
||||||
|
</div>
|
||||||
|
搜索
|
||||||
|
<div class="dropdown">
|
||||||
|
<font class="dropbtn"
|
||||||
|
>{{ typeNameTable[type] }} <svg-icon icon-class="arrow-down"
|
||||||
|
/></font>
|
||||||
|
<div class="dropdown-content">
|
||||||
|
<button
|
||||||
|
v-for="(val, key, i) in typeNameTable"
|
||||||
|
:key="{ val: val, i: i }"
|
||||||
|
@click="tranSearchType(key)"
|
||||||
|
>{{ typeNameTable[key] }}</button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div></span
|
||||||
|
>
|
||||||
|
<div class="searchKeywords">"{{ keywords }}"</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="type === 'tracks'">
|
||||||
|
<TrackList
|
||||||
|
:tracks="result"
|
||||||
|
type="playlist"
|
||||||
|
:max-size="100"
|
||||||
|
:other-server-access="false"
|
||||||
|
dbclick-track-func="none"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div v-if="type === 'playlists'">
|
||||||
|
<CoverRow
|
||||||
|
type="playlist"
|
||||||
|
:click-cover-to-play-fun="playThisListByTrack"
|
||||||
|
:items="result"
|
||||||
|
sub-text="title"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="load-more">
|
||||||
|
<ButtonTwoTone
|
||||||
|
v-show="hasMore"
|
||||||
|
color="grey"
|
||||||
|
@click.native="fetchData(true)"
|
||||||
|
>{{ $t('explore.loadMore') }}</ButtonTwoTone
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { getTrackDetail } from '@/api/track';
|
||||||
|
import { getPlaylistDetail } from '@/api/playlist';
|
||||||
|
import locale from '@/locale';
|
||||||
|
import { mapState, mapActions } from 'vuex';
|
||||||
|
import { camelCase } from 'change-case';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
import TrackList from '@/components/TrackList.vue';
|
||||||
|
import CoverRow from '@/components/CoverRow.vue';
|
||||||
|
import ButtonTwoTone from '@/components/ButtonTwoTone.vue';
|
||||||
|
export default {
|
||||||
|
name: 'Search',
|
||||||
|
components: {
|
||||||
|
TrackList,
|
||||||
|
CoverRow,
|
||||||
|
ButtonTwoTone,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return { show: false, result: [], hasMore: true, curpage: 1 };
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(['player']),
|
||||||
|
keywords() {
|
||||||
|
return this.$route.query.keywords;
|
||||||
|
},
|
||||||
|
type() {
|
||||||
|
return camelCase(this.$route.query.type || 'tracks');
|
||||||
|
},
|
||||||
|
typeNameTable() {
|
||||||
|
return {
|
||||||
|
musicVideos: locale.t('search.mv'),
|
||||||
|
tracks: locale.t('search.song'),
|
||||||
|
albums: locale.t('search.album'),
|
||||||
|
artists: locale.t('search.artist'),
|
||||||
|
playlists: locale.t('search.playlist'),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
$route: {
|
||||||
|
immediate: true,
|
||||||
|
handler() {
|
||||||
|
this.fetchData();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions(['showToast']),
|
||||||
|
playThisListByTrack(id) {
|
||||||
|
this.showToast('正在进行其他平台播放');
|
||||||
|
getPlaylistDetail(id, true, this.$route.query.server).then(data => {
|
||||||
|
console.log(data);
|
||||||
|
let playlist = data.playlist;
|
||||||
|
let tracks = playlist.tracks.filter(_track => {
|
||||||
|
return _track.playable == 1;
|
||||||
|
});
|
||||||
|
this.player.replacePlaylist(tracks, tracks[0], 'artist', tracks[0]);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
tranSearchType(type) {
|
||||||
|
this.$router.replace({ query: { ...this.$route.query, type } });
|
||||||
|
},
|
||||||
|
playTrack(id) {
|
||||||
|
this.player._replaceCurrentTrackByTrack(id, true);
|
||||||
|
},
|
||||||
|
formatTime(times) {
|
||||||
|
let t = '';
|
||||||
|
times /= 1000;
|
||||||
|
if (times > -1) {
|
||||||
|
var min = Math.floor(times / 60) % 60;
|
||||||
|
var sec = times % 60;
|
||||||
|
t += min + ':';
|
||||||
|
if (sec < 10) {
|
||||||
|
t += '0';
|
||||||
|
}
|
||||||
|
t += sec.toFixed(2);
|
||||||
|
}
|
||||||
|
t = t.substring(0, t.length - 3);
|
||||||
|
return t;
|
||||||
|
},
|
||||||
|
fetchData(isPush = false) {
|
||||||
|
const typeTable = {
|
||||||
|
musicVideos: 1004,
|
||||||
|
tracks: 1,
|
||||||
|
albums: 10,
|
||||||
|
artists: 100,
|
||||||
|
playlists: 1000,
|
||||||
|
};
|
||||||
|
request({
|
||||||
|
url: '/search',
|
||||||
|
method: 'get',
|
||||||
|
params: {
|
||||||
|
curpage: isPush ? (this.curpage += 1) : (this.curpage = 1),
|
||||||
|
...this.$route.query,
|
||||||
|
keywords: this.keywords || '群青',
|
||||||
|
type: typeTable[this.type],
|
||||||
|
},
|
||||||
|
}).then(result => {
|
||||||
|
result = result.result;
|
||||||
|
this.hasMore = result.hasMore ?? true;
|
||||||
|
switch (this.type) {
|
||||||
|
case 'musicVideos':
|
||||||
|
if (isPush) this.result.push(...result.mvs);
|
||||||
|
else this.result = result.mvs;
|
||||||
|
if (result.mvCount <= this.result.length) {
|
||||||
|
this.hasMore = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'artists':
|
||||||
|
if (isPush) this.result.push(...result.artists);
|
||||||
|
else this.result = result.artists;
|
||||||
|
break;
|
||||||
|
case 'albums':
|
||||||
|
if (isPush) this.result.push(...result.albums);
|
||||||
|
else this.result = result.albums;
|
||||||
|
if (result.albumCount <= this.result.length) {
|
||||||
|
this.hasMore = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'tracks':
|
||||||
|
if (isPush) this.result.push(...result.songs);
|
||||||
|
else this.result = result.songs;
|
||||||
|
break;
|
||||||
|
case 'playlists':
|
||||||
|
if (isPush) this.result.push(...result.playlists);
|
||||||
|
else this.result = result.playlists;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getTracksDetail() {
|
||||||
|
const trackIDs = this.result.map(t => t.id);
|
||||||
|
if (trackIDs.length === 0) return;
|
||||||
|
getTrackDetail(trackIDs.join(',')).then(result => {
|
||||||
|
this.result = result.songs;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.search-topside {
|
||||||
|
position: relative;
|
||||||
|
color: var(--color-text);
|
||||||
|
font-size: 1.4em;
|
||||||
|
margin: 1em auto;
|
||||||
|
.searchKeywords {
|
||||||
|
display: inline-block;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (max-width: 576px) {
|
||||||
|
.searchKeywords {
|
||||||
|
display: block !important;
|
||||||
|
margin: 15px auto !important;
|
||||||
|
text-align: center !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.dropdown {
|
||||||
|
line-height: 100%;
|
||||||
|
height: 100%;
|
||||||
|
font-size: 0.9em;
|
||||||
|
padding: 10px;
|
||||||
|
margin: 0 10px;
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
background-color: var(--color-primary-bg-for-transparent);
|
||||||
|
color: var(--color-primary);
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: 5px;
|
||||||
|
svg {
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.dropdown-content {
|
||||||
|
font-size: 1em;
|
||||||
|
opacity: 0;
|
||||||
|
transition: 0.5s;
|
||||||
|
position: absolute;
|
||||||
|
background-color: #ffffff;
|
||||||
|
width: 100%;
|
||||||
|
padding: 8px;
|
||||||
|
right: 0;
|
||||||
|
border-radius: 12px;
|
||||||
|
z-index: 55;
|
||||||
|
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
|
||||||
|
button {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
width: 100%;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 10px 12px;
|
||||||
|
border-radius: 8px;
|
||||||
|
cursor: default;
|
||||||
|
color: var(--color-text);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
&:hover {
|
||||||
|
color: var(--color-primary);
|
||||||
|
background: var(--color-primary-bg-for-transparent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.dropdown:hover,
|
||||||
|
.dropdown:focus {
|
||||||
|
.dropdown-content {
|
||||||
|
opacity: 1;
|
||||||
|
transition: 0.5s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
padding: 8px;
|
||||||
|
background: transparent;
|
||||||
|
border-radius: 25%;
|
||||||
|
transition: transform 0.2s;
|
||||||
|
.svg-icon {
|
||||||
|
height: 16px;
|
||||||
|
width: 16px;
|
||||||
|
color: var(--color-primary);
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
transform: scale(1.12);
|
||||||
|
}
|
||||||
|
&:active {
|
||||||
|
transform: scale(0.96);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.track {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 8px;
|
||||||
|
border-radius: 12px;
|
||||||
|
user-select: none;
|
||||||
|
|
||||||
|
.no {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin: 0 20px 0 10px;
|
||||||
|
width: 12px;
|
||||||
|
color: var(--color-text);
|
||||||
|
cursor: default;
|
||||||
|
span {
|
||||||
|
opacity: 0.58;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.explicit-symbol {
|
||||||
|
opacity: 0.28;
|
||||||
|
color: var(--color-text);
|
||||||
|
.svg-icon {
|
||||||
|
margin-bottom: -3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.explicit-symbol.before-artist {
|
||||||
|
.svg-icon {
|
||||||
|
margin-bottom: -3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
border-radius: 8px;
|
||||||
|
height: 46px;
|
||||||
|
width: 46px;
|
||||||
|
margin-right: 14px;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.04);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
img.hover {
|
||||||
|
filter: drop-shadow(100 200 0 black);
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-and-artist {
|
||||||
|
min-width: 120px;
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-text);
|
||||||
|
cursor: default;
|
||||||
|
padding-right: 12px;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
word-break: break-all;
|
||||||
|
.featured {
|
||||||
|
margin-right: 2px;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 14px;
|
||||||
|
opacity: 0.72;
|
||||||
|
}
|
||||||
|
.sub-title {
|
||||||
|
color: #7a7a7a;
|
||||||
|
opacity: 0.7;
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.artist {
|
||||||
|
margin-top: 2px;
|
||||||
|
font-size: 13px;
|
||||||
|
opacity: 0.68;
|
||||||
|
color: var(--color-text);
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
a {
|
||||||
|
span {
|
||||||
|
margin-right: 3px;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.album {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
font-size: 16px;
|
||||||
|
min-width: 80px;
|
||||||
|
opacity: 0.88;
|
||||||
|
color: var(--color-text);
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.time,
|
||||||
|
.count {
|
||||||
|
font-size: 16px;
|
||||||
|
width: 50px;
|
||||||
|
cursor: default;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
margin-right: 10px;
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
opacity: 0.88;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
.count {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 22px;
|
||||||
|
line-height: 22px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.track.focus {
|
||||||
|
transition: all 0.3s;
|
||||||
|
background: var(--color-secondary-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.track.disable {
|
||||||
|
img {
|
||||||
|
filter: grayscale(1) opacity(0.6);
|
||||||
|
}
|
||||||
|
.title,
|
||||||
|
.artist,
|
||||||
|
.album,
|
||||||
|
.time,
|
||||||
|
.no,
|
||||||
|
.featured {
|
||||||
|
opacity: 0.28 !important;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.track.tracklist {
|
||||||
|
img {
|
||||||
|
height: 36px;
|
||||||
|
width: 36px;
|
||||||
|
border-radius: 6px;
|
||||||
|
margin-right: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
.artist {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.load-more {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.track.album {
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
width: 80px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.track.playing {
|
||||||
|
background: var(--color-primary-bg);
|
||||||
|
color: var(--color-primary);
|
||||||
|
.title,
|
||||||
|
.album,
|
||||||
|
.time,
|
||||||
|
.title-and-artist .sub-title {
|
||||||
|
color: var(--color-primary);
|
||||||
|
}
|
||||||
|
.title .featured,
|
||||||
|
.artist,
|
||||||
|
.explicit-symbol,
|
||||||
|
.count {
|
||||||
|
color: var(--color-primary);
|
||||||
|
opacity: 0.88;
|
||||||
|
}
|
||||||
|
.no span {
|
||||||
|
color: var(--color-primary);
|
||||||
|
opacity: 0.78;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
Loading…
Reference in new issue