基本完成单曲搜索
This commit is contained in:
parent
03542b80a7
commit
82e56c3d51
40
src/App.vue
40
src/App.vue
@ -13,6 +13,7 @@ import SongStatus from "./views/common/SongStatus.vue";
|
|||||||
import SongProgress from "@/views/common/SongProgress.vue";
|
import SongProgress from "@/views/common/SongProgress.vue";
|
||||||
import PlayingList from "@/views/common/PlayingList.vue";
|
import PlayingList from "@/views/common/PlayingList.vue";
|
||||||
import ZPlayingList from "@/views/common/ZPlayingList.vue";
|
import ZPlayingList from "@/views/common/ZPlayingList.vue";
|
||||||
|
import Searching from "@/views/common/Searching.vue";
|
||||||
import SongDetail from "@/views/common/SongDetail.vue";
|
import SongDetail from "@/views/common/SongDetail.vue";
|
||||||
import pubsub from "pubsub-js";
|
import pubsub from "pubsub-js";
|
||||||
import {
|
import {
|
||||||
@ -47,6 +48,7 @@ store.commit("loadCaches");
|
|||||||
|
|
||||||
const showPlaying = ref(false); //是否显示播放列表
|
const showPlaying = ref(false); //是否显示播放列表
|
||||||
const showSongDetail = ref(false); //是否显示歌曲详细信息
|
const showSongDetail = ref(false); //是否显示歌曲详细信息
|
||||||
|
const showSearch = ref(false); //是否显示搜索
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
()=> store.state.showSongDetail,
|
()=> store.state.showSongDetail,
|
||||||
@ -78,6 +80,12 @@ const token = pubsub.subscribe("zp", (msg, data) => {
|
|||||||
case "zp.toggleSongDetail":
|
case "zp.toggleSongDetail":
|
||||||
showSongDetail.value = store.state.showSongDetail = !showSongDetail.value;
|
showSongDetail.value = store.state.showSongDetail = !showSongDetail.value;
|
||||||
break;
|
break;
|
||||||
|
case "zp.showSearch":
|
||||||
|
showSearch.value = true;
|
||||||
|
break;
|
||||||
|
case "zp.toggleSearch":
|
||||||
|
showSearch.value = !showSearch.value ;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -91,6 +99,7 @@ onUnmounted(() => {
|
|||||||
const wpEl = ref('')
|
const wpEl = ref('')
|
||||||
const hideWins = (e) => {
|
const hideWins = (e) => {
|
||||||
// console.log(e.clientX > 0,e, wpEl.value.clientWidth);
|
// console.log(e.clientX > 0,e, wpEl.value.clientWidth);
|
||||||
|
//显示当前播放
|
||||||
if (showPlaying.value
|
if (showPlaying.value
|
||||||
&& e.clientX > 0
|
&& e.clientX > 0
|
||||||
&& e.clientX < wpEl.value.clientWidth - 500
|
&& e.clientX < wpEl.value.clientWidth - 500
|
||||||
@ -99,6 +108,15 @@ const hideWins = (e) => {
|
|||||||
) {
|
) {
|
||||||
showPlaying.value = false;
|
showPlaying.value = false;
|
||||||
}
|
}
|
||||||
|
//显示搜索
|
||||||
|
if (showSearch.value
|
||||||
|
&& e.clientX > 0
|
||||||
|
&& e.clientX < wpEl.value.clientWidth - 360
|
||||||
|
&& e.clientY > 40
|
||||||
|
&& e.clientY < wpEl.value.clientHeight - 64
|
||||||
|
) {
|
||||||
|
showSearch.value = false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -144,6 +162,11 @@ const hideWins = (e) => {
|
|||||||
<ZPlayingList />
|
<ZPlayingList />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="wpSearch" v-show="showSearch">
|
||||||
|
<div id="search">
|
||||||
|
<Searching />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div id="footer">
|
<div id="footer">
|
||||||
<div id="songDetail"></div>
|
<div id="songDetail"></div>
|
||||||
<div id="songProgress">
|
<div id="songProgress">
|
||||||
@ -208,6 +231,7 @@ body {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
|
user-select: none;
|
||||||
#top {
|
#top {
|
||||||
height: 40px;
|
height: 40px;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -252,6 +276,22 @@ body {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#wpSearch{
|
||||||
|
#search{
|
||||||
|
position: absolute;
|
||||||
|
top: 40px;
|
||||||
|
right: 0;
|
||||||
|
bottom: 64px;
|
||||||
|
width: 360px;
|
||||||
|
background-color: #fff;
|
||||||
|
z-index: 2000;
|
||||||
|
border: #ddd solid 1px;
|
||||||
|
|
||||||
|
overflow-y: auto;
|
||||||
|
// padding: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#footer {
|
#footer {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
1
src/assets/svgs/SearchOutline.svg
Normal file
1
src/assets/svgs/SearchOutline.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512"><path d="M221.09 64a157.09 157.09 0 1 0 157.09 157.09A157.1 157.1 0 0 0 221.09 64z" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32"></path><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="32" d="M338.29 338.29L448 448"></path></svg>
|
After Width: | Height: | Size: 415 B |
332
src/components/Songlist.vue
Normal file
332
src/components/Songlist.vue
Normal file
@ -0,0 +1,332 @@
|
|||||||
|
<script setup>
|
||||||
|
import {
|
||||||
|
ref,
|
||||||
|
reactive,
|
||||||
|
h,
|
||||||
|
watch,
|
||||||
|
toRaw,
|
||||||
|
onMounted,
|
||||||
|
onUnmounted,
|
||||||
|
nextTick,
|
||||||
|
} from "vue";
|
||||||
|
import { RouterLink, useRoute, useRouter } from "vue-router";
|
||||||
|
import { useStore } from "vuex";
|
||||||
|
import {
|
||||||
|
NButton,
|
||||||
|
NButtonGroup,
|
||||||
|
NSpace,
|
||||||
|
NIcon,
|
||||||
|
NDropdown,
|
||||||
|
NMenu,
|
||||||
|
NLayout,
|
||||||
|
NLayoutHeader,
|
||||||
|
NLayoutFooter,
|
||||||
|
NLayoutContent,
|
||||||
|
NLayoutSider,
|
||||||
|
NTag,
|
||||||
|
NDataTable,
|
||||||
|
useMessage,
|
||||||
|
} from "naive-ui";
|
||||||
|
import Play from "@/assets/svgs/Play_.svg";
|
||||||
|
import Pause from "@/assets/svgs/Pause.svg";
|
||||||
|
import svgDots from "@/assets/svgs/Dots.svg";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
import "dayjs/locale/zh-cn";
|
||||||
|
import duration from "dayjs/plugin/duration";
|
||||||
|
import pubsub from "pubsub-js";
|
||||||
|
import ArtistsSpan from "@/components/ArtistsSpan.vue";
|
||||||
|
import AlbumSpan from "@/components/AlbumSpan.vue";
|
||||||
|
|
||||||
|
const store = useStore();
|
||||||
|
const router = useRouter();
|
||||||
|
dayjs.extend(duration);
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
songs: Array,
|
||||||
|
});
|
||||||
|
|
||||||
|
// const s = ref(props.songs)
|
||||||
|
// console.log(s.value.value);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="wp-list" ref="wpTable" v-if="false">
|
||||||
|
<div
|
||||||
|
class="tr"
|
||||||
|
v-for="(p, idx) in songs"
|
||||||
|
:key="idx"
|
||||||
|
draggable="true"
|
||||||
|
@dragstart="dragstart(idx)"
|
||||||
|
@dragenter="dragenter($event, idx)"
|
||||||
|
@dragover="dragover($event, idx)"
|
||||||
|
@drop="drop($event, idx)"
|
||||||
|
@dblclick="pubsub.publish('zp.play', { id: p.id, im: true })"
|
||||||
|
>
|
||||||
|
<div class="icon">
|
||||||
|
<NButton
|
||||||
|
v-show="p.id === store.state.settings.songId"
|
||||||
|
text
|
||||||
|
type="primary"
|
||||||
|
size="tiny"
|
||||||
|
>
|
||||||
|
<NIcon style="bottom: -1px; left: -2px; position: absolute">
|
||||||
|
<Play v-if="store.state.settings.playing"></Play>
|
||||||
|
<Pause v-else></Pause>
|
||||||
|
</NIcon>
|
||||||
|
</NButton>
|
||||||
|
</div>
|
||||||
|
<div class="name">
|
||||||
|
<span class="ntext">{{ p.name }}</span>
|
||||||
|
<span class="nm">
|
||||||
|
<n-dropdown
|
||||||
|
placement="right-start"
|
||||||
|
@select="handleSelect($event, p.id)"
|
||||||
|
trigger="click"
|
||||||
|
:show-arrow="true"
|
||||||
|
>
|
||||||
|
<NButton
|
||||||
|
class="mn"
|
||||||
|
text
|
||||||
|
type="primary"
|
||||||
|
style="font-size: 18px"
|
||||||
|
>
|
||||||
|
<NIcon>
|
||||||
|
<svg-dots />
|
||||||
|
</NIcon>
|
||||||
|
</NButton>
|
||||||
|
</n-dropdown>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="ar">
|
||||||
|
<ArtistsSpan :artists="p.artists" />
|
||||||
|
</div>
|
||||||
|
<div class="al">{{ p.album.name }}</div>
|
||||||
|
<div class="dt">
|
||||||
|
{{ dayjs.duration(p.duration).format("mm:ss") }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<table class="tbList">
|
||||||
|
<tr class="tr trh">
|
||||||
|
<td class="icon"></td>
|
||||||
|
<td class="name">音乐标题</td>
|
||||||
|
<td class="ar">歌手</td>
|
||||||
|
<td class="al">专辑</td>
|
||||||
|
<td class="dt">时长</td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
<tr
|
||||||
|
class="tr"
|
||||||
|
v-for="p in songs"
|
||||||
|
:key="p.id"
|
||||||
|
draggable="false"
|
||||||
|
@dblclick="pubsub.publish('zp.play', { id: p.id, im: true })"
|
||||||
|
>
|
||||||
|
<td class="icon">
|
||||||
|
<NButton
|
||||||
|
v-show="p.id === store.state.settings.songId"
|
||||||
|
text
|
||||||
|
type="primary"
|
||||||
|
size="tiny"
|
||||||
|
>
|
||||||
|
<NIcon style="bottom: -1px; left: -2px; position: absolute">
|
||||||
|
<Play v-if="store.state.settings.playing"></Play>
|
||||||
|
<Pause v-else></Pause>
|
||||||
|
</NIcon>
|
||||||
|
</NButton>
|
||||||
|
</td>
|
||||||
|
<td class="name">
|
||||||
|
<span class="ntext">{{ p.name }}</span>
|
||||||
|
<span class="nm">
|
||||||
|
<n-dropdown
|
||||||
|
placement="right-start"
|
||||||
|
@select="handleSelect($event, p.id)"
|
||||||
|
trigger="click"
|
||||||
|
:show-arrow="true"
|
||||||
|
>
|
||||||
|
<NButton
|
||||||
|
class="mn"
|
||||||
|
text
|
||||||
|
type="primary"
|
||||||
|
style="font-size: 18px"
|
||||||
|
>
|
||||||
|
<NIcon>
|
||||||
|
<svg-dots />
|
||||||
|
</NIcon>
|
||||||
|
</NButton>
|
||||||
|
</n-dropdown>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td class="ar"><ArtistsSpan :artists="p.artists" /></td>
|
||||||
|
<td class="al"><AlbumSpan :album="p.album" /></td>
|
||||||
|
<td class="dt">
|
||||||
|
{{ dayjs.duration(p.duration).format("mm:ss") }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "Songlist",
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
@import "@/assets/css/common.less";
|
||||||
|
.tbList {
|
||||||
|
border-spacing: 0;
|
||||||
|
border: 1px solid #eee;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 14px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
// table-layout: fixed;
|
||||||
|
user-select: none;
|
||||||
|
|
||||||
|
.trh{
|
||||||
|
background-color: #eee;
|
||||||
|
font-weight: 600;
|
||||||
|
td{
|
||||||
|
// background-color: red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tr {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
// line-height: 1.8;
|
||||||
|
|
||||||
|
&:nth-child(2n + 1):not(.trh) {
|
||||||
|
background-color: #f6f6f6;
|
||||||
|
}
|
||||||
|
td {
|
||||||
|
padding: 6px 6px;
|
||||||
|
// display: flex;
|
||||||
|
// align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #eee;
|
||||||
|
|
||||||
|
.name .mn {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
width: 20px;
|
||||||
|
}
|
||||||
|
.name {
|
||||||
|
flex: 3;
|
||||||
|
.text-el-line-normal();
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
.ntext {
|
||||||
|
.text-el-line-normal();
|
||||||
|
}
|
||||||
|
|
||||||
|
.mn {
|
||||||
|
flex: 1;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ar {
|
||||||
|
flex: 2;
|
||||||
|
.text-el-line-normal();
|
||||||
|
}
|
||||||
|
.ar,
|
||||||
|
.al,
|
||||||
|
.dt {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.al,
|
||||||
|
.dt {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
.al {
|
||||||
|
flex: 1;
|
||||||
|
.text-el-line-normal();
|
||||||
|
}
|
||||||
|
.dt {
|
||||||
|
width: 50px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
.wp-list {
|
||||||
|
// position: absolute;
|
||||||
|
// bottom: 0px;
|
||||||
|
// top: 80px;
|
||||||
|
// right: 0;
|
||||||
|
// left: 160px;
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
.tr {
|
||||||
|
display: flex;
|
||||||
|
font-size: 14px;
|
||||||
|
border-top: 1px #eee solid;
|
||||||
|
border-bottom: 1px #eee solid;
|
||||||
|
margin-bottom: -1px;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
padding: 4px 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:nth-child(2n + 1) {
|
||||||
|
background-color: #f6f6f6;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #eee;
|
||||||
|
|
||||||
|
.name .mn {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
padding-left: 10px;
|
||||||
|
width: 20px;
|
||||||
|
}
|
||||||
|
.name {
|
||||||
|
flex: 3;
|
||||||
|
.text-el-line();
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
.ntext {
|
||||||
|
.text-el-line();
|
||||||
|
}
|
||||||
|
|
||||||
|
.mn {
|
||||||
|
flex: 1;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ar {
|
||||||
|
width: 120px;
|
||||||
|
// flex: 2;
|
||||||
|
// color: #999;
|
||||||
|
margin-top: 1px;
|
||||||
|
font-size: 12px;
|
||||||
|
.text-el-line();
|
||||||
|
}
|
||||||
|
.al {
|
||||||
|
width: 80px;
|
||||||
|
// flex: 1;
|
||||||
|
margin-top: 1px;
|
||||||
|
color: #999;
|
||||||
|
font-size: 12px;
|
||||||
|
.text-el-line();
|
||||||
|
}
|
||||||
|
.dt {
|
||||||
|
margin-top: 1px;
|
||||||
|
color: #999;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
60
src/components/SongsList.vue
Normal file
60
src/components/SongsList.vue
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<script setup>
|
||||||
|
import {
|
||||||
|
ref,
|
||||||
|
reactive,
|
||||||
|
h,
|
||||||
|
watch,
|
||||||
|
toRaw,
|
||||||
|
onMounted,
|
||||||
|
onUnmounted,
|
||||||
|
nextTick,
|
||||||
|
} from "vue";
|
||||||
|
import { RouterLink, useRoute, useRouter } from "vue-router";
|
||||||
|
import { useStore } from "vuex";
|
||||||
|
import {
|
||||||
|
NButton,
|
||||||
|
NButtonGroup,
|
||||||
|
NSpace,
|
||||||
|
NIcon,
|
||||||
|
NDropdown,
|
||||||
|
NMenu,
|
||||||
|
NLayout,
|
||||||
|
NLayoutHeader,
|
||||||
|
NLayoutFooter,
|
||||||
|
NLayoutContent,
|
||||||
|
NLayoutSider,
|
||||||
|
NTag,
|
||||||
|
NDataTable,
|
||||||
|
useMessage,
|
||||||
|
} from "naive-ui";
|
||||||
|
import Play from "@/assets/svgs/Play_.svg";
|
||||||
|
import Pause from "@/assets/svgs/Pause.svg";
|
||||||
|
import svgDots from "@/assets/svgs/Dots.svg";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
import "dayjs/locale/zh-cn";
|
||||||
|
import duration from "dayjs/plugin/duration";
|
||||||
|
import pubsub from "pubsub-js";
|
||||||
|
import ArtistsSpan from "@/components/ArtistsSpan.vue";
|
||||||
|
|
||||||
|
const store = useStore();
|
||||||
|
const router = useRouter();
|
||||||
|
dayjs.extend(duration);
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
songs: Array,
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
{{songs}}
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
46
src/network/search.js
Normal file
46
src/network/search.js
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import {request} from './request'
|
||||||
|
|
||||||
|
// 搜索默认关键词
|
||||||
|
export function getDefault(){
|
||||||
|
return request({
|
||||||
|
url: '/search/default'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 热搜榜简略
|
||||||
|
export function getSearchHot(){
|
||||||
|
return request({
|
||||||
|
url: '/search/hot'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 热搜榜详情
|
||||||
|
export function getHotDetail(){
|
||||||
|
return request({
|
||||||
|
url: '/search/hot/detail'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索结果
|
||||||
|
export function searchResult(keywords, limit, offset, type){
|
||||||
|
return request({
|
||||||
|
url: '/search',
|
||||||
|
params: {
|
||||||
|
keywords,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
type
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索建议
|
||||||
|
export function searchSuggest(keywords, type){
|
||||||
|
return request({
|
||||||
|
url: '/search/suggest',
|
||||||
|
params: {
|
||||||
|
keywords,
|
||||||
|
type
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
@ -88,6 +88,15 @@ const routes = [
|
|||||||
keepAlive: true,
|
keepAlive: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/search/:type/:keywords",
|
||||||
|
name: "search",
|
||||||
|
component: ()=> import('@/views/SearchResult.vue'),
|
||||||
|
meta:{
|
||||||
|
keepAlive: false,
|
||||||
|
},
|
||||||
|
props: true,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "/friends",
|
path: "/friends",
|
||||||
name: "friends",
|
name: "friends",
|
||||||
|
@ -5,6 +5,7 @@ export default createStore({
|
|||||||
// appVersion: "0.0.1",
|
// appVersion: "0.0.1",
|
||||||
// debugStr: "测试debug字符",
|
// debugStr: "测试debug字符",
|
||||||
showSongDetail: false, //是否显示歌曲详情
|
showSongDetail: false, //是否显示歌曲详情
|
||||||
|
keywords: '', //查询关键字
|
||||||
settings: {
|
settings: {
|
||||||
currentRoute: "/discover/recommend", //当前路由
|
currentRoute: "/discover/recommend", //当前路由
|
||||||
songId: 0, //歌曲id
|
songId: 0, //歌曲id
|
||||||
@ -12,6 +13,7 @@ export default createStore({
|
|||||||
playMode: 0, //播放模式:0-3,顺序,循环,单曲,随机。
|
playMode: 0, //播放模式:0-3,顺序,循环,单曲,随机。
|
||||||
lastPlayed: [], //最近播放
|
lastPlayed: [], //最近播放
|
||||||
playingList: [], //当前播放
|
playingList: [], //当前播放
|
||||||
|
searchHistory: [], //搜索历史
|
||||||
},
|
},
|
||||||
caches: {},
|
caches: {},
|
||||||
theme: {
|
theme: {
|
||||||
|
157
src/views/SearchResult.vue
Normal file
157
src/views/SearchResult.vue
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
<script setup>
|
||||||
|
import { ref, onActivated, watch } from "vue";
|
||||||
|
import { searchResult } from "../network/search";
|
||||||
|
import Songlist from "../components/Songlist.vue";
|
||||||
|
import SongsList from "../components/SongsList.vue";
|
||||||
|
import { useStore } from 'vuex';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
type: String,
|
||||||
|
keywords: String,
|
||||||
|
});
|
||||||
|
|
||||||
|
const store = useStore()
|
||||||
|
|
||||||
|
onActivated(() => {});
|
||||||
|
|
||||||
|
const type = ref(props.type);
|
||||||
|
const keywords = ref(props.keywords);
|
||||||
|
const count = ref(0);
|
||||||
|
const things = ref("单曲");
|
||||||
|
const songs = ref([]);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => [props.type, props.keywords],
|
||||||
|
([t, k]) => {
|
||||||
|
search(t, k);
|
||||||
|
}
|
||||||
|
// { immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
const search = (t, k) => {
|
||||||
|
type.value = t;
|
||||||
|
keywords.value = k;
|
||||||
|
|
||||||
|
switch (t) {
|
||||||
|
case "1":
|
||||||
|
default:
|
||||||
|
type.value = "1";
|
||||||
|
things.value = "单曲";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keywords.value.length > 0) {
|
||||||
|
searchResult(k, 20, 0, t)
|
||||||
|
.then((res) => {
|
||||||
|
if (res.data.code == 200) {
|
||||||
|
if (type.value == 1) {
|
||||||
|
count.value = res.data.result.songCount;
|
||||||
|
songs.value = res.data.result.songs;
|
||||||
|
console.log(songs.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log("searchResult err ", err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const selStyle = (t) => {
|
||||||
|
if(t == type.value){
|
||||||
|
const {primaryColor} = store.state.theme.themeOverrides.common
|
||||||
|
return {
|
||||||
|
color: primaryColor,
|
||||||
|
borderBottom: 'solid 2px ' + primaryColor,
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="main-content">
|
||||||
|
<div class="lmt-width">
|
||||||
|
<div class="title">
|
||||||
|
{{ keywords }}
|
||||||
|
<span class="result">找到 {{ count }} {{ things }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tabs">
|
||||||
|
<div class="tab">
|
||||||
|
<div class="btns">
|
||||||
|
<span class="caption" :style="selStyle('1')">
|
||||||
|
单曲
|
||||||
|
</span>
|
||||||
|
<span class="caption" :style="selStyle('10')">
|
||||||
|
专辑
|
||||||
|
</span>
|
||||||
|
<span class="caption" :style="selStyle('100')">
|
||||||
|
歌手
|
||||||
|
</span>
|
||||||
|
<span class="caption" :style="selStyle('1000')">
|
||||||
|
歌单
|
||||||
|
</span>
|
||||||
|
<span class="caption" :style="selStyle('1009')">
|
||||||
|
电台
|
||||||
|
</span>
|
||||||
|
<span class="caption" :style="selStyle('1004')">
|
||||||
|
MV
|
||||||
|
</span>
|
||||||
|
<span class="caption" :style="selStyle('1014')">
|
||||||
|
视频
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="bt"></div>
|
||||||
|
</div>
|
||||||
|
<div class="panel" v-show="type == '1'">
|
||||||
|
<Songlist :songs="songs"></Songlist>
|
||||||
|
</div>
|
||||||
|
<div class="panel" v-show="type == '10'"></div>
|
||||||
|
<div class="panel" v-show="type == '100'"></div>
|
||||||
|
<div class="panel" v-show="type == '1000'"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
@import "@/assets/css/common.less";
|
||||||
|
|
||||||
|
.lmt-width {
|
||||||
|
padding: 0 12px;
|
||||||
|
.title {
|
||||||
|
font-size: 30px;
|
||||||
|
.result {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs {
|
||||||
|
.tab {
|
||||||
|
.btns {
|
||||||
|
font-size: 16px;
|
||||||
|
display: flex;
|
||||||
|
.caption {
|
||||||
|
padding: 6px 6px;
|
||||||
|
margin-right: 16px;
|
||||||
|
color: #666;
|
||||||
|
border-bottom: solid 2px #f0f0f0;
|
||||||
|
}
|
||||||
|
// .sel {
|
||||||
|
// color: red;
|
||||||
|
// border-bottom: solid 2px red;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
.bt{
|
||||||
|
margin-top: -2px;
|
||||||
|
height: 2px;
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,19 +1,63 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {NInput} from 'naive-ui'
|
import { NInput, NIcon } from "naive-ui";
|
||||||
|
import pubsub from "pubsub-js";
|
||||||
|
import { useRouter } from "vue-router";
|
||||||
|
import { useStore } from "vuex";
|
||||||
|
import { getHotDetail, searchSuggest } from "@/network/search.js";
|
||||||
|
import { ref } from "vue";
|
||||||
|
import SvgSearchOutline from "@/assets/svgs/SearchOutline.svg";
|
||||||
|
|
||||||
|
const store = useStore();
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const keywords = ref("");
|
||||||
|
const elSearch = ref(null);
|
||||||
|
|
||||||
|
const search = () => {
|
||||||
|
if (keywords.value.length > 0){
|
||||||
|
pubsub.publish("zp.toggleSearch");
|
||||||
|
// elSearch.value.blur()
|
||||||
|
router.push(`/search/1/${keywords.value}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInput = () => {
|
||||||
|
pubsub.publish('zp.showSearch');
|
||||||
|
pubsub.publish("zp.searchInput", keywords.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const result = ref({});
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div id="search">
|
<div id="search">
|
||||||
<n-input size="small" round placeholder="请搜索..." />
|
<n-input
|
||||||
|
ref="elSearch"
|
||||||
|
size="small"
|
||||||
|
round
|
||||||
|
placeholder="请搜索..."
|
||||||
|
clearable
|
||||||
|
@activate="
|
||||||
|
() => {
|
||||||
|
pubsub.publish('zp.showSearch');
|
||||||
|
}
|
||||||
|
"
|
||||||
|
v-model:value="keywords"
|
||||||
|
@keyup.enter="search"
|
||||||
|
@input="handleInput"
|
||||||
|
style="width: 190px"
|
||||||
|
>
|
||||||
|
<template #prefix>
|
||||||
|
<n-icon>
|
||||||
|
<SvgSearchOutline />
|
||||||
|
</n-icon>
|
||||||
|
</template>
|
||||||
|
</n-input>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {};
|
||||||
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style></style>
|
||||||
|
|
||||||
</style>
|
|
||||||
|
226
src/views/common/Searching.vue
Normal file
226
src/views/common/Searching.vue
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
<script setup>
|
||||||
|
import { useStore } from "vuex";
|
||||||
|
import { getHotDetail, searchSuggest } from "@/network/search.js";
|
||||||
|
import { ref, onUnmounted } from "vue";
|
||||||
|
import { NTag, NButton, NSpace } from "naive-ui";
|
||||||
|
import pubsub from "pubsub-js";
|
||||||
|
|
||||||
|
const store = useStore();
|
||||||
|
|
||||||
|
//#region 热搜
|
||||||
|
const hotSearch = ref([]);
|
||||||
|
hotSearch.value = store.getters.cache("hotSearch");
|
||||||
|
// if(store.getters.cache('topSongs'))
|
||||||
|
// {
|
||||||
|
// topSongs.value = store.getters.cache('topSongs')
|
||||||
|
// console.log('载入Caches');
|
||||||
|
// }
|
||||||
|
//最新音乐
|
||||||
|
getHotDetail()
|
||||||
|
.then((res) => {
|
||||||
|
if (res.data.code == 200) {
|
||||||
|
hotSearch.value = res.data.data;
|
||||||
|
store.commit("saveCaches", {
|
||||||
|
hotSearch: { data: hotSearch.value, time: Date.now() },
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
// console.log(hotSearch.value);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log("getHotDetail err", err);
|
||||||
|
});
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
const suggestResult = ref({});
|
||||||
|
const suggest = (keywords) => {
|
||||||
|
if (keywords == "") return;
|
||||||
|
searchSuggest(keywords)
|
||||||
|
.then((res) => {
|
||||||
|
suggestResult.value = res.data.result;
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log("suggest err", err);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const keywords = ref("");
|
||||||
|
const token = pubsub.subscribe("zp", (msg, data) => {
|
||||||
|
switch (msg) {
|
||||||
|
case "zp.searchInput":
|
||||||
|
keywords.value = data;
|
||||||
|
suggest(keywords.value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//卸载组件
|
||||||
|
onUnmounted(() => {
|
||||||
|
pubsub.unsubscribe(token);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="hot" v-if="keywords.length < 1">
|
||||||
|
<div
|
||||||
|
class="history"
|
||||||
|
v-if="store.state.settings.searchHistory?.length > 0"
|
||||||
|
>
|
||||||
|
<div class="caption">
|
||||||
|
<span class="txt">搜索历史</span>
|
||||||
|
<NButton round size="tiny" type="error">清除</NButton>
|
||||||
|
</div>
|
||||||
|
<NSpace class="h-list" :size="[6, 6]">
|
||||||
|
<NTag
|
||||||
|
v-for="h in store.state.settings.searchHistory"
|
||||||
|
closable
|
||||||
|
round
|
||||||
|
size="small"
|
||||||
|
type="primary"
|
||||||
|
>{{ h }}</NTag
|
||||||
|
>
|
||||||
|
</NSpace>
|
||||||
|
</div>
|
||||||
|
<div class="hot-search">
|
||||||
|
<div class="caption">热搜榜</div>
|
||||||
|
<div
|
||||||
|
class="hot-list"
|
||||||
|
v-for="(item, idx) in hotSearch"
|
||||||
|
key="idx"
|
||||||
|
>
|
||||||
|
<div class="idx" :class="{ idxHot: item.iconType == 1 }">
|
||||||
|
{{ idx + 1 }}
|
||||||
|
</div>
|
||||||
|
<div class="detail">
|
||||||
|
<div class="title">
|
||||||
|
<span class="word">{{ item.searchWord }}</span>
|
||||||
|
<span class="isHot" v-if="item.iconType == 1">HOT</span>
|
||||||
|
<span class="score">{{ item.score }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="content">{{ item.content }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="searching" v-else>
|
||||||
|
<div class="to-search">搜“{{ keywords }}”相关的结果 ></div>
|
||||||
|
<div class="suggest">
|
||||||
|
<div class="caption">单曲</div>
|
||||||
|
<div
|
||||||
|
class="list"
|
||||||
|
v-for="s in suggestResult.songs"
|
||||||
|
@click="() => pubsub.publish('zp.play', {id: s.id, im: true})"
|
||||||
|
>
|
||||||
|
{{ s.name }} -
|
||||||
|
<template v-for="(ar, idx) of s.artists" key="idx">
|
||||||
|
<span style="margin-right: 4px; cursor: pointer">{{
|
||||||
|
ar.name
|
||||||
|
}}</span>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
<div class="caption">歌手</div>
|
||||||
|
<div class="list" v-for="s in suggestResult.artists">
|
||||||
|
{{ s.name }}
|
||||||
|
</div>
|
||||||
|
<div class="caption">专辑</div>
|
||||||
|
<div class="list" v-for="s in suggestResult.albums">
|
||||||
|
{{ s.name }}
|
||||||
|
<template v-for="(ar, idx) of s.artists" key="idx">
|
||||||
|
<span style="margin-right: 4px; cursor: pointer">{{
|
||||||
|
ar.name
|
||||||
|
}}</span>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
<div class="caption">歌单</div>
|
||||||
|
<div class="list" v-for="s in suggestResult.albums">
|
||||||
|
{{ s.name }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
@import "@/assets/css/common.less";
|
||||||
|
.hot {
|
||||||
|
padding: 8px;
|
||||||
|
.history {
|
||||||
|
margin-bottom: 6px;
|
||||||
|
.caption {
|
||||||
|
display: flex;
|
||||||
|
padding-bottom: 4px;
|
||||||
|
.txt {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.h-list {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.hot-search {
|
||||||
|
.hot-list {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
color: #999;
|
||||||
|
.idx {
|
||||||
|
padding: 6px 12px;
|
||||||
|
width: 30px;
|
||||||
|
justify-items: end;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
.idxHot {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
.detail {
|
||||||
|
padding: 6px;
|
||||||
|
.title {
|
||||||
|
.text-el-line();
|
||||||
|
|
||||||
|
& > * {
|
||||||
|
margin-right: 6px;
|
||||||
|
}
|
||||||
|
.word {
|
||||||
|
color: #333;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.isHot {
|
||||||
|
font-size: 12px;
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
.score {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
font-size: 12px;
|
||||||
|
.text-el-line();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.searching {
|
||||||
|
padding: 8px;
|
||||||
|
|
||||||
|
.suggest {
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.8;
|
||||||
|
.caption {
|
||||||
|
color: #999;
|
||||||
|
.text-el-line();
|
||||||
|
}
|
||||||
|
.list {
|
||||||
|
padding-left: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
.text-el-line();
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #eee;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
Loading…
x
Reference in New Issue
Block a user