dev...
@ -11,13 +11,20 @@ let p = require('path').join(NMApiPath + '/node_modules');
|
|||||||
require('module').globalPaths.unshift(p); //加入到module的路径列表
|
require('module').globalPaths.unshift(p); //加入到module的路径列表
|
||||||
|
|
||||||
console.log(process.resourcesPath, NMApiPath)
|
console.log(process.resourcesPath, NMApiPath)
|
||||||
if(!isDev)const svc = require(NMApiPath + '/app.js')
|
let svc
|
||||||
|
if(!isDev)svc = require(NMApiPath + '/app.js')
|
||||||
|
|
||||||
function createWindow() {
|
function createWindow() {
|
||||||
// Create the browser window.
|
// Create the browser window.
|
||||||
const mainWindow = new BrowserWindow({
|
const mainWindow = new BrowserWindow({
|
||||||
width: 800,
|
width: 800,
|
||||||
height: 600,
|
height: 600,
|
||||||
|
minWidth: 800,
|
||||||
|
minHeight: 600,
|
||||||
|
maxWidth: 1000,
|
||||||
|
maxHeight: 800,
|
||||||
|
maximizable: false,
|
||||||
|
minimizable: false,
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
preload: path.join(__dirname, 'preload.js'),
|
preload: path.join(__dirname, 'preload.js'),
|
||||||
nodeIntegration: true,
|
nodeIntegration: true,
|
||||||
|
73
src/App.vue
@ -1,5 +1,5 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { h, ref, onMounted, onUnmounted, toRaw} from "vue";
|
import { h, ref, onMounted, onUnmounted, toRaw, watch } from "vue";
|
||||||
import { useStore } from "vuex";
|
import { useStore } from "vuex";
|
||||||
import styled from "vue3-styled-components";
|
import styled from "vue3-styled-components";
|
||||||
import Nav from "@/views/common/Nav.vue";
|
import Nav from "@/views/common/Nav.vue";
|
||||||
@ -13,8 +13,13 @@ 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 SongDetail from "@/views/common/SongDetail.vue";
|
||||||
import pubsub from "pubsub-js";
|
import pubsub from "pubsub-js";
|
||||||
import { NConfigProvider, darkTheme, NMessageProvider } from "naive-ui";
|
import {
|
||||||
|
NConfigProvider,
|
||||||
|
darkTheme,
|
||||||
|
NMessageProvider,
|
||||||
|
} from "naive-ui";
|
||||||
import router from "./router";
|
import router from "./router";
|
||||||
// import { CloudCircleSharp } from "@vicons/ionicons5";
|
// import { CloudCircleSharp } from "@vicons/ionicons5";
|
||||||
|
|
||||||
@ -41,11 +46,20 @@ store.commit("loadCaches");
|
|||||||
// router.replace('/discover/recommend')
|
// router.replace('/discover/recommend')
|
||||||
|
|
||||||
const showPlaying = ref(false); //是否显示播放列表
|
const showPlaying = ref(false); //是否显示播放列表
|
||||||
|
const showSongDetail = ref(false); //是否显示歌曲详细信息
|
||||||
|
|
||||||
|
watch(
|
||||||
|
()=> store.state.showSongDetail,
|
||||||
|
()=>{
|
||||||
|
showSongDetail.value = toRaw(store.state.showSongDetail)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
//处理route消息
|
//处理route消息
|
||||||
const routeToken = pubsub.subscribe(
|
const routeToken = pubsub.subscribe("router", (msg, data) => {
|
||||||
"router",
|
|
||||||
(msg, data) => {
|
|
||||||
switch (msg) {
|
switch (msg) {
|
||||||
case "router.beforeEach":
|
case "router.beforeEach":
|
||||||
case "router.afterEach":
|
case "router.afterEach":
|
||||||
@ -54,14 +68,16 @@ const routeToken = pubsub.subscribe(
|
|||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
const token = pubsub.subscribe("zp", (msg, data) => {
|
const token = pubsub.subscribe("zp", (msg, data) => {
|
||||||
switch (msg) {
|
switch (msg) {
|
||||||
case "zp.togglePlaying":
|
case "zp.togglePlaying":
|
||||||
showPlaying.value = !showPlaying.value;
|
showPlaying.value = !showPlaying.value;
|
||||||
break;
|
break;
|
||||||
|
case "zp.toggleSongDetail":
|
||||||
|
showSongDetail.value = store.state.showSongDetail = !showSongDetail.value;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -70,6 +86,20 @@ onUnmounted(() => {
|
|||||||
pubsub.unsubscribe(routeToken);
|
pubsub.unsubscribe(routeToken);
|
||||||
pubsub.unsubscribe(token);
|
pubsub.unsubscribe(token);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const c = (item) => {
|
||||||
|
return (
|
||||||
|
item.id == "playingList" ||
|
||||||
|
item.id == "top" ||
|
||||||
|
item.id == "footer"
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const hideWins = (e) => {
|
||||||
|
if (showPlaying.value && e.path.findIndex(c) < 0) {
|
||||||
|
showPlaying.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -77,7 +107,7 @@ onUnmounted(() => {
|
|||||||
:theme-overrides="store.state.theme.themeOverrides"
|
:theme-overrides="store.state.theme.themeOverrides"
|
||||||
>
|
>
|
||||||
<n-message-provider>
|
<n-message-provider>
|
||||||
<div id="wp">
|
<div id="wp" @click="hideWins">
|
||||||
<!-- <NThemeEditor/> -->
|
<!-- <NThemeEditor/> -->
|
||||||
<div id="top">
|
<div id="top">
|
||||||
<Nav></Nav>
|
<Nav></Nav>
|
||||||
@ -89,7 +119,6 @@ onUnmounted(() => {
|
|||||||
<div id="side">
|
<div id="side">
|
||||||
<!-- <Personal></Personal> -->
|
<!-- <Personal></Personal> -->
|
||||||
<MainMenu></MainMenu>
|
<MainMenu></MainMenu>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div id="main">
|
<div id="main">
|
||||||
<router-view v-slot="{ Component, route }">
|
<router-view v-slot="{ Component, route }">
|
||||||
@ -107,13 +136,11 @@ onUnmounted(() => {
|
|||||||
</router-view> -->
|
</router-view> -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div id="wpSongDetail" v-show="showSongDetail">
|
||||||
id="wpPlayingList"
|
<SongDetail/>
|
||||||
v-show="showPlaying"
|
</div>
|
||||||
@click.self="showPlaying = false"
|
<div id="wpPlayingList" v-show="showPlaying">
|
||||||
>
|
|
||||||
<div id="playingList">
|
<div id="playingList">
|
||||||
<!-- <PlayingList /> -->
|
|
||||||
<ZPlayingList />
|
<ZPlayingList />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -155,8 +182,7 @@ body {
|
|||||||
margin-top: -44px;
|
margin-top: -44px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
||||||
.zm-top-menu.n-menu.n-menu--horizontal
|
.zm-top-menu.n-menu.n-menu--horizontal .n-menu-item-content {
|
||||||
.n-menu-item-content {
|
|
||||||
padding: 0 12px;
|
padding: 0 12px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -200,13 +226,16 @@ body {
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
padding: 6px;
|
padding: 6px;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
#wpSongDetail {
|
||||||
|
|
||||||
}
|
}
|
||||||
#wpPlayingList {
|
#wpPlayingList {
|
||||||
position: absolute;
|
// position: absolute;
|
||||||
left: 0;
|
// left: 0;
|
||||||
top: 0;
|
// top: 0;
|
||||||
right: 0;
|
// right: 0;
|
||||||
bottom: 0;
|
// bottom: 0;
|
||||||
|
|
||||||
#playingList {
|
#playingList {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
BIN
src/assets/images/disk.png
Normal file
After Width: | Height: | Size: 164 KiB |
BIN
src/assets/images/needle.png
Normal file
After Width: | Height: | Size: 15 KiB |
1
src/assets/svgs/ArrowMaximize24Regular.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 24 24"><g fill="none"><path d="M12.748 3.001h7.554l.1.014l.099.028l.061.026a.72.72 0 0 1 .218.15l.04.044l.061.082l.037.065l.039.09l.02.064l.013.064l.009.093v7.534a.75.75 0 0 1-1.493.102l-.006-.102l-.001-5.696l-13.94 13.945h5.69a.75.75 0 0 1 .744.65l.007.1a.75.75 0 0 1-.649.744l-.101.007H3.714L3.684 21a.705.705 0 0 1-.187-.04l-.09-.038l-.018-.01a.746.746 0 0 1-.384-.553l-.007-.105V12.75a.75.75 0 0 1 1.493-.102l.007.102v5.692L18.438 4.5l-5.69.001a.75.75 0 0 1-.743-.648l-.007-.102a.75.75 0 0 1 .648-.743L12.748 3z" fill="currentColor"></path></g></svg>
|
After Width: | Height: | Size: 650 B |
1
src/assets/svgs/ArrowMaximizeVertical24Regular.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 24 24"><g fill="none"><path d="M13.72 5.78a.75.75 0 1 0 1.06-1.06l-2.5-2.5a.75.75 0 0 0-1.06 0l-2.5 2.5a.75.75 0 0 0 1.06 1.06L11 4.56v4.19a.75.75 0 0 0 1.5 0V4.56l1.22 1.22z" fill="currentColor"></path><path d="M4 11.75a.75.75 0 0 1 .75-.75h14.5a.75.75 0 0 1 0 1.5H4.75a.75.75 0 0 1-.75-.75z" fill="currentColor"></path><path d="M12.5 14.75a.75.75 0 0 0-1.5 0v4.69l-1.22-1.22a.75.75 0 0 0-1.06 1.06l2.5 2.5a.75.75 0 0 0 1.06 0l2.5-2.5a.75.75 0 1 0-1.06-1.06l-1.22 1.22v-4.69z" fill="currentColor"></path></g></svg>
|
After Width: | Height: | Size: 611 B |
1
src/assets/svgs/ArrowMinimize24Regular.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 24 24"><g fill="none"><path d="M21.778 2.223a.75.75 0 0 1 .072.976l-.072.084l-6.223 6.224h5.693a.75.75 0 0 1 .743.65l.007.1a.75.75 0 0 1-.649.744l-.101.007l-7.55-.002l-.016-.002a.727.727 0 0 1-.195-.042l-.098-.046a.747.747 0 0 1-.386-.553l-.007-.105V2.754a.75.75 0 0 1 1.493-.102l.007.102v5.69l6.222-6.221a.749.749 0 0 1 1.06 0zM11.003 13.755v7.504a.75.75 0 0 1-1.494.102l-.007-.102v-5.695L3.28 21.78a.75.75 0 0 1-1.133-.977l.073-.084l6.22-6.214H2.751a.75.75 0 0 1-.743-.648L2 13.755a.75.75 0 0 1 .75-.75l7.554.002l.074.009l.097.023l.053.019l.086.04l.089.058a.761.761 0 0 1 .148.148l.066.106l.041.094l.022.07l.01.055l.007.058v-.008l.005.076z" fill="currentColor"></path></g></svg>
|
After Width: | Height: | Size: 776 B |
1
src/assets/svgs/ArrowMinimizeVertical24Regular.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 24 24"><g fill="none"><path d="M11.75 2a.75.75 0 0 1 .75.75v4.19l1.22-1.22a.75.75 0 1 1 1.06 1.06l-2.5 2.5a.75.75 0 0 1-1.06 0l-2.5-2.5a.75.75 0 0 1 1.06-1.06L11 6.94V2.75a.75.75 0 0 1 .75-.75zM4 11.75a.75.75 0 0 1 .75-.75h14.5a.75.75 0 0 1 0 1.5H4.75a.75.75 0 0 1-.75-.75zm9.72 6.03a.75.75 0 1 0 1.06-1.06l-2.5-2.5a.75.75 0 0 0-1.06 0l-2.5 2.5a.75.75 0 1 0 1.06 1.06L11 16.56v4.69a.75.75 0 0 0 1.5 0v-4.69l1.22 1.22z" fill="currentColor"></path></g></svg>
|
After Width: | Height: | Size: 552 B |
1
src/assets/svgs/ChevronDown.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 fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="48" d="M112 184l144 144l144-144"></path></svg>
|
After Width: | Height: | Size: 252 B |
1
src/assets/svgs/ChevronUp.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 fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="48" d="M112 328l144-144l144 144"></path></svg>
|
After Width: | Height: | Size: 252 B |
@ -4,6 +4,7 @@ export default createStore({
|
|||||||
state: {
|
state: {
|
||||||
// appVersion: "0.0.1",
|
// appVersion: "0.0.1",
|
||||||
// debugStr: "测试debug字符",
|
// debugStr: "测试debug字符",
|
||||||
|
showSongDetail: false, //是否显示歌曲详情
|
||||||
settings: {
|
settings: {
|
||||||
currentRoute: "/discover/recommend", //当前路由
|
currentRoute: "/discover/recommend", //当前路由
|
||||||
songId: 0, //歌曲id
|
songId: 0, //歌曲id
|
||||||
@ -11,8 +12,6 @@ export default createStore({
|
|||||||
playMode: 0, //播放模式:0-3,顺序,循环,单曲,随机。
|
playMode: 0, //播放模式:0-3,顺序,循环,单曲,随机。
|
||||||
lastPlayed: [], //最近播放
|
lastPlayed: [], //最近播放
|
||||||
playingList: [], //当前播放
|
playingList: [], //当前播放
|
||||||
tArr: [], //测试数组
|
|
||||||
ts: "", //测试字符
|
|
||||||
},
|
},
|
||||||
caches: {},
|
caches: {},
|
||||||
theme: {
|
theme: {
|
||||||
|
177
src/views/common/SongDetail.vue
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
<script setup>
|
||||||
|
import { ref, onUnmounted, watch } from "vue";
|
||||||
|
import { NButton, NIcon } from "naive-ui";
|
||||||
|
import { useStore } from "vuex";
|
||||||
|
import svgChevrongDown from "@/assets/svgs/ChevronDown.svg";
|
||||||
|
import pubsub from "pubsub-js";
|
||||||
|
|
||||||
|
const store = useStore();
|
||||||
|
|
||||||
|
const songInfo = ref(null);
|
||||||
|
const lyric = ref(null);
|
||||||
|
const coverAngle = ref(0);
|
||||||
|
|
||||||
|
let interval;
|
||||||
|
watch(
|
||||||
|
() => store.state.settings.playing,
|
||||||
|
(val) => {
|
||||||
|
if(val){
|
||||||
|
interval = setInterval(() => {
|
||||||
|
coverAngle.value += .5
|
||||||
|
}, 100);
|
||||||
|
} else {
|
||||||
|
clearInterval(interval)
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
{immediate: true}
|
||||||
|
);
|
||||||
|
|
||||||
|
//#region 处理消息订阅
|
||||||
|
|
||||||
|
const token = pubsub.subscribe("zp", (msg, data) => {
|
||||||
|
switch (msg) {
|
||||||
|
case "zp.songInfo":
|
||||||
|
console.log("SongDetail: 收到歌曲详细信息。", data);
|
||||||
|
songInfo.value = data;
|
||||||
|
break;
|
||||||
|
case "zp.lyric":
|
||||||
|
lyric.value = data;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
//卸载组件
|
||||||
|
onUnmounted(() => {
|
||||||
|
pubsub.unsubscribe(token);
|
||||||
|
});
|
||||||
|
//#endregion
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div id="sdTitle">
|
||||||
|
<n-button
|
||||||
|
circle
|
||||||
|
size="small"
|
||||||
|
@click="pubsub.publish('zp.toggleSongDetail')"
|
||||||
|
>
|
||||||
|
<template #icon>
|
||||||
|
<n-icon>
|
||||||
|
<svgChevrongDown />
|
||||||
|
</n-icon>
|
||||||
|
</template>
|
||||||
|
</n-button>
|
||||||
|
</div>
|
||||||
|
<div id="sdContent" v-if="songInfo">
|
||||||
|
<div class="detail">
|
||||||
|
<div class="disk">
|
||||||
|
<div class="styli">
|
||||||
|
<img
|
||||||
|
src="@/assets/images/needle.png"
|
||||||
|
:class="{ playing: store.state.settings.playing }"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="bg">
|
||||||
|
<img class="disk" src="@/assets/images/disk.png" />
|
||||||
|
<img
|
||||||
|
class="cover"
|
||||||
|
:src="songInfo.album.picUrl"
|
||||||
|
:style="{ transform: 'rotateZ(' + coverAngle + 'deg)' }"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="pic"></div>
|
||||||
|
</div>
|
||||||
|
<div class="song">
|
||||||
|
歌曲
|
||||||
|
<div class="name"></div>
|
||||||
|
<div class="others"></div>
|
||||||
|
<div class="ly"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="comments"></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
#sdTitle {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
right: 280px;
|
||||||
|
height: 40px;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
padding-left: 50px;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
#sdContent {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 40px;
|
||||||
|
right: 0;
|
||||||
|
bottom: 64px;
|
||||||
|
background-color: #f6f6f6;
|
||||||
|
|
||||||
|
.styli {
|
||||||
|
position: relative;
|
||||||
|
height: 60px;
|
||||||
|
img {
|
||||||
|
width: 160px;
|
||||||
|
position: absolute;
|
||||||
|
left: 135px;
|
||||||
|
transform-origin: 13px 13px;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
.playing {
|
||||||
|
transform: rotateZ(28deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.detail {
|
||||||
|
// margin: 2em;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
.pointer {
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
.disk {
|
||||||
|
--back-color: #eee;
|
||||||
|
--width-num: 340;
|
||||||
|
--padding-num: 10;
|
||||||
|
--width: calc(var(--width-num) * 1px);
|
||||||
|
--height: calc(var(--width-num) * 1px);
|
||||||
|
|
||||||
|
// position: relative;
|
||||||
|
// width: 300px;
|
||||||
|
.bg {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
width: var(--width);
|
||||||
|
height: var(--height);
|
||||||
|
background-color: var(--back-color);
|
||||||
|
border-radius: var(--width);
|
||||||
|
padding: calc(var(--padding-num) * 1px);
|
||||||
|
img.disk {
|
||||||
|
width: calc(
|
||||||
|
(var(--width-num) - var(--padding-num) * 2) * 1px
|
||||||
|
);
|
||||||
|
}
|
||||||
|
img.cover {
|
||||||
|
width: 220px;
|
||||||
|
border-radius: 200px;
|
||||||
|
position: absolute;
|
||||||
|
top: 60px;
|
||||||
|
left: 62px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.song {
|
||||||
|
position: relative;
|
||||||
|
width: 400px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -7,17 +7,19 @@ import {
|
|||||||
toRefs,
|
toRefs,
|
||||||
toRaw,
|
toRaw,
|
||||||
} from "vue";
|
} from "vue";
|
||||||
import {useStore} from 'vuex'
|
import { useStore } from "vuex";
|
||||||
import { NAvatar } from "naive-ui";
|
import { NAvatar, NIcon } from "naive-ui";
|
||||||
import pubsub from "pubsub-js";
|
import pubsub from "pubsub-js";
|
||||||
import { getSongDetial } from "@/network/song";
|
import { getSongDetial, getLyric } from "@/network/song";
|
||||||
import dayjs from 'dayjs'
|
import dayjs from "dayjs";
|
||||||
import 'dayjs/locale/zh-cn'
|
import "dayjs/locale/zh-cn";
|
||||||
import duration from 'dayjs/plugin/duration'
|
import duration from "dayjs/plugin/duration";
|
||||||
import ArtistsSpan from "@/components/ArtistsSpan.vue";
|
import ArtistsSpan from "@/components/ArtistsSpan.vue";
|
||||||
|
import svgArrowMin from "@/assets/svgs/ArrowMinimize24Regular.svg";
|
||||||
|
import svgArrowMax from "@/assets/svgs/ArrowMaximize24Regular.svg";
|
||||||
|
|
||||||
const store = useStore()
|
const store = useStore();
|
||||||
const showInfo = ref(false);
|
const showInfo = ref(true);
|
||||||
const info = reactive({
|
const info = reactive({
|
||||||
name: "",
|
name: "",
|
||||||
artists: [],
|
artists: [],
|
||||||
@ -26,7 +28,7 @@ const info = reactive({
|
|||||||
mv: 0,
|
mv: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
//#region 取得歌曲信息
|
//#region 取得歌曲信息、歌词
|
||||||
const songInfo = (id, im) => {
|
const songInfo = (id, im) => {
|
||||||
getSongDetial(id)
|
getSongDetial(id)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
@ -36,17 +38,37 @@ const songInfo = (id, im) => {
|
|||||||
info.album = res.data.songs[0].al;
|
info.album = res.data.songs[0].al;
|
||||||
info.duration = res.data.songs[0].dt;
|
info.duration = res.data.songs[0].dt;
|
||||||
info.mv = res.data.songs[0].mv;
|
info.mv = res.data.songs[0].mv;
|
||||||
currTime.value = '00:00'
|
currTime.value = "00:00";
|
||||||
totalTime.value = zpTime(info.duration)
|
totalTime.value = zpTime(info.duration);
|
||||||
if(im){
|
if (im) {
|
||||||
const p = {...{
|
const p = {
|
||||||
|
...{
|
||||||
id,
|
id,
|
||||||
date: Date.now(),
|
date: Date.now(),
|
||||||
}, ...toRaw(info)}
|
},
|
||||||
store.commit('savePlayed', p)
|
...toRaw(info),
|
||||||
store.commit('addToPlayingList', p)
|
};
|
||||||
console.log('savePlayed');
|
store.commit("savePlayed", p);
|
||||||
|
store.commit("addToPlayingList", p);
|
||||||
|
console.log("savePlayed");
|
||||||
}
|
}
|
||||||
|
pubsub.publish("zp.songInfo", {
|
||||||
|
...{
|
||||||
|
id,
|
||||||
|
date: Date.now(),
|
||||||
|
},
|
||||||
|
...toRaw(info),
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((err) => {});
|
||||||
|
};
|
||||||
|
const songLyric = (id) => {
|
||||||
|
getLyric(id)
|
||||||
|
.then((res) => {
|
||||||
|
if (res.data.code == 200)
|
||||||
|
pubsub.publish("zp.lyric", res.data.lrc.lyric );
|
||||||
|
else
|
||||||
|
pubsub.publish("zp.lyric", null);
|
||||||
})
|
})
|
||||||
.catch((err) => {});
|
.catch((err) => {});
|
||||||
};
|
};
|
||||||
@ -56,22 +78,23 @@ const songInfo = (id, im) => {
|
|||||||
let totalTime = ref("03:13");
|
let totalTime = ref("03:13");
|
||||||
let currTime = ref("00:03");
|
let currTime = ref("00:03");
|
||||||
|
|
||||||
dayjs.extend(duration)
|
dayjs.extend(duration);
|
||||||
function zpTime(time) {
|
function zpTime(time) {
|
||||||
return dayjs.duration(time).format('mm:ss')
|
return dayjs.duration(time).format("mm:ss");
|
||||||
}
|
}
|
||||||
// totalTime.value = zpTime(12345)
|
// totalTime.value = zpTime(12345)
|
||||||
const psToken = pubsub.subscribe("zp", (msg, data) => {
|
const psToken = pubsub.subscribe("zp", (msg, data) => {
|
||||||
switch (msg) {
|
switch (msg) {
|
||||||
case "zp.getSongInfo":
|
case "zp.getSongInfo":
|
||||||
songInfo(data.id, data.im);
|
songInfo(data.id, data.im);
|
||||||
|
songLyric(data.id);
|
||||||
break;
|
break;
|
||||||
case "zp.hideSongInfo":
|
case "zp.hideSongInfo":
|
||||||
showInfo.value = false
|
showInfo.value = false;
|
||||||
break;
|
break;
|
||||||
case "zp.progress":
|
case "zp.progress":
|
||||||
totalTime.value = zpTime(data.total * 1000)
|
totalTime.value = zpTime(data.total * 1000);
|
||||||
currTime.value = zpTime(data.progress * 1000)
|
currTime.value = zpTime(data.progress * 1000);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -80,25 +103,40 @@ onUnmounted(() => {
|
|||||||
pubsub.unsubscribe(psToken);
|
pubsub.unsubscribe(psToken);
|
||||||
});
|
});
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
|
const toggleSongDetail = () => {
|
||||||
|
console.log(
|
||||||
|
"显示/隐藏歌曲详细界面,包括歌词、模拟唱机以及其他操作。"
|
||||||
|
);
|
||||||
|
pubsub.publish("zp.toggleSongDetail");
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div id="songInfo">
|
<div id="songInfo">
|
||||||
<NAvatar style="border: 1px #ccc solid;"
|
<div class="wp-img" v-show="showInfo" @click="toggleSongDetail">
|
||||||
:size="40"
|
<img :src="info.album.picUrl" width="42" class="img" />
|
||||||
v-show="showInfo"
|
<span class="wp-icon">
|
||||||
:src="info.album.picUrl"
|
<NIcon v-if="store.state.showSongDetail"
|
||||||
></NAvatar>
|
><svgArrowMin
|
||||||
|
/></NIcon>
|
||||||
|
<NIcon v-else><svgArrowMax /></NIcon>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="song" v-show="showInfo">
|
<div class="song" v-show="showInfo">
|
||||||
<div class="w-song">
|
<div class="w-song">
|
||||||
<div class="song-name">{{ info.name }}</div>
|
<div class="song-name" @click="toggleSongDetail">
|
||||||
|
{{ info.name }}
|
||||||
|
</div>
|
||||||
<div class="song-author">
|
<div class="song-author">
|
||||||
<ArtistsSpan :artists="info.artists" />
|
<ArtistsSpan :artists="info.artists" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="song-time">
|
<div class="song-time" @click="toggleSongDetail">
|
||||||
<span class="played-time">{{ currTime }}</span>/<span class="total-time">{{ totalTime }}</span>
|
<span class="played-time">{{ currTime }}</span
|
||||||
|
>/<span class="total-time">{{ totalTime }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -116,14 +154,54 @@ export default {};
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
margin-left: 12px;
|
margin-left: 12px;
|
||||||
|
|
||||||
|
.wp-img {
|
||||||
|
--radius: 4px;
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
border: 1px #eee solid;
|
||||||
|
border-radius: var(--radius);
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.wp-icon {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.img {
|
||||||
|
border-radius: var(--radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
.wp-icon {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 42px;
|
||||||
|
height: 42px;
|
||||||
|
color: #fff;
|
||||||
|
background-color: rgba(255, 255, 255, 0.1);
|
||||||
|
border-radius: var(--radius);
|
||||||
|
-webkit-backdrop-filter: blur(2px);
|
||||||
|
backdrop-filter: blur(2px);
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 33px;
|
||||||
|
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.song {
|
.song {
|
||||||
padding-left: 6px;
|
padding-left: 6px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
cursor: pointer;
|
||||||
.w-song {
|
.w-song {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
.song-name{
|
.song-name {
|
||||||
// flex: 1;
|
// flex: 1;
|
||||||
.text-el-line-normal();
|
.text-el-line-normal();
|
||||||
}
|
}
|
||||||
|