初始化

This commit is contained in:
ZilongYang
2021-10-13 20:59:12 +08:00
commit 56a79617f0
73 changed files with 13328 additions and 0 deletions

View File

@@ -0,0 +1,108 @@
<script setup>
import {
h,
ref,
onMounted,
onUnmounted,
nextTick,
} from "vue";
import { useStore } from "vuex";
import {
RouterLink,
useRoute,
useRouter,
} from "vue-router";
import { NMenu, NIcon } from "naive-ui";
const menuOptions = ref([
{
label: () =>
h(
RouterLink,
{
to: {
path: "/discover/recommend",
},
},
{ default: () => "发现" }
),
key: "/discover",
},
{
label: () =>
h(
RouterLink,
{
to: {
path: "/videos/v",
},
},
{ default: () => "视频" }
),
key: "/videos",
},
{
label: () =>
h(
RouterLink,
{
to: {
path: "/played",
},
},
{ default: () => "最近播放" }
),
key: "/played",
},
//#region 其他
// {
// label: () =>
// h(
// RouterLink,
// {
// to: {
// path: '/fm'
// }
// },
// { default: () => '私人FM' }
// ),
// key: '/fm',
// },
// {
// label: () =>
// h(
// RouterLink,
// {
// to: {
// path: '/friends'
// }
// },
// { default: () => '朋友' }
// ),
// key: '/friends',
// },
//#endregion
]);
const store = useStore();
const {mainMenuSelected} = store.getters
</script>
<template>
<n-menu
:options="menuOptions"
:value="
mainMenuSelected(menuOptions)
"
/>
</template>
<script>
export default {
// beforeRouteEnter(to, from, next) {
// console.log("MainMenu beforeRouteEnter", to, from);
// next();
// },
};
</script>
<style></style>

34
src/views/common/Nav.vue Normal file
View File

@@ -0,0 +1,34 @@
<script setup>
import { useRouter } from "vue-router";
import { NButton, NIcon, NSpace } from "naive-ui";
import ChevronForward from '@/assets/svgs/ChevronForward.svg'
import ChevronBack from '@/assets/svgs/ChevronBack.svg'
const router = useRouter()
</script>
<template>
<NSpace id="nav" justify="end">
<n-button circle size="small" @click="router.back()" >
<template #icon>
<n-icon>
<ChevronBack />
</n-icon>
</template>
</n-button>
<n-button circle size="small" @click="router.forward()">
<template #icon>
<n-icon>
<ChevronForward />
</n-icon>
</template>
</n-button>
</NSpace>
</template>
<style lang="less" scoped>
#nav {
width: 150px;
// text-align: right;
// padding-top: 10px;
}
</style>

View File

@@ -0,0 +1,19 @@
<script setup>
import {NInput} from 'naive-ui'
</script>
<template>
<div id="search">
<n-input size="small" round placeholder="请搜索..." />
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>

View File

@@ -0,0 +1,39 @@
<script setup>
import { NButton, NIcon, NSpace } from "naive-ui";
import SettingsOutline from "@/assets/svgs/SettingsOutline.svg";
import MailOutline from "@/assets/svgs/MailOutline.svg";
</script>
<template>
<NSpace id="settings" >
<n-button circle size="small" >
<template #icon>
<n-icon>
<SettingsOutline />
</n-icon>
</template>
</n-button>
<n-button circle size="small" >
<template #icon>
<n-icon>
<MailOutline />
</n-icon>
</template>
</n-button>
</NSpace>
</template>
<script>
export default {
}
</script>
<style lang="less" scoped>
#settings{
// width: 100px;
margin: 0 15px
}
</style>

View File

@@ -0,0 +1,219 @@
<script setup>
import { ref, onMounted, onUnmounted, watch } from "vue";
import { useStore } from "vuex";
import { NButton, NIcon, NSpace } from "naive-ui";
import PlayCircle from "@/assets/svgs/PlayCircle.svg";
import PlaySkipForward from "@/assets/svgs/PlaySkipForward.svg";
import PlaySkipBack from "@/assets/svgs/PlaySkipBack.svg";
import HeartOutline from "@/assets/svgs/HeartOutline.svg";
import TrashOutline from "@/assets/svgs/TrashOutline.svg";
import PauseCircle from "@/assets/svgs/PauseCircle.svg";
import { getSongUrl } from "@/network/song";
import pubsub from "pubsub-js";
const store = useStore();
const { settings } = store.state;
const audioEl = ref("");
const playing = ref(false);
let currentTime = 0;
let lastPause = Date.now()
onMounted(() => {
audioEl.value.addEventListener("play", onPlay);
audioEl.value.addEventListener("pause", onPause);
audioEl.value.addEventListener("ended", onEnd);
if (settings.songId) {
pubsub.publish("zp.play", {
id: settings.songId,
im: false,
});
// play(settings.songId, false)
}
});
onUnmounted(() => {
console.log("另外一个Unmounted");
// audioEl.value.removeEventListener("play", onPlay);
// audioEl.value.removeEventListener("pause", onPause);
// audioEl.value.removeEventListener("ended", onEnd);
});
const onPlay = () => {
console.log("onPlay");
};
const onPause = () => {
console.log("onPause");
};
const onEnd = () => {
playing.value = false;
currentTime = 0;
console.log("onEnd");
};
const play = async (id, im = true) => {
console.log(id);
await getSongUrl(id)
.then((res) => {
audioEl.value.src = res.data.data[0].url;
store.commit("saveSettings", {
songId: id,
});
if (im) {
audioEl.value.play();
playing.value = true;
}
})
.catch((err) => {
console.log("getSongUrl err", err);
});
};
const pause = () => {
audioEl.value.pause();
playing.value = false;
};
const resume = async () => {
if (audioEl.value.readyState) {
//如果暂停过了5分钟需要再次载入歌曲
// console.log(Date.now() - lastPause);
if((Date.now() - lastPause) > 1000 * 60 * 5){
console.log('暂停过了5分钟再次载入歌曲');
await play(settings.songId, false);
audioEl.value.currentTime = currentTime;
}
audioEl.value.play();
playing.value = true;
}
};
const setProgressScale = (scale) => {
if (audioEl.value.readyState) {
// console.log(progress);
audioEl.value.currentTime = currentTime =
scale * audioEl.value.duration;
}
};
const favorite = () => {
// console.log(audioEl.value.currentTime);
};
let interval;
watch(playing, (val, old) => {
if (val === true) {
interval = setInterval(() => {
// console.log(audioEl.value.currentTime);
currentTime = audioEl.value.currentTime;
pubsub.publish("zp.progress", {
progress: audioEl.value.currentTime,
total: audioEl.value.duration,
});
}, 200);
} else {
clearInterval(interval);
lastPause = Date.now();
}
});
//#region 处理消息订阅
const psToken = pubsub.subscribe("zp", (msg, data) => {
switch (msg) {
case "zp.play":
play(data.id, data.im);
break;
case "zp.setProgressScale":
setProgressScale(data.scale);
break;
}
});
//卸载组件
onUnmounted(() => {
pubsub.unsubscribe(psToken);
});
//#endregion
</script>
<template>
<!-- <div id="songsCtrl"> -->
<audio src="" ref="audioEl"></audio>
<n-space
id="songCtrl"
align="center"
:size="[6]"
style="padding-top: 2px"
>
<n-button circle @click="favorite">
<template #icon>
<n-icon>
<HeartOutline />
</n-icon>
</template>
</n-button>
<n-button circle>
<template #icon>
<n-icon>
<PlaySkipBack />
</n-icon>
</template>
</n-button>
<n-button
v-if="!playing"
text
class="start-play"
style="font-size: 56px"
type="primary"
@click="resume"
>
<!-- <template #icon> -->
<n-icon>
<PlayCircle />
</n-icon>
<!-- </template> -->
</n-button>
<n-button
v-if="playing"
text
class="start-play"
style="font-size: 56px"
type="primary"
@click="pause"
>
<!-- <template #icon> -->
<n-icon size="56">
<PauseCircle />
</n-icon>
<!-- </template> -->
</n-button>
<!-- <n-button circle color="#18a058"> -->
<n-button circle>
<template #icon>
<n-icon>
<PlaySkipForward />
</n-icon>
</template>
</n-button>
<n-button circle>
<template #icon>
<n-icon>
<TrashOutline />
</n-icon>
</template>
</n-button>
</n-space>
<!-- </div> -->
</template>
<script>
export default {};
</script>
<style lang="less" scoped>
#songCtrl {
display: flex;
align-items: center;
}
</style>

View File

@@ -0,0 +1,115 @@
<script setup>
import {
ref,
onUnmounted,
reactive,
toRef,
toRefs,
} from "vue";
import { NAvatar } from "naive-ui";
import pubsub from "pubsub-js";
import { getSongDetial } from "@/network/song";
import dayjs from 'dayjs'
import 'dayjs/locale/zh-cn'
import duration from 'dayjs/plugin/duration'
const showInfo = ref(true);
const info = reactive({
name: "",
artists: "",
albumPicUrl: "",
});
//#region 取得歌曲信息
const songInfo = (id) => {
getSongDetial(id)
.then((res) => {
showInfo.value = true;
info.name = res.data.songs[0].name;
info.artists = res.data.songs[0].ar[0].name;
info.albumPicUrl = res.data.songs[0].al.picUrl;
})
.catch((err) => {});
};
//#endregion
//#region 处理消息订阅
let totalTime = ref("03:13");
let currTime = ref("00:03");
dayjs.extend(duration)
function zpTime(time) {
return dayjs.duration(time).format('mm:ss')
}
// totalTime.value = zpTime(12345)
const psToken = pubsub.subscribe("zp", (msg, data) => {
switch (msg) {
case "zp.play":
songInfo(data.id);
break;
case "zp.progress":
totalTime.value = zpTime(data.total * 1000)
currTime.value = zpTime(data.progress * 1000)
break;
}
});
//卸载组件
onUnmounted(() => {
pubsub.unsubscribe(psToken);
});
//#endregion
</script>
<template>
<div id="songInfo">
<NAvatar
:size="40"
v-show="showInfo"
:src="info.albumPicUrl"
></NAvatar>
<div class="song" v-show="showInfo">
<div class="w-song">
<div class="song-name">{{ info.name }}</div>
<div class="song-author">{{ info.artists }}</div>
</div>
<div class="song-time">
<span class="played-time">{{ currTime }}</span>/<span class="total-time">{{ totalTime }}</span>
</div>
</div>
</div>
</template>
<script>
export default {};
</script>
<style lang="less" scoped>
#songInfo {
flex: 3;
display: flex;
align-items: center;
margin-left: 12px;
.song {
padding-left: 6px;
display: flex;
flex-direction: column;
.w-song {
display: flex;
align-items: center;
.song-author {
margin-left: 4px;
color: #aaa;
font-size: 13px;
}
}
.song-time {
color: #aaa;
font-size: 13px;
font-family: Courier, monospace;
}
}
}
</style>

View File

@@ -0,0 +1,114 @@
<script setup>
import {
ref,
onUnmounted,
reactive,
toRef,
toRefs,
} from "vue";
import { useStore } from "vuex";
import { NProgress } from "naive-ui";
import pubsub from "pubsub-js";
import { getSongDetial } from "@/network/song";
import dayjs from "dayjs";
import "dayjs/locale/zh-cn";
import duration from "dayjs/plugin/duration";
const store = useStore();
const progress = ref("");
const wpProgress = ref("");
const setTime = (e) => {
//设定状态条长度
rightDot.value = wpProgress.value.clientWidth - e.offsetX + 'px'
percentage.value = e.offsetX / wpProgress.value.clientWidth * 100
// console.log(rightDot.value);
//发布 设置进度条消息
pubsub.publish("zp.setProgressScale", {
scale: e.offsetX / wpProgress.value.clientWidth,
});
};
// const primaryColor = store.state.theme.themeOverrides.common.primaryColor;
const rightDot = ref("px");
//#region 处理消息订阅
let percentage = ref(0.0);
const psToken = pubsub.subscribe("zp", (msg, data) => {
switch (msg) {
case "zp.progress":
percentage.value = (data.progress * 100) / data.total;
rightDot.value =
(1 - data.progress / (data.total - 0)) *
wpProgress.value.clientWidth +
"px";
// console.log(rightDot.value);
break;
}
});
//卸载组件
onUnmounted(() => {
pubsub.unsubscribe(psToken);
});
//#endregion
</script>
<template>
<div id="wpProgress" ref="wpProgress">
<n-progress
class="progress"
type="line"
:percentage="percentage"
:show-indicator="false"
:color="
store.state.theme.themeOverrides.common.primaryColor
"
:height="3"
:border-radius="0"
ref="progress"
@click="setTime"
/>
<div
class="dot"
:style="{
backgroundColor:
store.state.theme.themeOverrides.common
.primaryColor,
right: rightDot,
}"
></div>
</div>
</template>
<script>
export default {};
</script>
<style lang="less" scope>
#wpProgress {
position: relative;
// overflow: visible;
::-webkit-scrollbar {
display: none;
}
.progress {
cursor: pointer;
}
.dot {
position: absolute;
// background-color: red;
height: 10px;
width: 10px;
border-radius: 6px;
top: -4px;
// left: -4px;
display: none;
}
&:hover {
.dot {
display: block;
}
}
}
</style>

View File

@@ -0,0 +1,83 @@
<script setup>
import { ref } from "vue";
import { NButton, NIcon, NSpace } from "naive-ui";
import PlaylistMusic from "@/assets/svgs/PlaylistMusic.svg";
import VolumeOffOutline from "@/assets/svgs/VolumeOffOutline.svg";
import RepeatOutline from "@/assets/svgs/RepeatOutline.svg";
import RepeatOne from "@/assets/svgs/RepeatOne.svg";
import Playlist from "@/assets/svgs/Playlist.svg";
import Random from "@/assets/svgs/Random.svg";
//播放模式0-3顺序循环单曲随机。
const playMode = ref(0)
</script>
<template>
<!-- <div id="songsCtrl"> -->
<n-space
id="songStatus"
justify="end"
align="center"
:size="[6]"
style="padding-top: 2px; padding-right: 8px"
>
<n-button circle v-if="playMode==1">
<template #icon>
<n-icon>
<RepeatOutline />
</n-icon>
</template>
</n-button>
<n-button circle v-if="playMode==2">
<template #icon>
<n-icon>
<RepeatOne />
</n-icon>
</template>
</n-button>
<n-button circle v-if="playMode==0">
<template #icon>
<n-icon>
<Playlist />
</n-icon>
</template>
</n-button>
<n-button circle v-if="playMode==3">
<template #icon>
<n-icon>
<Random />
</n-icon>
</template>
</n-button>
<n-button circle>
<template #icon>
<n-icon>
<PlaylistMusic />
</n-icon>
</template>
</n-button>
<n-button circle>
<template #icon>
<n-icon>
<VolumeOffOutline />
</n-icon>
</template>
</n-button>
</n-space>
<!-- </div> -->
</template>
<script>
export default {
}
</script>
<style lang="less" scoped>
#songStatus {
flex: 2;
}
</style>

View File

@@ -0,0 +1,18 @@
<template>
<div id="topmenu">
</div>
</template>
<script>
export default {
}
</script>
<style lang="less" scoped>
#topmenu{
flex: 1;
}
</style>